diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp index 9c798cb1cc8f2..a800ef3fad041 100644 --- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -316,6 +316,7 @@ NativeProcessLinux::Manager::Attach( if (!tids_or) return tids_or.takeError(); ArrayRef<::pid_t> tids = *tids_or; + llvm::Expected arch_or = NativeRegisterContextLinux::DetermineArchitecture(tids[0]); if (!arch_or) @@ -447,6 +448,7 @@ NativeProcessLinux::NativeProcessLinux(::pid_t pid, int terminal_fd, llvm::Expected> NativeProcessLinux::Attach(::pid_t pid) { Log *log = GetLog(POSIXLog::Process); + uint64_t options = GetDefaultPtraceOpts(); Status status; // Use a map to keep track of the threads which we have attached/need to // attach. @@ -457,9 +459,12 @@ llvm::Expected> NativeProcessLinux::Attach(::pid_t pid) { if (it->second == false) { lldb::tid_t tid = it->first; - // Attach to the requested process. - // An attach will cause the thread to stop with a SIGSTOP. - if ((status = PtraceWrapper(PTRACE_ATTACH, tid)).Fail()) { + // Seize and interrupt the requested process. + // This will cause the thread to stop in a TRACE_STOP state. + // Akin to a sigstop but without sending the signal. + if ((status = + PtraceWrapper(PTRACE_SEIZE, tid, nullptr, (void *)options)) + .Fail()) { // No such thread. The thread may have exited. More error handling // may be needed. if (status.GetError() == ESRCH) { @@ -474,6 +479,24 @@ llvm::Expected> NativeProcessLinux::Attach(::pid_t pid) { return status.ToError(); } + // Send a sigstop, this makes it so our seize->interrupt is signal wise + // the same as ptrace_attach. We do this so any program/workflow + // depending on the sending of a sigstop will still receive a sigstop. + tgkill(tid, tid, SIGSTOP); + + if ((status = PtraceWrapper(PTRACE_INTERRUPT, tid)).Fail()) { + // No such thread, the thread may have exited, this shouldn't + // happen at this stage, but we check regardless + if (status.GetError() == ESRCH) { + it = tids_to_attach.erase(it); + continue; + } + + // No check for EPERM because we already checked for it above + // when we seized + return status.ToError(); + } + int wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, tid, nullptr, __WALL); // Need to use __WALL otherwise we receive an error with errno=ECHLD At @@ -489,9 +512,6 @@ llvm::Expected> NativeProcessLinux::Attach(::pid_t pid) { std::error_code(errno, std::generic_category())); } - if ((status = SetDefaultPtraceOpts(tid)).Fail()) - return status.ToError(); - LLDB_LOG(log, "adding tid = {0}", tid); it->second = true; } @@ -513,8 +533,8 @@ llvm::Expected> NativeProcessLinux::Attach(::pid_t pid) { return std::move(tids); } -Status NativeProcessLinux::SetDefaultPtraceOpts(lldb::pid_t pid) { - long ptrace_opts = 0; +uint64_t NativeProcessLinux::GetDefaultPtraceOpts() { + uint64_t ptrace_opts = 0; // Have the child raise an event on exit. This is used to keep the child in // limbo until it is destroyed. @@ -537,6 +557,11 @@ Status NativeProcessLinux::SetDefaultPtraceOpts(lldb::pid_t pid) { // the child finishes sharing memory. ptrace_opts |= PTRACE_O_TRACEVFORKDONE; + return ptrace_opts; +} + +Status NativeProcessLinux::SetDefaultPtraceOpts(lldb::pid_t pid) { + uint64_t ptrace_opts = GetDefaultPtraceOpts(); return PtraceWrapper(PTRACE_SETOPTIONS, pid, nullptr, (void *)ptrace_opts); } diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h index d345f165a75d8..73255c69bcad3 100644 --- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h +++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h @@ -175,7 +175,6 @@ class NativeProcessLinux : public NativeProcessELF, private: Manager &m_manager; ArchSpec m_arch; - LazyBool m_supports_mem_region = eLazyBoolCalculate; std::vector> m_mem_region_cache; @@ -194,6 +193,8 @@ class NativeProcessLinux : public NativeProcessELF, static Status SetDefaultPtraceOpts(const lldb::pid_t); + static uint64_t GetDefaultPtraceOpts(); + bool TryHandleWaitStatus(lldb::pid_t pid, WaitStatus status); void MonitorCallback(NativeThreadLinux &thread, WaitStatus status);