[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"
 }