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