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 //! ## Feature flags 6 //! 7 //! By default, the `std` and `alloc` features are enabled. 8 //! 9 //! When using `gdbstub` in `#![no_std]` contexts, make sure to set 10 //! `default-features = false`. 11 //! 12 //! - `alloc` 13 //! - Implement `Connection` for `Box<dyn Connection>`. 14 //! - Log outgoing packets via `log::trace!` (uses a heap-allocated output 15 //! buffer). 16 //! - Provide built-in implementations for certain protocol features: 17 //! - Use a heap-allocated packet buffer in `GdbStub` (if none is 18 //! provided via `GdbStubBuilder::with_packet_buffer`). 19 //! - (Monitor Command) Use a heap-allocated output buffer in 20 //! `ConsoleOutput`. 21 //! - (Extended Mode) Automatically track Attached/Spawned PIDs without 22 //! implementing `ExtendedMode::query_if_attached`. 23 //! - `std` (implies `alloc`) 24 //! - Implement `Connection` for [`TcpStream`](std::net::TcpStream) and 25 //! [`UnixStream`](std::os::unix::net::UnixStream). 26 //! - Implement [`std::error::Error`] for `gdbstub::Error`. 27 //! - Add a `TargetError::Io` error variant to simplify I/O Error handling 28 //! from `Target` methods. 29 //! 30 //! ## Getting Started 31 //! 32 //! This section provides a brief overview of the key traits and types used in 33 //! `gdbstub`, and walks though the basic steps required to integrate `gdbstub` 34 //! into a project. 35 //! 36 //! It is **highly recommended** to take a look at some of the 37 //! [**examples**](https://github.com/daniel5151/gdbstub/blob/master/README.md#examples) 38 //! listed in the project README. In particular, the included 39 //! [**`armv4t`**](https://github.com/daniel5151/gdbstub/tree/master/examples/armv4t) 40 //! example implements most of `gdbstub`'s protocol extensions, and can be a 41 //! valuable resource when getting up-and-running with `gdbstub`. 42 //! 43 //! ### The `Connection` Trait 44 //! 45 //! The [`Connection`] trait describes how `gdbstub` should communicate with the 46 //! main GDB process. 47 //! 48 //! `Connection` is automatically implemented for common `std` types such as 49 //! [`TcpStream`](std::net::TcpStream) and 50 //! [`UnixStream`](std::os::unix::net::UnixStream). In `#![no_std]` 51 //! environments, `Connection` must be manually implemented using whatever 52 //! in-order, serial, byte-wise I/O the hardware has available (e.g: 53 //! putchar/getchar over UART, an embedded TCP stack, etc.). 54 //! 55 //! A common way to start a remote debugging session is to wait for a GDB client 56 //! to connect via TCP: 57 //! 58 //! ```rust 59 //! use std::net::{TcpListener, TcpStream}; 60 //! 61 //! fn wait_for_gdb_connection(port: u16) -> std::io::Result<TcpStream> { 62 //! let sockaddr = format!("localhost:{}", port); 63 //! eprintln!("Waiting for a GDB connection on {:?}...", sockaddr); 64 //! let sock = TcpListener::bind(sockaddr)?; 65 //! let (stream, addr) = sock.accept()?; 66 //! 67 //! // Blocks until a GDB client connects via TCP. 68 //! // i.e: Running `target remote localhost:<port>` from the GDB prompt. 69 //! 70 //! eprintln!("Debugger connected from {}", addr); 71 //! Ok(stream) 72 //! } 73 //! ``` 74 //! 75 //! ### The `Target` Trait 76 //! 77 //! The [`Target`](target::Target) trait describes how to control and modify 78 //! a system's execution state during a GDB debugging session, and serves as the 79 //! primary bridge between `gdbstub`'s generic protocol implementation and a 80 //! target's project/platform-specific code. 81 //! 82 //! For example: the `Target` trait includes a method called `read_registers()`, 83 //! which the `GdbStub` calls whenever the GDB client queries the state of the 84 //! target's registers. 85 //! 86 //! **`Target` is the most important trait in `gdbstub`, and must be implemented 87 //! by anyone who uses the library!** 88 //! 89 //! Please refer to the [`target` module documentation](target) for in-depth 90 //! instructions on implementing `Target`. 91 //! 92 //! ### Starting the debugging session using `GdbStub` 93 //! 94 //! Once a `Connection` has been established and `Target` has been all wired up, 95 //! all that's left is to hand things off to [`GdbStub`] and let it do the rest! 96 //! 97 //! ```rust,ignore 98 //! // Set-up a valid `Target` 99 //! let mut target = MyTarget::new()?; // implements `Target` 100 //! 101 //! // Establish a `Connection` 102 //! let connection: TcpStream = wait_for_gdb_connection(9001); 103 //! 104 //! // Create a new `GdbStub` using the established `Connection`. 105 //! let mut debugger = GdbStub::new(connection); 106 //! 107 //! // Instead of taking ownership of the system, `GdbStub` takes a &mut, yielding 108 //! // ownership back to the caller once the debugging session is closed. 109 //! match debugger.run(&mut target) { 110 //! Ok(disconnect_reason) => match disconnect_reason { 111 //! DisconnectReason::Disconnect => println!("GDB client disconnected."), 112 //! DisconnectReason::TargetHalted => println!("Target halted!"), 113 //! DisconnectReason::Kill => println!("GDB client sent a kill command!"), 114 //! } 115 //! // Handle any target-specific errors 116 //! Err(GdbStubError::TargetError(e)) => { 117 //! println!("Target raised a fatal error: {:?}", e); 118 //! // e.g: re-enter the debugging session after "freezing" a system to 119 //! // conduct some post-mortem debugging 120 //! debugger.run(&mut target)?; 121 //! } 122 //! Err(e) => return Err(e.into()) 123 //! } 124 //! ``` 125 126 #![cfg_attr(not(feature = "std"), no_std)] 127 #![deny(missing_docs)] 128 129 #[cfg(feature = "alloc")] 130 extern crate alloc; 131 132 #[macro_use] 133 extern crate log; 134 135 mod connection; 136 mod gdbstub_impl; 137 mod protocol; 138 mod util; 139 140 #[doc(hidden)] 141 pub mod internal; 142 143 pub mod arch; 144 pub mod common; 145 pub mod target; 146 147 pub use connection::Connection; 148 pub use gdbstub_impl::*; 149 150 /// (Internal) The fake Tid that's used when running in single-threaded mode. 151 // SAFETY: 1 is clearly non-zero. 152 const SINGLE_THREAD_TID: common::Tid = unsafe { common::Tid::new_unchecked(1) }; 153 /// (Internal) The fake Pid reported to GDB (since `gdbstub` only supports 154 /// debugging a single process). 155 const FAKE_PID: common::Pid = unsafe { common::Pid::new_unchecked(1) }; 156