rdhindsa updated this revision to Diff 371425.
rdhindsa marked 2 inline comments as done.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D108061/new/
https://reviews.llvm.org/D108061
Files:
lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h
lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
lldb/test/API/functionalities/dyld-launch-linux/Makefile
lldb/test/API/functionalities/dyld-launch-linux/TestDyldLaunchLinux.py
lldb/test/API/functionalities/dyld-launch-linux/main.cpp
lldb/test/API/functionalities/dyld-launch-linux/signal_file.cpp
lldb/test/API/functionalities/dyld-launch-linux/signal_file.h
Index: lldb/test/API/functionalities/dyld-launch-linux/signal_file.h
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/dyld-launch-linux/signal_file.h
@@ -0,0 +1 @@
+int get_signal_crash();
Index: lldb/test/API/functionalities/dyld-launch-linux/signal_file.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/dyld-launch-linux/signal_file.cpp
@@ -0,0 +1,7 @@
+#include "signal_file.h"
+#include <signal.h>
+
+int get_signal_crash(void) {
+ raise(SIGSEGV);
+ return 0;
+}
Index: lldb/test/API/functionalities/dyld-launch-linux/main.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/dyld-launch-linux/main.cpp
@@ -0,0 +1,6 @@
+#include "signal_file.h"
+
+int main() {
+ // Break here
+ return get_signal_crash();
+}
Index: lldb/test/API/functionalities/dyld-launch-linux/TestDyldLaunchLinux.py
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/dyld-launch-linux/TestDyldLaunchLinux.py
@@ -0,0 +1,52 @@
+"""
+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 *
+
+class TestLinux64LaunchingViaDynamicLoader(TestBase):
+ mydir = TestBase.compute_mydir(__file__)
+
+ @skipIf(oslist=no_match(['linux']))
+ @no_debug_info_test
+ def test(self):
+ self.build()
+ candidates = [
+ "/lib64/ld-linux-x86-64.so.2",
+ "/usr/lib/ld-linux-x86-64.so.2"
+ ]
+ exe = next((c for c in candidates if os.path.exists(c)), None)
+ if not os.path.exists(exe):
+ return
+ target = self.dbg.CreateTarget(exe)
+ self.assertTrue(target, VALID_TARGET)
+
+ # Set breakpoints both on shared library function as well as on
+ # main. Both of them will be pending breakpoints.
+ breakpoint_main = target.BreakpointCreateBySourceRegex("// Break here", lldb.SBFileSpec("main.cpp"))
+ breakpoint_shared_library = target.BreakpointCreateBySourceRegex("get_signal_crash", lldb.SBFileSpec("signal_file.cpp"))
+ launch_info = lldb.SBLaunchInfo([ "--library-path", self.get_process_working_directory(), self.getBuildArtifact("a.out")])
+ launch_info.SetWorkingDirectory(self.get_process_working_directory())
+ error = lldb.SBError()
+ process = target.Launch(launch_info, error)
+ self.assertTrue(error.Success())
+
+ # Stopped on main here.
+ self.assertEqual(process.GetState(), lldb.eStateStopped)
+ thread = process.GetSelectedThread()
+ self.assertIn("main", thread.GetFrameAtIndex(0).GetDisplayFunctionName())
+ process.Continue()
+
+ # Stopped on get_signal_crash function here.
+ self.assertEqual(process.GetState(), lldb.eStateStopped)
+ self.assertIn("get_signal_crash", thread.GetFrameAtIndex(0).GetDisplayFunctionName())
+ process.Continue()
+
+ # Stopped because of generated signal.
+ self.assertEqual(process.GetState(), lldb.eStateStopped)
+ self.assertIn("raise", thread.GetFrameAtIndex(0).GetDisplayFunctionName())
+ self.assertIn("get_signal_crash", thread.GetFrameAtIndex(1).GetDisplayFunctionName())
Index: lldb/test/API/functionalities/dyld-launch-linux/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/functionalities/dyld-launch-linux/Makefile
@@ -0,0 +1,4 @@
+CXX_SOURCES := main.cpp
+DYLIB_NAME := signal_file
+DYLIB_CXX_SOURCES := signal_file.cpp
+include Makefile.rules
Index: lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
===================================================================
--- lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
+++ lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -333,28 +333,37 @@
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<std::string> 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) {
+ 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 {
+ 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) {
Index: lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h
===================================================================
--- lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h
+++ lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.h
@@ -183,6 +183,9 @@
/// Location of the r_debug structure in the inferiors address space.
lldb::addr_t m_rendezvous_addr;
+ /// It is set to true when executable is run with argv[0] as ld.so.
+ bool m_executable_interpreter;
+
/// Current and previous snapshots of the rendezvous structure.
Rendezvous m_current;
Rendezvous m_previous;
@@ -246,6 +249,8 @@
void UpdateBaseAddrIfNecessary(SOEntry &entry, std::string const &file_path);
+ void UpdateFileSpecIfNecessary(SOEntry &entry);
+
bool SOEntryIsMainExecutable(const SOEntry &entry);
/// Reads the current list of shared objects according to the link map
Index: lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
===================================================================
--- lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
+++ lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp
@@ -25,8 +25,10 @@
using namespace lldb_private;
/// Locates the address of the rendezvous structure. Returns the address on
-/// success and LLDB_INVALID_ADDRESS on failure.
-static addr_t ResolveRendezvousAddress(Process *process) {
+/// success and LLDB_INVALID_ADDRESS on failure. It updates
+/// m_executable_interpreter if address is extracted from _r_debug.
+static addr_t ResolveRendezvousAddress(Process *process,
+ bool &m_executable_interpreter) {
Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER));
addr_t info_location;
addr_t info_addr;
@@ -56,6 +58,20 @@
"%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);
+ m_executable_interpreter = true;
+ return info_addr;
+ }
+ }
LLDB_LOGF(log,
"%s FAILED - direct object file approach did not yield a "
"valid address",
@@ -91,8 +107,9 @@
}
DYLDRendezvous::DYLDRendezvous(Process *process)
- : m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS), m_current(),
- m_previous(), m_loaded_modules(), m_soentries(), m_added_soentries(),
+ : m_process(process), m_rendezvous_addr(LLDB_INVALID_ADDRESS),
+ m_executable_interpreter(false), m_current(), m_previous(),
+ m_loaded_modules(), m_soentries(), m_added_soentries(),
m_removed_soentries() {
m_thread_info.valid = false;
UpdateExecutablePath();
@@ -132,7 +149,8 @@
__FUNCTION__, uint64_t(address_size), uint64_t(padding));
if (m_rendezvous_addr == LLDB_INVALID_ADDRESS)
- cursor = info_addr = ResolveRendezvousAddress(m_process);
+ cursor = info_addr =
+ ResolveRendezvousAddress(m_process, m_executable_interpreter);
else
cursor = info_addr = m_rendezvous_addr;
LLDB_LOGF(log, "DYLDRendezvous::%s cursor = 0x%" PRIx64, __FUNCTION__,
@@ -296,8 +314,11 @@
return false;
// Only add shared libraries and not the executable.
- if (!SOEntryIsMainExecutable(entry))
+ if (!SOEntryIsMainExecutable(entry)) {
+ if (entry.file_spec.GetFilename().IsEmpty())
+ UpdateFileSpecIfNecessary(entry);
m_soentries.push_back(entry);
+ }
}
m_loaded_modules = module_list;
@@ -324,6 +345,8 @@
// Only add shared libraries and not the executable.
if (!SOEntryIsMainExecutable(entry)) {
+ if (entry.file_spec.GetFilename().IsEmpty())
+ UpdateFileSpecIfNecessary(entry);
m_soentries.push_back(entry);
m_added_soentries.push_back(entry);
}
@@ -383,6 +406,9 @@
if (SOEntryIsMainExecutable(entry))
continue;
+ if (entry.file_spec.GetFilename().IsEmpty())
+ UpdateFileSpecIfNecessary(entry);
+
pos = std::find(m_soentries.begin(), m_soentries.end(), entry);
if (pos == m_soentries.end()) {
m_soentries.push_back(entry);
@@ -424,6 +450,11 @@
case llvm::Triple::Linux:
if (triple.isAndroid())
return entry.file_spec == m_exe_file_spec;
+ // When executable is run with argv[0] as ld.so, ld.so corresponds to
+ // m_exe_file_spec. In this case, the returned link map
+ // has empty entry for executable, which is not the main executable.
+ if (!entry.file_spec && m_executable_interpreter)
+ return false;
return !entry.file_spec;
default:
return false;
@@ -447,6 +478,9 @@
if (SOEntryIsMainExecutable(entry))
continue;
+ if (entry.file_spec.GetFilename().IsEmpty())
+ UpdateFileSpecIfNecessary(entry);
+
entry_list.push_back(entry);
}
@@ -512,6 +546,18 @@
}
}
+void DYLDRendezvous::UpdateFileSpecIfNecessary(SOEntry &entry) {
+ // ld.so saves empty file name for the executable file in the link map.
+ // When argv[0] is ld.so, we need to be update executable path.
+ if (entry.file_spec.GetFilename().IsEmpty()) {
+ MemoryRegionInfo region;
+ Status region_status =
+ m_process->GetMemoryRegionInfo(entry.dyn_addr, region);
+ std::string file_path = region.GetName().AsCString();
+ entry.file_spec.SetFile(file_path, FileSpec::Style::native);
+ }
+}
+
bool DYLDRendezvous::ReadSOEntryFromMemory(lldb::addr_t addr, SOEntry &entry) {
entry.clear();
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits