1 use alloc::string::String;
2 
3 use crate::common::{
4     DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineStrOffset, DebugLocListsBase,
5     DebugLocListsIndex, DebugRngListsBase, DebugRngListsIndex, DebugStrOffset, DebugStrOffsetsBase,
6     DebugStrOffsetsIndex, DebugTypesOffset, DwarfFileType, Encoding, LocationListsOffset,
7     RangeListsOffset, SectionId, UnitSectionOffset,
8 };
9 use crate::constants;
10 use crate::read::{
11     Abbreviations, AttributeValue, DebugAbbrev, DebugAddr, DebugInfo, DebugInfoUnitHeadersIter,
12     DebugLine, DebugLineStr, DebugStr, DebugStrOffsets, DebugTypes, DebugTypesUnitHeadersIter,
13     DebuggingInformationEntry, EntriesCursor, EntriesRaw, EntriesTree, Error,
14     IncompleteLineProgram, LocListIter, LocationLists, Range, RangeLists, Reader, ReaderOffset,
15     ReaderOffsetId, Result, RngListIter, Section, UnitHeader, UnitOffset,
16 };
17 
18 /// All of the commonly used DWARF sections, and other common information.
19 #[derive(Debug, Default)]
20 pub struct Dwarf<R> {
21     /// The `.debug_abbrev` section.
22     pub debug_abbrev: DebugAbbrev<R>,
23 
24     /// The `.debug_addr` section.
25     pub debug_addr: DebugAddr<R>,
26 
27     /// The `.debug_info` section.
28     pub debug_info: DebugInfo<R>,
29 
30     /// The `.debug_line` section.
31     pub debug_line: DebugLine<R>,
32 
33     /// The `.debug_line_str` section.
34     pub debug_line_str: DebugLineStr<R>,
35 
36     /// The `.debug_str` section.
37     pub debug_str: DebugStr<R>,
38 
39     /// The `.debug_str_offsets` section.
40     pub debug_str_offsets: DebugStrOffsets<R>,
41 
42     /// The `.debug_str` section for a supplementary object file.
43     pub debug_str_sup: DebugStr<R>,
44 
45     /// The `.debug_types` section.
46     pub debug_types: DebugTypes<R>,
47 
48     /// The location lists in the `.debug_loc` and `.debug_loclists` sections.
49     pub locations: LocationLists<R>,
50 
51     /// The range lists in the `.debug_ranges` and `.debug_rnglists` sections.
52     pub ranges: RangeLists<R>,
53 
54     /// The type of this file.
55     pub file_type: DwarfFileType,
56 }
57 
58 impl<T> Dwarf<T> {
59     /// Try to load the DWARF sections using the given loader functions.
60     ///
61     /// `section` loads a DWARF section from the main object file.
62     /// `sup` loads a DWARF sections from the supplementary object file.
63     /// These functions should return an empty section if the section does not exist.
64     ///
65     /// The provided callback functions may either directly return a `Reader` instance
66     /// (such as `EndianSlice`), or they may return some other type and then convert
67     /// that type into a `Reader` using `Dwarf::borrow`.
load<F1, F2, E>(mut section: F1, mut sup: F2) -> core::result::Result<Self, E> where F1: FnMut(SectionId) -> core::result::Result<T, E>, F2: FnMut(SectionId) -> core::result::Result<T, E>,68     pub fn load<F1, F2, E>(mut section: F1, mut sup: F2) -> core::result::Result<Self, E>
69     where
70         F1: FnMut(SectionId) -> core::result::Result<T, E>,
71         F2: FnMut(SectionId) -> core::result::Result<T, E>,
72     {
73         // Section types are inferred.
74         let debug_loc = Section::load(&mut section)?;
75         let debug_loclists = Section::load(&mut section)?;
76         let debug_ranges = Section::load(&mut section)?;
77         let debug_rnglists = Section::load(&mut section)?;
78         Ok(Dwarf {
79             debug_abbrev: Section::load(&mut section)?,
80             debug_addr: Section::load(&mut section)?,
81             debug_info: Section::load(&mut section)?,
82             debug_line: Section::load(&mut section)?,
83             debug_line_str: Section::load(&mut section)?,
84             debug_str: Section::load(&mut section)?,
85             debug_str_offsets: Section::load(&mut section)?,
86             debug_str_sup: Section::load(&mut sup)?,
87             debug_types: Section::load(&mut section)?,
88             locations: LocationLists::new(debug_loc, debug_loclists),
89             ranges: RangeLists::new(debug_ranges, debug_rnglists),
90             file_type: DwarfFileType::Main,
91         })
92     }
93 
94     /// Create a `Dwarf` structure that references the data in `self`.
95     ///
96     /// This is useful when `R` implements `Reader` but `T` does not.
97     ///
98     /// ## Example Usage
99     ///
100     /// It can be useful to load DWARF sections into owned data structures,
101     /// such as `Vec`. However, we do not implement the `Reader` trait
102     /// for `Vec`, because it would be very inefficient, but this trait
103     /// is required for all of the methods that parse the DWARF data.
104     /// So we first load the DWARF sections into `Vec`s, and then use
105     /// `borrow` to create `Reader`s that reference the data.
106     ///
107     /// ```rust,no_run
108     /// # fn example() -> Result<(), gimli::Error> {
109     /// # let loader = |name| -> Result<_, gimli::Error> { unimplemented!() };
110     /// # let sup_loader = |name| { unimplemented!() };
111     /// // Read the DWARF sections into `Vec`s with whatever object loader you're using.
112     /// let owned_dwarf: gimli::Dwarf<Vec<u8>> = gimli::Dwarf::load(loader, sup_loader)?;
113     /// // Create references to the DWARF sections.
114     /// let dwarf = owned_dwarf.borrow(|section| {
115     ///     gimli::EndianSlice::new(&section, gimli::LittleEndian)
116     /// });
117     /// # unreachable!()
118     /// # }
119     /// ```
borrow<'a, F, R>(&'a self, mut borrow: F) -> Dwarf<R> where F: FnMut(&'a T) -> R,120     pub fn borrow<'a, F, R>(&'a self, mut borrow: F) -> Dwarf<R>
121     where
122         F: FnMut(&'a T) -> R,
123     {
124         Dwarf {
125             debug_abbrev: self.debug_abbrev.borrow(&mut borrow),
126             debug_addr: self.debug_addr.borrow(&mut borrow),
127             debug_info: self.debug_info.borrow(&mut borrow),
128             debug_line: self.debug_line.borrow(&mut borrow),
129             debug_line_str: self.debug_line_str.borrow(&mut borrow),
130             debug_str: self.debug_str.borrow(&mut borrow),
131             debug_str_offsets: self.debug_str_offsets.borrow(&mut borrow),
132             debug_str_sup: self.debug_str_sup.borrow(&mut borrow),
133             debug_types: self.debug_types.borrow(&mut borrow),
134             locations: self.locations.borrow(&mut borrow),
135             ranges: self.ranges.borrow(&mut borrow),
136             file_type: self.file_type,
137         }
138     }
139 }
140 
141 impl<R: Reader> Dwarf<R> {
142     /// Iterate the unit headers in the `.debug_info` section.
143     ///
144     /// Can be [used with
145     /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
146     #[inline]
units(&self) -> DebugInfoUnitHeadersIter<R>147     pub fn units(&self) -> DebugInfoUnitHeadersIter<R> {
148         self.debug_info.units()
149     }
150 
151     /// Construct a new `Unit` from the given unit header.
152     #[inline]
unit(&self, header: UnitHeader<R>) -> Result<Unit<R>>153     pub fn unit(&self, header: UnitHeader<R>) -> Result<Unit<R>> {
154         Unit::new(self, header)
155     }
156 
157     /// Iterate the type-unit headers in the `.debug_types` section.
158     ///
159     /// Can be [used with
160     /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
161     #[inline]
type_units(&self) -> DebugTypesUnitHeadersIter<R>162     pub fn type_units(&self) -> DebugTypesUnitHeadersIter<R> {
163         self.debug_types.units()
164     }
165 
166     /// Parse the abbreviations for a compilation unit.
167     // TODO: provide caching of abbreviations
168     #[inline]
abbreviations(&self, unit: &UnitHeader<R>) -> Result<Abbreviations>169     pub fn abbreviations(&self, unit: &UnitHeader<R>) -> Result<Abbreviations> {
170         unit.abbreviations(&self.debug_abbrev)
171     }
172 
173     /// Return the string offset at the given index.
174     #[inline]
string_offset( &self, unit: &Unit<R>, index: DebugStrOffsetsIndex<R::Offset>, ) -> Result<DebugStrOffset<R::Offset>>175     pub fn string_offset(
176         &self,
177         unit: &Unit<R>,
178         index: DebugStrOffsetsIndex<R::Offset>,
179     ) -> Result<DebugStrOffset<R::Offset>> {
180         self.debug_str_offsets
181             .get_str_offset(unit.header.format(), unit.str_offsets_base, index)
182     }
183 
184     /// Return the string at the given offset in `.debug_str`.
185     #[inline]
string(&self, offset: DebugStrOffset<R::Offset>) -> Result<R>186     pub fn string(&self, offset: DebugStrOffset<R::Offset>) -> Result<R> {
187         self.debug_str.get_str(offset)
188     }
189 
190     /// Return the string at the given offset in `.debug_line_str`.
191     #[inline]
line_string(&self, offset: DebugLineStrOffset<R::Offset>) -> Result<R>192     pub fn line_string(&self, offset: DebugLineStrOffset<R::Offset>) -> Result<R> {
193         self.debug_line_str.get_str(offset)
194     }
195 
196     /// Return an attribute value as a string slice.
197     ///
198     /// If the attribute value is one of:
199     ///
200     /// - an inline `DW_FORM_string` string
201     /// - a `DW_FORM_strp` reference to an offset into the `.debug_str` section
202     /// - a `DW_FORM_strp_sup` reference to an offset into a supplementary
203     /// object file
204     /// - a `DW_FORM_line_strp` reference to an offset into the `.debug_line_str`
205     /// section
206     /// - a `DW_FORM_strx` index into the `.debug_str_offsets` entries for the unit
207     ///
208     /// then return the attribute's string value. Returns an error if the attribute
209     /// value does not have a string form, or if a string form has an invalid value.
attr_string(&self, unit: &Unit<R>, attr: AttributeValue<R>) -> Result<R>210     pub fn attr_string(&self, unit: &Unit<R>, attr: AttributeValue<R>) -> Result<R> {
211         match attr {
212             AttributeValue::String(string) => Ok(string),
213             AttributeValue::DebugStrRef(offset) => self.debug_str.get_str(offset),
214             AttributeValue::DebugStrRefSup(offset) => self.debug_str_sup.get_str(offset),
215             AttributeValue::DebugLineStrRef(offset) => self.debug_line_str.get_str(offset),
216             AttributeValue::DebugStrOffsetsIndex(index) => {
217                 let offset = self.debug_str_offsets.get_str_offset(
218                     unit.header.format(),
219                     unit.str_offsets_base,
220                     index,
221                 )?;
222                 self.debug_str.get_str(offset)
223             }
224             _ => Err(Error::ExpectedStringAttributeValue),
225         }
226     }
227 
228     /// Return the address at the given index.
address(&self, unit: &Unit<R>, index: DebugAddrIndex<R::Offset>) -> Result<u64>229     pub fn address(&self, unit: &Unit<R>, index: DebugAddrIndex<R::Offset>) -> Result<u64> {
230         self.debug_addr
231             .get_address(unit.encoding().address_size, unit.addr_base, index)
232     }
233 
234     /// Try to return an attribute value as an address.
235     ///
236     /// If the attribute value is one of:
237     ///
238     /// - a `DW_FORM_addr`
239     /// - a `DW_FORM_addrx` index into the `.debug_addr` entries for the unit
240     ///
241     /// then return the address.
242     /// Returns `None` for other forms.
attr_address(&self, unit: &Unit<R>, attr: AttributeValue<R>) -> Result<Option<u64>>243     pub fn attr_address(&self, unit: &Unit<R>, attr: AttributeValue<R>) -> Result<Option<u64>> {
244         match attr {
245             AttributeValue::Addr(addr) => Ok(Some(addr)),
246             AttributeValue::DebugAddrIndex(index) => self.address(unit, index).map(Some),
247             _ => Ok(None),
248         }
249     }
250 
251     /// Return the range list offset at the given index.
ranges_offset( &self, unit: &Unit<R>, index: DebugRngListsIndex<R::Offset>, ) -> Result<RangeListsOffset<R::Offset>>252     pub fn ranges_offset(
253         &self,
254         unit: &Unit<R>,
255         index: DebugRngListsIndex<R::Offset>,
256     ) -> Result<RangeListsOffset<R::Offset>> {
257         self.ranges
258             .get_offset(unit.encoding(), unit.rnglists_base, index)
259     }
260 
261     /// Iterate over the `RangeListEntry`s starting at the given offset.
ranges( &self, unit: &Unit<R>, offset: RangeListsOffset<R::Offset>, ) -> Result<RngListIter<R>>262     pub fn ranges(
263         &self,
264         unit: &Unit<R>,
265         offset: RangeListsOffset<R::Offset>,
266     ) -> Result<RngListIter<R>> {
267         self.ranges.ranges(
268             offset,
269             unit.encoding(),
270             unit.low_pc,
271             &self.debug_addr,
272             unit.addr_base,
273         )
274     }
275 
276     /// Try to return an attribute value as a range list offset.
277     ///
278     /// If the attribute value is one of:
279     ///
280     /// - a `DW_FORM_sec_offset` reference to the `.debug_ranges` or `.debug_rnglists` sections
281     /// - a `DW_FORM_rnglistx` index into the `.debug_rnglists` entries for the unit
282     ///
283     /// then return the range list offset of the range list.
284     /// Returns `None` for other forms.
attr_ranges_offset( &self, unit: &Unit<R>, attr: AttributeValue<R>, ) -> Result<Option<RangeListsOffset<R::Offset>>>285     pub fn attr_ranges_offset(
286         &self,
287         unit: &Unit<R>,
288         attr: AttributeValue<R>,
289     ) -> Result<Option<RangeListsOffset<R::Offset>>> {
290         match attr {
291             AttributeValue::RangeListsRef(offset) => Ok(Some(offset)),
292             AttributeValue::DebugRngListsIndex(index) => self.ranges_offset(unit, index).map(Some),
293             _ => Ok(None),
294         }
295     }
296 
297     /// Try to return an attribute value as a range list entry iterator.
298     ///
299     /// If the attribute value is one of:
300     ///
301     /// - a `DW_FORM_sec_offset` reference to the `.debug_ranges` or `.debug_rnglists` sections
302     /// - a `DW_FORM_rnglistx` index into the `.debug_rnglists` entries for the unit
303     ///
304     /// then return an iterator over the entries in the range list.
305     /// Returns `None` for other forms.
attr_ranges( &self, unit: &Unit<R>, attr: AttributeValue<R>, ) -> Result<Option<RngListIter<R>>>306     pub fn attr_ranges(
307         &self,
308         unit: &Unit<R>,
309         attr: AttributeValue<R>,
310     ) -> Result<Option<RngListIter<R>>> {
311         match self.attr_ranges_offset(unit, attr)? {
312             Some(offset) => Ok(Some(self.ranges(unit, offset)?)),
313             None => Ok(None),
314         }
315     }
316 
317     /// Return an iterator for the address ranges of a `DebuggingInformationEntry`.
318     ///
319     /// This uses `DW_AT_low_pc`, `DW_AT_high_pc` and `DW_AT_ranges`.
die_ranges( &self, unit: &Unit<R>, entry: &DebuggingInformationEntry<R>, ) -> Result<RangeIter<R>>320     pub fn die_ranges(
321         &self,
322         unit: &Unit<R>,
323         entry: &DebuggingInformationEntry<R>,
324     ) -> Result<RangeIter<R>> {
325         let mut low_pc = None;
326         let mut high_pc = None;
327         let mut size = None;
328         let mut attrs = entry.attrs();
329         while let Some(attr) = attrs.next()? {
330             match attr.name() {
331                 constants::DW_AT_low_pc => {
332                     if let AttributeValue::Addr(val) = attr.value() {
333                         low_pc = Some(val);
334                     }
335                 }
336                 constants::DW_AT_high_pc => match attr.value() {
337                     AttributeValue::Addr(val) => high_pc = Some(val),
338                     AttributeValue::Udata(val) => size = Some(val),
339                     _ => return Err(Error::UnsupportedAttributeForm),
340                 },
341                 constants::DW_AT_ranges => {
342                     if let Some(list) = self.attr_ranges(unit, attr.value())? {
343                         return Ok(RangeIter(RangeIterInner::List(list)));
344                     }
345                 }
346                 _ => {}
347             }
348         }
349         let range = low_pc.and_then(|begin| {
350             let end = size.map(|size| begin + size).or(high_pc);
351             // TODO: perhaps return an error if `end` is `None`
352             end.map(|end| Range { begin, end })
353         });
354         Ok(RangeIter(RangeIterInner::Single(range)))
355     }
356 
357     /// Return an iterator for the address ranges of a `Unit`.
358     ///
359     /// This uses `DW_AT_low_pc`, `DW_AT_high_pc` and `DW_AT_ranges` of the
360     /// root `DebuggingInformationEntry`.
unit_ranges(&self, unit: &Unit<R>) -> Result<RangeIter<R>>361     pub fn unit_ranges(&self, unit: &Unit<R>) -> Result<RangeIter<R>> {
362         let mut cursor = unit.header.entries(&unit.abbreviations);
363         cursor.next_dfs()?;
364         let root = cursor.current().ok_or(Error::MissingUnitDie)?;
365         self.die_ranges(unit, root)
366     }
367 
368     /// Return the location list offset at the given index.
locations_offset( &self, unit: &Unit<R>, index: DebugLocListsIndex<R::Offset>, ) -> Result<LocationListsOffset<R::Offset>>369     pub fn locations_offset(
370         &self,
371         unit: &Unit<R>,
372         index: DebugLocListsIndex<R::Offset>,
373     ) -> Result<LocationListsOffset<R::Offset>> {
374         self.locations
375             .get_offset(unit.encoding(), unit.loclists_base, index)
376     }
377 
378     /// Iterate over the `LocationListEntry`s starting at the given offset.
locations( &self, unit: &Unit<R>, offset: LocationListsOffset<R::Offset>, ) -> Result<LocListIter<R>>379     pub fn locations(
380         &self,
381         unit: &Unit<R>,
382         offset: LocationListsOffset<R::Offset>,
383     ) -> Result<LocListIter<R>> {
384         match self.file_type {
385             DwarfFileType::Main => self.locations.locations(
386                 offset,
387                 unit.encoding(),
388                 unit.low_pc,
389                 &self.debug_addr,
390                 unit.addr_base,
391             ),
392             DwarfFileType::Dwo => self.locations.locations_dwo(
393                 offset,
394                 unit.encoding(),
395                 unit.low_pc,
396                 &self.debug_addr,
397                 unit.addr_base,
398             ),
399         }
400     }
401 
402     /// Try to return an attribute value as a location list offset.
403     ///
404     /// If the attribute value is one of:
405     ///
406     /// - a `DW_FORM_sec_offset` reference to the `.debug_loc` or `.debug_loclists` sections
407     /// - a `DW_FORM_loclistx` index into the `.debug_loclists` entries for the unit
408     ///
409     /// then return the location list offset of the location list.
410     /// Returns `None` for other forms.
attr_locations_offset( &self, unit: &Unit<R>, attr: AttributeValue<R>, ) -> Result<Option<LocationListsOffset<R::Offset>>>411     pub fn attr_locations_offset(
412         &self,
413         unit: &Unit<R>,
414         attr: AttributeValue<R>,
415     ) -> Result<Option<LocationListsOffset<R::Offset>>> {
416         match attr {
417             AttributeValue::LocationListsRef(offset) => Ok(Some(offset)),
418             AttributeValue::DebugLocListsIndex(index) => {
419                 self.locations_offset(unit, index).map(Some)
420             }
421             _ => Ok(None),
422         }
423     }
424 
425     /// Try to return an attribute value as a location list entry iterator.
426     ///
427     /// If the attribute value is one of:
428     ///
429     /// - a `DW_FORM_sec_offset` reference to the `.debug_loc` or `.debug_loclists` sections
430     /// - a `DW_FORM_loclistx` index into the `.debug_loclists` entries for the unit
431     ///
432     /// then return an iterator over the entries in the location list.
433     /// Returns `None` for other forms.
attr_locations( &self, unit: &Unit<R>, attr: AttributeValue<R>, ) -> Result<Option<LocListIter<R>>>434     pub fn attr_locations(
435         &self,
436         unit: &Unit<R>,
437         attr: AttributeValue<R>,
438     ) -> Result<Option<LocListIter<R>>> {
439         match self.attr_locations_offset(unit, attr)? {
440             Some(offset) => Ok(Some(self.locations(unit, offset)?)),
441             None => Ok(None),
442         }
443     }
444 
445     /// Call `Reader::lookup_offset_id` for each section, and return the first match.
446     ///
447     /// The first element of the tuple is `true` for supplementary sections.
lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(bool, SectionId, R::Offset)>448     pub fn lookup_offset_id(&self, id: ReaderOffsetId) -> Option<(bool, SectionId, R::Offset)> {
449         None.or_else(|| self.debug_abbrev.lookup_offset_id(id))
450             .or_else(|| self.debug_addr.lookup_offset_id(id))
451             .or_else(|| self.debug_info.lookup_offset_id(id))
452             .or_else(|| self.debug_line.lookup_offset_id(id))
453             .or_else(|| self.debug_line_str.lookup_offset_id(id))
454             .or_else(|| self.debug_str.lookup_offset_id(id))
455             .or_else(|| self.debug_str_offsets.lookup_offset_id(id))
456             .or_else(|| self.debug_types.lookup_offset_id(id))
457             .or_else(|| self.locations.lookup_offset_id(id))
458             .or_else(|| self.ranges.lookup_offset_id(id))
459             .map(|(id, offset)| (false, id, offset))
460             .or_else(|| {
461                 self.debug_str_sup
462                     .lookup_offset_id(id)
463                     .map(|(id, offset)| (true, id, offset))
464             })
465     }
466 
467     /// Returns a string representation of the given error.
468     ///
469     /// This uses information from the DWARF sections to provide more information in some cases.
format_error(&self, err: Error) -> String470     pub fn format_error(&self, err: Error) -> String {
471         #[allow(clippy::single_match)]
472         match err {
473             Error::UnexpectedEof(id) => match self.lookup_offset_id(id) {
474                 Some((sup, section, offset)) => {
475                     return format!(
476                         "{} at {}{}+0x{:x}",
477                         err,
478                         section.name(),
479                         if sup { "(sup)" } else { "" },
480                         offset.into_u64(),
481                     );
482                 }
483                 None => {}
484             },
485             _ => {}
486         }
487         err.description().into()
488     }
489 }
490 
491 /// All of the commonly used information for a unit in the `.debug_info` or `.debug_types`
492 /// sections.
493 #[derive(Debug)]
494 pub struct Unit<R, Offset = <R as Reader>::Offset>
495 where
496     R: Reader<Offset = Offset>,
497     Offset: ReaderOffset,
498 {
499     /// The header of the unit.
500     pub header: UnitHeader<R, Offset>,
501 
502     /// The parsed abbreviations for the unit.
503     pub abbreviations: Abbreviations,
504 
505     /// The `DW_AT_name` attribute of the unit.
506     pub name: Option<R>,
507 
508     /// The `DW_AT_comp_dir` attribute of the unit.
509     pub comp_dir: Option<R>,
510 
511     /// The `DW_AT_low_pc` attribute of the unit. Defaults to 0.
512     pub low_pc: u64,
513 
514     /// The `DW_AT_str_offsets_base` attribute of the unit. Defaults to 0.
515     pub str_offsets_base: DebugStrOffsetsBase<Offset>,
516 
517     /// The `DW_AT_addr_base` attribute of the unit. Defaults to 0.
518     pub addr_base: DebugAddrBase<Offset>,
519 
520     /// The `DW_AT_loclists_base` attribute of the unit. Defaults to 0.
521     pub loclists_base: DebugLocListsBase<Offset>,
522 
523     /// The `DW_AT_rnglists_base` attribute of the unit. Defaults to 0.
524     pub rnglists_base: DebugRngListsBase<Offset>,
525 
526     /// The line number program of the unit.
527     pub line_program: Option<IncompleteLineProgram<R, Offset>>,
528 }
529 
530 impl<R: Reader> Unit<R> {
531     /// Construct a new `Unit` from the given unit header.
532     #[inline]
new(dwarf: &Dwarf<R>, header: UnitHeader<R>) -> Result<Self>533     pub fn new(dwarf: &Dwarf<R>, header: UnitHeader<R>) -> Result<Self> {
534         let abbreviations = header.abbreviations(&dwarf.debug_abbrev)?;
535         let mut unit = Unit {
536             abbreviations,
537             name: None,
538             comp_dir: None,
539             low_pc: 0,
540             str_offsets_base: DebugStrOffsetsBase::default_for_encoding_and_file(
541                 header.encoding(),
542                 dwarf.file_type,
543             ),
544             // NB: Because the .debug_addr section never lives in a .dwo, we can assume its base is always 0 or provided.
545             addr_base: DebugAddrBase(R::Offset::from_u8(0)),
546             loclists_base: DebugLocListsBase::default_for_encoding_and_file(
547                 header.encoding(),
548                 dwarf.file_type,
549             ),
550             rnglists_base: DebugRngListsBase::default_for_encoding_and_file(
551                 header.encoding(),
552                 dwarf.file_type,
553             ),
554             line_program: None,
555             header,
556         };
557         let mut name = None;
558         let mut comp_dir = None;
559         let mut line_program_offset = None;
560 
561         {
562             let mut cursor = unit.header.entries(&unit.abbreviations);
563             cursor.next_dfs()?;
564             let root = cursor.current().ok_or(Error::MissingUnitDie)?;
565             let mut attrs = root.attrs();
566             while let Some(attr) = attrs.next()? {
567                 match attr.name() {
568                     constants::DW_AT_name => {
569                         name = Some(attr.value());
570                     }
571                     constants::DW_AT_comp_dir => {
572                         comp_dir = Some(attr.value());
573                     }
574                     constants::DW_AT_low_pc => {
575                         if let AttributeValue::Addr(address) = attr.value() {
576                             unit.low_pc = address;
577                         }
578                     }
579                     constants::DW_AT_stmt_list => {
580                         if let AttributeValue::DebugLineRef(offset) = attr.value() {
581                             line_program_offset = Some(offset);
582                         }
583                     }
584                     constants::DW_AT_str_offsets_base => {
585                         if let AttributeValue::DebugStrOffsetsBase(base) = attr.value() {
586                             unit.str_offsets_base = base;
587                         }
588                     }
589                     constants::DW_AT_addr_base | constants::DW_AT_GNU_addr_base => {
590                         if let AttributeValue::DebugAddrBase(base) = attr.value() {
591                             unit.addr_base = base;
592                         }
593                     }
594                     constants::DW_AT_loclists_base => {
595                         if let AttributeValue::DebugLocListsBase(base) = attr.value() {
596                             unit.loclists_base = base;
597                         }
598                     }
599                     constants::DW_AT_rnglists_base | constants::DW_AT_GNU_ranges_base => {
600                         if let AttributeValue::DebugRngListsBase(base) = attr.value() {
601                             unit.rnglists_base = base;
602                         }
603                     }
604                     _ => {}
605                 }
606             }
607         }
608 
609         unit.name = match name {
610             Some(val) => dwarf.attr_string(&unit, val).ok(),
611             None => None,
612         };
613         unit.comp_dir = match comp_dir {
614             Some(val) => dwarf.attr_string(&unit, val).ok(),
615             None => None,
616         };
617         unit.line_program = match line_program_offset {
618             Some(offset) => Some(dwarf.debug_line.program(
619                 offset,
620                 unit.header.address_size(),
621                 unit.comp_dir.clone(),
622                 unit.name.clone(),
623             )?),
624             None => None,
625         };
626         Ok(unit)
627     }
628 
629     /// Return the encoding parameters for this unit.
630     #[inline]
encoding(&self) -> Encoding631     pub fn encoding(&self) -> Encoding {
632         self.header.encoding()
633     }
634 
635     /// Read the `DebuggingInformationEntry` at the given offset.
entry(&self, offset: UnitOffset<R::Offset>) -> Result<DebuggingInformationEntry<R>>636     pub fn entry(&self, offset: UnitOffset<R::Offset>) -> Result<DebuggingInformationEntry<R>> {
637         self.header.entry(&self.abbreviations, offset)
638     }
639 
640     /// Navigate this unit's `DebuggingInformationEntry`s.
641     #[inline]
entries(&self) -> EntriesCursor<R>642     pub fn entries(&self) -> EntriesCursor<R> {
643         self.header.entries(&self.abbreviations)
644     }
645 
646     /// Navigate this unit's `DebuggingInformationEntry`s
647     /// starting at the given offset.
648     #[inline]
entries_at_offset(&self, offset: UnitOffset<R::Offset>) -> Result<EntriesCursor<R>>649     pub fn entries_at_offset(&self, offset: UnitOffset<R::Offset>) -> Result<EntriesCursor<R>> {
650         self.header.entries_at_offset(&self.abbreviations, offset)
651     }
652 
653     /// Navigate this unit's `DebuggingInformationEntry`s as a tree
654     /// starting at the given offset.
655     #[inline]
entries_tree(&self, offset: Option<UnitOffset<R::Offset>>) -> Result<EntriesTree<R>>656     pub fn entries_tree(&self, offset: Option<UnitOffset<R::Offset>>) -> Result<EntriesTree<R>> {
657         self.header.entries_tree(&self.abbreviations, offset)
658     }
659 
660     /// Read the raw data that defines the Debugging Information Entries.
661     #[inline]
entries_raw(&self, offset: Option<UnitOffset<R::Offset>>) -> Result<EntriesRaw<R>>662     pub fn entries_raw(&self, offset: Option<UnitOffset<R::Offset>>) -> Result<EntriesRaw<R>> {
663         self.header.entries_raw(&self.abbreviations, offset)
664     }
665 
666     /// Copy attributes that are subject to relocation from another unit. This is intended
667     /// to be used to copy attributes from a skeleton compilation unit to the corresponding
668     /// split compilation unit.
copy_relocated_attributes(&mut self, other: &Unit<R>)669     pub fn copy_relocated_attributes(&mut self, other: &Unit<R>) {
670         self.low_pc = other.low_pc;
671         self.addr_base = other.addr_base;
672         if self.header.version() < 5 {
673             self.rnglists_base = other.rnglists_base;
674         }
675     }
676 }
677 
678 impl<T: ReaderOffset> UnitSectionOffset<T> {
679     /// Convert an offset to be relative to the start of the given unit,
680     /// instead of relative to the start of the section.
681     /// Returns `None` if the offset is not within the unit entries.
to_unit_offset<R>(&self, unit: &Unit<R>) -> Option<UnitOffset<T>> where R: Reader<Offset = T>,682     pub fn to_unit_offset<R>(&self, unit: &Unit<R>) -> Option<UnitOffset<T>>
683     where
684         R: Reader<Offset = T>,
685     {
686         let (offset, unit_offset) = match (self, unit.header.offset()) {
687             (
688                 UnitSectionOffset::DebugInfoOffset(offset),
689                 UnitSectionOffset::DebugInfoOffset(unit_offset),
690             ) => (offset.0, unit_offset.0),
691             (
692                 UnitSectionOffset::DebugTypesOffset(offset),
693                 UnitSectionOffset::DebugTypesOffset(unit_offset),
694             ) => (offset.0, unit_offset.0),
695             _ => return None,
696         };
697         let offset = match offset.checked_sub(unit_offset) {
698             Some(offset) => UnitOffset(offset),
699             None => return None,
700         };
701         if !unit.header.is_valid_offset(offset) {
702             return None;
703         }
704         Some(offset)
705     }
706 }
707 
708 impl<T: ReaderOffset> UnitOffset<T> {
709     /// Convert an offset to be relative to the start of the .debug_info section,
710     /// instead of relative to the start of the given compilation unit.
711     ///
712     /// Does not check that the offset is valid.
to_unit_section_offset<R>(&self, unit: &Unit<R>) -> UnitSectionOffset<T> where R: Reader<Offset = T>,713     pub fn to_unit_section_offset<R>(&self, unit: &Unit<R>) -> UnitSectionOffset<T>
714     where
715         R: Reader<Offset = T>,
716     {
717         match unit.header.offset() {
718             UnitSectionOffset::DebugInfoOffset(unit_offset) => {
719                 DebugInfoOffset(unit_offset.0 + self.0).into()
720             }
721             UnitSectionOffset::DebugTypesOffset(unit_offset) => {
722                 DebugTypesOffset(unit_offset.0 + self.0).into()
723             }
724         }
725     }
726 }
727 
728 /// An iterator for the address ranges of a `DebuggingInformationEntry`.
729 ///
730 /// Returned by `Dwarf::die_ranges` and `Dwarf::unit_ranges`.
731 #[derive(Debug)]
732 pub struct RangeIter<R: Reader>(RangeIterInner<R>);
733 
734 #[derive(Debug)]
735 enum RangeIterInner<R: Reader> {
736     Single(Option<Range>),
737     List(RngListIter<R>),
738 }
739 
740 impl<R: Reader> Default for RangeIter<R> {
default() -> Self741     fn default() -> Self {
742         RangeIter(RangeIterInner::Single(None))
743     }
744 }
745 
746 impl<R: Reader> RangeIter<R> {
747     /// Advance the iterator to the next range.
next(&mut self) -> Result<Option<Range>>748     pub fn next(&mut self) -> Result<Option<Range>> {
749         match self.0 {
750             RangeIterInner::Single(ref mut range) => Ok(range.take()),
751             RangeIterInner::List(ref mut list) => list.next(),
752         }
753     }
754 }
755 
756 #[cfg(feature = "fallible-iterator")]
757 impl<R: Reader> fallible_iterator::FallibleIterator for RangeIter<R> {
758     type Item = Range;
759     type Error = Error;
760 
761     #[inline]
next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error>762     fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
763         RangeIter::next(self)
764     }
765 }
766 
767 #[cfg(test)]
768 mod tests {
769     use super::*;
770     use crate::read::EndianSlice;
771     use crate::{Endianity, LittleEndian};
772 
773     /// Ensure that `Dwarf<R>` is covariant wrt R.
774     #[test]
test_dwarf_variance()775     fn test_dwarf_variance() {
776         /// This only needs to compile.
777         fn _f<'a: 'b, 'b, E: Endianity>(x: Dwarf<EndianSlice<'a, E>>) -> Dwarf<EndianSlice<'b, E>> {
778             x
779         }
780     }
781 
782     /// Ensure that `Unit<R>` is covariant wrt R.
783     #[test]
test_dwarf_unit_variance()784     fn test_dwarf_unit_variance() {
785         /// This only needs to compile.
786         fn _f<'a: 'b, 'b, E: Endianity>(x: Unit<EndianSlice<'a, E>>) -> Unit<EndianSlice<'b, E>> {
787             x
788         }
789     }
790 
791     #[test]
test_format_error()792     fn test_format_error() {
793         let owned_dwarf =
794             Dwarf::load(|_| -> Result<_> { Ok(vec![1, 2]) }, |_| Ok(vec![1, 2])).unwrap();
795         let dwarf = owned_dwarf.borrow(|section| EndianSlice::new(&section, LittleEndian));
796 
797         match dwarf.debug_str.get_str(DebugStrOffset(1)) {
798             Ok(r) => panic!("Unexpected str {:?}", r),
799             Err(e) => {
800                 assert_eq!(
801                     dwarf.format_error(e),
802                     "Hit the end of input before it was expected at .debug_str+0x1"
803                 );
804             }
805         }
806         match dwarf.debug_str_sup.get_str(DebugStrOffset(1)) {
807             Ok(r) => panic!("Unexpected str {:?}", r),
808             Err(e) => {
809                 assert_eq!(
810                     dwarf.format_error(e),
811                     "Hit the end of input before it was expected at .debug_str(sup)+0x1"
812                 );
813             }
814         }
815         assert_eq!(dwarf.format_error(Error::Io), Error::Io.description());
816     }
817 }
818