1 //! Base operations required to debug any target (read/write memory/registers, 2 //! step/resume, etc...) 3 //! 4 //! It is recommended that single threaded targets implement the simplified 5 //! `singlethread` API, as `gdbstub` includes optimized implementations of 6 //! certain internal routines when operating in singlethreaded mode. 7 8 pub mod multithread; 9 pub mod singlethread; 10 11 mod single_register_access; 12 13 pub use single_register_access::{SingleRegisterAccess, SingleRegisterAccessOps}; 14 15 /// Base operations for single/multi threaded targets. 16 pub enum BaseOps<'a, A, E> { 17 /// Single-threaded target 18 SingleThread(&'a mut dyn singlethread::SingleThreadOps<Arch = A, Error = E>), 19 /// Multi-threaded target 20 MultiThread(&'a mut dyn multithread::MultiThreadOps<Arch = A, Error = E>), 21 } 22 23 /// Describes how the target should be resumed. 24 /// 25 /// Due to a quirk / bug in the mainline GDB client, targets are required to 26 /// handle the `WithSignal` variants of `Step` and `Continue` regardless of 27 /// whether or not they have a concept of "signals". 28 /// 29 /// If your target does not support signals (e.g: the target is a bare-metal 30 /// microcontroller / emulator), the recommended behavior is to either return a 31 /// target-specific fatal error, or to handle `{Step,Continue}WithSignal` the 32 /// same way as their non-`WithSignal` variants. 33 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 34 pub enum ResumeAction { 35 /// Continue execution, stopping once a 36 /// [`StopReason`](singlethread::StopReason) occurs. 37 Continue, 38 /// Step execution. 39 Step, 40 /// Continue with signal. 41 ContinueWithSignal(u8), 42 /// Step with signal. 43 StepWithSignal(u8), 44 } 45 46 /// Describes the point reached in a replay log for the corresponding stop 47 /// reason. 48 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 49 pub enum ReplayLogPosition { 50 /// Reached the beginning of the replay log. 51 Begin, 52 /// Reached the end of the replay log. 53 End, 54 } 55 56 /// A handle to check for incoming GDB interrupts. 57 /// 58 /// At the moment, checking for incoming interrupts requires periodically 59 /// polling for pending interrupts. e.g: 60 /// 61 /// ```ignore 62 /// let interrupts = gdb_interrupt.no_async(); 63 /// loop { 64 /// if interrupts.pending() { 65 /// return Ok(StopReason::GdbInterrupt) 66 /// } 67 /// 68 /// // execute some number of clock cycles 69 /// for _ in 0..1024 { 70 /// match self.system.step() { .. } 71 /// } 72 /// } 73 /// ``` 74 /// 75 /// There is an outstanding issue to add a non-blocking interface to 76 /// `GdbInterrupt` (see [daniel5151/gdbstub#36](https://github.com/daniel5151/gdbstub/issues/36)). 77 /// Please comment on the issue if this is something you'd like to see 78 /// implemented and/or would like to help out with! 79 pub struct GdbInterrupt<'a> { 80 inner: &'a mut dyn FnMut() -> bool, 81 } 82 83 impl<'a> GdbInterrupt<'a> { new(inner: &'a mut dyn FnMut() -> bool) -> GdbInterrupt<'a>84 pub(crate) fn new(inner: &'a mut dyn FnMut() -> bool) -> GdbInterrupt<'a> { 85 GdbInterrupt { inner } 86 } 87 88 /// Returns a [`GdbInterruptNoAsync`] struct which can be polled using a 89 /// simple non-blocking [`pending(&mut self) -> 90 /// bool`](GdbInterruptNoAsync::pending) method. no_async(self) -> GdbInterruptNoAsync<'a>91 pub fn no_async(self) -> GdbInterruptNoAsync<'a> { 92 GdbInterruptNoAsync { inner: self.inner } 93 } 94 } 95 96 /// A simplified interface to [`GdbInterrupt`] for projects without 97 /// async/await infrastructure. 98 pub struct GdbInterruptNoAsync<'a> { 99 inner: &'a mut dyn FnMut() -> bool, 100 } 101 102 impl<'a> GdbInterruptNoAsync<'a> { 103 /// Checks if there is a pending GDB interrupt. pending(&mut self) -> bool104 pub fn pending(&mut self) -> bool { 105 (self.inner)() 106 } 107 } 108