• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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