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