aboutsummaryrefslogtreecommitdiff
path: root/gdb/python/py-record.c
diff options
context:
space:
mode:
authorSimon Marchi <simon.marchi@efficios.com>2025-07-29 10:58:13 -0400
committerSimon Marchi <simon.marchi@efficios.com>2025-08-22 10:45:48 -0400
commitd33a66a31134bd63c4945d0d570e7296aaac3574 (patch)
treeb954480f1ec76f5504dbcb494d278988bf7d8aee /gdb/python/py-record.c
parenta7ba2c42b807d1f23b2cc11598973a1c7386e379 (diff)
downloadgdb-d33a66a31134bd63c4945d0d570e7296aaac3574.zip
gdb-d33a66a31134bd63c4945d0d570e7296aaac3574.tar.gz
gdb-d33a66a31134bd63c4945d0d570e7296aaac3574.tar.bz2
gdb/solib-svr4: fix wrong namespace id for dynamic linker
When running a program that uses multiple linker namespaces, I get something like: $ ./gdb -nx -q --data-directory=data-directory testsuite/outputs/gdb.base/dlmopen-ns-ids/dlmopen-ns-ids -ex "tb 50" -ex r -ex "info shared" -batch ... From To NS Syms Read Shared Object Library 0x00007ffff7fc6000 0x00007ffff7fff000 0 Yes /lib64/ld-linux-x86-64.so.2 0x00007ffff7e93000 0x00007ffff7f8b000 0 Yes /usr/lib/libm.so.6 0x00007ffff7ca3000 0x00007ffff7e93000 0 Yes /usr/lib/libc.so.6 0x00007ffff7fb7000 0x00007ffff7fbc000 1 Yes /home/smarchi/build/binutils-gdb/gdb/testsuite/outputs/gdb.base/dlmopen-ns-ids/dlmopen-lib.so 0x00007ffff7b77000 0x00007ffff7c6f000 1 Yes /usr/lib/libm.so.6 0x00007ffff7987000 0x00007ffff7b77000 1 Yes /usr/lib/libc.so.6 0x00007ffff7fc6000 0x00007ffff7fff000 1 Yes /usr/lib/ld-linux-x86-64.so.2 0x00007ffff7fb2000 0x00007ffff7fb7000 2 Yes /home/smarchi/build/binutils-gdb/gdb/testsuite/outputs/gdb.base/dlmopen-ns-ids/dlmopen-lib.so 0x00007ffff788f000 0x00007ffff7987000 2 Yes /usr/lib/libm.so.6 0x00007ffff769f000 0x00007ffff788f000 2 Yes /usr/lib/libc.so.6 0x00007ffff7fc6000 0x00007ffff7fff000 1! Yes /usr/lib/ld-linux-x86-64.so.2 0x00007ffff7fad000 0x00007ffff7fb2000 3 Yes /home/smarchi/build/binutils-gdb/gdb/testsuite/outputs/gdb.base/dlmopen-ns-ids/dlmopen-lib.so 0x00007ffff75a7000 0x00007ffff769f000 3 Yes /usr/lib/libm.so.6 0x00007ffff73b7000 0x00007ffff75a7000 3 Yes /usr/lib/libc.so.6 0x00007ffff7fc6000 0x00007ffff7fff000 1! Yes /usr/lib/ld-linux-x86-64.so.2 Some namespace IDs for the dynamic linker entries (ld-linux) are wrong (I placed a ! next to those that are wrong). The dynamic linker is special: it is loaded only once (notice how all ld-linux entries have the same addresses), but it is visible in all namespaces. It is therefore listed separately in all namespaces. The problem happens like this: - for each solib, print_solib_list_table calls solib_ops::find_solib_ns to get the namespace ID to print - svr4_solib_ops::find_solib_ns calls find_debug_base_for_solib - find_debug_base_for_solib iterates on the list of solibs in all namespaces, looking for a match for the given solib. For this, it uses svr4_same, which compares two SOs by name and low address. Because there are entries for the dynamic linker in all namespaces, with the same low address, find_debug_base_for_solib is unable to distinguish them, and sometimes returns the wrong namespace. To fix this, save in lm_info_svr4 the debug base address that this lm/solib comes from, as a way to distinguish two solibs that would be otherwise identical. The code changes are: - Add a constructor to lm_info_svr4 accepting the debug base. Update all callers, which sometimes requires passing down the debug base. - Modify find_debug_base_for_solib to return the debug base directly from lm_info_svr4. - Modify svr4_same to consider the debug base value of the two libraries before saying they are the same. While at it, move the address checks before the name check, since they are likely less expensive to do. - Modify svr4_solib_ops::default_debug_base to update the debug base of existing solibs when the default debug base becomes known. I found the last point to be necessary, because when running an inferior, we list the shared libraries very early (before the first instruction): #0 svr4_solib_ops::current_sos (this=0x7c1ff1e09710) #1 0x00005555643c774e in update_solib_list (from_tty=0) #2 0x00005555643ca377 in solib_add (pattern=0x0, from_tty=0, readsyms=1) #3 0x0000555564335585 in svr4_solib_ops::enable_break (this=0x7c1ff1e09710, info=0x7d2ff1de8c40, from_tty=0) #4 0x000055556433c85c in svr4_solib_ops::create_inferior_hook (this=0x7c1ff1e09710, from_tty=0) #5 0x00005555643d22cb in solib_create_inferior_hook (from_tty=0) #6 0x000055556337071b in post_create_inferior (from_tty=0, set_pspace_solib_ops=true) #7 0x00005555633726a2 in run_command_1 (args=0x0, from_tty=0, run_how=RUN_NORMAL) #8 0x0000555563372b35 in run_command (args=0x0, from_tty=0) At this point, the dynamic linker hasn't yet filled the DT_DEBUG slot, which normally points at the base of r_debug. Since we're unable to list shared libraries at this point, we go through svr4_solib_ops::default_sos, which creates an solib entry for the dynamic linker. At this point, we have no choice but to create it with a debug base of 0 (or some other value that indicates "unknown"). If we left it as-is, then it would later not be recognized to be part of any existing namespace and that would cause problems down the line. With this change, the namespaces of the dynamic linker become correct. I was not sure if the code in library_list_start_library was conflating debug base and lmid. The documentation says this about the "lmid" field in the response of a qxfer:libraries-svr4:read packet: lmid, which is an identifier for a linker namespace, such as the memory address of the r_debug object that contains this namespace’s load map or the namespace identifier returned by dlinfo (3). When I read "lmid", I typically think about "the namespace identifier returned by dlinfo (3)". In library_list_start_library, we use the value of the "lmid" attribute as the debug base address. This is the case even before this patch, since we do: solist = &list->solib_lists[lmid]; The key for the solib_lists map is documented as being the debug base address. In practice, GDBserver uses the debug base address for the "lmid" field, so we're good for now. If the remote side instead used "the namespace identifier returned by dlinfo (3)" (which in practice with glibc are sequential integers starting at 0), I think we would be mostly fine. If we use the qxfer packet to read the libraries, we normally won't use the namespace base address to do any memory reads, as all the information comes from the XML. There might be some problems however because we treat the namespace 0 specially, for instance in svr4_solib_ops::update_incremental. In that case, we might need a different way of indicating that the remote side does not give namespace information than using namespace 0. This is just a thought for the future. I improved the existing test gdb.base/dlmopen-ns-ids.exp to verify that "info sharedlibrary" does not show duplicate libraries, duplicate meaning same address range, namespace and name. Change-Id: I84467c6abf4e0109b1c53a86ef688b934e8eff99 Reviewed-By: Guinevere Larsen <guinevere@redhat.com>
Diffstat (limited to 'gdb/python/py-record.c')
0 files changed, 0 insertions, 0 deletions