https://github.com/daniel5151/gdb-optional-step-bug
GDB client doesn't respect optional single-step support on certain target architectures
https://github.com/daniel5151/gdb-optional-step-bug
Last synced: over 1 year ago
JSON representation
GDB client doesn't respect optional single-step support on certain target architectures
- Host: GitHub
- URL: https://github.com/daniel5151/gdb-optional-step-bug
- Owner: daniel5151
- Created: 2021-10-10T21:18:36.000Z (almost 5 years ago)
- Default Branch: main
- Last Pushed: 2025-02-23T23:46:23.000Z (over 1 year ago)
- Last Synced: 2025-03-24T08:54:41.010Z (over 1 year ago)
- Language: Rust
- Size: 23.4 KB
- Stars: 3
- Watchers: 3
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# GDB optional single-step bug repro
This repo exhibits the behavior reported at https://sourceware.org/bugzilla/show_bug.cgi?id=28440
## The Bug
On certain architectures, the GDB client doesn't respect `vCont?` responses that don't report support for single-stepping (i.e: via `;s;S`), and will _unconditionally_ send single-step resume packets. This can lead to very Bad Things happening when targets encounter unexpected single-step packets, ranging from silently ignoring the request, to failing to parse the `vCont` packet the request is encapsulated in.
## This Repo
This repo includes a few basic GDB remote targets, implemented using [`gdbstub`](https://github.com/daniel5151/gdbstub), a Rust library that implements the server-side of the GDB Remote Serial Protocol.
These are incredibly barebones "dummy" remote targets, whereby they present a memory space entirely filled with `NOP` instructions, and use dummy values when reporting register values.
## Running
Use the provided `check_vcont.sh` script to verify how `vCont?` is handled by
your version of GDB (use `$GDB` to configure the path):
```
$ GDB=gdb-multiarch ./check_vcont.sh armv4t mips i386:x86-64 aarch64
GNU gdb (GDB) 15.2 for x86_64-pc-linux-gnu
===================== [armv4t] =====================
TRACE gdbstub::protocol::recv_packet > <-- $vCont?#49
TRACE gdbstub::protocol::response_writer > --> $vCont;c;C#26
TRACE gdbstub::protocol::recv_packet > <-- $vCont;c:p1.-1#0f
=================== [armv4t (SS)] ===================
TRACE gdbstub::protocol::recv_packet > <-- $vCont?#49
TRACE gdbstub::protocol::response_writer > --> $vCont;c;C;s;S#62
TRACE gdbstub::protocol::recv_packet > <-- $vCont;s:p1.1;c:p1.-1#f7
===================== [mips] =====================
TRACE gdbstub::protocol::recv_packet > <-- $vCont?#49
TRACE gdbstub::protocol::response_writer > --> $vCont;c;C#26
TRACE gdbstub::protocol::recv_packet > <-- $vCont;c:p1.-1#0f
=================== [mips (SS)] ===================
TRACE gdbstub::protocol::recv_packet > <-- $vCont?#49
TRACE gdbstub::protocol::response_writer > --> $vCont;c;C;s;S#62
TRACE gdbstub::protocol::recv_packet > <-- $vCont;c:p1.-1#0f
===================== [i386:x86-64] =====================
TRACE gdbstub::protocol::recv_packet > <-- $vCont?#49
TRACE gdbstub::protocol::response_writer > --> $vCont;c;C#26
TRACE gdbstub::protocol::recv_packet > <-- $vCont;s:p1.1;c:p1.-1#f7
ERROR gdbstub::stub::core_impl::resume > GDB client sent resume action not reported by `vCont?`
=================== [i386:x86-64 (SS)] ===================
TRACE gdbstub::protocol::recv_packet > <-- $vCont?#49
TRACE gdbstub::protocol::response_writer > --> $vCont;c;C;s;S#62
TRACE gdbstub::protocol::recv_packet > <-- $vCont;s:p1.1;c:p1.-1#f7
===================== [aarch64] =====================
TRACE gdbstub::protocol::recv_packet > <-- $vCont?#49
TRACE gdbstub::protocol::response_writer > --> $vCont;c;C#26
TRACE gdbstub::protocol::recv_packet > <-- $vCont;s:p1.1;c:p1.-1#f7
ERROR gdbstub::stub::core_impl::resume > GDB client sent resume action not reported by `vCont?`
=================== [aarch64 (SS)] ===================
TRACE gdbstub::protocol::recv_packet > <-- $vCont?#49
TRACE gdbstub::protocol::response_writer > --> $vCont;c;C;s;S#62
TRACE gdbstub::protocol::recv_packet > <-- $vCont;s:p1.1;c:p1.-1#f7
```
However, when using a GDB version compiled for bare-metal targets:
```
$ GDB=arm-none-eabi-gdb ./check_vcont.sh armv4t mips
GNU gdb (GDB) 15.2 for arm-none-eabi
===================== [armv4t] =====================
TRACE gdbstub::protocol::recv_packet > <-- $vCont?#49
TRACE gdbstub::protocol::response_writer > --> $vCont;c;C#26
TRACE gdbstub::protocol::recv_packet > <-- $vCont;s:p1.1;c:p1.-1#f7
ERROR gdbstub::stub::core_impl::resume > GDB client sent resume action not reported by `vCont?`
=================== [armv4t (SS)] ===================
TRACE gdbstub::protocol::recv_packet > <-- $vCont?#49
TRACE gdbstub::protocol::response_writer > --> $vCont;c;C;s;S#62
TRACE gdbstub::protocol::recv_packet > <-- $vCont;s:p1.1;c:p1.-1#f7
===================== [mips] =====================
TRACE gdbstub::protocol::recv_packet > <-- $vCont?#49
TRACE gdbstub::protocol::response_writer > --> $vCont;c;C#26
TRACE gdbstub::protocol::recv_packet > <-- $vCont;s:p1.1;c:p1.-1#f7
ERROR gdbstub::stub::core_impl::resume > GDB client sent resume action not reported by `vCont?`
=================== [mips (SS)] ===================
TRACE gdbstub::protocol::recv_packet > <-- $vCont?#49
TRACE gdbstub::protocol::response_writer > --> $vCont;c;C;s;S#62
TRACE gdbstub::protocol::recv_packet > <-- $vCont;s:p1.1;c:p1.-1#f7
```
### Running Manually
You can test any architecture supported by GDB's `set architecture` command when connecting to the stub, such as:
- `armv4t`: ARMv4T
- `mips`: MIPS
- `i386:x86-64`: X86_64
- `aarch64`: AArch64
By passing the `--single-step` flag, support can be added to the target. For
example:
```bash
# enable trace logs for the `gdbstub` library, dumping send/recv'd packets to stderr
export RUST_LOG=trace
# run the stub with trace logging enabled + single-step support
cargo run -- --single-step
# run the stub with trace logging enabled, *without* single-step support
cargo run --
```
The GDB client can connect to these targets over TCP loopback. i.e:
```
(gdb) set architecture armv4t
(gdb) target remote :9001
```
See the `try_stepi.gdb` script for more commands.
## Observations
When using GDB for x86_64-pc-linux-gnu:
| | `--single-step` (`vCont;c;C;s;S`) | (no support) (`vCont;c;C`) |
|:------:|:---------------------------------:|:--------------------------:|
| `armv4t` | `vCont;c:p1.-1` | `vCont;s:p1.1;c:p1.-1` |
| `mips` | `vCont;c:p1.-1` | `vCont;c:p1.-1` |
| `i386:x86-64` | `vCont;s:p1.1;c:p1.-1` | `vCont;s:p1.1;c:p1.-1` |
| `aarch64` | `vCont;s:p1.1;c:p1.-1` | `vCont;s:p1.1;c:p1.-1` |
When using GDB for bare-metal targets (e.g. arm-none-eabi-gdb):
| | `--single-step` (`vCont;c;C;s;S`) | (no support) (`vCont;c;C`) |
|:------:|:---------------------------------:|:--------------------------:|
| `armv4t` | `vCont;s:p1.1;c:p1.-1` | `vCont;s:p1.1;c:p1.-1` |
| `mips` | `vCont;s:p1.1;c:p1.-1` | `vCont;s:p1.1;c:p1.-1` |
- The armv4t example works as expected.
- If `--single-step` is not provided, the GDB stub reports `vCont;c;C`, and the GDB client responds with `vCont;c:p1.-1`. If `--single-step` is provided, the GDB stub reports `vCont;c;C;s;S`, and the GDB client responds with with `vCont;s:p1.1;c:p1.-1`.
- This matches the spec.
- Both x86_64 and aarch64 examples do _not_ work as expected.
- If `--single-step` is not provided, the GDB stub reports `vCont;c;C`, and the GDB client nonetheless responds with `vCont;s:p1.1;c:p1.-1`! This results in an internal `gdbstub` error, and the example terminates.
- If `--single-step` is provided, both work correctly by sending `vCont;s:p1.1;c:p1.-1`.
- The MIPS example is interesting.
- Regardless if `--single-step` was provided, the GDB client will _never_ send a `vCont;s:pX.X` packet!
- While this isn't strictly an "error", it isn't nonetheless weird that the GDB client doesn't attempt to use the target's "native" single step feature.
- However, when using bare-metal GDB versions (e.g. arm-none-eabi-gdb):
- Both armv4t and MIPS targets unconditionally receive single-step packets (`vCont;s:p1.1;c:p1.-1`), regardless of their reported capabilities.
- This suggests the issue may be more prevalent in bare-metal GDB variants.
## Expected behaviors
- The GDB client should not send `s` resumption packets when the `vCont?` response doesn't include support for `s`, regardless of architecture or GDB variant
- The GDB client should use the `s` resumption packet when `vCont?` includes support for `s`