[Lldb-commits] [PATCH] Primitive attach support for linux

Marco Minutoli mminutoli at gmail.com
Tue Jun 14 05:48:53 PDT 2011


This patch is a starting point for the attach functionality.
---
 source/Plugins/Process/Linux/ProcessLinux.cpp   |   11 ++-
 source/Plugins/Process/Linux/ProcessMonitor.cpp |  178 +++++++++++++++++++++--
 source/Plugins/Process/Linux/ProcessMonitor.h   |   49 ++++++-
 3 files changed, 214 insertions(+), 24 deletions(-)

diff --git a/source/Plugins/Process/Linux/ProcessLinux.cpp b/source/Plugins/Process/Linux/ProcessLinux.cpp
index c4ce8ee..e6940fe 100644
--- a/source/Plugins/Process/Linux/ProcessLinux.cpp
+++ b/source/Plugins/Process/Linux/ProcessLinux.cpp
@@ -105,7 +105,16 @@ ProcessLinux::CanDebug(Target &target)
 Error
 ProcessLinux::DoAttachToProcessWithID(lldb::pid_t pid)
 {
-    return Error(1, eErrorTypeGeneric);
+    Error error;
+    assert(m_monitor == NULL);
+
+    m_monitor = new ProcessMonitor(this, pid, error);
+
+    if (!error.Success())
+        return error;
+
+    SetID(pid);
+    return error;
 }
 
 Error
diff --git a/source/Plugins/Process/Linux/ProcessMonitor.cpp b/source/Plugins/Process/Linux/ProcessMonitor.cpp
index ce16159..ebe5959 100644
--- a/source/Plugins/Process/Linux/ProcessMonitor.cpp
+++ b/source/Plugins/Process/Linux/ProcessMonitor.cpp
@@ -524,6 +524,17 @@ KillOperation::Execute(ProcessMonitor *monitor)
         m_result = true;
 }
 
+ProcessMonitor::OperationArgs::OperationArgs(ProcessMonitor *monitor)
+    : m_monitor(monitor)
+{
+    sem_init(&m_semaphore, 0, 0);
+}
+
+ProcessMonitor::OperationArgs::~OperationArgs()
+{
+    sem_destroy(&m_semaphore);
+}
+
 ProcessMonitor::LaunchArgs::LaunchArgs(ProcessMonitor *monitor,
                                        lldb_private::Module *module,
                                        char const **argv,
@@ -531,21 +542,23 @@ ProcessMonitor::LaunchArgs::LaunchArgs(ProcessMonitor *monitor,
                                        const char *stdin_path,
                                        const char *stdout_path,
                                        const char *stderr_path)
-    : m_monitor(monitor),
+    : OperationArgs(monitor),
       m_module(module),
       m_argv(argv),
       m_envp(envp),
       m_stdin_path(stdin_path),
       m_stdout_path(stdout_path),
-      m_stderr_path(stderr_path)
-{
-    sem_init(&m_semaphore, 0, 0);
-}
+      m_stderr_path(stderr_path) { }
 
 ProcessMonitor::LaunchArgs::~LaunchArgs()
-{
-    sem_destroy(&m_semaphore);
-}
+{ }
+
+ProcessMonitor::AttachArgs::AttachArgs(ProcessMonitor *monitor,
+                                       lldb::pid_t pid)
+    : OperationArgs(monitor), m_pid(pid) { }
+
+ProcessMonitor::AttachArgs::~AttachArgs()
+{ }
 
 //------------------------------------------------------------------------------
 /// The basic design of the ProcessMonitor is built around two threads.
@@ -587,7 +600,7 @@ ProcessMonitor::ProcessMonitor(ProcessLinux *process,
         error.SetErrorString("Monitor failed to initialize.");
     }
 
-    StartOperationThread(args.get(), error);
+    StartLaunchOpThread(args.get(), error);
     if (!error.Success())
         return;
 
@@ -607,7 +620,7 @@ WAIT_AGAIN:
     // Check that the launch was a success.
     if (!args->m_error.Success())
     {
-        StopOperationThread();
+        StopLaunchOpThread();
         error = args->m_error;
         return;
     }
@@ -623,6 +636,64 @@ WAIT_AGAIN:
     }
 }
 
