Add initial support to trace spawned threads in a process on Linux.



git-svn-id: https://llvm.org/svn/llvm-project/lldb/trunk@171864 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/source/Plugins/Process/Linux/ProcessLinux.cpp b/source/Plugins/Process/Linux/ProcessLinux.cpp
index 6a766d7..6118a09 100644
--- a/source/Plugins/Process/Linux/ProcessLinux.cpp
+++ b/source/Plugins/Process/Linux/ProcessLinux.cpp
@@ -97,22 +97,7 @@
 bool
 ProcessLinux::UpdateThreadList(ThreadList &old_thread_list, ThreadList &new_thread_list)
 {
-    LogSP log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_THREAD));
-    if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
-        log->Printf ("ProcessLinux::%s() (pid = %" PRIu64 ")", __FUNCTION__, GetID());
-
-    // Update the process thread list with this new thread.
-    // FIXME: We should be using tid, not pid.
-    assert(m_monitor);
-    ThreadSP thread_sp (old_thread_list.FindThreadByID (GetID(), false));
-    if (!thread_sp) {
-        thread_sp.reset(new POSIXThread(*this, GetID()));
-    }
-
-    if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
-        log->Printf ("ProcessLinux::%s() updated pid = %" PRIu64, __FUNCTION__, GetID());
-    new_thread_list.AddThread(thread_sp);
-
+    new_thread_list = old_thread_list;
     return new_thread_list.GetSize(false) > 0;
 }
 
diff --git a/source/Plugins/Process/Linux/ProcessMonitor.cpp b/source/Plugins/Process/Linux/ProcessMonitor.cpp
index b71f0f9..f36a9ee 100644
--- a/source/Plugins/Process/Linux/ProcessMonitor.cpp
+++ b/source/Plugins/Process/Linux/ProcessMonitor.cpp
@@ -985,6 +985,7 @@
     const size_t err_len = 1024;
     char err_str[err_len];
     lldb::pid_t pid;
+    long ptrace_opts = 0;
 
     lldb::ThreadSP inferior;
     LogSP log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
@@ -1102,7 +1103,12 @@
 
     // Have the child raise an event on exit.  This is used to keep the child in
     // limbo until it is destroyed.
