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
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
//! 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.
//!
//! `gdbstub` is entirely `#![no_std]` compatible, and can be used on platforms
//! without a global allocator. In embedded contexts, `gdbstub` can be
//! configured to use pre-allocated buffers and communicate over any available
//! serial I/O connection (e.g: UART).
//!
//! `gdbstub` is particularly well suited for _emulation_, making it easy to add
//! powerful, non-intrusive debugging support to an emulated system. Just
//! provide an implementation of [`Target`](trait.Target.html) for your target
//! platform, and you're ready to start debugging!
//!
//! ## Debugging Features
//!
//! Features marked as (optional) aren't required to be implemented, but can be
//! implemented to enhance the debugging experience.
//!
//! - Core GDB Protocol
//!     - Step + Continue
//!     - Add + Remove Software Breakpoints
//!     - Read/Write memory
//!     - Read/Write registers
//!     - (optional) Add + Remove Hardware Breakpoints
//!     - (optional) Read/Write/Access Watchpoints (i.e: value breakpoints)
//!     - (optional) Multithreading support
//! - Extended GDB Protocol
//!     - (optional) Handle custom debug commands (sent via GDB's `monitor`
//!       command)
//!     - (optional) Automatic architecture detection
//!
//! If `gdbstub` is missing a feature you'd like to use, please file an issue /
//! open a PR!
//!
//! ## Feature flags
//!
//! The `std` feature is enabled by default. In `#![no_std]` contexts, use
//! `default-features = false`.
//!
//! - `alloc`
//!     - Implements `Connection` for `Box<dyn Connection>`.
//!     - Adds output buffering to `ConsoleOutput`.
//! - `std` (implies `alloc`)
//!     - Implements `Connection` for [`TcpStream`](https://doc.rust-lang.org/std/net/struct.TcpStream.html)
//!       and [`UnixStream`](https://doc.rust-lang.org/std/os/unix/net/struct.UnixStream.html).
//!     - Implements [`std::error::Error`](https://doc.rust-lang.org/std/error/trait.Error.html)
//!       for `gdbstub::Error`
//!     - Log outgoing packets via `log::trace!` (uses a heap-allocated output
//!       buffer)
//!
//! ## 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.
//!
//! Additionally, if you're looking for some more fleshed-out examples, take a
//! look at some of the [examples](https://github.com/daniel5151/gdbstub/blob/master/README.md#examples)
//! listed in the project README.
//!
//! ### The `Connection` Trait
//!
//! The [`Connection`](trait.Connection.html) trait describes how `gdbstub`
//! should communicate with the main GDB process.
//!
//! `Connection` is automatically implemented for common `std` types such as
//! `TcpStream` and `UnixStream`. In `#![no_std]` environments, `Connection`
//! must be implemented manually, using whatever bytewise transport the
//! hardware has available (e.g: UART).
//!
//! A common way to start a remote debugging session is to wait for the GDB
//! client to connect via TCP:
//!
//! ```rust
//! use std::net::{TcpListener, TcpStream};
//!
//! fn wait_for_gdb_connection(port: u16) -> std::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)
//! }
//! ```
//!
//! ### The `Target` Trait
//!
//! The [`Target`](trait.Target.html) trait describes how to control and modify
//! a system's execution state during a GDB debugging session. Since each target
//! is different, it's up to the user to provide methods to read/write memory,
//! start/stop execution, etc...
//!
//! The [`Target::Arch`](arch/trait.Arch.html) associated type encodes
//! information about the target's architecture, such as it's pointer size,
//! register layout, etc... `gdbstub` comes with several built-in architecture
//! definitions, which can be found under the [`arch`](arch/index.html) module.
//!
//! One key ergonomic feature of the `Target` trait is that it "plumbs-through"
//! any existing project-specific error-handling via the `Target::Error`
//! associated type. Every method of `Target` returns a `Result<T,
//! Target::Error>`, which makes it's possible to use the `?` operator for error
//! handling, _without_ having wrapping errors in `gdbstub` specific variants!
//!
//! For example, here's what an implementation of `Target` might look like for a
//! single-core emulator targeting the ARMv4T instruction set. See the
//! [examples](https://github.com/daniel5151/gdbstub/blob/master/README.md#examples)
//! section of the project README for more fleshed-out examples.
//!
//! ```rust,ignore
//! // Simplified and modified from gdbstub/examples/armv4t/gdb.rs
//!
//! use gdbstub::{
//!     arch, BreakOp, ResumeAction, StopReason, Target, Tid, TidSelector,
//!     SINGLE_THREAD_TID,
//! };
//!
//! // ------------- Existing Emulator Code ------------- //
//!
//! enum EmuError {
//!     BadRead,
//!     BadWrite,
//!     // ...
//! }
//!
//! struct Emu {
//!     breakpoints: Vec<u32>,
//!     /* ... */
//! }
//! impl Emu {
//!     fn step(&mut self) -> Result<Option<EmuEvent>, EmuError>;
//!     fn read8(&mut self, addr: u32) -> Result<u8, EmuError>;
//!     fn write8(&mut self, addr: u32, val: u8) -> Result<(), EmuError>;
//! }
//!
//! enum EmuEvent {
//!     Halted,
//!     Break
//! }
//!
//! // ------------- `gdbstub` Integration ------------- //
//!
//! impl Target for Emu {
//!     type Arch = arch::arm::Armv4t;
//!     type Error = EmuError;
//!
//!     fn resume(
//!         &mut self,
//!         actions: &mut dyn Iterator<Item = (TidSelector, ResumeAction)>,
//!         check_gdb_interrupt: &mut dyn FnMut() -> bool,
//!     ) -> Result<(Tid, StopReason<u32>), Self::Error> {
//!         // one thread, only one action
//!         let (_, action) = actions.next().unwrap();
//!
//!         let event = match action {
//!             ResumeAction::Step => match self.step()? {
//!                 Some(e) => e,
//!                 None => return Ok((SINGLE_THREAD_TID, StopReason::DoneStep)),
//!             },
//!             ResumeAction::Continue => {
//!                 let mut cycles = 0;
//!                 loop {
//!                     if let Some(event) = self.step()? {
//!                         break event;
//!                     };
//!
//!                     // check for GDB interrupt every 1024 instructions
//!                     cycles += 1;
//!                     if cycles % 1024 == 0 && check_gdb_interrupt() {
//!                         return Ok((SINGLE_THREAD_TID, StopReason::GdbInterrupt));
//!                     }
//!                 }
//!             }
//!         };
//!
//!         Ok((
//!             SINGLE_THREAD_TID,
//!             match event {
//!                 EmuEvent::Halted => StopReason::Halted,
//!                 EmuEvent::Break => StopReason::HwBreak,
//!             },
//!         ))
//!     }
//!
//!     fn read_registers(
//!         &mut self,
//!         regs: &mut arch::arm::reg::ArmCoreRegs,
//!     ) -> Result<(), EmuError> {
//!         // fill up `regs` be querying self
//!         Ok(())
//!     }
//!
//!     fn write_registers(&mut self, regs: &arch::arm::reg::ArmCoreRegs) -> Result<(), EmuError> {
//!         // update `self` with data from `regs`
//!         Ok(())
//!     }
//!
//!     fn read_addrs(
//!         &mut self,
//!         addr: std::ops::Range<u32>,
//!         push_byte: &mut dyn FnMut(u8),
//!     ) -> Result<(), EmuError> {
//!         for addr in addr {
//!             push_byte(self.read8(addr)?)
//!         }
//!         Ok(())
//!     }
//!
//!     fn write_addrs(&mut self, start_addr: u32, data: &[u8]) -> Result<(), EmuError> {
//!         for (addr, val) in (start_addr..).zip(data.iter().copied()) {
//!             self.write8(addr, val)?
//!         }
//!         Ok(())
//!     }
//!
//!     fn update_sw_breakpoint(&mut self, addr: u32, op: BreakOp) -> Result<bool, EmuError> {
//!         match op {
//!             BreakOp::Add => self.breakpoints.push(addr),
//!             BreakOp::Remove => {
//!                 let pos = match self.breakpoints.iter().position(|x| *x == addr) {
//!                     None => return Ok(false),
//!                     Some(pos) => pos,
//!                 };
//!                 self.breakpoints.remove(pos);
//!             }
//!         }
//!
//!         Ok(true)
//!     }
//! }
//! ```
//!
//! ### Starting the debugging session
//!
//! Once a `Connection` has been established and a `Target` is available, all
//! that's left is to pass both of them over to
//! [`GdbStub`](struct.GdbStub.html) and let it do the rest!
//!
//! ```rust,ignore
//! fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     // Pre-existing setup code
//!     let mut emu = Emu::new()?;
//!     // ... etc ...
//!
//!     // Establish a `Connection`
//!     let connection = wait_for_gdb_connection(9001);
//!
//!     // Create a new `GdbStub` using the established `Connection`.
//!     let debugger = GdbStub::new(connection);
//!
//!     // Instead of taking ownership of the system, GdbStub takes a &mut, yielding
//!     // ownership once the debugging session is closed, or an error occurs.
//!     match debugger.run(&mut emu) {
//!         Ok(disconnect_reason) => match disconnect_reason {
//!             DisconnectReason::Disconnect => {
//!                 // run to completion
//!                 while emu.step() != Some(EmuEvent::Halted) {}
//!             }
//!             DisconnectReason::TargetHalted => println!("Target halted!"),
//!             DisconnectReason::Kill => {
//!                 println!("GDB sent a kill command!");
//!             }
//!         }
//!         Err(GdbStubError::TargetError(e)) => {
//!             println!("Emu raised a fatal error: {:?}", e);
//!         }
//!         Err(e) => return Err(e.into())
//!     }
//!
//!     Ok(())
//! }
//! ```

#![cfg_attr(not(feature = "std"), no_std)]
#![deny(missing_docs)]

#[cfg(feature = "alloc")]
extern crate alloc;

#[macro_use]
extern crate log;

pub mod arch;
pub mod internal;

mod connection;
mod gdbstub_impl;
mod protocol;
mod target;
mod util;

pub use connection::Connection;
pub use gdbstub_impl::*;
pub use protocol::{ConsoleOutput, TidSelector};
pub use target::*;

/// Thread ID
// TODO: FUTURE: expose full PID.TID to client?
pub type Tid = core::num::NonZeroUsize;

/// TID which should be returned by
/// [`Target::resume`](trait.Target.html#tymethod.resume) on single-threaded
/// targets.
// SAFETY: 1 is a non-zero value :P
pub const SINGLE_THREAD_TID: Tid = unsafe { Tid::new_unchecked(1) };

/// A result type used by optional [`Target`](trait.Target.html) methods.
///
/// `OptResult<T, E>` should be indistinguishable from `Result<T, E>`, aside
/// from the small caveat of having to use `.into()` when returning `Err`
/// variants (i.e: `return Err(foo)` will fail to compile).
pub type OptResult<T, E> = Result<T, internal::MaybeUnimpl<E>>;