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