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