| 1 | use std::error::Error as StdError; |
| 2 | use std::fmt; |
| 3 | |
| 4 | pub(crate) type Result<T> = std::result::Result<T, Error>; |
| 5 | |
| 6 | /// Helper trait for converting an error to a `&dyn std::error::Error`. |
| 7 | pub trait AsDynError<'a> { |
| 8 | fn as_dyn_error(&self) -> &(dyn StdError + 'a); |
| 9 | } |
| 10 | |
| 11 | impl<'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 ] |
| 21 | pub 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 | |
| 120 | impl 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 | |
| 167 | impl 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 | |
| 266 | impl From<std::io::Error> for Error { |
| 267 | fn from(source: std::io::Error) -> Self { |
| 268 | Error::Io(source) |
| 269 | } |
| 270 | } |
| 271 | |
| 272 | impl From<object::Error> for Error { |
| 273 | fn from(source: object::Error) -> Self { |
| 274 | Error::ObjectRead(source) |
| 275 | } |
| 276 | } |
| 277 | |
| 278 | impl From<object::write::Error> for Error { |
| 279 | fn from(source: object::write::Error) -> Self { |
| 280 | Error::ObjectWrite(source) |
| 281 | } |
| 282 | } |
| 283 | |
| 284 | impl From<gimli::read::Error> for Error { |
| 285 | fn from(source: gimli::read::Error) -> Self { |
| 286 | Error::GimliRead(source) |
| 287 | } |
| 288 | } |
| 289 | |
| 290 | impl From<gimli::write::Error> for Error { |
| 291 | fn from(source: gimli::write::Error) -> Self { |
| 292 | Error::GimliWrite(source) |
| 293 | } |
| 294 | } |
| 295 | |