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