1 //! This crate provides a cross-platform library and binary for translating addresses into
2 //! function names, file names and line numbers. Given an address in an executable or an
3 //! offset in a section of a relocatable object, it uses the debugging information to
4 //! figure out which file name and line number are associated with it.
5 //!
6 //! When used as a library, files must first be loaded using the
7 //! [`object`](https://github.com/gimli-rs/object) crate.
8 //! A context can then be created with [`Context::new`](./struct.Context.html#method.new).
9 //! The context caches some of the parsed information so that multiple lookups are
10 //! efficient.
11 //! Location information is obtained with
12 //! [`Context::find_location`](./struct.Context.html#method.find_location) or
13 //! [`Context::find_location_range`](./struct.Context.html#method.find_location_range).
14 //! Function information is obtained with
15 //! [`Context::find_frames`](./struct.Context.html#method.find_frames), which returns
16 //! a frame for each inline function. Each frame contains both name and location.
17 //!
18 //! The crate has an example CLI wrapper around the library which provides some of
19 //! the functionality of the `addr2line` command line tool distributed with [GNU
20 //! binutils](https://www.gnu.org/software/binutils/).
21 //!
22 //! Currently this library only provides information from the DWARF debugging information,
23 //! which is parsed using [`gimli`](https://github.com/gimli-rs/gimli).  The example CLI
24 //! wrapper also uses symbol table information provided by the `object` crate.
25 #![deny(missing_docs)]
26 #![no_std]
27 
28 #[allow(unused_imports)]
29 #[macro_use]
30 extern crate alloc;
31 
32 #[cfg(feature = "cpp_demangle")]
33 extern crate cpp_demangle;
34 #[cfg(feature = "fallible-iterator")]
35 pub extern crate fallible_iterator;
36 pub extern crate gimli;
37 #[cfg(feature = "object")]
38 pub extern crate object;
39 #[cfg(feature = "rustc-demangle")]
40 extern crate rustc_demangle;
41 
42 use alloc::borrow::Cow;
43 use alloc::boxed::Box;
44 #[cfg(feature = "object")]
45 use alloc::rc::Rc;
46 use alloc::string::{String, ToString};
47 use alloc::vec::Vec;
48 
49 use core::cmp::{self, Ordering};
50 use core::iter;
51 use core::mem;
52 use core::u64;
53 
54 use crate::lazy::LazyCell;
55 
56 #[cfg(feature = "smallvec")]
57 mod maybe_small {
58     pub type Vec<T> = smallvec::SmallVec<[T; 16]>;
59     pub type IntoIter<T> = smallvec::IntoIter<[T; 16]>;
60 }
61 #[cfg(not(feature = "smallvec"))]
62 mod maybe_small {
63     pub type Vec<T> = alloc::vec::Vec<T>;
64     pub type IntoIter<T> = alloc::vec::IntoIter<T>;
65 }
66 
67 mod lazy;
68 
69 type Error = gimli::Error;
70 
71 /// The state necessary to perform address to line translation.
72 ///
73 /// Constructing a `Context` is somewhat costly, so users should aim to reuse `Context`s
74 /// when performing lookups for many addresses in the same executable.
75 pub struct Context<R>
76 where
77     R: gimli::Reader,
78 {
79     unit_ranges: Vec<UnitRange>,
80     units: Vec<ResUnit<R>>,
81     sections: gimli::Dwarf<R>,
82 }
83 
84 struct UnitRange {
85     unit_id: usize,
86     max_end: u64,
87     range: gimli::Range,
88 }
89 
90 /// The type of `Context` that supports the `new` method.
91 #[cfg(feature = "std-object")]
92 pub type ObjectContext = Context<gimli::EndianRcSlice<gimli::RunTimeEndian>>;
93 
94 #[cfg(feature = "std-object")]
95 impl Context<gimli::EndianRcSlice<gimli::RunTimeEndian>> {
96     /// Construct a new `Context`.
97     ///
98     /// The resulting `Context` uses `gimli::EndianRcSlice<gimli::RunTimeEndian>`.
99     /// This means it is not thread safe, has no lifetime constraints (since it copies
100     /// the input data), and works for any endianity.
101     ///
102     /// Performance sensitive applications may want to use `Context::from_sections`
103     /// with a more specialised `gimli::Reader` implementation.
new<'data: 'file, 'file, O: object::Object<'data, 'file>>( file: &'file O, ) -> Result<Self, Error>104     pub fn new<'data: 'file, 'file, O: object::Object<'data, 'file>>(
105         file: &'file O,
106     ) -> Result<Self, Error> {
107         let endian = if file.is_little_endian() {
108             gimli::RunTimeEndian::Little
109         } else {
110             gimli::RunTimeEndian::Big
111         };
112 
113         fn load_section<'data: 'file, 'file, O, S, Endian>(file: &'file O, endian: Endian) -> S
114         where
115             O: object::Object<'data, 'file>,
116             S: gimli::Section<gimli::EndianRcSlice<Endian>>,
117             Endian: gimli::Endianity,
118         {
119             use object::ObjectSection;
120 
121             let data = file
122                 .section_by_name(S::section_name())
123                 .and_then(|section| section.uncompressed_data().ok())
124                 .unwrap_or(Cow::Borrowed(&[]));
125             S::from(gimli::EndianRcSlice::new(Rc::from(&*data), endian))
126         }
127 
128         let debug_abbrev: gimli::DebugAbbrev<_> = load_section(file, endian);
129         let debug_addr: gimli::DebugAddr<_> = load_section(file, endian);
130         let debug_info: gimli::DebugInfo<_> = load_section(file, endian);
131         let debug_line: gimli::DebugLine<_> = load_section(file, endian);
132         let debug_line_str: gimli::DebugLineStr<_> = load_section(file, endian);
133         let debug_ranges: gimli::DebugRanges<_> = load_section(file, endian);
134         let debug_rnglists: gimli::DebugRngLists<_> = load_section(file, endian);
135         let debug_str: gimli::DebugStr<_> = load_section(file, endian);
136         let debug_str_offsets: gimli::DebugStrOffsets<_> = load_section(file, endian);
137         let default_section = gimli::EndianRcSlice::new(Rc::from(&[][..]), endian);
138 
139         Context::from_sections(
140             debug_abbrev,
141             debug_addr,
142             debug_info,
143             debug_line,
144             debug_line_str,
145             debug_ranges,
146             debug_rnglists,
147             debug_str,
148             debug_str_offsets,
149             default_section,
150         )
151     }
152 }
153 
154 impl<R: gimli::Reader> Context<R> {
155     /// Construct a new `Context` from DWARF sections.
from_sections( debug_abbrev: gimli::DebugAbbrev<R>, debug_addr: gimli::DebugAddr<R>, debug_info: gimli::DebugInfo<R>, debug_line: gimli::DebugLine<R>, debug_line_str: gimli::DebugLineStr<R>, debug_ranges: gimli::DebugRanges<R>, debug_rnglists: gimli::DebugRngLists<R>, debug_str: gimli::DebugStr<R>, debug_str_offsets: gimli::DebugStrOffsets<R>, default_section: R, ) -> Result<Self, Error>156     pub fn from_sections(
157         debug_abbrev: gimli::DebugAbbrev<R>,
158         debug_addr: gimli::DebugAddr<R>,
159         debug_info: gimli::DebugInfo<R>,
160         debug_line: gimli::DebugLine<R>,
161         debug_line_str: gimli::DebugLineStr<R>,
162         debug_ranges: gimli::DebugRanges<R>,
163         debug_rnglists: gimli::DebugRngLists<R>,
164         debug_str: gimli::DebugStr<R>,
165         debug_str_offsets: gimli::DebugStrOffsets<R>,
166         default_section: R,
167     ) -> Result<Self, Error> {
168         Self::from_dwarf(gimli::Dwarf {
169             debug_abbrev,
170             debug_addr,
171             debug_info,
172             debug_line,
173             debug_line_str,
174             debug_str,
175             debug_str_offsets,
176             debug_str_sup: default_section.clone().into(),
177             debug_types: default_section.clone().into(),
178             locations: gimli::LocationLists::new(
179                 default_section.clone().into(),
180                 default_section.clone().into(),
181             ),
182             ranges: gimli::RangeLists::new(debug_ranges, debug_rnglists),
183             file_type: gimli::DwarfFileType::Main,
184         })
185     }
186 
187     /// Construct a new `Context` from an existing [`gimli::Dwarf`] object.
from_dwarf(sections: gimli::Dwarf<R>) -> Result<Self, Error>188     pub fn from_dwarf(sections: gimli::Dwarf<R>) -> Result<Self, Error> {
189         let mut unit_ranges = Vec::new();
190         let mut res_units = Vec::new();
191         let mut units = sections.units();
192         while let Some(header) = units.next()? {
193             let unit_id = res_units.len();
194             let offset = match header.offset().as_debug_info_offset() {
195                 Some(offset) => offset,
196                 None => continue,
197             };
198             let dw_unit = match sections.unit(header) {
199                 Ok(dw_unit) => dw_unit,
200                 Err(_) => continue,
201             };
202 
203             let mut lang = None;
204             {
205                 let mut entries = dw_unit.entries_raw(None)?;
206 
207                 let abbrev = match entries.read_abbreviation()? {
208                     Some(abbrev) if abbrev.tag() == gimli::DW_TAG_compile_unit => abbrev,
209                     _ => continue, // wtf?
210                 };
211 
212                 let mut ranges = RangeAttributes::default();
213                 for spec in abbrev.attributes() {
214                     let attr = entries.read_attribute(*spec)?;
215                     match attr.name() {
216                         gimli::DW_AT_low_pc => {
217                             if let gimli::AttributeValue::Addr(val) = attr.value() {
218                                 ranges.low_pc = Some(val);
219                             }
220                         }
221                         gimli::DW_AT_high_pc => match attr.value() {
222                             gimli::AttributeValue::Addr(val) => ranges.high_pc = Some(val),
223                             gimli::AttributeValue::Udata(val) => ranges.size = Some(val),
224                             _ => {}
225                         },
226                         gimli::DW_AT_ranges => {
227                             ranges.ranges_offset =
228                                 sections.attr_ranges_offset(&dw_unit, attr.value())?;
229                         }
230                         gimli::DW_AT_language => {
231                             if let gimli::AttributeValue::Language(val) = attr.value() {
232                                 lang = Some(val);
233                             }
234                         }
235                         _ => {}
236                     }
237                 }
238 
239                 ranges.for_each_range(&sections, &dw_unit, |range| {
240                     unit_ranges.push(UnitRange {
241                         range,
242                         unit_id,
243                         max_end: 0,
244                     });
245                 })?;
246             }
247 
248             res_units.push(ResUnit {
249                 offset,
250                 dw_unit,
251                 lang,
252                 lines: LazyCell::new(),
253                 funcs: LazyCell::new(),
254             });
255         }
256 
257         // Sort this for faster lookup in `find_unit_and_address` below.
258         unit_ranges.sort_by_key(|i| i.range.begin);
259 
260         // Calculate the `max_end` field now that we've determined the order of
261         // CUs.
262         let mut max = 0;
263         for i in unit_ranges.iter_mut() {
264             max = max.max(i.range.end);
265             i.max_end = max;
266         }
267 
268         Ok(Context {
269             units: res_units,
270             unit_ranges,
271             sections,
272         })
273     }
274 
275     /// The dwarf sections associated with this `Context`.
dwarf(&self) -> &gimli::Dwarf<R>276     pub fn dwarf(&self) -> &gimli::Dwarf<R> {
277         &self.sections
278     }
279 
280     /// Finds the CUs for the function address given.
281     ///
282     /// There might be multiple CUs whose range contains this address.
283     /// Weak symbols have shown up in the wild which cause this to happen
284     /// but otherwise this can happen if the CU has non-contiguous functions
285     /// but only reports a single range.
286     ///
287     /// Consequently we return an iterator for all CUs which may contain the
288     /// address, and the caller must check if there is actually a function or
289     /// location in the CU for that address.
find_units(&self, probe: u64) -> impl Iterator<Item = &ResUnit<R>>290     fn find_units(&self, probe: u64) -> impl Iterator<Item = &ResUnit<R>> {
291         self.find_units_range(probe, probe + 1)
292             .map(|(unit, _range)| unit)
293     }
294 
295     /// Finds the CUs covering the range of addresses given.
296     ///
297     /// The range is [low, high) (ie, the upper bound is exclusive). This can return multiple
298     /// ranges for the same unit.
299     #[inline]
find_units_range( &self, probe_low: u64, probe_high: u64, ) -> impl Iterator<Item = (&ResUnit<R>, &gimli::Range)>300     fn find_units_range(
301         &self,
302         probe_low: u64,
303         probe_high: u64,
304     ) -> impl Iterator<Item = (&ResUnit<R>, &gimli::Range)> {
305         // First up find the position in the array which could have our function
306         // address.
307         let pos = match self
308             .unit_ranges
309             .binary_search_by_key(&probe_high, |i| i.range.begin)
310         {
311             // Although unlikely, we could find an exact match.
312             Ok(i) => i + 1,
313             // No exact match was found, but this probe would fit at slot `i`.
314             // This means that slot `i` is bigger than `probe`, along with all
315             // indices greater than `i`, so we need to search all previous
316             // entries.
317             Err(i) => i,
318         };
319 
320         // Once we have our index we iterate backwards from that position
321         // looking for a matching CU.
322         self.unit_ranges[..pos]
323             .iter()
324             .rev()
325             .take_while(move |i| {
326                 // We know that this CU's start is beneath the probe already because
327                 // of our sorted array.
328                 debug_assert!(i.range.begin <= probe_high);
329 
330                 // Each entry keeps track of the maximum end address seen so far,
331                 // starting from the beginning of the array of unit ranges. We're
332                 // iterating in reverse so if our probe is beyond the maximum range
333                 // of this entry, then it's guaranteed to not fit in any prior
334                 // entries, so we break out.
335                 probe_low < i.max_end
336             })
337             .filter_map(move |i| {
338                 // If this CU doesn't actually contain this address, move to the
339                 // next CU.
340                 if probe_low >= i.range.end || probe_high <= i.range.begin {
341                     return None;
342                 }
343                 Some((&self.units[i.unit_id], &i.range))
344             })
345     }
346 
347     /// Find the DWARF unit corresponding to the given virtual memory address.
find_dwarf_unit(&self, probe: u64) -> Option<&gimli::Unit<R>>348     pub fn find_dwarf_unit(&self, probe: u64) -> Option<&gimli::Unit<R>> {
349         for unit in self.find_units(probe) {
350             match unit.find_function_or_location(probe, &self.sections, &self.units) {
351                 Ok((Some(_), _)) | Ok((_, Some(_))) => return Some(&unit.dw_unit),
352                 _ => {}
353             }
354         }
355         None
356     }
357 
358     /// Find the source file and line corresponding to the given virtual memory address.
find_location(&self, probe: u64) -> Result<Option<Location<'_>>, Error>359     pub fn find_location(&self, probe: u64) -> Result<Option<Location<'_>>, Error> {
360         for unit in self.find_units(probe) {
361             if let Some(location) = unit.find_location(probe, &self.sections)? {
362                 return Ok(Some(location));
363             }
364         }
365         Ok(None)
366     }
367 
368     /// Return source file and lines for a range of addresses. For each location it also
369     /// returns the address and size of the range of the underlying instructions.
find_location_range( &self, probe_low: u64, probe_high: u64, ) -> Result<LocationRangeIter<'_, R>, Error>370     pub fn find_location_range(
371         &self,
372         probe_low: u64,
373         probe_high: u64,
374     ) -> Result<LocationRangeIter<'_, R>, Error> {
375         LocationRangeIter::new(self, probe_low, probe_high)
376     }
377 
378     /// Return an iterator for the function frames corresponding to the given virtual
379     /// memory address.
380     ///
381     /// If the probe address is not for an inline function then only one frame is
382     /// returned.
383     ///
384     /// If the probe address is for an inline function then the first frame corresponds
385     /// to the innermost inline function.  Subsequent frames contain the caller and call
386     /// location, until an non-inline caller is reached.
find_frames(&self, probe: u64) -> Result<FrameIter<R>, Error>387     pub fn find_frames(&self, probe: u64) -> Result<FrameIter<R>, Error> {
388         for unit in self.find_units(probe) {
389             match unit.find_function_or_location(probe, &self.sections, &self.units)? {
390                 (Some(function), location) => {
391                     let inlined_functions = function.find_inlined_functions(probe);
392                     return Ok(FrameIter(FrameIterState::Frames(FrameIterFrames {
393                         unit,
394                         sections: &self.sections,
395                         function,
396                         inlined_functions,
397                         next: location,
398                     })));
399                 }
400                 (None, Some(location)) => {
401                     return Ok(FrameIter(FrameIterState::Location(Some(location))));
402                 }
403                 _ => {}
404             }
405         }
406         Ok(FrameIter(FrameIterState::Empty))
407     }
408 
409     /// Initialize all line data structures. This is used for benchmarks.
410     #[doc(hidden)]
parse_lines(&self) -> Result<(), Error>411     pub fn parse_lines(&self) -> Result<(), Error> {
412         for unit in &self.units {
413             unit.parse_lines(&self.sections)?;
414         }
415         Ok(())
416     }
417 
418     /// Initialize all function data structures. This is used for benchmarks.
419     #[doc(hidden)]
parse_functions(&self) -> Result<(), Error>420     pub fn parse_functions(&self) -> Result<(), Error> {
421         for unit in &self.units {
422             unit.parse_functions(&self.sections)?;
423         }
424         Ok(())
425     }
426 
427     /// Initialize all inlined function data structures. This is used for benchmarks.
428     #[doc(hidden)]
parse_inlined_functions(&self) -> Result<(), Error>429     pub fn parse_inlined_functions(&self) -> Result<(), Error> {
430         for unit in &self.units {
431             unit.parse_inlined_functions(&self.sections, &self.units)?;
432         }
433         Ok(())
434     }
435 }
436 
437 struct Lines {
438     files: Box<[String]>,
439     sequences: Box<[LineSequence]>,
440 }
441 
442 struct LineSequence {
443     start: u64,
444     end: u64,
445     rows: Box<[LineRow]>,
446 }
447 
448 struct LineRow {
449     address: u64,
450     file_index: u64,
451     line: u32,
452     column: u32,
453 }
454 
455 struct ResUnit<R>
456 where
457     R: gimli::Reader,
458 {
459     offset: gimli::DebugInfoOffset<R::Offset>,
460     dw_unit: gimli::Unit<R>,
461     lang: Option<gimli::DwLang>,
462     lines: LazyCell<Result<Lines, Error>>,
463     funcs: LazyCell<Result<Functions<R>, Error>>,
464 }
465 
466 impl<R> ResUnit<R>
467 where
468     R: gimli::Reader,
469 {
parse_lines(&self, sections: &gimli::Dwarf<R>) -> Result<Option<&Lines>, Error>470     fn parse_lines(&self, sections: &gimli::Dwarf<R>) -> Result<Option<&Lines>, Error> {
471         let ilnp = match self.dw_unit.line_program {
472             Some(ref ilnp) => ilnp,
473             None => return Ok(None),
474         };
475         self.lines
476             .borrow_with(|| {
477                 let mut sequences = Vec::new();
478                 let mut sequence_rows = Vec::<LineRow>::new();
479                 let mut rows = ilnp.clone().rows();
480                 while let Some((_, row)) = rows.next_row()? {
481                     if row.end_sequence() {
482                         if let Some(start) = sequence_rows.first().map(|x| x.address) {
483                             let end = row.address();
484                             let mut rows = Vec::new();
485                             mem::swap(&mut rows, &mut sequence_rows);
486                             sequences.push(LineSequence {
487                                 start,
488                                 end,
489                                 rows: rows.into_boxed_slice(),
490                             });
491                         }
492                         continue;
493                     }
494 
495                     let address = row.address();
496                     let file_index = row.file_index();
497                     let line = row.line().unwrap_or(0) as u32;
498                     let column = match row.column() {
499                         gimli::ColumnType::LeftEdge => 0,
500                         gimli::ColumnType::Column(x) => x as u32,
501                     };
502 
503                     if let Some(last_row) = sequence_rows.last_mut() {
504                         if last_row.address == address {
505                             last_row.file_index = file_index;
506                             last_row.line = line;
507                             last_row.column = column;
508                             continue;
509                         }
510                     }
511 
512                     sequence_rows.push(LineRow {
513                         address,
514                         file_index,
515                         line,
516                         column,
517                     });
518                 }
519                 sequences.sort_by_key(|x| x.start);
520 
521                 let mut files = Vec::new();
522                 let header = ilnp.header();
523                 match header.file(0) {
524                     Some(file) => files.push(self.render_file(file, header, sections)?),
525                     None => files.push(String::from("")), // DWARF version <= 4 may not have 0th index
526                 }
527                 let mut index = 1;
528                 while let Some(file) = header.file(index) {
529                     files.push(self.render_file(file, header, sections)?);
530                     index += 1;
531                 }
532 
533                 Ok(Lines {
534                     files: files.into_boxed_slice(),
535                     sequences: sequences.into_boxed_slice(),
536                 })
537             })
538             .as_ref()
539             .map(Some)
540             .map_err(Error::clone)
541     }
542 
parse_functions(&self, sections: &gimli::Dwarf<R>) -> Result<&Functions<R>, Error>543     fn parse_functions(&self, sections: &gimli::Dwarf<R>) -> Result<&Functions<R>, Error> {
544         self.funcs
545             .borrow_with(|| Functions::parse(&self.dw_unit, sections))
546             .as_ref()
547             .map_err(Error::clone)
548     }
549 
parse_inlined_functions( &self, sections: &gimli::Dwarf<R>, units: &[ResUnit<R>], ) -> Result<(), Error>550     fn parse_inlined_functions(
551         &self,
552         sections: &gimli::Dwarf<R>,
553         units: &[ResUnit<R>],
554     ) -> Result<(), Error> {
555         self.funcs
556             .borrow_with(|| Functions::parse(&self.dw_unit, sections))
557             .as_ref()
558             .map_err(Error::clone)?
559             .parse_inlined_functions(&self.dw_unit, sections, units)
560     }
561 
find_location( &self, probe: u64, sections: &gimli::Dwarf<R>, ) -> Result<Option<Location<'_>>, Error>562     fn find_location(
563         &self,
564         probe: u64,
565         sections: &gimli::Dwarf<R>,
566     ) -> Result<Option<Location<'_>>, Error> {
567         if let Some(mut iter) = LocationRangeUnitIter::new(self, sections, probe, probe + 1)? {
568             match iter.next() {
569                 None => Ok(None),
570                 Some((_addr, _len, loc)) => Ok(Some(loc)),
571             }
572         } else {
573             Ok(None)
574         }
575     }
576 
577     #[inline]
find_location_range( &self, probe_low: u64, probe_high: u64, sections: &gimli::Dwarf<R>, ) -> Result<Option<LocationRangeUnitIter<'_>>, Error>578     fn find_location_range(
579         &self,
580         probe_low: u64,
581         probe_high: u64,
582         sections: &gimli::Dwarf<R>,
583     ) -> Result<Option<LocationRangeUnitIter<'_>>, Error> {
584         LocationRangeUnitIter::new(self, sections, probe_low, probe_high)
585     }
586 
find_function_or_location( &self, probe: u64, sections: &gimli::Dwarf<R>, units: &[ResUnit<R>], ) -> Result<(Option<&Function<R>>, Option<Location<'_>>), Error>587     fn find_function_or_location(
588         &self,
589         probe: u64,
590         sections: &gimli::Dwarf<R>,
591         units: &[ResUnit<R>],
592     ) -> Result<(Option<&Function<R>>, Option<Location<'_>>), Error> {
593         let functions = self.parse_functions(sections)?;
594         let function = match functions.find_address(probe) {
595             Some(address) => {
596                 let function_index = functions.addresses[address].function;
597                 let (offset, ref function) = functions.functions[function_index];
598                 Some(
599                     function
600                         .borrow_with(|| Function::parse(offset, &self.dw_unit, sections, units))
601                         .as_ref()
602                         .map_err(Error::clone)?,
603                 )
604             }
605             None => None,
606         };
607         let location = self.find_location(probe, sections)?;
608         Ok((function, location))
609     }
610 
render_file( &self, file: &gimli::FileEntry<R, R::Offset>, header: &gimli::LineProgramHeader<R, R::Offset>, sections: &gimli::Dwarf<R>, ) -> Result<String, gimli::Error>611     fn render_file(
612         &self,
613         file: &gimli::FileEntry<R, R::Offset>,
614         header: &gimli::LineProgramHeader<R, R::Offset>,
615         sections: &gimli::Dwarf<R>,
616     ) -> Result<String, gimli::Error> {
617         let mut path = if let Some(ref comp_dir) = self.dw_unit.comp_dir {
618             comp_dir.to_string_lossy()?.into_owned()
619         } else {
620             String::new()
621         };
622 
623         if let Some(directory) = file.directory(header) {
624             path_push(
625                 &mut path,
626                 sections
627                     .attr_string(&self.dw_unit, directory)?
628                     .to_string_lossy()?
629                     .as_ref(),
630             );
631         }
632 
633         path_push(
634             &mut path,
635             sections
636                 .attr_string(&self.dw_unit, file.path_name())?
637                 .to_string_lossy()?
638                 .as_ref(),
639         );
640 
641         Ok(path)
642     }
643 }
644 
645 /// Iterator over `Location`s in a range of addresses, returned by `Context::find_location_range`.
646 pub struct LocationRangeIter<'ctx, R: gimli::Reader> {
647     unit_iter: Box<dyn Iterator<Item = (&'ctx ResUnit<R>, &'ctx gimli::Range)> + 'ctx>,
648     iter: Option<LocationRangeUnitIter<'ctx>>,
649 
650     probe_low: u64,
651     probe_high: u64,
652     sections: &'ctx gimli::Dwarf<R>,
653 }
654 
655 impl<'ctx, R: gimli::Reader> LocationRangeIter<'ctx, R> {
656     #[inline]
new(ctx: &'ctx Context<R>, probe_low: u64, probe_high: u64) -> Result<Self, Error>657     fn new(ctx: &'ctx Context<R>, probe_low: u64, probe_high: u64) -> Result<Self, Error> {
658         let sections = &ctx.sections;
659         let unit_iter = ctx.find_units_range(probe_low, probe_high);
660         Ok(Self {
661             unit_iter: Box::new(unit_iter),
662             iter: None,
663             probe_low,
664             probe_high,
665             sections,
666         })
667     }
668 
next_loc(&mut self) -> Result<Option<(u64, u64, Location<'ctx>)>, Error>669     fn next_loc(&mut self) -> Result<Option<(u64, u64, Location<'ctx>)>, Error> {
670         loop {
671             let iter = self.iter.take();
672             match iter {
673                 None => match self.unit_iter.next() {
674                     Some((unit, range)) => {
675                         self.iter = unit.find_location_range(
676                             cmp::max(self.probe_low, range.begin),
677                             cmp::min(self.probe_high, range.end),
678                             self.sections,
679                         )?;
680                     }
681                     None => return Ok(None),
682                 },
683                 Some(mut iter) => {
684                     if let item @ Some(_) = iter.next() {
685                         self.iter = Some(iter);
686                         return Ok(item);
687                     }
688                 }
689             }
690         }
691     }
692 }
693 
694 impl<'ctx, R> Iterator for LocationRangeIter<'ctx, R>
695 where
696     R: gimli::Reader + 'ctx,
697 {
698     type Item = (u64, u64, Location<'ctx>);
699 
700     #[inline]
next(&mut self) -> Option<Self::Item>701     fn next(&mut self) -> Option<Self::Item> {
702         match self.next_loc() {
703             Err(_) => None,
704             Ok(loc) => loc,
705         }
706     }
707 }
708 
709 #[cfg(feature = "fallible-iterator")]
710 impl<'ctx, R> fallible_iterator::FallibleIterator for LocationRangeIter<'ctx, R>
711 where
712     R: gimli::Reader + 'ctx,
713 {
714     type Item = (u64, u64, Location<'ctx>);
715     type Error = Error;
716 
717     #[inline]
next(&mut self) -> Result<Option<Self::Item>, Self::Error>718     fn next(&mut self) -> Result<Option<Self::Item>, Self::Error> {
719         self.next_loc()
720     }
721 }
722 
723 struct LocationRangeUnitIter<'ctx> {
724     lines: &'ctx Lines,
725     seqs: &'ctx [LineSequence],
726     seq_idx: usize,
727     row_idx: usize,
728     probe_high: u64,
729 }
730 
731 impl<'ctx> LocationRangeUnitIter<'ctx> {
new<R: gimli::Reader>( resunit: &'ctx ResUnit<R>, sections: &gimli::Dwarf<R>, probe_low: u64, probe_high: u64, ) -> Result<Option<Self>, Error>732     fn new<R: gimli::Reader>(
733         resunit: &'ctx ResUnit<R>,
734         sections: &gimli::Dwarf<R>,
735         probe_low: u64,
736         probe_high: u64,
737     ) -> Result<Option<Self>, Error> {
738         let lines = resunit.parse_lines(sections)?;
739 
740         if let Some(lines) = lines {
741             // Find index for probe_low.
742             let seq_idx = lines.sequences.binary_search_by(|sequence| {
743                 if probe_low < sequence.start {
744                     Ordering::Greater
745                 } else if probe_low >= sequence.end {
746                     Ordering::Less
747                 } else {
748                     Ordering::Equal
749                 }
750             });
751             let seq_idx = match seq_idx {
752                 Ok(x) => x,
753                 Err(0) => 0, // probe below sequence, but range could overlap
754                 Err(_) => lines.sequences.len(),
755             };
756 
757             let row_idx = if let Some(seq) = lines.sequences.get(seq_idx) {
758                 let idx = seq.rows.binary_search_by(|row| row.address.cmp(&probe_low));
759                 let idx = match idx {
760                     Ok(x) => x,
761                     Err(0) => 0, // probe below sequence, but range could overlap
762                     Err(x) => x - 1,
763                 };
764                 idx
765             } else {
766                 0
767             };
768 
769             Ok(Some(Self {
770                 lines,
771                 seqs: &*lines.sequences,
772                 seq_idx,
773                 row_idx,
774                 probe_high,
775             }))
776         } else {
777             Ok(None)
778         }
779     }
780 }
781 
782 impl<'ctx> Iterator for LocationRangeUnitIter<'ctx> {
783     type Item = (u64, u64, Location<'ctx>);
784 
next(&mut self) -> Option<(u64, u64, Location<'ctx>)>785     fn next(&mut self) -> Option<(u64, u64, Location<'ctx>)> {
786         loop {
787             let seq = match self.seqs.get(self.seq_idx) {
788                 Some(seq) => seq,
789                 None => break,
790             };
791 
792             if seq.start >= self.probe_high {
793                 break;
794             }
795 
796             match seq.rows.get(self.row_idx) {
797                 Some(row) => {
798                     if row.address >= self.probe_high {
799                         break;
800                     }
801 
802                     let file = self
803                         .lines
804                         .files
805                         .get(row.file_index as usize)
806                         .map(String::as_str);
807                     let nextaddr = seq
808                         .rows
809                         .get(self.row_idx + 1)
810                         .map(|row| row.address)
811                         .unwrap_or(seq.end);
812 
813                     let item = (
814                         row.address,
815                         nextaddr - row.address,
816                         Location {
817                             file,
818                             line: if row.line != 0 { Some(row.line) } else { None },
819                             column: if row.column != 0 {
820                                 Some(row.column)
821                             } else {
822                                 None
823                             },
824                         },
825                     );
826                     self.row_idx += 1;
827 
828                     return Some(item);
829                 }
830                 None => {
831                     self.seq_idx += 1;
832                     self.row_idx = 0;
833                 }
834             }
835         }
836         None
837     }
838 }
839 
path_push(path: &mut String, p: &str)840 fn path_push(path: &mut String, p: &str) {
841     if p.starts_with('/') {
842         *path = p.to_string();
843     } else {
844         if !path.ends_with('/') {
845             path.push('/');
846         }
847         *path += p;
848     }
849 }
850 
name_attr<R>( attr: gimli::AttributeValue<R>, unit: &gimli::Unit<R>, sections: &gimli::Dwarf<R>, units: &[ResUnit<R>], recursion_limit: usize, ) -> Result<Option<R>, Error> where R: gimli::Reader,851 fn name_attr<R>(
852     attr: gimli::AttributeValue<R>,
853     unit: &gimli::Unit<R>,
854     sections: &gimli::Dwarf<R>,
855     units: &[ResUnit<R>],
856     recursion_limit: usize,
857 ) -> Result<Option<R>, Error>
858 where
859     R: gimli::Reader,
860 {
861     if recursion_limit == 0 {
862         return Ok(None);
863     }
864 
865     let (unit, offset) = match attr {
866         gimli::AttributeValue::UnitRef(offset) => (unit, offset),
867         gimli::AttributeValue::DebugInfoRef(dr) => {
868             let res_unit = match units.binary_search_by_key(&dr.0, |unit| unit.offset.0) {
869                 // There is never a DIE at the unit offset or before the first unit.
870                 Ok(_) | Err(0) => return Err(gimli::Error::NoEntryAtGivenOffset),
871                 Err(i) => &units[i - 1],
872             };
873             (
874                 &res_unit.dw_unit,
875                 gimli::UnitOffset(dr.0 - res_unit.offset.0),
876             )
877         }
878         _ => return Ok(None),
879     };
880 
881     let mut entries = unit.entries_raw(Some(offset))?;
882     let abbrev = if let Some(abbrev) = entries.read_abbreviation()? {
883         abbrev
884     } else {
885         return Err(gimli::Error::NoEntryAtGivenOffset);
886     };
887 
888     let mut name = None;
889     let mut next = None;
890     for spec in abbrev.attributes() {
891         match entries.read_attribute(*spec) {
892             Ok(ref attr) => match attr.name() {
893                 gimli::DW_AT_linkage_name | gimli::DW_AT_MIPS_linkage_name => {
894                     if let Ok(val) = sections.attr_string(unit, attr.value()) {
895                         return Ok(Some(val));
896                     }
897                 }
898                 gimli::DW_AT_name => {
899                     if let Ok(val) = sections.attr_string(unit, attr.value()) {
900                         name = Some(val);
901                     }
902                 }
903                 gimli::DW_AT_abstract_origin | gimli::DW_AT_specification => {
904                     next = Some(attr.value());
905                 }
906                 _ => {}
907             },
908             Err(e) => return Err(e),
909         }
910     }
911 
912     if name.is_some() {
913         return Ok(name);
914     }
915 
916     if let Some(next) = next {
917         return name_attr(next, unit, sections, units, recursion_limit - 1);
918     }
919 
920     Ok(None)
921 }
922 
923 struct Functions<R: gimli::Reader> {
924     /// List of all `DW_TAG_subprogram` details in the unit.
925     functions: Box<
926         [(
927             gimli::UnitOffset<R::Offset>,
928             LazyCell<Result<Function<R>, Error>>,
929         )],
930     >,
931     /// List of `DW_TAG_subprogram` address ranges in the unit.
932     addresses: Box<[FunctionAddress]>,
933 }
934 
935 /// A single address range for a function.
936 ///
937 /// It is possible for a function to have multiple address ranges; this
938 /// is handled by having multiple `FunctionAddress` entries with the same
939 /// `function` field.
940 struct FunctionAddress {
941     range: gimli::Range,
942     /// An index into `Functions::functions`.
943     function: usize,
944 }
945 
946 struct Function<R: gimli::Reader> {
947     dw_die_offset: gimli::UnitOffset<R::Offset>,
948     name: Option<R>,
949     /// List of all `DW_TAG_inlined_subroutine` details in this function.
950     inlined_functions: Box<[InlinedFunction<R>]>,
951     /// List of `DW_TAG_inlined_subroutine` address ranges in this function.
952     inlined_addresses: Box<[InlinedFunctionAddress]>,
953 }
954 
955 struct InlinedFunctionAddress {
956     range: gimli::Range,
957     call_depth: usize,
958     /// An index into `Function::inlined_functions`.
959     function: usize,
960 }
961 
962 struct InlinedFunction<R: gimli::Reader> {
963     dw_die_offset: gimli::UnitOffset<R::Offset>,
964     name: Option<R>,
965     call_file: u64,
966     call_line: u32,
967     call_column: u32,
968 }
969 
970 impl<R: gimli::Reader> Functions<R> {
parse(unit: &gimli::Unit<R>, sections: &gimli::Dwarf<R>) -> Result<Functions<R>, Error>971     fn parse(unit: &gimli::Unit<R>, sections: &gimli::Dwarf<R>) -> Result<Functions<R>, Error> {
972         let mut functions = Vec::new();
973         let mut addresses = Vec::new();
974         let mut entries = unit.entries_raw(None)?;
975         while !entries.is_empty() {
976             let dw_die_offset = entries.next_offset();
977             if let Some(abbrev) = entries.read_abbreviation()? {
978                 if abbrev.tag() == gimli::DW_TAG_subprogram {
979                     let mut ranges = RangeAttributes::default();
980                     for spec in abbrev.attributes() {
981                         match entries.read_attribute(*spec) {
982                             Ok(ref attr) => {
983                                 match attr.name() {
984                                     gimli::DW_AT_low_pc => {
985                                         if let gimli::AttributeValue::Addr(val) = attr.value() {
986                                             ranges.low_pc = Some(val);
987                                         }
988                                     }
989                                     gimli::DW_AT_high_pc => match attr.value() {
990                                         gimli::AttributeValue::Addr(val) => {
991                                             ranges.high_pc = Some(val)
992                                         }
993                                         gimli::AttributeValue::Udata(val) => {
994                                             ranges.size = Some(val)
995                                         }
996                                         _ => {}
997                                     },
998                                     gimli::DW_AT_ranges => {
999                                         ranges.ranges_offset =
1000                                             sections.attr_ranges_offset(unit, attr.value())?;
1001                                     }
1002                                     _ => {}
1003                                 };
1004                             }
1005                             Err(e) => return Err(e),
1006                         }
1007                     }
1008 
1009                     let function_index = functions.len();
1010                     if ranges.for_each_range(sections, unit, |range| {
1011                         addresses.push(FunctionAddress {
1012                             range,
1013                             function: function_index,
1014                         });
1015                     })? {
1016                         functions.push((dw_die_offset, LazyCell::new()));
1017                     }
1018                 } else {
1019                     for spec in abbrev.attributes() {
1020                         match entries.read_attribute(*spec) {
1021                             Ok(_) => {}
1022                             Err(e) => return Err(e),
1023                         }
1024                     }
1025                 }
1026             }
1027         }
1028 
1029         // The binary search requires the addresses to be sorted.
1030         //
1031         // It also requires them to be non-overlapping.  In practice, overlapping
1032         // function ranges are unlikely, so we don't try to handle that yet.
1033         //
1034         // It's possible for multiple functions to have the same address range if the
1035         // compiler can detect and remove functions with identical code.  In that case
1036         // we'll nondeterministically return one of them.
1037         addresses.sort_by_key(|x| x.range.begin);
1038 
1039         Ok(Functions {
1040             functions: functions.into_boxed_slice(),
1041             addresses: addresses.into_boxed_slice(),
1042         })
1043     }
1044 
find_address(&self, probe: u64) -> Option<usize>1045     fn find_address(&self, probe: u64) -> Option<usize> {
1046         self.addresses
1047             .binary_search_by(|address| {
1048                 if probe < address.range.begin {
1049                     Ordering::Greater
1050                 } else if probe >= address.range.end {
1051                     Ordering::Less
1052                 } else {
1053                     Ordering::Equal
1054                 }
1055             })
1056             .ok()
1057     }
1058 
parse_inlined_functions( &self, unit: &gimli::Unit<R>, sections: &gimli::Dwarf<R>, units: &[ResUnit<R>], ) -> Result<(), Error>1059     fn parse_inlined_functions(
1060         &self,
1061         unit: &gimli::Unit<R>,
1062         sections: &gimli::Dwarf<R>,
1063         units: &[ResUnit<R>],
1064     ) -> Result<(), Error> {
1065         for function in &*self.functions {
1066             function
1067                 .1
1068                 .borrow_with(|| Function::parse(function.0, unit, sections, units))
1069                 .as_ref()
1070                 .map_err(Error::clone)?;
1071         }
1072         Ok(())
1073     }
1074 }
1075 
1076 impl<R: gimli::Reader> Function<R> {
parse( dw_die_offset: gimli::UnitOffset<R::Offset>, unit: &gimli::Unit<R>, sections: &gimli::Dwarf<R>, units: &[ResUnit<R>], ) -> Result<Self, Error>1077     fn parse(
1078         dw_die_offset: gimli::UnitOffset<R::Offset>,
1079         unit: &gimli::Unit<R>,
1080         sections: &gimli::Dwarf<R>,
1081         units: &[ResUnit<R>],
1082     ) -> Result<Self, Error> {
1083         let mut entries = unit.entries_raw(Some(dw_die_offset))?;
1084         let depth = entries.next_depth();
1085         let abbrev = entries.read_abbreviation()?.unwrap();
1086         debug_assert_eq!(abbrev.tag(), gimli::DW_TAG_subprogram);
1087 
1088         let mut name = None;
1089         for spec in abbrev.attributes() {
1090             match entries.read_attribute(*spec) {
1091                 Ok(ref attr) => {
1092                     match attr.name() {
1093                         gimli::DW_AT_linkage_name | gimli::DW_AT_MIPS_linkage_name => {
1094                             if let Ok(val) = sections.attr_string(unit, attr.value()) {
1095                                 name = Some(val);
1096                             }
1097                         }
1098                         gimli::DW_AT_name => {
1099                             if name.is_none() {
1100                                 name = sections.attr_string(unit, attr.value()).ok();
1101                             }
1102                         }
1103                         gimli::DW_AT_abstract_origin | gimli::DW_AT_specification => {
1104                             if name.is_none() {
1105                                 name = name_attr(attr.value(), unit, sections, units, 16)?;
1106                             }
1107                         }
1108                         _ => {}
1109                     };
1110                 }
1111                 Err(e) => return Err(e),
1112             }
1113         }
1114 
1115         let mut inlined_functions = Vec::new();
1116         let mut inlined_addresses = Vec::new();
1117         Function::parse_children(
1118             &mut entries,
1119             depth,
1120             unit,
1121             sections,
1122             units,
1123             &mut inlined_functions,
1124             &mut inlined_addresses,
1125             0,
1126         )?;
1127 
1128         // Sort ranges in "breadth-first traversal order", i.e. first by call_depth
1129         // and then by range.begin. This allows finding the range containing an
1130         // address at a certain depth using binary search.
1131         // Note: Using DFS order, i.e. ordering by range.begin first and then by
1132         // call_depth, would not work! Consider the two examples
1133         // "[0..10 at depth 0], [0..2 at depth 1], [6..8 at depth 1]"  and
1134         // "[0..5 at depth 0], [0..2 at depth 1], [5..10 at depth 0], [6..8 at depth 1]".
1135         // In this example, if you want to look up address 7 at depth 0, and you
1136         // encounter [0..2 at depth 1], are you before or after the target range?
1137         // You don't know.
1138         inlined_addresses.sort_by(|r1, r2| {
1139             if r1.call_depth < r2.call_depth {
1140                 Ordering::Less
1141             } else if r1.call_depth > r2.call_depth {
1142                 Ordering::Greater
1143             } else if r1.range.begin < r2.range.begin {
1144                 Ordering::Less
1145             } else if r1.range.begin > r2.range.begin {
1146                 Ordering::Greater
1147             } else {
1148                 Ordering::Equal
1149             }
1150         });
1151 
1152         Ok(Function {
1153             dw_die_offset,
1154             name,
1155             inlined_functions: inlined_functions.into_boxed_slice(),
1156             inlined_addresses: inlined_addresses.into_boxed_slice(),
1157         })
1158     }
1159 
parse_children( entries: &mut gimli::EntriesRaw<R>, depth: isize, unit: &gimli::Unit<R>, sections: &gimli::Dwarf<R>, units: &[ResUnit<R>], inlined_functions: &mut Vec<InlinedFunction<R>>, inlined_addresses: &mut Vec<InlinedFunctionAddress>, inlined_depth: usize, ) -> Result<(), Error>1160     fn parse_children(
1161         entries: &mut gimli::EntriesRaw<R>,
1162         depth: isize,
1163         unit: &gimli::Unit<R>,
1164         sections: &gimli::Dwarf<R>,
1165         units: &[ResUnit<R>],
1166         inlined_functions: &mut Vec<InlinedFunction<R>>,
1167         inlined_addresses: &mut Vec<InlinedFunctionAddress>,
1168         inlined_depth: usize,
1169     ) -> Result<(), Error> {
1170         loop {
1171             let dw_die_offset = entries.next_offset();
1172             let next_depth = entries.next_depth();
1173             if next_depth <= depth {
1174                 return Ok(());
1175             }
1176             if let Some(abbrev) = entries.read_abbreviation()? {
1177                 match abbrev.tag() {
1178                     gimli::DW_TAG_subprogram => {
1179                         Function::skip(entries, abbrev, next_depth)?;
1180                     }
1181                     gimli::DW_TAG_inlined_subroutine => {
1182                         InlinedFunction::parse(
1183                             dw_die_offset,
1184                             entries,
1185                             abbrev,
1186                             next_depth,
1187                             unit,
1188                             sections,
1189                             units,
1190                             inlined_functions,
1191                             inlined_addresses,
1192                             inlined_depth,
1193                         )?;
1194                     }
1195                     _ => {
1196                         for spec in abbrev.attributes() {
1197                             match entries.read_attribute(*spec) {
1198                                 Ok(_) => {}
1199                                 Err(e) => return Err(e),
1200                             }
1201                         }
1202                     }
1203                 }
1204             }
1205         }
1206     }
1207 
skip( entries: &mut gimli::EntriesRaw<R>, abbrev: &gimli::Abbreviation, depth: isize, ) -> Result<(), Error>1208     fn skip(
1209         entries: &mut gimli::EntriesRaw<R>,
1210         abbrev: &gimli::Abbreviation,
1211         depth: isize,
1212     ) -> Result<(), Error> {
1213         // TODO: use DW_AT_sibling
1214         for spec in abbrev.attributes() {
1215             match entries.read_attribute(*spec) {
1216                 Ok(_) => {}
1217                 Err(e) => return Err(e),
1218             }
1219         }
1220         while entries.next_depth() > depth {
1221             if let Some(abbrev) = entries.read_abbreviation()? {
1222                 for spec in abbrev.attributes() {
1223                     match entries.read_attribute(*spec) {
1224                         Ok(_) => {}
1225                         Err(e) => return Err(e),
1226                     }
1227                 }
1228             }
1229         }
1230         Ok(())
1231     }
1232 
1233     /// Build the list of inlined functions that contain `probe`.
find_inlined_functions( &self, probe: u64, ) -> iter::Rev<maybe_small::IntoIter<&InlinedFunction<R>>>1234     fn find_inlined_functions(
1235         &self,
1236         probe: u64,
1237     ) -> iter::Rev<maybe_small::IntoIter<&InlinedFunction<R>>> {
1238         // `inlined_functions` is ordered from outside to inside.
1239         let mut inlined_functions = maybe_small::Vec::new();
1240         let mut inlined_addresses = &self.inlined_addresses[..];
1241         loop {
1242             let current_depth = inlined_functions.len();
1243             // Look up (probe, current_depth) in inline_ranges.
1244             // `inlined_addresses` is sorted in "breadth-first traversal order", i.e.
1245             // by `call_depth` first, and then by `range.begin`. See the comment at
1246             // the sort call for more information about why.
1247             let search = inlined_addresses.binary_search_by(|range| {
1248                 if range.call_depth > current_depth {
1249                     Ordering::Greater
1250                 } else if range.call_depth < current_depth {
1251                     Ordering::Less
1252                 } else if range.range.begin > probe {
1253                     Ordering::Greater
1254                 } else if range.range.end <= probe {
1255                     Ordering::Less
1256                 } else {
1257                     Ordering::Equal
1258                 }
1259             });
1260             if let Ok(index) = search {
1261                 let function_index = inlined_addresses[index].function;
1262                 inlined_functions.push(&self.inlined_functions[function_index]);
1263                 inlined_addresses = &inlined_addresses[index + 1..];
1264             } else {
1265                 break;
1266             }
1267         }
1268         inlined_functions.into_iter().rev()
1269     }
1270 }
1271 
1272 impl<R: gimli::Reader> InlinedFunction<R> {
parse( dw_die_offset: gimli::UnitOffset<R::Offset>, entries: &mut gimli::EntriesRaw<R>, abbrev: &gimli::Abbreviation, depth: isize, unit: &gimli::Unit<R>, sections: &gimli::Dwarf<R>, units: &[ResUnit<R>], inlined_functions: &mut Vec<InlinedFunction<R>>, inlined_addresses: &mut Vec<InlinedFunctionAddress>, inlined_depth: usize, ) -> Result<(), Error>1273     fn parse(
1274         dw_die_offset: gimli::UnitOffset<R::Offset>,
1275         entries: &mut gimli::EntriesRaw<R>,
1276         abbrev: &gimli::Abbreviation,
1277         depth: isize,
1278         unit: &gimli::Unit<R>,
1279         sections: &gimli::Dwarf<R>,
1280         units: &[ResUnit<R>],
1281         inlined_functions: &mut Vec<InlinedFunction<R>>,
1282         inlined_addresses: &mut Vec<InlinedFunctionAddress>,
1283         inlined_depth: usize,
1284     ) -> Result<(), Error> {
1285         let mut ranges = RangeAttributes::default();
1286         let mut name = None;
1287         let mut call_file = 0;
1288         let mut call_line = 0;
1289         let mut call_column = 0;
1290         for spec in abbrev.attributes() {
1291             match entries.read_attribute(*spec) {
1292                 Ok(ref attr) => match attr.name() {
1293                     gimli::DW_AT_low_pc => {
1294                         if let gimli::AttributeValue::Addr(val) = attr.value() {
1295                             ranges.low_pc = Some(val);
1296                         }
1297                     }
1298                     gimli::DW_AT_high_pc => match attr.value() {
1299                         gimli::AttributeValue::Addr(val) => ranges.high_pc = Some(val),
1300                         gimli::AttributeValue::Udata(val) => ranges.size = Some(val),
1301                         _ => {}
1302                     },
1303                     gimli::DW_AT_ranges => {
1304                         ranges.ranges_offset = sections.attr_ranges_offset(unit, attr.value())?;
1305                     }
1306                     gimli::DW_AT_linkage_name | gimli::DW_AT_MIPS_linkage_name => {
1307                         if let Ok(val) = sections.attr_string(unit, attr.value()) {
1308                             name = Some(val);
1309                         }
1310                     }
1311                     gimli::DW_AT_name => {
1312                         if name.is_none() {
1313                             name = sections.attr_string(unit, attr.value()).ok();
1314                         }
1315                     }
1316                     gimli::DW_AT_abstract_origin | gimli::DW_AT_specification => {
1317                         if name.is_none() {
1318                             name = name_attr(attr.value(), unit, sections, units, 16)?;
1319                         }
1320                     }
1321                     gimli::DW_AT_call_file => {
1322                         if let gimli::AttributeValue::FileIndex(fi) = attr.value() {
1323                             call_file = fi;
1324                         }
1325                     }
1326                     gimli::DW_AT_call_line => {
1327                         call_line = attr.udata_value().unwrap_or(0) as u32;
1328                     }
1329                     gimli::DW_AT_call_column => {
1330                         call_column = attr.udata_value().unwrap_or(0) as u32;
1331                     }
1332                     _ => {}
1333                 },
1334                 Err(e) => return Err(e),
1335             }
1336         }
1337 
1338         let function_index = inlined_functions.len();
1339         inlined_functions.push(InlinedFunction {
1340             dw_die_offset,
1341             name,
1342             call_file,
1343             call_line,
1344             call_column,
1345         });
1346 
1347         ranges.for_each_range(sections, unit, |range| {
1348             inlined_addresses.push(InlinedFunctionAddress {
1349                 range,
1350                 call_depth: inlined_depth,
1351                 function: function_index,
1352             });
1353         })?;
1354 
1355         Function::parse_children(
1356             entries,
1357             depth,
1358             unit,
1359             sections,
1360             units,
1361             inlined_functions,
1362             inlined_addresses,
1363             inlined_depth + 1,
1364         )
1365     }
1366 }
1367 
1368 struct RangeAttributes<R: gimli::Reader> {
1369     low_pc: Option<u64>,
1370     high_pc: Option<u64>,
1371     size: Option<u64>,
1372     ranges_offset: Option<gimli::RangeListsOffset<<R as gimli::Reader>::Offset>>,
1373 }
1374 
1375 impl<R: gimli::Reader> Default for RangeAttributes<R> {
default() -> Self1376     fn default() -> Self {
1377         RangeAttributes {
1378             low_pc: None,
1379             high_pc: None,
1380             size: None,
1381             ranges_offset: None,
1382         }
1383     }
1384 }
1385 
1386 impl<R: gimli::Reader> RangeAttributes<R> {
for_each_range<F: FnMut(gimli::Range)>( &self, sections: &gimli::Dwarf<R>, unit: &gimli::Unit<R>, mut f: F, ) -> Result<bool, Error>1387     fn for_each_range<F: FnMut(gimli::Range)>(
1388         &self,
1389         sections: &gimli::Dwarf<R>,
1390         unit: &gimli::Unit<R>,
1391         mut f: F,
1392     ) -> Result<bool, Error> {
1393         let mut added_any = false;
1394         let mut add_range = |range: gimli::Range| {
1395             if range.begin < range.end {
1396                 f(range);
1397                 added_any = true
1398             }
1399         };
1400         if let Some(ranges_offset) = self.ranges_offset {
1401             let mut range_list = sections.ranges(unit, ranges_offset)?;
1402             while let Some(range) = range_list.next()? {
1403                 add_range(range);
1404             }
1405         } else if let (Some(begin), Some(end)) = (self.low_pc, self.high_pc) {
1406             add_range(gimli::Range { begin, end });
1407         } else if let (Some(begin), Some(size)) = (self.low_pc, self.size) {
1408             add_range(gimli::Range {
1409                 begin,
1410                 end: begin + size,
1411             });
1412         }
1413         Ok(added_any)
1414     }
1415 }
1416 
1417 /// An iterator over function frames.
1418 pub struct FrameIter<'ctx, R>(FrameIterState<'ctx, R>)
1419 where
1420     R: gimli::Reader + 'ctx;
1421 
1422 enum FrameIterState<'ctx, R>
1423 where
1424     R: gimli::Reader + 'ctx,
1425 {
1426     Empty,
1427     Location(Option<Location<'ctx>>),
1428     Frames(FrameIterFrames<'ctx, R>),
1429 }
1430 
1431 struct FrameIterFrames<'ctx, R>
1432 where
1433     R: gimli::Reader + 'ctx,
1434 {
1435     unit: &'ctx ResUnit<R>,
1436     sections: &'ctx gimli::Dwarf<R>,
1437     function: &'ctx Function<R>,
1438     inlined_functions: iter::Rev<maybe_small::IntoIter<&'ctx InlinedFunction<R>>>,
1439     next: Option<Location<'ctx>>,
1440 }
1441 
1442 impl<'ctx, R> FrameIter<'ctx, R>
1443 where
1444     R: gimli::Reader + 'ctx,
1445 {
1446     /// Advances the iterator and returns the next frame.
next(&mut self) -> Result<Option<Frame<'ctx, R>>, Error>1447     pub fn next(&mut self) -> Result<Option<Frame<'ctx, R>>, Error> {
1448         let frames = match &mut self.0 {
1449             FrameIterState::Empty => return Ok(None),
1450             FrameIterState::Location(location) => {
1451                 // We can't move out of a mutable reference, so use `take` instead.
1452                 let location = location.take();
1453                 self.0 = FrameIterState::Empty;
1454                 return Ok(Some(Frame {
1455                     dw_die_offset: None,
1456                     function: None,
1457                     location,
1458                 }));
1459             }
1460             FrameIterState::Frames(frames) => frames,
1461         };
1462 
1463         let loc = frames.next.take();
1464         let func = match frames.inlined_functions.next() {
1465             Some(func) => func,
1466             None => {
1467                 let frame = Frame {
1468                     dw_die_offset: Some(frames.function.dw_die_offset),
1469                     function: frames.function.name.clone().map(|name| FunctionName {
1470                         name,
1471                         language: frames.unit.lang,
1472                     }),
1473                     location: loc,
1474                 };
1475                 self.0 = FrameIterState::Empty;
1476                 return Ok(Some(frame));
1477             }
1478         };
1479 
1480         let mut next = Location {
1481             file: None,
1482             line: if func.call_line != 0 {
1483                 Some(func.call_line)
1484             } else {
1485                 None
1486             },
1487             column: if func.call_column != 0 {
1488                 Some(func.call_column)
1489             } else {
1490                 None
1491             },
1492         };
1493         if func.call_file != 0 {
1494             if let Some(lines) = frames.unit.parse_lines(frames.sections)? {
1495                 next.file = lines.files.get(func.call_file as usize).map(String::as_str);
1496             }
1497         }
1498         frames.next = Some(next);
1499 
1500         Ok(Some(Frame {
1501             dw_die_offset: Some(func.dw_die_offset),
1502             function: func.name.clone().map(|name| FunctionName {
1503                 name,
1504                 language: frames.unit.lang,
1505             }),
1506             location: loc,
1507         }))
1508     }
1509 }
1510 
1511 #[cfg(feature = "fallible-iterator")]
1512 impl<'ctx, R> fallible_iterator::FallibleIterator for FrameIter<'ctx, R>
1513 where
1514     R: gimli::Reader + 'ctx,
1515 {
1516     type Item = Frame<'ctx, R>;
1517     type Error = Error;
1518 
1519     #[inline]
next(&mut self) -> Result<Option<Frame<'ctx, R>>, Error>1520     fn next(&mut self) -> Result<Option<Frame<'ctx, R>>, Error> {
1521         self.next()
1522     }
1523 }
1524 
1525 /// A function frame.
1526 pub struct Frame<'ctx, R: gimli::Reader> {
1527     /// The DWARF unit offset corresponding to the DIE of the function.
1528     pub dw_die_offset: Option<gimli::UnitOffset<R::Offset>>,
1529     /// The name of the function.
1530     pub function: Option<FunctionName<R>>,
1531     /// The source location corresponding to this frame.
1532     pub location: Option<Location<'ctx>>,
1533 }
1534 
1535 /// A function name.
1536 pub struct FunctionName<R: gimli::Reader> {
1537     /// The name of the function.
1538     pub name: R,
1539     /// The language of the compilation unit containing this function.
1540     pub language: Option<gimli::DwLang>,
1541 }
1542 
1543 impl<R: gimli::Reader> FunctionName<R> {
1544     /// The raw name of this function before demangling.
raw_name(&self) -> Result<Cow<str>, Error>1545     pub fn raw_name(&self) -> Result<Cow<str>, Error> {
1546         self.name.to_string_lossy()
1547     }
1548 
1549     /// The name of this function after demangling (if applicable).
demangle(&self) -> Result<Cow<str>, Error>1550     pub fn demangle(&self) -> Result<Cow<str>, Error> {
1551         self.raw_name().map(|x| demangle_auto(x, self.language))
1552     }
1553 }
1554 
1555 /// Demangle a symbol name using the demangling scheme for the given language.
1556 ///
1557 /// Returns `None` if demangling failed or is not required.
1558 #[allow(unused_variables)]
demangle(name: &str, language: gimli::DwLang) -> Option<String>1559 pub fn demangle(name: &str, language: gimli::DwLang) -> Option<String> {
1560     match language {
1561         #[cfg(feature = "rustc-demangle")]
1562         gimli::DW_LANG_Rust => rustc_demangle::try_demangle(name)
1563             .ok()
1564             .as_ref()
1565             .map(|x| format!("{:#}", x)),
1566         #[cfg(feature = "cpp_demangle")]
1567         gimli::DW_LANG_C_plus_plus
1568         | gimli::DW_LANG_C_plus_plus_03
1569         | gimli::DW_LANG_C_plus_plus_11
1570         | gimli::DW_LANG_C_plus_plus_14 => cpp_demangle::Symbol::new(name)
1571             .ok()
1572             .and_then(|x| x.demangle(&Default::default()).ok()),
1573         _ => None,
1574     }
1575 }
1576 
1577 /// Apply 'best effort' demangling of a symbol name.
1578 ///
1579 /// If `language` is given, then only the demangling scheme for that language
1580 /// is used.
1581 ///
1582 /// If `language` is `None`, then heuristics are used to determine how to
1583 /// demangle the name. Currently, these heuristics are very basic.
1584 ///
1585 /// If demangling fails or is not required, then `name` is returned unchanged.
demangle_auto(name: Cow<str>, language: Option<gimli::DwLang>) -> Cow<str>1586 pub fn demangle_auto(name: Cow<str>, language: Option<gimli::DwLang>) -> Cow<str> {
1587     match language {
1588         Some(language) => demangle(name.as_ref(), language),
1589         None => demangle(name.as_ref(), gimli::DW_LANG_Rust)
1590             .or_else(|| demangle(name.as_ref(), gimli::DW_LANG_C_plus_plus)),
1591     }
1592     .map(Cow::from)
1593     .unwrap_or(name)
1594 }
1595 
1596 /// A source location.
1597 pub struct Location<'a> {
1598     /// The file name.
1599     pub file: Option<&'a str>,
1600     /// The line number.
1601     pub line: Option<u32>,
1602     /// The column number.
1603     pub column: Option<u32>,
1604 }
1605