gdbstub

A no_std-first Rust implementation of the GDB Remote Serial Protocol for debugging emulators and embedded targets.

Library
Cargo
v0.7.10
412stars
MIT OR Apache-2.0

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
51/100Fair
Development Activity16
Maintenance32
Community68
Maturity60
Momentum28

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
85/100Excellent
Architecture85
Code Quality80
Innovation90
Learning Curve85

gdbstub is a Rust crate that implements the GDB Remote Serial Protocol (RSP), letting you plug real GDB (or LLDB) debugging support into an emulator, hypervisor, or embedded firmware project without writing any protocol-handling code by hand. Instead of exposing the raw wire protocol, it organizes the dozens of optional GDB extensions — breakpoints, watchpoints, reverse execution, host I/O, tracepoints, and more — into a type-safe hierarchy of traits, so a target only pays for (and implements) the features it actually needs.

Because it is a no_std-first library with optional alloc/std features, gdbstub runs on everything from full desktop hypervisors to bare-metal microcontrollers, using a technique the maintainers call Inlineable Dyn Extension Traits (IDETs) to keep unused protocol extensions completely dead-code-eliminated in release builds. The companion gdbstub_arch crate ships ready-made register and target-description definitions for popular architectures (ARM, x86, RISC-V, MIPS, and more), so most integrations only need to implement a handful of memory/register access methods to get a working debug session.

What You Get

  • A Target trait hierarchy that maps directly onto the GDB protocol’s optional extensions (breakpoints, watchpoints, extended mode, host I/O, tracepoints) so you only implement what you use
  • The gdbstub_arch companion crate with pre-built architecture definitions (ARM, x86, x86_64, RISC-V, MIPS, and more) covering register layouts and target XML
  • A transport-agnostic Connection trait with built-in implementations for TcpStream and UnixStream, plus a clear path to implement it over raw UART/serial for bare-metal targets
  • #![no_std] support with zero required heap allocation, letting gdbstub run on resource-constrained microcontrollers with a sub-10kb .text+.rodata footprint
  • Compile-time dead-code elimination of any GDB protocol extension you don’t implement, via the crate’s Inlineable Dyn Extension Traits (IDET) pattern

Common Use Cases

  • Adding gdb/lldb remote debugging to a CPU or system emulator (e.g. debugging guest code running inside an ARMv4T, RISC-V, or x86 emulator)
  • Building guest-debugging support into a hypervisor or VMM, as used in production by projects like Firecracker and crosvm
  • Exposing a debug interface for embedded/no_std firmware over UART or another serial transport, without pulling in a heap allocator
  • Prototyping custom monitor commands to extend gdb with project-specific debug/inspection commands

Under The Hood

Architecture - gdbstub centers on two traits that meet in the middle of the GDB Remote Serial Protocol: Target (src/target/mod.rs), which a host project implements against its own CPU/memory model, and Connection (src/conn/mod.rs), which abstracts the byte-wise transport GDB talks over. The GdbStub type (src/stub/mod.rs, built via GdbStubBuilder in src/stub/builder.rs) drives the session: it parses incoming RSP packets (src/protocol/packet.rs, commands.rs), dispatches them against whatever optional Target extensions are implemented, and writes protocol-conformant responses back through Connection. Optional protocol features (breakpoints, tracepoints, extended mode, host I/O, and more, under src/target/ext/) are each modeled as their own extension trait returned via Option<ProtocolExtOps> methods on Target — the “Inlineable Dyn Extension Trait” (IDET) pattern — so the compiler can prove which extensions are active and dead-code-eliminate the rest, giving fine-grained protocol control without Cargo feature flags. A state_machine module (src/stub/state_machine.rs) additionally exposes the stub as an explicit state machine for integrations that can’t block on I/O (e.g. async or single-threaded emulator loops).

Tech Stack - gdbstub 0.7.10 targets 2018-edition Rust and is a no_std-first crate: its only unconditional dependencies are bitflags, cfg-if, log, managed (for pre-allocated buffer management), num-traits, and pastey (a proc-macro helper), all usable without std. The alloc and std Cargo features are additive layers that unlock heap-backed buffers and TcpStream/UnixStream Connection impls respectively; default-features = false drops both for bare-metal targets. The workspace’s gdbstub_arch member crate depends on gdbstub itself plus num-traits, keeping architecture definitions decoupled from the core protocol engine. Dev-dependencies (armv4t_emu, goblin, pretty_env_logger) back the in-tree examples/armv4t and examples/armv4t_multicore emulator examples used both as documentation and as an integration-test harness.

Code Quality - The crate carries around 29 in-tree #[test] functions covering protocol parsing, response writing, and internal buffer/byte-order helpers, plus dedicated scripts (scripts/test_dead_code_elim.sh) that verify the IDET dead-code-elimination claim actually holds under real release builds — a level of build-output verification uncommon even in well-tested crates. Error handling is deliberately layered: a pub(crate) InternalError<T, C> enum (src/stub/error.rs) captures protocol-level failure modes distinctly from the user-facing Target::Error associated type, so a target’s own error type is threaded through without being conflated with gdbstub’s internal state. Naming is consistent and protocol-literal (packet/command/response terminology mirrors the GDB RSP spec directly), and extensive /// doc comments annotate nearly every public trait and method, including cross-references back to the relevant GDB documentation.

API Design - The Target trait is the sole integration point, and the IDET pattern keeps its surface area proportional to what a given integration actually needs — a minimal target implements only memory/register access and thread enumeration, while advanced features (reverse execution, tracepoints, host I/O) are opt-in via additional trait implementations rather than large default method lists. GdbStubBuilder provides a fluent, no_std-safe construction path with explicit, typed error variants (GdbStubBuilderError) for misconfiguration like a missing packet buffer. Getting-started friction is low for a protocol-implementation crate: the crate-level docs walk through Connection, Target, and the event loop end-to-end, and the in-tree examples/armv4t reference implementation is explicitly pointed to from the docs as the canonical integration example.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search