From: Simon Marchi Date: Fri, 29 Aug 2025 20:05:27 +0000 (-0400) Subject: gdb/solib-svr4: update default debug base in svr4_solib_ops::current_sos X-Git-Tag: gdb-17-branchpoint~110 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=a98c610f9514c957d5bacc4929188562b48ee16e;p=thirdparty%2Fbinutils-gdb.git gdb/solib-svr4: update default debug base in svr4_solib_ops::current_sos Commit d33a66a31134 ("gdb/solib-svr4: fix wrong namespace id for dynamic linker") regressed test gdb.base/break-probes.exp with the native-gdbserver board: Running /home/simark/src/binutils-gdb/gdb/testsuite/gdb.base/break-probes.exp ... FAIL: gdb.base/break-probes.exp: run til our library loads (the program exited) FAIL: gdb.base/break-probes.exp: call (int) foo(23) In the logs, we see this: Stopped due to shared library event: Inferior unloaded target:/lib64/ld-linux-x86-64.so.2 Inferior loaded target:/lib64/ld-linux-x86-64.so.2 When we should see this: Stopped due to shared library event (no libraries added or removed) In the unexpected output, GDB claims that the inferior unloaded and then loaded the dynamic linker. This is obviously not true. Commit d33a66a31134 changed the svr4_same function to consider the debug bases the solibs come from. Two solibs with the same inferior address but different debug base (such as the multiple solibs representing the dynamic linker in all the namespaces) now compare unequal. That commit also introduced a mechanism to update the debug base of an existing solib (more precisely, field lm_info_svr4::debug_base) when that value becomes known. The solib for the dynamic linker view in the default namespace starts with a debug base of 0, and is then changed to have the real debug base address later on. With the particular code path taken when connecting to a remote target, nothing triggers the update of the debug base of the dynamic linker solib initially created with a debug base of 0. So when svr4_solib_ops::current_sos returns a list with an solib for the dynamic linker with the real debug base value, the core sees this as an unload and a load. This happens specifically when debuggin remotely, because, svr4_solib_ops::current_sos_direct takes the "using_xfer" branch, which doesn't do any svr4_solib_ops::default_debug_base call. In local, we don't take that branch, which leads us to a call to default_debug_base. The way I propose to fix it is to add a call to svr4_solib_ops::default_debug_base at the beginning of svr4_solib_ops::current_sos. The rationale to put it there is that if the core is requesting a fresh list of libraries, and then compare that list with what it had previously, then we better make sure that the core's list has received the debug base update, if one is needed. Change-Id: If09c5a7b3d956e18d4b9514466226267c85f12a6 Approved-by: Kevin Buettner --- diff --git a/gdb/solib-svr4.c b/gdb/solib-svr4.c index 635e52a1987..58432b69a5d 100644 --- a/gdb/solib-svr4.c +++ b/gdb/solib-svr4.c @@ -1512,6 +1512,15 @@ owning_intrusive_list svr4_solib_ops::current_sos () const { svr4_info *info = get_svr4_info (current_program_space); + + /* Call this for the side-effect of updating the debug base in existing + solibs' lm_info_svr4, if needed. It is possible for the core to have + an solib with a stale lm_info_svr4::debug_base. In that case, we are + about to return the same solib, but with an updated debug_base. If we + didn't do this call, then it would appear as two different libraries to + the core, and it would appear as a spurious unload / load. */ + this->default_debug_base (info); + owning_intrusive_list sos = this->current_sos_1 (info); struct mem_range vsyscall_range;