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    ContributionOutOfBounds(crate::index::Contribution, usize),
90    /// Compilation unit in input DWARF object has no content.
91    EmptyUnit(u64),
92    /// Found multiple `.debug_info.dwo` sections.
93    MultipleDebugInfoSection,
94    /// Found multiple `.debug_types.dwo` sections in a DWARF package file.
95    MultipleDebugTypesSection,
96    /// Found a regular compilation unit in a DWARF object.
97    NotSplitUnit,
98    /// Found duplicate split compilation unit.
99    DuplicateUnit(u64),
100    /// Unit referenced by an executable was not found.
101    MissingReferencedUnit(u64),
102    /// No output object was created from inputs
103    NoOutputObjectCreated,
104    /// Input objects have different encodings.
105    MixedInputEncodings,
106    /// A DW_LLE value was unrecognized.
107    UnsupportedLocListsEntry(u8),
108    /// `.debug_info.dwo` compilation unit is malformed or truncated during GC.
109    MalformedDebugInfo,
110    /// An abbreviation form encountered during GC byte-level rewriting is not supported.
111    UnsupportedForm(u16),
112    /// A section-absolute reference was found where not expected.
113    UnexpectedSectionAbsoluteReference,
114    /// GC input object or executable added without prior `preprocess_gc_executable` call.
115    GcNotInitialized,
116    /// A `.dwo` is referenced by multiple executables that supply DWARF4 `.debug_ranges`.
117    ///
118    /// DWARF4 range lists hold raw addresses that live in the linked executable.
119    /// When several executables reference the same `.dwo`, each has its own (independently
120    /// tombstoned) `.debug_ranges`, but the GC currently only supports consulting one
121    /// of them. Proceeding could prune a range list still live in a different executable.
122    GcSharedDwarf4Ranges(crate::package::DwoId),
123
124    /// Catch-all for `std::io::Error`.
125    Io(std::io::Error),
126    /// Catch-all for `object::Error`.
127    ObjectRead(object::Error),
128    /// Catch-all for `object::write::Error`.
129    ObjectWrite(object::write::Error),
130    /// Catch-all for `gimli::read::Error`.
131    GimliRead(gimli::read::Error),
132    /// Catch-all for `gimli::write::Error`.
133    GimliWrite(gimli::write::Error),
134}
135
136impl StdError for Error {
137    fn source(&self) -> Option<&(dyn StdError + 'static)> {
138        match self {
139            Error::ReadInput(source) => Some(source.as_dyn_error()),
140            Error::ParseFileKind(source) => Some(source.as_dyn_error()),
141            Error::ParseObjectFile(source) => Some(source.as_dyn_error()),
142            Error::ParseArchiveFile(source) => Some(source.as_dyn_error()),
143            Error::ParseArchiveMember(source) => Some(source.as_dyn_error()),
144            Error::InvalidInputKind => None,
145            Error::DecompressData(source) => Some(source.as_dyn_error()),
146            Error::NamelessSection(source, _) => Some(source.as_dyn_error()),
147            Error::RelocationWithInvalidSymbol(_, _) => None,
148            Error::MultipleRelocations(_, _) => None,
149            Error::UnsupportedRelocation(_, _) => None,
150            Error::MissingDwoName(_) => None,
151            Error::NoCompilationUnits => None,
152            Error::NoDie => None,
153            Error::TopLevelDieNotUnit => None,
154            Error::MissingRequiredSection(_) => None,
155            Error::ParseUnitAbbreviations(source) => Some(source.as_dyn_error()),
156            Error::ParseUnitHeader(source) => Some(source.as_dyn_error()),
157            Error::ParseUnit(source) => Some(source.as_dyn_error()),
158            Error::IncompatibleIndexVersion(_, _, _) => None,
159            Error::OffsetAtIndex(source, _) => Some(source.as_dyn_error()),
160            Error::StrAtOffset(source, _) => Some(source.as_dyn_error()),
161            Error::ParseIndex(source, _) => Some(source.as_dyn_error()),
162            Error::UnitNotInIndex(_) => None,
163            Error::RowNotInIndex(source, _) => Some(source.as_dyn_error()),
164            Error::SectionNotInRow => None,
165            Error::ContributionOutOfBounds(..) => None,
166            Error::EmptyUnit(_) => None,
167            Error::MultipleDebugInfoSection => None,
168            Error::MultipleDebugTypesSection => None,
169            Error::NotSplitUnit => None,
170            Error::DuplicateUnit(_) => None,
171            Error::MissingReferencedUnit(_) => None,
172            Error::NoOutputObjectCreated => None,
173            Error::MixedInputEncodings => None,
174            Error::UnsupportedLocListsEntry(_) => None,
175            Error::MalformedDebugInfo => None,
176            Error::UnsupportedForm(_) => None,
177            Error::UnexpectedSectionAbsoluteReference => None,
178            Error::GcNotInitialized => None,
179            Error::GcSharedDwarf4Ranges(_) => None,
180            Error::Io(transparent) => StdError::source(transparent.as_dyn_error()),
181            Error::ObjectRead(transparent) => StdError::source(transparent.as_dyn_error()),
182            Error::ObjectWrite(transparent) => StdError::source(transparent.as_dyn_error()),
183            Error::GimliRead(transparent) => StdError::source(transparent.as_dyn_error()),
184            Error::GimliWrite(transparent) => StdError::source(transparent.as_dyn_error()),
185        }
186    }
187}
188
189impl fmt::Display for Error {
190    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
191        match self {
192            Error::ReadInput(_) => write!(f, "Failed to read input file"),
193            Error::ParseFileKind(_) => write!(f, "Failed to parse input file kind"),
194            Error::ParseObjectFile(_) => write!(f, "Failed to parse input object file"),
195            Error::ParseArchiveFile(_) => write!(f, "Failed to parse input archive file"),
196            Error::ParseArchiveMember(_) => write!(f, "Failed to parse archive member"),
197            Error::InvalidInputKind => write!(f, "Input is not an archive or elf object"),
198            Error::DecompressData(_) => write!(f, "Failed to decompress compressed section"),
199            Error::NamelessSection(_, offset) => {
200                write!(f, "Section without name at offset 0x{:08x}", offset)
201            }
202            Error::RelocationWithInvalidSymbol(section, offset) => write!(
203                f,
204                "Relocation with invalid symbol for section `{}` at offset 0x{:08x}",
205                section, offset
206            ),
207            Error::MultipleRelocations(section, offset) => write!(
208                f,
209                "Multiple relocations for section `{}` at offset 0x{:08x}",
210                section, offset
211            ),
212            Error::UnsupportedRelocation(section, offset) => write!(
213                f,
214                "Unsupported relocation for section {} at offset 0x{:08x}",
215                section, offset
216            ),
217            Error::MissingDwoName(id) => {
218                write!(f, "Missing path attribute to DWARF object (0x{:08x})", id)
219            }
220            Error::NoCompilationUnits => {
221                write!(f, "Input object has no compilation units")
222            }
223            Error::NoDie => {
224                write!(f, "No top-level debugging information entry in compilation/type unit")
225            }
226            Error::TopLevelDieNotUnit => {
227                write!(f, "Top-level debugging information entry is not a compilation/type unit")
228            }
229            Error::MissingRequiredSection(section) => {
230                write!(f, "Input object missing required section `{}`", section)
231            }
232            Error::ParseUnitAbbreviations(_) => write!(f, "Failed to parse unit abbreviations"),
233            Error::ParseUnitHeader(_) => write!(f, "Failed to parse unit header"),
234            Error::ParseUnit(_) => write!(f, "Failed to parse unit"),
235            Error::IncompatibleIndexVersion(section, format, actual) => {
236                write!(
237                    f,
238                    "Incompatible `{}` index version: found version {}, expected version {}",
239                    section, actual, format
240                )
241            }
242            Error::OffsetAtIndex(_, index) => {
243                write!(f, "Read offset at index {} of `.debug_str_offsets.dwo` section", index)
244            }
245            Error::StrAtOffset(_, offset) => {
246                write!(f, "Read string at offset 0x{:08x} of `.debug_str.dwo` section", offset)
247            }
248            Error::ParseIndex(_, section) => {
249                write!(f, "Failed to parse `{}` index section", section)
250            }
251            Error::UnitNotInIndex(unit) => {
252                write!(f, "Unit 0x{0:08x} from input package is not in its index", unit)
253            }
254            Error::RowNotInIndex(_, row) => {
255                write!(f, "Row {0} found in index's hash table not present in index", row)
256            }
257            Error::SectionNotInRow => write!(f, "Section not found in unit's row in index"),
258            Error::ContributionOutOfBounds(contribution, section_len) => {
259                write!(
260                    f,
261                    "Index contribution at offset 0x{:08x} with size 0x{:x} extends beyond section \
262                     of length 0x{:x}",
263                    contribution.offset.0, contribution.size, section_len
264                )
265            }
266            Error::EmptyUnit(unit) => {
267                write!(f, "Unit 0x{:08x} in input DWARF object with no data", unit)
268            }
269            Error::MultipleDebugInfoSection => {
270                write!(f, "Multiple `.debug_info.dwo` sections")
271            }
272            Error::MultipleDebugTypesSection => {
273                write!(f, "Multiple `.debug_types.dwo` sections in a package")
274            }
275            Error::NotSplitUnit => {
276                write!(f, "Regular compilation unit in object (missing dwo identifier)")
277            }
278            Error::DuplicateUnit(unit) => {
279                write!(f, "Duplicate split compilation unit (0x{:08x})", unit)
280            }
281            Error::MissingReferencedUnit(unit) => {
282                write!(f, "Unit 0x{:08x} referenced by executable was not found", unit)
283            }
284            Error::NoOutputObjectCreated => write!(f, "No output object was created from inputs"),
285            Error::MixedInputEncodings => write!(f, "Input objects haved mixed encodings"),
286            Error::UnsupportedLocListsEntry(s) => {
287                write!(f, "Unsupported DW_LLE value: {}", s)
288            }
289            Error::MalformedDebugInfo => write!(f, "Malformed `.debug_info.dwo` compilation unit"),
290            Error::UnsupportedForm(form) => {
291                write!(f, "Unsupported DWARF form 0x{:02x} during GC rewrite", form)
292            }
293            Error::UnexpectedSectionAbsoluteReference => {
294                write!(f, "A section-absolute reference was found in a .dwo file")
295            }
296            Error::GcNotInitialized => {
297                write!(f, "GC was requested but no executables were preprocessed")
298            }
299            Error::GcSharedDwarf4Ranges(dwo_id) => {
300                write!(
301                    f,
302                    "DWARF4 .debug_ranges for {dwo_id:?} is supplied by multiple executables; \
303                     cannot safely GC"
304                )
305            }
306            Error::Io(e) => fmt::Display::fmt(e, f),
307            Error::ObjectRead(e) => fmt::Display::fmt(e, f),
308            Error::ObjectWrite(e) => fmt::Display::fmt(e, f),
309            Error::GimliRead(e) => fmt::Display::fmt(e, f),
310            Error::GimliWrite(e) => fmt::Display::fmt(e, f),
311        }
312    }
313}
314
315impl From<std::io::Error> for Error {
316    fn from(source: std::io::Error) -> Self {
317        Error::Io(source)
318    }
319}
320
321impl From<object::Error> for Error {
322    fn from(source: object::Error) -> Self {
323        Error::ObjectRead(source)
324    }
325}
326
327impl From<object::write::Error> for Error {
328    fn from(source: object::write::Error) -> Self {
329        Error::ObjectWrite(source)
330    }
331}
332
333impl From<gimli::read::Error> for Error {
334    fn from(source: gimli::read::Error) -> Self {
335        Error::GimliRead(source)
336    }
337}
338
339impl From<gimli::write::Error> for Error {
340    fn from(source: gimli::write::Error) -> Self {
341        Error::GimliWrite(source)
342    }
343}