1use std::borrow::Cow;
13use std::collections::BTreeSet;
14use std::error::Error;
15use std::fmt;
16use std::marker::PhantomData;
17use std::ops::Deref;
18use std::sync::Arc;
19
20use fallible_iterator::FallibleIterator;
21use gimli::read::{AttributeValue, Error as GimliError, Range};
22use gimli::{constants, AbbreviationsCacheStrategy, DwarfFileType, UnitSectionOffset};
23use once_cell::sync::OnceCell;
24use thiserror::Error;
25
26use symbolic_common::{AsSelf, Language, Name, NameMangling, SelfCell};
27
28use crate::base::*;
29use crate::function_builder::FunctionBuilder;
30#[cfg(feature = "macho")]
31use crate::macho::BcSymbolMap;
32use crate::sourcebundle::SourceFileDescriptor;
33
34#[cfg(not(feature = "macho"))]
37#[derive(Debug)]
38pub struct BcSymbolMap<'d> {
39 _marker: std::marker::PhantomData<&'d str>,
40}
41
42#[cfg(not(feature = "macho"))]
43impl<'d> BcSymbolMap<'d> {
44 pub(crate) fn resolve_opt(&self, _name: impl AsRef<[u8]>) -> Option<&str> {
45 None
46 }
47}
48
49#[doc(hidden)]
50pub use gimli;
51pub use gimli::RunTimeEndian as Endian;
52
53type Slice<'a> = gimli::read::EndianSlice<'a, Endian>;
54type RangeLists<'a> = gimli::read::RangeLists<Slice<'a>>;
55type Unit<'a> = gimli::read::Unit<Slice<'a>>;
56type DwarfInner<'a> = gimli::read::Dwarf<Slice<'a>>;
57
58type Die<'d> = gimli::read::DebuggingInformationEntry<Slice<'d>, usize>;
59type Attribute<'a> = gimli::read::Attribute<Slice<'a>>;
60type UnitOffset = gimli::read::UnitOffset<usize>;
61type DebugInfoOffset = gimli::DebugInfoOffset<usize>;
62type EntriesRaw<'d, 'u> = gimli::EntriesRaw<'u, Slice<'d>>;
63
64type UnitHeader<'a> = gimli::read::UnitHeader<Slice<'a>>;
65type IncompleteLineNumberProgram<'a> = gimli::read::IncompleteLineProgram<Slice<'a>>;
66type LineNumberProgramHeader<'a> = gimli::read::LineProgramHeader<Slice<'a>>;
67type LineProgramFileEntry<'a> = gimli::read::FileEntry<Slice<'a>>;
68
69fn offset(addr: u64, offset: i64) -> u64 {
74 (addr as i64).wrapping_sub(offset) as u64
75}
76
77#[non_exhaustive]
79#[derive(Clone, Copy, Debug, PartialEq, Eq)]
80pub enum DwarfErrorKind {
81 InvalidUnitRef(usize),
83
84 InvalidFileRef(u64),
86
87 UnexpectedInline,
89
90 InvertedFunctionRange,
92
93 CorruptedData,
95}
96
97impl fmt::Display for DwarfErrorKind {
98 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99 match self {
100 Self::InvalidUnitRef(offset) => {
101 write!(f, "compilation unit for offset {offset} does not exist")
102 }
103 Self::InvalidFileRef(id) => write!(f, "referenced file {id} does not exist"),
104 Self::UnexpectedInline => write!(f, "unexpected inline function without parent"),
105 Self::InvertedFunctionRange => write!(f, "function with inverted address range"),
106 Self::CorruptedData => write!(f, "corrupted dwarf debug data"),
107 }
108 }
109}
110
111#[derive(Debug, Error)]
113#[error("{kind}")]
114pub struct DwarfError {
115 kind: DwarfErrorKind,
116 #[source]
117 source: Option<Box<dyn Error + Send + Sync + 'static>>,
118}
119
120impl DwarfError {
121 fn new<E>(kind: DwarfErrorKind, source: E) -> Self
124 where
125 E: Into<Box<dyn Error + Send + Sync>>,
126 {
127 let source = Some(source.into());
128 Self { kind, source }
129 }
130
131 pub fn kind(&self) -> DwarfErrorKind {
133 self.kind
134 }
135}
136
137impl From<DwarfErrorKind> for DwarfError {
138 fn from(kind: DwarfErrorKind) -> Self {
139 Self { kind, source: None }
140 }
141}
142
143impl From<GimliError> for DwarfError {
144 fn from(e: GimliError) -> Self {
145 Self::new(DwarfErrorKind::CorruptedData, e)
146 }
147}
148
149#[derive(Clone)]
155pub struct DwarfSection<'data> {
156 pub address: u64,
158
159 pub offset: u64,
161
162 pub align: u64,
164
165 pub data: Cow<'data, [u8]>,
167}
168
169impl fmt::Debug for DwarfSection<'_> {
170 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
171 f.debug_struct("DwarfSection")
172 .field("address", &format_args!("{:#x}", self.address))
173 .field("offset", &format_args!("{:#x}", self.offset))
174 .field("align", &format_args!("{:#x}", self.align))
175 .field("len()", &self.data.len())
176 .finish()
177 }
178}
179
180pub trait Dwarf<'data> {
186 fn endianity(&self) -> Endian;
191
192 fn raw_section(&self, name: &str) -> Option<DwarfSection<'data>>;
201
202 fn section(&self, name: &str) -> Option<DwarfSection<'data>> {
211 self.raw_section(name)
212 }
213
214 fn has_section(&self, name: &str) -> bool {
220 self.raw_section(name).is_some()
221 }
222}
223
224#[derive(Debug)]
226struct DwarfRow {
227 address: u64,
228 file_index: u64,
229 line: Option<u64>,
230 size: Option<u64>,
231}
232
233#[derive(Debug)]
235struct DwarfSequence {
236 start: u64,
237 end: u64,
238 rows: Vec<DwarfRow>,
239}
240
241#[derive(Debug)]
243struct DwarfLineProgram<'d> {
244 header: LineNumberProgramHeader<'d>,
245 sequences: Vec<DwarfSequence>,
246}
247
248impl<'d> DwarfLineProgram<'d> {
249 fn prepare(program: IncompleteLineNumberProgram<'d>) -> Self {
250 let mut sequences = Vec::new();
251 let mut sequence_rows = Vec::<DwarfRow>::new();
252 let mut prev_address = 0;
253 let mut state_machine = program.rows();
254
255 while let Ok(Some((_, &program_row))) = state_machine.next_row() {
256 let address = program_row.address();
257
258 if address == 0 {
264 continue;
265 }
266
267 if let Some(last_row) = sequence_rows.last_mut() {
268 if address >= last_row.address {
269 last_row.size = Some(address - last_row.address);
270 }
271 }
272
273 if program_row.end_sequence() {
274 if !sequence_rows.is_empty() {
277 sequences.push(DwarfSequence {
278 start: sequence_rows[0].address,
279 end: if address < prev_address {
282 prev_address + 1
283 } else {
284 address
285 },
286 rows: std::mem::take(&mut sequence_rows),
287 });
288 }
289 prev_address = 0;
290 } else if address < prev_address {
291 } else {
298 let file_index = program_row.file_index();
299 let line = program_row.line().map(|v| v.get());
300 let mut duplicate = false;
301 if let Some(last_row) = sequence_rows.last_mut() {
302 if last_row.address == address {
303 last_row.file_index = file_index;
304 last_row.line = line;
305 duplicate = true;
306 }
307 }
308 if !duplicate {
309 sequence_rows.push(DwarfRow {
310 address,
311 file_index,
312 line,
313 size: None,
314 });
315 }
316 prev_address = address;
317 }
318 }
319
320 if !sequence_rows.is_empty() {
321 let start = sequence_rows[0].address;
324 let end = prev_address + 1;
325 sequences.push(DwarfSequence {
326 start,
327 end,
328 rows: sequence_rows,
329 });
330 }
331
332 sequences.sort_by_key(|x| x.start);
334
335 DwarfLineProgram {
336 header: state_machine.header().clone(),
337 sequences,
338 }
339 }
340
341 pub fn get_rows(&self, range: &Range) -> &[DwarfRow] {
342 for seq in &self.sequences {
343 if seq.end <= range.begin || seq.start > range.end {
344 continue;
345 }
346
347 let from = match seq.rows.binary_search_by_key(&range.begin, |x| x.address) {
348 Ok(idx) => idx,
349 Err(0) => continue,
350 Err(next_idx) => next_idx - 1,
351 };
352
353 let len = seq.rows[from..]
354 .binary_search_by_key(&range.end, |x| x.address)
355 .unwrap_or_else(|e| e);
356 return &seq.rows[from..from + len];
357 }
358 &[]
359 }
360}
361
362#[derive(Clone, Copy, Debug)]
364struct UnitRef<'d, 'a> {
365 info: &'a DwarfInfo<'d>,
366 unit: &'a Unit<'d>,
367}
368
369impl<'d> UnitRef<'d, '_> {
370 #[inline(always)]
372 fn slice_value(&self, value: AttributeValue<Slice<'d>>) -> Option<&'d [u8]> {
373 self.info
374 .attr_string(self.unit, value)
375 .map(|reader| reader.slice())
376 .ok()
377 }
378
379 #[inline(always)]
381 fn string_value(&self, value: AttributeValue<Slice<'d>>) -> Option<Cow<'d, str>> {
382 let slice = self.slice_value(value)?;
383 Some(String::from_utf8_lossy(slice))
384 }
385
386 fn resolve_reference<T, F>(&self, attr: Attribute<'d>, f: F) -> Result<Option<T>, DwarfError>
391 where
392 F: FnOnce(Self, &Die<'d>) -> Result<Option<T>, DwarfError>,
393 {
394 let (unit, offset) = match attr.value() {
395 AttributeValue::UnitRef(offset) => (*self, offset),
396 AttributeValue::DebugInfoRef(offset) => self.info.find_unit_offset(offset)?,
397 _ => return Ok(None),
399 };
400
401 let mut entries = unit.unit.entries_at_offset(offset)?;
402 entries.next_entry()?;
403
404 if let Some(entry) = entries.current() {
405 f(unit, entry)
406 } else {
407 Ok(None)
408 }
409 }
410
411 fn offset(&self) -> UnitSectionOffset {
413 self.unit.header.offset()
414 }
415
416 fn language(&self) -> Result<Option<Language>, DwarfError> {
418 let mut entries = self.unit.entries();
419 let Some(root_entry) = entries.next_dfs()? else {
420 return Ok(None);
421 };
422 let Some(AttributeValue::Language(lang)) = root_entry.attr_value(constants::DW_AT_language)
423 else {
424 return Ok(None);
425 };
426 Ok(Some(language_from_dwarf(lang)))
427 }
428
429 const MAX_ABSTRACT_ORIGIN_DEPTH: u8 = 16;
432
433 fn resolve_entry_language(
437 &self,
438 entry: &Die<'d>,
439 depth: u8,
440 ) -> Result<Option<Language>, DwarfError> {
441 if depth == 0 {
442 return Ok(None);
443 }
444 if let Some(attr) = entry.attr(constants::DW_AT_abstract_origin) {
445 return self.resolve_reference(*attr, |ref_unit, ref_entry| {
446 if let Some(lang) = ref_unit.resolve_entry_language(ref_entry, depth - 1)? {
448 return Ok(Some(lang));
449 }
450 if self.offset() != ref_unit.offset() {
452 ref_unit.language()
453 } else {
454 Ok(None)
455 }
456 });
457 }
458 Ok(None)
459 }
460
461 fn resolve_function_name(
463 &self,
464 entry: &Die<'d>,
465 language: Language,
466 bcsymbolmap: Option<&'d BcSymbolMap<'d>>,
467 prior_offset: Option<UnitOffset>,
468 ) -> Result<Option<Name<'d>>, DwarfError> {
469 let mut fallback_name = None;
470 let mut reference_target = None;
471
472 for attr in entry.attrs() {
473 match attr.name() {
474 constants::DW_AT_linkage_name | constants::DW_AT_MIPS_linkage_name => {
476 return Ok(self
477 .string_value(attr.value())
478 .map(|n| resolve_cow_name(bcsymbolmap, n))
479 .map(|n| Name::new(n, NameMangling::Mangled, language)));
480 }
481 constants::DW_AT_name => {
482 fallback_name = Some(attr);
483 }
484 constants::DW_AT_abstract_origin | constants::DW_AT_specification => {
485 reference_target = Some(attr);
486 }
487 _ => {}
488 }
489 }
490
491 if let Some(attr) = fallback_name {
492 return Ok(self
493 .string_value(attr.value())
494 .map(|n| resolve_cow_name(bcsymbolmap, n))
495 .map(|n| Name::new(n, NameMangling::Unmangled, language)));
496 }
497
498 if let Some(attr) = reference_target {
499 return self.resolve_reference(*attr, |ref_unit, ref_entry| {
500 if let Some(prior) = prior_offset {
503 if self.offset() == ref_unit.offset() && prior == ref_entry.offset() {
504 return Ok(None);
505 }
506 }
507
508 if self.offset() != ref_unit.offset() || entry.offset() != ref_entry.offset() {
509 ref_unit.resolve_function_name(
510 ref_entry,
511 language,
512 bcsymbolmap,
513 Some(entry.offset()),
514 )
515 } else {
516 Ok(None)
517 }
518 });
519 }
520
521 Ok(None)
522 }
523}
524
525#[derive(Debug)]
527struct DwarfUnit<'d, 'a> {
528 inner: UnitRef<'d, 'a>,
529 bcsymbolmap: Option<&'d BcSymbolMap<'d>>,
530 language: Language,
531 line_program: Option<DwarfLineProgram<'d>>,
532 prefer_dwarf_names: bool,
533}
534
535impl<'d, 'a> DwarfUnit<'d, 'a> {
536 fn from_unit(
538 unit: &'a Unit<'d>,
539 info: &'a DwarfInfo<'d>,
540 bcsymbolmap: Option<&'d BcSymbolMap<'d>>,
541 ) -> Result<Option<Self>, DwarfError> {
542 let inner = UnitRef { info, unit };
543 let mut entries = unit.entries();
544 let entry = match entries.next_dfs()? {
545 Some(entry) => entry,
546 None => return Err(gimli::read::Error::MissingUnitDie.into()),
547 };
548
549 if info.kind != ObjectKind::Relocatable
554 && unit.low_pc == 0
555 && entry.attr(constants::DW_AT_ranges).is_none()
556 {
557 return Ok(None);
558 }
559
560 let language = match entry.attr_value(constants::DW_AT_language) {
561 Some(AttributeValue::Language(lang)) => language_from_dwarf(lang),
562 _ => Language::Unknown,
563 };
564
565 let line_program = unit
566 .line_program
567 .as_ref()
568 .map(|program| DwarfLineProgram::prepare(program.clone()));
569
570 let producer = entry
574 .attr_value(constants::DW_AT_producer)
575 .and_then(|av| av.string_value(&info.inner.debug_str));
576
577 let prefer_dwarf_names = producer.as_deref() == Some(b"Dart VM");
580
581 Ok(Some(DwarfUnit {
582 inner,
583 bcsymbolmap,
584 language,
585 line_program,
586 prefer_dwarf_names,
587 }))
588 }
589
590 fn compilation_dir(&self) -> &'d [u8] {
592 match self.inner.unit.comp_dir {
593 Some(ref dir) => resolve_byte_name(self.bcsymbolmap, dir.slice()),
594 None => &[],
595 }
596 }
597
598 fn parse_ranges<'r>(
604 &self,
605 entries: &mut EntriesRaw<'d, '_>,
606 abbrev: &gimli::Abbreviation,
607 range_buf: &'r mut Vec<Range>,
608 ) -> Result<(&'r mut Vec<Range>, CallLocation), DwarfError> {
609 range_buf.clear();
610
611 let mut call_line = None;
612 let mut call_file = None;
613 let mut low_pc = None;
614 let mut high_pc = None;
615 let mut high_pc_rel = None;
616
617 let kind = self.inner.info.kind;
618
619 for spec in abbrev.attributes() {
620 let attr = entries.read_attribute(*spec)?;
621 match attr.name() {
622 constants::DW_AT_low_pc => match attr.value() {
623 AttributeValue::Addr(addr) => low_pc = Some(addr),
624 AttributeValue::DebugAddrIndex(index) => {
625 low_pc = Some(self.inner.info.address(self.inner.unit, index)?)
626 }
627 _ => return Err(GimliError::UnsupportedAttributeForm(attr.form()).into()),
628 },
629 constants::DW_AT_high_pc => match attr.value() {
630 AttributeValue::Addr(addr) => high_pc = Some(addr),
631 AttributeValue::DebugAddrIndex(index) => {
632 high_pc = Some(self.inner.info.address(self.inner.unit, index)?)
633 }
634 AttributeValue::Udata(size) => high_pc_rel = Some(size),
635 _ => return Err(GimliError::UnsupportedAttributeForm(attr.form()).into()),
636 },
637 constants::DW_AT_call_line => match attr.value() {
638 AttributeValue::Udata(line) => call_line = Some(line),
639 _ => return Err(GimliError::UnsupportedAttributeForm(attr.form()).into()),
640 },
641 constants::DW_AT_call_file => match attr.value() {
642 AttributeValue::FileIndex(file) => call_file = Some(file),
643 _ => return Err(GimliError::UnsupportedAttributeForm(attr.form()).into()),
644 },
645 constants::DW_AT_ranges
646 | constants::DW_AT_rnglists_base
647 | constants::DW_AT_start_scope => {
648 match self.inner.info.attr_ranges(self.inner.unit, attr.value())? {
649 Some(mut ranges) => {
650 while let Some(range) = match ranges.next() {
651 Ok(range) => range,
652 Err(gimli::Error::InvalidCfiSetLoc(_)) => None,
658 Err(err) => {
659 return Err(err.into());
660 }
661 } {
662 if range.begin > 0 || kind == ObjectKind::Relocatable {
665 range_buf.push(range);
666 }
667 }
668 }
669 None => continue,
670 }
671 }
672 _ => continue,
673 }
674 }
675
676 let call_location = CallLocation {
677 call_file,
678 call_line,
679 };
680
681 if range_buf.is_empty() {
682 if let Some(range) = Self::convert_pc_range(low_pc, high_pc, high_pc_rel, kind)? {
683 range_buf.push(range);
684 }
685 }
686
687 Ok((range_buf, call_location))
688 }
689
690 fn convert_pc_range(
691 low_pc: Option<u64>,
692 high_pc: Option<u64>,
693 high_pc_rel: Option<u64>,
694 kind: ObjectKind,
695 ) -> Result<Option<Range>, DwarfError> {
696 let low_pc = match low_pc {
701 Some(low_pc) if low_pc != 0 || kind == ObjectKind::Relocatable => low_pc,
702 _ => return Ok(None),
703 };
704
705 let high_pc = match (high_pc, high_pc_rel) {
706 (Some(high_pc), _) => high_pc,
707 (_, Some(high_pc_rel)) => low_pc.wrapping_add(high_pc_rel),
708 _ => return Ok(None),
709 };
710
711 if low_pc == high_pc {
712 return Ok(None);
715 }
716
717 if low_pc == u64::MAX || low_pc == u64::MAX - 1 {
718 return Ok(None);
721 }
722
723 if low_pc > high_pc {
724 return Err(DwarfErrorKind::InvertedFunctionRange.into());
725 }
726
727 Ok(Some(Range {
728 begin: low_pc,
729 end: high_pc,
730 }))
731 }
732
733 fn file_info(
735 &self,
736 line_program: &LineNumberProgramHeader<'d>,
737 file: &LineProgramFileEntry<'d>,
738 ) -> FileInfo<'d> {
739 FileInfo::new(
740 Cow::Borrowed(resolve_byte_name(
741 self.bcsymbolmap,
742 file.directory(line_program)
743 .and_then(|attr| self.inner.slice_value(attr))
744 .unwrap_or_default(),
745 )),
746 Cow::Borrowed(resolve_byte_name(
747 self.bcsymbolmap,
748 self.inner.slice_value(file.path_name()).unwrap_or_default(),
749 )),
750 )
751 }
752
753 fn resolve_file(&self, file_id: u64) -> Option<FileInfo<'d>> {
755 let line_program = match self.line_program {
756 Some(ref program) => &program.header,
757 None => return None,
758 };
759
760 line_program
761 .file(file_id)
762 .map(|file| self.file_info(line_program, file))
763 }
764
765 fn resolve_symbol_name(&self, address: u64, language: Language) -> Option<Name<'d>> {
767 let symbol = self.inner.info.symbol_map.lookup_exact(address)?;
768 let name = resolve_cow_name(self.bcsymbolmap, symbol.name.clone()?);
769 Some(Name::new(name, NameMangling::Mangled, language))
770 }
771
772 fn resolve_function_language(&self, entry: &Die<'d>, fallback_language: Language) -> Language {
780 self.inner
781 .resolve_entry_language(entry, UnitRef::MAX_ABSTRACT_ORIGIN_DEPTH)
782 .ok()
783 .flatten()
784 .unwrap_or(fallback_language)
785 }
786
787 fn parse_functions(
789 &self,
790 depth: isize,
791 entries: &mut EntriesRaw<'d, '_>,
792 output: &mut FunctionsOutput<'_, 'd>,
793 ) -> Result<(), DwarfError> {
794 while !entries.is_empty() {
795 let dw_die_offset = entries.next_offset();
796 let next_depth = entries.next_depth();
797 if next_depth <= depth {
798 return Ok(());
799 }
800 if let Some(abbrev) = entries.read_abbreviation()? {
801 if abbrev.tag() == constants::DW_TAG_subprogram {
802 self.parse_function(dw_die_offset, next_depth, entries, abbrev, output)?;
803 } else {
804 entries.skip_attributes(abbrev.attributes())?;
805 }
806 }
807 }
808 Ok(())
809 }
810
811 fn parse_function(
821 &self,
822 dw_die_offset: gimli::UnitOffset<usize>,
823 depth: isize,
824 entries: &mut EntriesRaw<'d, '_>,
825 abbrev: &gimli::Abbreviation,
826 output: &mut FunctionsOutput<'_, 'd>,
827 ) -> Result<(), DwarfError> {
828 let (ranges, _) = self.parse_ranges(entries, abbrev, &mut output.range_buf)?;
829
830 let seen_ranges = &mut *output.seen_ranges;
831 ranges.retain(|range| {
832 if range.begin > range.end {
834 return false;
835 }
836
837 let address = offset(range.begin, self.inner.info.address_offset);
846 let size = range.end - range.begin;
847
848 seen_ranges.insert((address, size))
849 });
850
851 if ranges.is_empty() {
859 return self.parse_functions(depth, entries, output);
860 }
861
862 let entry = self.inner.unit.entry(dw_die_offset)?;
870 let language = self.resolve_function_language(&entry, self.language);
874
875 let symbol_name = if self.prefer_dwarf_names {
876 None
877 } else {
878 let first_range_begin = ranges.iter().map(|range| range.begin).min().unwrap();
879 let function_address = offset(first_range_begin, self.inner.info.address_offset);
880 self.resolve_symbol_name(function_address, language)
881 };
882
883 let name = symbol_name
884 .or_else(|| {
885 self.inner
886 .resolve_function_name(&entry, language, self.bcsymbolmap, None)
887 .ok()
888 .flatten()
889 })
890 .unwrap_or_else(|| Name::new("", NameMangling::Unmangled, language));
891
892 let mut builders: Vec<(Range, FunctionBuilder)> = ranges
895 .iter()
896 .map(|range| {
897 let address = offset(range.begin, self.inner.info.address_offset);
898 let size = range.end - range.begin;
899 (
900 *range,
901 FunctionBuilder::new(name.clone(), self.compilation_dir(), address, size),
902 )
903 })
904 .collect();
905
906 self.parse_function_children(depth, 0, entries, &mut builders, output, language)?;
907
908 if let Some(line_program) = &self.line_program {
909 for (range, builder) in &mut builders {
910 for row in line_program.get_rows(range) {
911 let address = offset(row.address, self.inner.info.address_offset);
912 let size = row.size;
913 let file = self.resolve_file(row.file_index).unwrap_or_default();
914 let line = row.line.unwrap_or(0);
915 builder.add_leaf_line(address, size, file, line);
916 }
917 }
918 }
919
920 for (_range, builder) in builders {
921 output.functions.push(builder.finish());
922 }
923
924 Ok(())
925 }
926
927 fn parse_function_children(
929 &self,
930 depth: isize,
931 inline_depth: u32,
932 entries: &mut EntriesRaw<'d, '_>,
933 builders: &mut [(Range, FunctionBuilder<'d>)],
934 output: &mut FunctionsOutput<'_, 'd>,
935 language: Language,
936 ) -> Result<(), DwarfError> {
937 while !entries.is_empty() {
938 let dw_die_offset = entries.next_offset();
939 let next_depth = entries.next_depth();
940 if next_depth <= depth {
941 return Ok(());
942 }
943 let abbrev = match entries.read_abbreviation()? {
944 Some(abbrev) => abbrev,
945 None => continue,
946 };
947 match abbrev.tag() {
948 constants::DW_TAG_subprogram => {
949 self.parse_function(dw_die_offset, next_depth, entries, abbrev, output)?;
951 }
952 constants::DW_TAG_inlined_subroutine => {
953 self.parse_inlinee(
954 dw_die_offset,
955 next_depth,
956 inline_depth,
957 entries,
958 abbrev,
959 builders,
960 output,
961 language,
962 )?;
963 }
964 _ => {
965 entries.skip_attributes(abbrev.attributes())?;
966 }
967 }
968 }
969 Ok(())
970 }
971
972 #[allow(clippy::too_many_arguments)]
981 fn parse_inlinee(
982 &self,
983 dw_die_offset: gimli::UnitOffset<usize>,
984 depth: isize,
985 inline_depth: u32,
986 entries: &mut EntriesRaw<'d, '_>,
987 abbrev: &gimli::Abbreviation,
988 builders: &mut [(Range, FunctionBuilder<'d>)],
989 output: &mut FunctionsOutput<'_, 'd>,
990 language: Language,
991 ) -> Result<(), DwarfError> {
992 let (ranges, call_location) = self.parse_ranges(entries, abbrev, &mut output.range_buf)?;
993
994 ranges.retain(|range| range.end > range.begin);
995
996 if ranges.is_empty() {
1004 return self.parse_functions(depth, entries, output);
1005 }
1006
1007 let entry = self.inner.unit.entry(dw_die_offset)?;
1008 let language = self.resolve_function_language(&entry, language);
1009
1010 let name = self
1014 .inner
1015 .resolve_function_name(&entry, language, self.bcsymbolmap, None)
1016 .ok()
1017 .flatten()
1018 .unwrap_or_else(|| Name::new("", NameMangling::Unmangled, language));
1019
1020 let call_file = call_location
1021 .call_file
1022 .and_then(|i| self.resolve_file(i))
1023 .unwrap_or_default();
1024 let call_line = call_location.call_line.unwrap_or(0);
1025
1026 for range in ranges.iter() {
1028 let builder = match builders.iter_mut().find(|(outer_range, _builder)| {
1031 range.begin >= outer_range.begin && range.begin < outer_range.end
1032 }) {
1033 Some((_outer_range, builder)) => builder,
1034 None => continue,
1035 };
1036
1037 let address = offset(range.begin, self.inner.info.address_offset);
1038 let size = range.end - range.begin;
1039 builder.add_inlinee(
1040 inline_depth,
1041 name.clone(),
1042 address,
1043 size,
1044 call_file.clone(),
1045 call_line,
1046 );
1047 }
1048
1049 self.parse_function_children(depth, inline_depth + 1, entries, builders, output, language)
1050 }
1051
1052 fn functions(
1054 &self,
1055 seen_ranges: &mut BTreeSet<(u64, u64)>,
1056 ) -> Result<Vec<Function<'d>>, DwarfError> {
1057 let mut entries = self.inner.unit.entries_raw(None)?;
1058 let mut output = FunctionsOutput::with_seen_ranges(seen_ranges);
1059 self.parse_functions(-1, &mut entries, &mut output)?;
1060 Ok(output.functions)
1061 }
1062}
1063
1064struct FunctionsOutput<'a, 'd> {
1066 pub functions: Vec<Function<'d>>,
1069 pub range_buf: Vec<Range>,
1071 pub seen_ranges: &'a mut BTreeSet<(u64, u64)>,
1073}
1074
1075impl<'a> FunctionsOutput<'a, '_> {
1076 pub fn with_seen_ranges(seen_ranges: &'a mut BTreeSet<(u64, u64)>) -> Self {
1077 Self {
1078 functions: Vec::new(),
1079 range_buf: Vec::new(),
1080 seen_ranges,
1081 }
1082 }
1083}
1084
1085#[derive(Debug, Default, Clone, Copy)]
1087struct CallLocation {
1088 pub call_file: Option<u64>,
1089 pub call_line: Option<u64>,
1090}
1091
1092fn language_from_dwarf(language: gimli::DwLang) -> Language {
1094 match language {
1095 constants::DW_LANG_C => Language::C,
1096 constants::DW_LANG_C11 => Language::C,
1097 constants::DW_LANG_C89 => Language::C,
1098 constants::DW_LANG_C99 => Language::C,
1099 constants::DW_LANG_C_plus_plus => Language::Cpp,
1100 constants::DW_LANG_C_plus_plus_03 => Language::Cpp,
1101 constants::DW_LANG_C_plus_plus_11 => Language::Cpp,
1102 constants::DW_LANG_C_plus_plus_14 => Language::Cpp,
1103 constants::DW_LANG_D => Language::D,
1104 constants::DW_LANG_Go => Language::Go,
1105 constants::DW_LANG_ObjC => Language::ObjC,
1106 constants::DW_LANG_ObjC_plus_plus => Language::ObjCpp,
1107 constants::DW_LANG_Rust => Language::Rust,
1108 constants::DW_LANG_Swift => Language::Swift,
1109 _ => Language::Unknown,
1110 }
1111}
1112
1113struct DwarfSectionData<'data, S> {
1115 data: Cow<'data, [u8]>,
1116 endianity: Endian,
1117 _ph: PhantomData<S>,
1118}
1119
1120impl<'data, S> DwarfSectionData<'data, S>
1121where
1122 S: gimli::read::Section<Slice<'data>>,
1123{
1124 fn load<D>(dwarf: &D) -> Self
1126 where
1127 D: Dwarf<'data>,
1128 {
1129 DwarfSectionData {
1130 data: dwarf
1131 .section(&S::section_name()[1..])
1132 .map(|section| section.data)
1133 .unwrap_or_default(),
1134 endianity: dwarf.endianity(),
1135 _ph: PhantomData,
1136 }
1137 }
1138
1139 fn to_gimli(&'data self) -> S {
1141 S::from(Slice::new(&self.data, self.endianity))
1142 }
1143}
1144
1145impl<'d, S> fmt::Debug for DwarfSectionData<'d, S>
1146where
1147 S: gimli::read::Section<Slice<'d>>,
1148{
1149 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1150 let owned = match self.data {
1151 Cow::Owned(_) => true,
1152 Cow::Borrowed(_) => false,
1153 };
1154
1155 f.debug_struct("DwarfSectionData")
1156 .field("type", &S::section_name())
1157 .field("endianity", &self.endianity)
1158 .field("len()", &self.data.len())
1159 .field("owned()", &owned)
1160 .finish()
1161 }
1162}
1163
1164struct DwarfSections<'data> {
1166 debug_abbrev: DwarfSectionData<'data, gimli::read::DebugAbbrev<Slice<'data>>>,
1167 debug_addr: DwarfSectionData<'data, gimli::read::DebugAddr<Slice<'data>>>,
1168 debug_aranges: DwarfSectionData<'data, gimli::read::DebugAranges<Slice<'data>>>,
1169 debug_info: DwarfSectionData<'data, gimli::read::DebugInfo<Slice<'data>>>,
1170 debug_line: DwarfSectionData<'data, gimli::read::DebugLine<Slice<'data>>>,
1171 debug_line_str: DwarfSectionData<'data, gimli::read::DebugLineStr<Slice<'data>>>,
1172 debug_names: DwarfSectionData<'data, gimli::read::DebugNames<Slice<'data>>>,
1173 debug_str: DwarfSectionData<'data, gimli::read::DebugStr<Slice<'data>>>,
1174 debug_str_offsets: DwarfSectionData<'data, gimli::read::DebugStrOffsets<Slice<'data>>>,
1175 debug_ranges: DwarfSectionData<'data, gimli::read::DebugRanges<Slice<'data>>>,
1176 debug_rnglists: DwarfSectionData<'data, gimli::read::DebugRngLists<Slice<'data>>>,
1177 debug_macinfo: DwarfSectionData<'data, gimli::read::DebugMacinfo<Slice<'data>>>,
1178 debug_macro: DwarfSectionData<'data, gimli::read::DebugMacro<Slice<'data>>>,
1179}
1180
1181impl<'data> DwarfSections<'data> {
1182 fn from_dwarf<D>(dwarf: &D) -> Self
1184 where
1185 D: Dwarf<'data>,
1186 {
1187 DwarfSections {
1188 debug_abbrev: DwarfSectionData::load(dwarf),
1189 debug_addr: DwarfSectionData::load(dwarf),
1190 debug_aranges: DwarfSectionData::load(dwarf),
1191 debug_info: DwarfSectionData::load(dwarf),
1192 debug_line: DwarfSectionData::load(dwarf),
1193 debug_line_str: DwarfSectionData::load(dwarf),
1194 debug_names: DwarfSectionData::load(dwarf),
1195 debug_str: DwarfSectionData::load(dwarf),
1196 debug_str_offsets: DwarfSectionData::load(dwarf),
1197 debug_ranges: DwarfSectionData::load(dwarf),
1198 debug_rnglists: DwarfSectionData::load(dwarf),
1199 debug_macinfo: DwarfSectionData::load(dwarf),
1200 debug_macro: DwarfSectionData::load(dwarf),
1201 }
1202 }
1203}
1204
1205struct DwarfInfo<'data> {
1206 inner: DwarfInner<'data>,
1207 headers: Vec<UnitHeader<'data>>,
1208 units: Vec<OnceCell<Option<Unit<'data>>>>,
1209 symbol_map: SymbolMap<'data>,
1210 address_offset: i64,
1211 kind: ObjectKind,
1212}
1213
1214impl<'d> Deref for DwarfInfo<'d> {
1215 type Target = DwarfInner<'d>;
1216
1217 fn deref(&self) -> &Self::Target {
1218 &self.inner
1219 }
1220}
1221
1222impl<'d> DwarfInfo<'d> {
1223 pub fn parse(
1225 sections: &'d DwarfSections<'d>,
1226 symbol_map: SymbolMap<'d>,
1227 address_offset: i64,
1228 kind: ObjectKind,
1229 ) -> Result<Self, DwarfError> {
1230 let mut inner = gimli::read::Dwarf {
1231 abbreviations_cache: Default::default(),
1232 debug_abbrev: sections.debug_abbrev.to_gimli(),
1233 debug_addr: sections.debug_addr.to_gimli(),
1234 debug_aranges: sections.debug_aranges.to_gimli(),
1235 debug_info: sections.debug_info.to_gimli(),
1236 debug_line: sections.debug_line.to_gimli(),
1237 debug_line_str: sections.debug_line_str.to_gimli(),
1238 debug_names: sections.debug_names.to_gimli(),
1239 debug_str: sections.debug_str.to_gimli(),
1240 debug_str_offsets: sections.debug_str_offsets.to_gimli(),
1241 debug_types: Default::default(),
1242 debug_macinfo: sections.debug_macinfo.to_gimli(),
1243 debug_macro: sections.debug_macro.to_gimli(),
1244 locations: Default::default(),
1245 ranges: RangeLists::new(
1246 sections.debug_ranges.to_gimli(),
1247 sections.debug_rnglists.to_gimli(),
1248 ),
1249 file_type: DwarfFileType::Main,
1250 sup: Default::default(),
1251 };
1252 inner.populate_abbreviations_cache(AbbreviationsCacheStrategy::Duplicates);
1253
1254 let headers = FallibleIterator::collect::<Vec<_>>(inner.units())?;
1256 let units = headers.iter().map(|_| OnceCell::new()).collect();
1257
1258 Ok(DwarfInfo {
1259 inner,
1260 headers,
1261 units,
1262 symbol_map,
1263 address_offset,
1264 kind,
1265 })
1266 }
1267
1268 fn get_unit(&self, index: usize) -> Result<Option<&Unit<'d>>, DwarfError> {
1270 let cell = match self.units.get(index) {
1272 Some(cell) => cell,
1273 None => return Ok(None),
1274 };
1275
1276 let unit_opt = cell.get_or_try_init(|| {
1277 let header = self.headers[index];
1282 match self.inner.unit(header) {
1283 Ok(unit) => Ok(Some(unit)),
1284 Err(gimli::read::Error::MissingUnitDie) => Ok(None),
1285 Err(error) => Err(DwarfError::from(error)),
1286 }
1287 })?;
1288
1289 Ok(unit_opt.as_ref())
1290 }
1291
1292 fn find_unit_offset(
1294 &self,
1295 offset: DebugInfoOffset,
1296 ) -> Result<(UnitRef<'d, '_>, UnitOffset), DwarfError> {
1297 let section_offset = UnitSectionOffset(offset.0);
1298 let search_result = self
1299 .headers
1300 .binary_search_by_key(§ion_offset, UnitHeader::offset);
1301
1302 let index = match search_result {
1303 Ok(index) => index,
1304 Err(0) => return Err(DwarfErrorKind::InvalidUnitRef(offset.0).into()),
1305 Err(next_index) => next_index - 1,
1306 };
1307
1308 if let Some(unit) = self.get_unit(index)? {
1309 if let Some(unit_offset) = section_offset.to_unit_offset(unit) {
1310 return Ok((UnitRef { unit, info: self }, unit_offset));
1311 }
1312 }
1313
1314 Err(DwarfErrorKind::InvalidUnitRef(offset.0).into())
1315 }
1316
1317 fn units(&'d self, bcsymbolmap: Option<&'d BcSymbolMap<'d>>) -> DwarfUnitIterator<'d> {
1319 DwarfUnitIterator {
1320 info: self,
1321 bcsymbolmap,
1322 index: 0,
1323 }
1324 }
1325}
1326
1327impl<'slf, 'd: 'slf> AsSelf<'slf> for DwarfInfo<'d> {
1328 type Ref = DwarfInfo<'slf>;
1329
1330 fn as_self(&'slf self) -> &'slf Self::Ref {
1331 unsafe { std::mem::transmute(self) }
1332 }
1333}
1334
1335impl fmt::Debug for DwarfInfo<'_> {
1336 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1337 f.debug_struct("DwarfInfo")
1338 .field("headers", &self.headers)
1339 .field("symbol_map", &self.symbol_map)
1340 .field("address_offset", &self.address_offset)
1341 .finish()
1342 }
1343}
1344
1345struct DwarfUnitIterator<'s> {
1347 info: &'s DwarfInfo<'s>,
1348 bcsymbolmap: Option<&'s BcSymbolMap<'s>>,
1349 index: usize,
1350}
1351
1352impl<'s> Iterator for DwarfUnitIterator<'s> {
1353 type Item = Result<DwarfUnit<'s, 's>, DwarfError>;
1354
1355 fn next(&mut self) -> Option<Self::Item> {
1356 while self.index < self.info.headers.len() {
1357 let result = self.info.get_unit(self.index);
1358 self.index += 1;
1359
1360 let unit = match result {
1361 Ok(Some(unit)) => unit,
1362 Ok(None) => continue,
1363 Err(error) => return Some(Err(error)),
1364 };
1365
1366 match DwarfUnit::from_unit(unit, self.info, self.bcsymbolmap) {
1367 Ok(Some(unit)) => return Some(Ok(unit)),
1368 Ok(None) => continue,
1369 Err(error) => return Some(Err(error)),
1370 }
1371 }
1372
1373 None
1374 }
1375}
1376
1377impl std::iter::FusedIterator for DwarfUnitIterator<'_> {}
1378
1379pub struct DwarfDebugSession<'data> {
1381 cell: SelfCell<Box<DwarfSections<'data>>, DwarfInfo<'data>>,
1382 bcsymbolmap: Option<Arc<BcSymbolMap<'data>>>,
1383}
1384
1385impl<'data> DwarfDebugSession<'data> {
1386 pub fn parse<D>(
1388 dwarf: &D,
1389 symbol_map: SymbolMap<'data>,
1390 address_offset: i64,
1391 kind: ObjectKind,
1392 ) -> Result<Self, DwarfError>
1393 where
1394 D: Dwarf<'data>,
1395 {
1396 let sections = DwarfSections::from_dwarf(dwarf);
1397 let cell = SelfCell::try_new(Box::new(sections), |sections| {
1398 DwarfInfo::parse(unsafe { &*sections }, symbol_map, address_offset, kind)
1399 })?;
1400
1401 Ok(DwarfDebugSession {
1402 cell,
1403 bcsymbolmap: None,
1404 })
1405 }
1406
1407 #[cfg(feature = "macho")]
1412 pub(crate) fn load_symbolmap(&mut self, symbolmap: Option<Arc<BcSymbolMap<'data>>>) {
1413 self.bcsymbolmap = symbolmap;
1414 }
1415
1416 pub fn files(&self) -> DwarfFileIterator<'_> {
1418 DwarfFileIterator {
1419 units: self.cell.get().units(self.bcsymbolmap.as_deref()),
1420 files: DwarfUnitFileIterator::default(),
1421 finished: false,
1422 }
1423 }
1424
1425 pub fn functions(&self) -> DwarfFunctionIterator<'_> {
1427 DwarfFunctionIterator {
1428 units: self.cell.get().units(self.bcsymbolmap.as_deref()),
1429 functions: Vec::new().into_iter(),
1430 seen_ranges: BTreeSet::new(),
1431 finished: false,
1432 }
1433 }
1434
1435 pub fn source_by_path(
1437 &self,
1438 _path: &str,
1439 ) -> Result<Option<SourceFileDescriptor<'_>>, DwarfError> {
1440 Ok(None)
1441 }
1442}
1443
1444impl<'session> DebugSession<'session> for DwarfDebugSession<'_> {
1445 type Error = DwarfError;
1446 type FunctionIterator = DwarfFunctionIterator<'session>;
1447 type FileIterator = DwarfFileIterator<'session>;
1448
1449 fn functions(&'session self) -> Self::FunctionIterator {
1450 self.functions()
1451 }
1452
1453 fn files(&'session self) -> Self::FileIterator {
1454 self.files()
1455 }
1456
1457 fn source_by_path(&self, path: &str) -> Result<Option<SourceFileDescriptor<'_>>, Self::Error> {
1458 self.source_by_path(path)
1459 }
1460}
1461
1462#[derive(Debug, Default)]
1463struct DwarfUnitFileIterator<'s> {
1464 unit: Option<DwarfUnit<'s, 's>>,
1465 index: usize,
1466}
1467
1468impl<'s> Iterator for DwarfUnitFileIterator<'s> {
1469 type Item = FileEntry<'s>;
1470
1471 fn next(&mut self) -> Option<Self::Item> {
1472 let unit = self.unit.as_ref()?;
1473 let line_program = unit.line_program.as_ref().map(|p| &p.header)?;
1474 let file = line_program.file_names().get(self.index)?;
1475
1476 self.index += 1;
1477
1478 Some(FileEntry::new(
1479 Cow::Borrowed(unit.compilation_dir()),
1480 unit.file_info(line_program, file),
1481 ))
1482 }
1483}
1484
1485fn resolve_byte_name<'s>(bcsymbolmap: Option<&'s BcSymbolMap<'s>>, s: &'s [u8]) -> &'s [u8] {
1486 bcsymbolmap
1487 .and_then(|b| b.resolve_opt(s))
1488 .map(AsRef::as_ref)
1489 .unwrap_or(s)
1490}
1491
1492fn resolve_cow_name<'s>(bcsymbolmap: Option<&'s BcSymbolMap<'s>>, s: Cow<'s, str>) -> Cow<'s, str> {
1493 bcsymbolmap
1494 .and_then(|b| b.resolve_opt(s.as_bytes()))
1495 .map(Cow::Borrowed)
1496 .unwrap_or(s)
1497}
1498
1499pub struct DwarfFileIterator<'s> {
1501 units: DwarfUnitIterator<'s>,
1502 files: DwarfUnitFileIterator<'s>,
1503 finished: bool,
1504}
1505
1506impl<'s> Iterator for DwarfFileIterator<'s> {
1507 type Item = Result<FileEntry<'s>, DwarfError>;
1508
1509 fn next(&mut self) -> Option<Self::Item> {
1510 if self.finished {
1511 return None;
1512 }
1513
1514 loop {
1515 if let Some(file_entry) = self.files.next() {
1516 return Some(Ok(file_entry));
1517 }
1518
1519 let unit = match self.units.next() {
1520 Some(Ok(unit)) => unit,
1521 Some(Err(error)) => return Some(Err(error)),
1522 None => break,
1523 };
1524
1525 self.files = DwarfUnitFileIterator {
1526 unit: Some(unit),
1527 index: 0,
1528 };
1529 }
1530
1531 self.finished = true;
1532 None
1533 }
1534}
1535
1536pub struct DwarfFunctionIterator<'s> {
1538 units: DwarfUnitIterator<'s>,
1539 functions: std::vec::IntoIter<Function<'s>>,
1540 seen_ranges: BTreeSet<(u64, u64)>,
1541 finished: bool,
1542}
1543
1544impl<'s> Iterator for DwarfFunctionIterator<'s> {
1545 type Item = Result<Function<'s>, DwarfError>;
1546
1547 fn next(&mut self) -> Option<Self::Item> {
1548 if self.finished {
1549 return None;
1550 }
1551
1552 loop {
1553 if let Some(func) = self.functions.next() {
1554 return Some(Ok(func));
1555 }
1556
1557 let unit = match self.units.next() {
1558 Some(Ok(unit)) => unit,
1559 Some(Err(error)) => return Some(Err(error)),
1560 None => break,
1561 };
1562
1563 self.functions = match unit.functions(&mut self.seen_ranges) {
1564 Ok(functions) => functions.into_iter(),
1565 Err(error) => return Some(Err(error)),
1566 };
1567 }
1568
1569 self.finished = true;
1570 None
1571 }
1572}
1573
1574impl std::iter::FusedIterator for DwarfFunctionIterator<'_> {}
1575
1576#[cfg(test)]
1577mod tests {
1578 use super::*;
1579
1580 use crate::macho::MachObject;
1581
1582 #[cfg(feature = "macho")]
1583 #[test]
1584 fn test_loads_debug_str_offsets() {
1585 let data = std::fs::read("tests/fixtures/helloworld").unwrap();
1588
1589 let obj = MachObject::parse(&data).unwrap();
1590
1591 let sections = DwarfSections::from_dwarf(&obj);
1592 assert_eq!(sections.debug_str_offsets.data.len(), 48);
1593 }
1594}