diff options
Diffstat (limited to 'lldb/source/Plugins')
6 files changed, 128 insertions, 1 deletions
diff --git a/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp b/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp index 7e0476caf9c..1cf50453a74 100644 --- a/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp +++ b/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp @@ -1637,6 +1637,29 @@ ProcessMonitor::StopMonitor() // even though still has the file descriptor, we shouldn't close it here. } +// FIXME: On Linux, when a new thread is created, we receive to notifications, +// (1) a SIGTRAP|PTRACE_EVENT_CLONE from the main process thread with the +// child thread id as additional information, and (2) a SIGSTOP|SI_USER from +// the new child thread indicating that it has is stopped because we attached. +// We have no guarantee of the order in which these arrive, but we need both +// before we are ready to proceed. We currently keep a list of threads which +// have sent the initial SIGSTOP|SI_USER event. Then when we receive the +// SIGTRAP|PTRACE_EVENT_CLONE notification, if the initial stop has not occurred +// we call ProcessMonitor::WaitForInitialTIDStop() to wait for it. +// +// Right now, the above logic is in ProcessPOSIX, so we need a definition of +// this function in the FreeBSD ProcessMonitor implementation even if it isn't +// logically needed. +// +// We really should figure out what actually happens on FreeBSD and move the +// Linux-specific logic out of ProcessPOSIX as needed. + +bool +ProcessMonitor::WaitForInitialTIDStop(lldb::tid_t tid) +{ + return true; +} + void ProcessMonitor::StopOpThread() { diff --git a/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h b/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h index ce66c03f2f8..5442867314f 100644 --- a/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h +++ b/lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h @@ -193,6 +193,10 @@ public: void StopMonitor(); + // Waits for the initial stop message from a new thread. + bool + WaitForInitialTIDStop(lldb::tid_t tid); + private: ProcessFreeBSD *m_process; diff --git a/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp b/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp index 673ca180e5f..3ce036b070a 100644 --- a/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp +++ b/lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp @@ -1595,6 +1595,80 @@ ProcessMonitor::MonitorSignal(ProcessMonitor *monitor, return ProcessMessage::Signal(pid, signo); } +// On Linux, when a new thread is created, we receive to notifications, +// (1) a SIGTRAP|PTRACE_EVENT_CLONE from the main process thread with the +// child thread id as additional information, and (2) a SIGSTOP|SI_USER from +// the new child thread indicating that it has is stopped because we attached. +// We have no guarantee of the order in which these arrive, but we need both +// before we are ready to proceed. We currently keep a list of threads which +// have sent the initial SIGSTOP|SI_USER event. Then when we receive the +// SIGTRAP|PTRACE_EVENT_CLONE notification, if the initial stop has not occurred +// we call ProcessMonitor::WaitForInitialTIDStop() to wait for it. + +bool +ProcessMonitor::WaitForInitialTIDStop(lldb::tid_t tid) +{ + Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS)); + if (log) + log->Printf ("ProcessMonitor::%s(%d) waiting for thread to stop...", __FUNCTION__, tid); + + // Wait for the thread to stop + while (true) + { + int status = -1; + if (log) + log->Printf ("ProcessMonitor::%s(%d) waitpid...", __FUNCTION__, tid); + lldb::pid_t wait_pid = waitpid(tid, &status, __WALL); + if (status == -1) + { + // If we got interrupted by a signal (in our process, not the + // inferior) try again. + if (errno == EINTR) + continue; + else + { + if (log) + log->Printf("ProcessMonitor::%s(%d) waitpid error -- %s", __FUNCTION__, tid, strerror(errno)); + return false; // This is bad, but there's nothing we can do. + } + } + + if (log) + log->Printf ("ProcessMonitor::%s(%d) waitpid, status = %d", __FUNCTION__, tid, status); + + assert(wait_pid == tid); + + siginfo_t info; + int ptrace_err; + if (!GetSignalInfo(wait_pid, &info, ptrace_err)) + { + if (log) + { + log->Printf ("ProcessMonitor::%s() GetSignalInfo failed. errno=%d (%s)", __FUNCTION__, ptrace_err, strerror(ptrace_err)); + } + return false; + } + + // If this is a thread exit, we won't get any more information. + if (WIFEXITED(status)) + { + m_process->SendMessage(ProcessMessage::Exit(wait_pid, WEXITSTATUS(status))); + if (wait_pid == tid) + return true; + continue; + } + + assert(info.si_code == SI_USER); + assert(WSTOPSIG(status) == SIGSTOP); + + if (log) + log->Printf ("ProcessMonitor::%s(bp) received thread stop signal", __FUNCTION__); + m_process->AddThreadForInitialStopIfNeeded(wait_pid); + return true; + } + return false; +} + bool ProcessMonitor::StopThread(lldb::tid_t tid) { diff --git a/lldb/source/Plugins/Process/Linux/ProcessMonitor.h b/lldb/source/Plugins/Process/Linux/ProcessMonitor.h index 4d02e61a10f..3729e257feb 100644 --- a/lldb/source/Plugins/Process/Linux/ProcessMonitor.h +++ b/lldb/source/Plugins/Process/Linux/ProcessMonitor.h @@ -185,6 +185,10 @@ public: bool StopThread(lldb::tid_t tid); + // Waits for the initial stop message from a new thread. + bool + WaitForInitialTIDStop(lldb::tid_t tid); + private: ProcessLinux *m_process; diff --git a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp index 5ab864f59a4..5e6604458ad 100644 --- a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp +++ b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp @@ -418,13 +418,26 @@ ProcessPOSIX::SendMessage(const ProcessMessage &message) case ProcessMessage::eBreakpointMessage: case ProcessMessage::eTraceMessage: case ProcessMessage::eWatchpointMessage: - case ProcessMessage::eNewThreadMessage: case ProcessMessage::eCrashMessage: assert(thread); thread->SetState(eStateStopped); StopAllThreads(message.GetTID()); SetPrivateState(eStateStopped); break; + + case ProcessMessage::eNewThreadMessage: + { + lldb::tid_t new_tid = message.GetChildTID(); + if (WaitingForInitialStop(new_tid)) + { + m_monitor->WaitForInitialTIDStop(new_tid); + } + assert(thread); + thread->SetState(eStateStopped); + StopAllThreads(message.GetTID()); + SetPrivateState(eStateStopped); + break; + } } m_message_queue.push(message); @@ -449,6 +462,12 @@ ProcessPOSIX::AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid) return added_to_set; } +bool +ProcessPOSIX::WaitingForInitialStop(lldb::tid_t stop_tid) +{ + return (m_seen_initial_stop.find(stop_tid) == m_seen_initial_stop.end()); +} + POSIXThread * ProcessPOSIX::CreateNewPOSIXThread(lldb_private::Process &process, lldb::tid_t tid) { diff --git a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h index 114667ad159..080b089243e 100644 --- a/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h +++ b/lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h @@ -167,6 +167,9 @@ public: bool AddThreadForInitialStopIfNeeded(lldb::tid_t stop_tid); + bool + WaitingForInitialStop(lldb::tid_t stop_tid); + virtual POSIXThread * CreateNewPOSIXThread(lldb_private::Process &process, lldb::tid_t tid); |