summaryrefslogtreecommitdiffstats
path: root/lldb/source/Plugins
diff options
context:
space:
mode:
Diffstat (limited to 'lldb/source/Plugins')
-rw-r--r--lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp23
-rw-r--r--lldb/source/Plugins/Process/FreeBSD/ProcessMonitor.h4
-rw-r--r--lldb/source/Plugins/Process/Linux/ProcessMonitor.cpp74
-rw-r--r--lldb/source/Plugins/Process/Linux/ProcessMonitor.h4
-rw-r--r--lldb/source/Plugins/Process/POSIX/ProcessPOSIX.cpp21
-rw-r--r--lldb/source/Plugins/Process/POSIX/ProcessPOSIX.h3
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);
OpenPOWER on IntegriCloud