//! An ergonomic and easy-to-integrate implementation of the //! [GDB Remote Serial Protocol](https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html#Remote-Protocol) //! in Rust, with full `#![no_std]` support. //! //! ## Feature flags //! //! By default, the `std` and `alloc` features are enabled. //! //! When using `gdbstub` in `#![no_std]` contexts, make sure to set //! `default-features = false`. //! //! - `alloc` //! - Implement `Connection` for `Box`. //! - 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 via `GdbStubBuilder::with_packet_buffer`). //! - (Monitor Command) Use a heap-allocated output buffer in //! `ConsoleOutput`. //! - (Extended Mode) Automatically track Attached/Spawned PIDs without //! implementing `ExtendedMode::query_if_attached`. //! - `std` (implies `alloc`) //! - Implement `Connection` for [`TcpStream`](std::net::TcpStream) and //! [`UnixStream`](std::os::unix::net::UnixStream). //! - Implement [`std::error::Error`] for `gdbstub::Error`. //! - Add a `TargetError::Io` error variant to simplify I/O Error handling //! from `Target` methods. //! //! ## 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. //! //! It is **highly recommended** to take a look at some of the //! [**examples**](https://github.com/daniel5151/gdbstub/blob/master/README.md#examples) //! listed in the project README. In particular, the included //! [**`armv4t`**](https://github.com/daniel5151/gdbstub/tree/master/examples/armv4t) //! example implements most of `gdbstub`'s protocol extensions, and can be a //! valuable resource when getting up-and-running with `gdbstub`. //! //! ### The `Connection` Trait //! //! The [`Connection`] trait describes how `gdbstub` should communicate with the //! main GDB process. //! //! `Connection` is automatically implemented for common `std` types such as //! [`TcpStream`](std::net::TcpStream) and //! [`UnixStream`](std::os::unix::net::UnixStream). In `#![no_std]` //! environments, `Connection` must be manually implemented using whatever //! in-order, serial, byte-wise I/O the hardware has available (e.g: //! putchar/getchar over UART, an embedded TCP stack, etc.). //! //! A common way to start a remote debugging session is to wait for a GDB client //! to connect via TCP: //! //! ```rust //! use std::net::{TcpListener, TcpStream}; //! //! fn wait_for_gdb_connection(port: u16) -> std::io::Result { //! 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:` from the GDB prompt. //! //! eprintln!("Debugger connected from {}", addr); //! Ok(stream) //! } //! ``` //! //! ### The `Target` Trait //! //! The [`Target`](target::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 protocol implementation and a //! target's project/platform-specific code. //! //! For example: the `Target` trait includes a method called `read_registers()`, //! which the `GdbStub` calls whenever the GDB client queries the state of the //! target's registers. //! //! **`Target` is the most important trait in `gdbstub`, and must be implemented //! by anyone who uses the library!** //! //! Please refer to the [`target` module documentation](target) for in-depth //! instructions on implementing `Target`. //! //! ### 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`] and let it do the rest! //! //! ```rust,ignore //! // 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` using the established `Connection`. //! let mut debugger = 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); //! // e.g: re-enter the debugging session after "freezing" a system to //! // conduct some post-mortem debugging //! debugger.run(&mut target)?; //! } //! Err(e) => return Err(e.into()) //! } //! ``` #![cfg_attr(not(feature = "std"), no_std)] #![deny(missing_docs)] #[cfg(feature = "alloc")] extern crate alloc; #[macro_use] extern crate log; mod connection; mod gdbstub_impl; mod protocol; mod util; #[doc(hidden)] pub mod internal; pub mod arch; pub mod common; pub mod target; pub use connection::Connection; pub use gdbstub_impl::*; /// (Internal) The fake Tid that's used when running in single-threaded mode. // SAFETY: 1 is clearly non-zero. const SINGLE_THREAD_TID: common::Tid = unsafe { common::Tid::new_unchecked(1) }; /// (Internal) The fake Pid reported to GDB (since `gdbstub` only supports /// debugging a single process). const FAKE_PID: common::Pid = unsafe { common::Pid::new_unchecked(1) };