Skip to main content

macho_dyld_cache/
error.rs

1use std::fmt;
2
3use macho_core::{ContextFrame, OffsetSpan, ParseError};
4
5const INVALID_FORMAT_CODE: &str = "dyld_cache.format.invalid";
6const OUT_OF_BOUNDS_CODE: &str = "dyld_cache.bounds.exceeded";
7const INVALID_ADDRESS_CODE: &str = "dyld_cache.address.invalid";
8const UNSUPPORTED_INPUT_CODE: &str = "dyld_cache.input.unsupported";
9const CORE_FAILED_CODE: &str = "dyld_cache.core.failed";
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12/// The DyldCacheErrorKind type.
13#[non_exhaustive]
14pub enum DyldCacheErrorKind {
15    /// The InvalidFormat variant.
16    InvalidFormat,
17    /// The OutOfBounds variant.
18    OutOfBounds,
19    /// The InvalidAddress variant.
20    InvalidAddress,
21    /// The Unsupported variant.
22    Unsupported,
23    /// The Core variant.
24    Core,
25}
26
27#[derive(Debug)]
28/// The DyldCacheError type.
29pub struct DyldCacheError {
30    /// The kind field.
31    pub kind: DyldCacheErrorKind,
32    /// The location field.
33    pub location: Option<OffsetSpan>,
34    /// The context field.
35    pub context: Vec<ContextFrame>,
36    message: String,
37    /// The source field.
38    pub source: Option<Box<ParseError>>,
39}
40
41impl DyldCacheError {
42    /// Performs new.
43    pub fn new(kind: DyldCacheErrorKind, message: impl Into<String>) -> Self {
44        Self {
45            kind,
46            location: None,
47            context: Vec::new(),
48            message: message.into(),
49            source: None,
50        }
51    }
52    /// Performs format.
53    pub fn format(message: impl Into<String>) -> Self {
54        Self::new(DyldCacheErrorKind::InvalidFormat, message)
55    }
56    /// Performs address.
57    pub fn address(message: impl Into<String>) -> Self {
58        Self::new(DyldCacheErrorKind::InvalidAddress, message)
59    }
60    /// Performs unsupported.
61    pub fn unsupported(message: impl Into<String>) -> Self {
62        Self::new(DyldCacheErrorKind::Unsupported, message)
63    }
64    /// Performs bounds.
65    pub fn bounds(offset: u64, needed: u64, available: u64) -> Self {
66        let mut error = Self::new(
67            DyldCacheErrorKind::OutOfBounds,
68            format!("offset {offset:#x}, needed {needed} bytes, have {available}"),
69        );
70        error.location = Some(OffsetSpan {
71            offset,
72            len: needed,
73        });
74        error
75    }
76    /// Performs with_context.
77    pub fn with_context(mut self, frame: ContextFrame) -> Self {
78        self.context.push(frame);
79        self
80    }
81    /// Performs message.
82    pub fn message(&self) -> &str {
83        &self.message
84    }
85    /// Performs code.
86    pub const fn code(&self) -> &'static str {
87        match self.kind {
88            DyldCacheErrorKind::InvalidFormat => INVALID_FORMAT_CODE,
89            DyldCacheErrorKind::OutOfBounds => OUT_OF_BOUNDS_CODE,
90            DyldCacheErrorKind::InvalidAddress => INVALID_ADDRESS_CODE,
91            DyldCacheErrorKind::Unsupported => UNSUPPORTED_INPUT_CODE,
92            DyldCacheErrorKind::Core => CORE_FAILED_CODE,
93        }
94    }
95}
96
97impl From<ParseError> for DyldCacheError {
98    fn from(source: ParseError) -> Self {
99        let mut context = source.context.clone();
100        context.push(ContextFrame::Operation { name: "dyld_cache" });
101        Self {
102            kind: DyldCacheErrorKind::Core,
103            location: source.location,
104            context,
105            message: source.message().to_owned(),
106            source: Some(Box::new(source)),
107        }
108    }
109}
110
111impl fmt::Display for DyldCacheError {
112    fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
113        write!(formatter, "{}: {}", self.code(), self.message)
114    }
115}
116impl std::error::Error for DyldCacheError {
117    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
118        self.source.as_deref().map(|source| source as _)
119    }
120}
121
122/// The Result type.
123pub type Result<T> = std::result::Result<T, DyldCacheError>;
124/// The Error type.
125pub(crate) type Error = DyldCacheError;