Skip to main content

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 header.
68    ParseUnitHeader(gimli::read::Error),
69    /// Failed to parse unit.
70    ParseUnit(gimli::read::Error),
71    /// Input DWARF package has a different index version than the version being output.
72    IncompatibleIndexVersion(String, u16, u16),
73    /// Failed to read string offset from `.debug_str_offsets` at index.
74    OffsetAtIndex(gimli::read::Error, u64),
75    /// Failed to read string from `.debug_str` at offset.
76    StrAtOffset(gimli::read::Error, usize),
77    /// Failed to parse index section.
78    ///
79    /// If an input file is a DWARF package, its index section needs to be read to ensure that the
80    /// contributions within it are preserved.
81    ParseIndex(gimli::read::Error, String),
82    /// Compilation unit in DWARF package is not its index.
83    UnitNotInIndex(u64),
84    /// Row for a compilation unit is not in the index.
85    RowNotInIndex(gimli::read::Error, u32),
86    /// Section not found in unit's row in index, i.e. a DWARF package contains a section but its
87    /// index doesn't record contributions to it.
88    SectionNotInRow,
89    /// Compilation unit in input DWARF object has no content.
90    EmptyUnit(u64),
91    /// Found multiple `.debug_info.dwo` sections.
92    MultipleDebugInfoSection,
93    /// Found multiple `.debug_types.dwo` sections in a DWARF package file.
94    MultipleDebugTypesSection,
95    /// Found a regular compilation unit in a DWARF object.
96    NotSplitUnit,
97    /// Found duplicate split compilation unit.
98    DuplicateUnit(u64),
99    /// Unit referenced by an executable was not found.
100    MissingReferencedUnit(u64),
101    /// No output object was created from inputs
102    NoOutputObjectCreated,
103    /// Input objects have different encodings.
104    MixedInputEncodings,
105
106    /// Catch-all for `std::io::Error`.
107    Io(std::io::Error),
108    /// Catch-all for `object::Error`.
109    ObjectRead(object::Error),
110    /// Catch-all for `object::write::Error`.
111    ObjectWrite(object::write::Error),
112    /// Catch-all for `gimli::read::Error`.
113    GimliRead(gimli::read::Error),
114    /// Catch-all for `gimli::write::Error`.
115    GimliWrite(gimli::write::Error),
116}
117
118impl StdError for Error {
119    fn source(&self) -> Option<&(dyn StdError + 'static)> {
120        match self {
121            Error::ReadInput(source) => Some(source.as_dyn_error()),
122            Error::ParseFileKind(source) => Some(source.as_dyn_error()),
123            Error::ParseObjectFile(source) => Some(source.as_dyn_error()),
124            Error::ParseArchiveFile(source) => Some(source.as_dyn_error()),
125            Error::ParseArchiveMember(source) => Some(source.as_dyn_error()),
126            Error::InvalidInputKind => None,
127            Error::DecompressData(source) => Some(source.as_dyn_error()),
128            Error::NamelessSection(source, _) => Some(source.as_dyn_error()),
129            Error::RelocationWithInvalidSymbol(_, _) => None,
130            Error::MultipleRelocations(_, _) => None,
131            Error::UnsupportedRelocation(_, _) => None,
132            Error::MissingDwoName(_) => None,
133            Error::NoCompilationUnits => None,
134            Error::NoDie => None,
135            Error::TopLevelDieNotUnit => None,
136            Error::MissingRequiredSection(_) => None,
137            Error::ParseUnitAbbreviations(source) => Some(source.as_dyn_error()),
138            Error::ParseUnitHeader(source) => Some(source.as_dyn_error()),
139            Error::ParseUnit(source) => Some(source.as_dyn_error()),
140            Error::IncompatibleIndexVersion(_, _, _) => None,
141            Error::OffsetAtIndex(source, _) => Some(source.as_dyn_error()),
142            Error::StrAtOffset(source, _) => Some(source.as_dyn_error()),
143            Error::ParseIndex(source, _) => Some(source.as_dyn_error()),
144            Error::UnitNotInIndex(_) => None,
145            Error::RowNotInIndex(source, _) => Some(source.as_dyn_error()),
146            Error::SectionNotInRow => None,
147            Error::EmptyUnit(_) => None,
148            Error::MultipleDebugInfoSection => None,
149            Error::MultipleDebugTypesSection => None,
150            Error::NotSplitUnit => None,
151            Error::DuplicateUnit(_) => None,
152            Error::MissingReferencedUnit(_) => None,
153            Error::NoOutputObjectCreated => None,
154            Error::MixedInputEncodings => None,
155            Error::Io(transparent) => StdError::source(transparent.as_dyn_error()),
156            Error::ObjectRead(transparent) => StdError::source(transparent.as_dyn_error()),
157            Error::ObjectWrite(transparent) => StdError::source(transparent.as_dyn_error()),
158            Error::GimliRead(transparent) => StdError::source(transparent.as_dyn_error()),
159            Error::GimliWrite(transparent) => StdError::source(transparent.as_dyn_error()),
160        }
161    }
162}
163
164impl fmt::Display for Error {
165    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
166        match self {
167            Error::ReadInput(_) => write!(f, "Failed to read input file"),
168            Error::ParseFileKind(_) => write!(f, "Failed to parse input file kind"),
169            Error::ParseObjectFile(_) => write!(f, "Failed to parse input object file"),
170            Error::ParseArchiveFile(_) => write!(f, "Failed to parse input archive file"),
171            Error::ParseArchiveMember(_) => write!(f, "Failed to parse archive member"),
172            Error::InvalidInputKind => write!(f, "Input is not an archive or elf object"),
173            Error::DecompressData(_) => write!(f, "Failed to decompress compressed section"),
174            Error::NamelessSection(_, offset) => {
175                write!(f, "Section without name at offset 0x{:08x}", offset)
176            }
177            Error::RelocationWithInvalidSymbol(section, offset) => write!(
178                f,
179                "Relocation with invalid symbol for section `{}` at offset 0x{:08x}",
180                section, offset
181            ),
182            Error::MultipleRelocations(section, offset) => write!(
183                f,
184                "Multiple relocations for section `{}` at offset 0x{:08x}",
185                section, offset
186            ),
187            Error::UnsupportedRelocation(section, offset) => write!(
188                f,
189                "Unsupported relocation for section {} at offset 0x{:08x}",
190                section, offset
191            ),
192            Error::MissingDwoName(id) => {
193                write!(f, "Missing path attribute to DWARF object (0x{:08x})", id)
194            }
195            Error::NoCompilationUnits => {
196                write!(f, "Input object has no compilation units")
197            }
198            Error::NoDie => {
199                write!(f, "No top-level debugging information entry in compilation/type unit")
200            }
201            Error::TopLevelDieNotUnit => {
202                write!(f, "Top-level debugging information entry is not a compilation/type unit")
203            }
204            Error::MissingRequiredSection(section) => {
205                write!(f, "Input object missing required section `{}`", section)
206            }
207            Error::ParseUnitAbbreviations(_) => write!(f, "Failed to parse unit abbreviations"),
208            Error::ParseUnitHeader(_) => write!(f, "Failed to parse unit header"),
209            Error::ParseUnit(_) => write!(f, "Failed to parse unit"),
210            Error::IncompatibleIndexVersion(section, format, actual) => {
211                write!(
212                    f,
213                    "Incompatible `{}` index version: found version {}, expected version {}",
214                    section, actual, format
215                )
216            }
217            Error::OffsetAtIndex(_, index) => {
218                write!(f, "Read offset at index {} of `.debug_str_offsets.dwo` section", index)
219            }
220            Error::StrAtOffset(_, offset) => {
221                write!(f, "Read string at offset 0x{:08x} of `.debug_str.dwo` section", offset)
222            }
223            Error::ParseIndex(_, section) => {
224                write!(f, "Failed to parse `{}` index section", section)
225            }
226            Error::UnitNotInIndex(unit) => {
227                write!(f, "Unit 0x{0:08x} from input package is not in its index", unit)
228            }
229            Error::RowNotInIndex(_, row) => {
230                write!(f, "Row {0} found in index's hash table not present in index", row)
231            }
232            Error::SectionNotInRow => write!(f, "Section not found in unit's row in index"),
233            Error::EmptyUnit(unit) => {
234                write!(f, "Unit 0x{:08x} in input DWARF object with no data", unit)
235            }
236            Error::MultipleDebugInfoSection => {
237                write!(f, "Multiple `.debug_info.dwo` sections")
238            }
239            Error::MultipleDebugTypesSection => {
240                write!(f, "Multiple `.debug_types.dwo` sections in a package")
241            }
242            Error::NotSplitUnit => {
243                write!(f, "Regular compilation unit in object (missing dwo identifier)")
244            }
245            Error::DuplicateUnit(unit) => {
246                write!(f, "Duplicate split compilation unit (0x{:08x})", unit)
247            }
248            Error::MissingReferencedUnit(unit) => {
249                write!(f, "Unit 0x{:08x} referenced by executable was not found", unit)
250            }
251            Error::NoOutputObjectCreated => write!(f, "No output object was created from inputs"),
252            Error::MixedInputEncodings => write!(f, "Input objects haved mixed encodings"),
253            Error::Io(e) => fmt::Display::fmt(e, f),
254            Error::ObjectRead(e) => fmt::Display::fmt(e, f),
255            Error::ObjectWrite(e) => fmt::Display::fmt(e, f),
256            Error::GimliRead(e) => fmt::Display::fmt(e, f),
257            Error::GimliWrite(e) => fmt::Display::fmt(e, f),
258        }
259    }
260}
261
262impl From<std::io::Error> for Error {
263    fn from(source: std::io::Error) -> Self {
264        Error::Io(source)
265    }
266}
267
268impl From<object::Error> for Error {
269    fn from(source: object::Error) -> Self {
270        Error::ObjectRead(source)
271    }
272}
273
274impl From<object::write::Error> for Error {
275    fn from(source: object::write::Error) -> Self {
276        Error::ObjectWrite(source)
277    }
278}
279
280impl From<gimli::read::Error> for Error {
281    fn from(source: gimli::read::Error) -> Self {
282        Error::GimliRead(source)
283    }
284}
285
286impl From<gimli::write::Error> for Error {
287    fn from(source: gimli::write::Error) -> Self {
288        Error::GimliWrite(source)
289    }
290}