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