-    if (PTRACE(PTRACE_SETOPTIONS, pid, NULL, (void*)PTRACE_O_TRACEEXIT) < 0)
+    ptrace_opts |= PTRACE_O_TRACEEXIT;
+
+    // Have the tracer trace threads which spawn in the inferior process.
+    ptrace_opts |= PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACECLONE;
+
+    if (PTRACE(PTRACE_SETOPTIONS, pid, NULL, (void*)ptrace_opts) < 0)
     {
         args->m_error.SetErrorToErrno();
         goto FINISH;
@@ -1282,6 +1288,17 @@
         assert(false && "Unexpected SIGTRAP code!");
         break;
 
+    case (SIGTRAP | (PTRACE_EVENT_FORK << 8)):
+    case (SIGTRAP | (PTRACE_EVENT_VFORK << 8)):
+    case (SIGTRAP | (PTRACE_EVENT_CLONE << 8)):
+    {
+        unsigned long tid = 0;
+        if (!monitor->GetEventMessage(pid, &tid))
+            tid = -1;
+        message = ProcessMessage::NewThread(pid, tid);
+        break;
+    }
+
     case (SIGTRAP | (PTRACE_EVENT_EXIT << 8)):
     {
         // The inferior process is about to exit.  Maintain the process in a
diff --git a/source/Plugins/Process/POSIX/POSIXStopInfo.cpp b/source/Plugins/Process/POSIX/POSIXStopInfo.cpp
index 3dd3c86..b9765b6 100644
--- a/source/Plugins/Process/POSIX/POSIXStopInfo.cpp
+++ b/source/Plugins/Process/POSIX/POSIXStopInfo.cpp
@@ -58,3 +58,32 @@
 {
     return ProcessMessage::GetCrashReasonString(m_crash_reason);
 }
+
+//===----------------------------------------------------------------------===//
+// POSIXNewThreadStopInfo
+
+POSIXNewThreadStopInfo::~POSIXNewThreadStopInfo() { }
+
+lldb::StopReason
+POSIXNewThreadStopInfo::GetStopReason() const
+{
+    return lldb::eStopReasonNone;
+}
+
+const char *
+POSIXNewThreadStopInfo::GetDescription()
+{
+    return "thread spawned";
+}
+
+bool
+POSIXNewThreadStopInfo::ShouldStop(Event *event_ptr)
+{
+    return false;
+}
+
+bool
+POSIXNewThreadStopInfo::ShouldNotify(Event *event_ptr)
+{
+    return false;
+}
diff --git a/source/Plugins/Process/POSIX/POSIXStopInfo.h b/source/Plugins/Process/POSIX/POSIXStopInfo.h
index c510377..7c5be3d 100644
--- a/source/Plugins/Process/POSIX/POSIXStopInfo.h
+++ b/source/Plugins/Process/POSIX/POSIXStopInfo.h
@@ -89,4 +89,32 @@
     ProcessMessage::CrashReason m_crash_reason;
 };    
 
+//===----------------------------------------------------------------------===//
+/// @class POSIXNewThreadStopInfo
+/// @brief Represents the stop state of process when a new thread is spawned.
+///
+
+class POSIXNewThreadStopInfo
+    : public POSIXStopInfo
+{
+public:
+    POSIXNewThreadStopInfo (POSIXThread &thread)
+        : POSIXStopInfo (thread, 0)
+        { }
+
+    ~POSIXNewThreadStopInfo();
+
+    lldb::StopReason
+    GetStopReason() const;
+
+    const char *
+    GetDescription();
+
+    bool
+    ShouldStop(lldb_private::Event *event_ptr);
+
+    bool
+    ShouldNotify(lldb_private::Event *event_ptr);
+};
+
 #endif
diff --git a/source/Plugins/Process/POSIX/POSIXThread.cpp b/source/Plugins/Process/POSIX/POSIXThread.cpp
index e7848c0..ce43913 100644
--- a/source/Plugins/Process/POSIX/POSIXThread.cpp
+++ b/source/Plugins/Process/POSIX/POSIXThread.cpp
@@ -226,6 +226,10 @@
     case ProcessMessage::eCrashMessage:
         CrashNotify(message);
         break;
+
+    case ProcessMessage::eNewThreadMessage:
+        ThreadNotify(message);
+        break;
     }
 }
 
@@ -301,6 +305,12 @@
     SetResumeSignal(signo);
 }
 
+void
+POSIXThread::ThreadNotify(const ProcessMessage &message)
+{
+    m_stop_info = lldb::StopInfoSP(new POSIXNewThreadStopInfo(*this));
+}
+
 unsigned
 POSIXThread::GetRegisterIndexFromOffset(unsigned offset)
 {
diff --git a/source/Plugins/Process/POSIX/POSIXThread.h b/source/Plugins/Process/POSIX/POSIXThread.h
index 95280d4..7aad671 100644
--- a/source/Plugins/Process/POSIX/POSIXThread.h
+++ b/source/Plugins/Process/POSIX/POSIXThread.h
@@ -98,6 +98,7 @@
     void SignalNotify(const ProcessMessage &message);
     void SignalDeliveredNotify(const ProcessMessage &message);
     void CrashNotify(const ProcessMessage &message);
+    void ThreadNotify(const ProcessMessage &message);
 
     lldb_private::Unwind *
     GetUnwinder();
diff --git a/source/Plugins/Process/POSIX/ProcessMessage.cpp b/source/Plugins/Process/POSIX/ProcessMessage.cpp
index a8b8e95..cefacc3 100644
--- a/source/Plugins/Process/POSIX/ProcessMessage.cpp
+++ b/source/Plugins/Process/POSIX/ProcessMessage.cpp
@@ -224,6 +224,9 @@
     case eCrashMessage:
         str = "eCrashMessage";
         break;
+    case eNewThreadMessage:
+        str = "eNewThreadMessage";
+        break;
     }
 #endif
 
diff --git a/source/Plugins/Process/POSIX/ProcessMessage.h b/source/Plugins/Process/POSIX/ProcessMessage.h
index 826567e..7eca5c8 100644
--- a/source/Plugins/Process/POSIX/ProcessMessage.h
+++ b/source/Plugins/Process/POSIX/ProcessMessage.h
@@ -29,7 +29,8 @@
         eSignalDeliveredMessage,
         eTraceMessage,
         eBreakpointMessage,
-        eCrashMessage
+        eCrashMessage,
+        eNewThreadMessage
     };
 
     enum CrashReason
@@ -111,6 +112,11 @@
         return message;
     }
 
+    /// Indicates that the thread @p tid was spawned.
+    static ProcessMessage NewThread(lldb::tid_t parent_tid, lldb::tid_t child_tid) {
+        return ProcessMessage(parent_tid, eNewThreadMessage, child_tid);
+    }
+
     int GetExitStatus() const {
         assert(GetKind() == eExitMessage || GetKind() == eLimboMessage);
         return m_status;
@@ -137,6 +143,11 @@
         return m_addr;
     }
 
+    lldb::tid_t GetChildTID() const {
+        assert(GetKind() == eNewThreadMessage);
+        return m_child_tid;
+    }
+
     static const char *
     GetCrashReasonString(CrashReason reason);
 
@@ -159,13 +170,23 @@
           m_kind(kind),
           m_crash_reason(eInvalidCrashReason),
           m_status(status),
-          m_addr(addr) { }
+          m_addr(addr),
+          m_child_tid(0) { }
+
+    ProcessMessage(lldb::tid_t tid, Kind kind, lldb::tid_t child_tid)
+        : m_tid(tid),
+          m_kind(kind),
+          m_crash_reason(eInvalidCrashReason),
+          m_status(0),
+          m_addr(0),
+          m_child_tid(child_tid) { }
 
     lldb::tid_t m_tid;
     Kind        m_kind         : 8;
     CrashReason m_crash_reason : 8;
     int m_status;
     lldb::addr_t m_addr;
+    lldb::tid_t m_child_tid;
 };
 
 #endif // #ifndef liblldb_ProcessMessage_H_
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
index a694865..980778f 100644
--- a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
+++ b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
@@ -361,13 +361,26 @@
 
     case ProcessMessage::eSignalMessage:
     case ProcessMessage::eSignalDeliveredMessage:
-        SetPrivateState(eStateStopped);
-        break;
+    {
+        lldb::tid_t tid = message.GetTID();
+        lldb::tid_t pid = GetID();
+        if (tid == pid) {
+            SetPrivateState(eStateStopped);
+            break;
+        } else {
+            // FIXME: Ignore any signals generated by children.
+            return;
+        }
+    }
 
     case ProcessMessage::eCrashMessage:
         // FIXME: Update stop reason as per bugzilla 14598
         SetPrivateState(eStateStopped);
         break;
+
+    case ProcessMessage::eNewThreadMessage:
+        SetPrivateState(eStateStopped);
+        break;
     }
 
     m_message_queue.push(message);
@@ -395,6 +408,12 @@
     POSIXThread *thread = static_cast<POSIXThread*>(
         GetThreadList().FindThreadByID(tid, false).get());
 
+    if (message.GetKind() == ProcessMessage::eNewThreadMessage) {
+        ThreadSP thread_sp;
+        thread_sp.reset(new POSIXThread(*this, message.GetChildTID()));
+        m_thread_list.AddThread(thread_sp);
+    }
+
     assert(thread);
     thread->Notify(message);