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 lists; 203 204 mod loclists; 205 pub use self::loclists::*; 206 207 mod lookup; 208 209 mod op; 210 pub use self::op::*; 211 212 mod pubnames; 213 pub use self::pubnames::*; 214 215 mod pubtypes; 216 pub use self::pubtypes::*; 217 218 mod rnglists; 219 pub use self::rnglists::*; 220 221 mod str; 222 pub use self::str::*; 223 224 mod unit; 225 pub use self::unit::*; 226 227 mod value; 228 pub use self::value::*; 229 230 /// `EndianBuf` has been renamed to `EndianSlice`. For ease of upgrading across 231 /// `gimli` versions, we export this type alias. 232 #[deprecated(note = "EndianBuf has been renamed to EndianSlice, use that instead.")] 233 pub type EndianBuf<'input, Endian> = EndianSlice<'input, Endian>; 234 235 /// An error that occurred when parsing. 236 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 237 pub enum Error { 238 /// An I/O error occurred while reading. 239 Io, 240 /// Found a PC relative pointer, but the section base is undefined. 241 PcRelativePointerButSectionBaseIsUndefined, 242 /// Found a `.text` relative pointer, but the `.text` base is undefined. 243 TextRelativePointerButTextBaseIsUndefined, 244 /// Found a data relative pointer, but the data base is undefined. 245 DataRelativePointerButDataBaseIsUndefined, 246 /// Found a function relative pointer in a context that does not have a 247 /// function base. 248 FuncRelativePointerInBadContext, 249 /// Cannot parse a pointer with a `DW_EH_PE_omit` encoding. 250 CannotParseOmitPointerEncoding, 251 /// An error parsing an unsigned LEB128 value. 252 BadUnsignedLeb128, 253 /// An error parsing a signed LEB128 value. 254 BadSignedLeb128, 255 /// An abbreviation declared that its tag is zero, but zero is reserved for 256 /// null records. 257 AbbreviationTagZero, 258 /// An attribute specification declared that its form is zero, but zero is 259 /// reserved for null records. 260 AttributeFormZero, 261 /// The abbreviation's has-children byte was not one of 262 /// `DW_CHILDREN_{yes,no}`. 263 BadHasChildren, 264 /// The specified length is impossible. 265 BadLength, 266 /// Found an unknown `DW_FORM_*` type. 267 UnknownForm, 268 /// Expected a zero, found something else. 269 ExpectedZero, 270 /// Found an abbreviation code that has already been used. 271 DuplicateAbbreviationCode, 272 /// Found a duplicate arange. 273 DuplicateArange, 274 /// Found an unknown reserved length value. 275 UnknownReservedLength, 276 /// Found an unknown DWARF version. 277 UnknownVersion(u64), 278 /// Found a record with an unknown abbreviation code. 279 UnknownAbbreviation, 280 /// Hit the end of input before it was expected. 281 UnexpectedEof(ReaderOffsetId), 282 /// Read a null entry before it was expected. 283 UnexpectedNull, 284 /// Found an unknown standard opcode. 285 UnknownStandardOpcode(constants::DwLns), 286 /// Found an unknown extended opcode. 287 UnknownExtendedOpcode(constants::DwLne), 288 /// The specified address size is not supported. 289 UnsupportedAddressSize(u8), 290 /// The specified offset size is not supported. 291 UnsupportedOffsetSize(u8), 292 /// The specified field size is not supported. 293 UnsupportedFieldSize(u8), 294 /// The minimum instruction length must not be zero. 295 MinimumInstructionLengthZero, 296 /// The maximum operations per instruction must not be zero. 297 MaximumOperationsPerInstructionZero, 298 /// The line range must not be zero. 299 LineRangeZero, 300 /// The opcode base must not be zero. 301 OpcodeBaseZero, 302 /// Found an invalid UTF-8 string. 303 BadUtf8, 304 /// Expected to find the CIE ID, but found something else. 305 NotCieId, 306 /// Expected to find a pointer to a CIE, but found the CIE ID instead. 307 NotCiePointer, 308 /// Expected to find a pointer to an FDE, but found a CIE instead. 309 NotFdePointer, 310 /// Invalid branch target for a DW_OP_bra or DW_OP_skip. 311 BadBranchTarget(u64), 312 /// DW_OP_push_object_address used but no address passed in. 313 InvalidPushObjectAddress, 314 /// Not enough items on the stack when evaluating an expression. 315 NotEnoughStackItems, 316 /// Too many iterations to compute the expression. 317 TooManyIterations, 318 /// An unrecognized operation was found while parsing a DWARF 319 /// expression. 320 InvalidExpression(constants::DwOp), 321 /// The expression had a piece followed by an expression 322 /// terminator without a piece. 323 InvalidPiece, 324 /// An expression-terminating operation was followed by something 325 /// other than the end of the expression or a piece operation. 326 InvalidExpressionTerminator(u64), 327 /// Division or modulus by zero when evaluating an expression. 328 DivisionByZero, 329 /// An expression operation used mismatching types. 330 TypeMismatch, 331 /// An expression operation required an integral type but saw a 332 /// floating point type. 333 IntegralTypeRequired, 334 /// An expression operation used types that are not supported. 335 UnsupportedTypeOperation, 336 /// The shift value in an expression must be a non-negative integer. 337 InvalidShiftExpression, 338 /// An unknown DW_CFA_* instruction. 339 UnknownCallFrameInstruction(constants::DwCfa), 340 /// The end of an address range was before the beginning. 341 InvalidAddressRange, 342 /// The end offset of a loc list entry was before the beginning. 343 InvalidLocationAddressRange, 344 /// Encountered a call frame instruction in a context in which it is not 345 /// valid. 346 CfiInstructionInInvalidContext, 347 /// When evaluating call frame instructions, found a `DW_CFA_restore_state` 348 /// stack pop instruction, but the stack was empty, and had nothing to pop. 349 PopWithEmptyStack, 350 /// Do not have unwind info for the given address. 351 NoUnwindInfoForAddress, 352 /// An offset value was larger than the maximum supported value. 353 UnsupportedOffset, 354 /// The given pointer encoding is either unknown or invalid. 355 UnknownPointerEncoding, 356 /// Did not find an entry at the given offset. 357 NoEntryAtGivenOffset, 358 /// The given offset is out of bounds. 359 OffsetOutOfBounds, 360 /// Found an unknown CFI augmentation. 361 UnknownAugmentation, 362 /// We do not support the given pointer encoding yet. 363 UnsupportedPointerEncoding, 364 /// Registers larger than `u16` are not supported. 365 UnsupportedRegister(u64), 366 /// The CFI program defined more register rules than we have storage for. 367 TooManyRegisterRules, 368 /// Attempted to push onto the CFI stack, but it was already at full 369 /// capacity. 370 CfiStackFull, 371 /// The `.eh_frame_hdr` binary search table claims to be variable-length encoded, 372 /// which makes binary search impossible. 373 VariableLengthSearchTable, 374 /// The `DW_UT_*` value for this unit is not supported yet. 375 UnsupportedUnitType, 376 /// Ranges using AddressIndex are not supported yet. 377 UnsupportedAddressIndex, 378 /// Nonzero segment selector sizes aren't supported yet. 379 UnsupportedSegmentSize, 380 /// A compilation unit or type unit is missing its top level DIE. 381 MissingUnitDie, 382 /// A DIE attribute used an unsupported form. 383 UnsupportedAttributeForm, 384 /// Missing DW_LNCT_path in file entry format. 385 MissingFileEntryFormatPath, 386 /// Expected an attribute value to be a string form. 387 ExpectedStringAttributeValue, 388 /// `DW_FORM_implicit_const` used in an invalid context. 389 InvalidImplicitConst, 390 } 391 392 impl fmt::Display for Error { 393 #[inline] fmt(&self, f: &mut fmt::Formatter) -> ::core::result::Result<(), fmt::Error>394 fn fmt(&self, f: &mut fmt::Formatter) -> ::core::result::Result<(), fmt::Error> { 395 write!(f, "{}", self.description()) 396 } 397 } 398 399 impl Error { 400 /// A short description of the error. description(&self) -> &str401 pub fn description(&self) -> &str { 402 match *self { 403 Error::Io => "An I/O error occurred while reading.", 404 Error::PcRelativePointerButSectionBaseIsUndefined => { 405 "Found a PC relative pointer, but the section base is undefined." 406 } 407 Error::TextRelativePointerButTextBaseIsUndefined => { 408 "Found a `.text` relative pointer, but the `.text` base is undefined." 409 } 410 Error::DataRelativePointerButDataBaseIsUndefined => { 411 "Found a data relative pointer, but the data base is undefined." 412 } 413 Error::FuncRelativePointerInBadContext => { 414 "Found a function relative pointer in a context that does not have a function base." 415 } 416 Error::CannotParseOmitPointerEncoding => { 417 "Cannot parse a pointer with a `DW_EH_PE_omit` encoding." 418 } 419 Error::BadUnsignedLeb128 => "An error parsing an unsigned LEB128 value", 420 Error::BadSignedLeb128 => "An error parsing a signed LEB128 value", 421 Error::AbbreviationTagZero => { 422 "An abbreviation declared that its tag is zero, 423 but zero is reserved for null records" 424 } 425 Error::AttributeFormZero => { 426 "An attribute specification declared that its form is zero, 427 but zero is reserved for null records" 428 } 429 Error::BadHasChildren => { 430 "The abbreviation's has-children byte was not one of 431 `DW_CHILDREN_{yes,no}`" 432 } 433 Error::BadLength => "The specified length is impossible", 434 Error::UnknownForm => "Found an unknown `DW_FORM_*` type", 435 Error::ExpectedZero => "Expected a zero, found something else", 436 Error::DuplicateAbbreviationCode => { 437 "Found an abbreviation code that has already been used" 438 } 439 Error::DuplicateArange => "Found a duplicate arange", 440 Error::UnknownReservedLength => "Found an unknown reserved length value", 441 Error::UnknownVersion(_) => "Found an unknown DWARF version", 442 Error::UnknownAbbreviation => "Found a record with an unknown abbreviation code", 443 Error::UnexpectedEof(_) => "Hit the end of input before it was expected", 444 Error::UnexpectedNull => "Read a null entry before it was expected.", 445 Error::UnknownStandardOpcode(_) => "Found an unknown standard opcode", 446 Error::UnknownExtendedOpcode(_) => "Found an unknown extended opcode", 447 Error::UnsupportedAddressSize(_) => "The specified address size is not supported", 448 Error::UnsupportedOffsetSize(_) => "The specified offset size is not supported", 449 Error::UnsupportedFieldSize(_) => "The specified field size is not supported", 450 Error::MinimumInstructionLengthZero => { 451 "The minimum instruction length must not be zero." 452 } 453 Error::MaximumOperationsPerInstructionZero => { 454 "The maximum operations per instruction must not be zero." 455 } 456 Error::LineRangeZero => "The line range must not be zero.", 457 Error::OpcodeBaseZero => "The opcode base must not be zero.", 458 Error::BadUtf8 => "Found an invalid UTF-8 string.", 459 Error::NotCieId => "Expected to find the CIE ID, but found something else.", 460 Error::NotCiePointer => "Expected to find a CIE pointer, but found the CIE ID instead.", 461 Error::NotFdePointer => { 462 "Expected to find an FDE pointer, but found a CIE pointer instead." 463 } 464 Error::BadBranchTarget(_) => "Invalid branch target in DWARF expression", 465 Error::InvalidPushObjectAddress => { 466 "DW_OP_push_object_address used but no object address given" 467 } 468 Error::NotEnoughStackItems => "Not enough items on stack when evaluating expression", 469 Error::TooManyIterations => "Too many iterations to evaluate DWARF expression", 470 Error::InvalidExpression(_) => "Invalid opcode in DWARF expression", 471 Error::InvalidPiece => { 472 "DWARF expression has piece followed by non-piece expression at end" 473 } 474 Error::InvalidExpressionTerminator(_) => "Expected DW_OP_piece or DW_OP_bit_piece", 475 Error::DivisionByZero => "Division or modulus by zero when evaluating expression", 476 Error::TypeMismatch => "Type mismatch when evaluating expression", 477 Error::IntegralTypeRequired => "Integral type expected when evaluating expression", 478 Error::UnsupportedTypeOperation => { 479 "An expression operation used types that are not supported" 480 } 481 Error::InvalidShiftExpression => { 482 "The shift value in an expression must be a non-negative integer." 483 } 484 Error::UnknownCallFrameInstruction(_) => "An unknown DW_CFA_* instructiion", 485 Error::InvalidAddressRange => { 486 "The end of an address range must not be before the beginning." 487 } 488 Error::InvalidLocationAddressRange => { 489 "The end offset of a location list entry must not be before the beginning." 490 } 491 Error::CfiInstructionInInvalidContext => { 492 "Encountered a call frame instruction in a context in which it is not valid." 493 } 494 Error::PopWithEmptyStack => { 495 "When evaluating call frame instructions, found a `DW_CFA_restore_state` stack pop \ 496 instruction, but the stack was empty, and had nothing to pop." 497 } 498 Error::NoUnwindInfoForAddress => "Do not have unwind info for the given address.", 499 Error::UnsupportedOffset => { 500 "An offset value was larger than the maximum supported value." 501 } 502 Error::UnknownPointerEncoding => { 503 "The given pointer encoding is either unknown or invalid." 504 } 505 Error::NoEntryAtGivenOffset => "Did not find an entry at the given offset.", 506 Error::OffsetOutOfBounds => "The given offset is out of bounds.", 507 Error::UnknownAugmentation => "Found an unknown CFI augmentation.", 508 Error::UnsupportedPointerEncoding => { 509 "We do not support the given pointer encoding yet." 510 } 511 Error::UnsupportedRegister(_) => "Registers larger than `u16` are not supported.", 512 Error::TooManyRegisterRules => { 513 "The CFI program defined more register rules than we have storage for." 514 } 515 Error::CfiStackFull => { 516 "Attempted to push onto the CFI stack, but it was already at full capacity." 517 } 518 Error::VariableLengthSearchTable => { 519 "The `.eh_frame_hdr` binary search table claims to be variable-length encoded, \ 520 which makes binary search impossible." 521 } 522 Error::UnsupportedUnitType => "The `DW_UT_*` value for this unit is not supported yet", 523 Error::UnsupportedAddressIndex => "Ranges involving AddressIndex are not supported yet", 524 Error::UnsupportedSegmentSize => "Nonzero segment size not supported yet", 525 Error::MissingUnitDie => { 526 "A compilation unit or type unit is missing its top level DIE." 527 } 528 Error::UnsupportedAttributeForm => "A DIE attribute used an unsupported form.", 529 Error::MissingFileEntryFormatPath => "Missing DW_LNCT_path in file entry format.", 530 Error::ExpectedStringAttributeValue => { 531 "Expected an attribute value to be a string form." 532 } 533 Error::InvalidImplicitConst => "DW_FORM_implicit_const used in an invalid context.", 534 } 535 } 536 } 537 538 #[cfg(feature = "std")] 539 impl error::Error for Error {} 540 541 #[cfg(feature = "std")] 542 impl From<io::Error> for Error { from(_: io::Error) -> Self543 fn from(_: io::Error) -> Self { 544 Error::Io 545 } 546 } 547 548 /// The result of a parse. 549 pub type Result<T> = result::Result<T, Error>; 550 551 /// A convenience trait for loading DWARF sections from object files. To be 552 /// used like: 553 /// 554 /// ``` 555 /// use gimli::{DebugInfo, EndianSlice, LittleEndian, Reader, Section}; 556 /// 557 /// let buf = [0x00, 0x01, 0x02, 0x03]; 558 /// let reader = EndianSlice::new(&buf, LittleEndian); 559 /// let loader = |name| -> Result<_, ()> { Ok(reader) }; 560 /// 561 /// let debug_info: DebugInfo<_> = Section::load(loader).unwrap(); 562 /// ``` 563 pub trait Section<R>: From<R> { 564 /// Returns the section id for this type. id() -> SectionId565 fn id() -> SectionId; 566 567 /// Returns the ELF section name for this type. section_name() -> &'static str568 fn section_name() -> &'static str { 569 Self::id().name() 570 } 571 572 /// Returns the ELF section name (if any) for this type when used in a dwo 573 /// file. dwo_section_name() -> Option<&'static str>574 fn dwo_section_name() -> Option<&'static str> { 575 Self::id().dwo_name() 576 } 577 578 /// 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>,579 fn load<F, E>(f: F) -> core::result::Result<Self, E> 580 where 581 F: FnOnce(SectionId) -> core::result::Result<R, E>, 582 { 583 f(Self::id()).map(From::from) 584 } 585 586 /// Returns the `Reader` for this section. reader(&self) -> &R where R: Reader587 fn reader(&self) -> &R 588 where 589 R: Reader; 590 591 /// Returns the `Reader` for this section. lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> where R: Reader,592 fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> 593 where 594 R: Reader, 595 { 596 self.reader() 597 .lookup_offset_id(id) 598 .map(|offset| (Self::id(), offset)) 599 } 600 } 601 602 impl Register { from_u64(x: u64) -> Result<Register>603 pub(crate) fn from_u64(x: u64) -> Result<Register> { 604 let y = x as u16; 605 if u64::from(y) == x { 606 Ok(Register(y)) 607 } else { 608 Err(Error::UnsupportedRegister(x)) 609 } 610 } 611 } 612 613 #[cfg(test)] 614 mod tests { 615 use super::*; 616 use crate::common::Format; 617 use crate::endianity::LittleEndian; 618 use test_assembler::{Endian, Section}; 619 620 #[test] test_parse_initial_length_32_ok()621 fn test_parse_initial_length_32_ok() { 622 let section = Section::with_endian(Endian::Little).L32(0x7856_3412); 623 let buf = section.get_contents().unwrap(); 624 625 let input = &mut EndianSlice::new(&buf, LittleEndian); 626 match input.read_initial_length() { 627 Ok((length, format)) => { 628 assert_eq!(input.len(), 0); 629 assert_eq!(format, Format::Dwarf32); 630 assert_eq!(0x7856_3412, length); 631 } 632 otherwise => panic!("Unexpected result: {:?}", otherwise), 633 } 634 } 635 636 #[test] test_parse_initial_length_64_ok()637 fn test_parse_initial_length_64_ok() { 638 let section = Section::with_endian(Endian::Little) 639 // Dwarf_64_INITIAL_UNIT_LENGTH 640 .L32(0xffff_ffff) 641 // Actual length 642 .L64(0xffde_bc9a_7856_3412); 643 let buf = section.get_contents().unwrap(); 644 let input = &mut EndianSlice::new(&buf, LittleEndian); 645 646 #[cfg(target_pointer_width = "64")] 647 match input.read_initial_length() { 648 Ok((length, format)) => { 649 assert_eq!(input.len(), 0); 650 assert_eq!(format, Format::Dwarf64); 651 assert_eq!(0xffde_bc9a_7856_3412, length); 652 } 653 otherwise => panic!("Unexpected result: {:?}", otherwise), 654 } 655 656 #[cfg(target_pointer_width = "32")] 657 match input.read_initial_length() { 658 Err(Error::UnsupportedOffset) => {} 659 otherwise => panic!("Unexpected result: {:?}", otherwise), 660 }; 661 } 662 663 #[test] test_parse_initial_length_unknown_reserved_value()664 fn test_parse_initial_length_unknown_reserved_value() { 665 let section = Section::with_endian(Endian::Little).L32(0xffff_fffe); 666 let buf = section.get_contents().unwrap(); 667 668 let input = &mut EndianSlice::new(&buf, LittleEndian); 669 match input.read_initial_length() { 670 Err(Error::UnknownReservedLength) => assert!(true), 671 otherwise => panic!("Unexpected result: {:?}", otherwise), 672 }; 673 } 674 675 #[test] test_parse_initial_length_incomplete()676 fn test_parse_initial_length_incomplete() { 677 let buf = [0xff, 0xff, 0xff]; // Need at least 4 bytes. 678 679 let input = &mut EndianSlice::new(&buf, LittleEndian); 680 match input.read_initial_length() { 681 Err(Error::UnexpectedEof(_)) => assert!(true), 682 otherwise => panic!("Unexpected result: {:?}", otherwise), 683 }; 684 } 685 686 #[test] test_parse_initial_length_64_incomplete()687 fn test_parse_initial_length_64_incomplete() { 688 let section = Section::with_endian(Endian::Little) 689 // Dwarf_64_INITIAL_UNIT_LENGTH 690 .L32(0xffff_ffff) 691 // Actual length is not long enough. 692 .L32(0x7856_3412); 693 let buf = section.get_contents().unwrap(); 694 695 let input = &mut EndianSlice::new(&buf, LittleEndian); 696 match input.read_initial_length() { 697 Err(Error::UnexpectedEof(_)) => assert!(true), 698 otherwise => panic!("Unexpected result: {:?}", otherwise), 699 }; 700 } 701 702 #[test] test_parse_offset_32()703 fn test_parse_offset_32() { 704 let section = Section::with_endian(Endian::Little).L32(0x0123_4567); 705 let buf = section.get_contents().unwrap(); 706 707 let input = &mut EndianSlice::new(&buf, LittleEndian); 708 match input.read_offset(Format::Dwarf32) { 709 Ok(val) => { 710 assert_eq!(input.len(), 0); 711 assert_eq!(val, 0x0123_4567); 712 } 713 otherwise => panic!("Unexpected result: {:?}", otherwise), 714 }; 715 } 716 717 #[test] test_parse_offset_64_small()718 fn test_parse_offset_64_small() { 719 let section = Section::with_endian(Endian::Little).L64(0x0123_4567); 720 let buf = section.get_contents().unwrap(); 721 722 let input = &mut EndianSlice::new(&buf, LittleEndian); 723 match input.read_offset(Format::Dwarf64) { 724 Ok(val) => { 725 assert_eq!(input.len(), 0); 726 assert_eq!(val, 0x0123_4567); 727 } 728 otherwise => panic!("Unexpected result: {:?}", otherwise), 729 }; 730 } 731 732 #[test] 733 #[cfg(target_pointer_width = "64")] test_parse_offset_64_large()734 fn test_parse_offset_64_large() { 735 let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef); 736 let buf = section.get_contents().unwrap(); 737 738 let input = &mut EndianSlice::new(&buf, LittleEndian); 739 match input.read_offset(Format::Dwarf64) { 740 Ok(val) => { 741 assert_eq!(input.len(), 0); 742 assert_eq!(val, 0x0123_4567_89ab_cdef); 743 } 744 otherwise => panic!("Unexpected result: {:?}", otherwise), 745 }; 746 } 747 748 #[test] 749 #[cfg(target_pointer_width = "32")] test_parse_offset_64_large()750 fn test_parse_offset_64_large() { 751 let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef); 752 let buf = section.get_contents().unwrap(); 753 754 let input = &mut EndianSlice::new(&buf, LittleEndian); 755 match input.read_offset(Format::Dwarf64) { 756 Err(Error::UnsupportedOffset) => assert!(true), 757 otherwise => panic!("Unexpected result: {:?}", otherwise), 758 }; 759 } 760 } 761