use super::call::CallError;
use super::call::fmt::FmtCallError;
use crate::debugger::address::GlobalAddress;
use crate::debugger::r#async::AsyncError;
use crate::debugger::debugee::RendezvousError;
use crate::debugger::debugee::dwarf::unit::DieAddr;
use crate::debugger::variable::value::ParsingError;
use gimli::UnitOffset;
use nix::unistd::Pid;
use std::str::Utf8Error;
use std::string::FromUtf8Error;
#[derive(Debug, thiserror::Error)]
pub enum Error {
#[error("debugee already run")]
AlreadyRun,
#[error(transparent)]
IO(#[from] std::io::Error),
#[error(transparent)]
Utf8(#[from] Utf8Error),
#[error(transparent)]
FromUtf8(#[from] FromUtf8Error),
#[error(transparent)]
RegEx(#[from] regex::Error),
#[error("no debug information for {0}")]
NoDebugInformation(&'static str),
#[error("unknown register {0:?}")]
RegisterNotFound(gimli::Register),
#[error("unknown register {0:?}")]
RegisterNameNotFound(String),
#[error("source place not found at address {0}")]
PlaceNotFound(GlobalAddress),
#[error("there are no suitable places for this request")]
NoSuitablePlace,
#[error("unit not found at address {0}")]
UnitNotFound(GlobalAddress),
#[error("function not found at address {0}")]
FunctionNotFound(GlobalAddress),
#[error("type not found")]
TypeNotFound,
#[error("frame number {0} not found")]
FrameNotFound(u32),
#[error("tracee number {0} not found")]
TraceeNotFound(u32),
#[error("debug information entry (die) not found, reference: {0:?}")]
DieNotFound(DieAddr),
#[error("section \"{0}\" not found")]
SectionNotFound(&'static str),
#[error("invalid binary representation of type `{0}`: {1:?}")]
TypeBinaryRepr(&'static str, Box<[u8]>),
#[error("unknown address")]
UnknownAddress,
#[error("memory region offset not found ({0})")]
MappingOffsetNotFound(&'static str),
#[error("memory region not found for a file: {0}")]
MappingNotFound(String),
#[error("waitpid syscall error: {0}")]
Waitpid(nix::Error),
#[error("ptrace syscall error: {0}")]
Ptrace(nix::Error),
#[error("{0} syscall error: {1}")]
Syscall(&'static str, nix::Error),
#[error("multiple syscall errors {0:?}")]
MultipleErrors(Vec<Self>),
#[error("variable or argument to watch not found")]
WatchSubjectNotFound,
#[error("there is more than one watchpoint candidate, try to specify the expression")]
WatchpointCollision,
#[error("there is no memory address for watchpoint")]
WatchpointNoAddress,
#[error("size of watch object is undefined")]
WatchpointUndefinedSize,
#[error(
"the size of the watch object does not fit into one of the size class (1, 2, 4, 8 bytes), try to specify a field to observe"
)]
WatchpointWrongSize,
#[error("watchpoint limit is reached (maximum 4 watchpoints), try to remove unused")]
WatchpointLimitReached,
#[error("memory location observed by another watchpoint")]
AddressAlreadyObserved,
#[error("unknown expression scope")]
UnknownScope,
#[error("variable frame is unavailable")]
VarFrameNotFound,
#[error("dwarf file parsing error: {0}")]
DwarfParsing(#[from] gimli::Error),
#[error("invalid debug-id note format")]
DebugIDFormat,
#[error("object file parsing error: {0}")]
ObjParsing(#[from] object::Error),
#[error(transparent)]
VariableParsing(#[from] ParsingError),
#[error("function specification ({0:?}) reference to unseen declaration")]
InvalidSpecification(UnitOffset),
#[error("unwind: no unwind context")]
UnwindNoContext,
#[error("unwind: too deep frame number")]
UnwindTooDeepFrame,
#[error("dwarf expression evaluation: eval option `{0}` required")]
EvalOptionRequired(&'static str),
#[error("dwarf expression evaluation: unsupported evaluation require ({0})")]
EvalUnsupportedRequire(&'static str),
#[error("no frame base address")]
NoFBA,
#[error("frame base address attribute not an expression")]
FBANotAnExpression,
#[error("range information for function `{0:?}` not exists")]
NoFunctionRanges(Option<String>),
#[error("die type not exists")]
NoDieType,
#[error("fail to read/evaluate implicit pointer address")]
ImplicitPointer,
#[error("libthread_db not enabled")]
NoThreadDB,
#[error("libthread_db: {0}")]
ThreadDB(#[from] thread_db::ThreadDbError),
#[error(transparent)]
Rendezvous(#[from] RendezvousError),
#[error("debugee process exit with code {0}")]
ProcessExit(i32),
#[error("program is not being started")]
ProcessNotStarted,
#[error("default toolchain not found")]
DefaultToolchainNotFound,
#[error("unrecognized rustup output")]
UnrecognizedRustupOut,
#[error("install disassembler: {0}")]
DisAsmInit(capstone::Error),
#[error("instructions disassembly error: {0}")]
DisAsm(capstone::Error),
#[error("error to determine current function start/end place")]
FunctionRangeNotFound,
#[error("hook: {0}")]
Hook(anyhow::Error),
#[error("process pid {0} not found")]
AttachedProcessNotFound(Pid),
#[error("attach a running process: {0}")]
Attach(nix::Error),
#[error("{0}. Maybe your async runtime version is unsupported.")]
Async(#[from] AsyncError),
#[error(transparent)]
Call(#[from] CallError),
#[error(transparent)]
FmtCall(#[from] FmtCallError),
}
impl Error {
pub fn is_fatal(&self) -> bool {
match self {
Error::AlreadyRun => false,
Error::IO(_) => false,
Error::Utf8(_) => false,
Error::FromUtf8(_) => false,
Error::RegEx(_) => false,
Error::NoDebugInformation(_) => false,
Error::RegisterNotFound(_) => false,
Error::RegisterNameNotFound(_) => false,
Error::PlaceNotFound(_) => false,
Error::NoSuitablePlace => false,
Error::UnitNotFound(_) => false,
Error::FunctionNotFound(_) => false,
Error::TypeNotFound => false,
Error::FrameNotFound(_) => false,
Error::TraceeNotFound(_) => false,
Error::DieNotFound(_) => false,
Error::TypeBinaryRepr(_, _) => false,
Error::UnknownAddress => false,
Error::MappingOffsetNotFound(_) => false,
Error::MappingNotFound(_) => false,
Error::Waitpid(_) => false,
Error::Ptrace(_) => false,
Error::MultipleErrors(_) => false,
Error::DebugIDFormat => false,
Error::VariableParsing(_) => false,
Error::UnwindNoContext => false,
Error::UnwindTooDeepFrame => false,
Error::EvalOptionRequired(_) => false,
Error::EvalUnsupportedRequire(_) => false,
Error::NoFBA => false,
Error::FBANotAnExpression => false,
Error::NoFunctionRanges(_) => false,
Error::NoDieType => false,
Error::ImplicitPointer => false,
Error::ThreadDB(_) => false,
Error::Rendezvous(_) => false,
Error::ProcessExit(_) => false,
Error::ProcessNotStarted => false,
Error::DefaultToolchainNotFound => false,
Error::UnrecognizedRustupOut => false,
Error::Hook(_) => false,
Error::SectionNotFound(_) => false,
Error::DisAsm(_) => false,
Error::InvalidSpecification(_) => false,
Error::FunctionRangeNotFound => false,
Error::WatchpointCollision => false,
Error::WatchpointNoAddress => false,
Error::WatchpointUndefinedSize => false,
Error::WatchpointWrongSize => false,
Error::WatchpointLimitReached => false,
Error::WatchSubjectNotFound => false,
Error::AddressAlreadyObserved => false,
Error::UnknownScope => false,
Error::VarFrameNotFound => false,
Error::Async(_) => false,
Error::Call(_) => false,
Error::FmtCall(_) => false,
Error::DwarfParsing(_) => true,
Error::ObjParsing(_) => true,
Error::Syscall(_, _) => true,
Error::NoThreadDB => true,
Error::DisAsmInit(_) => true,
Error::AttachedProcessNotFound(_) => true,
Error::Attach(_) => true,
}
}
}
#[macro_export]
macro_rules! _error {
($log_fn: path, $res: expr) => {
match $res {
Ok(value) => Some(value),
Err(e) => {
$log_fn!(target: "debugger", "{:#}", e);
None
}
}
};
($log_fn: path, $res: expr, $msg: tt) => {
match $res {
Ok(value) => Some(value),
Err(e) => {
$log_fn!(target: "debugger", concat!($msg, " {:#}"), e);
None
}
}
};
}
#[macro_export]
macro_rules! weak_error {
($res: expr) => {
$crate::_error!(log::warn, $res)
};
($res: expr, $msg: tt) => {
$crate::_error!(log::warn, $res, $msg)
};
}
#[macro_export]
macro_rules! muted_error {
($res: expr) => {
$crate::_error!(log::debug, $res)
};
($res: expr, $msg: tt) => {
$crate::_error!(log::debug, $res, $msg)
};
}
#[macro_export]
macro_rules! print_warns {
($errors:expr) => {
$errors.iter().for_each(|e| {
log::warn!(target: "debugger", "{:#}", e);
})
};
}