]> git.proxmox.com Git - rustc.git/blame - vendor/gimli-0.23.0/src/read/dwarf.rs
New upstream version 1.55.0+dfsg1
[rustc.git] / vendor / gimli-0.23.0 / src / read / dwarf.rs
CommitLineData
f035d41b
XL
1use alloc::string::String;
2
3use crate::common::{
4 DebugAddrBase, DebugAddrIndex, DebugInfoOffset, DebugLineStrOffset, DebugLocListsBase,
5 DebugLocListsIndex, DebugRngListsBase, DebugRngListsIndex, DebugStrOffset, DebugStrOffsetsBase,
fc512014
XL
6 DebugStrOffsetsIndex, DebugTypesOffset, DwarfFileType, Encoding, LocationListsOffset,
7 RangeListsOffset, SectionId, UnitSectionOffset,
f035d41b
XL
8};
9use crate::constants;
10use crate::read::{
fc512014
XL
11 Abbreviations, AttributeValue, DebugAbbrev, DebugAddr, DebugInfo, DebugInfoUnitHeadersIter,
12 DebugLine, DebugLineStr, DebugStr, DebugStrOffsets, DebugTypes, DebugTypesUnitHeadersIter,
f035d41b
XL
13 DebuggingInformationEntry, EntriesCursor, EntriesRaw, EntriesTree, Error,
14 IncompleteLineProgram, LocListIter, LocationLists, Range, RangeLists, Reader, ReaderOffset,
fc512014 15 ReaderOffsetId, Result, RngListIter, Section, UnitHeader, UnitOffset,
f035d41b
XL
16};
17
18/// All of the commonly used DWARF sections, and other common information.
19#[derive(Debug, Default)]
20pub 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>,
fc512014
XL
53
54 /// The type of this file.
55 pub file_type: DwarfFileType,
f035d41b
XL
56}
57
58impl<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`.
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),
fc512014 90 file_type: DwarfFileType::Main,
f035d41b
XL
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 /// ```
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),
fc512014 136 file_type: self.file_type,
f035d41b
XL
137 }
138 }
139}
140
141impl<R: Reader> Dwarf<R> {
fc512014 142 /// Iterate the unit headers in the `.debug_info` section.
f035d41b
XL
143 ///
144 /// Can be [used with
145 /// `FallibleIterator`](./index.html#using-with-fallibleiterator).
146 #[inline]
fc512014 147 pub fn units(&self) -> DebugInfoUnitHeadersIter<R> {
f035d41b
XL
148 self.debug_info.units()
149 }
150
fc512014 151 /// Construct a new `Unit` from the given unit header.
f035d41b 152 #[inline]
fc512014 153 pub fn unit(&self, header: UnitHeader<R>) -> Result<Unit<R>> {
f035d41b
XL
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]
fc512014 162 pub fn type_units(&self) -> DebugTypesUnitHeadersIter<R> {
f035d41b
XL
163 self.debug_types.units()
164 }
165
f035d41b
XL
166 /// Parse the abbreviations for a compilation unit.
167 // TODO: provide caching of abbreviations
168 #[inline]
fc512014 169 pub fn abbreviations(&self, unit: &UnitHeader<R>) -> Result<Abbreviations> {
f035d41b
XL
170 unit.abbreviations(&self.debug_abbrev)
171 }
172
173 /// Return the string offset at the given index.
174 #[inline]
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]
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]
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.
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.
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
fc512014
XL
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.
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
f035d41b
XL
251 /// Return the range list offset at the given index.
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.
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.
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.
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`.
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`.
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.
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.
379 pub fn locations(
380 &self,
381 unit: &Unit<R>,
382 offset: LocationListsOffset<R::Offset>,
383 ) -> Result<LocListIter<R>> {
fc512014
XL
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 }
f035d41b
XL
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.
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.
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.
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.
470 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)]
494pub struct Unit<R, Offset = <R as Reader>::Offset>
495where
496 R: Reader<Offset = Offset>,
497 Offset: ReaderOffset,
498{
f035d41b
XL
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
530impl<R: Reader> Unit<R> {
fc512014 531 /// Construct a new `Unit` from the given unit header.
f035d41b 532 #[inline]
fc512014 533 pub fn new(dwarf: &Dwarf<R>, header: UnitHeader<R>) -> Result<Self> {
f035d41b
XL
534 let abbreviations = header.abbreviations(&dwarf.debug_abbrev)?;
535 let mut unit = Unit {
f035d41b
XL
536 abbreviations,
537 name: None,
538 comp_dir: None,
539 low_pc: 0,
fc512014
XL
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.
f035d41b 545 addr_base: DebugAddrBase(R::Offset::from_u8(0)),
fc512014
XL
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 ),
f035d41b 554 line_program: None,
fc512014 555 header,
f035d41b
XL
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 }
fc512014 589 constants::DW_AT_addr_base | constants::DW_AT_GNU_addr_base => {
f035d41b
XL
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 }
fc512014 599 constants::DW_AT_rnglists_base | constants::DW_AT_GNU_ranges_base => {
f035d41b
XL
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 {
3dfed10e 610 Some(val) => dwarf.attr_string(&unit, val).ok(),
f035d41b
XL
611 None => None,
612 };
613 unit.comp_dir = match comp_dir {
3dfed10e 614 Some(val) => dwarf.attr_string(&unit, val).ok(),
f035d41b
XL
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]
631 pub fn encoding(&self) -> Encoding {
632 self.header.encoding()
633 }
634
635 /// Read the `DebuggingInformationEntry` at the given offset.
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]
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]
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]
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]
662 pub fn entries_raw(&self, offset: Option<UnitOffset<R::Offset>>) -> Result<EntriesRaw<R>> {
663 self.header.entries_raw(&self.abbreviations, offset)
664 }
fc512014
XL
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.
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 }
f035d41b
XL
676}
677
678impl<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.
682 pub fn to_unit_offset<R>(&self, unit: &Unit<R>) -> Option<UnitOffset<T>>
683 where
684 R: Reader<Offset = T>,
685 {
fc512014 686 let (offset, unit_offset) = match (self, unit.header.offset()) {
f035d41b
XL
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
708impl<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.
713 pub fn to_unit_section_offset<R>(&self, unit: &Unit<R>) -> UnitSectionOffset<T>
714 where
715 R: Reader<Offset = T>,
716 {
fc512014 717 match unit.header.offset() {
f035d41b 718 UnitSectionOffset::DebugInfoOffset(unit_offset) => {
fc512014 719 DebugInfoOffset(unit_offset.0 + self.0).into()
f035d41b
XL
720 }
721 UnitSectionOffset::DebugTypesOffset(unit_offset) => {
fc512014 722 DebugTypesOffset(unit_offset.0 + self.0).into()
f035d41b
XL
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)]
732pub struct RangeIter<R: Reader>(RangeIterInner<R>);
733
734#[derive(Debug)]
735enum RangeIterInner<R: Reader> {
736 Single(Option<Range>),
737 List(RngListIter<R>),
738}
739
740impl<R: Reader> Default for RangeIter<R> {
741 fn default() -> Self {
742 RangeIter(RangeIterInner::Single(None))
743 }
744}
745
746impl<R: Reader> RangeIter<R> {
747 /// Advance the iterator to the next 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")]
757impl<R: Reader> fallible_iterator::FallibleIterator for RangeIter<R> {
758 type Item = Range;
759 type Error = Error;
760
761 #[inline]
762 fn next(&mut self) -> ::core::result::Result<Option<Self::Item>, Self::Error> {
763 RangeIter::next(self)
764 }
765}
766
767#[cfg(test)]
768mod 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]
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]
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]
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}