Commit graph

718 commits

Author SHA1 Message Date
Tom de Vries
ca3dd1c6af [gdb] More codespell fixes
I did this in gdb/pyproject.toml:
...
+regex = "[a-zA-Z0-9\\-']+"
...
allowing us to detect things like 'gcs_availabe':
...
$ echo gcs_availabe | codespell --regex="[a-zA-Z0-9\-']+" -
1: gcs_availabe
	availabe ==> available
...
and ran:
...
$ codespell --toml gdb/pyproject.toml gdb*
...
and manually fixed fallout.

This fixes the following typos:
...
  typdef -> typedef
  bloc -> block
  reenables -> re-enables
  overlayed -> overlaid
  advertized -> advertised
  stript -> script
  reenable -> re-enable
  interruptable -> interruptible
  restire -> restore
  sufix -> suffix
  regisers -> registers
  constrait -> constraint
  attriute -> attribute
  followin -> following
  immedate -> immediate
  constrol -> control
  sting -> string
  vesion -> version
  operatons -> operations
  inheritence -> inheritance
  decsription -> description
  hilighted -> highlighted
  enque -> enqueue
  ouputs -> outputs
...

The "vesion -> version" fix in gdb.dwarf2/dw2-entry-pc.exp allowed a bit of
cleanup.

Tested on x86_64-linux and aarch64-linux.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=34241
2026-07-13 15:23:12 +02:00
Tom de Vries
5aebabf11c [gdb] convert struct pointer typedefs
Convert "typedef struct foo { ... } *bar" to
"struct foo { ... }; using bar = foo *".

Generated by a script written by Claude Code.

Approved-By: Tom Tromey <tom@tromey.com>
2026-07-13 15:06:35 +02:00
Tom de Vries
496c2954e6 [gdb] Convert anonymous struct typedefs
Convert "typedef struct { ... } foo" into "struct foo { ... }".

Generated by a script written by Claude Code.

Approved-By: Tom Tromey <tom@tromey.com>
2026-07-13 15:06:35 +02:00
Tom de Vries
c3ea9a009d [gdb] Fix redundant struct typedefs
Convert "typedef struct foo { ... } foo" into "struct foo { ... }".

Generated by a script written by Claude Code.

Approved-By: Tom Tromey <tom@tromey.com>
2026-07-13 15:06:35 +02:00
Tom de Vries
0adf0abd96 [gdb] Convert function typedefs to using
Convert "typedef void foo ()" to "using foo = void ()".

Generated by a script written by Claude Code.

Approved-By: Tom Tromey <tom@tromey.com>
2026-07-13 15:06:35 +02:00
Tom de Vries
ef5907287a [gdb] Convert template typedefs to using
Convert "typedef foo<...> bar" to "using bar = foo<...>".

Generated by a script written by Claude Code.

Approved-By: Tom Tromey <tom@tromey.com>
2026-07-13 15:06:35 +02:00
Tom de Vries
7717301873 [gdb] Convert function pointer typedefs to using
Transform "typedef void (*foo) ()" into "using foo =  void (*) ()".

Generated by a script written by Claude Code.

Approved-By: Tom Tromey <tom@tromey.com>
2026-07-13 15:06:35 +02:00
Tom de Vries
bc7e910e10 [gdb] Use using instead of typedef some more (part 2)
Result of:
...
$ find gdb* -type f -name "*.[ch]" -o -name "*.cc" \
    | egrep -v /testsuite/ \
    | xargs sed -i \
        '/WINAPI/b l;s/^\([ \t]*\)typedef \([a-zA-Z_0-9:<>,.()\* ]*\) \([a-zA-Z_0-9]*\) \((.*)\);/\1using \3 = \2 \4;/;:l'
$ find gdb* -type f -name "*.[ch]" -o -name "*.cc" \
    | egrep -v /testsuite/ \
    | xargs sed -i \
        '/WINAPI/b l;s/^\([ \t]*\)typedef \([a-zA-Z_0-9:<>,.()\* ]*\) (\([a-zA-Z_0-9]*\)) \((.*)\);/\1using \3 = \2 \4;/;:l'
$ find gdb* -type f -name "*.[ch]" -o -name "*.cc" \
    | egrep -v /testsuite/ \
    | xargs sed -i \
        '/WINAPI/b l;s/^\([ \t]*\)typedef \([a-zA-Z_0-9:<>,.()\* ]*\) (\([a-zA-Z_0-9]*\))\((.*)\);/\1using \3 = \2 \4;/;:l'
$ find gdb* -type f -name "*.[ch]" -o -name "*.cc" \
    | egrep -v /testsuite/ \
    | xargs sed -i \
        '/WINAPI/b l;s/^\([ \t]*\)typedef \([a-zA-Z_0-9:<>,.()\* ]*\) (\*\([a-zA-Z_0-9]*\)) \((.*)\);/\1using \3 = \2 (*) \4;/;:l'
...
and fixing up this incorrect rewrite:
...
-typedef int td_key_iter_f (thread_key_t, void (*) (void *), void *);
+using void = int td_key_iter_f (thread_key_t, (*) (void *), void *);
...

Approved-By: Tom Tromey <tom@tromey.com>
2026-07-13 15:06:35 +02:00
Tom de Vries
5befd84f46 [gdb] Move ChangeLog files to archive dir
We stopped updating ChangeLog files in 2021, and they are no longer
maintained.

If I want to see history, I use git log, so I don't use them for any purpose.

And they're in my way when I'm searching for files, grepping, or refactoring
using sed.

Move them out of the way, into a root-level directory named archive
(alternative names: legacy, deprecated, attic, stale, historical,
unmaintained).

Result of:
...
for f in $(find gdb* -name "ChangeLog*"); do
    dir=$(dirname $f)
    f=$(basename $f)
    u=archive/$dir
    mkdir -p $u
    git mv $dir/$f $u/$f
done
...

Also drop ignoring ChangeLog files in some pre-commit tools.

A less impactful but also less effective change would be to move <dir>/ChangeLog
into <dir>/archive/ChangeLog.
2026-07-13 13:33:42 +02:00
Keith Seitz
84a23870fd [gdbserver] Use const_target_desc_up for regformat tdescs
Regformat tdescs are now declared 'const_target_desc_up' by
gdb's regdat.sh, so update the various gdbserver target descriptions
to observe this API change.

There should be no user visible changes.

Approved-By: Simon Marchi <simon.marchi@efficios.com>
2026-07-07 12:11:09 -07:00
Pedro Alves
7b0af7864c Windows: Normalize backslashes to forward slashes
Currently, on native Windows, GDB presents a mix of backslashes and
forward slashes to users, like e.g.:

 ...
 attach 15044
 Attaching to program: C:\msys2\home\alves\gdb\build-testsuite\outputs\gdb.base\attach\attach.exe, process 15044
 ...
 [Switching to thread 1 (Thread 15044.0x1294)]
 main () at C:/rocgdb/src/gdb/testsuite/gdb.base/attach.c:19
 19        while (! should_exit)
 (gdb) FAIL: gdb.base/attach.exp: do_attach_failure_tests: first attach
 ...

Note how above, the "attach" command uses backslashes, and the source
path uses forward slashes.

Most annoyingly, depending on compiler, you can end up with mixed
slash styles in the same path:

  Temporary breakpoint 1 at 0x1400010ec: file C:/rocgdb/src/gdb/testsuite/gdb.rocm\simple.cpp, line 33.
                                                                                  ^

