Crate gdbstub[−][src]
Expand description
An ergonomic and easy-to-integrate implementation of the
GDB Remote Serial Protocol
in Rust, with full #![no_std]
support.
Getting Started
This section provides a brief overview of the key traits and types used in
gdbstub
, and walks though the basic steps required to integrate gdbstub
into a project.
At a high level, there are only two things that are required to get up and
running with gdbstub
: a Connection
, and a
Target
Note: I highly recommended referencing some of the examples listed in the project README when integrating
gdbstub
into a project for the first time.
In particular, the in-tree
armv4t
example contains basic implementations off almost all protocol extensions, making it an incredibly valuable reference when implementing protocol extensions.
The Connection
Trait
First things first: gdbstub
needs some way to communicate with a GDB
client. To facilitate this communication, gdbstub
uses a custom
Connection
trait.
Connection
is automatically implemented for common std
types such as
TcpStream
and
UnixStream
.
If you’re using gdbstub
in a #![no_std]
environment, Connection
will
most likely need to be manually implemented on top of whatever in-order,
serial, byte-wise I/O your particular platform has available (e.g:
putchar/getchar over UART, using an embedded TCP stack, etc.).
One common way to start a remote debugging session is to simply wait for a GDB client to connect via TCP:
use std::io; use std::net::{TcpListener, TcpStream}; fn wait_for_gdb_connection(port: u16) -> io::Result<TcpStream> { let sockaddr = format!("localhost:{}", port); eprintln!("Waiting for a GDB connection on {:?}...", sockaddr); let sock = TcpListener::bind(sockaddr)?; let (stream, addr) = sock.accept()?; // Blocks until a GDB client connects via TCP. // i.e: Running `target remote localhost:<port>` from the GDB prompt. eprintln!("Debugger connected from {}", addr); Ok(stream) // `TcpStream` implements `gdbstub::Connection` }
The Target
Trait
The Target
trait describes how to control and modify
a system’s execution state during a GDB debugging session, and serves as the
primary bridge between gdbstub
’s generic GDB protocol implementation and a
specific target’s project/platform-specific code.
At a high level, the Target
trait is a collection of user-defined handler
methods that the GDB client can invoke via the GDB remote serial protocol.
For example, the Target
trait includes methods to read/write
registers/memory, start/stop execution, etc…
Target
is the most important trait in gdbstub
, and must be implemented
by anyone integrating gdbstub
into their project!
Please refer to the target
module documentation for in-depth
instructions on how to implement Target
for a particular
platform.
Starting the debugging session using GdbStub
Once a Connection
has been established and
Target
has been all wired up, all that’s left is to
hand things off to gdbstub::GdbStub
and let it do the rest!
// Set-up a valid `Target` let mut target = MyTarget::new()?; // implements `Target` // Establish a `Connection` let connection: TcpStream = wait_for_gdb_connection(9001); // Create a new `gdbstub::GdbStub` using the established `Connection`. let mut debugger = gdbstub::GdbStub::new(connection); // Instead of taking ownership of the system, `GdbStub` takes a &mut, yielding // ownership back to the caller once the debugging session is closed. match debugger.run(&mut target) { Ok(disconnect_reason) => match disconnect_reason { DisconnectReason::Disconnect => println!("GDB client disconnected."), DisconnectReason::TargetHalted => println!("Target halted!"), DisconnectReason::Kill => println!("GDB client sent a kill command!"), } // Handle any target-specific errors Err(GdbStubError::TargetError(e)) => { println!("Target raised a fatal error: {:?}", e); // `gdbstub` will not immediate close the debugging session if a // fatal error occurs, enabling "post mortem" debugging if required. debugger.run(&mut target)?; } Err(e) => return Err(e.into()) }
Feature flags
By default, both the std
and alloc
features are enabled.
When using gdbstub
in #![no_std]
contexts, make sure to set
default-features = false
.
alloc
- Implement
Connection
forBox<dyn Connection>
. - Log outgoing packets via
log::trace!
(uses a heap-allocated output buffer). - Provide built-in implementations for certain protocol features:
- Use a heap-allocated packet buffer in
GdbStub
(if none is provided viaGdbStubBuilder::with_packet_buffer
). - (Monitor Command) Use a heap-allocated output buffer in
ConsoleOutput
.
- Use a heap-allocated packet buffer in
- Implement
std
(impliesalloc
)- Implement
Connection
forTcpStream
andUnixStream
. - Implement
std::error::Error
forgdbstub::Error
. - Add a
TargetError::Io
error variant to simplify I/O Error handling fromTarget
methods.
- Implement
Modules
arch | Traits to encode architecture-specific target information. |
common | Common types and definitions. |
target | The core |
Macros
output | Send formatted data to the GDB client console. |
outputln | Send formatted data to the GDB client console, with a newline appended. |
Structs
GdbStub | Debug a |
GdbStubBuilder | Helper to construct and customize |
Enums
DisconnectReason | Describes why the GDB session ended. |
GdbStubBuilderError | An error which may occur when building a |
GdbStubError | An error which may occur during a GDB debugging session. |
Traits
Connection | A trait to perform in-order, serial, byte-wise I/O. |