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