[PATCHv6 4/7] gdb: handle dprintf breakpoints when unloading a shared library
Andrew Burgess
aburgess@redhat.com
Mon Dec 16 16:26:46 GMT 2024
While working on the previous commit I realised that GDB would not
handle dprintf breakpoints correctly when a shared library was
unloaded.
Consider this example using the test binary from the previous commit,
the function 'foo' where we create a dprintf is in a shared library:
(gdb) b 59
Breakpoint 1 at 0x401215: file /tmp/projects/binutils-gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/shlib-unload.c, line 59.
(gdb) r
Starting program: /tmp/projects/binutils-gdb/build/gdb/testsuite/outputs/gdb.base/shlib-unload/shlib-unload
Breakpoint 1, main () at /tmp/projects/binutils-gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/shlib-unload.c:59
59 res = dlclose (handle); /* Break here. */
(gdb) dprintf foo,"In foo"
Dprintf 2 at 0x7ffff7fc50fd: file /tmp/projects/binutils-gdb/build/gdb/testsuite/../../../src/gdb/testsuite/gdb.base/shlib-unload-lib.c, line 23.
(gdb) n
Error in re-setting breakpoint 2: Function "foo" not defined.
warning: error removing breakpoint 2 at 0x7ffff7fc50fd
warning: error removing breakpoint 2 at 0x7ffff7fc50fd
warning: error removing breakpoint 2 at 0x7ffff7fc50fd
warning: error removing breakpoint 2 at 0x7ffff7fc50fd
warning: error removing breakpoint 2 at 0x7ffff7fc50fd
warning: error removing breakpoint 2 at 0x7ffff7fc50fd
warning: error removing breakpoint 2 at 0x7ffff7fc50fd
warning: error removing breakpoint 2 at 0x7ffff7fc50fd
Cannot remove breakpoints because program is no longer writable.
Further execution is probably impossible.
60 assert (res == 0);
(gdb)
What happens here is that as the inferior steps over the dlclose call
the shared library containing 'foo' is unloaded and
disable_breakpoints_in_unloaded_shlib is called. However in
disable_breakpoints_in_unloaded_shlib we have this check:
if (b.type != bp_breakpoint
&& b.type != bp_jit_event
&& b.type != bp_hardware_breakpoint
&& !is_tracepoint (&b))
continue;
As the dprintf has type bp_dprintf then this check triggers and we
ignore the dprintf, meaning the dprintf is not disabled. When the
inferior stops after the 'next' GDB tries to remove all breakpoints
but the dprintf can no longer be removed, the memory in which it was
placed has been unmapped from the inferior.
The fix is to start using is_breakpoint() in
disable_breakpoints_in_unloaded_shlib instead of the bp_breakpoint and
bp_hardware_breakpoint checks. The is_breakpoint() function also
checks for bp_dprintf.
With this fix in place GDB now correctly disables the breakpoint and
we no longer see the warning about removing the breakpoint.
Tested-By: Hannes Domani <ssbssa@yahoo.de>
---
gdb/breakpoint.c | 5 ++---
gdb/testsuite/gdb.base/shlib-unload.exp | 29 +++++++++++++++++++++++++
2 files changed, 31 insertions(+), 3 deletions(-)
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 1131e996a18..50e80b2b75a 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -8083,9 +8083,8 @@ disable_breakpoints_in_unloaded_shlib (program_space *pspace, const solib &solib
{
bool bp_modified = false;
- if (b.type != bp_breakpoint
- && b.type != bp_jit_event
- && b.type != bp_hardware_breakpoint
+ if (b.type != bp_jit_event
+ && !is_breakpoint (&b)
&& !is_tracepoint (&b))
continue;
diff --git a/gdb/testsuite/gdb.base/shlib-unload.exp b/gdb/testsuite/gdb.base/shlib-unload.exp
index 791f9f518e8..7516ee2a292 100644
--- a/gdb/testsuite/gdb.base/shlib-unload.exp
+++ b/gdb/testsuite/gdb.base/shlib-unload.exp
@@ -111,4 +111,33 @@ proc_with_prefix test_bp_modified_events {} {
}
}
+# Check that GDB disables dprintf breakpoints within a shared library
+# when the shared library is unloaded.
+proc_with_prefix test_dprintf_at_unload {} {
+ clean_restart $::binfile
+
+ if {![runto_main]} {
+ return
+ }
+
+ gdb_breakpoint $::srcfile:$::bp_line
+ gdb_continue_to_breakpoint "stop before dlclose"
+
+ # Setup a dprintf within the shared library.
+ gdb_test "dprintf foo,\"In foo\""
+ set bp_num [get_integer_valueof "\$bpnum" "*UNKNOWN*" \
+ "get b/p number"]
+
+ # Unload the shared library, GDB should disable our b/p.
+ gdb_test "next" $::stop_after_bp_re
+
+ # Check that our b/p is now showing as disabled.
+ gdb_test "info breakpoints $bp_num" \
+ [multi_line \
+ "^Num\\s+Type\\s+Disp\\s+Enb\\s+Address\\s+What" \
+ "$bp_num\\s+dprintf\\s+keep\\s+y\\s+<PENDING>\\s+foo" \
+ "\\s+printf \"In foo\""]
+}
+
test_bp_modified_events
+test_dprintf_at_unload
--
2.25.4
More information about the Gdb-patches
mailing list