Coverage Report

Created: 2021-03-22 08:29

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