thorin/
error.rs

1use std::error::Error as StdError;
2use std::fmt;
3
4pub(crate) type Result<T> = std::result::Result<T, Error>;
5
6/// Helper trait for converting an error to a `&dyn std::error::Error`.
7pub trait AsDynError<'a> {
8    fn as_dyn_error(&self) -> &(dyn StdError + 'a);
9}
10
11impl<'a, T: StdError + 'a> AsDynError<'a> for T {
12    #[inline]
13    fn as_dyn_error(&self) -> &(dyn StdError + 'a) {
14        self
15    }
16}
17
18/// Diagnostics (and contexts) emitted during DWARF packaging.
19#[derive(Debug)]
20#[non_exhaustive]
21pub enum Error {
22    /// Failure to read input file.
23    ///
24    /// This error occurs in the `Session::read_input` function provided by the user of `thorin`.
25    ReadInput(std::io::Error),
26    /// Failed to parse kind of input file.
27    ///
28    /// Input file kind is necessary to determine how to parse the rest of the input, and to
29    /// validate that the input file is of a type that `thorin` can process.
30    ParseFileKind(object::Error),
31    /// Failed to parse object file.
32    ParseObjectFile(object::Error),
33    /// Failed to parse archive file.
34    ParseArchiveFile(object::Error),
35    /// Failed to parse archive member.
36    ParseArchiveMember(object::Error),
37    /// Invalid kind of input.
38    ///
39    /// Only archive and elf files are supported input files.
40    InvalidInputKind,
41    /// Failed to decompress data.
42    ///
43    /// `thorin` uses `object` for decompression, so `object` probably didn't have support for the
44    /// type of compression used.
45    DecompressData(object::Error),
46    /// Section without a name.
47    NamelessSection(object::Error, usize),
48    /// Relocation has invalid symbol for a section.
49    RelocationWithInvalidSymbol(String, usize),
50    /// Multiple relocations for a section.
51    MultipleRelocations(String, usize),
52    /// Unsupported relocations for a section.
53    UnsupportedRelocation(String, usize),
54    /// Input object that has a `DwoId` (or `DebugTypeSignature`) does not have a
55    /// `DW_AT_GNU_dwo_name` or `DW_AT_dwo_name` attribute.
56    MissingDwoName(u64),
57    /// Input object has no compilation units.
58    NoCompilationUnits,
59    /// No top-level debugging information entry in unit.
60    NoDie,
61    /// Top-level debugging information entry is not a compilation/type unit.
62    TopLevelDieNotUnit,
63    /// Section required of input DWARF objects was missing.
64    MissingRequiredSection(&'static str),
65    /// Failed to parse unit abbreviations.
66    ParseUnitAbbreviations(gimli::read::Error),
67    /// Failed to parse unit attribute.
68    ParseUnitAttribute(gimli::read::Error),
69    /// Failed to parse unit header.
70    ParseUnitHeader(gimli::read::Error),
71    /// Failed to parse unit.
72    ParseUnit(gimli::read::Error),
73    /// Input DWARF package has a different index version than the version being output.
74    IncompatibleIndexVersion(String, u16, u16),
75    /// Failed to read string offset from `.debug_str_offsets` at index.
76    OffsetAtIndex(gimli::read::Error, u64),
77    /// Failed to read string from `.debug_str` at offset.
78    StrAtOffset(gimli::read::Error, usize),
79    /// Failed to parse index section.
80    ///
81    /// If an input file is a DWARF package, its index section needs to be read to ensure that the
82    /// contributions within it are preserved.
83    ParseIndex(gimli::read::Error, String),
84    /// Compilation unit in DWARF package is not its index.
85    UnitNotInIndex(u64),
86    /// Row for a compilation unit is not in the index.
87    RowNotInIndex(gimli::read::Error, u32),
88    /// Section not found in unit's row in index, i.e. a DWARF package contains a section but its
89    /// index doesn't record contributions to it.
90    SectionNotInRow,
91    /// Compilation unit in input DWARF object has no content.
92    EmptyUnit(u64),
93    /// Found multiple `.debug_info.dwo` sections.
94    MultipleDebugInfoSection,
95    /// Found multiple `.debug_types.dwo` sections in a DWARF package file.
96    MultipleDebugTypesSection,
97    /// Found a regular compilation unit in a DWARF object.
98    NotSplitUnit,
99    /// Found duplicate split compilation unit.
100    DuplicateUnit(u64),
101    /// Unit referenced by an executable was not found.
102    MissingReferencedUnit(u64),
103    /// No output object was created from inputs
104    NoOutputObjectCreated,
105    /// Input objects have different encodings.
106    MixedInputEncodings,
107
108    /// Catch-all for `std::io::Error`.
109    Io(std::io::Error),
110    /// Catch-all for `object::Error`.
111    ObjectRead(object::Error),
112    /// Catch-all for `object::write::Error`.
113    ObjectWrite(object::write::Error),
114    /// Catch-all for `gimli::read::Error`.
115    GimliRead(gimli::read::Error),
116    /// Catch-all for `gimli::write::Error`.
117    GimliWrite(gimli::write::Error),
118}
119
120impl StdError for Error {
121    fn source(&self) -> Option<&(dyn StdError + 'static)> {
122        match self {
123            Error::ReadInput(source) => Some(source.as_dyn_error()),
124            Error::ParseFileKind(source) => Some(source.as_dyn_error()),
125            Error::ParseObjectFile(source) => Some(source.as_dyn_error()),
126            Error::ParseArchiveFile(source) => Some(source.as_dyn_error()),
127            Error::ParseArchiveMember(source) => Some(source.as_dyn_error()),
128            Error::InvalidInputKind => None,
129            Error::DecompressData(source) => Some(source.as_dyn_error()),
130            Error::NamelessSection(source, _) => Some(source.as_dyn_error()),
131            Error::RelocationWithInvalidSymbol(_, _) => None,
132            Error::MultipleRelocations(_, _) => None,
133            Error::UnsupportedRelocation(_, _) => None,
134            Error::MissingDwoName(_) => None,
135            Error::NoCompilationUnits => None,
136            Error::NoDie => None,
137            Error::TopLevelDieNotUnit => None,
138            Error::MissingRequiredSection(_) => None,
139            Error::ParseUnitAbbreviations(source) => Some(source.as_dyn_error()),
140            Error::ParseUnitAttribute(source) => Some(source.as_dyn_error()),
141            Error::ParseUnitHeader(source) => Some(source.as_dyn_error()),
142            Error::ParseUnit(source) => Some(source.as_dyn_error()),
143            Error::IncompatibleIndexVersion(_, _, _) => None,
144            Error::OffsetAtIndex(source, _) => Some(source.as_dyn_error()),
145            Error::StrAtOffset(source, _) => Some(source.as_dyn_error()),
146            Error::ParseIndex(source, _) => Some(source.as_dyn_error()),
147            Error::UnitNotInIndex(_) => None,
148            Error::RowNotInIndex(source, _) => Some(source.as_dyn_error()),
149            Error::SectionNotInRow => None,
150            Error::EmptyUnit(_) => None,
151            Error::MultipleDebugInfoSection => None,
152            Error::MultipleDebugTypesSection => None,
153            Error::NotSplitUnit => None,
154            Error::DuplicateUnit(_) => None,
155            Error::MissingReferencedUnit(_) => None,
156            Error::NoOutputObjectCreated => None,
157            Error::MixedInputEncodings => None,
158            Error::Io(transparent) => StdError::source(transparent.as_dyn_error()),
159            Error::ObjectRead(transparent) => StdError::source(transparent.as_dyn_error()),
160            Error::ObjectWrite(transparent) => StdError::source(transparent.as_dyn_error()),
161            Error::GimliRead(transparent) => StdError::source(transparent.as_dyn_error()),
162            Error::GimliWrite(transparent) => StdError::source(transparent.as_dyn_error()),
163        }
164    }
165}
166
167impl fmt::Display for Error {
168    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
169        match self {
170            Error::ReadInput(_) => write!(f, "Failed to read input file"),
171            Error::ParseFileKind(_) => write!(f, "Failed to parse input file kind"),
172            Error::ParseObjectFile(_) => write!(f, "Failed to parse input object file"),
173            Error::ParseArchiveFile(_) => write!(f, "Failed to parse input archive file"),
174            Error::ParseArchiveMember(_) => write!(f, "Failed to parse archive member"),
175            Error::InvalidInputKind => write!(f, "Input is not an archive or elf object"),
176            Error::DecompressData(_) => write!(f, "Failed to decompress compressed section"),
177            Error::NamelessSection(_, offset) => {
178                write!(f, "Section without name at offset 0x{:08x}", offset)
179            }
180            Error::RelocationWithInvalidSymbol(section, offset) => write!(
181                f,
182                "Relocation with invalid symbol for section `{}` at offset 0x{:08x}",
183                section, offset
184            ),
185            Error::MultipleRelocations(section, offset) => write!(
186                f,
187                "Multiple relocations for section `{}` at offset 0x{:08x}",
188                section, offset
189            ),
190            Error::UnsupportedRelocation(section, offset) => write!(
191                f,
192                "Unsupported relocation for section {} at offset 0x{:08x}",
193                section, offset
194            ),
195            Error::MissingDwoName(id) => {
196                write!(f, "Missing path attribute to DWARF object (0x{:08x})", id)
197            }
198            Error::NoCompilationUnits => {
199                write!(f, "Input object has no compilation units")
200            }
201            Error::NoDie => {
202                write!(f, "No top-level debugging information entry in compilation/type unit")
203            }
204            Error::TopLevelDieNotUnit => {
205                write!(f, "Top-level debugging information entry is not a compilation/type unit")
206            }
207            Error::MissingRequiredSection(section) => {
208                write!(f, "Input object missing required section `{}`", section)
209            }
210            Error::ParseUnitAbbreviations(_) => write!(f, "Failed to parse unit abbreviations"),
211            Error::ParseUnitAttribute(_) => write!(f, "Failed to parse unit attribute"),
212            Error::ParseUnitHeader(_) => write!(f, "Failed to parse unit header"),
213            Error::ParseUnit(_) => write!(f, "Failed to parse unit"),
214            Error::IncompatibleIndexVersion(section, format, actual) => {
215                write!(
216                    f,
217                    "Incompatible `{}` index version: found version {}, expected version {}",
218                    section, actual, format
219                )
220            }
221            Error::OffsetAtIndex(_, index) => {
222                write!(f, "Read offset at index {} of `.debug_str_offsets.dwo` section", index)
223            }
224            Error::StrAtOffset(_, offset) => {
225                write!(f, "Read string at offset 0x{:08x} of `.debug_str.dwo` section", offset)
226            }
227            Error::ParseIndex(_, section) => {
228                write!(f, "Failed to parse `{}` index section", section)
229            }
230            Error::UnitNotInIndex(unit) => {
231                write!(f, "Unit 0x{0:08x} from input package is not in its index", unit)
232            }
233            Error::RowNotInIndex(_, row) => {
234                write!(f, "Row {0} found in index's hash table not present in index", row)
235            }
236            Error::SectionNotInRow => write!(f, "Section not found in unit's row in index"),
237            Error::EmptyUnit(unit) => {
238                write!(f, "Unit 0x{:08x} in input DWARF object with no data", unit)
239            }
240            Error::MultipleDebugInfoSection => {
241                write!(f, "Multiple `.debug_info.dwo` sections")
242            }
243            Error::MultipleDebugTypesSection => {
244                write!(f, "Multiple `.debug_types.dwo` sections in a package")
245            }
246            Error::NotSplitUnit => {
247                write!(f, "Regular compilation unit in object (missing dwo identifier)")
248            }
249            Error::DuplicateUnit(unit) => {
250                write!(f, "Duplicate split compilation unit (0x{:08x})", unit)
251            }
252            Error::MissingReferencedUnit(unit) => {
253                write!(f, "Unit 0x{:08x} referenced by executable was not found", unit)
254            }
255            Error::NoOutputObjectCreated => write!(f, "No output object was created from inputs"),
256            Error::MixedInputEncodings => write!(f, "Input objects haved mixed encodings"),
257            Error::Io(e) => fmt::Display::fmt(e, f),
258            Error::ObjectRead(e) => fmt::Display::fmt(e, f),
259            Error::ObjectWrite(e) => fmt::Display::fmt(e, f),
260            Error::GimliRead(e) => fmt::Display::fmt(e, f),
261            Error::GimliWrite(e) => fmt::Display::fmt(e, f),
262        }
263    }
264}
265
266impl From<std::io::Error> for Error {
267    fn from(source: std::io::Error) -> Self {
268        Error::Io(source)
269    }
270}
271
272impl From<object::Error> for Error {
273    fn from(source: object::Error) -> Self {
274        Error::ObjectRead(source)
275    }
276}
277
278impl From<object::write::Error> for Error {
279    fn from(source: object::write::Error) -> Self {
280        Error::ObjectWrite(source)
281    }
282}
283
284impl From<gimli::read::Error> for Error {
285    fn from(source: gimli::read::Error) -> Self {
286        Error::GimliRead(source)
287    }
288}
289
290impl From<gimli::write::Error> for Error {
291    fn from(source: gimli::write::Error) -> Self {
292        Error::GimliWrite(source)
293    }
294}