+ProcessMonitor::ProcessMonitor(ProcessLinux *process,
+                               lldb::pid_t pid,
+                               lldb_private::Error &error)
+    : m_process(process),
+      m_operation_thread(LLDB_INVALID_HOST_THREAD),
+      m_pid(LLDB_INVALID_PROCESS_ID),
+      m_terminal_fd(-1),
+      m_monitor_thread(LLDB_INVALID_HOST_THREAD),
+      m_client_fd(-1),
+      m_server_fd(-1)
+{
+    std::auto_ptr<AttachArgs> args;
+
+    args.reset(new AttachArgs(this, pid));
+
+    // Server/client descriptors.
+    if (!EnableIPC())
+    {
+        error.SetErrorToGenericError();
+        error.SetErrorString("Monitor failed to initialize.");
+    }
+
+    StartAttachOpThread(args.get(), error);
+    if (!error.Success())
+        return;
+
+WAIT_AGAIN:
+    // Wait for the operation thread to initialize.
+    if (sem_wait(&args->m_semaphore))
+    {
+        if (errno == EINTR)
+            goto WAIT_AGAIN;
+        else
+        {
+            error.SetErrorToErrno();
+            return;
+        }
+    }
+
+    // Check that the launch was a success.
+    if (!args->m_error.Success())
+    {
+        StopAttachOpThread();
+        error = args->m_error;
+        return;
+    }
+
+    // Finally, start monitoring the child process for change in state.
+    m_monitor_thread = Host::StartMonitoringChildProcess(
+        ProcessMonitor::MonitorCallback, this, GetPID(), true);
+    if (!IS_VALID_LLDB_HOST_THREAD(m_monitor_thread))
+    {
+        error.SetErrorToGenericError();
+        error.SetErrorString("Process attach failed.");
+        return;
+    }
+}
+
 ProcessMonitor::~ProcessMonitor()
 {
     StopMonitor();
@@ -631,7 +702,7 @@ ProcessMonitor::~ProcessMonitor()
 //------------------------------------------------------------------------------
 // Thread setup and tear down.
 void
-ProcessMonitor::StartOperationThread(LaunchArgs *args, Error &error)
+ProcessMonitor::StartLaunchOpThread(LaunchArgs *args, Error &error)
 {
     static const char *g_thread_name = "lldb.process.linux.operation";
 
@@ -639,11 +710,11 @@ ProcessMonitor::StartOperationThread(LaunchArgs *args, Error &error)
         return;
 
     m_operation_thread =
-        Host::ThreadCreate(g_thread_name, OperationThread, args, &error);
+        Host::ThreadCreate(g_thread_name, LaunchOpThread, args, &error);
 }
 
 void
-ProcessMonitor::StopOperationThread()
+ProcessMonitor::StopLaunchOpThread()
 {
     lldb::thread_result_t result;
 
@@ -655,7 +726,7 @@ ProcessMonitor::StopOperationThread()
 }
 
 void *
-ProcessMonitor::OperationThread(void *arg)
+ProcessMonitor::LaunchOpThread(void *arg)
 {
     LaunchArgs *args = static_cast<LaunchArgs*>(arg);
 
@@ -833,6 +904,80 @@ ProcessMonitor::EnableIPC()
     return true;
 }
 
+void
+ProcessMonitor::StartAttachOpThread(AttachArgs *args, lldb_private::Error &error)
+{
+    static const char *g_thread_name = "lldb.process.linux.operation";
+
+    if (IS_VALID_LLDB_HOST_THREAD(m_operation_thread))
+        return;
+
+    m_operation_thread =
+        Host::ThreadCreate(g_thread_name, AttachOpThread, args, &error);
+}
+
+void
+ProcessMonitor::StopAttachOpThread()
+{
+    assert(!"Not implemented yet!!!");
+}
+
+void *
+ProcessMonitor::AttachOpThread(void *arg)
+{
+    AttachArgs *args = static_cast<AttachArgs*>(arg);
+
+    if (!Attach(args))
+        return NULL;
+
+    ServeOperation(args);
+    return NULL;
+}
+
+bool
+ProcessMonitor::Attach(AttachArgs *args)
+{
+    lldb::pid_t pid = args->m_pid;
+
+    ProcessMonitor *monitor = args->m_monitor;
+    ProcessLinux &process = monitor->GetProcess();
+
+    lldb::ThreadSP inferior;
+
+    if (pid <= 1)
+    {
+        args->m_error.SetErrorToGenericError();
+        args->m_error.SetErrorString("Attaching to process 1 is not allowed.");
+        goto FINISH;
+    }
+
+    // Attach to the requested process.
+    if (ptrace(PTRACE_ATTACH, pid, NULL, NULL) < 0)
+    {
+        args->m_error.SetErrorToErrno();
+        goto FINISH;
+    }
+
+    int status;
+    if ((status = waitpid(pid, NULL, 0)) < 0)
+    {
+        args->m_error.SetErrorToErrno();
+        goto FINISH;
+    }
+
+    // Update the process thread list with the attached thread and
+    // mark it as current.
+    inferior.reset(new LinuxThread(process, pid));
+    process.GetThreadList().AddThread(inferior);
+    process.GetThreadList().SetSelectedThreadByID(pid);
+
+    // Let our process instance know the thread has stopped.
+    process.SendMessage(ProcessMessage::Trace(pid));
+
+ FINISH:
+    return args->m_error.Success();
+}
+
 bool
 ProcessMonitor::MonitorCallback(void *callback_baton,
                                 lldb::pid_t pid,
@@ -1094,10 +1239,11 @@ ProcessMonitor::GetCrashReasonForSIGBUS(const struct siginfo *info)
 }
 
 void
-ProcessMonitor::ServeOperation(LaunchArgs *args)
+ProcessMonitor::ServeOperation(OperationArgs *args)
 {
     int status;
     pollfd fdset;
+
     ProcessMonitor *monitor = args->m_monitor;
 
     fdset.fd = monitor->m_server_fd;
@@ -1326,7 +1472,7 @@ void
 ProcessMonitor::StopMonitor()
 {
     StopMonitoringChildProcess();
-    StopOperationThread();
+    StopLaunchOpThread();
     CloseFD(m_terminal_fd);
     CloseFD(m_client_fd);
     CloseFD(m_server_fd);
diff --git a/source/Plugins/Process/Linux/ProcessMonitor.h b/source/Plugins/Process/Linux/ProcessMonitor.h
index 9b8051b..ef9a179 100644
--- a/source/Plugins/Process/Linux/ProcessMonitor.h
+++ b/source/Plugins/Process/Linux/ProcessMonitor.h
@@ -56,6 +56,10 @@ public:
                    const char *stderr_path,
                    lldb_private::Error &error);
 
+    ProcessMonitor(ProcessLinux *process,
+                   lldb::pid_t pid,
+                   lldb_private::Error &error);
+
     ~ProcessMonitor();
 
     /// Provides the process number of debugee.
@@ -169,11 +173,22 @@ private:
     int m_client_fd;
     int m_server_fd;
 
+    struct OperationArgs
+    {
+        OperationArgs(ProcessMonitor *monitor);
+
+        ~OperationArgs();
+
+        ProcessMonitor *m_monitor;      // The monitor performing the attach.
+        sem_t m_semaphore;              // Posted to once operation complete.
+        lldb_private::Error m_error;    // Set if process operation failed.
+    };
+
     /// @class LauchArgs
     ///
     /// @brief Simple structure to pass data to the thread responsible for
     /// launching a child process.
-    struct LaunchArgs
+    struct LaunchArgs : OperationArgs
     {
         LaunchArgs(ProcessMonitor *monitor,
                    lldb_private::Module *module,
@@ -192,18 +207,16 @@ private:
         const char *m_stdin_path;       // Redirect stdin or NULL.
         const char *m_stdout_path;      // Redirect stdout or NULL.
         const char *m_stderr_path;      // Redirect stderr or NULL.
-        sem_t m_semaphore;              // Posted to once launch complete.
-        lldb_private::Error m_error;    // Set if process launch failed.
     };
 
     void
-    StartOperationThread(LaunchArgs *args, lldb_private::Error &error);
+    StartLaunchOpThread(LaunchArgs *args, lldb_private::Error &error);
 
     void
-    StopOperationThread();
+    StopLaunchOpThread();
 
     static void *
-    OperationThread(void *arg);
+    LaunchOpThread(void *arg);
 
     static bool
     Launch(LaunchArgs *args);
@@ -211,8 +224,30 @@ private:
     bool
     EnableIPC();
 
+    struct AttachArgs : OperationArgs
+    {
+        AttachArgs(ProcessMonitor *monitor,
+                   lldb::pid_t pid);
+
+        ~AttachArgs();
+
+        lldb::pid_t m_pid;              // pid of the process to be attached.
+    };
+
+    void
+    StartAttachOpThread(AttachArgs *args, lldb_private::Error &error);
+
+    void
+    StopAttachOpThread();
+
+    static void *
+    AttachOpThread(void *args);
+
+    static bool
+    Attach(AttachArgs *args);
+
     static void
-    ServeOperation(LaunchArgs *args);
+    ServeOperation(OperationArgs *args);
 
     static bool
     DupDescriptor(const char *path, int fd, int flags);
-- 
1.7.3.4




More information about the lldb-commits mailing list