Skip to content

[mingw, x64] gdbstub seems to send a packet 24 bytes too long on connect #165

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
uglyoldbob opened this issue Mar 2, 2025 · 10 comments · Fixed by #171
Closed

[mingw, x64] gdbstub seems to send a packet 24 bytes too long on connect #165

uglyoldbob opened this issue Mar 2, 2025 · 10 comments · Fixed by #171

Comments

@uglyoldbob
Copy link

I am running on windows, with mingw gdb (GNU gdb (GDB) 14.2 according to gdb -v)

I have implemented the gdbstub blocking event loop in a dedicated thread in my kernel.
The target system is virtualbox, running a tcp server to a serial port on my kernel.

I setup gdb with this script.

add-symbol-file ./kernel/kernel64.debug
set architecture i386:x86-64
disp /i $pc
set debug remote 1
target remote :1234

Here is my gdb output when I try to connect to my system.

[remote] start_remote_1: enter
  [remote] Sending packet: $qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+;memory-tagging+;xmlRegisters=i386#77
  [remote] Received Ack
  [remote] Packet received: PacketSize=1000;vContSupported+;multiprocess+;QStartNoAckMode+;qXfer:features:read+
  [remote] packet_ok: Packet qSupported (supported-packets) is supported
  [remote] Sending packet: $vCont?#49
  [remote] Received Ack
  [remote] Packet received: vCont;c;C
  [remote] packet_ok: Packet vCont (verbose-resume) is supported
  [remote] Sending packet: $vMustReplyEmpty#3a
  [remote] Received Ack
  [remote] Packet received:
  [remote] Sending packet: $QStartNoAckMode#b0
  [remote] Received Ack
  [remote] Packet received: OK
  [remote] Sending packet: $Hgp0.0#ad
  [remote] Packet received: OK
  [remote] Sending packet: $qXfer:features:read:target.xml:0,ffb#79
  [remote] Packet received: m<target version="1.0"><architecture>i386:x86-64</architecture><feature name="org.gnu.gdb.i386.sse"></feature></target>
  [remote] Sending packet: $qXfer:features:read:target.xml:76,ffb#b6
  [remote] Packet received: l
  [remote] Sending packet: $qTStatus#49
  [remote] Packet received:
  [remote] packet_ok: Packet qTStatus (trace-status) is NOT supported
  [remote] Sending packet: $?#3f
  [remote] Packet received: T05thread:p01.01;
  [remote] Sending packet: $qfThreadInfo#bb
  [remote] Packet received: mp01.01,p01.09
  [remote] Sending packet: $qsThreadInfo#c8
  [remote] Packet received: l
  [remote] Sending packet: $qAttached:1#fa
  [remote] Packet received: 1
  [remote] packet_ok: Packet qAttached (query-attached) is supported
warning: No executable has been specified and target does not support
determining executable automatically.  Try using the "file" command.
  [remote] Sending packet: $Hc-1#09
  [remote] Packet received: OK
  [remote] wait: enter
  [remote] wait: exit
  [remote] Sending packet: $g#67
  [remote] Packet received: 640000000000000000fb000000000006650000000000000066000000000000006f0000000000000080ed1200000000006700000000000000680d430000000000680000000000000069000000000000006a00000000000000b00f43000000000090ed12000000000008000000000000000602010000000000b00f4300000000000000000000000000f00f43000800000010000000080000000800000008000000080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 [608 bytes omitted]
[remote] start_remote_1: exit
gdb.gdb:5: Error in sourced command file:
Remote 'g' packet reply is too long (expected 536 bytes, got 560 bytes): 640000000000000000fb000000000006650000000000000066000000000000006f0000000000000080ed1200000000006700000000000000680d430000000000680000000000000069000000000000006a00000000000000b00f43000000000090ed12000000000008000000000000000602010000000000b00f4300000000000000000000000000f00f4300080000001000000008000000080000000800000008000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
@daniel5151
Copy link
Owner

Thanks for sending in this bug report!
Lets dig in here and see what's going on...

Assuming I found the right repo - this is the gdbstub integration in your kernel, yes? https://github.com/uglyoldbob/doors-os/blob/master/kernel/src/gdbstub.rs

A few initial observations:

This is most perplexing indeed...

As a next step, could you confirm I'm understanding the situation right, and also, try this one thing for me?

Can you try removing the explicit set architecture directive from your GDB init script, and seeing what happens if you let GDB infer the target type based on the target.xml response?

@uglyoldbob
Copy link
Author

Yes that is the correct repo. I'm currently working out of the packetrx branch, which is slightly different on the gdbstub (but probably not enough to matter yet).

I tried removing the set architecture line from the script. It did not change the results.

(gdb) show arch
The target architecture is set to "auto" (currently "i386:x86-64").

I tried removing the extra 24 bytes in core64.rs in gdbstub_arch and it seems to fix the problem. Probably not the best solution. Maybe it is a deviation specific to the mingw version of gdb?

@daniel5151
Copy link
Owner

That's very interesting indeed...

While it would certainly be good to get to the bottom of why your particular GDB client version isn't playing nice with the existing arch implementation, I'm not particularly inclined to change the current implementation in gdbstub_arch just yet. After all, it appears to have been working fine for many years now, and I worry that fixing your issue might accidentally break other folks.

If you'd like to help me debug here, I would certainly appreciate it if you could try connecting to your kernel using an alternative GDB client. e.g: you could install gdb inside WSL2, and see if you're still seeing the same behavior. e.g: see what happens if you connect via lldb.

