1 //! Base debugging operations for single threaded targets. 2 3 use crate::arch::Arch; 4 use crate::target::ext::breakpoints::WatchKind; 5 use crate::target::{Target, TargetResult}; 6 7 use super::{ReplayLogPosition, SingleRegisterAccessOps}; 8 9 // Convenient re-exports 10 pub use super::{GdbInterrupt, ResumeAction}; 11 12 /// Base debugging operations for single threaded targets. 13 #[allow(clippy::type_complexity)] 14 pub trait SingleThreadOps: Target { 15 /// Resume execution on the target. 16 /// 17 /// `action` specifies how the target should be resumed (i.e: step or 18 /// continue). 19 /// 20 /// The `check_gdb_interrupt` callback can be invoked to check if GDB sent 21 /// an Interrupt packet (i.e: the user pressed Ctrl-C). It's recommended to 22 /// invoke this callback every-so-often while the system is running (e.g: 23 /// every X cycles/milliseconds). Periodically checking for incoming 24 /// interrupt packets is _not_ required, but it is _recommended_. 25 /// 26 /// # Implementation requirements 27 /// 28 /// These requirements cannot be satisfied by `gdbstub` internally, and must 29 /// be handled on a per-target basis. 30 /// 31 /// ### Adjusting PC after a breakpoint is hit 32 /// 33 /// The [GDB remote serial protocol documentation](https://sourceware.org/gdb/current/onlinedocs/gdb/Stop-Reply-Packets.html#swbreak-stop-reason) 34 /// notes the following: 35 /// 36 /// > On some architectures, such as x86, at the architecture level, when a 37 /// > breakpoint instruction executes the program counter points at the 38 /// > breakpoint address plus an offset. On such targets, the stub is 39 /// > responsible for adjusting the PC to point back at the breakpoint 40 /// > address. 41 /// 42 /// Omitting PC adjustment may result in unexpected execution flow and/or 43 /// breakpoints not appearing to work correctly. resume( &mut self, action: ResumeAction, gdb_interrupt: GdbInterrupt<'_>, ) -> Result<StopReason<<Self::Arch as Arch>::Usize>, Self::Error>44 fn resume( 45 &mut self, 46 action: ResumeAction, 47 gdb_interrupt: GdbInterrupt<'_>, 48 ) -> Result<StopReason<<Self::Arch as Arch>::Usize>, Self::Error>; 49 50 /// Support for the optimized [range stepping] resume action. 51 /// 52 /// [range stepping]: https://sourceware.org/gdb/current/onlinedocs/gdb/Continuing-and-Stepping.html#range-stepping 53 #[inline(always)] support_resume_range_step(&mut self) -> Option<SingleThreadRangeSteppingOps<Self>>54 fn support_resume_range_step(&mut self) -> Option<SingleThreadRangeSteppingOps<Self>> { 55 None 56 } 57 58 /// Support for [reverse stepping] a target. 59 /// 60 /// [reverse stepping]: https://sourceware.org/gdb/current/onlinedocs/gdb/Reverse-Execution.html 61 #[inline(always)] support_reverse_step(&mut self) -> Option<SingleThreadReverseStepOps<Self>>62 fn support_reverse_step(&mut self) -> Option<SingleThreadReverseStepOps<Self>> { 63 None 64 } 65 66 /// Support for [reverse continuing] a target. 67 /// 68 /// [reverse continuing]: https://sourceware.org/gdb/current/onlinedocs/gdb/Reverse-Execution.html 69 #[inline(always)] support_reverse_cont(&mut self) -> Option<SingleThreadReverseContOps<Self>>70 fn support_reverse_cont(&mut self) -> Option<SingleThreadReverseContOps<Self>> { 71 None 72 } 73 74 /// Read the target's registers. read_registers( &mut self, regs: &mut <Self::Arch as Arch>::Registers, ) -> TargetResult<(), Self>75 fn read_registers( 76 &mut self, 77 regs: &mut <Self::Arch as Arch>::Registers, 78 ) -> TargetResult<(), Self>; 79 80 /// Write the target's registers. write_registers(&mut self, regs: &<Self::Arch as Arch>::Registers) -> TargetResult<(), Self>81 fn write_registers(&mut self, regs: &<Self::Arch as Arch>::Registers) 82 -> TargetResult<(), Self>; 83 84 /// Support for single-register access. 85 /// See [`SingleRegisterAccess`](super::SingleRegisterAccess) for more 86 /// details. 87 /// 88 /// While this is an optional feature, it is **highly recommended** to 89 /// implement it when possible, as it can significantly improve performance 90 /// on certain architectures. 91 #[inline(always)] single_register_access(&mut self) -> Option<SingleRegisterAccessOps<(), Self>>92 fn single_register_access(&mut self) -> Option<SingleRegisterAccessOps<(), Self>> { 93 None 94 } 95 96 /// Read bytes from the specified address range. 97 /// 98 /// If the requested address range could not be accessed (e.g: due to 99 /// MMU protection, unhanded page fault, etc...), an appropriate 100 /// non-fatal error should be returned. read_addrs( &mut self, start_addr: <Self::Arch as Arch>::Usize, data: &mut [u8], ) -> TargetResult<(), Self>101 fn read_addrs( 102 &mut self, 103 start_addr: <Self::Arch as Arch>::Usize, 104 data: &mut [u8], 105 ) -> TargetResult<(), Self>; 106 107 /// Write bytes to the specified address range. 108 /// 109 /// If the requested address range could not be accessed (e.g: due to 110 /// MMU protection, unhanded page fault, etc...), an appropriate 111 /// non-fatal error should be returned. write_addrs( &mut self, start_addr: <Self::Arch as Arch>::Usize, data: &[u8], ) -> TargetResult<(), Self>112 fn write_addrs( 113 &mut self, 114 start_addr: <Self::Arch as Arch>::Usize, 115 data: &[u8], 116 ) -> TargetResult<(), Self>; 117 } 118 119 /// Target Extension - [Reverse continue] for single threaded targets. 120 /// 121 /// Reverse continue allows the target to run backwards until it reaches the end 122 /// of the replay log. 123 /// 124 /// [Reverse continue]: https://sourceware.org/gdb/current/onlinedocs/gdb/Reverse-Execution.html 125 pub trait SingleThreadReverseCont: Target + SingleThreadOps { 126 /// Reverse-continue the target. reverse_cont( &mut self, gdb_interrupt: GdbInterrupt<'_>, ) -> Result<StopReason<<Self::Arch as Arch>::Usize>, Self::Error>127 fn reverse_cont( 128 &mut self, 129 gdb_interrupt: GdbInterrupt<'_>, 130 ) -> Result<StopReason<<Self::Arch as Arch>::Usize>, Self::Error>; 131 } 132 133 define_ext!(SingleThreadReverseContOps, SingleThreadReverseCont); 134 135 /// Target Extension - [Reverse stepping] for single threaded targets. 136 /// 137 /// Reverse stepping allows the target to run backwards by one step. 138 /// 139 /// [Reverse stepping]: https://sourceware.org/gdb/current/onlinedocs/gdb/Reverse-Execution.html 140 pub trait SingleThreadReverseStep: Target + SingleThreadOps { 141 /// Reverse-step the target. reverse_step( &mut self, gdb_interrupt: GdbInterrupt<'_>, ) -> Result<StopReason<<Self::Arch as Arch>::Usize>, Self::Error>142 fn reverse_step( 143 &mut self, 144 gdb_interrupt: GdbInterrupt<'_>, 145 ) -> Result<StopReason<<Self::Arch as Arch>::Usize>, Self::Error>; 146 } 147 148 define_ext!(SingleThreadReverseStepOps, SingleThreadReverseStep); 149 150 /// Target Extension - Optimized [range stepping] for single threaded targets. 151 /// See [`SingleThreadOps::support_resume_range_step`]. 152 /// 153 /// Range Stepping will step the target once, and keep stepping the target as 154 /// long as execution remains between the specified start (inclusive) and end 155 /// (exclusive) addresses, or another stop condition is met (e.g: a breakpoint 156 /// it hit). 157 /// 158 /// If the range is empty (`start` == `end`), then the action becomes 159 /// equivalent to the ‘s’ action. In other words, single-step once, and 160 /// report the stop (even if the stepped instruction jumps to start). 161 /// 162 /// _Note:_ A stop reply may be sent at any point even if the PC is still 163 /// within the stepping range; for example, it is valid to implement range 164 /// stepping in a degenerate way as a single instruction step operation. 165 /// 166 /// [range stepping]: https://sourceware.org/gdb/current/onlinedocs/gdb/Continuing-and-Stepping.html#range-stepping 167 pub trait SingleThreadRangeStepping: Target + SingleThreadOps { 168 /// See [`SingleThreadOps::resume`]. resume_range_step( &mut self, start: <Self::Arch as Arch>::Usize, end: <Self::Arch as Arch>::Usize, gdb_interrupt: GdbInterrupt<'_>, ) -> Result<StopReason<<Self::Arch as Arch>::Usize>, Self::Error>169 fn resume_range_step( 170 &mut self, 171 start: <Self::Arch as Arch>::Usize, 172 end: <Self::Arch as Arch>::Usize, 173 gdb_interrupt: GdbInterrupt<'_>, 174 ) -> Result<StopReason<<Self::Arch as Arch>::Usize>, Self::Error>; 175 } 176 177 define_ext!(SingleThreadRangeSteppingOps, SingleThreadRangeStepping); 178 179 /// Describes why the target stopped. 180 /// 181 /// Targets MUST only respond with stop reasons that correspond to IDETs that 182 /// target has implemented. 183 /// 184 /// e.g: A target which has not implemented the [`HwBreakpoint`] IDET must not 185 /// return a `HwBreak` stop reason. While this is not enforced at compile time, 186 /// doing so will result in a runtime `UnsupportedStopReason` error. 187 /// 188 /// [`HwBreakpoint`]: crate::target::ext::breakpoints::HwBreakpoint 189 // NOTE: This is a simplified version of `multithread::ThreadStopReason` that omits any references 190 // to Tid or threads. Internally, it is converted into multithread::ThreadStopReason. 191 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 192 #[non_exhaustive] 193 pub enum StopReason<U> { 194 /// Completed the single-step request. 195 DoneStep, 196 /// `check_gdb_interrupt` returned `true`. 197 GdbInterrupt, 198 /// The process exited with the specified exit status. 199 Exited(u8), 200 /// The process terminated with the specified signal number. 201 Terminated(u8), 202 /// The program received a signal. 203 Signal(u8), 204 /// Hit a software breakpoint (e.g. due to a trap instruction). 205 /// 206 /// Requires: [`SwBreakpoint`]. 207 /// 208 /// NOTE: This does not necessarily have to be a breakpoint configured by 209 /// the client/user of the current GDB session. 210 /// 211 /// [`SwBreakpoint`]: crate::target::ext::breakpoints::SwBreakpoint 212 SwBreak, 213 /// Hit a hardware breakpoint. 214 /// 215 /// Requires: [`HwBreakpoint`]. 216 /// 217 /// [`HwBreakpoint`]: crate::target::ext::breakpoints::HwBreakpoint 218 HwBreak, 219 /// Hit a watchpoint. 220 /// 221 /// Requires: [`HwWatchpoint`]. 222 /// 223 /// [`HwWatchpoint`]: crate::target::ext::breakpoints::HwWatchpoint 224 Watch { 225 /// Kind of watchpoint that was hit 226 kind: WatchKind, 227 /// Address of watched memory 228 addr: U, 229 }, 230 /// The program has reached the end of the logged replay events. 231 /// 232 /// Requires: [`SingleThreadReverseCont`] or [`SingleThreadReverseStep`]. 233 /// 234 /// This is used for GDB's reverse execution. When playing back a recording, 235 /// you may hit the end of the buffer of recorded events, and as such no 236 /// further execution can be done. This stop reason tells GDB that this has 237 /// occurred. 238 ReplayLog(ReplayLogPosition), 239 } 240