1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use std::error::Error;
use std::fmt;

use thiserror::Error;

#[doc(hidden)]
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum ValueKind {
    Symbol,
    Function,
    File,
    Line,
    ParentOffset,
    Language,
}

impl fmt::Display for ValueKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            ValueKind::Symbol => write!(f, "symbol"),
            ValueKind::Function => write!(f, "function"),
            ValueKind::File => write!(f, "file"),
            ValueKind::Line => write!(f, "line record"),
            ValueKind::ParentOffset => write!(f, "inline parent offset"),
            ValueKind::Language => write!(f, "language"),
        }
    }
}

/// The error type for [`SymCacheError`].
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum SymCacheErrorKind {
    /// Invalid magic bytes in the symcache header.
    BadFileMagic,

    /// Invalid flags or fields in the symcache header.
    BadFileHeader,

    /// A segment could not be read, likely due to IO errors.
    BadSegment,

    /// Contents in the symcache file are malformed.
    BadCacheFile,

    /// The symcache version is not known.
    UnsupportedVersion,

    /// The `Object` contains invalid data and cannot be converted.
    BadDebugFile,

    /// A required debug section is missing in the `Object` file.
    MissingDebugSection,

    /// The `Object` file was stripped of debug information.
    MissingDebugInfo,

    /// The debug information in the `Object` file is not supported.
    UnsupportedDebugKind,

    /// A value cannot be written to symcache as it overflows the record size.
    ValueTooLarge(ValueKind),

    /// A value cannot be written to symcache as it overflows the segment counter.
    TooManyValues(ValueKind),

    /// Generic error when writing a symcache, most likely IO.
    WriteFailed,
}

impl fmt::Display for SymCacheErrorKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::BadFileMagic => write!(f, "bad symcache magic"),
            Self::BadFileHeader => write!(f, "invalid symcache header"),
            Self::BadSegment => write!(f, "cannot read symcache segment"),
            Self::BadCacheFile => write!(f, "malformed symcache file"),
            Self::UnsupportedVersion => write!(f, "unsupported symcache version"),
            Self::BadDebugFile => write!(f, "malformed debug info file"),
            Self::MissingDebugSection => write!(f, "missing debug section"),
            Self::MissingDebugInfo => write!(f, "no debug information found in file"),
            Self::UnsupportedDebugKind => write!(f, "unsupported debug information"),
            Self::ValueTooLarge(kind) => write!(f, "{} too large for symcache file format", kind),
            Self::TooManyValues(kind) => write!(f, "too many {}s for symcache", kind),
            Self::WriteFailed => write!(f, "failed to write symcache"),
        }
    }
}

/// An error returned when handling a [`SymCache`](super::cache::SymCache).
#[derive(Debug, Error)]
#[error("{kind}")]
pub struct SymCacheError {
    kind: SymCacheErrorKind,
    #[source]
    source: Option<Box<dyn Error + Send + Sync + 'static>>,
}

impl SymCacheError {
    /// Creates a new SymCache error from a known kind of error as well as an
    /// arbitrary error payload.
    pub(crate) fn new<E>(kind: SymCacheErrorKind, source: E) -> Self
    where
        E: Into<Box<dyn Error + Send + Sync>>,
    {
        let source = Some(source.into());
        Self { kind, source }
    }

    /// Returns the corresponding [`SymCacheErrorKind`] for this error.
    pub fn kind(&self) -> SymCacheErrorKind {
        self.kind
    }
}

impl From<SymCacheErrorKind> for SymCacheError {
    fn from(kind: SymCacheErrorKind) -> Self {
        Self { kind, source: None }
    }
}