1 //! An ergonomic and easy-to-integrate implementation of the 2 //! [GDB Remote Serial Protocol](https://sourceware.org/gdb/onlinedocs/gdb/Remote-Protocol.html#Remote-Protocol) 3 //! in Rust, with full `#![no_std]` support. 4 //! 5 //! ## Getting Started 6 //! 7 //! This section provides a brief overview of the key traits and types used in 8 //! `gdbstub`, and walks though the basic steps required to integrate `gdbstub` 9 //! into a project. 10 //! 11 //! At a high level, there are only two things that are required to get up and 12 //! running with `gdbstub`: a [`Connection`](#the-connection-trait), and a 13 //! [`Target`](#the-target-trait) 14 //! 15 //! > _Note:_ I _highly recommended_ referencing some of the 16 //! [examples](https://github.com/daniel5151/gdbstub/blob/master/README.md#examples) 17 //! listed in the project README when integrating `gdbstub` into a project for 18 //! the first time. 19 //! 20 //! > In particular, the in-tree 21 //! [`armv4t`](https://github.com/daniel5151/gdbstub/tree/master/examples/armv4t) 22 //! example contains basic implementations off almost all protocol extensions, 23 //! making it an incredibly valuable reference when implementing protocol 24 //! extensions. 25 //! 26 //! ### The `Connection` Trait 27 //! 28 //! First things first: `gdbstub` needs some way to communicate with a GDB 29 //! client. To facilitate this communication, `gdbstub` uses a custom 30 //! [`Connection`] trait. 31 //! 32 //! `Connection` is automatically implemented for common `std` types such as 33 //! [`TcpStream`](std::net::TcpStream) and 34 //! [`UnixStream`](std::os::unix::net::UnixStream). 35 //! 36 //! If you're using `gdbstub` in a `#![no_std]` environment, `Connection` will 37 //! most likely need to be manually implemented on top of whatever in-order, 38 //! serial, byte-wise I/O your particular platform has available (e.g: 39 //! putchar/getchar over UART, using an embedded TCP stack, etc.). 40 //! 41 //! One common way to start a remote debugging session is to simply wait for a 42 //! GDB client to connect via TCP: 43 //! 44 //! ```rust 45 //! use std::io; 46 //! use std::net::{TcpListener, TcpStream}; 47 //! 48 //! fn wait_for_gdb_connection(port: u16) -> io::Result<TcpStream> { 49 //! let sockaddr = format!("localhost:{}", port); 50 //! eprintln!("Waiting for a GDB connection on {:?}...", sockaddr); 51 //! let sock = TcpListener::bind(sockaddr)?; 52 //! let (stream, addr) = sock.accept()?; 53 //! 54 //! // Blocks until a GDB client connects via TCP. 55 //! // i.e: Running `target remote localhost:<port>` from the GDB prompt. 56 //! 57 //! eprintln!("Debugger connected from {}", addr); 58 //! Ok(stream) // `TcpStream` implements `gdbstub::Connection` 59 //! } 60 //! ``` 61 //! 62 //! ### The `Target` Trait 63 //! 64 //! The [`Target`](target::Target) trait describes how to control and modify 65 //! a system's execution state during a GDB debugging session, and serves as the 66 //! primary bridge between `gdbstub`'s generic GDB protocol implementation and a 67 //! specific target's project/platform-specific code. 68 //! 69 //! At a high level, the `Target` trait is a collection of user-defined handler 70 //! methods that the GDB client can invoke via the GDB remote serial protocol. 71 //! For example, the `Target` trait includes methods to read/write 72 //! registers/memory, start/stop execution, etc... 73 //! 74 //! **`Target` is the most important trait in `gdbstub`, and must be implemented 75 //! by anyone integrating `gdbstub` into their project!** 76 //! 77 //! Please refer to the [`target` module documentation](target) for in-depth 78 //! instructions on how to implement [`Target`](target::Target) for a particular 79 //! platform. 80 //! 81 //! ### Starting the debugging session using `GdbStub` 82 //! 83 //! Once a [`Connection`](#the-connection-trait) has been established and 84 //! [`Target`](#the-target-trait) has been all wired up, all that's left is to 85 //! hand things off to [`gdbstub::GdbStub`](GdbStub) and let it do the rest! 86 //! 87 //! ```rust,ignore 88 //! // Set-up a valid `Target` 89 //! let mut target = MyTarget::new()?; // implements `Target` 90 //! 91 //! // Establish a `Connection` 92 //! let connection: TcpStream = wait_for_gdb_connection(9001); 93 //! 94 //! // Create a new `gdbstub::GdbStub` using the established `Connection`. 95 //! let mut debugger = gdbstub::GdbStub::new(connection); 96 //! 97 //! // Instead of taking ownership of the system, `GdbStub` takes a &mut, yielding 98 //! // ownership back to the caller once the debugging session is closed. 99 //! match debugger.run(&mut target) { 100 //! Ok(disconnect_reason) => match disconnect_reason { 101 //! DisconnectReason::Disconnect => println!("GDB client disconnected."), 102 //! DisconnectReason::TargetHalted => println!("Target halted!"), 103 //! DisconnectReason::Kill => println!("GDB client sent a kill command!"), 104 //! } 105 //! // Handle any target-specific errors 106 //! Err(GdbStubError::TargetError(e)) => { 107 //! println!("Target raised a fatal error: {:?}", e); 108 //! // `gdbstub` will not immediate close the debugging session if a 109 //! // fatal error occurs, enabling "post mortem" debugging if required. 110 //! debugger.run(&mut target)?; 111 //! } 112 //! Err(e) => return Err(e.into()) 113 //! } 114 //! ``` 115 //! 116 //! ## Feature flags 117 //! 118 //! By default, both the `std` and `alloc` features are enabled. 119 //! 120 //! When using `gdbstub` in `#![no_std]` contexts, make sure to set 121 //! `default-features = false`. 122 //! 123 //! - `alloc` 124 //! - Implement `Connection` for `Box<dyn Connection>`. 125 //! - Log outgoing packets via `log::trace!` (uses a heap-allocated output 126 //! buffer). 127 //! - Provide built-in implementations for certain protocol features: 128 //! - Use a heap-allocated packet buffer in `GdbStub` (if none is 129 //! provided via `GdbStubBuilder::with_packet_buffer`). 130 //! - (Monitor Command) Use a heap-allocated output buffer in 131 //! `ConsoleOutput`. 132 //! - `std` (implies `alloc`) 133 //! - Implement `Connection` for [`TcpStream`](std::net::TcpStream) and 134 //! [`UnixStream`](std::os::unix::net::UnixStream). 135 //! - Implement [`std::error::Error`] for `gdbstub::Error`. 136 //! - Add a `TargetError::Io` error variant to simplify I/O Error handling 137 //! from `Target` methods. 138 139 #![cfg_attr(not(feature = "std"), no_std)] 140 #![deny(missing_docs)] 141 142 #[cfg(feature = "alloc")] 143 extern crate alloc; 144 145 #[macro_use] 146 extern crate log; 147 148 mod connection; 149 mod gdbstub_impl; 150 mod protocol; 151 mod util; 152 153 #[doc(hidden)] 154 pub mod internal; 155 156 pub mod arch; 157 pub mod common; 158 pub mod target; 159 160 pub use connection::Connection; 161 pub use gdbstub_impl::*; 162 163 /// (Internal) The fake Tid that's used when running in single-threaded mode. 164 // SAFETY: 1 is clearly non-zero. 165 const SINGLE_THREAD_TID: common::Tid = unsafe { common::Tid::new_unchecked(1) }; 166 /// (Internal) The fake Pid reported to GDB (since `gdbstub` only supports 167 /// debugging a single process). 168 const FAKE_PID: common::Pid = unsafe { common::Pid::new_unchecked(1) }; 169