[Lldb-commits] [PATCH] D158583: Fix shared library loading when users define duplicate _r_debug structure.

Greg Clayton via Phabricator via lldb-commits lldb-commits at lists.llvm.org
Wed Aug 23 11:52:27 PDT 2023

clayborg added a comment.

In D158583#4609320 <https://reviews.llvm.org/D158583#4609320>, @DavidSpickett wrote:

> I'm not familiar with this mechanism but just out of curiosity: `ld.so loads the main executable and any dependent shared libraries and wants to update the "_r_debug" structure, but it now finds "_r_debug" in the a.out program and updates the state in this other copy`
> Is this some undefined behaviour or is there a good use case for this? From the program's point of view.

This is just how name lookups happen across shared library boundaries as far as I know. External symbols get resolved by searching the shared libraries including the main executable.

I have verified this is indeed what is happening by debugging the ld.so binary and stepping through it at this code in rtld.c:

  /* Notify the debugger all new objects are now ready to go.  We must re-get
     the address since by now the variable might be in another object.  */
  r = _dl_debug_initialize (0, LM_ID_BASE);
  r->r_state = RT_CONSISTENT;
  _dl_debug_state ();

The code for _dl_debug_initialize() looks like:

  struct r_debug *
  _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
    struct r_debug *r;
    if (ns == LM_ID_BASE)
      r = &_r_debug; /// <- this will switch to 
      r = &GL(dl_ns)[ns]._ns_debug;
    if (r->r_map == NULL || ldbase != 0)
        /* Tell the debugger where to find the map of loaded objects.  */
        r->r_version = 1	/* R_DEBUG_VERSION XXX */;
        r->r_ldbase = ldbase ?: _r_debug.r_ldbase;
        r->r_map = (void *) GL(dl_ns)[ns]._ns_loaded;
        r->r_brk = (ElfW(Addr)) &_dl_debug_state;
    return r;

And the line "r = &_r_debug;" picks up the first item in the library search paths for "_r_debug" which gets the one from the a.out program...

Comment at: lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DYLDRendezvous.cpp:260-266
+    // the dynamic loader. The problem happens as soon as the executable or
+    // shared library that exports another "_r_debug" is loaded by the dynamic
+    // loader due to the way symbols are found using the shared library search
+    // paths will mean that the new copy takes precedence over the one in the
+    // dynamic loader and the dynamic loader will be updating the other copy
+    // somewhere else that we won't find and that copy will have the
+    // eConsistent state.
DavidSpickett wrote:
> DavidSpickett wrote:
> > Can we split this sentence just for readability? Bullet points of each step might be clearer.
> What you have in the commit message basically.
yeah, I was tired last night when finishing this up, I will grab the stuff from the commit message

Comment at: lldb/test/API/functionalities/dyld-multiple-rdebug/TestDyldWithMultupleRDebug.py:22
+    @no_debug_info_test
+    @skipIf(oslist=["linux"], archs=["arm"])
+    def test(self):
DavidSpickett wrote:
> Any specific reason for this? Not that it really matters, it'll get plenty of testing elsewhere.
Yeah, copy paste issue. I would be able to remove this.

Comment at: lldb/test/API/functionalities/dyld-multiple-rdebug/TestDyldWithMultupleRDebug.py:28
+        exe = self.getBuildArtifact("a.out")
+        print(exe)
+        target = self.dbg.CreateTarget(exe)
DavidSpickett wrote:
> Leftover debug print.
good catch, yes!

Comment at: lldb/test/API/functionalities/dyld-multiple-rdebug/TestDyldWithMultupleRDebug.py:54
+        self.assertIn("main",
+                      thread.GetFrameAtIndex(0).GetDisplayFunctionName())
+        process.Continue()
aprantl wrote:
> You should be able to shorten the test setup considerably by using lldbutil.run_to_name_breakpoint() and only manually setting the second breakpoint afterwards.
will do

  rG LLVM Github Monorepo



More information about the lldb-commits mailing list