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}
295