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] {
359 for seq in &self.sequences {
360 if range.begin >= seq.end || seq.start >= range.end {
361 continue;
362 }
363
364 let from = match seq.rows.binary_search_by_key(&range.begin, |x| x.address) {
365 Ok(idx) => idx,
366 Err(0) => 0,
373 Err(next_idx) => next_idx - 1,
374 };
375
376 let len = seq.rows[from..]
377 .binary_search_by_key(&range.end, |x| x.address)
378 .unwrap_or_else(|e| e);
385
386 return &seq.rows[from..from + len];
387 }
388 &[]
389 }
390}
391
392#[derive(Clone, Copy, Debug)]
394struct UnitRef<'d, 'a> {
395 info: &'a DwarfInfo<'d>,
396 unit: &'a Unit<'d>,
397}
398
399impl<'d> UnitRef<'d, '_> {
400 #[inline(always)]
402 fn slice_value(&self, value: AttributeValue<Slice<'d>>) -> Option<&'d [u8]> {
403 self.info
404 .attr_string(self.unit, value)
405 .map(|reader| reader.slice())
406 .ok()
407 }
408
409 #[inline(always)]
411 fn string_value(&self, value: AttributeValue<Slice<'d>>) -> Option<Cow<'d, str>> {
412 let slice = self.slice_value(value)?;
413 Some(String::from_utf8_lossy(slice))
414 }
415
416 fn resolve_reference<T, F>(&self, attr: Attribute<'d>, f: F) -> Result<Option<T>, DwarfError>
421 where
422 F: FnOnce(Self, &Die<'d>) -> Result<Option<T>, DwarfError>,
423 {
424 let (unit, offset) = match attr.value() {
425 AttributeValue::UnitRef(offset) => (*self, offset),
426 AttributeValue::DebugInfoRef(offset) => self.info.find_unit_offset(offset)?,
427 _ => return Ok(None),
429 };
430
431 let mut entries = unit.unit.entries_at_offset(offset)?;
432 entries.next_entry()?;
433
434 if let Some(entry) = entries.current() {
435 f(unit, entry)
436 } else {
437 Ok(None)
438 }
439 }
440
441 fn offset(&self) -> UnitSectionOffset {
443 self.unit.header.offset()
444 }
445
446 fn language(&self) -> Result<Option<Language>, DwarfError> {
448 let mut entries = self.unit.entries();
449 let Some(root_entry) = entries.next_dfs()? else {
450 return Ok(None);
451 };
452 let Some(AttributeValue::Language(lang)) = root_entry.attr_value(constants::DW_AT_language)
453 else {
454 return Ok(None);
455 };
456 Ok(Some(language_from_dwarf(lang)))
457 }
458
459 const MAX_ABSTRACT_ORIGIN_DEPTH: u8 = 16;
462
463 fn resolve_entry_language(
467 &self,
468 entry: &Die<'d>,
469 depth: u8,
470 ) -> Result<Option<Language>, DwarfError> {
471 if depth == 0 {
472 return Ok(None);
473 }
474 if let Some(attr) = entry.attr(constants::DW_AT_abstract_origin) {
475 return self.resolve_reference(*attr, |ref_unit, ref_entry| {
476 if let Some(lang) = ref_unit.resolve_entry_language(ref_entry, depth - 1)? {
478 return Ok(Some(lang));
479 }
480 if self.offset() != ref_unit.offset() {
482 ref_unit.language()
483 } else {
484 Ok(None)
485 }
486 });
487 }
488 Ok(None)
489 }
490
491 fn resolve_function_name(
493 &self,
494 entry: &Die<'d>,
495 language: Language,
496 bcsymbolmap: Option<&'d BcSymbolMap<'d>>,
497 prior_offset: Option<UnitOffset>,
498 ) -> Result<Option<Name<'d>>, DwarfError> {
499 let mut fallback_name = None;
500 let mut reference_target = None;
501
502 for attr in entry.attrs() {
503 match attr.name() {
504 constants::DW_AT_linkage_name | constants::DW_AT_MIPS_linkage_name => {
506 return Ok(self
507 .string_value(attr.value())
508 .map(|n| resolve_cow_name(bcsymbolmap, n))
509 .map(|n| Name::new(n, NameMangling::Mangled, language)));
510 }
511 constants::DW_AT_name => {
512 fallback_name = Some(attr);
513 }
514 constants::DW_AT_abstract_origin | constants::DW_AT_specification => {
515 reference_target = Some(attr);
516 }
517 _ => {}
518 }
519 }
520
521 if let Some(attr) = fallback_name {
522 return Ok(self
523 .string_value(attr.value())
524 .map(|n| resolve_cow_name(bcsymbolmap, n))
525 .map(|n| Name::new(n, NameMangling::Unmangled, language)));
526 }
527
528 if let Some(attr) = reference_target {
529 return self.resolve_reference(*attr, |ref_unit, ref_entry| {
530 if let Some(prior) = prior_offset {
533 if self.offset() == ref_unit.offset() && prior == ref_entry.offset() {
534 return Ok(None);
535 }
536 }
537
538 if self.offset() != ref_unit.offset() || entry.offset() != ref_entry.offset() {
539 ref_unit.resolve_function_name(
540 ref_entry,
541 language,
542 bcsymbolmap,
543 Some(entry.offset()),
544 )
545 } else {
546 Ok(None)
547 }
548 });
549 }
550
551 Ok(None)
552 }
553}
554
555#[derive(Debug)]
557struct DwarfUnit<'d, 'a> {
558 inner: UnitRef<'d, 'a>,
559 bcsymbolmap: Option<&'d BcSymbolMap<'d>>,
560 language: Language,
561 line_program: Option<DwarfLineProgram<'d>>,
562 prefer_dwarf_names: bool,
563}
564
565impl<'d, 'a> DwarfUnit<'d, 'a> {
566 fn from_unit(
568 unit: &'a Unit<'d>,
569 info: &'a DwarfInfo<'d>,
570 bcsymbolmap: Option<&'d BcSymbolMap<'d>>,
571 ) -> Result<Option<Self>, DwarfError> {
572 let inner = UnitRef { info, unit };
573 let mut entries = unit.entries();
574 let entry = match entries.next_dfs()? {
575 Some(entry) => entry,
576 None => return Err(gimli::read::Error::MissingUnitDie.into()),
577 };
578
579 if info.kind != ObjectKind::Relocatable
584 && unit.low_pc == 0
585 && entry.attr(constants::DW_AT_ranges).is_none()
586 {
587 return Ok(None);
588 }
589
590 let language = match entry.attr_value(constants::DW_AT_language) {
591 Some(AttributeValue::Language(lang)) => language_from_dwarf(lang),
592 _ => Language::Unknown,
593 };
594
595 let line_program = unit
596 .line_program
597 .as_ref()
598 .map(|program| DwarfLineProgram::prepare(program.clone()));
599
600 let producer = entry
604 .attr_value(constants::DW_AT_producer)
605 .and_then(|av| av.string_value(&info.inner.debug_str));
606
607 let prefer_dwarf_names = producer.as_deref() == Some(b"Dart VM");
610
611 Ok(Some(DwarfUnit {
612 inner,
613 bcsymbolmap,
614 language,
615 line_program,
616 prefer_dwarf_names,
617 }))
618 }
619
620 fn compilation_dir(&self) -> &'d [u8] {
622 match self.inner.unit.comp_dir {
623 Some(ref dir) => resolve_byte_name(self.bcsymbolmap, dir.slice()),
624 None => &[],
625 }
626 }
627
628 fn parse_ranges<'r>(
634 &self,
635 entries: &mut EntriesRaw<'d, '_>,
636 abbrev: &gimli::Abbreviation,
637 range_buf: &'r mut Vec<Range>,
638 ) -> Result<(&'r mut Vec<Range>, CallLocation), DwarfError> {
639 range_buf.clear();
640
641 let mut call_line = None;
642 let mut call_file = None;
643 let mut low_pc = None;
644 let mut high_pc = None;
645 let mut high_pc_rel = None;
646
647 let kind = self.inner.info.kind;
648
649 for spec in abbrev.attributes() {
650 let attr = entries.read_attribute(*spec)?;
651 match attr.name() {
652 constants::DW_AT_low_pc => match attr.value() {
653 AttributeValue::Addr(addr) => low_pc = Some(addr),
654 AttributeValue::DebugAddrIndex(index) => {
655 low_pc = Some(self.inner.info.address(self.inner.unit, index)?)
656 }
657 _ => return Err(GimliError::UnsupportedAttributeForm(attr.form()).into()),
658 },
659 constants::DW_AT_high_pc => match attr.value() {
660 AttributeValue::Addr(addr) => high_pc = Some(addr),
661 AttributeValue::DebugAddrIndex(index) => {
662 high_pc = Some(self.inner.info.address(self.inner.unit, index)?)
663 }
664 AttributeValue::Udata(size) => high_pc_rel = Some(size),
665 _ => return Err(GimliError::UnsupportedAttributeForm(attr.form()).into()),
666 },
667 constants::DW_AT_call_line => match attr.value() {
668 AttributeValue::Udata(line) => call_line = Some(line),
669 _ => return Err(GimliError::UnsupportedAttributeForm(attr.form()).into()),
670 },
671 constants::DW_AT_call_file => match attr.value() {
672 AttributeValue::FileIndex(file) => call_file = Some(file),
673 _ => return Err(GimliError::UnsupportedAttributeForm(attr.form()).into()),
674 },
675 constants::DW_AT_ranges
676 | constants::DW_AT_rnglists_base
677 | constants::DW_AT_start_scope => {
678 match self.inner.info.attr_ranges(self.inner.unit, attr.value())? {
679 Some(mut ranges) => {
680 while let Some(range) = match ranges.next() {
681 Ok(range) => range,
682 Err(gimli::Error::InvalidCfiSetLoc(_)) => None,
688 Err(err) => {
689 return Err(err.into());
690 }
691 } {
692 if range.begin > 0 || kind == ObjectKind::Relocatable {
695 range_buf.push(range);
696 }
697 }
698 }
699 None => continue,
700 }
701 }
702 _ => continue,
703 }
704 }
705
706 let call_location = CallLocation {
707 call_file,
708 call_line,
709 };
710
711 if range_buf.is_empty() {
712 if let Some(range) = Self::convert_pc_range(low_pc, high_pc, high_pc_rel, kind)? {
713 range_buf.push(range);
714 }
715 }
716
717 Ok((range_buf, call_location))
718 }
719
720 fn convert_pc_range(
721 low_pc: Option<u64>,
722 high_pc: Option<u64>,
723 high_pc_rel: Option<u64>,
724 kind: ObjectKind,
725 ) -> Result<Option<Range>, DwarfError> {
726 let low_pc = match low_pc {
731 Some(low_pc) if low_pc != 0 || kind == ObjectKind::Relocatable => low_pc,
732 _ => return Ok(None),
733 };
734
735 let high_pc = match (high_pc, high_pc_rel) {
736 (Some(high_pc), _) => high_pc,
737 (_, Some(high_pc_rel)) => low_pc.wrapping_add(high_pc_rel),
738 _ => return Ok(None),
739 };
740
741 if low_pc == high_pc {
742 return Ok(None);
745 }
746
747 if low_pc == u64::MAX || low_pc == u64::MAX - 1 {
748 return Ok(None);
751 }
752
753 if low_pc > high_pc {
754 return Err(DwarfErrorKind::InvertedFunctionRange.into());
755 }
756
757 Ok(Some(Range {
758 begin: low_pc,
759 end: high_pc,
760 }))
761 }
762
763 fn file_info(
765 &self,
766 line_program: &LineNumberProgramHeader<'d>,
767 file: &LineProgramFileEntry<'d>,
768 ) -> FileInfo<'d> {
769 FileInfo::new(
770 Cow::Borrowed(resolve_byte_name(
771 self.bcsymbolmap,
772 file.directory(line_program)
773 .and_then(|attr| self.inner.slice_value(attr))
774 .unwrap_or_default(),
775 )),
776 Cow::Borrowed(resolve_byte_name(
777 self.bcsymbolmap,
778 self.inner.slice_value(file.path_name()).unwrap_or_default(),
779 )),
780 )
781 }
782
783 fn resolve_file(&self, file_id: u64) -> Option<FileInfo<'d>> {
785 let line_program = match self.line_program {
786 Some(ref program) => &program.header,
787 None => return None,
788 };
789
790 line_program
791 .file(file_id)
792 .map(|file| self.file_info(line_program, file))
793 }
794
795 fn resolve_symbol_name(&self, address: u64, language: Language) -> Option<Name<'d>> {
797 let symbol = self.inner.info.symbol_map.lookup_exact(address)?;
798 let name = resolve_cow_name(self.bcsymbolmap, symbol.name.clone()?);
799 Some(Name::new(name, NameMangling::Mangled, language))
800 }
801
802 fn resolve_function_language(&self, entry: &Die<'d>, fallback_language: Language) -> Language {
810 self.inner
811 .resolve_entry_language(entry, UnitRef::MAX_ABSTRACT_ORIGIN_DEPTH)
812 .ok()
813 .flatten()
814 .unwrap_or(fallback_language)
815 }
816
817 fn parse_functions(
819 &self,
820 depth: isize,
821 entries: &mut EntriesRaw<'d, '_>,
822 output: &mut FunctionsOutput<'_, 'd>,
823 ) -> Result<(), DwarfError> {
824 while !entries.is_empty() {
825 let dw_die_offset = entries.next_offset();
826 let next_depth = entries.next_depth();
827 if next_depth <= depth {
828 return Ok(());
829 }
830 if let Some(abbrev) = entries.read_abbreviation()? {
831 if abbrev.tag() == constants::DW_TAG_subprogram {
832 self.parse_function(dw_die_offset, next_depth, entries, abbrev, output)?;
833 } else {
834 entries.skip_attributes(abbrev.attributes())?;
835 }
836 }
837 }
838 Ok(())
839 }
840
841 fn parse_function(
851 &self,
852 dw_die_offset: gimli::UnitOffset<usize>,
853 depth: isize,
854 entries: &mut EntriesRaw<'d, '_>,
855 abbrev: &gimli::Abbreviation,
856 output: &mut FunctionsOutput<'_, 'd>,
857 ) -> Result<(), DwarfError> {
858 let (ranges, _) = self.parse_ranges(entries, abbrev, &mut output.range_buf)?;
859
860 let seen_ranges = &mut *output.seen_ranges;
861 ranges.retain(|range| {
862 if range.begin > range.end {
864 return false;
865 }
866
867 let address = offset(range.begin, self.inner.info.address_offset);
876 let size = range.end - range.begin;
877
878 seen_ranges.insert((address, size))
879 });
880
881 if ranges.is_empty() {
889 return self.parse_functions(depth, entries, output);
890 }
891
892 let entry = self.inner.unit.entry(dw_die_offset)?;
900 let language = self.resolve_function_language(&entry, self.language);
904
905 let symbol_name = if self.prefer_dwarf_names {
906 None
907 } else {
908 let first_range_begin = ranges.iter().map(|range| range.begin).min().unwrap();
909 let function_address = offset(first_range_begin, self.inner.info.address_offset);
910 self.resolve_symbol_name(function_address, language)
911 };
912
913 let name = symbol_name
914 .or_else(|| {
915 self.inner
916 .resolve_function_name(&entry, language, self.bcsymbolmap, None)
917 .ok()
918 .flatten()
919 })
920 .unwrap_or_else(|| Name::new("", NameMangling::Unmangled, language));
921
922 let mut builders: Vec<(Range, FunctionBuilder)> = ranges
925 .iter()
926 .map(|range| {
927 let address = offset(range.begin, self.inner.info.address_offset);
928 let size = range.end - range.begin;
929 (
930 *range,
931 FunctionBuilder::new(name.clone(), self.compilation_dir(), address, size),
932 )
933 })
934 .collect();
935
936 self.parse_function_children(depth, 0, entries, &mut builders, output, language)?;
937
938 if let Some(line_program) = &self.line_program {
939 for (range, builder) in &mut builders {
940 for row in line_program.get_rows(range) {
941 let address = offset(row.address, self.inner.info.address_offset);
942 let size = row.size;
943 let file = self.resolve_file(row.file_index).unwrap_or_default();
944 let line = row.line.unwrap_or(0);
945 builder.add_leaf_line(address, size, file, line);
946 }
947 }
948 }
949
950 for (_range, builder) in builders {
951 output.functions.push(builder.finish());
952 }
953
954 Ok(())
955 }
956
957 fn parse_function_children(
959 &self,
960 depth: isize,
961 inline_depth: u32,
962 entries: &mut EntriesRaw<'d, '_>,
963 builders: &mut [(Range, FunctionBuilder<'d>)],
964 output: &mut FunctionsOutput<'_, 'd>,
965 language: Language,
966 ) -> Result<(), DwarfError> {
967 while !entries.is_empty() {
968 let dw_die_offset = entries.next_offset();
969 let next_depth = entries.next_depth();
970 if next_depth <= depth {
971 return Ok(());
972 }
973 let abbrev = match entries.read_abbreviation()? {
974 Some(abbrev) => abbrev,
975 None => continue,
976 };
977 match abbrev.tag() {
978 constants::DW_TAG_subprogram => {
979 self.parse_function(dw_die_offset, next_depth, entries, abbrev, output)?;
981 }
982 constants::DW_TAG_inlined_subroutine => {
983 self.parse_inlinee(
984 dw_die_offset,
985 next_depth,
986 inline_depth,
987 entries,
988 abbrev,
989 builders,
990 output,
991 language,
992 )?;
993 }
994 _ => {
995 entries.skip_attributes(abbrev.attributes())?;
996 }
997 }
998 }
999 Ok(())
1000 }
1001
1002 #[allow(clippy::too_many_arguments)]
1011 fn parse_inlinee(
1012 &self,
1013 dw_die_offset: gimli::UnitOffset<usize>,
1014 depth: isize,
1015 inline_depth: u32,
1016 entries: &mut EntriesRaw<'d, '_>,
1017 abbrev: &gimli::Abbreviation,
1018 builders: &mut [(Range, FunctionBuilder<'d>)],
1019 output: &mut FunctionsOutput<'_, 'd>,
1020 language: Language,
1021 ) -> Result<(), DwarfError> {
1022 let (ranges, call_location) = self.parse_ranges(entries, abbrev, &mut output.range_buf)?;
1023
1024 ranges.retain(|range| range.end > range.begin);
1025
1026 if ranges.is_empty() {
1034 return self.parse_functions(depth, entries, output);
1035 }
1036
1037 let entry = self.inner.unit.entry(dw_die_offset)?;
1038 let language = self.resolve_function_language(&entry, language);
1039
1040 let name = self
1044 .inner
1045 .resolve_function_name(&entry, language, self.bcsymbolmap, None)
1046 .ok()
1047 .flatten()
1048 .unwrap_or_else(|| Name::new("", NameMangling::Unmangled, language));
1049
1050 let call_file = call_location
1051 .call_file
1052 .and_then(|i| self.resolve_file(i))
1053 .unwrap_or_default();
1054 let call_line = call_location.call_line.unwrap_or(0);
1055
1056 for range in ranges.iter() {
1058 let builder = match builders.iter_mut().find(|(outer_range, _builder)| {
1061 range.begin >= outer_range.begin && range.begin < outer_range.end
1062 }) {
1063 Some((_outer_range, builder)) => builder,
1064 None => continue,
1065 };
1066
1067 let address = offset(range.begin, self.inner.info.address_offset);
1068 let size = range.end - range.begin;
1069 builder.add_inlinee(
1070 inline_depth,
1071 name.clone(),
1072 address,
1073 size,
1074 call_file.clone(),
1075 call_line,
1076 );
1077 }
1078
1079 self.parse_function_children(depth, inline_depth + 1, entries, builders, output, language)
1080 }
1081
1082 fn functions(
1084 &self,
1085 seen_ranges: &mut BTreeSet<(u64, u64)>,
1086 ) -> Result<Vec<Function<'d>>, DwarfError> {
1087 let mut entries = self.inner.unit.entries_raw(None)?;
1088 let mut output = FunctionsOutput::with_seen_ranges(seen_ranges);
1089 self.parse_functions(-1, &mut entries, &mut output)?;
1090 Ok(output.functions)
1091 }
1092}
1093
1094struct FunctionsOutput<'a, 'd> {
1096 pub functions: Vec<Function<'d>>,
1099 pub range_buf: Vec<Range>,
1101 pub seen_ranges: &'a mut BTreeSet<(u64, u64)>,
1103}
1104
1105impl<'a> FunctionsOutput<'a, '_> {
1106 pub fn with_seen_ranges(seen_ranges: &'a mut BTreeSet<(u64, u64)>) -> Self {
1107 Self {
1108 functions: Vec::new(),
1109 range_buf: Vec::new(),
1110 seen_ranges,
1111 }
1112 }
1113}
1114
1115#[derive(Debug, Default, Clone, Copy)]
1117struct CallLocation {
1118 pub call_file: Option<u64>,
1119 pub call_line: Option<u64>,
1120}
1121
1122fn language_from_dwarf(language: gimli::DwLang) -> Language {
1124 match language {
1125 constants::DW_LANG_C => Language::C,
1126 constants::DW_LANG_C11 => Language::C,
1127 constants::DW_LANG_C89 => Language::C,
1128 constants::DW_LANG_C99 => Language::C,
1129 constants::DW_LANG_C_plus_plus => Language::Cpp,
1130 constants::DW_LANG_C_plus_plus_03 => Language::Cpp,
1131 constants::DW_LANG_C_plus_plus_11 => Language::Cpp,
1132 constants::DW_LANG_C_plus_plus_14 => Language::Cpp,
1133 constants::DW_LANG_D => Language::D,
1134 constants::DW_LANG_Go => Language::Go,
1135 constants::DW_LANG_ObjC => Language::ObjC,
1136 constants::DW_LANG_ObjC_plus_plus => Language::ObjCpp,
1137 constants::DW_LANG_Rust => Language::Rust,
1138 constants::DW_LANG_Swift => Language::Swift,
1139 _ => Language::Unknown,
1140 }
1141}
1142
1143struct DwarfSectionData<'data, S> {
1145 data: Cow<'data, [u8]>,
1146 endianity: Endian,
1147 _ph: PhantomData<S>,
1148}
1149
1150impl<'data, S> DwarfSectionData<'data, S>
1151where
1152 S: gimli::read::Section<Slice<'data>>,
1153{
1154 fn load<D>(dwarf: &D) -> Self
1156 where
1157 D: Dwarf<'data>,
1158 {
1159 DwarfSectionData {
1160 data: dwarf
1161 .section(&S::section_name()[1..])
1162 .map(|section| section.data)
1163 .unwrap_or_default(),
1164 endianity: dwarf.endianity(),
1165 _ph: PhantomData,
1166 }
1167 }
1168
1169 fn to_gimli(&'data self) -> S {
1171 S::from(Slice::new(&self.data, self.endianity))
1172 }
1173}
1174
1175impl<'d, S> fmt::Debug for DwarfSectionData<'d, S>
1176where
1177 S: gimli::read::Section<Slice<'d>>,
1178{
1179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1180 let owned = match self.data {
1181 Cow::Owned(_) => true,
1182 Cow::Borrowed(_) => false,
1183 };
1184
1185 f.debug_struct("DwarfSectionData")
1186 .field("type", &S::section_name())
1187 .field("endianity", &self.endianity)
1188 .field("len()", &self.data.len())
1189 .field("owned()", &owned)
1190 .finish()
1191 }
1192}
1193
1194struct DwarfSections<'data> {
1196 debug_abbrev: DwarfSectionData<'data, gimli::read::DebugAbbrev<Slice<'data>>>,
1197 debug_addr: DwarfSectionData<'data, gimli::read::DebugAddr<Slice<'data>>>,
1198 debug_aranges: DwarfSectionData<'data, gimli::read::DebugAranges<Slice<'data>>>,
1199 debug_info: DwarfSectionData<'data, gimli::read::DebugInfo<Slice<'data>>>,
1200 debug_line: DwarfSectionData<'data, gimli::read::DebugLine<Slice<'data>>>,
1201 debug_line_str: DwarfSectionData<'data, gimli::read::DebugLineStr<Slice<'data>>>,
1202 debug_names: DwarfSectionData<'data, gimli::read::DebugNames<Slice<'data>>>,
1203 debug_str: DwarfSectionData<'data, gimli::read::DebugStr<Slice<'data>>>,
1204 debug_str_offsets: DwarfSectionData<'data, gimli::read::DebugStrOffsets<Slice<'data>>>,
1205 debug_ranges: DwarfSectionData<'data, gimli::read::DebugRanges<Slice<'data>>>,
1206 debug_rnglists: DwarfSectionData<'data, gimli::read::DebugRngLists<Slice<'data>>>,
1207 debug_macinfo: DwarfSectionData<'data, gimli::read::DebugMacinfo<Slice<'data>>>,
1208 debug_macro: DwarfSectionData<'data, gimli::read::DebugMacro<Slice<'data>>>,
1209}
1210
1211impl<'data> DwarfSections<'data> {
1212 fn from_dwarf<D>(dwarf: &D) -> Self
1214 where
1215 D: Dwarf<'data>,
1216 {
1217 DwarfSections {
1218 debug_abbrev: DwarfSectionData::load(dwarf),
1219 debug_addr: DwarfSectionData::load(dwarf),
1220 debug_aranges: DwarfSectionData::load(dwarf),
1221 debug_info: DwarfSectionData::load(dwarf),
1222 debug_line: DwarfSectionData::load(dwarf),
1223 debug_line_str: DwarfSectionData::load(dwarf),
1224 debug_names: DwarfSectionData::load(dwarf),
1225 debug_str: DwarfSectionData::load(dwarf),
1226 debug_str_offsets: DwarfSectionData::load(dwarf),
1227 debug_ranges: DwarfSectionData::load(dwarf),
1228 debug_rnglists: DwarfSectionData::load(dwarf),
1229 debug_macinfo: DwarfSectionData::load(dwarf),
1230 debug_macro: DwarfSectionData::load(dwarf),
1231 }
1232 }
1233}
1234
1235struct DwarfInfo<'data> {
1236 inner: DwarfInner<'data>,
1237 headers: Vec<UnitHeader<'data>>,
1238 units: Vec<OnceCell<Option<Unit<'data>>>>,
1239 symbol_map: SymbolMap<'data>,
1240 address_offset: i64,
1241 kind: ObjectKind,
1242}
1243
1244impl<'d> Deref for DwarfInfo<'d> {
1245 type Target = DwarfInner<'d>;
1246
1247 fn deref(&self) -> &Self::Target {
1248 &self.inner
1249 }
1250}
1251
1252impl<'d> DwarfInfo<'d> {
1253 pub fn parse(
1255 sections: &'d DwarfSections<'d>,
1256 symbol_map: SymbolMap<'d>,
1257 address_offset: i64,
1258 kind: ObjectKind,
1259 ) -> Result<Self, DwarfError> {
1260 let mut inner = gimli::read::Dwarf {
1261 abbreviations_cache: Default::default(),
1262 debug_abbrev: sections.debug_abbrev.to_gimli(),
1263 debug_addr: sections.debug_addr.to_gimli(),
1264 debug_aranges: sections.debug_aranges.to_gimli(),
1265 debug_info: sections.debug_info.to_gimli(),
1266 debug_line: sections.debug_line.to_gimli(),
1267 debug_line_str: sections.debug_line_str.to_gimli(),
1268 debug_names: sections.debug_names.to_gimli(),
1269 debug_str: sections.debug_str.to_gimli(),
1270 debug_str_offsets: sections.debug_str_offsets.to_gimli(),
1271 debug_types: Default::default(),
1272 debug_macinfo: sections.debug_macinfo.to_gimli(),
1273 debug_macro: sections.debug_macro.to_gimli(),
1274 locations: Default::default(),
1275 ranges: RangeLists::new(
1276 sections.debug_ranges.to_gimli(),
1277 sections.debug_rnglists.to_gimli(),
1278 ),
1279 file_type: DwarfFileType::Main,
1280 sup: Default::default(),
1281 };
1282 inner.populate_abbreviations_cache(AbbreviationsCacheStrategy::Duplicates);
1283
1284 let headers = FallibleIterator::collect::<Vec<_>>(inner.units())?;
1286 let units = headers.iter().map(|_| OnceCell::new()).collect();
1287
1288 Ok(DwarfInfo {
1289 inner,
1290 headers,
1291 units,
1292 symbol_map,
1293 address_offset,
1294 kind,
1295 })
1296 }
1297
1298 fn get_unit(&self, index: usize) -> Result<Option<&Unit<'d>>, DwarfError> {
1300 let cell = match self.units.get(index) {
1302 Some(cell) => cell,
1303 None => return Ok(None),
1304 };
1305
1306 let unit_opt = cell.get_or_try_init(|| {
1307 let header = self.headers[index];
1312 match self.inner.unit(header) {
1313 Ok(unit) => Ok(Some(unit)),
1314 Err(gimli::read::Error::MissingUnitDie) => Ok(None),
1315 Err(error) => Err(DwarfError::from(error)),
1316 }
1317 })?;
1318
1319 Ok(unit_opt.as_ref())
1320 }
1321
1322 fn find_unit_offset(
1324 &self,
1325 offset: DebugInfoOffset,
1326 ) -> Result<(UnitRef<'d, '_>, UnitOffset), DwarfError> {
1327 let section_offset = UnitSectionOffset(offset.0);
1328 let search_result = self
1329 .headers
1330 .binary_search_by_key(§ion_offset, UnitHeader::offset);
1331
1332 let index = match search_result {
1333 Ok(index) => index,
1334 Err(0) => return Err(DwarfErrorKind::InvalidUnitRef(offset.0).into()),
1335 Err(next_index) => next_index - 1,
1336 };
1337
1338 if let Some(unit) = self.get_unit(index)? {
1339 if let Some(unit_offset) = section_offset.to_unit_offset(unit) {
1340 return Ok((UnitRef { unit, info: self }, unit_offset));
1341 }
1342 }
1343
1344 Err(DwarfErrorKind::InvalidUnitRef(offset.0).into())
1345 }
1346
1347 fn units(&'d self, bcsymbolmap: Option<&'d BcSymbolMap<'d>>) -> DwarfUnitIterator<'d> {
1349 DwarfUnitIterator {
1350 info: self,
1351 bcsymbolmap,
1352 index: 0,
1353 }
1354 }
1355}
1356
1357impl<'slf, 'd: 'slf> AsSelf<'slf> for DwarfInfo<'d> {
1358 type Ref = DwarfInfo<'slf>;
1359
1360 fn as_self(&'slf self) -> &'slf Self::Ref {
1361 unsafe { std::mem::transmute(self) }
1362 }
1363}
1364
1365impl fmt::Debug for DwarfInfo<'_> {
1366 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1367 f.debug_struct("DwarfInfo")
1368 .field("headers", &self.headers)
1369 .field("symbol_map", &self.symbol_map)
1370 .field("address_offset", &self.address_offset)
1371 .finish()
1372 }
1373}
1374
1375struct DwarfUnitIterator<'s> {
1377 info: &'s DwarfInfo<'s>,
1378 bcsymbolmap: Option<&'s BcSymbolMap<'s>>,
1379 index: usize,
1380}
1381
1382impl<'s> Iterator for DwarfUnitIterator<'s> {
1383 type Item = Result<DwarfUnit<'s, 's>, DwarfError>;
1384
1385 fn next(&mut self) -> Option<Self::Item> {
1386 while self.index < self.info.headers.len() {
1387 let result = self.info.get_unit(self.index);
1388 self.index += 1;
1389
1390 let unit = match result {
1391 Ok(Some(unit)) => unit,
1392 Ok(None) => continue,
1393 Err(error) => return Some(Err(error)),
1394 };
1395
1396 match DwarfUnit::from_unit(unit, self.info, self.bcsymbolmap) {
1397 Ok(Some(unit)) => return Some(Ok(unit)),
1398 Ok(None) => continue,
1399 Err(error) => return Some(Err(error)),
1400 }
1401 }
1402
1403 None
1404 }
1405}
1406
1407impl std::iter::FusedIterator for DwarfUnitIterator<'_> {}
1408
1409pub struct DwarfDebugSession<'data> {
1411 cell: SelfCell<Box<DwarfSections<'data>>, DwarfInfo<'data>>,
1412 bcsymbolmap: Option<Arc<BcSymbolMap<'data>>>,
1413}
1414
1415impl<'data> DwarfDebugSession<'data> {
1416 pub fn parse<D>(
1418 dwarf: &D,
1419 symbol_map: SymbolMap<'data>,
1420 address_offset: i64,
1421 kind: ObjectKind,
1422 ) -> Result<Self, DwarfError>
1423 where
1424 D: Dwarf<'data>,
1425 {
1426 let sections = DwarfSections::from_dwarf(dwarf);
1427 let cell = SelfCell::try_new(Box::new(sections), |sections| {
1428 DwarfInfo::parse(unsafe { &*sections }, symbol_map, address_offset, kind)
1429 })?;
1430
1431 Ok(DwarfDebugSession {
1432 cell,
1433 bcsymbolmap: None,
1434 })
1435 }
1436
1437 #[cfg(feature = "macho")]
1442 pub(crate) fn load_symbolmap(&mut self, symbolmap: Option<Arc<BcSymbolMap<'data>>>) {
1443 self.bcsymbolmap = symbolmap;
1444 }
1445
1446 pub fn files(&self) -> DwarfFileIterator<'_> {
1448 DwarfFileIterator {
1449 units: self.cell.get().units(self.bcsymbolmap.as_deref()),
1450 files: DwarfUnitFileIterator::default(),
1451 finished: false,
1452 }
1453 }
1454
1455 pub fn functions(&self) -> DwarfFunctionIterator<'_> {
1457 DwarfFunctionIterator {
1458 units: self.cell.get().units(self.bcsymbolmap.as_deref()),
1459 functions: Vec::new().into_iter(),
1460 seen_ranges: BTreeSet::new(),
1461 finished: false,
1462 }
1463 }
1464
1465 pub fn source_by_path(
1467 &self,
1468 _path: &str,
1469 ) -> Result<Option<SourceFileDescriptor<'_>>, DwarfError> {
1470 Ok(None)
1471 }
1472}
1473
1474impl<'session> DebugSession<'session> for DwarfDebugSession<'_> {
1475 type Error = DwarfError;
1476 type FunctionIterator = DwarfFunctionIterator<'session>;
1477 type FileIterator = DwarfFileIterator<'session>;
1478
1479 fn functions(&'session self) -> Self::FunctionIterator {
1480 self.functions()
1481 }
1482
1483 fn files(&'session self) -> Self::FileIterator {
1484 self.files()
1485 }
1486
1487 fn source_by_path(&self, path: &str) -> Result<Option<SourceFileDescriptor<'_>>, Self::Error> {
1488 self.source_by_path(path)
1489 }
1490}
1491
1492#[derive(Debug, Default)]
1493struct DwarfUnitFileIterator<'s> {
1494 unit: Option<DwarfUnit<'s, 's>>,
1495 index: usize,
1496}
1497
1498impl<'s> Iterator for DwarfUnitFileIterator<'s> {
1499 type Item = FileEntry<'s>;
1500
1501 fn next(&mut self) -> Option<Self::Item> {
1502 let unit = self.unit.as_ref()?;
1503 let line_program = unit.line_program.as_ref().map(|p| &p.header)?;
1504 let file = line_program.file_names().get(self.index)?;
1505
1506 self.index += 1;
1507
1508 Some(FileEntry::new(
1509 Cow::Borrowed(unit.compilation_dir()),
1510 unit.file_info(line_program, file),
1511 ))
1512 }
1513}
1514
1515fn resolve_byte_name<'s>(bcsymbolmap: Option<&'s BcSymbolMap<'s>>, s: &'s [u8]) -> &'s [u8] {
1516 bcsymbolmap
1517 .and_then(|b| b.resolve_opt(s))
1518 .map(AsRef::as_ref)
1519 .unwrap_or(s)
1520}
1521
1522fn resolve_cow_name<'s>(bcsymbolmap: Option<&'s BcSymbolMap<'s>>, s: Cow<'s, str>) -> Cow<'s, str> {
1523 bcsymbolmap
1524 .and_then(|b| b.resolve_opt(s.as_bytes()))
1525 .map(Cow::Borrowed)
1526 .unwrap_or(s)
1527}
1528
1529pub struct DwarfFileIterator<'s> {
1531 units: DwarfUnitIterator<'s>,
1532 files: DwarfUnitFileIterator<'s>,
1533 finished: bool,
1534}
1535
1536impl<'s> Iterator for DwarfFileIterator<'s> {
1537 type Item = Result<FileEntry<'s>, DwarfError>;
1538
1539 fn next(&mut self) -> Option<Self::Item> {
1540 if self.finished {
1541 return None;
1542 }
1543
1544 loop {
1545 if let Some(file_entry) = self.files.next() {
1546 return Some(Ok(file_entry));
1547 }
1548
1549 let unit = match self.units.next() {
1550 Some(Ok(unit)) => unit,
1551 Some(Err(error)) => return Some(Err(error)),
1552 None => break,
1553 };
1554
1555 self.files = DwarfUnitFileIterator {
1556 unit: Some(unit),
1557 index: 0,
1558 };
1559 }
1560
1561 self.finished = true;
1562 None
1563 }
1564}
1565
1566pub struct DwarfFunctionIterator<'s> {
1568 units: DwarfUnitIterator<'s>,
1569 functions: std::vec::IntoIter<Function<'s>>,
1570 seen_ranges: BTreeSet<(u64, u64)>,
1571 finished: bool,
1572}
1573
1574impl<'s> Iterator for DwarfFunctionIterator<'s> {
1575 type Item = Result<Function<'s>, DwarfError>;
1576
1577 fn next(&mut self) -> Option<Self::Item> {
1578 if self.finished {
1579 return None;
1580 }
1581
1582 loop {
1583 if let Some(func) = self.functions.next() {
1584 return Some(Ok(func));
1585 }
1586
1587 let unit = match self.units.next() {
1588 Some(Ok(unit)) => unit,
1589 Some(Err(error)) => return Some(Err(error)),
1590 None => break,
1591 };
1592
1593 self.functions = match unit.functions(&mut self.seen_ranges) {
1594 Ok(functions) => functions.into_iter(),
1595 Err(error) => return Some(Err(error)),
1596 };
1597 }
1598
1599 self.finished = true;
1600 None
1601 }
1602}
1603
1604impl std::iter::FusedIterator for DwarfFunctionIterator<'_> {}
1605
1606#[cfg(test)]
1607mod tests {
1608 use super::*;
1609
1610 use crate::macho::MachObject;
1611
1612 #[cfg(feature = "macho")]
1613 #[test]
1614 fn test_loads_debug_str_offsets() {
1615 let data = std::fs::read("tests/fixtures/helloworld").unwrap();
1618
1619 let obj = MachObject::parse(&data).unwrap();
1620
1621 let sections = DwarfSections::from_dwarf(&obj);
1622 assert_eq!(sections.debug_str_offsets.data.len(), 48);
1623 }
1624}