1 //! Stop reasons reported back to the GDB client. 2 3 use crate::arch::Arch; 4 use crate::common::Signal; 5 use crate::common::Tid; 6 use crate::target::ext::base::reverse_exec::ReplayLogPosition; 7 use crate::target::ext::breakpoints::WatchKind; 8 use crate::target::ext::catch_syscalls::CatchSyscallPosition; 9 use crate::target::Target; 10 11 /// Describes why a thread stopped. 12 /// 13 /// Single threaded targets should set `Tid` to `()`, whereas multi threaded 14 /// targets should set `Tid` to [`Tid`]. To make things easier, it is 15 /// recommended to use the [`SingleThreadStopReason`] and 16 /// [`MultiThreadStopReason`] when possible. 17 /// 18 /// 19 /// 20 /// Targets MUST only respond with stop reasons that correspond to IDETs that 21 /// target has implemented. Not doing so will result in a runtime error. 22 /// 23 /// e.g: A target which has not implemented the [`HwBreakpoint`] IDET must not 24 /// return a `HwBreak` stop reason. While this is not enforced at compile time, 25 /// doing so will result in a runtime `UnsupportedStopReason` error. 26 /// 27 /// [`HwBreakpoint`]: crate::target::ext::breakpoints::HwBreakpoint 28 #[derive(Clone, Copy, Debug, PartialEq, Eq)] 29 #[non_exhaustive] 30 pub enum BaseStopReason<Tid, U> { 31 /// Completed the single-step request. 32 DoneStep, 33 /// The process exited with the specified exit status. 34 Exited(u8), 35 /// The process terminated with the specified signal number. 36 Terminated(Signal), 37 /// The program received a signal. 38 Signal(Signal), 39 /// A specific thread received a signal. 40 SignalWithThread { 41 /// Tid of the associated thread 42 tid: Tid, 43 /// The signal 44 signal: Signal, 45 }, 46 /// A thread hit a software breakpoint (e.g. due to a trap instruction). 47 /// 48 /// Requires: [`SwBreakpoint`]. 49 /// 50 /// NOTE: This does not necessarily have to be a breakpoint configured by 51 /// the client/user of the current GDB session. 52 /// 53 /// [`SwBreakpoint`]: crate::target::ext::breakpoints::SwBreakpoint 54 SwBreak(Tid), 55 /// A thread hit a hardware breakpoint. 56 /// 57 /// Requires: [`HwBreakpoint`]. 58 /// 59 /// [`HwBreakpoint`]: crate::target::ext::breakpoints::HwBreakpoint 60 HwBreak(Tid), 61 /// A thread hit a watchpoint. 62 /// 63 /// Requires: [`HwWatchpoint`]. 64 /// 65 /// [`HwWatchpoint`]: crate::target::ext::breakpoints::HwWatchpoint 66 Watch { 67 /// Tid of the associated thread 68 tid: Tid, 69 /// Kind of watchpoint that was hit 70 kind: WatchKind, 71 /// Address of watched memory 72 addr: U, 73 }, 74 /// The program has reached the end of the logged replay events. 75 /// 76 /// Requires: [`ReverseCont`] or [`ReverseStep`]. 77 /// 78 /// This is used for GDB's reverse execution. When playing back a recording, 79 /// you may hit the end of the buffer of recorded events, and as such no 80 /// further execution can be done. This stop reason tells GDB that this has 81 /// occurred. 82 /// 83 /// [`ReverseCont`]: crate::target::ext::base::reverse_exec::ReverseCont 84 /// [`ReverseStep`]: crate::target::ext::base::reverse_exec::ReverseStep 85 ReplayLog { 86 /// (optional) Tid of the associated thread. 87 tid: Option<Tid>, 88 /// The point reached in a replay log (i.e: beginning vs. end). 89 pos: ReplayLogPosition, 90 }, 91 /// The program has reached a syscall entry or return location. 92 /// 93 /// Requires: [`CatchSyscalls`]. 94 /// 95 /// [`CatchSyscalls`]: crate::target::ext::catch_syscalls::CatchSyscalls 96 CatchSyscall { 97 /// (optional) Tid of the associated thread. 98 tid: Option<Tid>, 99 /// The syscall number. 100 number: U, 101 /// The location the event occurred at. 102 position: CatchSyscallPosition, 103 }, 104 } 105 106 /// A stop reason for a single threaded target. 107 /// 108 /// Threads are identified using the unit type `()` (as there is only a single 109 /// possible thread-id). 110 pub type SingleThreadStopReason<U> = BaseStopReason<(), U>; 111 112 /// A stop reason for a multi threaded target. 113 /// 114 /// Threads are identified using a [`Tid`]. 115 pub type MultiThreadStopReason<U> = BaseStopReason<Tid, U>; 116 117 impl<U> From<BaseStopReason<(), U>> for BaseStopReason<Tid, U> { from(st_stop_reason: BaseStopReason<(), U>) -> BaseStopReason<Tid, U>118 fn from(st_stop_reason: BaseStopReason<(), U>) -> BaseStopReason<Tid, U> { 119 match st_stop_reason { 120 BaseStopReason::DoneStep => BaseStopReason::DoneStep, 121 BaseStopReason::Exited(code) => BaseStopReason::Exited(code), 122 BaseStopReason::Terminated(sig) => BaseStopReason::Terminated(sig), 123 BaseStopReason::SignalWithThread { signal, .. } => BaseStopReason::SignalWithThread { 124 tid: crate::SINGLE_THREAD_TID, 125 signal, 126 }, 127 BaseStopReason::SwBreak(_) => BaseStopReason::SwBreak(crate::SINGLE_THREAD_TID), 128 BaseStopReason::HwBreak(_) => BaseStopReason::HwBreak(crate::SINGLE_THREAD_TID), 129 BaseStopReason::Watch { kind, addr, .. } => BaseStopReason::Watch { 130 tid: crate::SINGLE_THREAD_TID, 131 kind, 132 addr, 133 }, 134 BaseStopReason::Signal(sig) => BaseStopReason::Signal(sig), 135 BaseStopReason::ReplayLog { pos, .. } => BaseStopReason::ReplayLog { tid: None, pos }, 136 BaseStopReason::CatchSyscall { 137 number, position, .. 138 } => BaseStopReason::CatchSyscall { 139 tid: None, 140 number, 141 position, 142 }, 143 } 144 } 145 } 146 147 mod private { 148 pub trait Sealed {} 149 150 impl<U> Sealed for super::SingleThreadStopReason<U> {} 151 impl<U> Sealed for super::MultiThreadStopReason<U> {} 152 } 153 154 /// A marker trait implemented by [`SingleThreadStopReason`] and 155 /// [`MultiThreadStopReason`]. 156 pub trait IntoStopReason<T: Target>: 157 private::Sealed + Into<MultiThreadStopReason<<<T as Target>::Arch as Arch>::Usize>> 158 { 159 } 160 161 impl<T: Target> IntoStopReason<T> for SingleThreadStopReason<<<T as Target>::Arch as Arch>::Usize> {} 162 impl<T: Target> IntoStopReason<T> for MultiThreadStopReason<<<T as Target>::Arch as Arch>::Usize> {} 163