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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
use std::borrow::Cow;
use std::fmt;

use failure::{Backtrace, Context, Fail};
use symbolic_debuginfo::ObjectError;

/// An internal error thrown during symcache conversion.
///
/// This error is used as cause for `BadDebugFile` errors to add more information to the generic
/// error kind. It should not be exposed to the user.
#[derive(Debug, Fail, Clone)]
#[fail(display = "{}", _0)]
pub(crate) struct ConversionError(pub Cow<'static, str>);

impl ConversionError {
    pub fn new<C>(message: C) -> Self
    where
        C: Into<Cow<'static, str>>,
    {
        ConversionError(message.into())
    }
}

#[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"),
        }
    }
}

/// Variants of `SymCacheError`.
#[derive(Debug, Fail, Copy, Clone, Eq, PartialEq)]
pub enum SymCacheErrorKind {
    /// Invalid magic bytes in the symcache header.
    #[fail(display = "bad symcache magic")]
    BadFileMagic,

    /// Invalid flags or fields in the symcache header.
    #[fail(display = "invalid symcache header")]
    BadFileHeader,

    /// A segment could not be read, likely due to IO errors.
    #[fail(display = "cannot read symcache segment")]
    BadSegment,

    /// Contents in the symcache file are malformed.
    #[fail(display = "malformed symcache file")]
    BadCacheFile,

    /// The symcache version is not known.
    #[fail(display = "unsupported symcache version")]
    UnsupportedVersion,

    /// The `Object` contains invalid data and cannot be converted.
    #[fail(display = "malformed debug info file")]
    BadDebugFile,

    /// A required debug section is missing in the `Object` file.
    #[fail(display = "missing debug section")]
    MissingDebugSection,

    /// The `Object` file was stripped of debug information.
    #[fail(display = "no debug information found in file")]
    MissingDebugInfo,

    /// The debug information in the `Object` file is not supported.
    #[fail(display = "unsupported debug information")]
    UnsupportedDebugKind,

    /// A value cannot be written to symcache as it overflows the record size.
    #[fail(display = "{} too large for symcache file format", _0)]
    ValueTooLarge(ValueKind),

    /// A value cannot be written to symcache as it overflows the segment counter.
    #[fail(display = "too many {}s for symcache", _0)]
    TooManyValues(ValueKind),

    /// Generic error when writing a symcache, most likely IO.
    #[fail(display = "failed to write symcache")]
    WriteFailed,
}

/// An error returned when handling symcaches.
#[derive(Debug)]
pub struct SymCacheError {
    inner: Context<SymCacheErrorKind>,
}

impl Fail for SymCacheError {
    fn cause(&self) -> Option<&dyn Fail> {
        self.inner.cause()
    }

    fn backtrace(&self) -> Option<&Backtrace> {
        self.inner.backtrace()
    }
}

impl fmt::Display for SymCacheError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        fmt::Display::fmt(&self.inner, f)
    }
}

impl SymCacheError {
    /// Returns the error kind of this error.
    pub fn kind(&self) -> SymCacheErrorKind {
        *self.inner.get_context()
    }
}

impl From<SymCacheErrorKind> for SymCacheError {
    fn from(kind: SymCacheErrorKind) -> SymCacheError {
        SymCacheError {
            inner: Context::new(kind),
        }
    }
}

impl From<Context<SymCacheErrorKind>> for SymCacheError {
    fn from(inner: Context<SymCacheErrorKind>) -> SymCacheError {
        SymCacheError { inner }
    }
}

impl From<ObjectError> for SymCacheError {
    fn from(error: ObjectError) -> SymCacheError {
        error.context(SymCacheErrorKind::BadDebugFile).into()
    }
}

impl From<gimli::Error> for SymCacheError {
    fn from(error: gimli::Error) -> SymCacheError {
        error.context(SymCacheErrorKind::BadDebugFile).into()
    }
}

impl From<ConversionError> for SymCacheError {
    fn from(error: ConversionError) -> SymCacheError {
        error.context(SymCacheErrorKind::BadDebugFile).into()
    }
}