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}