Skip to main content

bugstalker/debugger/
error.rs

1use super::call::CallError;
2use super::call::fmt::FmtCallError;
3use crate::debugger::address::GlobalAddress;
4use crate::debugger::r#async::AsyncError;
5use crate::debugger::debugee::RendezvousError;
6use crate::debugger::debugee::dwarf::unit::DieAddr;
7use crate::debugger::variable::value::ParsingError;
8use gimli::UnitOffset;
9use nix::unistd::Pid;
10use std::str::Utf8Error;
11use std::string::FromUtf8Error;
12
13#[derive(Debug, thiserror::Error)]
14pub enum Error {
15    // --------------------------------- generic errors --------------------------------------------
16    #[error("debugee already run")]
17    AlreadyRun,
18    #[error(transparent)]
19    IO(#[from] std::io::Error),
20    #[error(transparent)]
21    Utf8(#[from] Utf8Error),
22    #[error(transparent)]
23    FromUtf8(#[from] FromUtf8Error),
24    #[error(transparent)]
25    RegEx(#[from] regex::Error),
26
27    // --------------------------------- debugger entity not found----------------------------------
28    #[error("no debug information for {0}")]
29    NoDebugInformation(&'static str),
30    #[error("unknown register {0:?}")]
31    RegisterNotFound(gimli::Register),
32    #[error("unknown register {0:?}")]
33    RegisterNameNotFound(String),
34    #[error("source place not found at address {0}")]
35    PlaceNotFound(GlobalAddress),
36    #[error("there are no suitable places for this request")]
37    NoSuitablePlace,
38    #[error("unit not found at address {0}")]
39    UnitNotFound(GlobalAddress),
40    #[error("function not found at address {0}")]
41    FunctionNotFound(GlobalAddress),
42    #[error("type not found")]
43    TypeNotFound,
44    #[error("frame number {0} not found")]
45    FrameNotFound(u32),
46    #[error("tracee number {0} not found")]
47    TraceeNotFound(u32),
48    #[error("debug information entry (die) not found, reference: {0:?}")]
49    DieNotFound(DieAddr),
50    #[error("section \"{0}\" not found")]
51    SectionNotFound(&'static str),
52
53    // --------------------------------- remote memory errors --------------------------------------
54    #[error("invalid binary representation of type `{0}`: {1:?}")]
55    TypeBinaryRepr(&'static str, Box<[u8]>),
56    #[error("unknown address")]
57    UnknownAddress,
58    #[error("memory region offset not found ({0})")]
59    MappingOffsetNotFound(&'static str),
60    #[error("memory region not found for a file: {0}")]
61    MappingNotFound(String),
62
63    // --------------------------------- syscall errors --------------------------------------------
64    #[error("waitpid syscall error: {0}")]
65    Waitpid(nix::Error),
66    #[error("ptrace syscall error: {0}")]
67    Ptrace(nix::Error),
68    #[error("{0} syscall error: {1}")]
69    Syscall(&'static str, nix::Error),
70    #[error("multiple syscall errors {0:?}")]
71    MultipleErrors(Vec<Self>),
72
73    // --------------------------------- watchpoint errors -----------------------------------------
74    #[error("variable or argument to watch not found")]
75    WatchSubjectNotFound,
76    #[error("there is more than one watchpoint candidate, try to specify the expression")]
77    WatchpointCollision,
78    #[error("there is no memory address for watchpoint")]
79    WatchpointNoAddress,
80    #[error("size of watch object is undefined")]
81    WatchpointUndefinedSize,
82    #[error(
83        "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"
84    )]
85    WatchpointWrongSize,
86    #[error("watchpoint limit is reached (maximum 4 watchpoints), try to remove unused")]
87    WatchpointLimitReached,
88    #[error("memory location observed by another watchpoint")]
89    AddressAlreadyObserved,
90    #[error("unknown expression scope")]
91    UnknownScope,
92    #[error("variable frame is unavailable")]
93    VarFrameNotFound,
94
95    // --------------------------------- parsing errors --------------------------------------------
96    #[error("dwarf file parsing error: {0}")]
97    DwarfParsing(#[from] gimli::Error),
98    #[error("invalid debug-id note format")]
99    DebugIDFormat,
100    #[error("object file parsing error: {0}")]
101    ObjParsing(#[from] object::Error),
102    #[error(transparent)]
103    VariableParsing(#[from] ParsingError),
104    #[error("function specification ({0:?}) reference to unseen declaration")]
105    InvalidSpecification(UnitOffset),
106
107    // --------------------------------- unwind errors ---------------------------------------------
108    #[error("unwind: no unwind context")]
109    UnwindNoContext,
110    #[error("unwind: too deep frame number")]
111    UnwindTooDeepFrame,
112
113    // --------------------------------- dwarf errors ----------------------------------------------
114    #[error("dwarf expression evaluation: eval option `{0}` required")]
115    EvalOptionRequired(&'static str),
116    #[error("dwarf expression evaluation: unsupported evaluation require ({0})")]
117    EvalUnsupportedRequire(&'static str),
118    #[error("no frame base address")]
119    NoFBA,
120    #[error("frame base address attribute not an expression")]
121    FBANotAnExpression,
122    #[error("range information for function `{0:?}` not exists")]
123    NoFunctionRanges(Option<String>),
124    #[error("die type not exists")]
125    NoDieType,
126    #[error("fail to read/evaluate implicit pointer address")]
127    ImplicitPointer,
128
129    // --------------------------------- libthread_db errors ---------------------------------------
130    #[error("libthread_db not enabled")]
131    NoThreadDB,
132    #[error("libthread_db: {0}")]
133    ThreadDB(#[from] thread_db::ThreadDbError),
134
135    // --------------------------------- linker errors ---------------------------------------------
136    #[error(transparent)]
137    Rendezvous(#[from] RendezvousError),
138
139    // --------------------------------- debugee process errors ------------------------------------
140    #[error("debugee process exit with code {0}")]
141    ProcessExit(i32),
142    #[error("program is not being started")]
143    ProcessNotStarted,
144
145    // --------------------------------- rust toolchain errors -------------------------------------
146    #[error("default toolchain not found")]
147    DefaultToolchainNotFound,
148    #[error("unrecognized rustup output")]
149    UnrecognizedRustupOut,
150
151    // --------------------------------- disasm ----------------------------------------------------
152    #[error("install disassembler: {0}")]
153    DisAsmInit(capstone::Error),
154    #[error("instructions disassembly error: {0}")]
155    DisAsm(capstone::Error),
156    #[error("error to determine current function start/end place")]
157    FunctionRangeNotFound,
158
159    // --------------------------------- third party errors ----------------------------------------
160    #[error("hook: {0}")]
161    Hook(anyhow::Error),
162
163    // --------------------------------- attach debugee errors -------------------------------------
164    #[error("process pid {0} not found")]
165    AttachedProcessNotFound(Pid),
166    #[error("attach a running process: {0}")]
167    Attach(nix::Error),
168
169    // --------------------------------- async exploration errors ----------------------------------
170    #[error("{0}. Maybe your async runtime version is unsupported.")]
171    Async(#[from] AsyncError),
172
173    // --------------------------------- function call errors -------------------------------------
174    #[error(transparent)]
175    Call(#[from] CallError),
176    #[error(transparent)]
177    FmtCall(#[from] FmtCallError),
178}
179
180impl Error {
181    /// Return a hint to an interface - continue debugging after error or stop whole process.
182    pub fn is_fatal(&self) -> bool {
183        match self {
184            Error::AlreadyRun => false,
185            Error::IO(_) => false,
186            Error::Utf8(_) => false,
187            Error::FromUtf8(_) => false,
188            Error::RegEx(_) => false,
189            Error::NoDebugInformation(_) => false,
190            Error::RegisterNotFound(_) => false,
191            Error::RegisterNameNotFound(_) => false,
192            Error::PlaceNotFound(_) => false,
193            Error::NoSuitablePlace => false,
194            Error::UnitNotFound(_) => false,
195            Error::FunctionNotFound(_) => false,
196            Error::TypeNotFound => false,
197            Error::FrameNotFound(_) => false,
198            Error::TraceeNotFound(_) => false,
199            Error::DieNotFound(_) => false,
200            Error::TypeBinaryRepr(_, _) => false,
201            Error::UnknownAddress => false,
202            Error::MappingOffsetNotFound(_) => false,
203            Error::MappingNotFound(_) => false,
204            Error::Waitpid(_) => false,
205            Error::Ptrace(_) => false,
206            Error::MultipleErrors(_) => false,
207            Error::DebugIDFormat => false,
208            Error::VariableParsing(_) => false,
209            Error::UnwindNoContext => false,
210            Error::UnwindTooDeepFrame => false,
211            Error::EvalOptionRequired(_) => false,
212            Error::EvalUnsupportedRequire(_) => false,
213            Error::NoFBA => false,
214            Error::FBANotAnExpression => false,
215            Error::NoFunctionRanges(_) => false,
216            Error::NoDieType => false,
217            Error::ImplicitPointer => false,
218            Error::ThreadDB(_) => false,
219            Error::Rendezvous(_) => false,
220            Error::ProcessExit(_) => false,
221            Error::ProcessNotStarted => false,
222            Error::DefaultToolchainNotFound => false,
223            Error::UnrecognizedRustupOut => false,
224            Error::Hook(_) => false,
225            Error::SectionNotFound(_) => false,
226            Error::DisAsm(_) => false,
227            Error::InvalidSpecification(_) => false,
228            Error::FunctionRangeNotFound => false,
229            Error::WatchpointCollision => false,
230            Error::WatchpointNoAddress => false,
231            Error::WatchpointUndefinedSize => false,
232            Error::WatchpointWrongSize => false,
233            Error::WatchpointLimitReached => false,
234            Error::WatchSubjectNotFound => false,
235            Error::AddressAlreadyObserved => false,
236            Error::UnknownScope => false,
237            Error::VarFrameNotFound => false,
238            Error::Async(_) => false,
239            Error::Call(_) => false,
240            Error::FmtCall(_) => false,
241
242            // currently fatal errors
243            Error::DwarfParsing(_) => true,
244            Error::ObjParsing(_) => true,
245            Error::Syscall(_, _) => true,
246            Error::NoThreadDB => true,
247            Error::DisAsmInit(_) => true,
248            Error::AttachedProcessNotFound(_) => true,
249            Error::Attach(_) => true,
250        }
251    }
252}
253
254#[macro_export]
255macro_rules! _error {
256    ($log_fn: path, $res: expr) => {
257        match $res {
258            Ok(value) => Some(value),
259            Err(e) => {
260                $log_fn!(target: "debugger", "{:#}", e);
261                None
262            }
263        }
264    };
265    ($log_fn: path, $res: expr, $msg: tt) => {
266        match $res {
267            Ok(value) => Some(value),
268            Err(e) => {
269                $log_fn!(target: "debugger", concat!($msg, " {:#}"), e);
270                None
271            }
272        }
273    };
274}
275
276/// Transforms `Result` into `Option` and logs an error if it occurs.
277#[macro_export]
278macro_rules! weak_error {
279    ($res: expr) => {
280        $crate::_error!(log::warn, $res)
281    };
282    ($res: expr, $msg: tt) => {
283        $crate::_error!(log::warn, $res, $msg)
284    };
285}
286
287/// Transforms `Result` into `Option` and put error into debug logs if it occurs.
288#[macro_export]
289macro_rules! muted_error {
290    ($res: expr) => {
291        $crate::_error!(log::debug, $res)
292    };
293    ($res: expr, $msg: tt) => {
294        $crate::_error!(log::debug, $res, $msg)
295    };
296}
297
298/// Macro for handle an error lists as warnings.
299#[macro_export]
300macro_rules! print_warns {
301    ($errors:expr) => {
302        $errors.iter().for_each(|e| {
303            log::warn!(target: "debugger", "{:#}", e);
304        })
305    };
306}