Skip to main content

gimli/read/
mod.rs

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