1 //! Base debugging operations for multi threaded targets.
2 
3 use crate::arch::Arch;
4 use crate::common::Signal;
5 use crate::common::Tid;
6 use crate::target::Target;
7 use crate::target::TargetResult;
8 
9 /// Base required debugging operations for multi threaded targets.
10 pub trait MultiThreadBase: Target {
11     /// Read the target's registers.
12     ///
13     /// If the registers could not be accessed, an appropriate non-fatal error
14     /// should be returned.
read_registers( &mut self, regs: &mut <Self::Arch as Arch>::Registers, tid: Tid, ) -> TargetResult<(), Self>15     fn read_registers(
16         &mut self,
17         regs: &mut <Self::Arch as Arch>::Registers,
18         tid: Tid,
19     ) -> TargetResult<(), Self>;
20 
21     /// Write the target's registers.
22     ///
23     /// If the registers could not be accessed, an appropriate non-fatal error
24     /// should be returned.
write_registers( &mut self, regs: &<Self::Arch as Arch>::Registers, tid: Tid, ) -> TargetResult<(), Self>25     fn write_registers(
26         &mut self,
27         regs: &<Self::Arch as Arch>::Registers,
28         tid: Tid,
29     ) -> TargetResult<(), Self>;
30 
31     /// Support for single-register access.
32     /// See [`SingleRegisterAccess`] for more details.
33     ///
34     /// While this is an optional feature, it is **highly recommended** to
35     /// implement it when possible, as it can significantly improve performance
36     /// on certain architectures.
37     ///
38     /// [`SingleRegisterAccess`]:
39     /// super::single_register_access::SingleRegisterAccess
40     #[inline(always)]
support_single_register_access( &mut self, ) -> Option<super::single_register_access::SingleRegisterAccessOps<'_, Tid, Self>>41     fn support_single_register_access(
42         &mut self,
43     ) -> Option<super::single_register_access::SingleRegisterAccessOps<'_, Tid, Self>> {
44         None
45     }
46 
47     /// Read bytes from the specified address range and return the number of
48     /// bytes that were read.
49     ///
50     /// Implementations may return a number `n` that is less than `data.len()`
51     /// to indicate that memory starting at `start_addr + n` cannot be
52     /// accessed.
53     ///
54     /// Implemenations may also return an appropriate non-fatal error if the
55     /// requested address range could not be accessed (e.g: due to MMU
56     /// protection, unhanded page fault, etc...).
57     ///
58     /// Implementations must guarantee that the returned number is less than or
59     /// equal `data.len()`.
read_addrs( &mut self, start_addr: <Self::Arch as Arch>::Usize, data: &mut [u8], tid: Tid, ) -> TargetResult<usize, Self>60     fn read_addrs(
61         &mut self,
62         start_addr: <Self::Arch as Arch>::Usize,
63         data: &mut [u8],
64         tid: Tid,
65     ) -> TargetResult<usize, Self>;
66 
67     /// Write bytes to the specified address range.
68     ///
69     /// If the requested address range could not be accessed (e.g: due to
70     /// MMU protection, unhanded page fault, etc...), an appropriate non-fatal
71     /// error should be returned.
write_addrs( &mut self, start_addr: <Self::Arch as Arch>::Usize, data: &[u8], tid: Tid, ) -> TargetResult<(), Self>72     fn write_addrs(
73         &mut self,
74         start_addr: <Self::Arch as Arch>::Usize,
75         data: &[u8],
76         tid: Tid,
77     ) -> TargetResult<(), Self>;
78 
79     /// List all currently active threads.
80     ///
81     /// See [the section above](#bare-metal-targets) on implementing
82     /// thread-related methods on bare-metal (threadless) targets.
83     ///
84     /// _Note_: Implementors should mark this method as `#[inline(always)]`, as
85     /// this will result in better codegen (namely, by sidestepping any of the
86     /// `dyn FnMut` closure machinery).
list_active_threads( &mut self, thread_is_active: &mut dyn FnMut(Tid), ) -> Result<(), Self::Error>87     fn list_active_threads(
88         &mut self,
89         thread_is_active: &mut dyn FnMut(Tid),
90     ) -> Result<(), Self::Error>;
91 
92     /// Check if the specified thread is alive.
93     ///
94     /// As a convenience, this method provides a default implementation which
95     /// uses `list_active_threads` to do a linear-search through all active
96     /// threads. On thread-heavy systems, it may be more efficient
97     /// to override this method with a more direct query.
98     #[allow(clippy::wrong_self_convention)] // requires breaking change to fix
is_thread_alive(&mut self, tid: Tid) -> Result<bool, Self::Error>99     fn is_thread_alive(&mut self, tid: Tid) -> Result<bool, Self::Error> {
100         let mut found = false;
101         self.list_active_threads(&mut |active_tid| {
102             if tid == active_tid {
103                 found = true;
104             }
105         })?;
106         Ok(found)
107     }
108 
109     /// Support for resuming the target (e.g: via `continue` or `step`)
110     #[inline(always)]
support_resume(&mut self) -> Option<MultiThreadResumeOps<'_, Self>>111     fn support_resume(&mut self) -> Option<MultiThreadResumeOps<'_, Self>> {
112         None
113     }
114 
115     /// Support for providing thread extra information.
116     #[inline(always)]
support_thread_extra_info( &mut self, ) -> Option<crate::target::ext::thread_extra_info::ThreadExtraInfoOps<'_, Self>>117     fn support_thread_extra_info(
118         &mut self,
119     ) -> Option<crate::target::ext::thread_extra_info::ThreadExtraInfoOps<'_, Self>> {
120         None
121     }
122 }
123 
124 /// Target extension - support for resuming multi threaded targets.
125 pub trait MultiThreadResume: Target {
126     /// Resume execution on the target.
127     ///
128     /// Prior to calling `resume`, `gdbstub` will call `clear_resume_actions`,
129     /// followed by zero or more calls to the `set_resume_action_XXX` methods,
130     /// specifying any thread-specific resume actions.
131     ///
132     /// Upon returning from the `resume` method, the target being debugged
133     /// should be configured to run according to whatever resume actions the
134     /// GDB client had specified using any of the `set_resume_action_XXX`
135     /// methods.
136     ///
137     /// Any thread that wasn't explicitly resumed by a `set_resume_action_XXX`
138     /// method should be resumed as though it was resumed with
139     /// `set_resume_action_continue`.
140     ///
141     /// A basic target implementation only needs to implement support for
142     /// `set_resume_action_continue`, with all other resume actions requiring
143     /// their corresponding protocol extension to be implemented:
144     ///
145     /// Action                      | Protocol Extension
146     /// ----------------------------|------------------------------
147     /// Optimized [Single Stepping] | See [`support_single_step()`]
148     /// Optimized [Range Stepping]  | See [`support_range_step()`]
149     /// "Stop"                      | Used in "Non-Stop" mode \*
150     ///
151     /// \* "Non-Stop" mode is currently unimplemented in `gdbstub`
152     ///
153     /// [Single stepping]: https://sourceware.org/gdb/current/onlinedocs/gdb/Continuing-and-Stepping.html#index-stepi
154     /// [Range Stepping]: https://sourceware.org/gdb/current/onlinedocs/gdb/Continuing-and-Stepping.html#range-stepping
155     /// [`support_single_step()`]: Self::support_single_step
156     /// [`support_range_step()`]: Self::support_range_step
157     ///
158     /// # Additional Considerations
159     ///
160     /// ### Adjusting PC after a breakpoint is hit
161     ///
162     /// The [GDB remote serial protocol documentation](https://sourceware.org/gdb/current/onlinedocs/gdb/Stop-Reply-Packets.html#swbreak-stop-reason)
163     /// notes the following:
164     ///
165     /// > On some architectures, such as x86, at the architecture level, when a
166     /// > breakpoint instruction executes the program counter points at the
167     /// > breakpoint address plus an offset. On such targets, the stub is
168     /// > responsible for adjusting the PC to point back at the breakpoint
169     /// > address.
170     ///
171     /// Omitting PC adjustment may result in unexpected execution flow and/or
172     /// breakpoints not appearing to work correctly.
173     ///
174     /// ### Bare-Metal Targets
175     ///
176     /// On bare-metal targets (such as microcontrollers or emulators), it's
177     /// common to treat individual _CPU cores_ as a separate "threads". e.g:
178     /// in a dual-core system, [CPU0, CPU1] might be mapped to [TID1, TID2]
179     /// (note that TIDs cannot be zero).
180     ///
181     /// In this case, the `Tid` argument of `read/write_addrs` becomes quite
182     /// relevant, as different cores may have different memory maps.
resume(&mut self) -> Result<(), Self::Error>183     fn resume(&mut self) -> Result<(), Self::Error>;
184 
185     /// Clear all previously set resume actions.
clear_resume_actions(&mut self) -> Result<(), Self::Error>186     fn clear_resume_actions(&mut self) -> Result<(), Self::Error>;
187 
188     /// Continue the specified thread.
189     ///
190     /// See the [`resume`](Self::resume) docs for information on when this is
191     /// called.
192     ///
193     /// The GDB client may also include a `signal` which should be passed to the
194     /// target.
set_resume_action_continue( &mut self, tid: Tid, signal: Option<Signal>, ) -> Result<(), Self::Error>195     fn set_resume_action_continue(
196         &mut self,
197         tid: Tid,
198         signal: Option<Signal>,
199     ) -> Result<(), Self::Error>;
200 
201     /// Support for optimized [single stepping].
202     ///
203     /// [single stepping]: https://sourceware.org/gdb/current/onlinedocs/gdb/Continuing-and-Stepping.html#index-stepi
204     #[inline(always)]
support_single_step(&mut self) -> Option<MultiThreadSingleStepOps<'_, Self>>205     fn support_single_step(&mut self) -> Option<MultiThreadSingleStepOps<'_, Self>> {
206         None
207     }
208 
209     /// Support for optimized [range stepping].
210     ///
211     /// [range stepping]: https://sourceware.org/gdb/current/onlinedocs/gdb/Continuing-and-Stepping.html#range-stepping
212     #[inline(always)]
support_range_step(&mut self) -> Option<MultiThreadRangeSteppingOps<'_, Self>>213     fn support_range_step(&mut self) -> Option<MultiThreadRangeSteppingOps<'_, Self>> {
214         None
215     }
216 
217     /// Support for [reverse stepping] a target.
218     ///
219     /// [reverse stepping]: https://sourceware.org/gdb/current/onlinedocs/gdb/Reverse-Execution.html
220     #[inline(always)]
support_reverse_step( &mut self, ) -> Option<super::reverse_exec::ReverseStepOps<'_, Tid, Self>>221     fn support_reverse_step(
222         &mut self,
223     ) -> Option<super::reverse_exec::ReverseStepOps<'_, Tid, Self>> {
224         None
225     }
226 
227     /// Support for [reverse continuing] a target.
228     ///
229     /// [reverse continuing]: https://sourceware.org/gdb/current/onlinedocs/gdb/Reverse-Execution.html
230     #[inline(always)]
support_reverse_cont( &mut self, ) -> Option<super::reverse_exec::ReverseContOps<'_, Tid, Self>>231     fn support_reverse_cont(
232         &mut self,
233     ) -> Option<super::reverse_exec::ReverseContOps<'_, Tid, Self>> {
234         None
235     }
236 }
237 
238 define_ext!(MultiThreadResumeOps, MultiThreadResume);
239 
240 /// Target Extension - Optimized single stepping for multi threaded targets.
241 /// See [`MultiThreadResume::support_single_step`].
242 pub trait MultiThreadSingleStep: Target + MultiThreadResume {
243     /// [Single step] the specified target thread.
244     ///
245     /// Single stepping will step the target a single "step" - typically a
246     /// single instruction.
247     ///
248     /// The GDB client may also include a `signal` which should be passed to the
249     /// target.
250     ///
251     /// If your target does not support signals (e.g: the target is a bare-metal
252     /// microcontroller / emulator), the recommended behavior is to return a
253     /// target-specific fatal error
254     ///
255     /// [Single step]: https://sourceware.org/gdb/current/onlinedocs/gdb/Continuing-and-Stepping.html#index-stepi
set_resume_action_step( &mut self, tid: Tid, signal: Option<Signal>, ) -> Result<(), Self::Error>256     fn set_resume_action_step(
257         &mut self,
258         tid: Tid,
259         signal: Option<Signal>,
260     ) -> Result<(), Self::Error>;
261 }
262 
263 define_ext!(MultiThreadSingleStepOps, MultiThreadSingleStep);
264 
265 /// Target Extension - Optimized range stepping for multi threaded targets.
266 /// See [`MultiThreadResume::support_range_step`].
267 pub trait MultiThreadRangeStepping: Target + MultiThreadResume {
268     /// [Range step] the specified target thread.
269     ///
270     /// Range Stepping will step the target once, and keep stepping the target
271     /// as long as execution remains between the specified start (inclusive)
272     /// and end (exclusive) addresses, or another stop condition is met
273     /// (e.g: a breakpoint it hit).
274     ///
275     /// If the range is empty (`start` == `end`), then the action becomes
276     /// equivalent to the ‘s’ action. In other words, single-step once, and
277     /// report the stop (even if the stepped instruction jumps to start).
278     ///
279     /// _Note:_ A stop reply may be sent at any point even if the PC is still
280     /// within the stepping range; for example, it is valid to implement range
281     /// stepping in a degenerate way as a single instruction step operation.
282     ///
283     /// [Range step]: https://sourceware.org/gdb/current/onlinedocs/gdb/Continuing-and-Stepping.html#range-stepping
set_resume_action_range_step( &mut self, tid: Tid, start: <Self::Arch as Arch>::Usize, end: <Self::Arch as Arch>::Usize, ) -> Result<(), Self::Error>284     fn set_resume_action_range_step(
285         &mut self,
286         tid: Tid,
287         start: <Self::Arch as Arch>::Usize,
288         end: <Self::Arch as Arch>::Usize,
289     ) -> Result<(), Self::Error>;
290 }
291 
292 define_ext!(MultiThreadRangeSteppingOps, MultiThreadRangeStepping);
293