use thiserror::Error;
#[cfg(feature = "emulation")]
use crate::emulation::EmulationError;
use crate::metadata::{tables::TableId, token::Token};
#[cfg(not(feature = "emulation"))]
#[derive(Debug, Clone, PartialEq)]
pub struct EmulationError(String);
#[cfg(not(feature = "emulation"))]
impl std::fmt::Display for EmulationError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Emulation not available: {}", self.0)
}
}
#[macro_export]
macro_rules! malformed_error {
($msg:expr) => {
$crate::Error::Malformed {
message: $msg.to_string(),
file: file!(),
line: line!(),
}
};
($fmt:expr, $($arg:tt)*) => {
$crate::Error::Malformed {
message: format!($fmt, $($arg)*),
file: file!(),
line: line!(),
}
};
}
#[macro_export]
macro_rules! out_of_bounds_error {
() => {
$crate::Error::OutOfBounds {
file: file!(),
line: line!(),
}
};
}
#[derive(Error, Debug)]
pub enum Error {
#[error("Malformed - {file}:{line}: {message}")]
Malformed {
message: String,
file: &'static str,
line: u32,
},
#[error("Out of Bounds - {file}:{line}")]
OutOfBounds {
file: &'static str,
line: u32,
},
#[error("This file type is not supported")]
NotSupported,
#[error("{0}")]
Io(#[from] std::io::Error),
#[error("{0}")]
Other(String),
#[error("{0}")]
Goblin(#[from] goblin::error::Error),
#[error("Failed to find type in TypeSystem - {0}")]
TypeNotFound(Token),
#[error("{0}")]
TypeError(String),
#[error("The parent of the current type is missing")]
TypeMissingParent,
#[error("This type can not be converted to a primitive")]
TypeNotPrimitive,
#[error("The requested type conversion is not possible")]
TypeConversionInvalid,
#[error("Reach the maximum recursion level allowed - {0}")]
RecursionLimit(usize),
#[error("Marshalling error: {0}")]
MarshallingError(String),
#[error("Reached the maximum nesting depth allowed - {0}")]
DepthLimitExceeded(usize),
#[error("{0}")]
GraphError(String),
#[error("SSA error: {0}")]
SsaError(String),
#[error("Codegen error: {0}")]
CodegenFailed(String),
#[error("Cannot modify replaced table")]
CannotModifyReplacedTable,
#[error("Invalid modification: {0}")]
ModificationInvalid(String),
#[error("Invalid RID {rid} for table {table:?}")]
InvalidRid {
table: TableId,
rid: u32,
},
#[error("Cross-reference error: {0}")]
CrossReferenceError(String),
#[error("Heap bounds error: {heap} index {index}")]
HeapBoundsError {
heap: String,
index: u32,
},
#[error("Conflict resolution failed: {0}")]
ConflictResolution(String),
#[error("Validation Stage 1 failed: {message}")]
ValidationStage1Failed {
#[source]
source: Box<Error>,
message: String,
},
#[error("Validation Stage 2 failed with {error_count} errors: {summary}")]
ValidationStage2Failed {
errors: Vec<Error>,
error_count: usize,
summary: String,
},
#[error("Raw validation failed in {validator}: {message}")]
ValidationRawFailed {
validator: String,
message: String,
},
#[error("Owned validation failed in {validator}: {message}")]
ValidationOwnedFailed {
validator: String,
message: String,
},
#[error("Validation engine initialization failed: {message}")]
ValidationEngineInitFailed {
message: String,
},
#[error("Invalid token {token}: {message}")]
InvalidToken {
token: Token,
message: String,
},
#[error("Layout failed: {0}")]
LayoutFailed(String),
#[error("Memory mapping failed: {0}")]
MmapFailed(String),
#[error("Finalization failed: {0}")]
FinalizationFailed(String),
#[error("Invalid instruction mnemonic: {0}")]
InvalidMnemonic(String),
#[error("Wrong operand type for instruction - expected {expected}")]
WrongOperandType {
expected: String,
},
#[error("Unexpected operand provided for instruction that expects none")]
UnexpectedOperand,
#[error("Invalid branch: {0}")]
InvalidBranch(String),
#[error("Undefined label referenced: {0}")]
UndefinedLabel(String),
#[error("Duplicate label definition: {0}")]
DuplicateLabel(String),
#[error("Lock error: {0}")]
LockError(String),
#[error("Configuration error: {0}")]
Configuration(String),
#[error("{0}")]
Emulation(Box<EmulationError>),
#[error("Deobfuscation error: {0}")]
Deobfuscation(String),
#[error("x86 error: {0}")]
X86Error(String),
#[error("Tracing error: {0}")]
TracingError(String),
}
impl Clone for Error {
fn clone(&self) -> Self {
match self {
Error::Io(io_err) => Error::Other(io_err.to_string()),
Error::Goblin(goblin_err) => Error::Other(goblin_err.to_string()),
Error::ValidationStage1Failed { source, message } => Error::ValidationStage1Failed {
source: source.clone(),
message: message.clone(),
},
Error::ValidationRawFailed { validator, message } => Error::ValidationRawFailed {
validator: validator.clone(),
message: message.clone(),
},
Error::ValidationOwnedFailed { validator, message } => Error::ValidationOwnedFailed {
validator: validator.clone(),
message: message.clone(),
},
Error::Emulation(e) => Error::Emulation(e.clone()),
Error::Deobfuscation(s) => Error::Deobfuscation(s.clone()),
Error::X86Error(s) => Error::X86Error(s.clone()),
Error::TracingError(s) => Error::TracingError(s.clone()),
other => Error::Other(other.to_string()),
}
}
}
#[cfg(feature = "emulation")]
impl From<EmulationError> for Error {
fn from(err: EmulationError) -> Self {
Error::Emulation(Box::new(err))
}
}