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