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 /// `DW_FORM_implicit_const` used in an invalid context. 387 InvalidImplicitConst, 388 } 389 390 impl fmt::Display for Error { 391 #[inline] fmt(&self, f: &mut fmt::Formatter) -> ::core::result::Result<(), fmt::Error>392 fn fmt(&self, f: &mut fmt::Formatter) -> ::core::result::Result<(), fmt::Error> { 393 write!(f, "{}", self.description()) 394 } 395 } 396 397 impl Error { 398 /// A short description of the error. description(&self) -> &str399 pub fn description(&self) -> &str { 400 match *self { 401 Error::Io => "An I/O error occurred while reading.", 402 Error::PcRelativePointerButSectionBaseIsUndefined => { 403 "Found a PC relative pointer, but the section base is undefined." 404 } 405 Error::TextRelativePointerButTextBaseIsUndefined => { 406 "Found a `.text` relative pointer, but the `.text` base is undefined." 407 } 408 Error::DataRelativePointerButDataBaseIsUndefined => { 409 "Found a data relative pointer, but the data base is undefined." 410 } 411 Error::FuncRelativePointerInBadContext => { 412 "Found a function relative pointer in a context that does not have a function base." 413 } 414 Error::CannotParseOmitPointerEncoding => { 415 "Cannot parse a pointer with a `DW_EH_PE_omit` encoding." 416 } 417 Error::BadUnsignedLeb128 => "An error parsing an unsigned LEB128 value", 418 Error::BadSignedLeb128 => "An error parsing a signed LEB128 value", 419 Error::AbbreviationTagZero => { 420 "An abbreviation declared that its tag is zero, 421 but zero is reserved for null records" 422 } 423 Error::AttributeFormZero => { 424 "An attribute specification declared that its form is zero, 425 but zero is reserved for null records" 426 } 427 Error::BadHasChildren => { 428 "The abbreviation's has-children byte was not one of 429 `DW_CHILDREN_{yes,no}`" 430 } 431 Error::BadLength => "The specified length is impossible", 432 Error::UnknownForm => "Found an unknown `DW_FORM_*` type", 433 Error::ExpectedZero => "Expected a zero, found something else", 434 Error::DuplicateAbbreviationCode => { 435 "Found an abbreviation code that has already been used" 436 } 437 Error::DuplicateArange => "Found a duplicate arange", 438 Error::UnknownReservedLength => "Found an unknown reserved length value", 439 Error::UnknownVersion(_) => "Found an unknown DWARF version", 440 Error::UnknownAbbreviation => "Found a record with an unknown abbreviation code", 441 Error::UnexpectedEof(_) => "Hit the end of input before it was expected", 442 Error::UnexpectedNull => "Read a null entry before it was expected.", 443 Error::UnknownStandardOpcode(_) => "Found an unknown standard opcode", 444 Error::UnknownExtendedOpcode(_) => "Found an unknown extended opcode", 445 Error::UnsupportedAddressSize(_) => "The specified address size is not supported", 446 Error::UnsupportedOffsetSize(_) => "The specified offset size is not supported", 447 Error::UnsupportedFieldSize(_) => "The specified field size is not supported", 448 Error::MinimumInstructionLengthZero => { 449 "The minimum instruction length must not be zero." 450 } 451 Error::MaximumOperationsPerInstructionZero => { 452 "The maximum operations per instruction must not be zero." 453 } 454 Error::LineRangeZero => "The line range must not be zero.", 455 Error::OpcodeBaseZero => "The opcode base must not be zero.", 456 Error::BadUtf8 => "Found an invalid UTF-8 string.", 457 Error::NotCieId => "Expected to find the CIE ID, but found something else.", 458 Error::NotCiePointer => "Expected to find a CIE pointer, but found the CIE ID instead.", 459 Error::NotFdePointer => { 460 "Expected to find an FDE pointer, but found a CIE pointer instead." 461 } 462 Error::BadBranchTarget(_) => "Invalid branch target in DWARF expression", 463 Error::InvalidPushObjectAddress => { 464 "DW_OP_push_object_address used but no object address given" 465 } 466 Error::NotEnoughStackItems => "Not enough items on stack when evaluating expression", 467 Error::TooManyIterations => "Too many iterations to evaluate DWARF expression", 468 Error::InvalidExpression(_) => "Invalid opcode in DWARF expression", 469 Error::InvalidPiece => { 470 "DWARF expression has piece followed by non-piece expression at end" 471 } 472 Error::InvalidExpressionTerminator(_) => "Expected DW_OP_piece or DW_OP_bit_piece", 473 Error::DivisionByZero => "Division or modulus by zero when evaluating expression", 474 Error::TypeMismatch => "Type mismatch when evaluating expression", 475 Error::IntegralTypeRequired => "Integral type expected when evaluating expression", 476 Error::UnsupportedTypeOperation => { 477 "An expression operation used types that are not supported" 478 } 479 Error::InvalidShiftExpression => { 480 "The shift value in an expression must be a non-negative integer." 481 } 482 Error::UnknownCallFrameInstruction(_) => "An unknown DW_CFA_* instructiion", 483 Error::InvalidAddressRange => { 484 "The end of an address range must not be before the beginning." 485 } 486 Error::InvalidLocationAddressRange => { 487 "The end offset of a location list entry must not be before the beginning." 488 } 489 Error::CfiInstructionInInvalidContext => { 490 "Encountered a call frame instruction in a context in which it is not valid." 491 } 492 Error::PopWithEmptyStack => { 493 "When evaluating call frame instructions, found a `DW_CFA_restore_state` stack pop \ 494 instruction, but the stack was empty, and had nothing to pop." 495 } 496 Error::NoUnwindInfoForAddress => "Do not have unwind info for the given address.", 497 Error::UnsupportedOffset => { 498 "An offset value was larger than the maximum supported value." 499 } 500 Error::UnknownPointerEncoding => { 501 "The given pointer encoding is either unknown or invalid." 502 } 503 Error::NoEntryAtGivenOffset => "Did not find an entry at the given offset.", 504 Error::OffsetOutOfBounds => "The given offset is out of bounds.", 505 Error::UnknownAugmentation => "Found an unknown CFI augmentation.", 506 Error::UnsupportedPointerEncoding => { 507 "We do not support the given pointer encoding yet." 508 } 509 Error::UnsupportedRegister(_) => "Registers larger than `u16` are not supported.", 510 Error::TooManyRegisterRules => { 511 "The CFI program defined more register rules than we have storage for." 512 } 513 Error::CfiStackFull => { 514 "Attempted to push onto the CFI stack, but it was already at full capacity." 515 } 516 Error::VariableLengthSearchTable => { 517 "The `.eh_frame_hdr` binary search table claims to be variable-length encoded, \ 518 which makes binary search impossible." 519 } 520 Error::UnsupportedUnitType => "The `DW_UT_*` value for this unit is not supported yet", 521 Error::UnsupportedAddressIndex => "Ranges involving AddressIndex are not supported yet", 522 Error::UnsupportedSegmentSize => "Nonzero segment size not supported yet", 523 Error::MissingUnitDie => { 524 "A compilation unit or type unit is missing its top level DIE." 525 } 526 Error::UnsupportedAttributeForm => "A DIE attribute used an unsupported form.", 527 Error::MissingFileEntryFormatPath => "Missing DW_LNCT_path in file entry format.", 528 Error::ExpectedStringAttributeValue => { 529 "Expected an attribute value to be a string form." 530 } 531 Error::InvalidImplicitConst => "DW_FORM_implicit_const used in an invalid context.", 532 } 533 } 534 } 535 536 #[cfg(feature = "std")] 537 impl error::Error for Error {} 538 539 #[cfg(feature = "std")] 540 impl From<io::Error> for Error { from(_: io::Error) -> Self541 fn from(_: io::Error) -> Self { 542 Error::Io 543 } 544 } 545 546 /// The result of a parse. 547 pub type Result<T> = result::Result<T, Error>; 548 549 /// A convenience trait for loading DWARF sections from object files. To be 550 /// used like: 551 /// 552 /// ``` 553 /// use gimli::{DebugInfo, EndianSlice, LittleEndian, Reader, Section}; 554 /// 555 /// let buf = [0x00, 0x01, 0x02, 0x03]; 556 /// let reader = EndianSlice::new(&buf, LittleEndian); 557 /// let loader = |name| -> Result<_, ()> { Ok(reader) }; 558 /// 559 /// let debug_info: DebugInfo<_> = Section::load(loader).unwrap(); 560 /// ``` 561 pub trait Section<R>: From<R> { 562 /// Returns the section id for this type. id() -> SectionId563 fn id() -> SectionId; 564 565 /// Returns the ELF section name for this type. section_name() -> &'static str566 fn section_name() -> &'static str { 567 Self::id().name() 568 } 569 570 /// Returns the ELF section name (if any) for this type when used in a dwo 571 /// file. dwo_section_name() -> Option<&'static str>572 fn dwo_section_name() -> Option<&'static str> { 573 Self::id().dwo_name() 574 } 575 576 /// 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>,577 fn load<F, E>(f: F) -> core::result::Result<Self, E> 578 where 579 F: FnOnce(SectionId) -> core::result::Result<R, E>, 580 { 581 f(Self::id()).map(From::from) 582 } 583 584 /// Returns the `Reader` for this section. reader(&self) -> &R where R: Reader585 fn reader(&self) -> &R 586 where 587 R: Reader; 588 589 /// Returns the `Reader` for this section. lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> where R: Reader,590 fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> 591 where 592 R: Reader, 593 { 594 self.reader() 595 .lookup_offset_id(id) 596 .map(|offset| (Self::id(), offset)) 597 } 598 } 599 600 impl Register { from_u64(x: u64) -> Result<Register>601 pub(crate) fn from_u64(x: u64) -> Result<Register> { 602 let y = x as u16; 603 if u64::from(y) == x { 604 Ok(Register(y)) 605 } else { 606 Err(Error::UnsupportedRegister(x)) 607 } 608 } 609 } 610 611 #[cfg(test)] 612 mod tests { 613 use super::*; 614 use crate::common::Format; 615 use crate::endianity::LittleEndian; 616 use test_assembler::{Endian, Section}; 617 618 #[test] test_parse_initial_length_32_ok()619 fn test_parse_initial_length_32_ok() { 620 let section = Section::with_endian(Endian::Little).L32(0x7856_3412); 621 let buf = section.get_contents().unwrap(); 622 623 let input = &mut EndianSlice::new(&buf, LittleEndian); 624 match input.read_initial_length() { 625 Ok((length, format)) => { 626 assert_eq!(input.len(), 0); 627 assert_eq!(format, Format::Dwarf32); 628 assert_eq!(0x7856_3412, length); 629 } 630 otherwise => panic!("Unexpected result: {:?}", otherwise), 631 } 632 } 633 634 #[test] test_parse_initial_length_64_ok()635 fn test_parse_initial_length_64_ok() { 636 let section = Section::with_endian(Endian::Little) 637 // Dwarf_64_INITIAL_UNIT_LENGTH 638 .L32(0xffff_ffff) 639 // Actual length 640 .L64(0xffde_bc9a_7856_3412); 641 let buf = section.get_contents().unwrap(); 642 let input = &mut EndianSlice::new(&buf, LittleEndian); 643 644 #[cfg(target_pointer_width = "64")] 645 match input.read_initial_length() { 646 Ok((length, format)) => { 647 assert_eq!(input.len(), 0); 648 assert_eq!(format, Format::Dwarf64); 649 assert_eq!(0xffde_bc9a_7856_3412, length); 650 } 651 otherwise => panic!("Unexpected result: {:?}", otherwise), 652 } 653 654 #[cfg(target_pointer_width = "32")] 655 match input.read_initial_length() { 656 Err(Error::UnsupportedOffset) => {} 657 otherwise => panic!("Unexpected result: {:?}", otherwise), 658 }; 659 } 660 661 #[test] test_parse_initial_length_unknown_reserved_value()662 fn test_parse_initial_length_unknown_reserved_value() { 663 let section = Section::with_endian(Endian::Little).L32(0xffff_fffe); 664 let buf = section.get_contents().unwrap(); 665 666 let input = &mut EndianSlice::new(&buf, LittleEndian); 667 match input.read_initial_length() { 668 Err(Error::UnknownReservedLength) => assert!(true), 669 otherwise => panic!("Unexpected result: {:?}", otherwise), 670 }; 671 } 672 673 #[test] test_parse_initial_length_incomplete()674 fn test_parse_initial_length_incomplete() { 675 let buf = [0xff, 0xff, 0xff]; // Need at least 4 bytes. 676 677 let input = &mut EndianSlice::new(&buf, LittleEndian); 678 match input.read_initial_length() { 679 Err(Error::UnexpectedEof(_)) => assert!(true), 680 otherwise => panic!("Unexpected result: {:?}", otherwise), 681 }; 682 } 683 684 #[test] test_parse_initial_length_64_incomplete()685 fn test_parse_initial_length_64_incomplete() { 686 let section = Section::with_endian(Endian::Little) 687 // Dwarf_64_INITIAL_UNIT_LENGTH 688 .L32(0xffff_ffff) 689 // Actual length is not long enough. 690 .L32(0x7856_3412); 691 let buf = section.get_contents().unwrap(); 692 693 let input = &mut EndianSlice::new(&buf, LittleEndian); 694 match input.read_initial_length() { 695 Err(Error::UnexpectedEof(_)) => assert!(true), 696 otherwise => panic!("Unexpected result: {:?}", otherwise), 697 }; 698 } 699 700 #[test] test_parse_offset_32()701 fn test_parse_offset_32() { 702 let section = Section::with_endian(Endian::Little).L32(0x0123_4567); 703 let buf = section.get_contents().unwrap(); 704 705 let input = &mut EndianSlice::new(&buf, LittleEndian); 706 match input.read_offset(Format::Dwarf32) { 707 Ok(val) => { 708 assert_eq!(input.len(), 0); 709 assert_eq!(val, 0x0123_4567); 710 } 711 otherwise => panic!("Unexpected result: {:?}", otherwise), 712 }; 713 } 714 715 #[test] test_parse_offset_64_small()716 fn test_parse_offset_64_small() { 717 let section = Section::with_endian(Endian::Little).L64(0x0123_4567); 718 let buf = section.get_contents().unwrap(); 719 720 let input = &mut EndianSlice::new(&buf, LittleEndian); 721 match input.read_offset(Format::Dwarf64) { 722 Ok(val) => { 723 assert_eq!(input.len(), 0); 724 assert_eq!(val, 0x0123_4567); 725 } 726 otherwise => panic!("Unexpected result: {:?}", otherwise), 727 }; 728 } 729 730 #[test] 731 #[cfg(target_pointer_width = "64")] test_parse_offset_64_large()732 fn test_parse_offset_64_large() { 733 let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef); 734 let buf = section.get_contents().unwrap(); 735 736 let input = &mut EndianSlice::new(&buf, LittleEndian); 737 match input.read_offset(Format::Dwarf64) { 738 Ok(val) => { 739 assert_eq!(input.len(), 0); 740 assert_eq!(val, 0x0123_4567_89ab_cdef); 741 } 742 otherwise => panic!("Unexpected result: {:?}", otherwise), 743 }; 744 } 745 746 #[test] 747 #[cfg(target_pointer_width = "32")] test_parse_offset_64_large()748 fn test_parse_offset_64_large() { 749 let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef); 750 let buf = section.get_contents().unwrap(); 751 752 let input = &mut EndianSlice::new(&buf, LittleEndian); 753 match input.read_offset(Format::Dwarf64) { 754 Err(Error::UnsupportedOffset) => assert!(true), 755 otherwise => panic!("Unexpected result: {:?}", otherwise), 756 }; 757 } 758 } 759