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