1 //! Read DWARF debugging information. 2 //! 3 //! * [Example Usage](#example-usage) 4 //! * [API Structure](#api-structure) 5 //! * [Using with `FallibleIterator`](#using-with-fallibleiterator) 6 //! 7 //! ## Example Usage 8 //! 9 //! Print out all of the functions in the debuggee program: 10 //! 11 //! ```rust,no_run 12 //! # fn example() -> Result<(), gimli::Error> { 13 //! # type R = gimli::EndianSlice<'static, gimli::LittleEndian>; 14 //! # let get_file_section_reader = |name| -> Result<R, gimli::Error> { unimplemented!() }; 15 //! # let get_sup_file_section_reader = |name| -> Result<R, gimli::Error> { unimplemented!() }; 16 //! // Read the DWARF sections with whatever object loader you're using. 17 //! // These closures should return a `Reader` instance (e.g. `EndianSlice`). 18 //! let loader = |section: gimli::SectionId| { get_file_section_reader(section.name()) }; 19 //! let sup_loader = |section: gimli::SectionId| { get_sup_file_section_reader(section.name()) }; 20 //! let mut dwarf = gimli::Dwarf::load(loader)?; 21 //! dwarf.load_sup(sup_loader)?; 22 //! 23 //! // Iterate over all compilation units. 24 //! let mut iter = dwarf.units(); 25 //! while let Some(header) = iter.next()? { 26 //! // Parse the abbreviations and other information for this compilation unit. 27 //! let unit = dwarf.unit(header)?; 28 //! 29 //! // Iterate over all of this compilation unit's entries. 30 //! let mut entries = unit.entries(); 31 //! while let Some((_, entry)) = entries.next_dfs()? { 32 //! // If we find an entry for a function, print it. 33 //! if entry.tag() == gimli::DW_TAG_subprogram { 34 //! println!("Found a function: {:?}", entry); 35 //! } 36 //! } 37 //! } 38 //! # unreachable!() 39 //! # } 40 //! ``` 41 //! 42 //! Full example programs: 43 //! 44 //! * [A simple parser](https://github.com/gimli-rs/gimli/blob/master/examples/simple.rs) 45 //! 46 //! * [A `dwarfdump` 47 //! clone](https://github.com/gimli-rs/gimli/blob/master/examples/dwarfdump.rs) 48 //! 49 //! * [An `addr2line` clone](https://github.com/gimli-rs/addr2line) 50 //! 51 //! * [`ddbug`](https://github.com/philipc/ddbug), a utility giving insight into 52 //! code generation by making debugging information readable 53 //! 54 //! * [`dwprod`](https://github.com/fitzgen/dwprod), a tiny utility to list the 55 //! compilers used to create each compilation unit within a shared library or 56 //! executable (via `DW_AT_producer`) 57 //! 58 //! * [`dwarf-validate`](https://github.com/gimli-rs/gimli/blob/master/examples/dwarf-validate.rs), 59 //! a program to validate the integrity of some DWARF and its references 60 //! between sections and compilation units. 61 //! 62 //! ## API Structure 63 //! 64 //! * Basic familiarity with DWARF is assumed. 65 //! 66 //! * The [`Dwarf`](./struct.Dwarf.html) type contains the commonly used DWARF 67 //! sections. It has methods that simplify access to debugging data that spans 68 //! multiple sections. Use of this type is optional, but recommended. 69 //! 70 //! * Each section gets its own type. Consider these types the entry points to 71 //! the library: 72 //! 73 //! * [`DebugAbbrev`](./struct.DebugAbbrev.html): The `.debug_abbrev` section. 74 //! 75 //! * [`DebugAddr`](./struct.DebugAddr.html): The `.debug_addr` section. 76 //! 77 //! * [`DebugAranges`](./struct.DebugAranges.html): The `.debug_aranges` 78 //! section. 79 //! 80 //! * [`DebugFrame`](./struct.DebugFrame.html): The `.debug_frame` section. 81 //! 82 //! * [`DebugInfo`](./struct.DebugInfo.html): The `.debug_info` section. 83 //! 84 //! * [`DebugLine`](./struct.DebugLine.html): The `.debug_line` section. 85 //! 86 //! * [`DebugLineStr`](./struct.DebugLineStr.html): The `.debug_line_str` section. 87 //! 88 //! * [`DebugLoc`](./struct.DebugLoc.html): The `.debug_loc` section. 89 //! 90 //! * [`DebugLocLists`](./struct.DebugLocLists.html): The `.debug_loclists` section. 91 //! 92 //! * [`DebugPubNames`](./struct.DebugPubNames.html): The `.debug_pubnames` 93 //! section. 94 //! 95 //! * [`DebugPubTypes`](./struct.DebugPubTypes.html): The `.debug_pubtypes` 96 //! section. 97 //! 98 //! * [`DebugRanges`](./struct.DebugRanges.html): The `.debug_ranges` section. 99 //! 100 //! * [`DebugRngLists`](./struct.DebugRngLists.html): The `.debug_rnglists` section. 101 //! 102 //! * [`DebugStr`](./struct.DebugStr.html): The `.debug_str` section. 103 //! 104 //! * [`DebugStrOffsets`](./struct.DebugStrOffsets.html): The `.debug_str_offsets` section. 105 //! 106 //! * [`DebugTypes`](./struct.DebugTypes.html): The `.debug_types` section. 107 //! 108 //! * [`DebugCuIndex`](./struct.DebugCuIndex.html): The `.debug_cu_index` section. 109 //! 110 //! * [`DebugTuIndex`](./struct.DebugTuIndex.html): The `.debug_tu_index` section. 111 //! 112 //! * [`EhFrame`](./struct.EhFrame.html): The `.eh_frame` section. 113 //! 114 //! * [`EhFrameHdr`](./struct.EhFrameHdr.html): The `.eh_frame_hdr` section. 115 //! 116 //! * Each section type exposes methods for accessing the debugging data encoded 117 //! in that section. For example, the [`DebugInfo`](./struct.DebugInfo.html) 118 //! struct has the [`units`](./struct.DebugInfo.html#method.units) method for 119 //! iterating over the compilation units defined within it. 120 //! 121 //! * Offsets into a section are strongly typed: an offset into `.debug_info` is 122 //! the [`DebugInfoOffset`](./struct.DebugInfoOffset.html) type. It cannot be 123 //! used to index into the [`DebugLine`](./struct.DebugLine.html) type because 124 //! `DebugLine` represents the `.debug_line` section. There are similar types 125 //! for offsets relative to a compilation unit rather than a section. 126 //! 127 //! ## Using with `FallibleIterator` 128 //! 129 //! The standard library's `Iterator` trait and related APIs do not play well 130 //! with iterators where the `next` operation is fallible. One can make the 131 //! `Iterator`'s associated `Item` type be a `Result<T, E>`, however the 132 //! provided methods cannot gracefully handle the case when an `Err` is 133 //! returned. 134 //! 135 //! This situation led to the 136 //! [`fallible-iterator`](https://crates.io/crates/fallible-iterator) crate's 137 //! existence. You can read more of the rationale for its existence in its 138 //! docs. The crate provides the helpers you have come to expect (eg `map`, 139 //! `filter`, etc) for iterators that can fail. 140 //! 141 //! `gimli`'s many lazy parsing iterators are a perfect match for the 142 //! `fallible-iterator` crate's `FallibleIterator` trait because parsing is not 143 //! done eagerly. Parse errors later in the input might only be discovered after 144 //! having iterated through many items. 145 //! 146 //! To use `gimli` iterators with `FallibleIterator`, import the crate and trait 147 //! into your code: 148 //! 149 //! ``` 150 //! # #[cfg(feature = "fallible-iterator")] 151 //! # fn foo() { 152 //! // Use the `FallibleIterator` trait so its methods are in scope! 153 //! use fallible_iterator::FallibleIterator; 154 //! use gimli::{DebugAranges, EndianSlice, LittleEndian}; 155 //! 156 //! fn find_sum_of_address_range_lengths(aranges: DebugAranges<EndianSlice<LittleEndian>>) 157 //! -> gimli::Result<u64> 158 //! { 159 //! // `DebugAranges::headers` returns a `FallibleIterator`! 160 //! aranges.headers() 161 //! // `flat_map` is provided by `FallibleIterator`! 162 //! .flat_map(|header| Ok(header.entries())) 163 //! // `map` is provided by `FallibleIterator`! 164 //! .map(|arange| Ok(arange.length())) 165 //! // `fold` is provided by `FallibleIterator`! 166 //! .fold(0, |sum, len| Ok(sum + len)) 167 //! } 168 //! # } 169 //! # fn main() {} 170 //! ``` 171 172 use core::fmt::{self, Debug}; 173 use core::result; 174 #[cfg(feature = "std")] 175 use std::{error, io}; 176 177 use crate::common::{Register, SectionId}; 178 use crate::constants; 179 180 mod util; 181 pub use util::*; 182 183 mod addr; 184 pub use self::addr::*; 185 186 mod cfi; 187 pub use self::cfi::*; 188 189 #[cfg(feature = "read")] 190 mod dwarf; 191 #[cfg(feature = "read")] 192 pub use self::dwarf::*; 193 194 mod endian_slice; 195 pub use self::endian_slice::*; 196 197 #[cfg(feature = "endian-reader")] 198 mod endian_reader; 199 #[cfg(feature = "endian-reader")] 200 pub use self::endian_reader::*; 201 202 mod reader; 203 pub use self::reader::*; 204 205 #[cfg(feature = "read")] 206 mod abbrev; 207 #[cfg(feature = "read")] 208 pub use self::abbrev::*; 209 210 mod aranges; 211 pub use self::aranges::*; 212 213 mod index; 214 pub use self::index::*; 215 216 #[cfg(feature = "read")] 217 mod line; 218 #[cfg(feature = "read")] 219 pub use self::line::*; 220 221 mod lists; 222 223 mod loclists; 224 pub use self::loclists::*; 225 226 #[cfg(feature = "read")] 227 mod lookup; 228 229 mod op; 230 pub use self::op::*; 231 232 #[cfg(feature = "read")] 233 mod pubnames; 234 #[cfg(feature = "read")] 235 pub use self::pubnames::*; 236 237 #[cfg(feature = "read")] 238 mod pubtypes; 239 #[cfg(feature = "read")] 240 pub use self::pubtypes::*; 241 242 mod rnglists; 243 pub use self::rnglists::*; 244 245 mod str; 246 pub use self::str::*; 247 248 /// An offset into the current compilation or type unit. 249 #[derive(Debug, Clone, Copy, PartialEq, Eq, Ord, PartialOrd, Hash)] 250 pub struct UnitOffset<T = usize>(pub T); 251 252 #[cfg(feature = "read")] 253 mod unit; 254 #[cfg(feature = "read")] 255 pub use self::unit::*; 256 257 mod value; 258 pub use self::value::*; 259 260 /// Indicates that storage should be allocated on heap. 261 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 262 pub struct StoreOnHeap; 263 264 /// `EndianBuf` has been renamed to `EndianSlice`. For ease of upgrading across 265 /// `gimli` versions, we export this type alias. 266 #[deprecated(note = "EndianBuf has been renamed to EndianSlice, use that instead.")] 267 pub type EndianBuf<'input, Endian> = EndianSlice<'input, Endian>; 268 269 /// An error that occurred when parsing. 270 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 271 pub enum Error { 272 /// An I/O error occurred while reading. 273 Io, 274 /// Found a PC relative pointer, but the section base is undefined. 275 PcRelativePointerButSectionBaseIsUndefined, 276 /// Found a `.text` relative pointer, but the `.text` base is undefined. 277 TextRelativePointerButTextBaseIsUndefined, 278 /// Found a data relative pointer, but the data base is undefined. 279 DataRelativePointerButDataBaseIsUndefined, 280 /// Found a function relative pointer in a context that does not have a 281 /// function base. 282 FuncRelativePointerInBadContext, 283 /// Cannot parse a pointer with a `DW_EH_PE_omit` encoding. 284 CannotParseOmitPointerEncoding, 285 /// An error parsing an unsigned LEB128 value. 286 BadUnsignedLeb128, 287 /// An error parsing a signed LEB128 value. 288 BadSignedLeb128, 289 /// An abbreviation declared that its tag is zero, but zero is reserved for 290 /// null records. 291 AbbreviationTagZero, 292 /// An attribute specification declared that its form is zero, but zero is 293 /// reserved for null records. 294 AttributeFormZero, 295 /// The abbreviation's has-children byte was not one of 296 /// `DW_CHILDREN_{yes,no}`. 297 BadHasChildren, 298 /// The specified length is impossible. 299 BadLength, 300 /// Found an unknown `DW_FORM_*` type. 301 UnknownForm, 302 /// Expected a zero, found something else. 303 ExpectedZero, 304 /// Found an abbreviation code that has already been used. 305 DuplicateAbbreviationCode, 306 /// Found a duplicate arange. 307 DuplicateArange, 308 /// Found an unknown reserved length value. 309 UnknownReservedLength, 310 /// Found an unknown DWARF version. 311 UnknownVersion(u64), 312 /// Found a record with an unknown abbreviation code. 313 UnknownAbbreviation, 314 /// Hit the end of input before it was expected. 315 UnexpectedEof(ReaderOffsetId), 316 /// Read a null entry before it was expected. 317 UnexpectedNull, 318 /// Found an unknown standard opcode. 319 UnknownStandardOpcode(constants::DwLns), 320 /// Found an unknown extended opcode. 321 UnknownExtendedOpcode(constants::DwLne), 322 /// The specified address size is not supported. 323 UnsupportedAddressSize(u8), 324 /// The specified offset size is not supported. 325 UnsupportedOffsetSize(u8), 326 /// The specified field size is not supported. 327 UnsupportedFieldSize(u8), 328 /// The minimum instruction length must not be zero. 329 MinimumInstructionLengthZero, 330 /// The maximum operations per instruction must not be zero. 331 MaximumOperationsPerInstructionZero, 332 /// The line range must not be zero. 333 LineRangeZero, 334 /// The opcode base must not be zero. 335 OpcodeBaseZero, 336 /// Found an invalid UTF-8 string. 337 BadUtf8, 338 /// Expected to find the CIE ID, but found something else. 339 NotCieId, 340 /// Expected to find a pointer to a CIE, but found the CIE ID instead. 341 NotCiePointer, 342 /// Expected to find a pointer to an FDE, but found a CIE instead. 343 NotFdePointer, 344 /// Invalid branch target for a DW_OP_bra or DW_OP_skip. 345 BadBranchTarget(u64), 346 /// DW_OP_push_object_address used but no address passed in. 347 InvalidPushObjectAddress, 348 /// Not enough items on the stack when evaluating an expression. 349 NotEnoughStackItems, 350 /// Too many iterations to compute the expression. 351 TooManyIterations, 352 /// An unrecognized operation was found while parsing a DWARF 353 /// expression. 354 InvalidExpression(constants::DwOp), 355 /// An unsupported operation was found while evaluating a DWARF expression. 356 UnsupportedEvaluation, 357 /// The expression had a piece followed by an expression 358 /// terminator without a piece. 359 InvalidPiece, 360 /// An expression-terminating operation was followed by something 361 /// other than the end of the expression or a piece operation. 362 InvalidExpressionTerminator(u64), 363 /// Division or modulus by zero when evaluating an expression. 364 DivisionByZero, 365 /// An expression operation used mismatching types. 366 TypeMismatch, 367 /// An expression operation required an integral type but saw a 368 /// floating point type. 369 IntegralTypeRequired, 370 /// An expression operation used types that are not supported. 371 UnsupportedTypeOperation, 372 /// The shift value in an expression must be a non-negative integer. 373 InvalidShiftExpression, 374 /// An unknown DW_CFA_* instruction. 375 UnknownCallFrameInstruction(constants::DwCfa), 376 /// The end of an address range was before the beginning. 377 InvalidAddressRange, 378 /// The end offset of a loc list entry was before the beginning. 379 InvalidLocationAddressRange, 380 /// Encountered a call frame instruction in a context in which it is not 381 /// valid. 382 CfiInstructionInInvalidContext, 383 /// When evaluating call frame instructions, found a `DW_CFA_restore_state` 384 /// stack pop instruction, but the stack was empty, and had nothing to pop. 385 PopWithEmptyStack, 386 /// Do not have unwind info for the given address. 387 NoUnwindInfoForAddress, 388 /// An offset value was larger than the maximum supported value. 389 UnsupportedOffset, 390 /// The given pointer encoding is either unknown or invalid. 391 UnknownPointerEncoding, 392 /// Did not find an entry at the given offset. 393 NoEntryAtGivenOffset, 394 /// The given offset is out of bounds. 395 OffsetOutOfBounds, 396 /// Found an unknown CFI augmentation. 397 UnknownAugmentation, 398 /// We do not support the given pointer encoding yet. 399 UnsupportedPointerEncoding, 400 /// Registers larger than `u16` are not supported. 401 UnsupportedRegister(u64), 402 /// The CFI program defined more register rules than we have storage for. 403 TooManyRegisterRules, 404 /// Attempted to push onto the CFI or evaluation stack, but it was already 405 /// at full capacity. 406 StackFull, 407 /// The `.eh_frame_hdr` binary search table claims to be variable-length encoded, 408 /// which makes binary search impossible. 409 VariableLengthSearchTable, 410 /// The `DW_UT_*` value for this unit is not supported yet. 411 UnsupportedUnitType, 412 /// Ranges using AddressIndex are not supported yet. 413 UnsupportedAddressIndex, 414 /// Nonzero segment selector sizes aren't supported yet. 415 UnsupportedSegmentSize, 416 /// A compilation unit or type unit is missing its top level DIE. 417 MissingUnitDie, 418 /// A DIE attribute used an unsupported form. 419 UnsupportedAttributeForm, 420 /// Missing DW_LNCT_path in file entry format. 421 MissingFileEntryFormatPath, 422 /// Expected an attribute value to be a string form. 423 ExpectedStringAttributeValue, 424 /// `DW_FORM_implicit_const` used in an invalid context. 425 InvalidImplicitConst, 426 /// Invalid section count in `.dwp` index. 427 InvalidIndexSectionCount, 428 /// Invalid slot count in `.dwp` index. 429 InvalidIndexSlotCount, 430 /// Invalid hash row in `.dwp` index. 431 InvalidIndexRow, 432 /// Unknown section type in `.dwp` index. 433 UnknownIndexSection, 434 } 435 436 impl fmt::Display for Error { 437 #[inline] fmt(&self, f: &mut fmt::Formatter) -> ::core::result::Result<(), fmt::Error>438 fn fmt(&self, f: &mut fmt::Formatter) -> ::core::result::Result<(), fmt::Error> { 439 write!(f, "{}", self.description()) 440 } 441 } 442 443 impl Error { 444 /// A short description of the error. description(&self) -> &str445 pub fn description(&self) -> &str { 446 match *self { 447 Error::Io => "An I/O error occurred while reading.", 448 Error::PcRelativePointerButSectionBaseIsUndefined => { 449 "Found a PC relative pointer, but the section base is undefined." 450 } 451 Error::TextRelativePointerButTextBaseIsUndefined => { 452 "Found a `.text` relative pointer, but the `.text` base is undefined." 453 } 454 Error::DataRelativePointerButDataBaseIsUndefined => { 455 "Found a data relative pointer, but the data base is undefined." 456 } 457 Error::FuncRelativePointerInBadContext => { 458 "Found a function relative pointer in a context that does not have a function base." 459 } 460 Error::CannotParseOmitPointerEncoding => { 461 "Cannot parse a pointer with a `DW_EH_PE_omit` encoding." 462 } 463 Error::BadUnsignedLeb128 => "An error parsing an unsigned LEB128 value", 464 Error::BadSignedLeb128 => "An error parsing a signed LEB128 value", 465 Error::AbbreviationTagZero => { 466 "An abbreviation declared that its tag is zero, 467 but zero is reserved for null records" 468 } 469 Error::AttributeFormZero => { 470 "An attribute specification declared that its form is zero, 471 but zero is reserved for null records" 472 } 473 Error::BadHasChildren => { 474 "The abbreviation's has-children byte was not one of 475 `DW_CHILDREN_{yes,no}`" 476 } 477 Error::BadLength => "The specified length is impossible", 478 Error::UnknownForm => "Found an unknown `DW_FORM_*` type", 479 Error::ExpectedZero => "Expected a zero, found something else", 480 Error::DuplicateAbbreviationCode => { 481 "Found an abbreviation code that has already been used" 482 } 483 Error::DuplicateArange => "Found a duplicate arange", 484 Error::UnknownReservedLength => "Found an unknown reserved length value", 485 Error::UnknownVersion(_) => "Found an unknown DWARF version", 486 Error::UnknownAbbreviation => "Found a record with an unknown abbreviation code", 487 Error::UnexpectedEof(_) => "Hit the end of input before it was expected", 488 Error::UnexpectedNull => "Read a null entry before it was expected.", 489 Error::UnknownStandardOpcode(_) => "Found an unknown standard opcode", 490 Error::UnknownExtendedOpcode(_) => "Found an unknown extended opcode", 491 Error::UnsupportedAddressSize(_) => "The specified address size is not supported", 492 Error::UnsupportedOffsetSize(_) => "The specified offset size is not supported", 493 Error::UnsupportedFieldSize(_) => "The specified field size is not supported", 494 Error::MinimumInstructionLengthZero => { 495 "The minimum instruction length must not be zero." 496 } 497 Error::MaximumOperationsPerInstructionZero => { 498 "The maximum operations per instruction must not be zero." 499 } 500 Error::LineRangeZero => "The line range must not be zero.", 501 Error::OpcodeBaseZero => "The opcode base must not be zero.", 502 Error::BadUtf8 => "Found an invalid UTF-8 string.", 503 Error::NotCieId => "Expected to find the CIE ID, but found something else.", 504 Error::NotCiePointer => "Expected to find a CIE pointer, but found the CIE ID instead.", 505 Error::NotFdePointer => { 506 "Expected to find an FDE pointer, but found a CIE pointer instead." 507 } 508 Error::BadBranchTarget(_) => "Invalid branch target in DWARF expression", 509 Error::InvalidPushObjectAddress => { 510 "DW_OP_push_object_address used but no object address given" 511 } 512 Error::NotEnoughStackItems => "Not enough items on stack when evaluating expression", 513 Error::TooManyIterations => "Too many iterations to evaluate DWARF expression", 514 Error::InvalidExpression(_) => "Invalid opcode in DWARF expression", 515 Error::UnsupportedEvaluation => "Unsupported operation when evaluating expression", 516 Error::InvalidPiece => { 517 "DWARF expression has piece followed by non-piece expression at end" 518 } 519 Error::InvalidExpressionTerminator(_) => "Expected DW_OP_piece or DW_OP_bit_piece", 520 Error::DivisionByZero => "Division or modulus by zero when evaluating expression", 521 Error::TypeMismatch => "Type mismatch when evaluating expression", 522 Error::IntegralTypeRequired => "Integral type expected when evaluating expression", 523 Error::UnsupportedTypeOperation => { 524 "An expression operation used types that are not supported" 525 } 526 Error::InvalidShiftExpression => { 527 "The shift value in an expression must be a non-negative integer." 528 } 529 Error::UnknownCallFrameInstruction(_) => "An unknown DW_CFA_* instructiion", 530 Error::InvalidAddressRange => { 531 "The end of an address range must not be before the beginning." 532 } 533 Error::InvalidLocationAddressRange => { 534 "The end offset of a location list entry must not be before the beginning." 535 } 536 Error::CfiInstructionInInvalidContext => { 537 "Encountered a call frame instruction in a context in which it is not valid." 538 } 539 Error::PopWithEmptyStack => { 540 "When evaluating call frame instructions, found a `DW_CFA_restore_state` stack pop \ 541 instruction, but the stack was empty, and had nothing to pop." 542 } 543 Error::NoUnwindInfoForAddress => "Do not have unwind info for the given address.", 544 Error::UnsupportedOffset => { 545 "An offset value was larger than the maximum supported value." 546 } 547 Error::UnknownPointerEncoding => { 548 "The given pointer encoding is either unknown or invalid." 549 } 550 Error::NoEntryAtGivenOffset => "Did not find an entry at the given offset.", 551 Error::OffsetOutOfBounds => "The given offset is out of bounds.", 552 Error::UnknownAugmentation => "Found an unknown CFI augmentation.", 553 Error::UnsupportedPointerEncoding => { 554 "We do not support the given pointer encoding yet." 555 } 556 Error::UnsupportedRegister(_) => "Registers larger than `u16` are not supported.", 557 Error::TooManyRegisterRules => { 558 "The CFI program defined more register rules than we have storage for." 559 } 560 Error::StackFull => { 561 "Attempted to push onto the CFI stack, but it was already at full capacity." 562 } 563 Error::VariableLengthSearchTable => { 564 "The `.eh_frame_hdr` binary search table claims to be variable-length encoded, \ 565 which makes binary search impossible." 566 } 567 Error::UnsupportedUnitType => "The `DW_UT_*` value for this unit is not supported yet", 568 Error::UnsupportedAddressIndex => "Ranges involving AddressIndex are not supported yet", 569 Error::UnsupportedSegmentSize => "Nonzero segment size not supported yet", 570 Error::MissingUnitDie => { 571 "A compilation unit or type unit is missing its top level DIE." 572 } 573 Error::UnsupportedAttributeForm => "A DIE attribute used an unsupported form.", 574 Error::MissingFileEntryFormatPath => "Missing DW_LNCT_path in file entry format.", 575 Error::ExpectedStringAttributeValue => { 576 "Expected an attribute value to be a string form." 577 } 578 Error::InvalidImplicitConst => "DW_FORM_implicit_const used in an invalid context.", 579 Error::InvalidIndexSectionCount => "Invalid section count in `.dwp` index.", 580 Error::InvalidIndexSlotCount => "Invalid slot count in `.dwp` index.", 581 Error::InvalidIndexRow => "Invalid hash row in `.dwp` index.", 582 Error::UnknownIndexSection => "Unknown section type in `.dwp` index.", 583 } 584 } 585 } 586 587 #[cfg(feature = "std")] 588 impl error::Error for Error {} 589 590 #[cfg(feature = "std")] 591 impl From<io::Error> for Error { from(_: io::Error) -> Self592 fn from(_: io::Error) -> Self { 593 Error::Io 594 } 595 } 596 597 /// The result of a parse. 598 pub type Result<T> = result::Result<T, Error>; 599 600 /// A convenience trait for loading DWARF sections from object files. To be 601 /// used like: 602 /// 603 /// ``` 604 /// use gimli::{DebugInfo, EndianSlice, LittleEndian, Reader, Section}; 605 /// 606 /// let buf = [0x00, 0x01, 0x02, 0x03]; 607 /// let reader = EndianSlice::new(&buf, LittleEndian); 608 /// let loader = |name| -> Result<_, ()> { Ok(reader) }; 609 /// 610 /// let debug_info: DebugInfo<_> = Section::load(loader).unwrap(); 611 /// ``` 612 pub trait Section<R>: From<R> { 613 /// Returns the section id for this type. id() -> SectionId614 fn id() -> SectionId; 615 616 /// Returns the ELF section name for this type. section_name() -> &'static str617 fn section_name() -> &'static str { 618 Self::id().name() 619 } 620 621 /// Returns the ELF section name (if any) for this type when used in a dwo 622 /// file. dwo_section_name() -> Option<&'static str>623 fn dwo_section_name() -> Option<&'static str> { 624 Self::id().dwo_name() 625 } 626 627 /// Try to load the section using the given loader function. load<F, E>(f: F) -> core::result::Result<Self, E> where F: FnOnce(SectionId) -> core::result::Result<R, E>,628 fn load<F, E>(f: F) -> core::result::Result<Self, E> 629 where 630 F: FnOnce(SectionId) -> core::result::Result<R, E>, 631 { 632 f(Self::id()).map(From::from) 633 } 634 635 /// Returns the `Reader` for this section. reader(&self) -> &R where R: Reader636 fn reader(&self) -> &R 637 where 638 R: Reader; 639 640 /// Returns the subrange of the section that is the contribution of 641 /// a unit in a `.dwp` file. dwp_range(&self, offset: u32, size: u32) -> Result<Self> where R: Reader,642 fn dwp_range(&self, offset: u32, size: u32) -> Result<Self> 643 where 644 R: Reader, 645 { 646 let mut data = self.reader().clone(); 647 data.skip(R::Offset::from_u32(offset))?; 648 data.truncate(R::Offset::from_u32(size))?; 649 Ok(data.into()) 650 } 651 652 /// Returns the `Reader` for this section. lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> where R: Reader,653 fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> 654 where 655 R: Reader, 656 { 657 self.reader() 658 .lookup_offset_id(id) 659 .map(|offset| (Self::id(), offset)) 660 } 661 } 662 663 impl Register { from_u64(x: u64) -> Result<Register>664 pub(crate) fn from_u64(x: u64) -> Result<Register> { 665 let y = x as u16; 666 if u64::from(y) == x { 667 Ok(Register(y)) 668 } else { 669 Err(Error::UnsupportedRegister(x)) 670 } 671 } 672 } 673 674 #[cfg(test)] 675 mod tests { 676 use super::*; 677 use crate::common::Format; 678 use crate::endianity::LittleEndian; 679 use test_assembler::{Endian, Section}; 680 681 #[test] test_parse_initial_length_32_ok()682 fn test_parse_initial_length_32_ok() { 683 let section = Section::with_endian(Endian::Little).L32(0x7856_3412); 684 let buf = section.get_contents().unwrap(); 685 686 let input = &mut EndianSlice::new(&buf, LittleEndian); 687 match input.read_initial_length() { 688 Ok((length, format)) => { 689 assert_eq!(input.len(), 0); 690 assert_eq!(format, Format::Dwarf32); 691 assert_eq!(0x7856_3412, length); 692 } 693 otherwise => panic!("Unexpected result: {:?}", otherwise), 694 } 695 } 696 697 #[test] test_parse_initial_length_64_ok()698 fn test_parse_initial_length_64_ok() { 699 let section = Section::with_endian(Endian::Little) 700 // Dwarf_64_INITIAL_UNIT_LENGTH 701 .L32(0xffff_ffff) 702 // Actual length 703 .L64(0xffde_bc9a_7856_3412); 704 let buf = section.get_contents().unwrap(); 705 let input = &mut EndianSlice::new(&buf, LittleEndian); 706 707 #[cfg(target_pointer_width = "64")] 708 match input.read_initial_length() { 709 Ok((length, format)) => { 710 assert_eq!(input.len(), 0); 711 assert_eq!(format, Format::Dwarf64); 712 assert_eq!(0xffde_bc9a_7856_3412, length); 713 } 714 otherwise => panic!("Unexpected result: {:?}", otherwise), 715 } 716 717 #[cfg(target_pointer_width = "32")] 718 match input.read_initial_length() { 719 Err(Error::UnsupportedOffset) => {} 720 otherwise => panic!("Unexpected result: {:?}", otherwise), 721 }; 722 } 723 724 #[test] test_parse_initial_length_unknown_reserved_value()725 fn test_parse_initial_length_unknown_reserved_value() { 726 let section = Section::with_endian(Endian::Little).L32(0xffff_fffe); 727 let buf = section.get_contents().unwrap(); 728 729 let input = &mut EndianSlice::new(&buf, LittleEndian); 730 match input.read_initial_length() { 731 Err(Error::UnknownReservedLength) => assert!(true), 732 otherwise => panic!("Unexpected result: {:?}", otherwise), 733 }; 734 } 735 736 #[test] test_parse_initial_length_incomplete()737 fn test_parse_initial_length_incomplete() { 738 let buf = [0xff, 0xff, 0xff]; // Need at least 4 bytes. 739 740 let input = &mut EndianSlice::new(&buf, LittleEndian); 741 match input.read_initial_length() { 742 Err(Error::UnexpectedEof(_)) => assert!(true), 743 otherwise => panic!("Unexpected result: {:?}", otherwise), 744 }; 745 } 746 747 #[test] test_parse_initial_length_64_incomplete()748 fn test_parse_initial_length_64_incomplete() { 749 let section = Section::with_endian(Endian::Little) 750 // Dwarf_64_INITIAL_UNIT_LENGTH 751 .L32(0xffff_ffff) 752 // Actual length is not long enough. 753 .L32(0x7856_3412); 754 let buf = section.get_contents().unwrap(); 755 756 let input = &mut EndianSlice::new(&buf, LittleEndian); 757 match input.read_initial_length() { 758 Err(Error::UnexpectedEof(_)) => assert!(true), 759 otherwise => panic!("Unexpected result: {:?}", otherwise), 760 }; 761 } 762 763 #[test] test_parse_offset_32()764 fn test_parse_offset_32() { 765 let section = Section::with_endian(Endian::Little).L32(0x0123_4567); 766 let buf = section.get_contents().unwrap(); 767 768 let input = &mut EndianSlice::new(&buf, LittleEndian); 769 match input.read_offset(Format::Dwarf32) { 770 Ok(val) => { 771 assert_eq!(input.len(), 0); 772 assert_eq!(val, 0x0123_4567); 773 } 774 otherwise => panic!("Unexpected result: {:?}", otherwise), 775 }; 776 } 777 778 #[test] test_parse_offset_64_small()779 fn test_parse_offset_64_small() { 780 let section = Section::with_endian(Endian::Little).L64(0x0123_4567); 781 let buf = section.get_contents().unwrap(); 782 783 let input = &mut EndianSlice::new(&buf, LittleEndian); 784 match input.read_offset(Format::Dwarf64) { 785 Ok(val) => { 786 assert_eq!(input.len(), 0); 787 assert_eq!(val, 0x0123_4567); 788 } 789 otherwise => panic!("Unexpected result: {:?}", otherwise), 790 }; 791 } 792 793 #[test] 794 #[cfg(target_pointer_width = "64")] test_parse_offset_64_large()795 fn test_parse_offset_64_large() { 796 let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef); 797 let buf = section.get_contents().unwrap(); 798 799 let input = &mut EndianSlice::new(&buf, LittleEndian); 800 match input.read_offset(Format::Dwarf64) { 801 Ok(val) => { 802 assert_eq!(input.len(), 0); 803 assert_eq!(val, 0x0123_4567_89ab_cdef); 804 } 805 otherwise => panic!("Unexpected result: {:?}", otherwise), 806 }; 807 } 808 809 #[test] 810 #[cfg(target_pointer_width = "32")] test_parse_offset_64_large()811 fn test_parse_offset_64_large() { 812 let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef); 813 let buf = section.get_contents().unwrap(); 814 815 let input = &mut EndianSlice::new(&buf, LittleEndian); 816 match input.read_offset(Format::Dwarf64) { 817 Err(Error::UnsupportedOffset) => assert!(true), 818 otherwise => panic!("Unexpected result: {:?}", otherwise), 819 }; 820 } 821 } 822