A while ago, in commit a63213cd37 ("MSYS2+MinGW testing: Unix <->
Windows path conversion"), I had made the testsuite normalize
backslashes to forward slashes, among other things.  I had said in the
commit log there:

    "It's arguable whether GDB itself should do this sanitization.  I
    suspect it should.  I personally dislike seeing backward slashes in
    e.g., "info shared" output, or worse, mixed backward and forward
    slashes.  Still, I propose starting with a testsuite adjustment that
    moves us forward, and handle that separately.  I won't be surprised if
    we need the new routine for some cases even if we adjust GDB."

After running into some other tests that would need backslash
adjustment, and also because this is something user-visible, not just
a testsuite issue, I decided to bite the bullet and make GDB itself do
the slashes normalization.

This patch fixes all the cases of backslashes that I could find:

 - source files and compilation directory
 - executable name, and shared library names
 - cd/pwd commands

It does this by normalizing slashes at some strategic places.  The
conversion is only attempted if needed -- i.e., if debugging on
Windows, or cross-debugging Windows programs from a non-Windows host.

For executable/shared library names, this is doing the backslash ->
forward slash conversion completely on the host side in common code,
without touching the target backend files in either GDB or GDBserver,
by design, so that this is all completely a client side decision, and
works the same against any Windows GDBserver version, against remote
servers other than ours (e.g., Wine's), so we can change it later if
we want, etc.

I did tweak the gdb and gdbserver backends for the other way around
(forward slash => backslash), to make sure that they pass backslashes
to CreateProcess, so that inferiors see native backslashes in their
own argv[0].  For GDBserver, it would already have been possible to
launch an executable with forward slashes before (e.g., when debugging
from a Linux or Cygwin client), so this makes Windows gdbserver
behavior more consistent, independently of client, too.

I did not add an option to make this configurable at runtime on
purpose.  I don't see the point, it'd just add more complication and
testing surface.  Always normalizing keeps it simple.

For the source paths, I considered doing the normalization earlier in
the DWARF reader, but decided against it, because that would force
extra copying of strings -- the DWARF reader works mostly by passing
around const char pointers.  Also, the places I picked in principle
will automatically handle PDB if/when we get to it.

The buildsym.c change takes care of compilation directory paths.

The allocate_symtab change takes care of source paths.  That one
required a (temporary) copy, but I think that that's acceptable there.

The gdb_realpath change is needed because just before the touched code
there's a GetFullPathName call, which itself normalizes to
backslashes.

The exec.c and solib.c changes take care of executable and shared
libraries.

The change to testsuite/lib/gdb.exp, to adjust to forward-slash style
for DOS full names, are necessary otherwise MI tests break.  E.g.:

  *stopped,reason="breakpoint-hit",disp="del",bkptno="1",frame={addr="0x00007ff780461508",
  func="main",args=[],file="C:/rocgdb/src/gdb/testsuite/gdb.mi/basics.c",
  fullname="C:/rocgdb/src/gdb/testsuite/gdb.mi/basics.c",line="64",arch="i386:x86-64"},
  thread-id="1",stopped-threads="all"
  FAIL: gdb.mi/gdb2549.exp: mi runto main (unknown output after running)

gdb.base/set-cwd.exp was the only test I found (so far at least) that
required adjustment, but note that without this patch that testcase
fails and throws TCL errors, like:

  ...
  FAIL: gdb.base/set-cwd.exp: test_cwd_reset: inferior cwd is correctly set
  ERROR: couldn't compile regular expression pattern: invalid escape \ sequence
  ...

It passes cleanly with the patch.

Below's the before / after comparison of different commands / output.

Before:

  Reading symbols from ./outputs/gdb.rocm/simple/simple...
  (gdb)
  start
  Temporary breakpoint 1 at 0x1400010ec: file C:/rocgdb/src/gdb/testsuite/gdb.rocm\simple.cpp, line 33.
  Starting program: C:\msys2\home\alves\gdb\build-testsuite\outputs\gdb.rocm\simple\simple

  Thread 1 hit Temporary breakpoint 1, main () at C:/rocgdb/src/gdb/testsuite/gdb.rocm\simple.cpp:33
  33        hipError_t error = hipMalloc (&result_ptr, sizeof (int));

  Thread 1 hit Temporary breakpoint 1, main () at C:/rocgdb/src/gdb/testsuite/gdb.rocm\simple.cpp:33
  33        hipError_t error = hipMalloc (&result_ptr, sizeof (int));
  (gdb)

  (gdb) info inferiors
    Num  Description       Connection           Executable
  * 1    process 15620     1 (native)           C:\msys2\home\alves\gdb\build-testsuite\outputs\gdb.rocm\simple\simple

  (gdb) info sharedlibrary
  From                To                  Syms Read   Shared Object Library
  0x00007ffd22f91000  0x00007ffd231a69a8  Yes (*)     C:\Windows\SYSTEM32\ntdll.dll
  0x00007ffd21af1000  0x00007ffd21bb2520  Yes (*)     C:\Windows\System32\kernel32.dll
  0x00007ffd20091000  0x00007ffd20432548  Yes (*)     C:\Windows\System32\KernelBase.dll
  0x00007ffcc89c1000  0x00007ffcc9b145bc  Yes (*)     C:\Windows\SYSTEM32\amdhip64_7.dll
  0x00007ffd22911000  0x00007ffd22d829b0  Yes (*)     C:\Windows\System32\setupapi.dll
  0x00007ffd216c1000  0x00007ffd217653f0  Yes (*)     C:\Windows\System32\msvcrt.dll
  0x00007ffd22431000  0x00007ffd224de5c8  Yes (*)     C:\Windows\System32\advapi32.dll
  0x00007ffd21a41000  0x00007ffd21ae52b8  Yes (*)     C:\Windows\System32\sechost.dll
  0x00007ffd20651000  0x00007ffd20676af0  Yes (*)     C:\Windows\System32\bcrypt.dll
  0x00007ffd21f31000  0x00007ffd22045860  Yes (*)     C:\Windows\System32\rpcrt4.dll
  0x00007ffd22d91000  0x00007ffd22f40e50  Yes (*)     C:\Windows\System32\user32.dll
  0x00007ffd20781000  0x00007ffd207a43d8  Yes (*)     C:\Windows\System32\win32u.dll
  0x00007ffd228d1000  0x00007ffd228f73d8  Yes (*)     C:\Windows\System32\gdi32.dll
  0x00007ffd207b1000  0x00007ffd208d09c8  Yes (*)     C:\Windows\System32\gdi32full.dll
  0x00007ffd20b91000  0x00007ffd20c28410  Yes (*)     C:\Windows\System32\msvcp_win.dll
  0x00007ffd20471000  0x00007ffd2057f410  Yes (*)     C:\Windows\System32\ucrtbase.dll
  0x00007ffd21541000  0x00007ffd215afbc8  Yes (*)     C:\Windows\System32\ws2_32.dll
  0x00007ffd223f1000  0x00007ffd2241fc40  Yes (*)     C:\Windows\System32\imm32.dll

  (gdb) info source
  Current source file is C:/rocgdb/src/gdb/testsuite/gdb.rocm\simple.cpp
  Compilation directory is C:\msys2\home\alves\gdb\build-testsuite
  Located in C:\rocgdb\src\gdb\testsuite\gdb.rocm\simple.cpp

  (gdb) info sources
  C:\msys2\home\alves\gdb\build-testsuite\outputs\gdb.rocm\simple\simple:

  C:\rocgdb\src\gdb\testsuite\gdb.rocm\simple.cpp, C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\ucrt\corecrt_stdio_config.h,
  C:\Program Files\AMD\ROCm\7.1\include\hip\hip_runtime_api.h, C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\stdint.h,
  C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\ucrt\stdio.h, C:\Program Files\AMD\ROCm\7.1\lib\clang\21\include\__stddef_nullptr_t.h,
  C:\Program Files\AMD\ROCm\7.1\lib\clang\21\include\__stddef_size_t.h, C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.39.33519\include\cstdlib,
  C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\ucrt\stdlib.h, C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\ucrt\corecrt_search.h,
  C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\ucrt\corecrt_malloc.h,
  ...

  (gdb) detach
  Detaching from program: C:\msys2\home\alves\gdb\build-testsuite\outputs\gdb.rocm\simple\simple, process 20800
  [Inferior 1 (process 20800) detached]

  (gdb) cd /tmp
  Working directory C:\tmp.
  (gdb) pwd
  Working directory C:\tmp.

After:

  Reading symbols from ./outputs/gdb.rocm/simple/simple...
  (gdb) start
  Temporary breakpoint 1 at 0x1400010ec: file C:/rocgdb/src/gdb/testsuite/gdb.rocm/simple.cpp, line 33.
  Starting program: C:/msys2/home/alves/gdb/build-testsuite/outputs/gdb.rocm/simple/simple

  Thread 1 hit Temporary breakpoint 1, main () at C:/rocgdb/src/gdb/testsuite/gdb.rocm/simple.cpp:33
  33        hipError_t error = hipMalloc (&result_ptr, sizeof (int));

  (gdb) info sources
  C:/msys2/home/alves/gdb/build-testsuite/outputs/gdb.rocm/simple/simple:

  C:/rocgdb/src/gdb/testsuite/gdb.rocm/simple.cpp, C:/Program Files (x86)/Windows Kits/10/Include/10.0.22621.0/ucrt/corecrt_stdio_config.h,
  C:/Program Files/AMD/ROCm/7.1/include/hip/hip_runtime_api.h, C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.39.33519/include/stdint.h,
  C:/Program Files (x86)/Windows Kits/10/Include/10.0.22621.0/ucrt/stdio.h, C:/Program Files/AMD/ROCm/7.1/lib/clang/21/include/__stddef_nullptr_t.h,
  C:/Program Files/AMD/ROCm/7.1/lib/clang/21/include/__stddef_size_t.h, C:/Program Files/Microsoft Visual Studio/2022/Community/VC/Tools/MSVC/14.39.33519/include/cstdlib,
  C:/Program Files (x86)/Windows Kits/10/Include/10.0.22621.0/ucrt/stdlib.h, C:/Program Files (x86)/Windows Kits/10/Include/10.0.22621.0/ucrt/corecrt_search.h,
  C:/Program Files (x86)/Windows Kits/10/Include/10.0.22621.0/ucrt/corecrt_malloc.h,
  ...

  (gdb) info inferiors
    Num  Description       Connection           Executable
  * 1    process 19920     1 (native)           C:/msys2/home/alves/gdb/build-testsuite/outputs/gdb.rocm/simple/simple

  (gdb) info shared
  From                To                  Syms Read   Shared Object Library
  0x00007ffd22f91000  0x00007ffd231a69a8  Yes (*)     C:/Windows/SYSTEM32/ntdll.dll
  0x00007ffd21af1000  0x00007ffd21bb2520  Yes (*)     C:/Windows/System32/kernel32.dll
  0x00007ffd20091000  0x00007ffd20432548  Yes (*)     C:/Windows/System32/KernelBase.dll
  0x00007ffcc89c1000  0x00007ffcc9b145bc  Yes (*)     C:/Windows/SYSTEM32/amdhip64_7.dll
  0x00007ffd22911000  0x00007ffd22d829b0  Yes (*)     C:/Windows/System32/setupapi.dll
  0x00007ffd216c1000  0x00007ffd217653f0  Yes (*)     C:/Windows/System32/msvcrt.dll
  0x00007ffd22431000  0x00007ffd224de5c8  Yes (*)     C:/Windows/System32/advapi32.dll
  0x00007ffd21a41000  0x00007ffd21ae52b8  Yes (*)     C:/Windows/System32/sechost.dll
  0x00007ffd20651000  0x00007ffd20676af0  Yes (*)     C:/Windows/System32/bcrypt.dll
  0x00007ffd21f31000  0x00007ffd22045860  Yes (*)     C:/Windows/System32/rpcrt4.dll
  0x00007ffd22d91000  0x00007ffd22f40e50  Yes (*)     C:/Windows/System32/user32.dll
  0x00007ffd20781000  0x00007ffd207a43d8  Yes (*)     C:/Windows/System32/win32u.dll
  0x00007ffd228d1000  0x00007ffd228f73d8  Yes (*)     C:/Windows/System32/gdi32.dll
  0x00007ffd207b1000  0x00007ffd208d09c8  Yes (*)     C:/Windows/System32/gdi32full.dll
  0x00007ffd20b91000  0x00007ffd20c28410  Yes (*)     C:/Windows/System32/msvcp_win.dll
  0x00007ffd20471000  0x00007ffd2057f410  Yes (*)     C:/Windows/System32/ucrtbase.dll
  0x00007ffd21541000  0x00007ffd215afbc8  Yes (*)     C:/Windows/System32/ws2_32.dll
  0x00007ffd223f1000  0x00007ffd2241fc40  Yes (*)     C:/Windows/System32/imm32.dll
  (*): Shared library is missing debugging information.

  (gdb) detach
  Detaching from program: C:/msys2/home/alves/gdb/build-testsuite/outputs/gdb.rocm/simple/simple, process 7816
  [Inferior 1 (process 7816) detached]

  (gdb) cd /tmp
  Working directory C:/tmp.
  (gdb) pwd
  Working directory C:/tmp.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Reviewed-By: Andrew Burgess <aburgess@redhat.com>
Change-Id: I6366c41d200938259330e60bc1e98b576f787518
2026-07-06 22:13:07 +01:00
Tom Tromey
c2d4b5e113 Do not write negative PID or TID in remote protocol
Currently both gdb and gdbserver can write a negative number for the
PID or TID.  However, the only negative value that really makes sense
is the special case of "-1" -- in other cases if the PID or TID has
the high bit set, it should still be written as a positive number.

This patch attempts to fix the bug.

v2 of this patch combines the implementations and moves them to
gdbsupport.  I tried making these standalone functions in rsp-low.cc,
but that runs afoul of libipa.  So, I made them methods of ptid_t.

The new unit tests pointed out that round-tripping a sign-extended
number didn't really work, because the checks were done via ULONGEST.
It's kind of unfortunate that the PID and LWP are host-dependent
types.  This should probably be fixed, but I haven't done so here.
Meanwhile I changed the checks to use the corresponding unsigned type.

v1 is here

    https://inbox.sourceware.org/gdb-patches/20260311202152.2704410-1-tromey@adacore.com/

Regression tested on x86-64 Fedora 43.

Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=25111
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33979
Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=33983
2026-07-01 11:47:57 -06:00
Simon Marchi
e17f386d7f gdbserver/linux-low: carry over stop_expected flag after exec (avoid spurious SIGSTOPs)
Running test gdb.base/vfork-follow-parent.exp on the native-gdbserver
board is flaky.  This test has GDB debugging a vfork parent and child.
When resuming the child, we expect it to run through an exec, and then
exit, like so:

    continue
    Continuing.
    [New inferior 2 (process 3286309)]
    process 3286309 is executing new program: /home/simark/build/binutils-gdb/gdb/testsuite/outputs/gdb.base/vfork-follow-parent/vforked-prog
    [Inferior 2 (process 3286309) exited normally]
    (gdb) PASS: gdb.base/vfork-follow-parent.exp: exec_file=vfork-follow-parent-exec: target-non-stop=off: non-stop=off: resolution_method=schedule-multiple: continue to end of inferior 2

Instead, we sometimes see it reporting a spurious SIGSTOP:

    continue
    Continuing.
    [New inferior 2 (process 3281383)]
    process 3281383 is executing new program: /home/simark/build/binutils-gdb/gdb/testsuite/outputs/gdb.base/vfork-follow-parent/vforked-prog

    Thread 2.1 "vforked-prog" received signal SIGSTOP, Stopped (signal).
    Cannot remove breakpoints because program is no longer writable.
    Further execution is probably impossible.
    0x00007ffff7fe0300 in ?? () from /lib64/ld-linux-x86-64.so.2
    (gdb) FAIL: gdb.base/vfork-follow-parent.exp: exec_file=vfork-follow-parent-exec: target-non-stop=off: non-stop=off: resolution_method=schedule-multiple: continue to end of inferior 2

Note that this case uses "target-non-stop=off", meaning that when one
thread reports a stop, GDBserver attempts to stop the other threads
itself before reporting the stop to GDB.  The bug is related to
GDBserver's bookkeeping of the threads.

When running the test 100 times, it failed 6 times.  Using taskset to
pin the process subtree to a single CPU seemed to make it more likely
to fail: on 100 runs, it failed 30 times.

The cause
=========

The steps occurring in the "pass" case are:

 1. Process P (Parent) is blocked inside the vfork system call, waiting
    for process C (Child) to exec or exit.
 2. Process C is currently stopped at its first instruction (right out
    of vfork).
 3. We resume process C (the "continue" seen in the logs above).
 4. Process C calls exec, as a result the kernel produces two events to
    be consumed by the tracer (GDBserver):

     - For P, a vfork done event (PTRACE_EVENT_VFORK_DONE)
     - For C, an exec event (PTRACE_EVENT_EXEC)

 5. Let's suppose here that waitpid happens to return the
    PTRACE_EVENT_EXEC for C first.
 6. Upon receiving the event, GDBserver calls stop_all_lwps, which sends
    a SIGSTOP to P, and sets `lwp->stop_expected` for P.
 7. GDBserver waits for P to stop, waitpid returns the
    PTRACE_EVENT_VFORK_DONE event.  GDBserver stashes it in
    lwp->status_pending.  The SIGSTOP for P is still pending at the
    kernel level.
 8. When we resume C, everything is fine, it runs until exit.
 9. When we resume P, GDBserver receives the SIGSTOP event for P, but
    suppresses it because `lwp->stop_expected` is set for P.

Now, for the failing case, imagine that at step 5 the kernel decided to
return the PTRACE_EVENT_VFORK_DONE event for P first.  The following
steps would play out like this:

 6. Upon receiving the event, GDBserver calls stop_all_lwps, which sends
    a SIGSTOP to C, and sets `lwp->stop_expected` for C.
 7. GDBserver waits for C to stop, waitpid returns the PTRACE_EVENT_EXEC
    event.
 8. In the handling of PTRACE_EVENT_EXEC (in
    linux_process_target::handle_extended_wait), GDBserver deletes the
    process and its threads (the mourn call), and creates a brand new
    process and lwp_info for C.  Note that this loses the previously set
    `lwp->stop_expected`.  The SIGSTOP for C is still pending at the
    kernel level.
 9. When we resume C, GDBserver receives the SIGSTOP event for C, and
    because `lwp->stop_expected` is not set, GDBserver doesn't recognize
    it as its own, and the stop is presented to the user.

The fix
=======

The (simplest) fix is to transfer the `lwp->stop_expected` from the old
lwp_info to the new one.  When doing so, when we resume C and GDBserver
receives the SIGSTOP event for C, it recognizes it as its own and
suppresses it.

Some care is needed in case process C is multi-threaded and the exec is
done by a non-leader thread.  When a non-leader thread execs, the kernel
scraps all other threads and renumbers this one to the tgid, so that it
becomes the new leader.  The PTRACE_EVENT_EXEC event is reported using
that new renumbered id.  But if a SIGSTOP was pending for the non-leader
exec'ing thread when the exec happened, it will still be pending
post-exec for that thread under its new post-exec leader identity.

Here is a hypothetical but more concrete scenario:

 - There are two threads, 100.100 (the leader) and 100.101.
 - Thread 100.101 is stopped at the entry of the execve system call (so
   the effects of execve haven't occurred yet) when GDBserver sends it a
   SIGSTOP and sets `lwp->stop_expected`.  The SIGSTOP becomes pending
   in the kernel.
 - When 100.101 is resumed, the exec occurs, the kernel deletes thread
   100.100 and renumbers 100.101 to 100.100.  The latter still has the
   SIGSTOP pending.
 - GDBserver receives a PTRACE_EVENT_EXEC event for thread 100.100.
 - Upon resumption, GDBserver then receives an event for the SIGSTOP,
   for thread 100.100.

All this to say that when transferring the `lwp->stop_expected` flag
from the old lwp_info to the new, we must take care to read the exec'ing
thread's flag.  If we use the id reported for the PTRACE_EVENT_EXEC to
look up an lwp_info, then we'll get the leader's lwp_info, which may not
have `lwp->stop_expected` set.  Instead, we must get the exec'ing
thread's original id using PTRACE_GETEVENTMSG, and use that to source
the right lwp_info to transfer the `lwp->stop_expected` flag.

There is a comment about using PTRACE_GETEVENTMSG with PTRACE_EVENT_EXEC
in gdb/linux-nat.c:

    ...
    tid to the tgid, and the previous leader vanishes.  Since
    Linux 3.0, the former thread ID can be retrieved with
    PTRACE_GETEVENTMSG, but since we support older kernels, don't
    bother with it, and just walk the LWP list.  Even with
    ...

Linux 3.0 was released in 2011, so I think it's fine to use that.

With the fix, I don't get any failures after 100 test runs (even with
taskset).

Kernel behavior experiments
===========================

The fix relies on assumptions about how the kernel orders ptrace events
and handles pending signals across exec.  I experimented with these
using standalone ptrace programs (mostly written by my buddy Claude).
The programs would drive a thread of the tracee to the execve syscall
entry, deliver a SIGSTOP to a thread, resume things and then look at
what events would come out of waitpid.  Here are the scenarios I tried:

  - Single-threaded: a tracee stopped at execve syscall entry is sent a
    SIGSTOP, then allowed to exec.  The kernel reports PTRACE_EVENT_EXEC first,
    then the SIGSTOP.

  - Multi-threaded, non-leader exec: a non-leader thread stopped at
    execve syscall entry is sent a SIGSTOP, then allowed to exec.  The
    kernel reports PTRACE_EVENT_EXEC, then the SIGSTOP, both under the
    leader id (the exec'ing non-leader got renumbered).

  - Multi-threaded, leader has a pending SIGSTOP while a non-leader
    execs: the leader is sent a SIGSTOP, which stays pending, then we
    let the non-leader thread exec (giving it a few seconds to be sure).
    The kernel reports PTRACE_EVENT_EXEC under the leader id (the
    exec'ing non-leader got renumbered) and the SIGSTOP has vanished.

What about GDB
==============

I tried to check if the same bug could happen with GDB's linux-nat
target, and if the same fix was needed.  linux-nat takes a different
approach when handling PTRACE_EVENT_EXEC.  It wipes all lwp_infos except
the leader:

      for (lwp_info &other_lp : all_lwps_safe ())
	if (&other_lp != lp && other_lp.ptid.pid () == lp->ptid.pid ())
	  exit_lwp (&other_lp);

Here, LP is an lwp_info obtained using the event ptid of the
PTRACE_EVENT_EXEC, therefore the leader's lwp_info (even if the exec was
done by a non-leader).

If the exec is done by the leader, as is the case with
gdb.base/vfork-follow-parent.exp, we are ok.  Because GDB doesn't delete
and re-create the lwp_info, the equivalent of GDBserver's
`lwp_info::stop_expected`, `lwp_info::signalled`, survives the exec.

If the exec is done by a non-leader, then we could be in trouble.  If
the leader's signalled flag is not set, but the exec'ing non-leader's
flag is set, then we'll lose it.  I suppose we could fix GDB to use
PTRACE_GETEVENTMSG to get the exec'ing thread former id, look up the
lwp_info for that id, and preserve that lwp_info.

Change-Id: Iaebd1d2cf813dcad35d7d8639bbaed80d40b7d1e
Approved-By: Pedro Alves <pedro@palves.net>
2026-06-26 22:35:42 -04:00
Hannes Domani
a1523d5159 gdb+gdbserver: Fix build for aarch64-windows
Some time ago siginfo_re was made per-thread state, but
not every use location was adjusted, giving this error:

../../gdb/aarch64-windows-nat.c:139:31: error: no member named 'siginfo_er' in 'aarch64_windows_per_inferior'
  139 |   if (aarch64_windows_process.siginfo_er.ExceptionCode != EXCEPTION_BREAKPOINT
      |       ~~~~~~~~~~~~~~~~~~~~~~~ ^

Fix by looking up the exception-record of the current thread.

Approved-By: Tom Tromey <tom@tromey.com>
2026-06-26 17:02:09 +02:00
Pedro Alves
613b8ee3f8 Windows gdb+gdbserver: Decode Cygwin ExitProcess codes
On native Cygwin, GDB misreports the inferior's exit reason in several
common cases, resulting in several gdb.base/exitsignal.exp failures:

 $ grep FAIL gdb.sum
 FAIL: gdb.base/exitsignal.exp: how=run: signal: program terminated with SIGSEGV (the program exited)
 FAIL: gdb.base/exitsignal.exp: how=run: signal: $_exitsignal is 11 (SIGSEGV) after SIGSEGV.
 FAIL: gdb.base/exitsignal.exp: how=run: signal: $_exitcode is still void after SIGSEGV
 FAIL: gdb.base/exitsignal.exp: how=run: signal: $_exitsignal is 11 (SIGSEGV) after restarting the inferior
 FAIL: gdb.base/exitsignal.exp: how=run: signal: $_exitcode is still void after restarting the inferior
 FAIL: gdb.base/exitsignal.exp: how=run: normal: continue to exit
 FAIL: gdb.base/exitsignal.exp: how=run: normal: $_exitcode is one after normal inferior is executed
 FAIL: gdb.base/exitsignal.exp: how=run: normal: $_exitsignal is still void after normal inferior is executed
 FAIL: gdb.base/exitsignal.exp: how=attach: normal: continue to exit (the program exited)
 FAIL: gdb.base/exitsignal.exp: how=attach: normal: $_exitcode is one after normal inferior is executed

For example, from gdb.log, the normal exit case:

 ...
 [Thread 14300.0x4214 (id 1) exited with code 1]
 [Thread 14300.0x1b1c (id 4) exited with code 1]
 [Thread 14300.0x1e2c (id 2) exited with code 1]

 Program terminated with signal SIGHUP, Hangup.
 The program no longer exists.
 (gdb) FAIL: gdb.base/exitsignal.exp: how=run: normal: continue to exit

The program in fact exited normally with code 1.  SIGHUP happens to be
signal 1, and GDB picked the wrong interpretation.

Similarly, for the signal termination case:

 ...
 continue
 Continuing.
 [Thread 4600.0x3104 (id 4) exited with code 2816]
 [Thread 4600.0x2bcc (id 3) exited with code 2816]
 [Thread 4600.0x2f44 (id 1) exited with code 2816]
 [Inferior 1 (process 4600) exited with code 05400]
 (gdb) FAIL: gdb.base/exitsignal.exp: how=run: signal: program terminated with SIGSEGV (the program exited)

Here the inferior died with SIGSEGV, but GDB reported exit decimal
2816 / octal 05400 / hex 0x0B00, which is SIGSEGV swapped into the
high byte of a waitpid exit status.

The problem is that Cygwin waitpid exit status and Windows exit codes
do not have the same encoding, and GDB & GDBserver do not know about
this.

This commit fixes it.  It adds a Cygwin-specific branch to the code
that determines the terminating signal and status of a program.  The
branch for native Windows/MinGW GDB is left intact, no behavior change
there.

The way to decode the exit codes is a little bit tricky, see detailed
comments added by the patch.  To exercise the "raw NTSTATUS error
code" path in windows_process_info::exit_process_to_target_status,
gdb.base/exitsignal.exp is extended to debug a native Windows program
that crashes with a segfault (STATUS_ACCESS_VIOLATION).

With this, gdb.base/exitsignal.exp passes cleanly on Cygwin.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>
Change-Id: Icaebcc234b71927915c996fd120884604441415b
2026-06-12 14:57:21 +01:00
Pedro Alves
4fce4baa74 Windows gdb+gdbserver: Share exit status logic
Move the exit status logic added by commit 559e7e5056 ("Improve
process exit status macros on MinGW") from both GDB and GDBserver to a
shared routine used by both.

The next patch extends this routine with Cygwin-specific decoding.

Change-Id: I4bf08c6beff0d1688064a81d49bbdd615643735e
2026-06-12 14:57:21 +01:00
Tom de Vries
6c85ef111b [gdb] Use using instead of typedef
After commit 1eed06ae51 ("[gdbsupport] Use using instead of typedef in
next_iterator") I wondered if I could do something similar using sed.

Result of:
...
$ find gdb* -type f -name "*.[ch]" -o -name "*.cc" \
    | egrep -v /testsuite/ \
    | xargs sed -i \
	    's/^\([ \t]*\)typedef \([a-zA-Z_0-9:<>,.() ]*\) \([\*&][\*&]*\)\([a-zA-Z_0-9]*\);/\1using \4 = \2 \3;/'

$ find gdb* -type f -name "*.[ch]" -o -name "*.cc" \
    | egrep -v /testsuite/ \
    | xargs sed -i \
	    's/^\([ \t]*\)typedef \([a-zA-Z_0-9:<>,.() ]*\) \([a-zA-Z_0-9]*\);/\1using \3 = \2;/'
...

Tested on x86_64-linux.
2026-06-11 08:54:34 +02:00
Tom de Vries
970570ce5c [gdb] Add missing i18n support to warning strings (part 5)
Add missing i18n support to some multi-line warning strings.

Approved-By: Tom Tromey <tom@tromey.com>
2026-06-09 22:14:07 +02:00
Tom de Vries
ab0df7ebbf [gdb] Add missing i18n support to warning strings (part 4)
Add missing i18n support to some warning strings.

Result of:
...
$ find gdb* -type f -name "*.[ch]" -o -name "*.cc" \
    | egrep -v /testsuite/ \
    | xargs sed -i \
        '/"[ \t]*%s[ \t]*"/b l;s/\([ \t]\)warning (\("[^"]*"\)\(.*\));/\1warning (_(\2)\3);/;:l'
...

Approved-By: Tom Tromey <tom@tromey.com>
2026-06-09 22:14:07 +02:00
Tom de Vries
3d094ec4c5 [gdb] Add missing i18n support to warning strings (part 3)
Add missing i18n support to some warning strings.

Result of:
...
$ find gdb* -type f -name "*.[ch]" -o -name "*.cc"
    | egrep -v /testsuite/ \
    | xargs sed -i \
        '/"[ \t]*%s[ \t]*"/b l;s/\([ \t]\)warning (\("[^"]*"\),$/\1warning (_(\2),/;:l'
...

Approved-By: Tom Tromey <tom@tromey.com>
2026-06-09 22:14:07 +02:00
Tom de Vries
6c22e5b94a [gdb] Add missing i18n support to warning strings (part 2)
Add missing i18n support to some warning strings.

Result of:
...
$ find gdb* -type f -name "*.[ch]" -o -name "*.cc" \
    | egrep -v /testsuite/ \
    | xargs sed -i \
        '/"[ \t]*%s[ \t]*"/b l;s/\([ \t]\)warning (\("[^"]*"\)\([^)]*\));/\1warning (_(\2)\3);/;:l'
...

Approved-By: Tom Tromey <tom@tromey.com>
2026-06-09 22:14:07 +02:00
Tom de Vries
edad26d2e8 [gdb] Add missing i18n support to warning strings (part 1)
Add missing i18n support to some warning strings.

Result of:
...
$ find gdb* -type f -name "*.[ch]" -o -name "*.cc" \
    | egrep -v /testsuite/ \
    | xargs sed -i \
        's/\([ \t]\)warning (\("[^"]*"\));/\1warning (_(\2));/'
...

Approved-By: Tom Tromey <tom@tromey.com>
2026-06-09 22:14:07 +02:00
Tom de Vries
635572ef07 [gdb] Add missing i18n support to errors strings (part 5)
Add missing i18n support to some multi-line error strings.

Approved-By: Tom Tromey <tom@tromey.com>
2026-06-09 22:14:07 +02:00
Tom de Vries
ca83136019 [gdb] Add missing i18n support to error strings (part 4)
Add missing i18n support to some error strings.

Result of:
...
$ find gdb* -type f -name "*.[ch]" -o -name "*.cc" \
    | egrep -v /testsuite/ \
    | xargs sed -i \
        '/"[ \t]*%s[ \t]*"/b l;s/\([ \t]\)error (\("[^"]*"\)\(.*\));/\1error (_(\2)\3);/;:l'
...

Approved-By: Tom Tromey <tom@tromey.com>
2026-06-09 22:14:07 +02:00
Tom de Vries
d62997ecff [gdb] Add missing i18n support to error strings (part 3)
Add missing i18n support to some error strings.

Result of:
...
$ find gdb* -type f -name "*.[ch]" -o -name "*.cc" \
    | egrep -v /testsuite/ \
    | xargs sed -i \
        '/"[ \t]*%s[ \t]*"/b l;s/\([ \t]\)error (\("[^"]*"\)\([^)]*\));/\1error (_(\2)\3);/;:l'
...

Approved-By: Tom Tromey <tom@tromey.com>
2026-06-09 22:14:07 +02:00
Tom de Vries
5a6fa4bf84 [gdb] Add missing i18n support to error strings (part 2)
Add missing i18n support to some error strings.

Result of:
...
$ find gdb* -type f -name "*.[ch]" -o -name "*.cc" \
    | egrep -v /testsuite/ \
    | xargs sed -i \
        '/"[ \t]*%s[ \t]*"/b l;s/\([ \t]\)error (\("[^"]*"\),$/\1error (_(\2),/;:l'
...

Approved-By: Tom Tromey <tom@tromey.com>
2026-06-09 22:14:07 +02:00
Tom de Vries
d7e2f7f484 [gdb] Add missing i18n support to error strings (part 1)
Add missing i18n support to some error strings.

Result of:
...
$ find gdb* -type f \
    | egrep -v /testsuite/ \
    | xargs sed -i \
          's/\([ \t]\)error (\("[^"]*"\));/\1error (_(\2));/'
...

Approved-By: Tom Tromey <tom@tromey.com>
2026-06-09 22:14:06 +02:00
Tom Tromey
eba7a4ccfb Add two new warnings to warning.m4
I recently learned that GCC has improved -Wdangling-reference and
added -Wunterminated-string-initialization.  Both of these seem
sensible to me, so this patch adds them to warning.m4.

gdb rebuilds cleanly with this in place on x86-64 Fedora 43.

Reviewed-By: Tom de Vries <tdevries@suse.de>
2026-06-05 14:51:13 -06:00
Pedro Alves
342ed14c19 Fix "set cwd ..." on Cygwin, part 2
Even after the previous patch, on both native and gdbserver Cygwin, we
get:

 (gdb) set cwd /cygdrive/d/cygwin-gdb/build-testsuite/outputs/gdb.base/exitsignal
 (gdb) start
 Temporary breakpoint 3 at 0x100401094: file /home/alves/rocm/gdb/src/gdb/testsuite/gdb.base/segv.c, line 26.
 Starting program: /cygdrive/d/cygwin-gdb/build-testsuite/outputs/gdb.base/exitsignal/exitsignal.exe
 ️ Error creating process /cygdrive/d/cygwin-gdb/build-testsuite/outputs/gdb.base/exitsignal/exitsignal.exe (error 6): The handle is invalid.
 (gdb)

On the native side, this is because in
windows_nat_target::create_inferior, we unconditionally convert
forward slashes to backward slashes:

  /cygdrive/d/cygwin-gdb/build-testsuite/outputs/gdb.base/exitsignal
  =>
  \cygdrive\d\cygwin-gdb\build-testsuite\outputs\gdb.base\exitsignal

and then cygwin_conv_path(CCP_POSIX_TO_WIN_W) does nothing on such
path, as the backward slashes make the path not look like a Unix-style
path.

CreateProcess then fails to CD into that directory, as that's not a
real Windows native path.

The fix is to not do the slashes replacement on Cygwin.

On the GDBserver side, we're just completely missing the
cygwin_conv_path logic.  This commit adds it.  The code isn't shared
with GDB because GDB uses wide chars, and GDBserver uses narrow char.

Approved-By: Tom Tromey <tom@tromey.com>
Change-Id: I004f2a562757a566423f6acb9aecfcc1a7f2f746
commit-id: 85aa8c22
2026-05-25 15:34:58 +01:00
Tom Tromey
54c605be19 Allow styling when using throw_* functions
The throw_* family of functions use the varargs constructor for
gdb_exception, which then calls string_vprintf.  This means that
styling cannot be applied here by gdb.

This patch changes this code to use a client-supplied formatting
function.  For gdbserver this remains string_vprintf, but for gdb it
now allows styling.

I did look at unifying 'error' and the throw_* functions a bit more,
but this would have meant unravelling some IPA code.
2026-05-08 13:02:32 -06:00
Pedro Alves
ae2f226dc8 Windows gdb: Add non-stop support
This patch adds non-stop support to the native Windows target.

This is made possible by the ContinueDebugEvent DBG_REPLY_LATER flag:

https://learn.microsoft.com/en-us/windows/win32/api/debugapi/nf-debugapi-continuedebugevent

  Supported in Windows 10, version 1507 or above, this flag causes
  dwThreadId to replay the existing breaking event after the target
  continues. By calling the SuspendThread API against dwThreadId, a
             ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  debugger can resume other threads in the process and later return to
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  the breaking.
  ^^^^^^^^^^^^

The patch adds a new comment section in gdb/windows-nat.c providing an
overall picture of how all-stop / non-stop work.

Without DBG_REPLY_LATER, if we SuspendThread the thread, and then
immediately ContinueDebugThread(DBG_CONTINUE) before getting back to
the prompt, we could still have non-stop mode working, however, then
users wouldn't have a chance to decide whether to pass the signal to
the inferior the next time they resume the program, as that is done by
passing DBG_EXCEPTION_NOT_HANDLED to ContinueDebugEvent, and that has
already been called.

The patch teaches the Windows native backend to use that
DBG_REPLY_LATER flag, and also adds support for target_stop, so the
core can pause threads at its discretion.  This pausing does not use
the same mechanisms used in windows_nat_target::interrupt, as that
injects a new thread in the inferior.  Instead, for each thread the
core wants paused, it uses SuspendThread, and enqueues a pending
GDB_SIGNAL_0 stop on the thread.

Since DBG_REPLY_LATER only exists on Windows 10 and later, we only
enable non-stop mode on Windows 10 and later.

There is no displaced stepping support, but that's "just" a missed
optimization to be done later.

Cygwin signals handling was a major headache, but I managed to get it
working.  See the "Cygwin signals" description section I added at the
top of windows-nat.c.

Another interesting bit, is that the use DBG_REPLY_LATER caused one
problem with detach.  The Windows kernel re-raises any exception
previously intercepted and deferred with DBG_REPLY_LATER in the
inferior after we detach.  We need to flush those events, and suppress
those which aren't meant to be seen by the inferior (e.g.,
breakpoints, single-steps, any with matching "handle SIG nopass",
etc.), otherwise the inferior dies immediately after the detach, due
to an unhandled exception.

Acked-By: Tom Tromey <tom@tromey.com>
Change-Id: Id71aef461c43c244120635b5bedc638fe77c31fb
commit-id:bbf38a26
2026-04-30 18:37:32 +01:00
Pedro Alves
edeff39baf Introduce windows_nat::event_code_to_string
Instead of:

   switch (event_code)
     {
     case FOO_DEBUG_EVENT:
      DEBUG_EVENTS (..., "FOO_DEBUG_EVENT");
      ...
     case BAR_DEBUG_EVENT:
      DEBUG_EVENTS (..., "BAR_DEBUG_EVENT");
      ...

... with one DEBUG_EVENTS call per event type, log the event just once
before the switch, and introduce a new event_code_to_string function
to handle the event code to string conversion.

Do the same on GDB's and gdbserver's Windows backends.

Approved-By: Tom Tromey <tom@tromey.com>
Change-Id: Id38b7e30df182e4742f3179538de3c643cf42668
commit-id:a8abf6a6
2026-04-30 18:37:32 +01:00
Pedro Alves
1ba40beb4c Windows gdb: Avoid writing debug registers if watchpoint hit pending
Several watchpoint-related testcases, such as
gdb.threads/watchthreads.exp for example, when tested with the backend
in non-stop mode, exposed an interesting detail of the Windows debug
API that wasn't considered before.  The symptom observed is spurious
SIGTRAPs, like:

  Thread 1 "watchthreads" received signal SIGTRAP, Trace/breakpoint trap.
  0x00000001004010b1 in main () at .../src/gdb/testsuite/gdb.threads/watchthreads.c:48
  48              args[i] = 1; usleep (1); /* Init value.  */

After a good amount of staring at logs and headscratching, I realized
the problem:

 #0 - It all starts with the fact that multiple threads can hit an
      event at the same time.  Say, a watchpoint for thread A, and a
      breakpoint for thread B.

 #1 - Say, WaitForDebugEvent reports the breakpoint hit for thread B
      first, then GDB for some reason decides to update debug
      registers, and continue.  Updating debug registers means writing
      the debug registers to _all_ threads, with SetThreadContext.

 #2 - WaitForDebugEvent reports the watchpoint hit for thread A.
      Watchpoint hits are reported as EXCEPTION_SINGLE_STEP.

 #3 - windows-nat checks the Dr6 debug register to check if the step
      was a watchpoint or hardware breakpoint stop, and finds that Dr6
      is completely cleared.  So windows-nat reports a plain SIGTRAP
      (given EXCEPTION_SINGLE_STEP) to the core.

 #4 - Thread A was not supposed to be stepping, so infrun reports the
      SIGTRAP to the user as a random signal.

The strange part is #3 above.  Why was Dr6 cleared?

Turns out that (at least in Windows 10 & 11), writing to _any_ debug
register has the side effect of clearing Dr6, even if you write the
same values the registers already had, back to the registers.

I confirmed it clearly by adding this hack to GDB:

  if (th->context.ContextFlags == 0)
    {
      th->context.ContextFlags = CONTEXT_DEBUGGER_DR;

      /* Get current values of debug registers.  */
      CHECK (GetThreadContext (th->h, &th->context));

      DEBUG_EVENTS ("For 0x%x (once),  Dr6=0x%llx", th->tid, th->context.Dr6);

      /* Write debug registers back to thread, same values,
	 and re-read them.  */
      CHECK (SetThreadContext (th->h, &th->context));
      CHECK (GetThreadContext (th->h, &th->context));

      DEBUG_EVENTS ("For 0x%x (twice), Dr6=0x%llx", th->tid, th->context.Dr6);
    }

Which showed Dr6=0 after the write + re-read:

  [windows events] fill_thread_context: For 0x6a0 (once),  Dr6=0xffff0ff1
  [windows events] fill_thread_context: For 0x6a0 (twice), Dr6=0x0

This commit fixes the issue by detecting that a thread has a pending
watchpoint hit to report (Dr6 has interesting bits set), and if so,
avoid modifying any debug register.  Instead, let the pending
watchpoint hit be reported by WaitForDebugEvent.  If infrun did want
to modify watchpoints, it will still be done when the thread is
eventually re-resumed after the pending watchpoint hit is reported.
(infrun knows how to gracefully handle the case of a watchpoint hit
for a watchpoint that has since been deleted.)

Move the fill_thread_context method from windows_nat_target to
windows_per_inferior so it can be used by gdbserver too.

Approved-By: Tom Tromey <tom@tromey.com>
Change-Id: I21a3daa9e34eecfa054f0fea706e5ab40aabe70a
commit-id:a28f8d4e
2026-04-24 21:28:44 +01:00
Pedro Alves
0803ecc0b3 Windows gdb+gdbserver: Eliminate struct pending_stop
After the previous patches, struct pending_stop only contains one
field.  So move that field into the windows_thread_info structure
directly, and eliminate struct pending_stop.

Approved-By: Tom Tromey <tom@tromey.com>
Change-Id: I7955884b3f378d8b39b908f6252d215f6568b367
commit-id:fb68c808
2026-04-24 21:28:44 +01:00
Pedro Alves
6326101233 Windows gdb+gdbserver: Share $_siginfo reading code
Both GDB and GDBserver have similar code to read the $_siginfo data.
This patch moves the bulk of it to gdb/nat/windows-nat.c so it can be
shared.

Approved-By: Tom Tromey <tom@tromey.com>
Change-Id: I58f9074caf6362274453c78ed1fc9e31249f6854
2026-04-24 21:28:44 +01:00
Pedro Alves
fcff9da0d5 Add backpointer from windows_thread_info to windows_process_info
The next patch will move some duplicated code in gdb and gdbserver to
gdb/nat/windows-nat.c, where it would be convenient to get at the
Windows process info of a given Windows thread info, from within a
windows_thread_info method.

I first thought of passing down the windows_process_info pointer as
argument to the windows_thread_info method, but that looked a bit odd.
I think it looks better to just add a back pointer, so that's what
this patch does.  The following patch will then add a use of it.

I suspect this will help moving more duplicated code to
gdb/nat/windows-nat.c in the future, too.

Approved-By: Tom Tromey <tom@tromey.com>
Change-Id: I47fc0d3323be5b6f6fcfe912b768051a41910666
2026-04-24 21:28:44 +01:00
Pedro Alves
1139a5c8e7 Windows gdb+gdbserver: Make siginfo_er per-thread state
With non-stop mode support, each thread has its own "last event", and
so printing $_siginfo should print the siginfo of the selected thread.
Likewise, with all-stop and scheduler-locking.

This patch reworks the siginfo functions in gdb/windows-nat.c and
gdbserver/win32-low.cc to reuse the exception record already saved
within each thread's 'last_event' field.

Here's an example of what you'll see after the whole non-stop series:

  (gdb) thread apply all p -pretty -- $_siginfo

  Thread 3 (Thread 2612.0x1470):
  $1 = {
    ExceptionCode = DBG_CONTROL_C,
    ExceptionFlags = 0,
    ExceptionRecord = 0x0,
    ExceptionAddress = 0x7ffd0583e929 <KERNELBASE!EncodeRemotePointer+8249>,
    NumberParameters = 0,
    {
      ExceptionInformation = {0 <repeats 15 times>},
      AccessViolationInformation = {
	Type = READ_ACCESS_VIOLATION,
	Address = 0x0
      }
    }
  }

  Thread 2 (Thread 2612.0x1704):
  $2 = {
    ExceptionCode = SINGLE_STEP,
    ExceptionFlags = 0,
    ExceptionRecord = 0x0,
    ExceptionAddress = 0x7ffd080ad6e4 <ntdll!ZwDelayExecution+20>,
    NumberParameters = 0,
    {
      ExceptionInformation = {0 <repeats 15 times>},
      AccessViolationInformation = {
	Type = READ_ACCESS_VIOLATION,
	Address = 0x0
      }
    }
  }

  Thread 1 (Thread 2612.0x434):
  $3 = {
    ExceptionCode = BREAKPOINT,
    ExceptionFlags = 0,
    ExceptionRecord = 0x0,
    ExceptionAddress = 0x7ff6f691174c <main+185>,
    NumberParameters = 1,
    {
      ExceptionInformation = {0 <repeats 15 times>},
      AccessViolationInformation = {
	Type = READ_ACCESS_VIOLATION,
	Address = 0x0
      }
    }
  }
  (gdb)

This was in non-stop mode, and the program originally had two threads.
Thread 1 stopped for a breakpoint, then thread 2 was manually
interrupted/paused and then single-stepped.  And then I typed Ctrl-C
in the inferior's terminal, which made Windows inject thread 3 in the
inferior, and report a DBG_CONTROL_C exception for it.

Approved-By: Tom Tromey <tom@tromey.com>
Change-Id: I5d4f1b62f59e8aef3606642c6524df2362b0fb7d
commit-id:e0f75dea
2026-04-24 21:28:44 +01:00
Pedro Alves
1cccba5330 Windows gdb+gdbserver: Make last_sig per-thread state
With non-stop mode, each thread is controlled independently of the
others, and each thread has its own independent reason for its last
stop.

Thus, any thread-specific state that is currently per-process must be
converted to per-thread state.

This patch converts windows_process_info::last_sig to per-thread
state, moving it to windows_thread_info instead.

This adjusts both native gdb and gdbserver.

Approved-By: Tom Tromey <tom@tromey.com>
Change-Id: Ie8c673a819be445753d967afd3a6084565648448
commit-id:d7dd0d0e
2026-04-24 21:28:44 +01:00
Pedro Alves
2e1aacf15a Windows gdb+gdbserver: Make current_event per-thread state
With non-stop mode, each thread is controlled independently of the
others, and each thread has its own independent reason for its last
stop.

Thus, any thread-specific state that is currently per-process must be
converted to per-thread state.

This patch converts windows_process_info::current_event, moving it to
windows_thread_info instead, renamed to last_event.

Since each thread will have its own copy of its last Windows debug
event, we no longer need the same information stored in struct
pending_stop.

Since windows_process.current_event no longer exists, we need to pass
the current event as parameter to a number of methods.

This adjusts both native gdb and gdbserver.

Approved-By: Tom Tromey <tom@tromey.com>
Change-Id: Ice09a5d932c912210608d5af25e1898f823e3c99
commit-id:ca7e9182
2026-04-24 21:28:44 +01:00
Pedro Alves
7e1178a6e5 Windows gdbserver: Eliminate soft-interrupt mechanism
I noticed that faked_breakpoint is write only.  And then I hacked
win32_process_target::request_interrupt to force it to stop threads
using the soft_interrupt_requested mechanism (which suspends threads,
and then fakes a breakpoint event in the main thread), and saw that it
no longer works -- gdbserver crashes accessing a NULL current_thread,
because fake_breakpoint_event does not switch to a thread.

This code was originally added for Windows CE, as neither
GenerateConsoleCtrlEvent nor DebugBreakProcess worked there.  Windows
CE support has since been removed.

We nowadays require Windows XP or later, and XP has DebugBreakProcess.

The soft_interrupt_requested mechanism has other problems, like for
example faking the event in the main thread, even if that thread was
previously stopped, due to scheduler-locking.

A following patch will add a similar mechanism stopping all threads
with SuspendThread to native GDB, for non-stop mode, which doesn't
have these problems.  It's different enough from this old code that I
think we should just rip the old code out, and reimplement it from
scratch (based on gdb's version) when we need it.

Approved-By: Tom Tromey <tom@tromey.com>
Change-Id: I89e98233a9c40c6dcba7c8e1dacee08603843fb1
2026-04-24 21:28:44 +01:00
Pedro Alves
ec1aea5be3 Windows gdbserver: Fix scheduler-locking
This rewrites win32_process_target::resume such that scheduler-locking
is implemented properly.

It also uses the new get_last_debug_event_ptid function to avoid
considering passing a signal to the wrong thread, like done for the
native side in a previous patch.

Note this code/comment being removed:

 -    /* Yes, we're ignoring resume_info[0].thread.  It'd be tricky to make
 -       the Windows resume code do the right thing for thread switching.  */
 -    tid = windows_process.current_event.dwThreadId;

This meant that scheduler-locking currently is broken badly unless you
stay in the thread that last reported an event.  If you switch to a
different thread from the one that last reported an event and step,
you get a spurious SIGTRAP in the thread that last reported a stop,
not the one that you tried to step:

 (gdb) t 1
 [Switching to thread 1 (Thread 3908)]
 #0  0x00007fffc768d6e4 in ntdll!ZwDelayExecution () from target:C:/Windows/SYSTEM32/ntdll.dll
 (gdb) set scheduler-locking on
 (gdb) set disassemble-next-line on
 (gdb) frame
 #0  0x00007fffc768d6e4 in ntdll!ZwDelayExecution () from target:C:/Windows/SYSTEM32/ntdll.dll
 => 0x00007fffc768d6e4 <ntdll!ZwDelayExecution+20>:       c3                      ret
 (gdb) si

 Thread 3 received signal SIGTRAP, Trace/breakpoint trap.
 [Switching to Thread 2660]
 0x00007fffc4e4e92e in KERNELBASE!EncodeRemotePointer () from target:C:/Windows/System32/KernelBase.dll
 => 0x00007fffc4e4e92e <KERNELBASE!EncodeRemotePointer+8254>:    eb 78                   jmp    0x7fffc4e4e9a8 <KERNELBASE!EncodeRemotePointer+8376>
 (gdb)

Note how we switched to thread 1, stepped, and GDBserver still stepped
thread 3...  This is fixed by this patch.  We now get:

  (gdb) info threads
    Id   Target Id         Frame
    1    Thread 920        0x00007ffe0372d6e4 in ntdll!ZwDelayExecution () from target:C:/Windows/SYSTEM32/ntdll.dll
    2    Thread 8528       0x00007ffe03730ad4 in ntdll!ZwWaitForWorkViaWorkerFactory () from target:C:/Windows/SYSTEM32/ntdll.dll
    3    Thread 3128       0x00007ffe03730ad4 in ntdll!ZwWaitForWorkViaWorkerFactory () from target:C:/Windows/SYSTEM32/ntdll.dll
  * 4    Thread 7164       0x00007ffe0102e929 in KERNELBASE!EncodeRemotePointer () from target:C:/Windows/System32/KernelBase.dll
    5    Thread 8348       0x00007ffe0372d6e4 in ntdll!ZwDelayExecution () from target:C:/Windows/SYSTEM32/ntdll.dll
    6    Thread 2064       0x00007ffe0372d6e4 in ntdll!ZwDelayExecution () from target:C:/Windows/SYSTEM32/ntdll.dll
  (gdb) t 1
  [Switching to thread 1 (Thread 920)]
  #0  0x00007ffe0372d6e4 in ntdll!ZwDelayExecution () from target:C:/Windows/SYSTEM32/ntdll.dll
  (gdb) set scheduler-locking on
  (gdb) si
  0x00007ffe0372d6e4 in ntdll!ZwDelayExecution () from target:C:/Windows/SYSTEM32/ntdll.dll
  (gdb) si
  0x00007ffe00f9b44e in SleepEx () from target:C:/Windows/System32/KernelBase.dll
  (gdb) si
  0x00007ffe00f9b453 in SleepEx () from target:C:/Windows/System32/KernelBase.dll

I.e., we kept stepping the right thread, thread 1.

Note we stopped again at 0x00007ffe0372d6e4 the first time (same PC
the thread already was at before the first stepi) because the thread
had been stopped at a syscall, so that's normal:

 (gdb) disassemble
 Dump of assembler code for function ntdll!ZwDelayExecution:
    0x00007ffe0372d6d0 <+0>:     mov    %rcx,%r10
    0x00007ffe0372d6d3 <+3>:     mov    $0x34,%eax
    0x00007ffe0372d6d8 <+8>:     testb  $0x1,0x7ffe0308
    0x00007ffe0372d6e0 <+16>:    jne    0x7ffe0372d6e5 <ntdll!ZwDelayExecution+21>
    0x00007ffe0372d6e2 <+18>:    syscall
 => 0x00007ffe0372d6e4 <+20>:    ret

Approved-By: Tom Tromey <tom@tromey.com>
Change-Id: I44f4fe4cb98592517569c6716b9d189f42db25a0
commit-id:2a7b7d8e
2026-04-24 21:28:44 +01:00
Pedro Alves
e1c7509c93 Windows gdb+gdbserver: Elim desired_stop_thread_id / rework pending_stops
windows_process.desired_stop_thread_id doesn't work for non-stop, as
in that case every thread will have its own independent
WaitForDebugEvent event.

Instead, detect whether we have been reported a stop that was not
supposed to be reported by simply checking whether the thread that is
reporting the event is suspended.  This is now easilly possible since
each thread's suspend state is kept in sync with whether infrun wants
the thread executing or not.

windows_process.desired_stop_thread_id was also used as thread to pass
to windows_continue.  However, we don't really need that either.
windows_continue is used to update the thread's registers, unsuspend
them, and then finally call ContinueDebugEvent.  In most cases, we
only need the ContinueDebugEvent step, so we can convert the
windows_continue calls to continue_last_debug_event_main_thread calls.
The exception is when we see a thread creation event -- in that case,
we need to update the debug registers of the new thread.  We can use
continue_one_thread for that.

Since the pending stop is now stored in windows_thread_info,
get_windows_debug_event needs to avoid reaching the bottom code if
there's no thread associated with the event anymore (i.e.,
EXIT_THREAD_DEBUG_EVENT / EXIT_PROCESS_DEBUG_EVENT).

I considered whether it would be possible to keep the pending_stop
handling code shared in gdb/nat/windows-nat.c, in this patch and
throughout the series, but I conclused that it isn't worth it, until
gdbserver is taught about async and non-stop as well.

The pending_stop struct will eventually be eliminated later down the
series.

Approved-By: Tom Tromey <tom@tromey.com>
Change-Id: Ib7c8e8d16edc0900b7c411976c5d70cf93931c1c
commit-id:0b93b3f0
2026-04-24 21:28:44 +01:00
Pedro Alves
555cee0edf Windows gdb+gdbserver: Move suspending thread to when returning event
The current code suspends a thread just before calling
GetThreadContext.  You can only call GetThreadContext if the thread is
suspended.  But, after WaitForDebugEvent, all threads are implicitly
suspended.  So I don't think we even needed to call SuspendThread
explictly at all before our GetThreadContext calls.

However, suspending threads when we're about to present a stop to gdb
simplifies adding non-stop support later.  This way, the windows
SuspendThread state corresponds to whether a thread is suspended or
resumed from the core's perspective.  Curiously, I noticed that Wine's
winedbg does something similar:
234943344f/programs/winedbg/gdbproxy.c (L651)

This makes it much easier to reason about a thread's suspend state,
and simplifies adding non-stop mode later on.

Approved-By: Tom Tromey <tom@tromey.com>
Change-Id: Ifd6889a8afc041fad33cd1c4500e38941da6781b
commit-id:c4d2c92e
2026-04-24 21:28:44 +01:00
Pedro Alves
4768ec9b4f Windows gdb+gdbserver: Eliminate windows_process_info::thread_rec
After the previous patches, thread_rec is no longer called anywhere.
Delete it.

Approved-By: Tom Tromey <tom@tromey.com>
Change-Id: Ib14e5807fc427e1c3c4a393a9ea7b36b6047a2d7
2026-04-24 21:28:44 +01:00
Pedro Alves
0ab4174c4c Windows gdb+gdbserver: Eliminate thread_rec(INVALIDATE_CONTEXT) calls
Replace thread_rec(INVALIDATE_CONTEXT) calls with find_thread, and
invalidate_context / suspend calls in the spots that might need those.

I don't know why does the INVALIDATE_CONTEXT implementation in GDB
avoid suspending the event thread:

	case INVALIDATE_CONTEXT:
	  if (ptid.lwp () != current_event.dwThreadId)
	    th->suspend ();

Checks for a global "current_event" get in the way of non-stop support
later in the series, as each thread will have its own "last debug
event".  Regardless, it should be fine to suspend the event thread.
As a data point, the GDBserver implementation always suspends.  So
this patch does not try to avoid suspending the event thread on the
native side either.

Approved-By: Tom Tromey <tom@tromey.com>
Change-Id: I8d2f0a749d23329956e62362a7007189902dddb5
2026-04-24 21:28:44 +01:00
Pedro Alves
651baaff57 Windows gdb: handle_output_debug_string return type
handle_output_debug_string returns a Windows thread id, so it should
return a DWORD instead of an int.

Approved-By: Tom Tromey <tom@tromey.com>
Change-Id: Icbd071a1a37de8a0fc8918bd13254a8d40311e32
2026-04-24 21:28:44 +01:00
Pedro Alves
734a60d0a7 Windows gdb+gdbserver: New find_thread, replaces thread_rec(DONT_INVALIDATE_CONTEXT)
The goal of the next few patches is to eliminate thread_rec
completely.  This is the first patch in that effort.

thread_rec(DONT_INVALIDATE_CONTEXT) is really just a thread lookup
with no side effects, so this adds a find_thread function that lets
you do that.

Approved-By: Tom Tromey <tom@tromey.com>
Change-Id: Ie486badce00e234b10caa478b066c34537103e3f
2026-04-24 21:28:44 +01:00
Tom de Vries
eb221802ed [gdb] Remove unnecessary defs.h/common-defs.h includes
I asked an AI to review a patch that added a new file, and it mentioned I
should add an include of defs.h as first include.

That used to be true, but since commit 18d2988e5d ("gdb, gdbserver,
gdbsupport: remove includes of early headers") that's not the case anymore.

Error out when encountering a second include of defs.h, and remove a few of
those.

While we're at it, do the same for gdbsupport/common-defs.h and
gdbserver/server.h.

Tested by rebuilding gdb on x86_64-linux.

V1 submitted here [1].

Changes in v1:
- also handle gdbserver/server.h
- change error message to use "manually" instead of "twice"

Approved-By: Simon Marchi <simon.marchi@efficios.com>

[1] https://sourceware.org/pipermail/gdb-patches/2026-April/226694.html
2026-04-21 23:12:13 +02:00
Tankut Baris Aktemur
971b0152e9 gdb, testsuite: fix regression in gdb.multi/multi-{exit, kill}.exp
Commit d19862435d ("gdbserver:
require_running_or_break for the 'z' and 'vCont' packets") introduced
regressions in gdb.multi/multi-exit.exp and gdb.multi/multi-kill.exp.

If the remote target has multiple inferiors and is resumed with
schedule-multi on, all processes may terminate, making the target have
no threads left.  The target reports termination events to GDB.  GDB
processes the first event and attempts to stop all processes.  For
this, it sends 'vCont;t' packets to the target.  But the patch mentioned
above required the target to be in a running state, which is not true
anymore.  Therefore, target responds with an error.

Fix the regression by reverting the 'require_running_or_return'
enforcement for vCont.

Approved-By: Andrew Burgess <aburgess@redhat.com>
2026-04-20 09:26:15 +02:00
Simon Marchi
24bac805d7 gdb, gdbserver: split iterate_over_lwps into for_each_lwp and find_lwp
Even though it works, I have always been mildly annoyed by
iterate_over_lwps being used for both iterating over all lwps and
finding one lwp matching a criterion.  I think it would be clearer to
have two functions for the two use cases.  Then it would be 100% clear
at the call site what the intention is.  It would be clear that a
callback returning bool is meant to be a predicate for the find
function, while a callback returning void is meant to be a callback for
the "for each" function.

Therefore, split iterate_over_lwps in two:

 - find_lwp to find the first lwp matching a boolean predicate (and the
   given ptid filter)
 - for_each_lwp to apply a function on all lwps (optionally filtering by
   ptid or pid)

The callbacks given to for_each_lwp can now return void.

Introduce some overloads for for_each_lwp, for the various common use
cases:

 - filtering by ptid
 - filtering by pid
 - no ptid/pid filter

find_lwp and two overloads of for_each_lwp are actually only used in
gdb/linux-nat.c, so make them local to that file.  Only the pid variant
of for_each_lwp is used in shared code.

The pattern used in this patch serves as the basis for subsequent
patches that split other "iterate over" functions the same way.

Change-Id: I49d3af0916622300cc81e3c32d22e1aff13cf38f
Approved-By: Andrew Burgess <aburgess@redhat.com>
2026-04-17 15:30:30 -04:00