An ergonomic and easy-to-integrate implementation of the GDB Remote Serial Protocol in Rust.
gdbstub
is entirely #![no_std]
compatible, and can be used on platforms without a global allocator. In embedded contexts, gdbstub
can be configured to use pre-allocated buffers and communicate over any available serial I/O connection (e.g: UART).
gdbstub
is particularly well suited for emulation, making it easy to add powerful, non-intrusive debugging support to an emulated system. Just provide an implementation of gdbstub::Target
for your target platform, and you're ready to start debugging!
Features marked as (optional) aren't required to be implemented, but can be implemented to enhance the debugging experience.
- Core GDB Protocol
- Step + Continue
- Add + Remove Software Breakpoints
- Read/Write memory
- Read/Write registers
- (optional) Add + Remove Hardware Breakpoints
- (optional) Read/Write/Access Watchpoints (i.e: value breakpoints)
- (optional) Multithreading support
- Extended GDB Protocol
- (optional) Handle custom debug commands (sent via GDB's
monitor
command) - (optional) Automatic architecture detection
- (optional) Handle custom debug commands (sent via GDB's
The GDB Remote Serial Protocol is surprisingly complex, supporting advanced features such as remote file I/O, spawning new processes, "rewinding" program execution, and much, much more. Thankfully, most of these features are completely optional, and getting a basic debugging session up-and-running only requires a small subset of commands to be implemented.
If gdbstub
is missing a feature you'd like to use, please file an issue / open a PR!
The std
feature is enabled by default. In #![no_std]
contexts, use default-features = false
.
alloc
- Implements
Connection
forBox<dyn Connection>
. - Adds output buffering to
ConsoleOutput
.
- Implements
std
(impliesalloc
)- Implements
Connection
forTcpStream
andUnixStream
. - Implements
std::error::Error
forgdbstub::Error
- Log outgoing packets via
log::trace!
(uses a heap-allocated output buffer)
- Implements
The armv4t
example shows how gdbstub
can be used to add gdb
debugging support to an (incredibly simple) ARMv4T-based emulator. See examples/armv4t/README.md
for details.
A dual-core variation of the armv4t
example. Implements gdbstub
's multithread extensions to enable per-core debugging. See examples/armv4t_multicore/README.md
for details.
Several projects are already using gdbstub
.
- clicky - An emulator for classic clickwheel iPods (dual-core ARMv4T SoC)
- rustyboyadvance-ng - Nintendo GameBoy Advance emulator and debugger
- microcorruption-emu - msp430 emulator for the microcorruption.com ctf
- ts7200 - An emulator for the TS-7200, a somewhat bespoke embedded ARMv4t platform
If you end up using gdbstub
in your project, feel free to open a PR and add it to this list!
Since gdbstub
is #![no_std]
compatible, it should be possible to implement a gdbstub::Target
which uses low-level trap instructions + context switching to debug bare-metal code.
If you happen to stumble across this crate and end up using it to debug some bare-metal code, please let me know! I'd love to link to your project!
gdbstub
"core" only has 2 lines of unsafe code:
- A call to
NonZeroUsize::new_unchecked(1)
when defining theSINGLE_THREAD_TID
constant. - A call to
str::from_utf8_unchecked()
when working with incoming GDB packets (the underlying&[u8]
buffer is checked withis_ascii()
prior to the call).
With the std
feature enabled, there is one additional line of unsafe
code:
gdbstub
includes an implementation ofUnixStream::peek
which useslibc::recv
. This will be removed once rust-lang/rust#73761 is merged.
- Improve multiprocess / multi-thread / multi-core support
- Support thread-specific breakpoints
- Support non-stop mode?
- Support disabling multiprocess extensions on older GDB clients
- Support addresses larger than 64-bits?
- This would require plumbing-through the architecture's pointer size as a generic parameter into all the packet parsing code, which probably isn't too difficult, just time consuming.