In the meantime though, my actionable advice for you would be to "fork" a copy of the gdbstub_arch X86_64 Arch implementation into your own project, and tweak it to omit those problematic padding bytes. While this is technically a workaround, it's important to note that simply having a project-local Arch shouldn't be considered to be a "bad thing". Many projects that use gdbstub opt to forgo using gdbstub_arch if they need something tailor-suited to their particular scenario.


If you don't mind - I'll just go ahead and keep this issue open, renaming it to something a bit more generic, in case other folks run into this same issue.

@uglyoldbob
Copy link
Author

I don't mind at all. I'll see about doing some of the debugging with other gdb.

@uglyoldbob
Copy link
Author

In wsl2, ubuntu gdb works both with and without the 24 bytes at the end.

@daniel5151
Copy link
Owner

Very interesting indeed.

What GDB version were you running inside WSL2?

@uglyoldbob
Copy link
Author

Gdb version in wsl2 is GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git

@daniel5151
Copy link
Owner

It would be good to narrow down if the issue is related to the GDB version, or the mingw version of GDB.

If you have a chance, it'd be great to smoke-test some other versions of GDB (both via mingw, and in wsl2), and see what the behavior matrix looks like.

@daniel5151 daniel5151 changed the title gdbstub seems to send a packet 24 bytes too long on connect [mingw, x64] gdbstub seems to send a packet 24 bytes too long on connect Mar 4, 2025
@cadmic
Copy link
Contributor

cadmic commented May 24, 2025

I'm facing a similar issue when trying to debug a 32-bit Windows executable, my GDB client doesn't like the 4 bytes of "padding" here:

// padding
(0..4).for_each(|_| write_byte(None))

I think I figured out where this "padding" comes from. For 32-bit x86, it's this Linux-only orig_eax register: https://github.com/bminor/binutils-gdb/blob/f92db640ca2ff6fd12997974b441b81894d9cfa4/gdb/features/i386/32bit-linux.c

And for x86-64, the 24 extra bytes are orig_eax, as well as fs_base and gs_base: https://github.com/bminor/binutils-gdb/blob/f92db640ca2ff6fd12997974b441b81894d9cfa4/gdb/features/i386/64bit-segments.c#L12 (Maybe relevant to #52, turns out these registers were here all along.)

So, the x86 implementation in gdbstub_arch is specifically for Linux targets instead of being a generic x86 architecture. But, GDB seems fine if the register packet is too short, it will just assume the missing registers aren't available (https://github.com/bminor/binutils-gdb/blob/f92db640ca2ff6fd12997974b441b81894d9cfa4/gdb/remote.c#L8999). So maybe we can just remove the padding and call it a day?

@daniel5151
Copy link
Owner

Excellent sleuthing!

Given that this extra padding data is not user-controllable, it seems reasonable to publish a new minor revision of gdbstub_arch that omits this extra padding, and see if that fixes the issue for folks.

@jamcleod, as the original implementer of i386 support (via #23), do you have any thoughts / concerns about that?

In the meantime though, @cadmic, feel free to send in a PR tweaking this behavior. I don't mind shipping a new gdbstub_arch revision with this "bug fix", and if it turns out that the bug fix itself causes a regression (e.g: it turns out some clients aren't able to gracefully handle the undersized packet), we can yank the new revision, and come back to the drawing board to think of a different strategy here.


Of course, the meta-issue here is that until we have a reasonable approach towards #12, gdbstub_arch will be forced to go along one of two routes: shipping Arch implementations that target the "base subset" of registers available across a particular architecture's "family", or, having a fractal number of different x86::{linux, windows, etc...} Arch impls to account for all the different variants. Of these two routes, the former seems easier... but having some plan for supporting the latter in a sustainable, long-term way would be great.

Repository owner deleted a comment from bbbbbq May 26, 2025
cadmic added a commit to cadmic/gdbstub that referenced this issue May 26, 2025
Turns out these were actually Linux-specific registers, namely
`orig_eax` for 32-bit and `orig_eax`/`fs_base`/`gs_base` for 64-bit.
GDB will gracefully handle a too-short packet but not a too-long one,
so removing this padding should make this work for all x86 targets
and not just Linux.

Fixes daniel5151#165
cadmic added a commit to cadmic/gdbstub that referenced this issue May 29, 2025
Turns out these were actually Linux-specific registers, namely
`orig_eax` for 32-bit and `orig_eax`/`fs_base`/`gs_base` for 64-bit.
GDB will gracefully handle a too-short packet but not a too-long one,
so removing this padding should make this work for all x86 targets
and not just Linux.

Fixes daniel5151#165
cadmic added a commit to cadmic/gdbstub that referenced this issue May 30, 2025
Turns out these were actually Linux-specific registers, namely
`orig_eax` for 32-bit and `orig_eax`/`fs_base`/`gs_base` for 64-bit.
GDB will gracefully handle a too-short packet but not a too-long one,
so removing this padding should make this work for all x86 targets
and not just Linux.

Fixes daniel5151#165
daniel5151 pushed a commit that referenced this issue May 30, 2025
Turns out these were actually Linux-specific registers, namely
`orig_eax` for 32-bit and `orig_eax`/`fs_base`/`gs_base` for 64-bit.
GDB will gracefully handle a too-short packet but not a too-long one,
so removing this padding should make this work for all x86 targets
and not just Linux.

Fixes #165
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants