diff --git a/src/stub/core_impl.rs b/src/stub/core_impl.rs index 90cc5f44..6175f4fa 100644 --- a/src/stub/core_impl.rs +++ b/src/stub/core_impl.rs @@ -72,6 +72,8 @@ pub(crate) mod target_result_ext { Err(TargetError::Errno(code)) => code, #[cfg(feature = "std")] Err(TargetError::Io(e)) => e.raw_os_error().unwrap_or(121) as u8, + #[cfg(feature = "std")] + Err(TargetError::FatalCore(e)) => return Err(InternalError::TargetCoreError(e)), }; Err(InternalError::NonFatalError(code)) diff --git a/src/stub/error.rs b/src/stub/error.rs index 5b311dea..5e428913 100644 --- a/src/stub/error.rs +++ b/src/stub/error.rs @@ -28,6 +28,11 @@ pub(crate) enum InternalError { /// Target encountered a fatal error. TargetError(T), + /// Target encountered a fatal error. More information may be available + /// in the source of the error. + #[cfg(feature = "std")] + TargetCoreError(Box), + ClientSentNack, PacketBufferOverflow, PacketParse(PacketParseError), @@ -140,6 +145,8 @@ where PacketUnexpected => write!(f, "Client sent an unexpected packet. This should never happen! Please re-run with `log` trace-level logging enabled and file an issue at https://github.com/daniel5151/gdbstub/issues"), TargetMismatch => write!(f, "Received a packet with too much data for the given target"), TargetError(e) => write!(f, "Target threw a fatal error: {}", e), + #[cfg(feature = "std")] + TargetCoreError(e) => write!(f, "Target threw a fatal error: {}", e), UnsupportedStopReason => write!(f, "{} {}", unsupported_stop_reason!(), CONTEXT), UnexpectedStepPacket => write!(f, "{} {}", unexpected_step_packet!(), CONTEXT), @@ -159,6 +166,16 @@ where C: Debug + Display, T: Debug + Display, { + #[cfg(feature = "std")] + fn source(&self) -> Option<&(dyn CoreError + 'static)> { + let GdbStubError { + kind: InternalError::TargetCoreError(e), + } = self + else { + return None; + }; + e.source() + } } impl GdbStubError { @@ -175,6 +192,15 @@ impl GdbStubError { } } + /// If the error was due to a core error, return the core error trait. + #[cfg(feature = "std")] + pub fn into_core_error(self) -> Option> { + match self.kind { + InternalError::TargetCoreError(e) => Some(e), + _ => None, + } + } + /// Check if the error was due to a connection error. pub fn is_connection_error(&self) -> bool { matches!(self.kind, InternalError::Connection(..)) diff --git a/src/target/mod.rs b/src/target/mod.rs index 3143e878..132c6708 100644 --- a/src/target/mod.rs +++ b/src/target/mod.rs @@ -324,6 +324,13 @@ pub enum TargetError { /// debugging session, and return a /// [`GdbStubError`](crate::stub::GdbStubError)! Fatal(E), + /// A generic fatal error with a core Error implementation. + /// + /// **WARNING:** Returning this error will immediately terminate the GDB + /// debugging session, and return a + /// [`GdbStubError`](crate::stub::GdbStubError)! + #[cfg(feature = "std")] + FatalCore(Box), } /// Converts a `()` into a `TargetError::NonFatal`.