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