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 + +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; +}