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