Index: lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/global_constructor/TestBreakpointInGlobalConstructor.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/global_constructor/TestBreakpointInGlobalConstructor.py +++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/global_constructor/TestBreakpointInGlobalConstructor.py @@ -17,23 +17,23 @@ mydir = TestBase.compute_mydir(__file__) NO_DEBUG_INFO_TESTCASE = True - def setUp(self): - TestBase.setUp(self) + def test(self): + self.build() self.line_foo = line_number('foo.cpp', '// !BR_foo') self.line_main = line_number('main.cpp', '// !BR_main') - @expectedFailureAll(bugnumber="llvm.org/pr35480", oslist=["linux"]) - def test(self): - self.build() - exe = os.path.join(os.getcwd(), "a.out") - self.runCmd("file %s" % exe) + target = self.dbg.CreateTarget("a.out") + self.assertTrue(target, VALID_TARGET) + + env= self.registerSharedLibrariesWithTarget(target, ["foo"]) bp_main = lldbutil.run_break_set_by_file_and_line( self, 'main.cpp', self.line_main) bp_foo = lldbutil.run_break_set_by_file_and_line( self, 'foo.cpp', self.line_foo) - self.runCmd("run") + process = target.LaunchSimple( + None, env, self.get_process_working_directory()) self.assertIsNotNone( lldbutil.get_one_thread_stopped_at_breakpoint_id( Index: lldb/trunk/packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py =================================================================== --- lldb/trunk/packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py +++ lldb/trunk/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: lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h =================================================================== --- lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h +++ lldb/trunk/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: lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp =================================================================== --- lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp +++ lldb/trunk/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 entry point. + ProbeEntry(); + } m_process->GetTarget().ModulesDidLoad(module_list); } @@ -329,38 +335,77 @@ 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(); + BreakpointSP dyld_break; + if (m_rendezvous.IsValid()) { + 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, + break_addr); + dyld_break = target.CreateBreakpoint(break_addr, true, false); } 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; + } + + // 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 */); + } + + if (dyld_break->GetNumResolvedLocations() != 1) { + LLDB_LOG( + log, + "Rendezvous breakpoint has abnormal number of" + " resolved locations ({0}) in pid {1}. It's supposed to be exactly 1.", + dyld_break->GetNumResolvedLocations(), + m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); + + target.RemoveBreakpointByID(dyld_break->GetID()); + return false; } - // Make sure our breakpoint is at the right address. - assert(target.GetBreakpointByID(m_dyld_bid) - ->FindLocationByAddress(break_addr) - ->GetBreakpoint() - .GetID() == m_dyld_bid); + BreakpointLocationSP location = dyld_break->GetLocationAtIndex(0); + LLDB_LOG(log, + "Successfully set rendezvous breakpoint at address {0:x} " + "for pid {1}", + location->GetLoadAddress(), + m_process ? m_process->GetID() : LLDB_INVALID_PROCESS_ID); + + dyld_break->SetCallback(RendezvousBreakpointHit, this, true); + dyld_break->SetBreakpointKind("shared-library-event"); + m_dyld_bid = dyld_break->GetID(); + return true; } bool DynamicLoaderPOSIXDYLD::RendezvousBreakpointHit( @@ -485,7 +530,7 @@ return thread_plan_sp; } -void DynamicLoaderPOSIXDYLD::LoadVDSO(ModuleList &modules) { +void DynamicLoaderPOSIXDYLD::LoadVDSO() { if (m_vdso_base == LLDB_INVALID_ADDRESS) return; @@ -506,13 +551,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 +594,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 +606,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 +647,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() {