1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
//! 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. //! //! ## 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`](#the-connection-trait), and a //! [`Target`](#the-target-trait) //! //! > _Note:_ I _highly recommended_ referencing some of the //! [examples](https://github.com/daniel5151/gdbstub/blob/master/README.md#examples) //! listed in the project README when integrating `gdbstub` into a project for //! the first time. //! //! > In particular, the in-tree //! [`armv4t`](https://github.com/daniel5151/gdbstub/tree/master/examples/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`](std::net::TcpStream) and //! [`UnixStream`](std::os::unix::net::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: //! //! ```rust //! 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`](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 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](target) for in-depth //! instructions on how to implement [`Target`](target::Target) for a particular //! platform. //! //! ### Starting the debugging session using `GdbStub` //! //! Once a [`Connection`](#the-connection-trait) has been established and //! [`Target`](#the-target-trait) has been all wired up, all that's left is to //! hand things off to [`gdbstub::GdbStub`](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::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` for `Box<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 via `GdbStubBuilder::with_packet_buffer`). //! - (Monitor Command) Use a heap-allocated output buffer in //! `ConsoleOutput`. //! - `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. #![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) };