1 //! Add/Remove various kinds of breakpoints.
2 
3 use crate::arch::Arch;
4 use crate::target::Target;
5 use crate::target::TargetResult;
6 
7 /// Target Extension - Set/Remove Breakpoints.
8 pub trait Breakpoints: Target {
9     /// Support for setting / removing software breakpoints.
10     #[inline(always)]
support_sw_breakpoint(&mut self) -> Option<SwBreakpointOps<'_, Self>>11     fn support_sw_breakpoint(&mut self) -> Option<SwBreakpointOps<'_, Self>> {
12         None
13     }
14 
15     /// Support for setting / removing hardware breakpoints.
16     #[inline(always)]
support_hw_breakpoint(&mut self) -> Option<HwBreakpointOps<'_, Self>>17     fn support_hw_breakpoint(&mut self) -> Option<HwBreakpointOps<'_, Self>> {
18         None
19     }
20 
21     /// Support for setting / removing hardware watchpoints.
22     #[inline(always)]
support_hw_watchpoint(&mut self) -> Option<HwWatchpointOps<'_, Self>>23     fn support_hw_watchpoint(&mut self) -> Option<HwWatchpointOps<'_, Self>> {
24         None
25     }
26 }
27 
28 define_ext!(BreakpointsOps, Breakpoints);
29 
30 /// Nested Target Extension - Set/Remove Software Breakpoints.
31 ///
32 /// See [this stackoverflow discussion](https://stackoverflow.com/questions/8878716/what-is-the-difference-between-hardware-and-software-breakpoints)
33 /// about the differences between hardware and software breakpoints.
34 ///
35 /// _Recommendation:_ If you're implementing `Target` for an emulator that's
36 /// using an _interpreted_ CPU (as opposed to a JIT), the simplest way to
37 /// implement "software" breakpoints would be to check the `PC` value after each
38 /// CPU cycle, ignoring the specified breakpoint `kind` entirely.
39 pub trait SwBreakpoint: Target + Breakpoints {
40     /// Add a new software breakpoint.
41     ///
42     /// Return `Ok(false)` if the operation could not be completed.
add_sw_breakpoint( &mut self, addr: <Self::Arch as Arch>::Usize, kind: <Self::Arch as Arch>::BreakpointKind, ) -> TargetResult<bool, Self>43     fn add_sw_breakpoint(
44         &mut self,
45         addr: <Self::Arch as Arch>::Usize,
46         kind: <Self::Arch as Arch>::BreakpointKind,
47     ) -> TargetResult<bool, Self>;
48 
49     /// Remove an existing software breakpoint.
50     ///
51     /// Return `Ok(false)` if the operation could not be completed.
remove_sw_breakpoint( &mut self, addr: <Self::Arch as Arch>::Usize, kind: <Self::Arch as Arch>::BreakpointKind, ) -> TargetResult<bool, Self>52     fn remove_sw_breakpoint(
53         &mut self,
54         addr: <Self::Arch as Arch>::Usize,
55         kind: <Self::Arch as Arch>::BreakpointKind,
56     ) -> TargetResult<bool, Self>;
57 }
58 
59 define_ext!(SwBreakpointOps, SwBreakpoint);
60 
61 /// Nested Target Extension - Set/Remove Hardware Breakpoints.
62 ///
63 /// See [this stackoverflow discussion](https://stackoverflow.com/questions/8878716/what-is-the-difference-between-hardware-and-software-breakpoints)
64 /// about the differences between hardware and software breakpoints.
65 ///
66 /// _Recommendation:_ If you're implementing `Target` for an emulator that's
67 /// using an _interpreted_ CPU (as opposed to a JIT), there shouldn't be any
68 /// reason to implement this extension (as software breakpoints are likely to be
69 /// just-as-fast).
70 pub trait HwBreakpoint: Target + Breakpoints {
71     /// Add a new hardware breakpoint.
72     ///
73     /// Return `Ok(false)` if the operation could not be completed.
add_hw_breakpoint( &mut self, addr: <Self::Arch as Arch>::Usize, kind: <Self::Arch as Arch>::BreakpointKind, ) -> TargetResult<bool, Self>74     fn add_hw_breakpoint(
75         &mut self,
76         addr: <Self::Arch as Arch>::Usize,
77         kind: <Self::Arch as Arch>::BreakpointKind,
78     ) -> TargetResult<bool, Self>;
79 
80     /// Remove an existing hardware breakpoint.
81     ///
82     /// Return `Ok(false)` if the operation could not be completed.
remove_hw_breakpoint( &mut self, addr: <Self::Arch as Arch>::Usize, kind: <Self::Arch as Arch>::BreakpointKind, ) -> TargetResult<bool, Self>83     fn remove_hw_breakpoint(
84         &mut self,
85         addr: <Self::Arch as Arch>::Usize,
86         kind: <Self::Arch as Arch>::BreakpointKind,
87     ) -> TargetResult<bool, Self>;
88 }
89 
90 define_ext!(HwBreakpointOps, HwBreakpoint);
91 
92 /// The kind of watchpoint that should be set/removed.
93 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
94 pub enum WatchKind {
95     /// Fire when the memory location is written to.
96     Write,
97     /// Fire when the memory location is read from.
98     Read,
99     /// Fire when the memory location is written to and/or read from.
100     ReadWrite,
101 }
102 
103 /// Nested Target Extension - Set/Remove Hardware Watchpoints.
104 ///
105 /// See the [GDB documentation](https://sourceware.org/gdb/current/onlinedocs/gdb/Set-Watchpoints.html)
106 /// regarding watchpoints for how they're supposed to work.
107 ///
108 /// _Note:_ If this extension isn't implemented, GDB will default to using
109 /// _software watchpoints_, which tend to be excruciatingly slow (as hey are
110 /// implemented by single-stepping the system, and reading the watched memory
111 /// location after each step).
112 pub trait HwWatchpoint: Target + Breakpoints {
113     /// Add a new hardware watchpoint.
114     /// The number of bytes to watch is specified by `len`.
115     ///
116     /// Return `Ok(false)` if the operation could not be completed.
add_hw_watchpoint( &mut self, addr: <Self::Arch as Arch>::Usize, len: <Self::Arch as Arch>::Usize, kind: WatchKind, ) -> TargetResult<bool, Self>117     fn add_hw_watchpoint(
118         &mut self,
119         addr: <Self::Arch as Arch>::Usize,
120         len: <Self::Arch as Arch>::Usize,
121         kind: WatchKind,
122     ) -> TargetResult<bool, Self>;
123 
124     /// Remove an existing hardware watchpoint.
125     /// The number of bytes to watch is specified by `len`.
126     ///
127     /// Return `Ok(false)` if the operation could not be completed.
remove_hw_watchpoint( &mut self, addr: <Self::Arch as Arch>::Usize, len: <Self::Arch as Arch>::Usize, kind: WatchKind, ) -> TargetResult<bool, Self>128     fn remove_hw_watchpoint(
129         &mut self,
130         addr: <Self::Arch as Arch>::Usize,
131         len: <Self::Arch as Arch>::Usize,
132         kind: WatchKind,
133     ) -> TargetResult<bool, Self>;
134 }
135 
136 define_ext!(HwWatchpointOps, HwWatchpoint);
137