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