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