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