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