daniel5151 / gdbstub

An ergonomic, featureful, and easy-to-integrate implementation of the GDB Remote Serial Protocol in Rust (with no-compromises #![no_std] support)
Other
291 stars 45 forks source link

[riscv32] `PacketUnexpected` when issuing `stepi` #125

Closed xobs closed 1 year ago

xobs commented 1 year ago

When issuing a stepi command, gdbstub reports PacketUnexpcted:

(gdb) set debug remote 1
(gdb) tar ext :3456
Remote debugging using :3456
Sending packet: $qSupported:multiprocess+;swbreak+;hwbreak+;qRelocInsn+;fork-events+;vfork-events+;exec-events+;vContSupported+;QThreadEvents+;no-resumed+#df...Ack
Packet received: PacketSize=1000;vContSupported+;multiprocess+;QStartNoAckMode+;swbreak+;qXfer:features:read+
Packet qSupported (supported-packets) is supported
Sending packet: $vMustReplyEmpty#3a...Ack
Packet received:
Sending packet: $QStartNoAckMode#b0...Ack
Packet received: OK
Sending packet: $!#21...Packet received:
Sending packet: $Hgp0.0#ad...Packet received: OK
Sending packet: $qXfer:features:read:target.xml:0,ffb#79...Packet received: m<target version="1.0"><architecture>riscv:rv32</architecture></target>
Sending packet: $qXfer:features:read:target.xml:46,ffb#b3...Packet received: l
Sending packet: $qTStatus#49...Packet received:
Packet qTStatus (trace-status) is NOT supported
Sending packet: $?#3f...Packet received: T05thread:p01.01;
Sending packet: $qfThreadInfo#bb...Packet received: mp01.01
Sending packet: $qsThreadInfo#c8...Packet received: l
Sending packet: $qAttached:1#fa...Packet received: 1
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.
Sending packet: $Hc-1#09...Packet received: OK
Sending packet: $g#67...Packet received: 000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
Sending packet: $qfThreadInfo#bb...Packet received: mp01.01
Sending packet: $qsThreadInfo#c8...Packet received: l

Program received signal SIGTRAP, Trace/breakpoint trap.
0x00000000 in ?? ()
(gdb) mon pr 2
Sending packet: $qRcmd,70722032#ba...Packet received: O4e6f7720646562756767696e672050494420
Now debugging PID Packet received: O32
2Packet received: O0a

Packet received: OK
(gdb) info thr
Sending packet: $qfThreadInfo#bb...Packet received: mp01.02,p01.03
Sending packet: $qsThreadInfo#c8...Packet received: l
[New Thread 1.2]
[New Thread 1.3]
Sending packet: $qThreadExtraInfo,p1.2#86...Packet received:
Sending packet: $qP0000001f0000000000000002#7a...Packet received:
Sending packet: $qP0000001f0000000000000003#7b...Packet received:
  Id   Target Id         Frame
Sending packet: $qP0000001f0000000000000002#7a...Packet received:
Sending packet: $Hgp1.2#b0...Packet received: OK
Sending packet: $g#67...Packet received: 00000000c002030070f5ff7f000000000000006010000000724503009cf5ff7f98f6ff7f050000000f0000007469636b74696d65722d736572766572000000000000000000000000f0faff7f333333330400000088040020d805002001000000feffffff040000000f0f0f0f01010101010000000300000000000000b0000020d4020300
  2    Thread 1.2        0x000302d4 in ?? ()
Sending packet: $qP0000001f0000000000000003#7b...Packet received:
Sending packet: $Hgp1.3#b1...Packet received: OK
Sending packet: $g#67...Packet received: 00000000003080ffd04e02600000000000000000000000000000000000000000404f0260000000000f000000a24ede61f70001296ff6d10e4d30f8740000000000000000000000004d30f8746ff6d10e05000000f7000129a24ede610000000000000000644f0260010000000900000000000000000000000000000000000000b8340300
  3    Thread 1.3        0x000334b8 in ?? ()

The current thread <Thread ID 1> has terminated.  See `help thread'.
(gdb) thr 2
Sending packet: $Tp1.2#55...Packet received: OK
Sending packet: $Tp1.2#55...Packet received: OK
Sending packet: $Tp1.3#56...Packet received: OK
[Switching to thread 2 (Thread 1.2)]
#0  0x000302d4 in ?? ()
(gdb) stepi
Sending packet: $Hgp1.2#b0...Packet received: OK
Sending packet: $m0,2#fb...Packet received: ffff
Sending packet: $vCont?#49...Packet received: vCont;c;C
Packet vCont (verbose-resume) is supported
Sending packet: $vCont;s:p1.2;c:p1.-1#f8...

Note that this uses the mon pr 2 command to set Process #2, which simply sets which process is currently being debugged.

This occurs even if I have GDB use implicit breakpoints by using guard_rail_implicit_sw_breakpoints and not implementing breakpoints myself.

daniel5151 commented 1 year ago

This is a manifestation of an upstream GDB client bug, where on some targets, it doesn't respect the fact that vCont? only returns support for continue (via the vCont;c;C response), and opts to send a s command as part of its vCont packet regardless.

This is def not OK from the spec's perspective, but since upstream gdbserver (and likely most third-party project-specific gdbstubs) support both continue and single-step, no-one ever noticed this issue.

There is a different guard-rail (guard_rail_single_step_gdb_behavior) that attempts to work-around this upstream bug, by having Arch implementations declare how upstream GDB decides to send/not-send single-step commands to those targets.

...but it seems to be the case that this guard rail isn't working too well, and might not be tenable to maintain in the long-term. See https://github.com/daniel5151/gdbstub/issues/117#issuecomment-1464130901

All that is to say: it seems that for rv32, you're going to have to implement explicit support for single-stepping, as GDB will try and single-step your target regardless if it's declared support for single stepping. A bit of a bummer... but that's GDB for ya ¯\_(ツ)_/¯


P.S: this doesn't have anything to do with guard_rail_implicit_sw_breakpoints. That's an orthogonal guard-rail, which is there to prevent GDB from implicitly overwriting a guest's instruction stream in emulator-level gdbstub implementations.

And indeed, for your kernel implementation, it might even be beneficial to leave the nitty-gritty details of inserting software breakpoints to the GDB client itself (tho ofc, this is something for you to decide)

xobs commented 1 year ago

It looks like the risc-v target is set to SingleStepGdbBehavior::Ignored when it should be SingleStepGdbBehavior::Required, which is why the guard rail didn't activate on my target.

That's a bummer about having to manually single-step. I was hoping to avoid having to inspect opcodes in the kernel, but what can you do?

daniel5151 commented 1 year ago

Closed via #128