[Lldb-commits] [lldb] r183049 - Add ability to attach/detach to multi-threaded inferiors on Linux.

Matt Kopec Matt.Kopec at intel.com
Fri May 31 15:00:07 PDT 2013


Author: mkopec
Date: Fri May 31 17:00:07 2013
New Revision: 183049

URL: http://llvm.org/viewvc/llvm-project?rev=183049&view=rev
Log:
Add ability to attach/detach to multi-threaded inferiors on Linux.
All running threads will be detected and stopped on attach and all threads get resumed on detach.

Modified:
    lldb/trunk/include/lldb/Host/Host.h
    lldb/trunk/source/Host/common/Host.cpp
    lldb/trunk/source/Host/linux/Host.cpp
    lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp
    lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h
    lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp

Modified: lldb/trunk/include/lldb/Host/Host.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/include/lldb/Host/Host.h?rev=183049&r1=183048&r2=183049&view=diff
==============================================================================
--- lldb/trunk/include/lldb/Host/Host.h (original)
+++ lldb/trunk/include/lldb/Host/Host.h Fri May 31 17:00:07 2013
@@ -13,6 +13,7 @@
 
 #include <stdarg.h>
 
+#include <map>
 #include <string>
 
 #include "lldb/lldb-private.h"
@@ -414,7 +415,12 @@ public:
     static uint32_t
     FindProcesses (const ProcessInstanceInfoMatch &match_info,
                    ProcessInstanceInfoList &proc_infos);
-    
+
+    typedef std::map<lldb::pid_t, bool> TidMap;
+    typedef std::pair<lldb::pid_t, bool> TidPair;
+    static bool
+    FindProcessThreads (const lldb::pid_t pid, TidMap &tids_to_attach);
+
     static bool
     GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &proc_info);
     

Modified: lldb/trunk/source/Host/common/Host.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/Host.cpp?rev=183049&r1=183048&r2=183049&view=diff
==============================================================================
--- lldb/trunk/source/Host/common/Host.cpp (original)
+++ lldb/trunk/source/Host/common/Host.cpp Fri May 31 17:00:07 2013
@@ -1238,6 +1238,14 @@ Host::GetProcessInfo (lldb::pid_t pid, P
 }
 #endif
 
+#if !defined(__linux__)
+bool
+Host::FindProcessThreads (const lldb::pid_t pid, TidMap &tids_to_attach)
+{
+    return false;
+}
+#endif
+
 lldb::TargetSP
 Host::GetDummyTarget (lldb_private::Debugger &debugger)
 {

Modified: lldb/trunk/source/Host/linux/Host.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/linux/Host.cpp?rev=183049&r1=183048&r2=183049&view=diff
==============================================================================
--- lldb/trunk/source/Host/linux/Host.cpp (original)
+++ lldb/trunk/source/Host/linux/Host.cpp Fri May 31 17:00:07 2013
@@ -295,6 +295,37 @@ Host::FindProcesses (const ProcessInstan
     return process_infos.GetSize();
 }
 
+bool
+Host::FindProcessThreads (const lldb::pid_t pid, TidMap &tids_to_attach)
+{
+    bool tids_changed = false;
+    static const char procdir[] = "/proc/";
+    static const char taskdir[] = "/task/";
+    std::string process_task_dir = procdir + std::to_string(pid) + taskdir;
+    DIR *dirproc = opendir (process_task_dir.c_str());
+
+    if (dirproc)
+    {
+        struct dirent *direntry = NULL;
+        while ((direntry = readdir (dirproc)) != NULL)
+        {
+            if (direntry->d_type != DT_DIR || !IsDirNumeric (direntry->d_name))
+                continue;
+
+            lldb::tid_t tid = atoi(direntry->d_name);
+            TidMap::iterator it = tids_to_attach.find(tid);
+            if (it == tids_to_attach.end())
+            {
+                tids_to_attach.insert(TidPair(tid, false));
+                tids_changed = true;
+            }
+        }
+        closedir (dirproc);
+    }
+
+    return tids_changed;
+}
+
 static bool
 GetELFProcessCPUType (const char *exe_path, ProcessInstanceInfo &process_info)
 {

Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp?rev=183049&r1=183048&r2=183049&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.cpp Fri May 31 17:00:07 2013
@@ -857,22 +857,20 @@ KillOperation::Execute(ProcessMonitor *m
 class DetachOperation : public Operation
 {
 public:
-    DetachOperation(Error &result) : m_error(result) { }
+    DetachOperation(lldb::tid_t tid, Error &result) : m_tid(tid), m_error(result) { }
 
     void Execute(ProcessMonitor *monitor);
 
 private:
+    lldb::tid_t m_tid;
     Error &m_error;
 };
 
 void
 DetachOperation::Execute(ProcessMonitor *monitor)
 {
-    lldb::pid_t pid = monitor->GetPID();
-
-    if (ptrace(PT_DETACH, pid, NULL, 0) < 0)
+    if (ptrace(PT_DETACH, m_tid, NULL, 0) < 0)
         m_error.SetErrorToErrno();
-
 }
 
 ProcessMonitor::OperationArgs::OperationArgs(ProcessMonitor *monitor)
@@ -1098,7 +1096,6 @@ ProcessMonitor::Launch(LaunchArgs *args)
     const size_t err_len = 1024;
     char err_str[err_len];
     lldb::pid_t pid;
-    long ptrace_opts = 0;
 
     lldb::ThreadSP inferior;
     Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
@@ -1214,20 +1211,7 @@ ProcessMonitor::Launch(LaunchArgs *args)
     assert(WIFSTOPPED(status) && wpid == pid &&
            "Could not sync with inferior process.");
 
-    // Have the child raise an event on exit.  This is used to keep the child in
-    // limbo until it is destroyed.
-    ptrace_opts |= PTRACE_O_TRACEEXIT;
-
-    // Have the tracer trace threads which spawn in the inferior process.
-    // TODO: if we want to support tracing the inferiors' child, add the
-    // appropriate ptrace flags here (PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK)
-    ptrace_opts |= PTRACE_O_TRACECLONE;
-
-    // Have the tracer notify us before execve returns
-    // (needed to disable legacy SIGTRAP generation)
-    ptrace_opts |= PTRACE_O_TRACEEXEC;
-
-    if (PTRACE(PTRACE_SETOPTIONS, pid, NULL, (void*)ptrace_opts, 0) < 0)
+    if (!SetDefaultPtraceOpts(pid))
     {
         args->m_error.SetErrorToErrno();
         goto FINISH;
@@ -1308,6 +1292,9 @@ ProcessMonitor::Attach(AttachArgs *args)
     lldb::ThreadSP inferior;
     Log *log (ProcessPOSIXLog::GetLogIfAllCategoriesSet (POSIX_LOG_PROCESS));
 
+    // Use a map to keep track of the threads which we have attached/need to attach.
+    Host::TidMap tids_to_attach;
+
     if (pid <= 1)
     {
         args->m_error.SetErrorToGenericError();
@@ -1315,33 +1302,103 @@ ProcessMonitor::Attach(AttachArgs *args)
         goto FINISH;
     }
 
-    // Attach to the requested process.
-    if (PTRACE(PTRACE_ATTACH, pid, NULL, NULL, 0) < 0)
+    while (Host::FindProcessThreads(pid, tids_to_attach))
     {
-        args->m_error.SetErrorToErrno();
-        goto FINISH;
+        for (Host::TidMap::iterator it = tids_to_attach.begin();
+             it != tids_to_attach.end(); ++it)
+        {
+            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 (PTRACE(PTRACE_ATTACH, tid, NULL, NULL, 0) < 0)
+                {
+                    // No such thread. The thread may have exited.
+                    // More error handling may be needed.
+                    if (errno == ESRCH)
+                    {
+                        tids_to_attach.erase(it);
+                        continue;
+                    }
+                    else
+                    {
+                        args->m_error.SetErrorToErrno();
+                        goto FINISH;
+                    }
+                }
+
+                int status;
+                // Need to use __WALL otherwise we receive an error with errno=ECHLD
+                // At this point we should have a thread stopped if waitpid succeeds.
+                if ((status = waitpid(tid, NULL, __WALL)) < 0)
+                {
+                    // No such thread. The thread may have exited.
+                    // More error handling may be needed.
+                    if (errno == ESRCH)
+                    {
+                        tids_to_attach.erase(it);
+                        continue;
+                    }
+                    else
+                    {
+                        args->m_error.SetErrorToErrno();
+                        goto FINISH;
+                    }
+                }
+
+                if (!SetDefaultPtraceOpts(tid))
+                {
+                    args->m_error.SetErrorToErrno();
+                    goto FINISH;
+                }
+
+                // Update the process thread list with the attached thread.
+                inferior.reset(new POSIXThread(process, tid));
+                if (log)
+                    log->Printf ("ProcessMonitor::%s() adding tid = %" PRIu64, __FUNCTION__, tid);
+                process.GetThreadList().AddThread(inferior);
+                it->second = true;
+            }
+        }
     }
 
-    int status;
-    if ((status = waitpid(pid, NULL, 0)) < 0)
+    if (tids_to_attach.size() > 0)
     {
-        args->m_error.SetErrorToErrno();
-        goto FINISH;
+        monitor->m_pid = pid;
+        // Let our process instance know the thread has stopped.
+        process.SendMessage(ProcessMessage::Trace(pid));
+    }
+    else
+    {
+        args->m_error.SetErrorToGenericError();
+        args->m_error.SetErrorString("No such process.");
     }
 
-    monitor->m_pid = pid;
+ FINISH:
+    return args->m_error.Success();
+}
 
-    // Update the process thread list with the attached thread.
-    inferior.reset(new POSIXThread(process, pid));
-    if (log)
-        log->Printf ("ProcessMonitor::%s() adding tid = %" PRIu64, __FUNCTION__, pid);
-    process.GetThreadList().AddThread(inferior);
+bool
+ProcessMonitor::SetDefaultPtraceOpts(lldb::pid_t pid)
+{
+    long ptrace_opts = 0;
 
-    // Let our process instance know the thread has stopped.
-    process.SendMessage(ProcessMessage::Trace(pid));
+    // Have the child raise an event on exit.  This is used to keep the child in
+    // limbo until it is destroyed.
+    ptrace_opts |= PTRACE_O_TRACEEXIT;
 
- FINISH:
-    return args->m_error.Success();
+    // Have the tracer trace threads which spawn in the inferior process.
+    // TODO: if we want to support tracing the inferiors' child, add the
+    // appropriate ptrace flags here (PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK)
+    ptrace_opts |= PTRACE_O_TRACECLONE;
+
+    // Have the tracer notify us before execve returns
+    // (needed to disable legacy SIGTRAP generation)
+    ptrace_opts |= PTRACE_O_TRACEEXEC;
+
+    return PTRACE(PTRACE_SETOPTIONS, pid, NULL, (void*)ptrace_opts, 0) >= 0;
 }
 
 bool
@@ -2047,11 +2104,12 @@ ProcessMonitor::GetEventMessage(lldb::ti
 }
 
 lldb_private::Error
-ProcessMonitor::Detach()
+ProcessMonitor::Detach(lldb::tid_t tid)
 {
     lldb_private::Error error;
-    if (m_pid != LLDB_INVALID_PROCESS_ID) {
-        DetachOperation op(error);
+    if (tid != LLDB_INVALID_THREAD_ID)
+    {
+        DetachOperation op(tid, error);
         DoOperation(&op);
     }
     return error;

Modified: lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h?rev=183049&r1=183048&r2=183049&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h (original)
+++ lldb/trunk/source/Plugins/Process/Linux/ProcessMonitor.h Fri May 31 17:00:07 2013
@@ -175,7 +175,7 @@ public:
     BringProcessIntoLimbo();
 
     lldb_private::Error
-    Detach();
+    Detach(lldb::tid_t tid);
 
     /// Stops the requested thread and waits for the stop signal.
     bool
@@ -262,6 +262,9 @@ private:
     static bool
     Attach(AttachArgs *args);
 
+    static bool
+    SetDefaultPtraceOpts(const lldb::pid_t);
+
     static void
     ServeOperation(OperationArgs *args);
 

Modified: lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp?rev=183049&r1=183048&r2=183049&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp (original)
+++ lldb/trunk/source/Plugins/Process/POSIX/ProcessPOSIX.cpp Fri May 31 17:00:07 2013
@@ -329,7 +329,14 @@ ProcessPOSIX::DoDetach(bool keep_stopped
         return error;
     }
 
-    error = m_monitor->Detach();
+    uint32_t thread_count = m_thread_list.GetSize(false);
+    for (uint32_t i = 0; i < thread_count; ++i)
+    {
+        POSIXThread *thread = static_cast<POSIXThread*>(
+            m_thread_list.GetThreadAtIndex(i, false).get());
+        error = m_monitor->Detach(thread->GetID());
+    }
+
     if (error.Success())
         SetPrivateState(eStateDetached);
 
@@ -393,7 +400,7 @@ ProcessPOSIX::SendMessage(const ProcessM
             if (m_exit_now)
             {
                 SetPrivateState(eStateExited);
-                m_monitor->Detach();
+                m_monitor->Detach(GetID());
             }
             else
             {





More information about the lldb-commits mailing list