use crate::{
DebuggeeOffset, WdResult, WideStrArg,
data::{DebugValueType, VarType},
dbgmodel::{DataModelManager, ModelObject},
wd::dbgmodel::WdModelErrorObject,
};
use std::{
fmt,
num::{ParseIntError, TryFromIntError},
};
use thiserror::Error;
use windows::{
Win32::Foundation::{
E_FAIL, E_INVALIDARG, E_NOINTERFACE, E_UNEXPECTED, ERROR_READ_FAULT,
ERROR_TIMEOUT, ERROR_WRITE_FAULT,
},
core::HRESULT,
};
use windy::ConvertError;
pub const E_WRITE_FAULT: HRESULT = HRESULT::from_win32(ERROR_WRITE_FAULT.0);
pub const E_READ_FAULT: HRESULT = HRESULT::from_win32(ERROR_READ_FAULT.0);
pub const E_PENDING: HRESULT = HRESULT(0x8000000a_u32 as i32);
pub const E_INTERRUPTED: HRESULT = HRESULT(0xD000013A_u32 as i32);
#[derive(Error, Debug, Clone, Eq, PartialEq)]
pub enum WdErrorKind {
#[error("debug value coercion from {from:?} to {to:?} failed")]
ValueCoercionFailed {
from: DebugValueType,
to: DebugValueType,
},
#[error("debug value type mismatch: expected {expected:?}, got {actual:?}")]
DebugValueTypeMismatch {
expected: DebugValueType,
actual: DebugValueType,
},
#[error("variant type mismatch: expected {expected:?}, got {actual:?}")]
VariantTypeMismatch { expected: VarType, actual: VarType },
#[error("string conversion failed: {0}")]
Convert(#[from] ConvertError),
#[error("integer parsing failed: {0}")]
ParseInt(#[from] ParseIntError),
#[error("integer casting failed: {0}")]
TryFromInt(#[from] TryFromIntError),
#[error("the operation timed out")]
Timeout,
#[error("interrupted")]
Interrupted,
#[error(
"memory read starting at {address:#x} failed after reading \
{bytes_read} bytes"
)]
ReadMemoryError {
address: DebuggeeOffset,
bytes_read: usize,
},
#[error(
"memory write starting at {address:#x} failed after writing \
{bytes_write} bytes"
)]
WriteMemoryError {
address: DebuggeeOffset,
bytes_write: usize,
},
#[error("invalid flags: {0:#x}")]
InvalidFlags(u32),
#[error("invalid argument")]
InvalidArgument,
#[error("specific ID required")]
SpecificIdRequired,
#[error("the requested interface is not supported")]
InterfaceNotSupported,
#[error("callbacks were not found")]
CallbacksNotFound,
#[error("a cycle was detected in the linked list")]
ListEntryCycleDetected,
#[error("waiting for a debugger event was interrupted")]
EventWaitInterrupted,
#[error("the debugger is not in a state where it can wait for an event")]
EventWaitInvalidState,
#[error("another debugger event wait is already in progress")]
EventWaitAlreadyInProgress,
#[error("access to the target or object was denied")]
AccessDenied,
#[error("failed to evaluate expression {expression:?} as {desired_type:?}")]
Evaluate {
expression: String,
desired_type: DebugValueType,
},
#[error("register not found")]
RegisterNotFound,
#[error("the target or register is not currently accessible")]
RegisterUnavailable,
#[error("breakpoint not found")]
BreakpointNotFound,
#[error("process not found")]
ProcessNotFound,
#[error("thread not found")]
ThreadNotFound,
#[error("system not found")]
SystemNotFound,
#[error("symbol not found")]
SymbolNotFound,
#[error("symbol type not found")]
TypeNotFound,
#[error("symbol field not found")]
FieldNotFound,
#[error("constant not found")]
ConstantNotFound,
#[error("module not found")]
ModuleNotFound,
#[error("an unexpected debugger error occurred")]
Other,
}
impl WdErrorKind {
pub(crate) fn into_error(self) -> WdError { WdError::from_kind(self) }
fn default_hresult(&self) -> HRESULT {
match self {
WdErrorKind::ValueCoercionFailed { .. } => E_INVALIDARG,
WdErrorKind::DebugValueTypeMismatch { .. } => E_INVALIDARG,
WdErrorKind::VariantTypeMismatch { .. } => E_INVALIDARG,
WdErrorKind::Convert(_) => E_INVALIDARG,
WdErrorKind::ParseInt(_) => E_INVALIDARG,
WdErrorKind::TryFromInt(_) => E_INVALIDARG,
WdErrorKind::Timeout => HRESULT::from_win32(ERROR_TIMEOUT.0),
WdErrorKind::Interrupted => E_INTERRUPTED,
WdErrorKind::AccessDenied => E_FAIL,
WdErrorKind::Evaluate { .. } => E_FAIL,
WdErrorKind::RegisterNotFound => E_NOINTERFACE,
WdErrorKind::BreakpointNotFound => E_NOINTERFACE,
WdErrorKind::ProcessNotFound => E_NOINTERFACE,
WdErrorKind::ThreadNotFound => E_NOINTERFACE,
WdErrorKind::SystemNotFound => E_NOINTERFACE,
WdErrorKind::SymbolNotFound => E_NOINTERFACE,
WdErrorKind::TypeNotFound => E_NOINTERFACE,
WdErrorKind::FieldNotFound => E_NOINTERFACE,
WdErrorKind::ConstantNotFound => E_NOINTERFACE,
WdErrorKind::ModuleNotFound => E_NOINTERFACE,
WdErrorKind::ReadMemoryError { .. } => E_READ_FAULT,
WdErrorKind::WriteMemoryError { .. } => E_WRITE_FAULT,
WdErrorKind::InvalidFlags(_) => E_INVALIDARG,
WdErrorKind::InterfaceNotSupported => E_NOINTERFACE,
WdErrorKind::CallbacksNotFound => E_NOINTERFACE,
WdErrorKind::InvalidArgument => E_INVALIDARG,
WdErrorKind::SpecificIdRequired => E_INVALIDARG,
WdErrorKind::ListEntryCycleDetected => E_FAIL,
WdErrorKind::Other => E_UNEXPECTED,
WdErrorKind::EventWaitInterrupted => E_PENDING,
WdErrorKind::EventWaitInvalidState => E_UNEXPECTED,
WdErrorKind::EventWaitAlreadyInProgress => E_FAIL,
WdErrorKind::RegisterUnavailable => E_UNEXPECTED,
}
}
}
#[derive(Error, Debug, Clone, PartialEq, Eq)]
#[error(
"{kind}: {message} ({hresult:?})",
message = hresult.message().trim()
)]
pub struct WdError {
#[source]
kind: WdErrorKind,
hresult: HRESULT,
}
impl WdError {
pub fn kind(&self) -> WdErrorKind { self.kind.clone() }
pub fn hresult(&self) -> HRESULT { self.hresult }
pub fn from_kind(kind: WdErrorKind) -> Self {
let hresult = WdErrorKind::default_hresult(&kind);
Self { kind, hresult }
}
pub fn from_kind_with_hr(kind: WdErrorKind, hresult: HRESULT) -> Self {
if hresult == E_INTERRUPTED {
return Self::from_kind(WdErrorKind::Interrupted);
}
Self { kind, hresult }
}
}
impl From<WdErrorKind> for WdError {
fn from(value: WdErrorKind) -> Self { Self::from_kind(value) }
}
impl From<HRESULT> for WdError {
fn from(e: HRESULT) -> Self {
Self::from_kind_with_hr(WdErrorKind::Other, e)
}
}
impl From<(WdErrorKind, HRESULT)> for WdError {
fn from(value: (WdErrorKind, HRESULT)) -> Self {
Self::from_kind_with_hr(value.0, value.1)
}
}
impl From<windows::core::Error> for WdError {
fn from(e: windows::core::Error) -> Self {
Self::from_kind_with_hr(WdErrorKind::Other, e.code())
}
}
impl From<ConvertError> for WdError {
fn from(e: ConvertError) -> Self {
Self::from_kind(WdErrorKind::Convert(e))
}
}
impl From<ParseIntError> for WdError {
fn from(e: ParseIntError) -> Self {
Self::from_kind(WdErrorKind::ParseInt(e))
}
}
impl From<TryFromIntError> for WdError {
fn from(e: TryFromIntError) -> Self {
Self::from_kind(WdErrorKind::TryFromInt(e))
}
}
impl From<WdError> for HRESULT {
fn from(e: WdError) -> Self { e.hresult }
}
impl From<WdError> for windows::core::Error {
fn from(e: WdError) -> Self { e.hresult.into() }
}
#[derive(Clone, Eq, PartialEq)]
pub struct DbgModelError {
hr: HRESULT,
object: Option<WdModelErrorObject>,
}
impl fmt::Display for DbgModelError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.hr)
}
}
impl DbgModelError {
pub fn new(
hr: impl Into<HRESULT>,
object: Option<impl Into<ModelObject>>,
) -> Self {
match object {
None => Self {
hr: hr.into(),
object: None,
},
Some(object) => Self {
hr: hr.into(),
object: Some(WdModelErrorObject(object.into().into())),
},
}
}
pub fn new2<'a>(
manager: impl AsRef<DataModelManager>,
hr: impl Into<HRESULT>,
message: Option<impl Into<WideStrArg<'a>>>,
) -> WdResult<Self> {
let hr = hr.into();
Ok(match message {
None => Self { hr, object: None },
Some(message) => Self {
hr,
object: Some(WdModelErrorObject::create(manager, hr, message)?),
},
})
}
pub fn as_hresult(&self) -> HRESULT { self.hr }
}
impl From<DbgModelError> for HRESULT {
fn from(e: DbgModelError) -> Self { e.as_hresult() }
}
impl From<DbgModelError> for windows::core::Error {
fn from(e: DbgModelError) -> Self { e.as_hresult().into() }
}
impl From<DbgModelError> for WdError {
fn from(e: DbgModelError) -> Self { e.as_hresult().into() }
}