//! 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 { /// 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, /// 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, /// 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 = BaseStopReason<(), U>; /// A stop reason for a multi threaded target. /// /// Threads are identified using a [`Tid`]. pub type MultiThreadStopReason = BaseStopReason; impl From> for BaseStopReason { fn from(st_stop_reason: BaseStopReason<(), U>) -> BaseStopReason { 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 Sealed for super::SingleThreadStopReason {} impl Sealed for super::MultiThreadStopReason {} } /// A marker trait implemented by [`SingleThreadStopReason`] and /// [`MultiThreadStopReason`]. pub trait IntoStopReason: private::Sealed + Into::Arch as Arch>::Usize>> { } impl IntoStopReason for SingleThreadStopReason<<::Arch as Arch>::Usize> {} impl IntoStopReason for MultiThreadStopReason<<::Arch as Arch>::Usize> {}