[lldb-dev] [PATCH 2/2] Support debugging yourself on Linux.

eatnumber1 at google.com eatnumber1 at google.com
Fri Sep 26 09:56:48 PDT 2014


From: Russell Harmon <eatnumber1 at google.com>

---
 source/Plugins/Process/Linux/CMakeLists.txt        |   2 +
 source/Plugins/Process/Linux/ProcessMonitor.cpp    |  16 ++
 source/Plugins/Process/Linux/ProcessMonitor.h      |  25 +--
 .../Plugins/Process/Linux/ProcessMonitorOther.cpp  |   6 +-
 source/Plugins/Process/Linux/ProcessMonitorOther.h |   2 -
 .../Plugins/Process/Linux/ProcessMonitorSelf.cpp   | 237 +++++++++++++++++++++
 source/Plugins/Process/Linux/ProcessMonitorSelf.h  | 164 ++++++++++++++
 source/Plugins/Process/POSIX/ProcessPOSIX.cpp      |   9 +-
 8 files changed, 439 insertions(+), 22 deletions(-)
 create mode 100644 source/Plugins/Process/Linux/ProcessMonitor.cpp
 create mode 100644 source/Plugins/Process/Linux/ProcessMonitorSelf.cpp
 create mode 100644 source/Plugins/Process/Linux/ProcessMonitorSelf.h

diff --git a/source/Plugins/Process/Linux/CMakeLists.txt b/source/Plugins/Process/Linux/CMakeLists.txt
index 9b04315..021828e 100644
--- a/source/Plugins/Process/Linux/CMakeLists.txt
+++ b/source/Plugins/Process/Linux/CMakeLists.txt
@@ -9,7 +9,9 @@ add_lldb_library(lldbPluginProcessLinux
   NativeRegisterContextLinux_x86_64.cpp
   NativeThreadLinux.cpp
   ProcessLinux.cpp
+  ProcessMonitor.cpp
   ProcessMonitorOther.cpp
+  ProcessMonitorSelf.cpp
   ProcFileReader.cpp
   LinuxThread.cpp
   )
diff --git a/source/Plugins/Process/Linux/ProcessMonitor.cpp b/source/Plugins/Process/Linux/ProcessMonitor.cpp
new file mode 100644
index 0000000..780d20a
--- /dev/null
+++ b/source/Plugins/Process/Linux/ProcessMonitor.cpp
@@ -0,0 +1,16 @@
+//===-- ProcessMonitor.cpp ------------------------------------ -*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "ProcessPOSIX.h"
+#include "ProcessLinux.h"
+#include "ProcessMonitor.h"
+
+ProcessMonitor::ProcessMonitor(ProcessPOSIX *process)
+    : m_process(static_cast<ProcessLinux *>(process))
+{}
diff --git a/source/Plugins/Process/Linux/ProcessMonitor.h b/source/Plugins/Process/Linux/ProcessMonitor.h
index 96ddf28..1c3c9d3 100644
--- a/source/Plugins/Process/Linux/ProcessMonitor.h
+++ b/source/Plugins/Process/Linux/ProcessMonitor.h
@@ -22,12 +22,9 @@
 namespace lldb_private
 {
 class Error;
-class Module;
-class Scalar;
 } // End lldb_private namespace.
 
 class ProcessLinux;
-class Operation;
 
 /// @class ProcessMonitor
 /// @brief Manages communication with the inferior (debugee) process.
@@ -44,12 +41,18 @@ class Operation;
 class ProcessMonitor
 {
 public:
-    virtual ~ProcessMonitor() {};
+    ProcessMonitor(ProcessPOSIX *process);
+
+    virtual ~ProcessMonitor() {}
 
     /// Provides the process number of debugee.
     virtual lldb::pid_t
     GetPID() const = 0;
 
+    /// Returns the process associated with this ProcessMonitorOther.
+    ProcessLinux &
+    GetProcess() { return *m_process; }
+
     /// Returns a file descriptor to the controlling terminal of the inferior
     /// process.
     ///
@@ -125,17 +128,6 @@ public:
     virtual bool
     ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value) = 0;
 
-    /// Writes a siginfo_t structure corresponding to the given thread ID to the
-    /// memory region pointed to by @p siginfo.
-    virtual bool
-    GetSignalInfo(lldb::tid_t tid, void *siginfo, int &ptrace_err) = 0;
-
-    /// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG)
-    /// corresponding to the given thread IDto the memory pointed to by @p
-    /// message.
-    virtual bool
-    GetEventMessage(lldb::tid_t tid, unsigned long *message) = 0;
-
     /// Resumes the given thread.  If @p signo is anything but
     /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
     virtual bool
@@ -164,6 +156,9 @@ public:
     // Waits for the initial stop message from a new thread.
     virtual bool
     WaitForInitialTIDStop(lldb::tid_t tid) = 0;
+
+protected:
+    ProcessLinux *m_process;
 };
 
 #endif // #ifndef liblldb_ProcessMonitor_H_
diff --git a/source/Plugins/Process/Linux/ProcessMonitorOther.cpp b/source/Plugins/Process/Linux/ProcessMonitorOther.cpp
index 6ba900d..d151663 100644
--- a/source/Plugins/Process/Linux/ProcessMonitorOther.cpp
+++ b/source/Plugins/Process/Linux/ProcessMonitorOther.cpp
@@ -1008,8 +1008,7 @@ ProcessMonitorOther::ProcessMonitorOther(ProcessPOSIX *process,
                                const char *stderr_path,
                                const char *working_dir,
                                lldb_private::Error &error)
-    : ProcessMonitor(),
-      m_process(static_cast<ProcessLinux *>(process)),
+    : ProcessMonitor(process),
       m_operation_thread(LLDB_INVALID_HOST_THREAD),
       m_monitor_thread(LLDB_INVALID_HOST_THREAD),
       m_pid(LLDB_INVALID_PROCESS_ID),
@@ -1062,8 +1061,7 @@ WAIT_AGAIN:
 ProcessMonitorOther::ProcessMonitorOther(ProcessPOSIX *process,
                                lldb::pid_t pid,
                                lldb_private::Error &error)
-  : ProcessMonitor(),
-      m_process(static_cast<ProcessLinux *>(process)),
+  : ProcessMonitor(process),
       m_operation_thread(LLDB_INVALID_HOST_THREAD),
       m_monitor_thread(LLDB_INVALID_HOST_THREAD),
       m_pid(LLDB_INVALID_PROCESS_ID),
diff --git a/source/Plugins/Process/Linux/ProcessMonitorOther.h b/source/Plugins/Process/Linux/ProcessMonitorOther.h
index 7a61cc2..d5dc087 100644
--- a/source/Plugins/Process/Linux/ProcessMonitorOther.h
+++ b/source/Plugins/Process/Linux/ProcessMonitorOther.h
@@ -194,8 +194,6 @@ public:
     WaitForInitialTIDStop(lldb::tid_t tid);
 
 private:
-    ProcessLinux *m_process;
-
     lldb::thread_t m_operation_thread;
     lldb::thread_t m_monitor_thread;
     lldb::pid_t m_pid;
diff --git a/source/Plugins/Process/Linux/ProcessMonitorSelf.cpp b/source/Plugins/Process/Linux/ProcessMonitorSelf.cpp
new file mode 100644
index 0000000..79e2833
--- /dev/null
+++ b/source/Plugins/Process/Linux/ProcessMonitorSelf.cpp
@@ -0,0 +1,237 @@
+//===-- ProcessMonitorSelf.cpp ------------------------------------ -*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-python.h"
+
+// C Includes
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <stddef.h>
+
+// C++ Includes
+// Self libraries and framework includes
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Error.h"
+#include "lldb/Core/RegisterValue.h"
+#include "lldb/Core/Scalar.h"
+#include "lldb/Host/Host.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Utility/PseudoTerminal.h"
+
+#include "POSIXThread.h"
+#include "ProcessLinux.h"
+#include "ProcessPOSIXLog.h"
+#include "ProcessMonitorSelf.h"
+
+using namespace lldb_private;
+
+ProcessMonitorSelf::ProcessMonitorSelf(ProcessPOSIX *process,
+                                       lldb_private::Error &error)
+    : ProcessMonitor(process),
+      m_terminal_fd(-1)
+{
+    // TODO: Determine a better size for this buffer
+    // TODO: Do something reasonable if stderr is not open on the same terminal
+    // as stdout.
+    char buf[1024];
+    int err = ttyname_r(STDOUT_FILENO, buf, 1024);
+    if (err != 0) {
+        // TODO: Handle the error
+        assert(false);
+    }
+
+    int fd = open(buf, O_RDONLY);
+    if (fd == -1) {
+        // TODO: Handle the error
+        assert(false);
+    }
+
+    m_terminal_fd = fd;
+
+    process->SendMessage(ProcessMessage::Attach(GetPID()));
+}
+
+ProcessMonitorSelf::~ProcessMonitorSelf() {
+    // TODO: Handle errors on close
+    close(m_terminal_fd);
+}
+
+/// Provides the process number of debugee.
+lldb::pid_t
+ProcessMonitorSelf::GetPID() const
+{
+    return getpid();
+}
+
+/// Returns a file descriptor to the controlling terminal of the inferior
+/// process.
+///
+/// Reads from this file descriptor yield both the standard output and
+/// standard error of this debugee.  Even if stderr and stdout were
+/// redirected on launch it may still happen that data is available on this
+/// descriptor (if the inferior process opens /dev/tty, for example).
+///
+/// If this monitor was attached to an existing process this method returns
+/// -1.
+int
+ProcessMonitorSelf::GetTerminalFD() const {
+    return m_terminal_fd;
+}
+
+/// Reads @p size bytes from address @vm_adder in the inferior process
+/// address space.
+///
+/// This method is provided to implement Process::DoReadMemory.
+size_t
+ProcessMonitorSelf::ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+           lldb_private::Error &error)
+{
+    memcpy(buf, (void *) vm_addr, size);
+    return size;
+}
+
+/// Writes @p size bytes from address @p vm_adder in the inferior process
+/// address space.
+///
+/// This method is provided to implement Process::DoWriteMemory.
+size_t
+ProcessMonitorSelf::WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
+            lldb_private::Error &error)
+{
+    memcpy((void *) vm_addr, buf, size);
+    return size;
+}
+
+/// Reads the contents from the register identified by the given (architecture
+/// dependent) offset.
+///
+/// This method is provided for use by RegisterContextLinux derivatives.
+bool
+ProcessMonitorSelf::ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,
+                  unsigned size, lldb_private::RegisterValue &value)
+{
+    assert(false);
+}
+
+/// Writes the given value to the register identified by the given
+/// (architecture dependent) offset.
+///
+/// This method is provided for use by RegisterContextLinux derivatives.
+bool
+ProcessMonitorSelf::WriteRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,
+                   const lldb_private::RegisterValue &value)
+{
+    assert(false);
+}
+
+/// Reads all general purpose registers into the specified buffer.
+bool
+ProcessMonitorSelf::ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+    assert(false);
+}
+
+/// Reads generic floating point registers into the specified buffer.
+bool
+ProcessMonitorSelf::ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+    assert(false);
+}
+
+/// Reads the specified register set into the specified buffer.
+/// For instance, the extended floating-point register set.
+bool
+ProcessMonitorSelf::ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
+{
+    assert(false);
+}
+
+/// Writes all general purpose registers into the specified buffer.
+bool
+ProcessMonitorSelf::WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+    assert(false);
+}
+
+/// Writes generic floating point registers into the specified buffer.
+bool
+ProcessMonitorSelf::WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size)
+{
+    assert(false);
+}
+
+/// Writes the specified register set into the specified buffer.
+/// For instance, the extended floating-point register set.
+bool
+ProcessMonitorSelf::WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset)
+{
+    assert(false);
+}
+
+/// Reads the value of the thread-specific pointer for a given thread ID.
+bool
+ProcessMonitorSelf::ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value)
+{
+    assert(false);
+}
+
+/// Resumes the given thread.  If @p signo is anything but
+/// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+bool
+ProcessMonitorSelf::Resume(lldb::tid_t tid, uint32_t signo)
+{
+    assert(false);
+}
+
+/// Single steps the given thread.  If @p signo is anything but
+/// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+bool
+ProcessMonitorSelf::SingleStep(lldb::tid_t tid, uint32_t signo)
+{
+    assert(false);
+}
+
+/// Terminate the traced process.
+bool
+ProcessMonitorSelf::Kill()
+{
+    exit(EXIT_SUCCESS);
+}
+
+lldb_private::Error
+ProcessMonitorSelf::Detach(lldb::tid_t tid)
+{
+    return Error();
+}
+
+/// Stops the monitoring the child process thread.
+void
+ProcessMonitorSelf::StopMonitor()
+{}
+
+/// Stops the requested thread and waits for the stop signal.
+bool
+ProcessMonitorSelf::StopThread(lldb::tid_t tid)
+{
+    assert(false);
+}
+
+// Waits for the initial stop message from a new thread.
+bool
+ProcessMonitorSelf::WaitForInitialTIDStop(lldb::tid_t tid)
+{
+    assert(false);
+}
diff --git a/source/Plugins/Process/Linux/ProcessMonitorSelf.h b/source/Plugins/Process/Linux/ProcessMonitorSelf.h
new file mode 100644
index 0000000..4b4a4e4
--- /dev/null
+++ b/source/Plugins/Process/Linux/ProcessMonitorSelf.h
@@ -0,0 +1,164 @@
+//===-- ProcessMonitorSelf.h -------------------------------------- -*- C++ -*-===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef liblldb_ProcessMonitorSelf_H_
+#define liblldb_ProcessMonitorSelf_H_
+
+// C Includes
+#include <semaphore.h>
+#include <signal.h>
+
+// C++ Includes
+// Self libraries and framework includes
+#include "lldb/lldb-types.h"
+#include "lldb/Host/Mutex.h"
+
+#include "ProcessMonitor.h"
+
+namespace lldb_private
+{
+class Error;
+class Module;
+class Scalar;
+} // End lldb_private namespace.
+
+class ProcessLinux;
+class Operation;
+
+/// @class ProcessMonitorSelf
+/// @brief Manages communication with the inferior (debugee) process.
+///
+/// Upon construction, this class prepares and launches an inferior process for
+/// debugging.
+///
+/// Changes in the inferior process state are propagated to the associated
+/// ProcessLinux instance by calling ProcessLinux::SendMessage with the
+/// appropriate ProcessMessage events.
+///
+/// A purposely minimal set of operations are provided to interrogate and change
+/// the inferior process state.
+class ProcessMonitorSelf : public ProcessMonitor
+{
+public:
+    ProcessMonitorSelf(ProcessPOSIX *process, lldb_private::Error &error);
+    ~ProcessMonitorSelf();
+
+    /// Provides the process number of debugee.
+    lldb::pid_t
+    GetPID() const;
+
+    /// Returns a file descriptor to the controlling terminal of the inferior
+    /// process.
+    ///
+    /// Reads from this file descriptor yield both the standard output and
+    /// standard error of this debugee.  Even if stderr and stdout were
+    /// redirected on launch it may still happen that data is available on this
+    /// descriptor (if the inferior process opens /dev/tty, for example).
+    ///
+    /// If this monitor was attached to an existing process this method returns
+    /// -1.
+    int
+    GetTerminalFD() const;
+
+    /// Reads @p size bytes from address @vm_adder in the inferior process
+    /// address space.
+    ///
+    /// This method is provided to implement Process::DoReadMemory.
+    size_t
+    ReadMemory(lldb::addr_t vm_addr, void *buf, size_t size,
+               lldb_private::Error &error);
+
+    /// Writes @p size bytes from address @p vm_adder in the inferior process
+    /// address space.
+    ///
+    /// This method is provided to implement Process::DoWriteMemory.
+    size_t
+    WriteMemory(lldb::addr_t vm_addr, const void *buf, size_t size,
+                lldb_private::Error &error);
+
+    /// Reads the contents from the register identified by the given (architecture
+    /// dependent) offset.
+    ///
+    /// This method is provided for use by RegisterContextLinux derivatives.
+    bool
+    ReadRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,
+                      unsigned size, lldb_private::RegisterValue &value);
+
+    /// Writes the given value to the register identified by the given
+    /// (architecture dependent) offset.
+    ///
+    /// This method is provided for use by RegisterContextLinux derivatives.
+    bool
+    WriteRegisterValue(lldb::tid_t tid, unsigned offset, const char *reg_name,
+                       const lldb_private::RegisterValue &value);
+
+    /// Reads all general purpose registers into the specified buffer.
+    bool
+    ReadGPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+    /// Reads generic floating point registers into the specified buffer.
+    bool
+    ReadFPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+    /// Reads the specified register set into the specified buffer.
+    /// For instance, the extended floating-point register set.
+    bool
+    ReadRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset);
+
+    /// Writes all general purpose registers into the specified buffer.
+    bool
+    WriteGPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+    /// Writes generic floating point registers into the specified buffer.
+    bool
+    WriteFPR(lldb::tid_t tid, void *buf, size_t buf_size);
+
+    /// Writes the specified register set into the specified buffer.
+    /// For instance, the extended floating-point register set.
+    bool
+    WriteRegisterSet(lldb::tid_t tid, void *buf, size_t buf_size, unsigned int regset);
+
+    /// Reads the value of the thread-specific pointer for a given thread ID.
+    bool
+    ReadThreadPointer(lldb::tid_t tid, lldb::addr_t &value);
+
+    /// Resumes the given thread.  If @p signo is anything but
+    /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+    bool
+    Resume(lldb::tid_t tid, uint32_t signo);
+
+    /// Single steps the given thread.  If @p signo is anything but
+    /// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
+    bool
+    SingleStep(lldb::tid_t tid, uint32_t signo);
+
+    /// Terminate the traced process.
+    bool
+    Kill();
+
+    lldb_private::Error
+    Detach(lldb::tid_t tid);
+
+    /// Stops the monitoring the child process thread.
+    void
+    StopMonitor();
+
+    /// Stops the requested thread and waits for the stop signal.
+    bool
+    StopThread(lldb::tid_t tid);
+
+    // Waits for the initial stop message from a new thread.
+    bool
+    WaitForInitialTIDStop(lldb::tid_t tid);
+
+private:
+    int m_terminal_fd;
+};
+
+#endif // #ifndef liblldb_ProcessMonitorSelf_H_
diff --git a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
index 8333f01..fef629e 100644
--- a/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
+++ b/source/Plugins/Process/POSIX/ProcessPOSIX.cpp
@@ -11,6 +11,8 @@
 
 // C Includes
 #include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
 
 // C++ Includes
 // Other libraries and framework includes
@@ -30,6 +32,7 @@
 #include "Plugins/Process/Utility/InferiorCallPOSIX.h"
 #include "ProcessMonitor.h"
 #include "ProcessMonitorOther.h"
+#include "ProcessMonitorSelf.h"
 #include "POSIXThread.h"
 
 using namespace lldb;
@@ -124,7 +127,11 @@ ProcessPOSIX::DoAttachToProcessWithID(lldb::pid_t pid)
     if (log && log->GetMask().Test(POSIX_LOG_VERBOSE))
         log->Printf ("ProcessPOSIX::%s(pid = %" PRIi64 ")", __FUNCTION__, GetID());
 
-    m_monitor = new ProcessMonitorOther(this, pid, error);
+    if ((::pid_t) pid == getpid()) {
+      m_monitor = new ProcessMonitorSelf(this, error);
+    } else {
+      m_monitor = new ProcessMonitorOther(this, pid, error);
+    }
 
     if (!error.Success())
         return error;
-- 
2.1.0.rc2.206.gedb03e5




More information about the lldb-dev mailing list