[Lldb-commits] [lldb] r322209 - Advanced guessing of rendezvous breakpoint

Eugene Zemtsov via lldb-commits lldb-commits at lists.llvm.org
Wed Jan 10 11:04:36 PST 2018


Author: eugene
Date: Wed Jan 10 11:04:36 2018
New Revision: 322209

URL: http://llvm.org/viewvc/llvm-project?rev=322209&view=rev
Log:
Advanced guessing of rendezvous breakpoint

When rendezvous structure is not initialized we need to set up
rendezvous breakpoint anyway. In this case the code will locate
dynamic loader (interpreter) and look for known function names.

Bug: https://bugs.llvm.org/show_bug.cgi?id=25806
Differential Revision: https://reviews.llvm.org/D41533

Modified:
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/global_constructor/TestBreakpointInGlobalConstructor.py
    lldb/trunk/packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py
    lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
    lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h

Modified: lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/global_constructor/TestBreakpointInGlobalConstructor.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/global_constructor/TestBreakpointInGlobalConstructor.py?rev=322209&r1=322208&r2=322209&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/global_constructor/TestBreakpointInGlobalConstructor.py (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/breakpoint/global_constructor/TestBreakpointInGlobalConstructor.py Wed Jan 10 11:04:36 2018
@@ -17,23 +17,23 @@ class TestBreakpointInGlobalConstructors
     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(

Modified: lldb/trunk/packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py?rev=322209&r1=322208&r2=322209&view=diff
==============================================================================
--- lldb/trunk/packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py (original)
+++ lldb/trunk/packages/Python/lldbsuite/test/functionalities/load_unload/TestLoadUnload.py Wed Jan 10 11:04:36 2018
@@ -368,7 +368,6 @@ class LoadUnloadTestCase(TestBase):
 
     @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 @@ class LoadUnloadTestCase(TestBase):
         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'])

Modified: lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp?rev=322209&r1=322208&r2=322209&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp (original)
+++ lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp Wed Jan 10 11:04:36 2018
@@ -79,7 +79,8 @@ DynamicLoaderPOSIXDYLD::DynamicLoaderPOS
     : 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 @@ void DynamicLoaderPOSIXDYLD::DidAttach()
                               : "<null executable>",
                 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 @@ void DynamicLoaderPOSIXDYLD::DidLaunch()
 
   executable = GetTargetExecutable();
   load_offset = ComputeLoadOffset();
-  EvalVdsoStatus();
+  EvalSpecialModulesStatus();
 
   if (executable.get() && load_offset != LLDB_INVALID_ADDRESS) {
     ModuleList module_list;
@@ -217,7 +218,12 @@ void DynamicLoaderPOSIXDYLD::DidLaunch()
     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 @@ bool DynamicLoaderPOSIXDYLD::EntryBreakp
   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<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 */);
+  }
+
+  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 @@ DynamicLoaderPOSIXDYLD::GetStepThroughTr
   return thread_plan_sp;
 }
 
-void DynamicLoaderPOSIXDYLD::LoadVDSO(ModuleList &modules) {
+void DynamicLoaderPOSIXDYLD::LoadVDSO() {
   if (m_vdso_base == LLDB_INVALID_ADDRESS)
     return;
 
@@ -506,13 +551,38 @@ void DynamicLoaderPOSIXDYLD::LoadVDSO(Mo
   }
 }
 
+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 @@ void DynamicLoaderPOSIXDYLD::LoadAllCurr
   // that ourselves here.
   ModuleSP executable = GetTargetExecutable();
   m_loaded_modules[executable] = m_rendezvous.GetLinkMapAddress();
-  LoadVDSO(module_list);
+  LoadVDSO();
 
   std::vector<FileSpec> module_names;
   for (I = m_rendezvous.begin(), E = m_rendezvous.end(); I != E; ++I)
@@ -536,6 +606,8 @@ void DynamicLoaderPOSIXDYLD::LoadAllCurr
     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 @@ addr_t DynamicLoaderPOSIXDYLD::ComputeLo
   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() {

Modified: lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h?rev=322209&r1=322208&r2=322209&view=diff
==============================================================================
--- lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h (original)
+++ lldb/trunk/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.h Wed Jan 10 11:04:36 2018
@@ -85,13 +85,17 @@ protected:
   /// 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<lldb::ModuleWP, lldb::addr_t, std::owner_less<lldb::ModuleWP>>
       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 @@ protected:
   /// 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 @@ protected:
   /// 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);




More information about the lldb-commits mailing list