diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp --- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp +++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp @@ -56,6 +56,19 @@ "%s resolved via direct object file approach to 0x%" PRIx64, __FUNCTION__, info_location); } else { + const Symbol *_r_debug = + target->GetExecutableModule()->FindFirstSymbolWithNameAndType( + ConstString("_r_debug")); + if (_r_debug) { + info_addr = _r_debug->GetAddress().GetLoadAddress(target); + if (info_addr != LLDB_INVALID_ADDRESS) { + LLDB_LOGF(log, + "%s resolved by finding symbol '_r_debug' whose value is " + "0x%" PRIx64, + __FUNCTION__, info_addr); + return info_addr; + } + } LLDB_LOGF(log, "%s FAILED - direct object file approach did not yield a " "valid address", diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp --- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -333,28 +333,48 @@ LLDB_LOG(log, "Rendezvous structure is not set up yet. " "Trying to locate rendezvous breakpoint in the interpreter " "by symbol name."); - ModuleSP interpreter = LoadInterpreterModule(); - if (!interpreter) { - LLDB_LOG(log, "Can't find interpreter, rendezvous breakpoint isn't set."); - return false; - } - - // Function names from different dynamic loaders that are known to be used - // as rendezvous between the loader and debuggers. + // Function names from different dynamic loaders that are known to be + // used as rendezvous between the loader and debuggers. static std::vector DebugStateCandidates{ "_dl_debug_state", "rtld_db_dlactivity", "__dl_rtld_db_dlactivity", "r_debug_state", "_r_debug_state", "_rtld_debug_state", }; - FileSpecList containingModules; - containingModules.Append(interpreter->GetFileSpec()); - dyld_break = target.CreateBreakpoint( - &containingModules, nullptr /* containingSourceFiles */, - DebugStateCandidates, eFunctionNameTypeFull, eLanguageTypeC, - 0, /* offset */ - eLazyBoolNo, /* skip_prologue */ - true, /* internal */ - false /* request_hardware */); + ModuleSP interpreter = LoadInterpreterModule(); + if (!interpreter) { + if (NameMatches(m_process->GetTarget() + .GetExecutableModulePointer() + ->GetFileSpec() + .GetFilename() + .GetCString(), + NameMatch::StartsWith, "ld-")) { + FileSpecList containingModules; + containingModules.Append( + m_process->GetTarget().GetExecutableModulePointer()->GetFileSpec()); + + dyld_break = target.CreateBreakpoint( + &containingModules, /*containingSourceFiles=*/nullptr, + DebugStateCandidates, eFunctionNameTypeFull, eLanguageTypeC, + /*offset=*/0, + /*skip_prologue=*/eLazyBoolNo, + /*internal=*/true, + /*request_hardware=*/false); + } else { + LLDB_LOG(log, + "Can't find interpreter, rendezvous breakpoint isn't set."); + return false; + } + } else { + FileSpecList containingModules; + containingModules.Append(interpreter->GetFileSpec()); + dyld_break = target.CreateBreakpoint( + &containingModules, /*containingSourceFiles=*/nullptr, + DebugStateCandidates, eFunctionNameTypeFull, eLanguageTypeC, + /*offset=*/0, + /*skip_prologue=*/eLazyBoolNo, + /*internal=*/true, + /*request_hardware=*/false); + } } if (dyld_break->GetNumResolvedLocations() != 1) { diff --git a/lldb/test/API/functionalities/dyld-launch-linux/Makefile b/lldb/test/API/functionalities/dyld-launch-linux/Makefile new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/dyld-launch-linux/Makefile @@ -0,0 +1,15 @@ +CXX_SOURCES := main.cpp +LD_EXTRAS := -Wl,-rpath "-Wl,$(shell pwd)" +USE_LIBDL := 1 + +include Makefile.rules + +# The following shared library will be used to test breakpoints under dynamic loading +libsignal_file.so: signal_file.cpp + $(MAKE) -f $(MAKEFILE_RULES) \ + DYLIB_ONLY=YES DYLIB_CXX_SOURCES=signal_file.cpp DYLIB_NAME=signal_file + +a.out: libsignal_file.so main.cpp + $(MAKE) -f $(MAKEFILE_RULES) \ + CXX_SOURCES=main.cpp LD_EXTRAS=libsignal_file.so + diff --git a/lldb/test/API/functionalities/dyld-launch-linux/TestDyldLaunchLinux.py b/lldb/test/API/functionalities/dyld-launch-linux/TestDyldLaunchLinux.py new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/dyld-launch-linux/TestDyldLaunchLinux.py @@ -0,0 +1,31 @@ +""" +Test that LLDB can launch a linux executable through the dynamic loader and still hit a breakpoint. +""" + +import lldb +import os + +from lldbsuite.test.decorators import * +from lldbsuite.test.lldbtest import * +from lldbsuite.test import lldbutil + +class TestLinux64LaunchingViaDynamicLoader(TestBase): + mydir = TestBase.compute_mydir(__file__) + + def test(self): + """Test we can launch and hit a breakpoint when we run our program through the dynamic loader""" + self.build() + exe = "/lib64/ld-linux-x86-64.so.2" + + if(os.path.exists(exe)): + # Create a target by the debugger. + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + process = target.LaunchSimple( + ["--library-path",self.get_process_working_directory(),self.getBuildArtifact("a.out")], None, self.get_process_working_directory()) + + self.assertEqual(process.GetState(), lldb.eStateStopped) + thread = process.GetSelectedThread() + self.assertEqual(thread.GetStopReason(), lldb.eStopReasonSignal) + self.assertIn("raise",thread.GetFrameAtIndex(0).GetDisplayFunctionName()) + self.assertIn("get_signal_crash",thread.GetFrameAtIndex(1).GetDisplayFunctionName()) diff --git a/lldb/test/API/functionalities/dyld-launch-linux/main.cpp b/lldb/test/API/functionalities/dyld-launch-linux/main.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/dyld-launch-linux/main.cpp @@ -0,0 +1,3 @@ +#include "signal_file.h" + +int main() { return get_signal_crash(); } diff --git a/lldb/test/API/functionalities/dyld-launch-linux/signal_file.h b/lldb/test/API/functionalities/dyld-launch-linux/signal_file.h new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/dyld-launch-linux/signal_file.h @@ -0,0 +1 @@ +int get_signal_crash(void); diff --git a/lldb/test/API/functionalities/dyld-launch-linux/signal_file.cpp b/lldb/test/API/functionalities/dyld-launch-linux/signal_file.cpp new file mode 100644 --- /dev/null +++ b/lldb/test/API/functionalities/dyld-launch-linux/signal_file.cpp @@ -0,0 +1,7 @@ +#include "signal_file.h" +#include + +int get_signal_crash(void) { + raise(SIGSEGV); + return 0; +}