Index: packages/Python/lldbsuite/test/functionalities/breakpoint/global_constructor/TestBreakpointInGlobalConstructor.py =================================================================== --- packages/Python/lldbsuite/test/functionalities/breakpoint/global_constructor/TestBreakpointInGlobalConstructor.py +++ packages/Python/lldbsuite/test/functionalities/breakpoint/global_constructor/TestBreakpointInGlobalConstructor.py @@ -21,11 +21,26 @@ TestBase.setUp(self) self.line_foo = line_number('foo.cpp', '// !BR_foo') self.line_main = line_number('main.cpp', '// !BR_main') + if not self.platformIsDarwin(): + if lldb.remote_platform: + wd = lldb.remote_platform.GetWorkingDirectory() + else: + wd = os.getcwd() + self.runCmd( + "settings set target.env-vars " + + self.dylibPath + + "=" + + wd) + - @expectedFailureAll(bugnumber="llvm.org/pr35480", oslist=["linux"]) def test(self): self.build() exe = os.path.join(os.getcwd(), "a.out") + + target = self.dbg.CreateTarget("a.out") + self.assertTrue(target, VALID_TARGET) + self.registerSharedLibrariesWithTarget(target, ["foo"]) + self.runCmd("file %s" % exe) bp_main = lldbutil.run_break_set_by_file_and_line( Index: packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py =================================================================== --- packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py +++ packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py @@ -368,7 +368,6 @@ @skipIfFreeBSD # llvm.org/pr14424 - missing FreeBSD Makefiles/testcase support @skipIfWindows # Windows doesn't have dlopen and friends, dynamic libraries work differently - @unittest2.expectedFailure("llvm.org/pr25806") def test_static_init_during_load(self): """Test that we can set breakpoints correctly in static initializers""" @@ -395,19 +394,19 @@ self.runCmd("continue") self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, substrs=['stopped', - 'a_init', - 'stop reason = breakpoint %d' % a_init_bp_num]) + 'b_init', + 'stop reason = breakpoint %d' % b_init_bp_num]) self.expect("thread backtrace", - substrs=['a_init', + substrs=['b_init', 'dlopen', 'main']) self.runCmd("continue") self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, substrs=['stopped', - 'b_init', - 'stop reason = breakpoint %d' % b_init_bp_num]) + 'a_init', + 'stop reason = breakpoint %d' % a_init_bp_num]) self.expect("thread backtrace", - substrs=['b_init', + substrs=['a_init', 'dlopen', 'main']) Index: source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h =================================================================== --- source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h +++ source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h @@ -85,13 +85,17 @@ /// mapped to the address space lldb::addr_t m_vdso_base; + /// Contains AT_BASE, which means a dynamic loader has been + /// mapped to the address space + lldb::addr_t m_interpreter_base; + /// Loaded module list. (link map for each module) std::map> m_loaded_modules; - /// Enables a breakpoint on a function called by the runtime + /// If possible sets a breakpoint on a function called by the runtime /// linker each time a module is loaded or unloaded. - virtual void SetRendezvousBreakpoint(); + bool SetRendezvousBreakpoint(); /// Callback routine which updates the current list of loaded modules based /// on the information supplied by the runtime linker. @@ -138,7 +142,11 @@ /// of all dependent modules. virtual void LoadAllCurrentModules(); - void LoadVDSO(lldb_private::ModuleList &modules); + void LoadVDSO(); + + // Loading an interpreter module (if present) assumming m_interpreter_base + // already points to its base address. + lldb::ModuleSP LoadInterpreterModule(); /// Computes a value for m_load_offset returning the computed address on /// success and LLDB_INVALID_ADDRESS on failure. @@ -148,9 +156,10 @@ /// success and LLDB_INVALID_ADDRESS on failure. lldb::addr_t GetEntryPoint(); - /// Evaluate if Aux vectors contain vDSO information + /// Evaluate if Aux vectors contain vDSO and LD information /// in case they do, read and assign the address to m_vdso_base - void EvalVdsoStatus(); + /// and m_interpreter_base. + void EvalSpecialModulesStatus(); /// Loads Module from inferior process. void ResolveExecutableModule(lldb::ModuleSP &module_sp); Index: source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp =================================================================== --- source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp @@ -79,7 +79,8 @@ : DynamicLoader(process), m_rendezvous(process), m_load_offset(LLDB_INVALID_ADDRESS), m_entry_point(LLDB_INVALID_ADDRESS), m_auxv(), m_dyld_bid(LLDB_INVALID_BREAK_ID), - m_vdso_base(LLDB_INVALID_ADDRESS) {} + m_vdso_base(LLDB_INVALID_ADDRESS), + m_interpreter_base(LLDB_INVALID_ADDRESS) {} DynamicLoaderPOSIXDYLD::~DynamicLoaderPOSIXDYLD() { if (m_dyld_bid != LLDB_INVALID_BREAK_ID) { @@ -117,7 +118,7 @@ : "", load_offset); - EvalVdsoStatus(); + EvalSpecialModulesStatus(); // if we dont have a load address we cant re-base bool rebase_exec = (load_offset == LLDB_INVALID_ADDRESS) ? false : true; @@ -207,7 +208,7 @@ executable = GetTargetExecutable(); load_offset = ComputeLoadOffset(); - EvalVdsoStatus(); + EvalSpecialModulesStatus(); if (executable.get() && load_offset != LLDB_INVALID_ADDRESS) { ModuleList module_list; @@ -217,7 +218,12 @@ if (log) log->Printf("DynamicLoaderPOSIXDYLD::%s about to call ProbeEntry()", __FUNCTION__); - ProbeEntry(); + + if (!SetRendezvousBreakpoint()) { + // If we cannot establish rendezvous breakpoint right now + // we'll try again at enty point. + ProbeEntry(); + } m_process->GetTarget().ModulesDidLoad(module_list); } @@ -329,38 +335,72 @@ return false; // Continue running. } -void DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint() { +bool DynamicLoaderPOSIXDYLD::SetRendezvousBreakpoint() { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + if (m_dyld_bid != LLDB_INVALID_BREAK_ID) { + LLDB_LOG(log, + "Rendezvous breakpoint breakpoint id {0} for pid {1}" + "is already set.", + m_dyld_bid, + m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); + return true; + } - addr_t break_addr = m_rendezvous.GetBreakAddress(); + addr_t break_addr; Target &target = m_process->GetTarget(); - if (m_dyld_bid == LLDB_INVALID_BREAK_ID) { - if (log) - log->Printf("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 - " setting rendezvous break address at 0x%" PRIx64, - __FUNCTION__, - m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID, - break_addr); - Breakpoint *dyld_break = - target.CreateBreakpoint(break_addr, true, false).get(); - dyld_break->SetCallback(RendezvousBreakpointHit, this, true); - dyld_break->SetBreakpointKind("shared-library-event"); - m_dyld_bid = dyld_break->GetID(); + if (m_rendezvous.IsValid()) { + break_addr = m_rendezvous.GetBreakAddress(); } else { - if (log) - log->Printf("DynamicLoaderPOSIXDYLD::%s pid %" PRIu64 - " reusing break id %" PRIu32 ", address at 0x%" PRIx64, - __FUNCTION__, - m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID, - m_dyld_bid, break_addr); + 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; + } + + const Symbol *symbol = nullptr; + static const char *DebugStateCandidates[] = { + "_dl_debug_state", "rtld_db_dlactivity", "__dl_rtld_db_dlactivity", + "r_debug_state", "_r_debug_state", "_rtld_debug_state", + }; + + for (auto name : DebugStateCandidates) { + symbol = interpreter->FindFirstSymbolWithNameAndType(ConstString(name)); + if (symbol) + break; + } + if (symbol == nullptr) { + LLDB_LOG(log, "Can't find debug state function in the interpreter."); + return false; + } + break_addr = symbol->GetLoadAddress(&m_process->GetTarget()); + if (break_addr == LLDB_INVALID_ADDRESS) { + LLDB_LOG(log, "Can't resolve address of debug state function {0}.", + symbol->GetName()); + return false; + } else { + LLDB_LOG( + log, + "Function {0} from module {1} will be used as rendezvous breakpoint.", + symbol->GetName(), interpreter->GetFileSpec().GetFilename()); + } } - // Make sure our breakpoint is at the right address. - assert(target.GetBreakpointByID(m_dyld_bid) - ->FindLocationByAddress(break_addr) - ->GetBreakpoint() - .GetID() == m_dyld_bid); + LLDB_LOG(log, "Setting rendezvous break address for pid {0} at {1:x}", + m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID, + break_addr); + Breakpoint *dyld_break = + target.CreateBreakpoint(break_addr, true, false).get(); + dyld_break->SetCallback(RendezvousBreakpointHit, this, true); + dyld_break->SetBreakpointKind("shared-library-event"); + if (dyld_break->GetNumResolvedLocations() == 0) + return false; + + m_dyld_bid = dyld_break->GetID(); + return true; } bool DynamicLoaderPOSIXDYLD::RendezvousBreakpointHit( @@ -485,7 +525,7 @@ return thread_plan_sp; } -void DynamicLoaderPOSIXDYLD::LoadVDSO(ModuleList &modules) { +void DynamicLoaderPOSIXDYLD::LoadVDSO() { if (m_vdso_base == LLDB_INVALID_ADDRESS) return; @@ -506,13 +546,38 @@ } } +ModuleSP DynamicLoaderPOSIXDYLD::LoadInterpreterModule() { + if (m_interpreter_base == LLDB_INVALID_ADDRESS) + return nullptr; + + MemoryRegionInfo info; + Target &target = m_process->GetTarget(); + Status status = m_process->GetMemoryRegionInfo(m_interpreter_base, info); + if (status.Fail() || info.GetMapped() != MemoryRegionInfo::eYes || + info.GetName().IsEmpty()) { + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); + LLDB_LOG(log, "Failed to get interpreter region info: {0}", status); + return nullptr; + } + + FileSpec file(info.GetName().GetCString(), false); + ModuleSpec module_spec(file, target.GetArchitecture()); + + if (ModuleSP module_sp = target.GetSharedModule(module_spec)) { + UpdateLoadedSections(module_sp, LLDB_INVALID_ADDRESS, m_interpreter_base, + false); + return module_sp; + } + return nullptr; +} + void DynamicLoaderPOSIXDYLD::LoadAllCurrentModules() { DYLDRendezvous::iterator I; DYLDRendezvous::iterator E; ModuleList module_list; + Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); if (!m_rendezvous.Resolve()) { - Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); if (log) log->Printf("DynamicLoaderPOSIXDYLD::%s unable to resolve POSIX DYLD " "rendezvous address", @@ -524,7 +589,7 @@ // that ourselves here. ModuleSP executable = GetTargetExecutable(); m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress(); - LoadVDSO(module_list); + LoadVDSO(); std::vector module_names; for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I) @@ -536,6 +601,8 @@ ModuleSP module_sp = LoadModuleAtAddress(I->file_spec, I->link_addr, I->base_addr, true); if (module_sp.get()) { + LLDB_LOG(log, "LoadAllCurrentModules loading module: {0}", + I->file_spec.GetFilename()); module_list.Append(module_sp); } else { Log *log(GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER)); @@ -575,11 +642,14 @@ return m_load_offset; } -void DynamicLoaderPOSIXDYLD::EvalVdsoStatus() { - AuxVector::iterator I = m_auxv->FindEntry(AuxVector::AUXV_AT_SYSINFO_EHDR); - - if (I != m_auxv->end()) +void DynamicLoaderPOSIXDYLD::EvalSpecialModulesStatus() { + auto I = m_auxv->FindEntry(AuxVector::AUXV_AT_SYSINFO_EHDR); + if (I != m_auxv->end() && I->value != 0) m_vdso_base = I->value; + + I = m_auxv->FindEntry(AuxVector::AUXV_AT_BASE); + if (I != m_auxv->end() && I->value != 0) + m_interpreter_base = I->value; } addr_t DynamicLoaderPOSIXDYLD::GetEntryPoint() {