[Lldb-commits] [lldb] 879a47a - Add the ability to debug through an exec into ld

Greg Clayton via lldb-commits lldb-commits at lists.llvm.org
Mon May 9 16:07:47 PDT 2022


Author: Greg Clayton
Date: 2022-05-09T16:07:40-07:00
New Revision: 879a47a55ffb94976cbac1d191ef53be135d86a7

URL: https://github.com/llvm/llvm-project/commit/879a47a55ffb94976cbac1d191ef53be135d86a7
DIFF: https://github.com/llvm/llvm-project/commit/879a47a55ffb94976cbac1d191ef53be135d86a7.diff

LOG: Add the ability to debug through an exec into ld

A previous commit enabled LLDB to be able to debug a program launched via ld: https://reviews.llvm.org/D108061.

This commit adds the ability to debug a program launched via ld when it happens during an exec into the dynamic loader. There was an issue where after the exec we would locate the rendezvous structure right away but it didn't contain any valid values and we would try to set the dyanamic loader breakpoint at address zero. This patch fixes that and adds a test.

Differential Revision: https://reviews.llvm.org/D125253

Added: 
    lldb/test/API/functionalities/dyld-exec-linux/Makefile
    lldb/test/API/functionalities/dyld-exec-linux/TestDyldExecLinux.py
    lldb/test/API/functionalities/dyld-exec-linux/main.cpp

Modified: 
    lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp

Removed: 
    


################################################################################
diff  --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
index 7993c5906aa35..b3360dbf6158a 100644
--- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
+++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -309,7 +309,7 @@ bool DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint() {
   addr_t break_addr;
   Target &target = m_process->GetTarget();
   BreakpointSP dyld_break;
-  if (m_rendezvous.IsValid()) {
+  if (m_rendezvous.IsValid() && m_rendezvous.GetBreakAddress() != 0) {
     break_addr = m_rendezvous.GetBreakAddress();
     LLDB_LOG(log, "Setting rendezvous break address for pid {0} at {1:x}",
              m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID,
@@ -565,7 +565,7 @@ ModuleSP DynamicLoaderPOSIXDYLD::LoadInterpreterModule() {
   FileSpec file(info.GetName().GetCString());
   ModuleSpec module_spec(file, target.GetArchitecture());
 
-  if (ModuleSP module_sp = target.GetOrCreateModule(module_spec, 
+  if (ModuleSP module_sp = target.GetOrCreateModule(module_spec,
                                                     true /* notify */)) {
     UpdateLoadedSections(module_sp, LLDB_INVALID_ADDRESS, m_interpreter_base,
                          false);

diff  --git a/lldb/test/API/functionalities/dyld-exec-linux/Makefile b/lldb/test/API/functionalities/dyld-exec-linux/Makefile
new file mode 100644
index 0000000000000..3d0b98f13f3d7
--- /dev/null
+++ b/lldb/test/API/functionalities/dyld-exec-linux/Makefile
@@ -0,0 +1,2 @@
+CXX_SOURCES := main.cpp
+include Makefile.rules

diff  --git a/lldb/test/API/functionalities/dyld-exec-linux/TestDyldExecLinux.py b/lldb/test/API/functionalities/dyld-exec-linux/TestDyldExecLinux.py
new file mode 100644
index 0000000000000..2696ae1838249
--- /dev/null
+++ b/lldb/test/API/functionalities/dyld-exec-linux/TestDyldExecLinux.py
@@ -0,0 +1,61 @@
+"""
+Test that LLDB can launch a linux executable and then execs into the dynamic
+loader into this program again.
+"""
+
+import lldb
+import os
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+from lldbsuite.test import lldbutil
+
+class TestLinux64ExecViaDynamicLoader(TestBase):
+    mydir = TestBase.compute_mydir(__file__)
+
+    @skipIf(oslist=no_match(['linux']))
+    @no_debug_info_test
+    @skipIf(oslist=["linux"], archs=["arm"])
+    def test(self):
+        self.build()
+
+        # Extracts path of the interpreter.
+        exe = self.getBuildArtifact("a.out")
+
+        spec = lldb.SBModuleSpec()
+        spec.SetFileSpec(lldb.SBFileSpec(exe))
+        interp_section = lldb.SBModule(spec).FindSection(".interp")
+        if not interp_section:
+          return
+        section_data = interp_section.GetSectionData()
+        error = lldb.SBError()
+        dyld_path = section_data.GetString(error,0)
+        if error.Fail():
+          return
+
+        target = self.dbg.CreateTarget(exe)
+        self.assertTrue(target, VALID_TARGET)
+
+        # Set a breakpoint in the main function that will get hit after the
+        # program exec's via the dynamic loader. The breakpoint will only get
+        # hit if we can successfully read the shared library lists in the
+        # DynamicLoaderPOSIXDYLD.cpp when we exec into the dynamic loader.
+        breakpoint_main = target.BreakpointCreateBySourceRegex("// Break here", lldb.SBFileSpec("main.cpp"))
+        # Setup our launch info to supply the dynamic loader path to the
+        # program so it gets two args:
+        # - path to a.out
+        # - path to dynamic loader
+        launch_info = lldb.SBLaunchInfo([dyld_path])
+        error = lldb.SBError()
+        process = target.Launch(launch_info, error)
+        self.assertSuccess(error)
+
+        threads = lldbutil.get_stopped_threads(process, lldb.eStopReasonExec)
+        self.assertEqual(len(threads), 1, "We got a thread stopped for exec.")
+
+        process.Continue();
+
+        # Stopped on main here.
+        self.assertEqual(process.GetState(), lldb.eStateStopped)
+        thread = process.GetSelectedThread()
+        self.assertIn("main", thread.GetFrameAtIndex(0).GetDisplayFunctionName())

diff  --git a/lldb/test/API/functionalities/dyld-exec-linux/main.cpp b/lldb/test/API/functionalities/dyld-exec-linux/main.cpp
new file mode 100644
index 0000000000000..dddab58cb492c
--- /dev/null
+++ b/lldb/test/API/functionalities/dyld-exec-linux/main.cpp
@@ -0,0 +1,16 @@
+#include <unistd.h>
+
+int main(int argc, const char *argv[], const char *envp[]) {
+  if (argc == 2) {
+    // If we have two arguments the first is the path to this executable,
+    // the second is the path to the linux dynamic loader that we should
+    // exec with. We want to re-run this problem under the dynamic loader
+    // and make sure we can hit the breakpoint in the "else".
+    const char *interpreter = argv[1];
+    const char *this_program = argv[0];
+    const char *exec_argv[3] = {interpreter, this_program, nullptr};
+    execve(interpreter, (char *const *)exec_argv, (char *const *)envp);
+  }
+  // Break here
+  return 0;
+}


        


More information about the lldb-commits mailing list