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`](http://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 //!   * [`EhFrame`](./struct.EhFrame.html): The `.eh_frame` section.
109 //!
110 //!   * [`EhFrameHdr`](./struct.EhFrameHdr.html): The `.eh_frame_hdr` section.
111 //!
112 //! * Each section type exposes methods for accessing the debugging data encoded
113 //! in that section. For example, the [`DebugInfo`](./struct.DebugInfo.html)
114 //! struct has the [`units`](./struct.DebugInfo.html#method.units) method for
115 //! iterating over the compilation units defined within it.
116 //!
117 //! * Offsets into a section are strongly typed: an offset into `.debug_info` is
118 //! the [`DebugInfoOffset`](./struct.DebugInfoOffset.html) type. It cannot be
119 //! used to index into the [`DebugLine`](./struct.DebugLine.html) type because
120 //! `DebugLine` represents the `.debug_line` section. There are similar types
121 //! for offsets relative to a compilation unit rather than a section.
122 //!
123 //! ## Using with `FallibleIterator`
124 //!
125 //! The standard library's `Iterator` trait and related APIs do not play well
126 //! with iterators where the `next` operation is fallible. One can make the
127 //! `Iterator`'s associated `Item` type be a `Result<T, E>`, however the
128 //! provided methods cannot gracefully handle the case when an `Err` is
129 //! returned.
130 //!
131 //! This situation led to the
132 //! [`fallible-iterator`](https://crates.io/crates/fallible-iterator) crate's
133 //! existence. You can read more of the rationale for its existence in its
134 //! docs. The crate provides the helpers you have come to expect (eg `map`,
135 //! `filter`, etc) for iterators that can fail.
136 //!
137 //! `gimli`'s many lazy parsing iterators are a perfect match for the
138 //! `fallible-iterator` crate's `FallibleIterator` trait because parsing is not
139 //! done eagerly. Parse errors later in the input might only be discovered after
140 //! having iterated through many items.
141 //!
142 //! To use `gimli` iterators with `FallibleIterator`, import the crate and trait
143 //! into your code:
144 //!
145 //! ```
146 //! # #[cfg(feature = "fallible-iterator")]
147 //! # fn foo() {
148 //! // Use the `FallibleIterator` trait so its methods are in scope!
149 //! use fallible_iterator::FallibleIterator;
150 //! use gimli::{DebugAranges, EndianSlice, LittleEndian};
151 //!
152 //! fn find_sum_of_address_range_lengths(aranges: DebugAranges<EndianSlice<LittleEndian>>)
153 //!     -> gimli::Result<u64>
154 //! {
155 //!     // `DebugAranges::headers` returns a `FallibleIterator`!
156 //!     aranges.headers()
157 //!         // `flat_map` is provided by `FallibleIterator`!
158 //!         .flat_map(|header| Ok(header.entries()))
159 //!         // `map` is provided by `FallibleIterator`!
160 //!         .map(|arange| Ok(arange.length()))
161 //!         // `fold` is provided by `FallibleIterator`!
162 //!         .fold(0, |sum, len| Ok(sum + len))
163 //! }
164 //! # }
165 //! # fn main() {}
166 //! ```
167 
168 use core::fmt::{self, Debug};
169 use core::result;
170 #[cfg(feature = "std")]
171 use std::{error, io};
172 
173 use crate::common::{Register, SectionId};
174 use crate::constants;
175 
176 mod addr;
177 pub use self::addr::*;
178 
179 mod cfi;
180 pub use self::cfi::*;
181 
182 mod dwarf;
183 pub use self::dwarf::*;
184 
185 mod endian_slice;
186 pub use self::endian_slice::*;
187 
188 #[cfg(feature = "endian-reader")]
189 mod endian_reader;
190 #[cfg(feature = "endian-reader")]
191 pub use self::endian_reader::*;
192 
193 mod reader;
194 pub use self::reader::*;
195 
196 mod abbrev;
197 pub use self::abbrev::*;
198 
199 mod aranges;
200 pub use self::aranges::*;
201 
202 mod line;
203 pub use self::line::*;
204 
205 mod lists;
206 
207 mod loclists;
208 pub use self::loclists::*;
209 
210 mod lookup;
211 
212 mod op;
213 pub use self::op::*;
214 
215 mod pubnames;
216 pub use self::pubnames::*;
217 
218 mod pubtypes;
219 pub use self::pubtypes::*;
220 
221 mod rnglists;
222 pub use self::rnglists::*;
223 
224 mod str;
225 pub use self::str::*;
226 
227 mod unit;
228 pub use self::unit::*;
229 
230 mod value;
231 pub use self::value::*;
232 
233 /// `EndianBuf` has been renamed to `EndianSlice`. For ease of upgrading across
234 /// `gimli` versions, we export this type alias.
235 #[deprecated(note = "EndianBuf has been renamed to EndianSlice, use that instead.")]
236 pub type EndianBuf<'input, Endian> = EndianSlice<'input, Endian>;
237 
238 /// An error that occurred when parsing.
239 #[derive(Debug, Clone, Copy, PartialEq, Eq)]
240 pub enum Error {
241     /// An I/O error occurred while reading.
242     Io,
243     /// Found a PC relative pointer, but the section base is undefined.
244     PcRelativePointerButSectionBaseIsUndefined,
245     /// Found a `.text` relative pointer, but the `.text` base is undefined.
246     TextRelativePointerButTextBaseIsUndefined,
247     /// Found a data relative pointer, but the data base is undefined.
248     DataRelativePointerButDataBaseIsUndefined,
249     /// Found a function relative pointer in a context that does not have a
250     /// function base.
251     FuncRelativePointerInBadContext,
252     /// Cannot parse a pointer with a `DW_EH_PE_omit` encoding.
253     CannotParseOmitPointerEncoding,
254     /// An error parsing an unsigned LEB128 value.
255     BadUnsignedLeb128,
256     /// An error parsing a signed LEB128 value.
257     BadSignedLeb128,
258     /// An abbreviation declared that its tag is zero, but zero is reserved for
259     /// null records.
260     AbbreviationTagZero,
261     /// An attribute specification declared that its form is zero, but zero is
262     /// reserved for null records.
263     AttributeFormZero,
264     /// The abbreviation's has-children byte was not one of
265     /// `DW_CHILDREN_{yes,no}`.
266     BadHasChildren,
267     /// The specified length is impossible.
268     BadLength,
269     /// Found an unknown `DW_FORM_*` type.
270     UnknownForm,
271     /// Expected a zero, found something else.
272     ExpectedZero,
273     /// Found an abbreviation code that has already been used.
274     DuplicateAbbreviationCode,
275     /// Found a duplicate arange.
276     DuplicateArange,
277     /// Found an unknown reserved length value.
278     UnknownReservedLength,
279     /// Found an unknown DWARF version.
280     UnknownVersion(u64),
281     /// Found a record with an unknown abbreviation code.
282     UnknownAbbreviation,
283     /// Hit the end of input before it was expected.
284     UnexpectedEof(ReaderOffsetId),
285     /// Read a null entry before it was expected.
286     UnexpectedNull,
287     /// Found an unknown standard opcode.
288     UnknownStandardOpcode(constants::DwLns),
289     /// Found an unknown extended opcode.
290     UnknownExtendedOpcode(constants::DwLne),
291     /// The specified address size is not supported.
292     UnsupportedAddressSize(u8),
293     /// The specified offset size is not supported.
294     UnsupportedOffsetSize(u8),
295     /// The specified field size is not supported.
296     UnsupportedFieldSize(u8),
297     /// The minimum instruction length must not be zero.
298     MinimumInstructionLengthZero,
299     /// The maximum operations per instruction must not be zero.
300     MaximumOperationsPerInstructionZero,
301     /// The line range must not be zero.
302     LineRangeZero,
303     /// The opcode base must not be zero.
304     OpcodeBaseZero,
305     /// Found an invalid UTF-8 string.
306     BadUtf8,
307     /// Expected to find the CIE ID, but found something else.
308     NotCieId,
309     /// Expected to find a pointer to a CIE, but found the CIE ID instead.
310     NotCiePointer,
311     /// Expected to find a pointer to an FDE, but found a CIE instead.
312     NotFdePointer,
313     /// Invalid branch target for a DW_OP_bra or DW_OP_skip.
314     BadBranchTarget(u64),
315     /// DW_OP_push_object_address used but no address passed in.
316     InvalidPushObjectAddress,
317     /// Not enough items on the stack when evaluating an expression.
318     NotEnoughStackItems,
319     /// Too many iterations to compute the expression.
320     TooManyIterations,
321     /// An unrecognized operation was found while parsing a DWARF
322     /// expression.
323     InvalidExpression(constants::DwOp),
324     /// An unsupported operation was found while evaluating a DWARF expression.
325     UnsupportedEvaluation,
326     /// The expression had a piece followed by an expression
327     /// terminator without a piece.
328     InvalidPiece,
329     /// An expression-terminating operation was followed by something
330     /// other than the end of the expression or a piece operation.
331     InvalidExpressionTerminator(u64),
332     /// Division or modulus by zero when evaluating an expression.
333     DivisionByZero,
334     /// An expression operation used mismatching types.
335     TypeMismatch,
336     /// An expression operation required an integral type but saw a
337     /// floating point type.
338     IntegralTypeRequired,
339     /// An expression operation used types that are not supported.
340     UnsupportedTypeOperation,
341     /// The shift value in an expression must be a non-negative integer.
342     InvalidShiftExpression,
343     /// An unknown DW_CFA_* instruction.
344     UnknownCallFrameInstruction(constants::DwCfa),
345     /// The end of an address range was before the beginning.
346     InvalidAddressRange,
347     /// The end offset of a loc list entry was before the beginning.
348     InvalidLocationAddressRange,
349     /// Encountered a call frame instruction in a context in which it is not
350     /// valid.
351     CfiInstructionInInvalidContext,
352     /// When evaluating call frame instructions, found a `DW_CFA_restore_state`
353     /// stack pop instruction, but the stack was empty, and had nothing to pop.
354     PopWithEmptyStack,
355     /// Do not have unwind info for the given address.
356     NoUnwindInfoForAddress,
357     /// An offset value was larger than the maximum supported value.
358     UnsupportedOffset,
359     /// The given pointer encoding is either unknown or invalid.
360     UnknownPointerEncoding,
361     /// Did not find an entry at the given offset.
362     NoEntryAtGivenOffset,
363     /// The given offset is out of bounds.
364     OffsetOutOfBounds,
365     /// Found an unknown CFI augmentation.
366     UnknownAugmentation,
367     /// We do not support the given pointer encoding yet.
368     UnsupportedPointerEncoding,
369     /// Registers larger than `u16` are not supported.
370     UnsupportedRegister(u64),
371     /// The CFI program defined more register rules than we have storage for.
372     TooManyRegisterRules,
373     /// Attempted to push onto the CFI stack, but it was already at full
374     /// capacity.
375     CfiStackFull,
376     /// The `.eh_frame_hdr` binary search table claims to be variable-length encoded,
377     /// which makes binary search impossible.
378     VariableLengthSearchTable,
379     /// The `DW_UT_*` value for this unit is not supported yet.
380     UnsupportedUnitType,
381     /// Ranges using AddressIndex are not supported yet.
382     UnsupportedAddressIndex,
383     /// Nonzero segment selector sizes aren't supported yet.
384     UnsupportedSegmentSize,
385     /// A compilation unit or type unit is missing its top level DIE.
386     MissingUnitDie,
387     /// A DIE attribute used an unsupported form.
388     UnsupportedAttributeForm,
389     /// Missing DW_LNCT_path in file entry format.
390     MissingFileEntryFormatPath,
391     /// Expected an attribute value to be a string form.
392     ExpectedStringAttributeValue,
393     /// `DW_FORM_implicit_const` used in an invalid context.
394     InvalidImplicitConst,
395 }
396 
397 impl fmt::Display for Error {
398     #[inline]
fmt(&self, f: &mut fmt::Formatter) -> ::core::result::Result<(), fmt::Error>399     fn fmt(&self, f: &mut fmt::Formatter) -> ::core::result::Result<(), fmt::Error> {
400         write!(f, "{}", self.description())
401     }
402 }
403 
404 impl Error {
405     /// A short description of the error.
description(&self) -> &str406     pub fn description(&self) -> &str {
407         match *self {
408             Error::Io => "An I/O error occurred while reading.",
409             Error::PcRelativePointerButSectionBaseIsUndefined => {
410                 "Found a PC relative pointer, but the section base is undefined."
411             }
412             Error::TextRelativePointerButTextBaseIsUndefined => {
413                 "Found a `.text` relative pointer, but the `.text` base is undefined."
414             }
415             Error::DataRelativePointerButDataBaseIsUndefined => {
416                 "Found a data relative pointer, but the data base is undefined."
417             }
418             Error::FuncRelativePointerInBadContext => {
419                 "Found a function relative pointer in a context that does not have a function base."
420             }
421             Error::CannotParseOmitPointerEncoding => {
422                 "Cannot parse a pointer with a `DW_EH_PE_omit` encoding."
423             }
424             Error::BadUnsignedLeb128 => "An error parsing an unsigned LEB128 value",
425             Error::BadSignedLeb128 => "An error parsing a signed LEB128 value",
426             Error::AbbreviationTagZero => {
427                 "An abbreviation declared that its tag is zero,
428                  but zero is reserved for null records"
429             }
430             Error::AttributeFormZero => {
431                 "An attribute specification declared that its form is zero,
432                  but zero is reserved for null records"
433             }
434             Error::BadHasChildren => {
435                 "The abbreviation's has-children byte was not one of
436                  `DW_CHILDREN_{yes,no}`"
437             }
438             Error::BadLength => "The specified length is impossible",
439             Error::UnknownForm => "Found an unknown `DW_FORM_*` type",
440             Error::ExpectedZero => "Expected a zero, found something else",
441             Error::DuplicateAbbreviationCode => {
442                 "Found an abbreviation code that has already been used"
443             }
444             Error::DuplicateArange => "Found a duplicate arange",
445             Error::UnknownReservedLength => "Found an unknown reserved length value",
446             Error::UnknownVersion(_) => "Found an unknown DWARF version",
447             Error::UnknownAbbreviation => "Found a record with an unknown abbreviation code",
448             Error::UnexpectedEof(_) => "Hit the end of input before it was expected",
449             Error::UnexpectedNull => "Read a null entry before it was expected.",
450             Error::UnknownStandardOpcode(_) => "Found an unknown standard opcode",
451             Error::UnknownExtendedOpcode(_) => "Found an unknown extended opcode",
452             Error::UnsupportedAddressSize(_) => "The specified address size is not supported",
453             Error::UnsupportedOffsetSize(_) => "The specified offset size is not supported",
454             Error::UnsupportedFieldSize(_) => "The specified field size is not supported",
455             Error::MinimumInstructionLengthZero => {
456                 "The minimum instruction length must not be zero."
457             }
458             Error::MaximumOperationsPerInstructionZero => {
459                 "The maximum operations per instruction must not be zero."
460             }
461             Error::LineRangeZero => "The line range must not be zero.",
462             Error::OpcodeBaseZero => "The opcode base must not be zero.",
463             Error::BadUtf8 => "Found an invalid UTF-8 string.",
464             Error::NotCieId => "Expected to find the CIE ID, but found something else.",
465             Error::NotCiePointer => "Expected to find a CIE pointer, but found the CIE ID instead.",
466             Error::NotFdePointer => {
467                 "Expected to find an FDE pointer, but found a CIE pointer instead."
468             }
469             Error::BadBranchTarget(_) => "Invalid branch target in DWARF expression",
470             Error::InvalidPushObjectAddress => {
471                 "DW_OP_push_object_address used but no object address given"
472             }
473             Error::NotEnoughStackItems => "Not enough items on stack when evaluating expression",
474             Error::TooManyIterations => "Too many iterations to evaluate DWARF expression",
475             Error::InvalidExpression(_) => "Invalid opcode in DWARF expression",
476             Error::UnsupportedEvaluation => "Unsupported operation when evaluating expression",
477             Error::InvalidPiece => {
478                 "DWARF expression has piece followed by non-piece expression at end"
479             }
480             Error::InvalidExpressionTerminator(_) => "Expected DW_OP_piece or DW_OP_bit_piece",
481             Error::DivisionByZero => "Division or modulus by zero when evaluating expression",
482             Error::TypeMismatch => "Type mismatch when evaluating expression",
483             Error::IntegralTypeRequired => "Integral type expected when evaluating expression",
484             Error::UnsupportedTypeOperation => {
485                 "An expression operation used types that are not supported"
486             }
487             Error::InvalidShiftExpression => {
488                 "The shift value in an expression must be a non-negative integer."
489             }
490             Error::UnknownCallFrameInstruction(_) => "An unknown DW_CFA_* instructiion",
491             Error::InvalidAddressRange => {
492                 "The end of an address range must not be before the beginning."
493             }
494             Error::InvalidLocationAddressRange => {
495                 "The end offset of a location list entry must not be before the beginning."
496             }
497             Error::CfiInstructionInInvalidContext => {
498                 "Encountered a call frame instruction in a context in which it is not valid."
499             }
500             Error::PopWithEmptyStack => {
501                 "When evaluating call frame instructions, found a `DW_CFA_restore_state` stack pop \
502                  instruction, but the stack was empty, and had nothing to pop."
503             }
504             Error::NoUnwindInfoForAddress => "Do not have unwind info for the given address.",
505             Error::UnsupportedOffset => {
506                 "An offset value was larger than the maximum supported value."
507             }
508             Error::UnknownPointerEncoding => {
509                 "The given pointer encoding is either unknown or invalid."
510             }
511             Error::NoEntryAtGivenOffset => "Did not find an entry at the given offset.",
512             Error::OffsetOutOfBounds => "The given offset is out of bounds.",
513             Error::UnknownAugmentation => "Found an unknown CFI augmentation.",
514             Error::UnsupportedPointerEncoding => {
515                 "We do not support the given pointer encoding yet."
516             }
517             Error::UnsupportedRegister(_) => "Registers larger than `u16` are not supported.",
518             Error::TooManyRegisterRules => {
519                 "The CFI program defined more register rules than we have storage for."
520             }
521             Error::CfiStackFull => {
522                 "Attempted to push onto the CFI stack, but it was already at full capacity."
523             }
524             Error::VariableLengthSearchTable => {
525                 "The `.eh_frame_hdr` binary search table claims to be variable-length encoded, \
526                  which makes binary search impossible."
527             }
528             Error::UnsupportedUnitType => "The `DW_UT_*` value for this unit is not supported yet",
529             Error::UnsupportedAddressIndex => "Ranges involving AddressIndex are not supported yet",
530             Error::UnsupportedSegmentSize => "Nonzero segment size not supported yet",
531             Error::MissingUnitDie => {
532                 "A compilation unit or type unit is missing its top level DIE."
533             }
534             Error::UnsupportedAttributeForm => "A DIE attribute used an unsupported form.",
535             Error::MissingFileEntryFormatPath => "Missing DW_LNCT_path in file entry format.",
536             Error::ExpectedStringAttributeValue => {
537                 "Expected an attribute value to be a string form."
538             }
539             Error::InvalidImplicitConst => "DW_FORM_implicit_const used in an invalid context.",
540         }
541     }
542 }
543 
544 #[cfg(feature = "std")]
545 impl error::Error for Error {}
546 
547 #[cfg(feature = "std")]
548 impl From<io::Error> for Error {
from(_: io::Error) -> Self549     fn from(_: io::Error) -> Self {
550         Error::Io
551     }
552 }
553 
554 /// The result of a parse.
555 pub type Result<T> = result::Result<T, Error>;
556 
557 /// A convenience trait for loading DWARF sections from object files.  To be
558 /// used like:
559 ///
560 /// ```
561 /// use gimli::{DebugInfo, EndianSlice, LittleEndian, Reader, Section};
562 ///
563 /// let buf = [0x00, 0x01, 0x02, 0x03];
564 /// let reader = EndianSlice::new(&buf, LittleEndian);
565 /// let loader = |name| -> Result<_, ()> { Ok(reader) };
566 ///
567 /// let debug_info: DebugInfo<_> = Section::load(loader).unwrap();
568 /// ```
569 pub trait Section<R>: From<R> {
570     /// Returns the section id for this type.
id() -> SectionId571     fn id() -> SectionId;
572 
573     /// Returns the ELF section name for this type.
section_name() -> &'static str574     fn section_name() -> &'static str {
575         Self::id().name()
576     }
577 
578     /// Returns the ELF section name (if any) for this type when used in a dwo
579     /// file.
dwo_section_name() -> Option<&'static str>580     fn dwo_section_name() -> Option<&'static str> {
581         Self::id().dwo_name()
582     }
583 
584     /// 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>,585     fn load<F, E>(f: F) -> core::result::Result<Self, E>
586     where
587         F: FnOnce(SectionId) -> core::result::Result<R, E>,
588     {
589         f(Self::id()).map(From::from)
590     }
591 
592     /// Returns the `Reader` for this section.
reader(&self) -> &R where R: Reader593     fn reader(&self) -> &R
594     where
595         R: Reader;
596 
597     /// Returns the `Reader` for this section.
lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)> where R: Reader,598     fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(SectionId, R::Offset)>
599     where
600         R: Reader,
601     {
602         self.reader()
603             .lookup_offset_id(id)
604             .map(|offset| (Self::id(), offset))
605     }
606 }
607 
608 impl Register {
from_u64(x: u64) -> Result<Register>609     pub(crate) fn from_u64(x: u64) -> Result<Register> {
610         let y = x as u16;
611         if u64::from(y) == x {
612             Ok(Register(y))
613         } else {
614             Err(Error::UnsupportedRegister(x))
615         }
616     }
617 }
618 
619 #[cfg(test)]
620 mod tests {
621     use super::*;
622     use crate::common::Format;
623     use crate::endianity::LittleEndian;
624     use test_assembler::{Endian, Section};
625 
626     #[test]
test_parse_initial_length_32_ok()627     fn test_parse_initial_length_32_ok() {
628         let section = Section::with_endian(Endian::Little).L32(0x7856_3412);
629         let buf = section.get_contents().unwrap();
630 
631         let input = &mut EndianSlice::new(&buf, LittleEndian);
632         match input.read_initial_length() {
633             Ok((length, format)) => {
634                 assert_eq!(input.len(), 0);
635                 assert_eq!(format, Format::Dwarf32);
636                 assert_eq!(0x7856_3412, length);
637             }
638             otherwise => panic!("Unexpected result: {:?}", otherwise),
639         }
640     }
641 
642     #[test]
test_parse_initial_length_64_ok()643     fn test_parse_initial_length_64_ok() {
644         let section = Section::with_endian(Endian::Little)
645             // Dwarf_64_INITIAL_UNIT_LENGTH
646             .L32(0xffff_ffff)
647             // Actual length
648             .L64(0xffde_bc9a_7856_3412);
649         let buf = section.get_contents().unwrap();
650         let input = &mut EndianSlice::new(&buf, LittleEndian);
651 
652         #[cfg(target_pointer_width = "64")]
653         match input.read_initial_length() {
654             Ok((length, format)) => {
655                 assert_eq!(input.len(), 0);
656                 assert_eq!(format, Format::Dwarf64);
657                 assert_eq!(0xffde_bc9a_7856_3412, length);
658             }
659             otherwise => panic!("Unexpected result: {:?}", otherwise),
660         }
661 
662         #[cfg(target_pointer_width = "32")]
663         match input.read_initial_length() {
664             Err(Error::UnsupportedOffset) => {}
665             otherwise => panic!("Unexpected result: {:?}", otherwise),
666         };
667     }
668 
669     #[test]
test_parse_initial_length_unknown_reserved_value()670     fn test_parse_initial_length_unknown_reserved_value() {
671         let section = Section::with_endian(Endian::Little).L32(0xffff_fffe);
672         let buf = section.get_contents().unwrap();
673 
674         let input = &mut EndianSlice::new(&buf, LittleEndian);
675         match input.read_initial_length() {
676             Err(Error::UnknownReservedLength) => assert!(true),
677             otherwise => panic!("Unexpected result: {:?}", otherwise),
678         };
679     }
680 
681     #[test]
test_parse_initial_length_incomplete()682     fn test_parse_initial_length_incomplete() {
683         let buf = [0xff, 0xff, 0xff]; // Need at least 4 bytes.
684 
685         let input = &mut EndianSlice::new(&buf, LittleEndian);
686         match input.read_initial_length() {
687             Err(Error::UnexpectedEof(_)) => assert!(true),
688             otherwise => panic!("Unexpected result: {:?}", otherwise),
689         };
690     }
691 
692     #[test]
test_parse_initial_length_64_incomplete()693     fn test_parse_initial_length_64_incomplete() {
694         let section = Section::with_endian(Endian::Little)
695             // Dwarf_64_INITIAL_UNIT_LENGTH
696             .L32(0xffff_ffff)
697             // Actual length is not long enough.
698             .L32(0x7856_3412);
699         let buf = section.get_contents().unwrap();
700 
701         let input = &mut EndianSlice::new(&buf, LittleEndian);
702         match input.read_initial_length() {
703             Err(Error::UnexpectedEof(_)) => assert!(true),
704             otherwise => panic!("Unexpected result: {:?}", otherwise),
705         };
706     }
707 
708     #[test]
test_parse_offset_32()709     fn test_parse_offset_32() {
710         let section = Section::with_endian(Endian::Little).L32(0x0123_4567);
711         let buf = section.get_contents().unwrap();
712 
713         let input = &mut EndianSlice::new(&buf, LittleEndian);
714         match input.read_offset(Format::Dwarf32) {
715             Ok(val) => {
716                 assert_eq!(input.len(), 0);
717                 assert_eq!(val, 0x0123_4567);
718             }
719             otherwise => panic!("Unexpected result: {:?}", otherwise),
720         };
721     }
722 
723     #[test]
test_parse_offset_64_small()724     fn test_parse_offset_64_small() {
725         let section = Section::with_endian(Endian::Little).L64(0x0123_4567);
726         let buf = section.get_contents().unwrap();
727 
728         let input = &mut EndianSlice::new(&buf, LittleEndian);
729         match input.read_offset(Format::Dwarf64) {
730             Ok(val) => {
731                 assert_eq!(input.len(), 0);
732                 assert_eq!(val, 0x0123_4567);
733             }
734             otherwise => panic!("Unexpected result: {:?}", otherwise),
735         };
736     }
737 
738     #[test]
739     #[cfg(target_pointer_width = "64")]
test_parse_offset_64_large()740     fn test_parse_offset_64_large() {
741         let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef);
742         let buf = section.get_contents().unwrap();
743 
744         let input = &mut EndianSlice::new(&buf, LittleEndian);
745         match input.read_offset(Format::Dwarf64) {
746             Ok(val) => {
747                 assert_eq!(input.len(), 0);
748                 assert_eq!(val, 0x0123_4567_89ab_cdef);
749             }
750             otherwise => panic!("Unexpected result: {:?}", otherwise),
751         };
752     }
753 
754     #[test]
755     #[cfg(target_pointer_width = "32")]
test_parse_offset_64_large()756     fn test_parse_offset_64_large() {
757         let section = Section::with_endian(Endian::Little).L64(0x0123_4567_89ab_cdef);
758         let buf = section.get_contents().unwrap();
759 
760         let input = &mut EndianSlice::new(&buf, LittleEndian);
761         match input.read_offset(Format::Dwarf64) {
762             Err(Error::UnsupportedOffset) => assert!(true),
763             otherwise => panic!("Unexpected result: {:?}", otherwise),
764         };
765     }
766 }
767