memflow/
error.rs

1/*!
2Specialized `Error` and `Result` types for memflow.
3*/
4
5use std::num::NonZeroI32;
6use std::prelude::v1::*;
7use std::{fmt, result, str};
8
9use log::{debug, error, info, trace, warn};
10
11use crate::cglue::IntError;
12
13#[cfg(feature = "std")]
14use std::error;
15
16#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
17pub struct Error(pub ErrorOrigin, pub ErrorKind);
18
19impl Error {
20    /// Returns a static string representing the type of error.
21    pub fn as_str(&self) -> &'static str {
22        self.1.to_str()
23    }
24
25    /// Returns a static string representing the type of error.
26    pub fn into_str(self) -> &'static str {
27        self.as_str()
28    }
29
30    pub fn log_error(self, err: impl std::fmt::Display) -> Self {
31        error!("{}: {} ({})", self.0.to_str(), self.1.to_str(), err);
32        self
33    }
34
35    pub fn log_warn(self, err: impl std::fmt::Display) -> Self {
36        warn!("{}: {} ({})", self.0.to_str(), self.1.to_str(), err);
37        self
38    }
39
40    pub fn log_info(self, err: impl std::fmt::Display) -> Self {
41        info!("{}: {} ({})", self.0.to_str(), self.1.to_str(), err);
42        self
43    }
44
45    pub fn log_debug(self, err: impl std::fmt::Display) -> Self {
46        debug!("{}: {} ({})", self.0.to_str(), self.1.to_str(), err);
47        self
48    }
49
50    pub fn log_trace(self, err: impl std::fmt::Display) -> Self {
51        trace!("{}: {} ({})", self.0.to_str(), self.1.to_str(), err);
52        self
53    }
54}
55
56impl IntError for Error {
57    fn into_int_err(self) -> NonZeroI32 {
58        let origin = ((self.0 as i32 + 1) & 0xFFFi32) << 4;
59        let kind = ((self.1 as i32 + 1) & 0xFFFi32) << 16;
60        NonZeroI32::new(-(1 + origin + kind)).unwrap()
61    }
62
63    fn from_int_err(err: NonZeroI32) -> Self {
64        let origin = ((-err.get() - 1) >> 4i32) & 0xFFFi32;
65        let kind = ((-err.get() - 1) >> 16i32) & 0xFFFi32;
66
67        let error_origin = if origin > 0 && origin <= ErrorOrigin::Other as i32 + 1 {
68            unsafe { std::mem::transmute::<u16, ErrorOrigin>(origin as u16 - 1) }
69        } else {
70            ErrorOrigin::Other
71        };
72
73        let error_kind = if kind > 0 && kind <= ErrorKind::Unknown as i32 + 1 {
74            unsafe { std::mem::transmute::<u16, ErrorKind>(kind as u16 - 1) }
75        } else {
76            ErrorKind::Unknown
77        };
78
79        Self(error_origin, error_kind)
80    }
81}
82
83impl fmt::Display for Error {
84    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
85        write!(f, "{}: {}", self.0.to_str(), self.1.to_str())
86    }
87}
88
89#[cfg(feature = "std")]
90impl error::Error for Error {
91    fn description(&self) -> &str {
92        self.as_str()
93    }
94}
95
96/// Convert from PartialError
97impl<T> From<PartialError<T>> for Error {
98    fn from(err: PartialError<T>) -> Self {
99        match err {
100            PartialError::Error(e) => e,
101            _ => Error(ErrorOrigin::Memory, ErrorKind::PartialData),
102        }
103    }
104}
105
106impl From<ErrorOrigin> for Error {
107    fn from(origin: ErrorOrigin) -> Self {
108        Error(origin, ErrorKind::Unknown)
109    }
110}
111
112impl From<ErrorKind> for Error {
113    fn from(kind: ErrorKind) -> Self {
114        Error(ErrorOrigin::Other, kind)
115    }
116}
117
118#[repr(u16)]
119#[non_exhaustive]
120#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
121pub enum ErrorOrigin {
122    Pointer,
123
124    Args,
125    ArgsValidator,
126
127    Memory,
128    Mmu,
129    MemoryMap,
130
131    PhysicalMemory,
132    VirtualTranslate,
133    Cache,
134    TlbCache,
135    PageCache,
136    VirtualMemory,
137
138    Inventory,
139    Connector,
140    OsLayer,
141    Ffi,
142
143    Other,
144}
145
146impl ErrorOrigin {
147    /// Returns a static string representing the type of error.
148    pub fn to_str(self) -> &'static str {
149        match self {
150            ErrorOrigin::Pointer => "pointer",
151
152            ErrorOrigin::Args => "args",
153            ErrorOrigin::ArgsValidator => "args validator",
154
155            ErrorOrigin::Memory => "memory",
156            ErrorOrigin::Mmu => "mmu",
157            ErrorOrigin::MemoryMap => "memory map",
158
159            ErrorOrigin::PhysicalMemory => "physical memory",
160            ErrorOrigin::VirtualTranslate => "virtual translate",
161            ErrorOrigin::Cache => "cache",
162            ErrorOrigin::TlbCache => "tlb cache",
163            ErrorOrigin::PageCache => "page cache",
164            ErrorOrigin::VirtualMemory => "virtual memory",
165
166            ErrorOrigin::Inventory => "inventory",
167            ErrorOrigin::Connector => "connector",
168            ErrorOrigin::OsLayer => "oslayer",
169            ErrorOrigin::Ffi => "ffi",
170
171            ErrorOrigin::Other => "other",
172        }
173    }
174}
175
176#[repr(u16)]
177#[non_exhaustive]
178#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
179pub enum ErrorKind {
180    Uninitialized,
181    NotSupported,
182    NotImplemented,
183    Configuration,
184    Offset,
185    Http,
186
187    ArgNotExists,
188    ArgValidation,
189    RequiredArgNotFound,
190
191    InvalidArgument,
192
193    PartialData,
194
195    NotFound,
196    OutOfBounds,
197    OutOfMemoryRange,
198    Encoding,
199
200    InvalidPath,
201    ReadOnly,
202    UnableToReadDir,
203    UnableToReadDirEntry,
204    UnableToReadFile,
205    UnableToCreateDirectory,
206    UnableToWriteFile,
207    UnableToSeekFile,
208
209    UnableToMapFile,
210    MemoryMapOutOfRange,
211    UnableToReadMemory,
212
213    InvalidArchitecture,
214    InvalidMemorySize,
215    InvalidMemorySizeUnit,
216
217    UnableToLoadLibrary,
218    InvalidExeFile,
219    MemflowExportsNotFound,
220    VersionMismatch,
221    AlreadyExists,
222    PluginNotFound,
223    TargetNotFound,
224    InvalidAbi,
225    UnsupportedOptionalFeature,
226
227    ProcessNotFound,
228    InvalidProcessInfo,
229    ModuleNotFound,
230    ExportNotFound,
231    ImportNotFound,
232    SectionNotFound,
233
234    Unknown,
235}
236
237impl ErrorKind {
238    /// Returns a static string representing the type of error.
239    pub fn to_str(self) -> &'static str {
240        match self {
241            ErrorKind::Uninitialized => "unitialized",
242            ErrorKind::NotSupported => "not supported",
243            ErrorKind::NotImplemented => "not implemented",
244            ErrorKind::Configuration => "configuration error",
245            ErrorKind::Offset => "offset error",
246            ErrorKind::Http => "http error",
247
248            ErrorKind::ArgNotExists => "the given argument does not exist",
249            ErrorKind::ArgValidation => "the argument could not be validated",
250            ErrorKind::RequiredArgNotFound => "required argument is not set",
251
252            ErrorKind::InvalidArgument => "invalid argument passed",
253
254            ErrorKind::PartialData => "partial data",
255
256            ErrorKind::NotFound => "not found",
257            ErrorKind::OutOfBounds => "out of bounds",
258            ErrorKind::OutOfMemoryRange => "out of memory range",
259            ErrorKind::Encoding => "encoding error",
260
261            ErrorKind::InvalidPath => "invalid path",
262            ErrorKind::ReadOnly => "trying to write to a read only resource",
263            ErrorKind::UnableToReadDir => "unable to read directory",
264            ErrorKind::UnableToReadDirEntry => "unable to read directory entry",
265            ErrorKind::UnableToReadFile => "unable to read file",
266            ErrorKind::UnableToCreateDirectory => "unable to create directory",
267            ErrorKind::UnableToWriteFile => "unable to write file",
268            ErrorKind::UnableToSeekFile => "unable to seek file",
269
270            ErrorKind::UnableToMapFile => "unable to map file",
271            ErrorKind::MemoryMapOutOfRange => "memory map is out of range",
272            ErrorKind::UnableToReadMemory => "unable to read memory",
273
274            ErrorKind::InvalidArchitecture => "invalid architecture",
275            ErrorKind::InvalidMemorySize => "invalid memory size",
276            ErrorKind::InvalidMemorySizeUnit => "invalid memory size units (or none)",
277
278            ErrorKind::UnableToLoadLibrary => "unable to load library",
279            ErrorKind::InvalidExeFile => "file is not a valid executable file",
280            ErrorKind::MemflowExportsNotFound => "file does not contain any memflow exports",
281            ErrorKind::VersionMismatch => "version mismatch",
282            ErrorKind::AlreadyExists => "already exists",
283            ErrorKind::PluginNotFound => "plugin not found",
284            ErrorKind::TargetNotFound => "specified (connector) target could not be found",
285            ErrorKind::InvalidAbi => "invalid plugin ABI",
286            ErrorKind::UnsupportedOptionalFeature => "unsupported optional feature",
287
288            ErrorKind::ProcessNotFound => "process not found",
289            ErrorKind::InvalidProcessInfo => "invalid process info",
290            ErrorKind::ModuleNotFound => "module not found",
291            ErrorKind::ExportNotFound => "export not found",
292            ErrorKind::ImportNotFound => "import not found",
293            ErrorKind::SectionNotFound => "section not found",
294
295            ErrorKind::Unknown => "unknown error",
296        }
297    }
298}
299
300/// Specialized `PartialError` type for recoverable memflow errors.
301#[derive(Clone, Eq, PartialEq, Hash)]
302pub enum PartialError<T> {
303    /// Hard Error
304    ///
305    /// Catch-all for all hard  
306    Error(Error),
307    /// Partial Virtual Read Error
308    ///
309    /// Error when a read from virtual memory only completed partially.
310    /// This can usually happen when trying to read a page that is currently paged out.
311    PartialVirtualRead(T),
312    /// Partial Virtual Write Error
313    ///
314    /// Error when a write from virtual memory only completed partially.
315    /// This can usually happen when trying to read a page that is currently paged out.
316    PartialVirtualWrite(T),
317}
318
319/// Convert from Error
320impl<T> From<Error> for PartialError<T> {
321    fn from(err: Error) -> Self {
322        PartialError::Error(err)
323    }
324}
325
326impl<T> PartialError<T> {
327    /// Returns a static string representing the type of error.
328    pub fn as_str(&self) -> &'static str {
329        match self {
330            PartialError::Error(e) => e.as_str(),
331            PartialError::PartialVirtualRead(_) => "partial virtual read",
332            PartialError::PartialVirtualWrite(_) => "partial virtual write",
333        }
334    }
335
336    /// Returns a static string representing the type of error.
337    pub fn into_str(self) -> &'static str {
338        self.as_str()
339    }
340}
341
342impl IntError for PartialError<()> {
343    fn into_int_err(self) -> NonZeroI32 {
344        match self {
345            PartialError::Error(err) => err.into_int_err(),
346            PartialError::PartialVirtualRead(_) => NonZeroI32::new(-2).unwrap(),
347            PartialError::PartialVirtualWrite(_) => NonZeroI32::new(-3).unwrap(),
348        }
349    }
350
351    fn from_int_err(err: NonZeroI32) -> Self {
352        let errc = (-err.get()) & 0xFi32;
353        match errc {
354            1 => PartialError::Error(Error::from_int_err(err)),
355            2 => PartialError::PartialVirtualRead(()),
356            3 => PartialError::PartialVirtualWrite(()),
357            _ => PartialError::Error(Error(ErrorOrigin::Ffi, ErrorKind::Unknown)),
358        }
359    }
360}
361
362/// Custom fmt::Debug impl for the specialized memflow `Error` type.
363/// This is required due to our generic type T.
364impl<T> fmt::Debug for PartialError<T> {
365    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
366        f.write_str(&self.to_string())
367    }
368}
369
370impl<T> fmt::Display for PartialError<T> {
371    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
372        match self {
373            PartialError::Error(e) => f.write_str(e.as_str()),
374            _ => f.write_str(self.as_str()),
375        }
376    }
377}
378
379#[cfg(feature = "std")]
380impl<T: fmt::Debug> error::Error for PartialError<T> {
381    fn description(&self) -> &str {
382        self.as_str()
383    }
384}
385
386/// Specialized `Result` type for memflow results.
387pub type Result<T> = result::Result<T, Error>;
388
389/// Specialized `PartialResult` type for memflow results with recoverable errors.
390pub type PartialResult<T> = result::Result<T, PartialError<T>>;
391
392/// Specialized `PartialResult` extension for results.
393pub trait PartialResultExt<T> {
394    /// Tries to extract the data from the `Result`.
395    /// This will return a full error even if a partial error happened.
396    fn data(self) -> Result<T>;
397
398    /// Tries to extract the data or partial data from the `Result`.
399    /// This will return a full error only if a hard error happened.
400    /// A partial error will be converted to an `Ok(T)`.
401    fn data_part(self) -> Result<T>;
402
403    /// Maps the data contained in the partial result to another result.
404    /// This is especially useful if you want to return a different result type
405    /// but want to keep the partial result information.
406    fn map_data<U, F: FnOnce(T) -> U>(self, func: F) -> PartialResult<U>;
407}
408
409impl<T> PartialResultExt<T> for PartialResult<T> {
410    fn data(self) -> Result<T> {
411        match self {
412            Ok(data) => Ok(data),
413            Err(_) => Err(Error(ErrorOrigin::Memory, ErrorKind::PartialData)),
414        }
415    }
416
417    fn data_part(self) -> Result<T> {
418        match self {
419            Ok(data) => Ok(data),
420            Err(PartialError::PartialVirtualRead(data)) => Ok(data),
421            Err(PartialError::PartialVirtualWrite(data)) => Ok(data),
422            Err(PartialError::Error(e)) => Err(e),
423        }
424    }
425
426    fn map_data<U, F: FnOnce(T) -> U>(self, func: F) -> PartialResult<U> {
427        match self {
428            Ok(data) => Ok(func(data)),
429            Err(PartialError::Error(e)) => Err(PartialError::Error(e)),
430            Err(PartialError::PartialVirtualRead(data)) => Ok(func(data)),
431            Err(PartialError::PartialVirtualWrite(data)) => Ok(func(data)),
432        }
433    }
434}
435
436#[cfg(test)]
437mod tests {
438    use super::*;
439    use crate::cglue::result::{
440        from_int_result, from_int_result_empty, into_int_out_result, into_int_result, IntError,
441    };
442    use std::mem::MaybeUninit;
443    use std::num::NonZeroI32;
444
445    #[test]
446    pub fn error_from_i32_invalid() {
447        let mut err = Error::from_int_err(NonZeroI32::new(i32::MIN + 1).unwrap());
448        assert_eq!(err.0, ErrorOrigin::Other);
449        assert_eq!(err.1, ErrorKind::Unknown);
450
451        err = Error::from_int_err(NonZeroI32::new(-1).unwrap());
452        assert_eq!(err.0, ErrorOrigin::Other);
453        assert_eq!(err.1, ErrorKind::Unknown);
454
455        err = Error::from_int_err(NonZeroI32::new(-2).unwrap());
456        assert_eq!(err.0, ErrorOrigin::Other);
457        assert_eq!(err.1, ErrorKind::Unknown);
458
459        err = Error::from_int_err(NonZeroI32::new(-3).unwrap());
460        assert_eq!(err.0, ErrorOrigin::Other);
461        assert_eq!(err.1, ErrorKind::Unknown);
462    }
463
464    #[test]
465    pub fn part_error_from_i32_invalid() {
466        let mut result: PartialResult<()> = from_int_result_empty(-1);
467        assert!(result.is_err());
468        assert_eq!(
469            result.err().unwrap(),
470            PartialError::Error(Error(ErrorOrigin::Other, ErrorKind::Unknown))
471        );
472
473        result = from_int_result_empty(-2);
474        assert!(result.is_err());
475        assert_eq!(result.err().unwrap(), PartialError::PartialVirtualRead(()));
476
477        result = from_int_result_empty(-3);
478        assert!(result.is_err());
479        assert_eq!(result.err().unwrap(), PartialError::PartialVirtualWrite(()));
480
481        result = from_int_result_empty(-4);
482        assert!(result.is_err());
483        assert_eq!(
484            result.err().unwrap(),
485            PartialError::Error(Error(ErrorOrigin::Ffi, ErrorKind::Unknown))
486        );
487    }
488
489    #[test]
490    pub fn error_to_from_i32() {
491        let err = Error::from_int_err(
492            Error(ErrorOrigin::Other, ErrorKind::InvalidExeFile).into_int_err(),
493        );
494        assert_eq!(err.0, ErrorOrigin::Other);
495        assert_eq!(err.1, ErrorKind::InvalidExeFile);
496    }
497
498    #[test]
499    pub fn result_ok_void_ffi() {
500        let r: Result<()> = Ok(());
501        let result: Result<()> = from_int_result_empty(into_int_result(r));
502        assert!(result.is_ok());
503    }
504
505    #[test]
506    pub fn result_ok_value_ffi() {
507        let r: Result<i32> = Ok(1234i32);
508        let mut out = MaybeUninit::<i32>::uninit();
509        let result: Result<i32> = unsafe { from_int_result(into_int_out_result(r, &mut out), out) };
510        assert!(result.is_ok());
511        assert_eq!(result.unwrap(), 1234i32);
512    }
513
514    #[test]
515    pub fn result_error_void_ffi() {
516        let r: Result<i32> = Err(Error(ErrorOrigin::Other, ErrorKind::InvalidExeFile));
517        let result: Result<()> = from_int_result_empty(into_int_result(r));
518        assert!(result.is_err());
519        assert_eq!(result.err().unwrap().0, ErrorOrigin::Other);
520        assert_eq!(result.err().unwrap().1, ErrorKind::InvalidExeFile);
521    }
522
523    #[test]
524    pub fn result_error_value_ffi() {
525        let r: Result<i32> = Err(Error(ErrorOrigin::Other, ErrorKind::InvalidExeFile));
526        let mut out = MaybeUninit::<i32>::uninit();
527        let result: Result<i32> = unsafe { from_int_result(into_int_out_result(r, &mut out), out) };
528        assert!(result.is_err());
529        assert_eq!(result.err().unwrap().0, ErrorOrigin::Other);
530        assert_eq!(result.err().unwrap().1, ErrorKind::InvalidExeFile);
531    }
532
533    #[test]
534    pub fn part_result_ok_void_ffi() {
535        let r: PartialResult<()> = Ok(());
536        let result: PartialResult<()> = from_int_result_empty(into_int_result(r));
537        assert!(result.is_ok());
538    }
539
540    #[test]
541    pub fn part_result_error_void_ffi() {
542        let r: PartialResult<()> = Err(PartialError::Error(Error(
543            ErrorOrigin::Other,
544            ErrorKind::InvalidExeFile,
545        )));
546        let result: PartialResult<()> = from_int_result_empty(into_int_result(r));
547        assert!(result.is_err());
548        assert_eq!(
549            result.err().unwrap(),
550            PartialError::Error(Error(ErrorOrigin::Other, ErrorKind::InvalidExeFile))
551        );
552    }
553
554    #[test]
555    pub fn part_result_part_error_read_ffi() {
556        let r: PartialResult<()> = Err(PartialError::PartialVirtualRead(()));
557        let result: PartialResult<()> = from_int_result_empty(into_int_result(r));
558        assert!(result.is_err());
559        assert_eq!(result.err().unwrap(), PartialError::PartialVirtualRead(()));
560    }
561
562    #[test]
563    pub fn part_result_part_error_write_ffi() {
564        let r: PartialResult<()> = Err(PartialError::PartialVirtualWrite(()));
565        let result: PartialResult<()> = from_int_result_empty(into_int_result(r));
566        assert!(result.is_err());
567        assert_eq!(result.err().unwrap(), PartialError::PartialVirtualWrite(()));
568    }
569}