[binutils-gdb] [gdb/testsuite] Fix FAIL in gdb.threads/sw-watchpoint-step-over-bp-with-threads.exp
Tom de Vries via Gdb-cvs <[email protected]> Mon, 13 Jul 2026 13:29:19 +0000 (GMT)
| Newsgroups | gmane.comp.gdb.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3Dfbafe3b994c6= f8f9778bab0b3160e9a21bfa211f commit fbafe3b994c6f8f9778bab0b3160e9a21bfa211f Author: Tom de Vries <[email protected]> Date: Mon Jul 13 15:29:14 2026 +0200 [gdb/testsuite] Fix FAIL in gdb.threads/sw-watchpoint-step-over-bp-with= -threads.exp =20 On x86_64-linux, I ran into the following FAIL: ... (gdb) cont Continuing. [Switching to Thread 0x7ffff7cbe6c0 (LWP 3534988)] =20 Thread 2 "sw-watchpoint-s" hit Watchpoint 3: watched_global =20 Old value =3D 0 New value =3D 1 0x00007ffff7d514bf in futex_wait () at ../sysdeps/nptl/futex-internal.h= :146 146 int err =3D lll_futex_timed_wait (futex_word, expected, NULL,= private); (gdb) PASS: $exp: target-non-stop=3Dauto: displaced-stepping=3Dauto: \ continue to watchpoint break 64 No compiled code for line 64 in the current file. Make breakpoint pending on future shared library load? (y or [n]) n (gdb) FAIL: $exp: target-non-stop=3Dauto: displaced-stepping=3Dauto: \ gdb_breakpoint: set breakpoint at 64 ... =20 [ The FAIL initially reproduced only under heavy system load (simulated= using stress -c $(grep -c ^processor: /proc/cpuinfo)), but then I found that changing the delay in $srcfile from 1 second to 1 millisecond also repr= oduced it fairly reliably. Using this approach, I managed to reproduce both on x86_64-linux and aarch64-linux. ] =20 The test-case tries to set a breakpoint at $srcfile:64, using just "64"= , but that doesn't work because the inferior is not stopped in $srcfile. =20 This can be trivially fixed by using $srcfile:64 instead, and indeed, t= his is what this patch does. =20 However, that fix is only correct if gdb is indeed allowed to report a = stop in thread 2. =20 This is a question I found difficult to answer. =20 I found some text in the docs [1] that seems related to the test-case scenario: ... Warning: In multi-threaded programs, software watchpoints have only lim= ited usefulness. If GDB creates a software watchpoint, it can only watch th= e value of an expression in a single thread. If you are confident that the exp= ression can only change due to the current thread=E2=80=99s activity (and if yo= u are also confident that no other thread can become current), then you can use so= ftware watchpoints as usual. However, GDB may not notice when a non-current t= hread=E2=80=99s activity changes the expression. (Hardware watchpoints, in contrast, wa= tch an expression in all threads.) ... =20 After reading this text, my impression was that gdb shouldn't report a = stop in thread 2, because: - GDB "can only watch the value of an expression in a single thread", - the expression can only change due the current thread's activity (thr= ead 1), and - thread 2 cannot become current, it just spins and there's no breakpoi= nt set in the range where it spins. =20 However, in the test-case I came across the following text: ... # The final continue, with the software watchpoint set, so that # GDB single-steps all threads (if the target is non-stop). ... =20 Indeed, the test-case iterates over some dimensions: ... foreach_with_prefix target-non-stop {auto on off} { foreach_with_prefix displaced-stepping {auto on off} { test ${target-non-stop} ${displaced-stepping} } } ... and disregarding the auto, the FAIL reproduces with both displaced-step= ping on and off, but only with target-non-stop on. =20 So we have the default non-stop off, and target-non-stop on. =20 The documentation says about this [2]: ... set non-stop off, target operating in non-stop mode =20 When a thread hits a breakpoint, finishes a step, etc., the target does= not immediately stop all other threads. If, while processing the event, in= frun decides the stop should be reported to the user, it then explicitly sto= ps all threads, just before presenting the stop to the user; otherwise, infrun re-resumes the stopped thread. This scenario is also called =E2=80=9Ca= ll-stop on top of non-stop=E2=80=9D. ... =20 I was not able to deduce why in this situation and in presence of a sof= tware watchpoint all threads should be single stepping, so I asked Claude Cod= e. =20 It gave the following background information: - in the pure all-stop case (set non-stop off, target operating in all-= stop mode), in presence of a software watchpoint: - the current thread single-steps - the other threads stay stopped - consequently, only modifications by the current thread are detected, - in the all-stop on non-stop case (set non-stop off, target operating = in non-stop mode), in presence of a software watchpoint: - all threads single-step - consequently, modifications by any thread are detected, but it's not possible to attribute the modification to any specific thread, so g= db attributes it to the thread whose stop happens to be processed. =20 This adequately explains the behavior in the test-case. =20 I suspect that the warning text in the documentation needs updating, be= cause AFAICT it doesn't cover the "set non-stop off, target operating in non-= stop mode" behavior described above. =20 Tested on x86_64-linux. =20 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=3D34280 =20 [1] https://sourceware.org/gdb/current/onlinedocs/gdb.html/Set-Watchpoi= nts.html [2] https://sourceware.org/gdb/current/onlinedocs/gdb.html/Maintenance-= Commands.html#index-maint-set-target_002dnon_002dstop-mode-_005bon_007coff_= 007cauto_005d Diff: --- gdb/testsuite/gdb.threads/sw-watchpoint-step-over-bp-with-threads.exp | 2 = +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gdb/testsuite/gdb.threads/sw-watchpoint-step-over-bp-with-thre= ads.exp b/gdb/testsuite/gdb.threads/sw-watchpoint-step-over-bp-with-threads= .exp index 3dac2b85987..bd520cd62dd 100644 --- a/gdb/testsuite/gdb.threads/sw-watchpoint-step-over-bp-with-threads.exp +++ b/gdb/testsuite/gdb.threads/sw-watchpoint-step-over-bp-with-threads.exp @@ -80,7 +80,7 @@ proc test {target-non-stop displaced-stepping} { # fail an assertion that checks that we never ask the target to # hardware single-step a thread when we have a software # single-step breakpoint set for that thread. - gdb_breakpoint [gdb_get_line_number "break here end"] + gdb_breakpoint $::srcfile:[gdb_get_line_number "break here end"] gdb_continue_to_breakpoint "end" }