1use std::borrow::Cow;
2use std::collections::{BTreeMap, HashMap};
3use std::mem;
4use std::sync::Arc;
5
6use gimli::Reader as GimliReader;
7use object::{self, ObjectSection, ObjectSymbol};
8
9use crate::cfi::{Cfi, CfiDirective};
10use crate::file::{Architecture, Arena, DebugInfo, FileHash};
11use crate::function::{
12 Function, FunctionDetails, FunctionOffset, InlinedFunction, Parameter, ParameterOffset,
13};
14use crate::location::{Location, Piece, Register};
15use crate::namespace::{Namespace, NamespaceKind};
16use crate::range::Range;
17use crate::source::Source;
18use crate::types::{
19 ArrayType, BaseType, BaseTypeEncoding, Endianity, EnumerationType, Enumerator, FunctionType,
20 Inherit, Member, MemberOffset, ParameterType, PointerToMemberType, StructType, SubrangeType,
21 Type, TypeDef, TypeKind, TypeModifier, TypeModifierKind, TypeOffset, UnionType,
22 UnspecifiedType, Variant, VariantPart,
23};
24use crate::unit::Unit;
25use crate::variable::{LocalVariable, Variable, VariableOffset};
26use crate::{Address, Id, Result, Size};
27
28pub(crate) type RelocationMap = HashMap<usize, object::Relocation>;
29
30fn add_relocations<'input, 'file, Object>(
31 relocations: &mut RelocationMap,
32 file: &'file Object,
33 section: &Object::Section<'file>,
34) where
35 Object: object::Object<'input>,
36{
37 for (offset64, mut relocation) in section.relocations() {
38 let offset = offset64 as usize;
39 if offset as u64 != offset64 {
40 continue;
41 }
42 let target = match relocation.target() {
43 object::RelocationTarget::Symbol(index) => {
44 if let Ok(symbol) = file.symbol_by_index(index) {
45 symbol.address()
46 } else {
47 println!(
48 "Relocation with invalid symbol index {} for section {} at offset 0x{:08x}",
49 index.0,
50 section.name().unwrap(),
51 offset
52 );
53 continue;
54 }
55 }
56 object::RelocationTarget::Section(index) => {
57 if let Ok(section) = file.section_by_index(index) {
58 section.address()
59 } else {
60 println!(
61 "Relocation with invalid section index {} for section {} at offset 0x{:08x}",
62 index.0,
63 section.name().unwrap(),
64 offset
65 );
66 continue;
67 }
68 }
69 _ => {
70 continue;
71 }
72 };
73 match relocation.kind() {
74 object::RelocationKind::Absolute => {
75 let addend = target.wrapping_add(relocation.addend() as u64);
76 relocation.set_addend(addend as i64);
77 if relocations.insert(offset, relocation).is_some() {
78 println!(
79 "Multiple relocations for section {} at offset 0x{:08x}",
80 section.name().unwrap(),
81 offset
82 );
83 }
84 }
85 object::RelocationKind::Relative => {
86 let addend = target
87 .wrapping_add(relocation.addend() as u64)
88 .wrapping_sub(section.address())
89 .wrapping_sub(offset as u64);
90 relocation.set_addend(addend as i64);
91 if relocations.insert(offset, relocation).is_some() {
92 println!(
93 "Multiple relocations for section {} at offset 0x{:08x}",
94 section.name().unwrap(),
95 offset
96 );
97 }
98 }
99 _ => {
100 println!(
101 "Unsupported relocation for section {} at offset 0x{:08x}",
102 section.name().unwrap(),
103 offset
104 );
105 }
106 }
107 }
108}
109
110#[derive(Debug, Clone, Copy)]
111struct Relocate<'a, R: gimli::Reader<Offset = usize>> {
112 relocations: &'a RelocationMap,
113 section: R,
114 reader: R,
115}
116
117impl<'a, R: gimli::Reader<Offset = usize>> Relocate<'a, R> {
118 fn relocate(&self, offset: usize, value: u64) -> u64 {
119 if let Some(relocation) = self.relocations.get(&offset) {
120 match relocation.kind() {
121 object::RelocationKind::Absolute | object::RelocationKind::Relative => {
122 if relocation.has_implicit_addend() {
123 return value.wrapping_add(relocation.addend() as u64);
125 } else {
126 return relocation.addend() as u64;
127 }
128 }
129 _ => {}
130 }
131 };
132 value
133 }
134}
135
136impl<'a, Endian> Relocate<'a, gimli::EndianSlice<'a, Endian>>
137where
138 Endian: gimli::Endianity,
139{
140 fn slice(&self) -> &'a [u8] {
141 self.reader.slice()
142 }
143}
144
145impl<'a, R: gimli::Reader<Offset = usize>> gimli::Reader for Relocate<'a, R> {
146 type Endian = R::Endian;
147 type Offset = R::Offset;
148
149 fn read_address(&mut self, address_size: u8) -> gimli::Result<u64> {
150 let offset = self.reader.offset_from(&self.section);
151 let value = self.reader.read_address(address_size)?;
152 Ok(self.relocate(offset, value))
153 }
154
155 fn read_length(&mut self, format: gimli::Format) -> gimli::Result<usize> {
156 let offset = self.reader.offset_from(&self.section);
157 let value = self.reader.read_length(format)?;
158 <usize as gimli::ReaderOffset>::from_u64(self.relocate(offset, value as u64))
159 }
160
161 fn read_offset(&mut self, format: gimli::Format) -> gimli::Result<usize> {
162 let offset = self.reader.offset_from(&self.section);
163 let value = self.reader.read_offset(format)?;
164 <usize as gimli::ReaderOffset>::from_u64(self.relocate(offset, value as u64))
165 }
166
167 fn read_sized_offset(&mut self, size: u8) -> gimli::Result<usize> {
168 let offset = self.reader.offset_from(&self.section);
169 let value = self.reader.read_sized_offset(size)?;
170 <usize as gimli::ReaderOffset>::from_u64(self.relocate(offset, value as u64))
171 }
172
173 #[inline]
174 fn split(&mut self, len: Self::Offset) -> gimli::Result<Self> {
175 let mut other = self.clone();
176 other.reader.truncate(len)?;
177 self.reader.skip(len)?;
178 Ok(other)
179 }
180
181 #[inline]
184 fn endian(&self) -> Self::Endian {
185 self.reader.endian()
186 }
187
188 #[inline]
189 fn len(&self) -> Self::Offset {
190 self.reader.len()
191 }
192
193 #[inline]
194 fn empty(&mut self) {
195 self.reader.empty()
196 }
197
198 #[inline]
199 fn truncate(&mut self, len: Self::Offset) -> gimli::Result<()> {
200 self.reader.truncate(len)
201 }
202
203 #[inline]
204 fn offset_from(&self, base: &Self) -> Self::Offset {
205 self.reader.offset_from(&base.reader)
206 }
207
208 #[inline]
209 fn offset_id(&self) -> gimli::ReaderOffsetId {
210 self.reader.offset_id()
211 }
212
213 #[inline]
214 fn lookup_offset_id(&self, id: gimli::ReaderOffsetId) -> Option<Self::Offset> {
215 self.reader.lookup_offset_id(id)
216 }
217
218 #[inline]
219 fn find(&self, byte: u8) -> gimli::Result<Self::Offset> {
220 self.reader.find(byte)
221 }
222
223 #[inline]
224 fn skip(&mut self, len: Self::Offset) -> gimli::Result<()> {
225 self.reader.skip(len)
226 }
227
228 #[inline]
229 fn to_slice(&self) -> gimli::Result<Cow<[u8]>> {
230 self.reader.to_slice()
231 }
232
233 #[inline]
234 fn to_string(&self) -> gimli::Result<Cow<str>> {
235 self.reader.to_string()
236 }
237
238 #[inline]
239 fn to_string_lossy(&self) -> gimli::Result<Cow<str>> {
240 self.reader.to_string_lossy()
241 }
242
243 #[inline]
244 fn read_slice(&mut self, buf: &mut [u8]) -> gimli::Result<()> {
245 self.reader.read_slice(buf)
246 }
247}
248
249type Reader<'input, Endian> = Relocate<'input, gimli::EndianSlice<'input, Endian>>;
250
251pub(crate) struct DwarfDebugInfo<'input, Endian>
252where
253 Endian: gimli::Endianity,
254{
255 endian: Endian,
256 read: gimli::Dwarf<Reader<'input, Endian>>,
257 frame: DwarfFrame<Reader<'input, Endian>>,
258 arena: &'input Arena,
259 units: Vec<gimli::Unit<Reader<'input, Endian>, usize>>,
260}
261
262impl<'input, Endian> DwarfDebugInfo<'input, Endian>
263where
264 Endian: gimli::Endianity,
265{
266 fn string(
267 &self,
268 dwarf_unit: &DwarfUnit<'input, Endian>,
269 value: gimli::AttributeValue<Reader<'input, Endian>>,
270 ) -> Option<&'input str> {
271 self.read
272 .attr_string(dwarf_unit, value)
273 .map(|r| self.arena.add_string(r.slice()))
274 .ok()
275 }
276
277 fn tree(
278 &self,
279 offset: gimli::DebugInfoOffset,
280 ) -> Option<(
281 &DwarfUnit<'input, Endian>,
282 gimli::EntriesTree<Reader<'input, Endian>>,
283 )> {
284 let offset = gimli::UnitSectionOffset::DebugInfoOffset(offset);
287 for unit in &self.units {
288 if let Some(offset) = offset.to_unit_offset(unit) {
289 let tree = unit.entries_tree(Some(offset)).ok()?;
290 return Some((unit, tree));
291 }
292 }
293 None
294 }
295
296 fn type_tree(
297 &self,
298 offset: TypeOffset,
299 ) -> Option<(
300 &DwarfUnit<'input, Endian>,
301 gimli::EntriesTree<Reader<'input, Endian>>,
302 )> {
303 offset
304 .get()
305 .and_then(|offset| self.tree(gimli::DebugInfoOffset(offset)))
306 }
307
308 fn function_tree(
309 &self,
310 offset: FunctionOffset,
311 ) -> Option<(
312 &DwarfUnit<'input, Endian>,
313 gimli::EntriesTree<Reader<'input, Endian>>,
314 )> {
315 offset
316 .get()
317 .and_then(|offset| self.tree(gimli::DebugInfoOffset(offset)))
318 }
319
320 pub(crate) fn get_type(&self, offset: TypeOffset) -> Option<Type<'input>> {
321 self.type_tree(offset).and_then(|(unit, mut tree)| {
322 let node = tree.root().ok()?;
323 parse_unnamed_type(self, unit, node).ok()?
324 })
325 }
326
327 pub(crate) fn get_enumerators(&self, offset: TypeOffset) -> Vec<Enumerator<'input>> {
328 self.type_tree(offset)
329 .and_then(|(unit, mut tree)| {
330 let node = tree.root().ok()?;
331 parse_enumerators(self, unit, node).ok()
332 })
333 .unwrap_or_default()
334 }
335
336 pub(crate) fn get_function_details(
337 &self,
338 offset: FunctionOffset,
339 hash: &FileHash<'input>,
340 ) -> Option<FunctionDetails<'input>> {
341 self.function_tree(offset).and_then(|(unit, mut tree)| {
342 let node = tree.root().ok()?;
343 parse_subprogram_details(hash, self, unit, node).ok()
344 })
345 }
346
347 pub(crate) fn get_cfi(&self, range: Range) -> Vec<Cfi> {
348 self.frame.get_cfi(range).unwrap_or_default()
349 }
350
351 pub(crate) fn get_register_name(
352 &self,
353 machine: Architecture,
354 register: Register,
355 ) -> Option<&'static str> {
356 let register_name = match machine {
357 Architecture::Arm => gimli::Arm::register_name,
358 Architecture::I386 => gimli::X86::register_name,
359 Architecture::X86_64 => gimli::X86_64::register_name,
360 _ => return None,
361 };
362 register_name(gimli::Register(register.0))
363 }
364}
365
366type DwarfUnit<'input, Endian> = gimli::Unit<Reader<'input, Endian>>;
367
368struct DwarfSubprogram<'input> {
369 offset: gimli::UnitOffset,
370 specification: FunctionOffset,
371 abstract_origin: bool,
372 function: Function<'input>,
373}
374
375struct DwarfVariable<'input> {
376 offset: gimli::UnitOffset,
377 specification: Option<VariableOffset>,
378 variable: Variable<'input>,
379}
380
381pub(crate) fn parse<'input, Endian, Object>(
382 endian: Endian,
383 object: &Object,
384 arena: &'input Arena,
385) -> Result<(Vec<Unit<'input>>, DebugInfo<'input, Endian>)>
386where
387 Endian: gimli::Endianity,
388 Object: object::Object<'input>,
389{
390 let get_section = |id: gimli::SectionId| -> Result<_> {
391 let mut relocations = RelocationMap::default();
392 let data = match object.section_by_name(id.name()) {
393 Some(section) => {
394 add_relocations(&mut relocations, object, §ion);
395 match section.uncompressed_data()? {
396 Cow::Borrowed(bytes) => bytes,
397 Cow::Owned(bytes) => arena.add_buffer(bytes),
398 }
399 }
400 None => &[],
401 };
402 let relocations = arena.add_relocations(Box::new(relocations));
403 let reader = gimli::EndianSlice::new(data, endian);
404 Ok(Relocate {
405 relocations,
406 section: reader,
407 reader,
408 })
409 };
410 let read = gimli::Dwarf::load(get_section)?;
411
412 let debug_frame = get_section(gimli::SectionId::DebugFrame)?;
413 let eh_frame = get_section(gimli::SectionId::EhFrame)?;
414 let mut bases = gimli::BaseAddresses::default();
415 if let Some(section) = object.section_by_name(".eh_frame") {
416 bases = bases.set_eh_frame(section.address());
417 }
418 if let Some(section) = object.section_by_name(".text") {
419 bases = bases.set_text(section.address());
420 }
421 if let Some(section) = object.section_by_name(".got") {
422 bases = bases.set_got(section.address());
423 }
424 let frame = DwarfFrame::new(debug_frame.into(), eh_frame.into(), bases);
425
426 let mut dwarf = DwarfDebugInfo {
427 endian,
428 read,
429 frame,
430 arena,
431 units: Vec::new(),
432 };
433
434 let mut units = Vec::new();
435 let mut unit_headers = dwarf.read.units();
436 while let Some(unit_header) = unit_headers.next()? {
437 let dwarf_unit = dwarf.read.unit(unit_header)?;
438 units.push(parse_unit(&mut dwarf, dwarf_unit)?);
439 }
440 Ok((units, DebugInfo::Dwarf(dwarf)))
441}
442
443fn parse_unit<'input, Endian>(
444 dwarf: &mut DwarfDebugInfo<'input, Endian>,
445 dwarf_unit: DwarfUnit<'input, Endian>,
446) -> Result<Unit<'input>>
447where
448 Endian: gimli::Endianity,
449{
450 let mut unit = Unit::default();
451
452 let mut subprograms = Vec::new();
453 let mut variables = Vec::new();
454
455 let mut tree = dwarf_unit.entries_tree(None)?;
456 let root = tree.root()?;
457
458 let entry = root.entry();
459 if entry.tag() != gimli::DW_TAG_compile_unit {
460 return Err(format!("unknown CU tag: {}", entry.tag()).into());
461 }
462
463 let mut ranges = None;
464 let mut high_pc = None;
465 let mut size = None;
466 let mut attrs = entry.attrs();
467 while let Some(attr) = attrs.next()? {
468 match attr.name() {
469 gimli::DW_AT_name => {
470 unit.name = dwarf.string(&dwarf_unit, attr.value()).map(Cow::Borrowed);
471 }
472 gimli::DW_AT_comp_dir => {
473 unit.dir = dwarf.string(&dwarf_unit, attr.value()).map(Cow::Borrowed);
474 }
475 gimli::DW_AT_language => {
476 if let gimli::AttributeValue::Language(language) = attr.value() {
477 unit.language = Some(language);
478 }
479 }
480 gimli::DW_AT_low_pc => {
481 if let gimli::AttributeValue::Addr(addr) = attr.value() {
482 unit.low_pc = Some(addr);
483 }
484 }
485 gimli::DW_AT_high_pc => match attr.value() {
486 gimli::AttributeValue::Addr(val) => high_pc = Some(val),
487 gimli::AttributeValue::Udata(val) => size = Some(val),
488 val => debug!("unknown CU DW_AT_high_pc: {:?}", val),
489 },
490 gimli::DW_AT_ranges => {
491 if let gimli::AttributeValue::RangeListsRef(val) = attr.value() {
492 ranges = Some(val);
493 }
494 }
495 gimli::DW_AT_stmt_list
496 | gimli::DW_AT_producer
497 | gimli::DW_AT_entry_pc
498 | gimli::DW_AT_APPLE_optimized
499 | gimli::DW_AT_macro_info
500 | gimli::DW_AT_GNU_macros
501 | gimli::DW_AT_GNU_pubnames
502 | gimli::DW_AT_sibling => {}
503 _ => debug!("unknown CU attribute: {} {:?}", attr.name(), attr.value()),
504 }
505 }
506
507 if let Some(program) = dwarf_unit.line_program.clone() {
512 let mut rows = program.rows();
513 let mut seq_addr = None;
514 while let Some((_, row)) = rows.next_row()? {
515 let addr = row.address();
516 if row.end_sequence() {
517 if let Some(seq_addr) = seq_addr {
518 if seq_addr != 0 {
521 unit.ranges.push(Range {
522 begin: seq_addr,
523 end: addr,
524 });
525 }
526 }
527 seq_addr = None;
528 } else if seq_addr.is_none() {
529 seq_addr = Some(addr);
530 }
531 }
532 } else if let Some(offset) = ranges {
533 let offset = dwarf.read.ranges_offset_from_raw(&dwarf_unit, offset);
534 let mut ranges = dwarf.read.ranges(&dwarf_unit, offset)?;
535 while let Some(range) = ranges.next()? {
536 if range.begin < range.end {
537 unit.ranges.push(Range {
538 begin: range.begin,
539 end: range.end,
540 });
541 }
542 }
543 } else if let Some(low_pc) = unit.low_pc {
544 if let Some(size) = size {
545 if high_pc.is_none() {
546 high_pc = low_pc.checked_add(size);
547 }
548 }
549 if let Some(high_pc) = high_pc {
550 unit.ranges.push(Range {
551 begin: low_pc,
552 end: high_pc,
553 });
554 }
555 }
556 unit.ranges.sort();
557 unit.low_pc = unit.ranges.list().first().map(|range| range.begin);
559
560 let namespace = None;
561 parse_namespace_children(
562 &mut unit,
563 dwarf,
564 &dwarf_unit,
565 &mut subprograms,
566 &mut variables,
567 &namespace,
568 root.children(),
569 )?;
570
571 fixup_subprogram_specifications(
572 &mut unit,
573 dwarf,
574 &dwarf_unit,
575 &mut subprograms,
576 &mut variables,
577 )?;
578 fixup_variable_specifications(&mut unit, dwarf, &dwarf_unit, &mut variables)?;
579
580 dwarf.units.push(dwarf_unit);
581 Ok(unit)
582}
583
584#[inline(never)]
585fn fixup_subprogram_specifications<'input, Endian>(
586 unit: &mut Unit<'input>,
587 dwarf: &DwarfDebugInfo<'input, Endian>,
588 dwarf_unit: &DwarfUnit<'input, Endian>,
589 subprograms: &mut Vec<DwarfSubprogram<'input>>,
590 variables: &mut Vec<DwarfVariable<'input>>,
591) -> Result<()>
592where
593 Endian: gimli::Endianity,
594{
595 let mut functions = BTreeMap::new();
599 for function in unit.functions.drain(..) {
600 functions.insert(function.offset, function);
601 }
602
603 let mut defer = Vec::new();
604
605 while !subprograms.is_empty() {
606 let mut progress = false;
607
608 mem::swap(&mut defer, subprograms);
609 for mut subprogram in defer.drain(..) {
610 if inherit_subprogram(
611 &functions,
612 &mut subprogram.function,
613 subprogram.specification,
614 subprogram.abstract_origin,
615 ) {
616 let mut tree = dwarf_unit.entries_tree(Some(subprogram.offset))?;
617 parse_subprogram_children(
618 unit,
619 dwarf,
620 dwarf_unit,
621 subprograms,
622 variables,
623 &mut subprogram.function,
624 tree.root()?.children(),
625 )?;
626 let offset = subprogram.offset.to_unit_section_offset(dwarf_unit);
627 functions.insert(offset.into(), subprogram.function);
628 for function in unit.functions.drain(..) {
629 functions.insert(function.offset, function);
630 }
631 progress = true;
632 } else {
633 subprograms.push(subprogram);
634 }
635 }
636
637 if !progress {
638 debug!(
639 "invalid specification for {} subprograms",
640 subprograms.len()
641 );
642 mem::swap(&mut defer, subprograms);
643 for mut subprogram in defer.drain(..) {
644 let mut tree = dwarf_unit.entries_tree(Some(subprogram.offset))?;
645 parse_subprogram_children(
646 unit,
647 dwarf,
648 dwarf_unit,
649 subprograms,
650 variables,
651 &mut subprogram.function,
652 tree.root()?.children(),
653 )?;
654 let offset = subprogram.offset.to_unit_section_offset(dwarf_unit);
655 functions.insert(offset.into(), subprogram.function);
656 for function in unit.functions.drain(..) {
657 functions.insert(function.offset, function);
658 }
659 }
660 }
662 }
663
664 unit.functions = functions.into_values().collect();
665 Ok(())
666}
667
668#[inline(never)]
669fn fixup_variable_specifications<'input, Endian>(
670 unit: &mut Unit<'input>,
671 _dwarf: &DwarfDebugInfo<'input, Endian>,
672 dwarf_unit: &DwarfUnit<'input, Endian>,
673 variables: &mut Vec<DwarfVariable<'input>>,
674) -> Result<()>
675where
676 Endian: gimli::Endianity,
677{
678 let mut variable_map = BTreeMap::new();
680 for variable in unit.variables.drain(..) {
681 variable_map.insert(variable.offset, variable);
682 }
683
684 loop {
685 let mut progress = false;
686 let mut defer = Vec::new();
687
688 for mut variable in variables.drain(..) {
689 match variable.specification.and_then(|v| variable_map.get(&v)) {
690 Some(specification) => {
691 let variable = &mut variable.variable;
692 variable.namespace = specification.namespace.clone();
693 if variable.name.is_none() {
694 variable.name = specification.name;
695 }
696 if variable.linkage_name.is_none() {
697 variable.linkage_name = specification.linkage_name;
698 }
699 if variable.ty.is_none() {
700 variable.ty = specification.ty;
701 }
702 }
703 None => {
704 defer.push(variable);
705 continue;
706 }
707 }
708 let offset = variable.offset.to_unit_section_offset(dwarf_unit);
709 variable_map.insert(offset.into(), variable.variable);
710 progress = true;
711 }
712
713 if defer.is_empty() {
714 break;
715 }
716 if !progress {
717 debug!("invalid specification for {} variables", defer.len());
718 for variable in variables.drain(..) {
719 let offset = variable.offset.to_unit_section_offset(dwarf_unit);
720 variable_map.insert(offset.into(), variable.variable);
721 }
722 break;
723 }
724 *variables = defer;
725 }
726
727 unit.variables = variable_map.into_values().collect();
728 Ok(())
729}
730
731fn parse_namespace_children<'input, Endian>(
732 unit: &mut Unit<'input>,
733 dwarf: &DwarfDebugInfo<'input, Endian>,
734 dwarf_unit: &DwarfUnit<'input, Endian>,
735 subprograms: &mut Vec<DwarfSubprogram<'input>>,
736 variables: &mut Vec<DwarfVariable<'input>>,
737 namespace: &Option<Arc<Namespace<'input>>>,
738 mut iter: gimli::EntriesTreeIter<Reader<'input, Endian>>,
739) -> Result<()>
740where
741 Endian: gimli::Endianity,
742{
743 while let Some(child) = iter.next()? {
744 match child.entry().tag() {
745 gimli::DW_TAG_namespace => {
746 parse_namespace(
747 unit,
748 dwarf,
749 dwarf_unit,
750 subprograms,
751 variables,
752 namespace,
753 child,
754 )?;
755 }
756 gimli::DW_TAG_subprogram => {
757 parse_subprogram(
758 unit,
759 dwarf,
760 dwarf_unit,
761 subprograms,
762 variables,
763 namespace,
764 child,
765 )?;
766 }
767 gimli::DW_TAG_variable => {
768 let variable = parse_variable(unit, dwarf, dwarf_unit, namespace.clone(), child)?;
769 if variable.specification.is_some() {
770 variables.push(variable);
772 } else {
773 unit.variables.push(variable.variable);
774 }
775 }
776 gimli::DW_TAG_dwarf_procedure
777 | gimli::DW_TAG_imported_declaration
778 | gimli::DW_TAG_imported_module => {}
779 tag => {
780 if !parse_type(
781 unit,
782 dwarf,
783 dwarf_unit,
784 subprograms,
785 variables,
786 namespace,
787 child,
788 )? {
789 debug!("unknown namespace child tag: {}", tag);
790 }
791 }
792 }
793 }
794 Ok(())
795}
796
797fn parse_namespace<'input, Endian>(
798 unit: &mut Unit<'input>,
799 dwarf: &DwarfDebugInfo<'input, Endian>,
800 dwarf_unit: &DwarfUnit<'input, Endian>,
801 subprograms: &mut Vec<DwarfSubprogram<'input>>,
802 variables: &mut Vec<DwarfVariable<'input>>,
803 namespace: &Option<Arc<Namespace<'input>>>,
804 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
805) -> Result<()>
806where
807 Endian: gimli::Endianity,
808{
809 let mut name = None;
810
811 let entry = node.entry();
812 let mut attrs = entry.attrs();
813 while let Some(attr) = attrs.next()? {
814 match attr.name() {
815 gimli::DW_AT_name => {
816 name = dwarf.string(dwarf_unit, attr.value());
817 }
818 gimli::DW_AT_decl_file | gimli::DW_AT_decl_line | gimli::DW_AT_decl_column => {}
819 _ => debug!(
820 "unknown namespace attribute: {} {:?}",
821 attr.name(),
822 attr.value()
823 ),
824 }
825 }
826
827 let namespace = Some(Namespace::new(namespace, name, NamespaceKind::Namespace));
828 parse_namespace_children(
829 unit,
830 dwarf,
831 dwarf_unit,
832 subprograms,
833 variables,
834 &namespace,
835 node.children(),
836 )
837}
838
839fn parse_type<'input, Endian>(
866 unit: &mut Unit<'input>,
867 dwarf: &DwarfDebugInfo<'input, Endian>,
868 dwarf_unit: &DwarfUnit<'input, Endian>,
869 subprograms: &mut Vec<DwarfSubprogram<'input>>,
870 variables: &mut Vec<DwarfVariable<'input>>,
871 namespace: &Option<Arc<Namespace<'input>>>,
872 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
873) -> Result<bool>
874where
875 Endian: gimli::Endianity,
876{
877 let tag = node.entry().tag();
878 let mut ty = Type::default();
879 let offset = node.entry().offset();
880 let offset = offset.to_unit_section_offset(dwarf_unit);
881 ty.offset = offset.into();
882 ty.kind = match tag {
883 gimli::DW_TAG_base_type => TypeKind::Base(parse_base_type(dwarf, dwarf_unit, node)?),
884 gimli::DW_TAG_typedef => TypeKind::Def(parse_typedef(dwarf, dwarf_unit, namespace, node)?),
885 gimli::DW_TAG_class_type | gimli::DW_TAG_structure_type => {
887 TypeKind::Struct(parse_structure_type(
888 unit,
889 dwarf,
890 dwarf_unit,
891 subprograms,
892 variables,
893 namespace,
894 node,
895 )?)
896 }
897 gimli::DW_TAG_union_type => TypeKind::Union(parse_union_type(
898 unit,
899 dwarf,
900 dwarf_unit,
901 subprograms,
902 variables,
903 namespace,
904 node,
905 )?),
906 gimli::DW_TAG_enumeration_type => TypeKind::Enumeration(parse_enumeration_type(
907 ty.offset,
908 unit,
909 dwarf,
910 dwarf_unit,
911 subprograms,
912 variables,
913 namespace,
914 node,
915 )?),
916 gimli::DW_TAG_unspecified_type => {
917 TypeKind::Unspecified(parse_unspecified_type(dwarf, dwarf_unit, namespace, node)?)
918 }
919 _ => return parse_unnamed_type(dwarf, dwarf_unit, node).map(|x| x.is_some()),
921 };
922 unit.types.push(ty);
923 Ok(true)
924}
925
926fn parse_unnamed_type<'input, Endian>(
927 dwarf: &DwarfDebugInfo<'input, Endian>,
928 dwarf_unit: &DwarfUnit<'input, Endian>,
929 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
930) -> Result<Option<Type<'input>>>
931where
932 Endian: gimli::Endianity,
933{
934 let tag = node.entry().tag();
935 let mut ty = Type::default();
936 let offset = node.entry().offset();
937 let offset = offset.to_unit_section_offset(dwarf_unit);
938 ty.offset = offset.into();
939 ty.kind = match tag {
940 gimli::DW_TAG_array_type => TypeKind::Array(parse_array_type(dwarf, dwarf_unit, node)?),
941 gimli::DW_TAG_subrange_type => {
942 TypeKind::Subrange(parse_subrange_type(dwarf, dwarf_unit, node)?)
943 }
944 gimli::DW_TAG_subroutine_type => {
945 TypeKind::Function(parse_subroutine_type(dwarf, dwarf_unit, node)?)
946 }
947 gimli::DW_TAG_ptr_to_member_type => {
948 TypeKind::PointerToMember(parse_pointer_to_member_type(dwarf, dwarf_unit, node)?)
949 }
950 gimli::DW_TAG_pointer_type => TypeKind::Modifier(parse_type_modifier(
951 dwarf,
952 dwarf_unit,
953 node,
954 TypeModifierKind::Pointer,
955 )?),
956 gimli::DW_TAG_reference_type => TypeKind::Modifier(parse_type_modifier(
957 dwarf,
958 dwarf_unit,
959 node,
960 TypeModifierKind::Reference,
961 )?),
962 gimli::DW_TAG_const_type => TypeKind::Modifier(parse_type_modifier(
963 dwarf,
964 dwarf_unit,
965 node,
966 TypeModifierKind::Const,
967 )?),
968 gimli::DW_TAG_packed_type => TypeKind::Modifier(parse_type_modifier(
969 dwarf,
970 dwarf_unit,
971 node,
972 TypeModifierKind::Packed,
973 )?),
974 gimli::DW_TAG_volatile_type => TypeKind::Modifier(parse_type_modifier(
975 dwarf,
976 dwarf_unit,
977 node,
978 TypeModifierKind::Volatile,
979 )?),
980 gimli::DW_TAG_restrict_type => TypeKind::Modifier(parse_type_modifier(
981 dwarf,
982 dwarf_unit,
983 node,
984 TypeModifierKind::Restrict,
985 )?),
986 gimli::DW_TAG_shared_type => TypeKind::Modifier(parse_type_modifier(
987 dwarf,
988 dwarf_unit,
989 node,
990 TypeModifierKind::Shared,
991 )?),
992 gimli::DW_TAG_rvalue_reference_type => TypeKind::Modifier(parse_type_modifier(
993 dwarf,
994 dwarf_unit,
995 node,
996 TypeModifierKind::RvalueReference,
997 )?),
998 gimli::DW_TAG_atomic_type => TypeKind::Modifier(parse_type_modifier(
999 dwarf,
1000 dwarf_unit,
1001 node,
1002 TypeModifierKind::Atomic,
1003 )?),
1004 _ => return Ok(None),
1005 };
1006 Ok(Some(ty))
1007}
1008
1009fn parse_type_modifier<'input, Endian>(
1010 dwarf: &DwarfDebugInfo<'input, Endian>,
1011 dwarf_unit: &DwarfUnit<'input, Endian>,
1012 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
1013 kind: TypeModifierKind,
1014) -> Result<TypeModifier<'input>>
1015where
1016 Endian: gimli::Endianity,
1017{
1018 let mut modifier = TypeModifier {
1019 kind,
1020 ty: TypeOffset::none(),
1021 name: None,
1022 byte_size: Size::none(),
1023 address_size: Some(u64::from(dwarf_unit.header.address_size())),
1024 };
1025
1026 let mut attrs = node.entry().attrs();
1027 while let Some(attr) = attrs.next()? {
1028 match attr.name() {
1029 gimli::DW_AT_name => {
1030 modifier.name = dwarf.string(dwarf_unit, attr.value());
1031 }
1032 gimli::DW_AT_type => {
1033 if let Some(offset) = parse_type_offset(dwarf_unit, &attr) {
1034 modifier.ty = offset;
1035 }
1036 }
1037 gimli::DW_AT_byte_size => {
1038 if let Some(byte_size) = attr.udata_value() {
1039 modifier.byte_size = Size::new(byte_size);
1040 }
1041 }
1042 gimli::DW_AT_artificial => {}
1043 _ => debug!(
1044 "unknown type modifier attribute: {} {:?}",
1045 attr.name(),
1046 attr.value()
1047 ),
1048 }
1049 }
1050
1051 let mut iter = node.children();
1052 while let Some(child) = iter.next()? {
1053 match child.entry().tag() {
1054 tag => {
1055 debug!("unknown type modifier child tag: {}", tag);
1056 }
1057 }
1058 }
1059 Ok(modifier)
1060}
1061
1062fn parse_base_type<'input, Endian>(
1063 dwarf: &DwarfDebugInfo<'input, Endian>,
1064 dwarf_unit: &DwarfUnit<'input, Endian>,
1065 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
1066) -> Result<BaseType<'input>>
1067where
1068 Endian: gimli::Endianity,
1069{
1070 let mut ty = BaseType::default();
1071
1072 let mut attrs = node.entry().attrs();
1073 while let Some(attr) = attrs.next()? {
1074 match attr.name() {
1075 gimli::DW_AT_name => {
1076 ty.name = dwarf.string(dwarf_unit, attr.value());
1077 }
1078 gimli::DW_AT_byte_size => {
1079 if let Some(byte_size) = attr.udata_value() {
1080 ty.byte_size = Size::new(byte_size);
1081 }
1082 }
1083 gimli::DW_AT_encoding => {
1084 if let gimli::AttributeValue::Encoding(val) = attr.value() {
1085 ty.encoding = match val {
1086 gimli::DW_ATE_boolean => BaseTypeEncoding::Boolean,
1087 gimli::DW_ATE_address => BaseTypeEncoding::Address,
1088 gimli::DW_ATE_signed => BaseTypeEncoding::Signed,
1089 gimli::DW_ATE_signed_char => BaseTypeEncoding::SignedChar,
1090 gimli::DW_ATE_unsigned => BaseTypeEncoding::Unsigned,
1091 gimli::DW_ATE_unsigned_char => BaseTypeEncoding::UnsignedChar,
1092 gimli::DW_ATE_float => BaseTypeEncoding::Float,
1093 _ => {
1094 debug!("unknown base type encoding: {} {:?}", attr.name(), val);
1095 BaseTypeEncoding::Other
1096 }
1097 }
1098 }
1099 }
1100 gimli::DW_AT_endianity => {
1101 if let gimli::AttributeValue::Endianity(val) = attr.value() {
1102 ty.endianity = match val {
1103 gimli::DW_END_default => Endianity::Default,
1104 gimli::DW_END_big => Endianity::Big,
1105 gimli::DW_END_little => Endianity::Little,
1106 _ => {
1107 debug!("unknown base type endianity: {} {:?}", attr.name(), val);
1108 Endianity::Default
1109 }
1110 }
1111 }
1112 }
1113 gimli::DW_AT_artificial | gimli::DW_AT_decimal_scale => {}
1114 _ => debug!(
1115 "unknown base type attribute: {} {:?}",
1116 attr.name(),
1117 attr.value()
1118 ),
1119 }
1120 }
1121
1122 let mut iter = node.children();
1123 while let Some(child) = iter.next()? {
1124 match child.entry().tag() {
1125 tag => {
1126 debug!("unknown base type child tag: {}", tag);
1127 }
1128 }
1129 }
1130 Ok(ty)
1131}
1132
1133fn parse_typedef<'input, Endian>(
1134 dwarf: &DwarfDebugInfo<'input, Endian>,
1135 dwarf_unit: &DwarfUnit<'input, Endian>,
1136 namespace: &Option<Arc<Namespace<'input>>>,
1137 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
1138) -> Result<TypeDef<'input>>
1139where
1140 Endian: gimli::Endianity,
1141{
1142 let mut typedef = TypeDef {
1143 namespace: namespace.clone(),
1144 ..Default::default()
1145 };
1146
1147 let mut attrs = node.entry().attrs();
1148 while let Some(attr) = attrs.next()? {
1149 match attr.name() {
1150 gimli::DW_AT_name => {
1151 typedef.name = dwarf.string(dwarf_unit, attr.value());
1152 }
1153 gimli::DW_AT_type => {
1154 if let Some(offset) = parse_type_offset(dwarf_unit, &attr) {
1155 typedef.ty = offset;
1156 }
1157 }
1158 gimli::DW_AT_decl_file => {
1159 parse_source_file(dwarf, dwarf_unit, &attr, &mut typedef.source)
1160 }
1161 gimli::DW_AT_decl_line => parse_source_line(&attr, &mut typedef.source),
1162 gimli::DW_AT_decl_column => parse_source_column(&attr, &mut typedef.source),
1163 gimli::DW_AT_alignment => {}
1164 _ => debug!(
1165 "unknown typedef attribute: {} {:?}",
1166 attr.name(),
1167 attr.value()
1168 ),
1169 }
1170 }
1171
1172 let mut iter = node.children();
1173 while let Some(child) = iter.next()? {
1174 match child.entry().tag() {
1175 tag => {
1176 debug!("unknown typedef child tag: {}", tag);
1177 }
1178 }
1179 }
1180 Ok(typedef)
1181}
1182
1183fn parse_structure_type<'input, Endian>(
1184 unit: &mut Unit<'input>,
1185 dwarf: &DwarfDebugInfo<'input, Endian>,
1186 dwarf_unit: &DwarfUnit<'input, Endian>,
1187 subprograms: &mut Vec<DwarfSubprogram<'input>>,
1188 variables: &mut Vec<DwarfVariable<'input>>,
1189 namespace: &Option<Arc<Namespace<'input>>>,
1190 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
1191) -> Result<StructType<'input>>
1192where
1193 Endian: gimli::Endianity,
1194{
1195 let mut ty = StructType {
1196 namespace: namespace.clone(),
1197 ..Default::default()
1198 };
1199
1200 let mut attrs = node.entry().attrs();
1201 while let Some(attr) = attrs.next()? {
1202 match attr.name() {
1203 gimli::DW_AT_name => {
1204 ty.name = dwarf.string(dwarf_unit, attr.value());
1205 }
1206 gimli::DW_AT_byte_size => {
1207 if let Some(byte_size) = attr.udata_value() {
1208 ty.byte_size = Size::new(byte_size);
1209 }
1210 }
1211 gimli::DW_AT_declaration => {
1212 if let gimli::AttributeValue::Flag(flag) = attr.value() {
1213 ty.declaration = flag;
1214 }
1215 }
1216 gimli::DW_AT_decl_file => parse_source_file(dwarf, dwarf_unit, &attr, &mut ty.source),
1217 gimli::DW_AT_decl_line => parse_source_line(&attr, &mut ty.source),
1218 gimli::DW_AT_decl_column => parse_source_column(&attr, &mut ty.source),
1219 gimli::DW_AT_containing_type | gimli::DW_AT_alignment | gimli::DW_AT_sibling => {}
1220 _ => debug!(
1221 "unknown struct attribute: {} {:?}",
1222 attr.name(),
1223 attr.value()
1224 ),
1225 }
1226 }
1227
1228 let namespace = Some(Namespace::new(&ty.namespace, ty.name, NamespaceKind::Type));
1229 let mut iter = node.children();
1230 while let Some(child) = iter.next()? {
1231 match child.entry().tag() {
1232 gimli::DW_TAG_subprogram => {
1233 parse_subprogram(
1234 unit,
1235 dwarf,
1236 dwarf_unit,
1237 subprograms,
1238 variables,
1239 &namespace,
1240 child,
1241 )?;
1242 }
1243 gimli::DW_TAG_member => {
1244 parse_member(&mut ty.members, unit, dwarf, dwarf_unit, &namespace, child)?;
1245 }
1246 gimli::DW_TAG_inheritance => {
1247 parse_inheritance(&mut ty.inherits, dwarf_unit, child)?;
1248 }
1249 gimli::DW_TAG_variant_part => {
1250 parse_variant_part(
1251 &mut ty.members,
1252 &mut ty.variant_parts,
1253 unit,
1254 dwarf,
1255 dwarf_unit,
1256 &namespace,
1257 child,
1258 )?;
1259 }
1260 gimli::DW_TAG_template_type_parameter
1261 | gimli::DW_TAG_template_value_parameter
1262 | gimli::DW_TAG_GNU_template_parameter_pack => {}
1263 tag => {
1264 if !parse_type(
1265 unit,
1266 dwarf,
1267 dwarf_unit,
1268 subprograms,
1269 variables,
1270 &namespace,
1271 child,
1272 )? {
1273 debug!("unknown struct child tag: {}", tag);
1274 }
1275 }
1276 }
1277 }
1278 Ok(ty)
1279}
1280
1281fn parse_union_type<'input, Endian>(
1282 unit: &mut Unit<'input>,
1283 dwarf: &DwarfDebugInfo<'input, Endian>,
1284 dwarf_unit: &DwarfUnit<'input, Endian>,
1285 subprograms: &mut Vec<DwarfSubprogram<'input>>,
1286 variables: &mut Vec<DwarfVariable<'input>>,
1287 namespace: &Option<Arc<Namespace<'input>>>,
1288 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
1289) -> Result<UnionType<'input>>
1290where
1291 Endian: gimli::Endianity,
1292{
1293 let mut ty = UnionType {
1294 namespace: namespace.clone(),
1295 ..Default::default()
1296 };
1297
1298 let mut attrs = node.entry().attrs();
1299 while let Some(attr) = attrs.next()? {
1300 match attr.name() {
1301 gimli::DW_AT_name => {
1302 ty.name = dwarf.string(dwarf_unit, attr.value());
1303 }
1304 gimli::DW_AT_byte_size => {
1305 if let Some(byte_size) = attr.udata_value() {
1306 ty.byte_size = Size::new(byte_size);
1307 }
1308 }
1309 gimli::DW_AT_declaration => {
1310 if let gimli::AttributeValue::Flag(flag) = attr.value() {
1311 ty.declaration = flag;
1312 }
1313 }
1314 gimli::DW_AT_decl_file => parse_source_file(dwarf, dwarf_unit, &attr, &mut ty.source),
1315 gimli::DW_AT_decl_line => parse_source_line(&attr, &mut ty.source),
1316 gimli::DW_AT_decl_column => parse_source_column(&attr, &mut ty.source),
1317 gimli::DW_AT_alignment | gimli::DW_AT_sibling => {}
1318 _ => debug!(
1319 "unknown union attribute: {} {:?}",
1320 attr.name(),
1321 attr.value()
1322 ),
1323 }
1324 }
1325
1326 let namespace = Some(Namespace::new(&ty.namespace, ty.name, NamespaceKind::Type));
1327 let mut iter = node.children();
1328 while let Some(child) = iter.next()? {
1329 match child.entry().tag() {
1330 gimli::DW_TAG_subprogram => {
1331 parse_subprogram(
1332 unit,
1333 dwarf,
1334 dwarf_unit,
1335 subprograms,
1336 variables,
1337 &namespace,
1338 child,
1339 )?;
1340 }
1341 gimli::DW_TAG_member => {
1342 parse_member(&mut ty.members, unit, dwarf, dwarf_unit, &namespace, child)?;
1343 }
1344 gimli::DW_TAG_template_type_parameter => {}
1345 tag => {
1346 if !parse_type(
1347 unit,
1348 dwarf,
1349 dwarf_unit,
1350 subprograms,
1351 variables,
1352 &namespace,
1353 child,
1354 )? {
1355 debug!("unknown union child tag: {}", tag);
1356 }
1357 }
1358 }
1359 }
1360 Ok(ty)
1361}
1362
1363fn parse_variant_part<'input, Endian>(
1364 members: &mut Vec<Member<'input>>,
1365 variant_parts: &mut Vec<VariantPart<'input>>,
1366 unit: &mut Unit<'input>,
1367 dwarf: &DwarfDebugInfo<'input, Endian>,
1368 dwarf_unit: &DwarfUnit<'input, Endian>,
1369 namespace: &Option<Arc<Namespace<'input>>>,
1370 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
1371) -> Result<()>
1372where
1373 Endian: gimli::Endianity,
1374{
1375 let mut variant_part = VariantPart::default();
1376
1377 let mut attrs = node.entry().attrs();
1378 while let Some(attr) = attrs.next()? {
1379 match attr.name() {
1380 gimli::DW_AT_discr => {
1381 if let Some(offset) = parse_member_offset(dwarf_unit, &attr) {
1382 variant_part.discr = offset;
1383 }
1384 }
1385 gimli::DW_AT_sibling => {}
1386 _ => debug!(
1387 "unknown variant_part attribute: {} {:?}",
1388 attr.name(),
1389 attr.value()
1390 ),
1391 }
1392 }
1393
1394 let mut iter = node.children();
1395 while let Some(child) = iter.next()? {
1396 match child.entry().tag() {
1397 gimli::DW_TAG_member => {
1398 parse_member(members, unit, dwarf, dwarf_unit, namespace, child)?;
1401 }
1402 gimli::DW_TAG_variant => {
1403 parse_variant(
1404 &mut variant_part.variants,
1405 unit,
1406 dwarf,
1407 dwarf_unit,
1408 namespace,
1409 child,
1410 )?;
1411 }
1412 tag => {
1413 debug!("unknown variant_part child tag: {}", tag);
1414 }
1415 }
1416 }
1417
1418 variant_parts.push(variant_part);
1419 Ok(())
1420}
1421
1422fn parse_variant<'input, Endian>(
1423 variants: &mut Vec<Variant<'input>>,
1424 unit: &mut Unit<'input>,
1425 dwarf: &DwarfDebugInfo<'input, Endian>,
1426 dwarf_unit: &DwarfUnit<'input, Endian>,
1427 namespace: &Option<Arc<Namespace<'input>>>,
1428 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
1429) -> Result<()>
1430where
1431 Endian: gimli::Endianity,
1432{
1433 let mut variant = Variant::default();
1434
1435 let mut attrs = node.entry().attrs();
1436 while let Some(attr) = attrs.next()? {
1437 match attr.name() {
1438 gimli::DW_AT_discr_value => {
1439 if let Some(value) = attr.udata_value() {
1440 variant.discr_value = Some(value);
1441 }
1442 }
1443 gimli::DW_AT_sibling => {}
1444 _ => debug!(
1445 "unknown variant attribute: {} {:?}",
1446 attr.name(),
1447 attr.value()
1448 ),
1449 }
1450 }
1451
1452 let mut iter = node.children();
1453 while let Some(child) = iter.next()? {
1454 match child.entry().tag() {
1455 gimli::DW_TAG_member => {
1456 parse_member(
1457 &mut variant.members,
1458 unit,
1459 dwarf,
1460 dwarf_unit,
1461 namespace,
1462 child,
1463 )?;
1464 }
1465 gimli::DW_TAG_subrange_type => {
1470 parse_subrange_type(dwarf, dwarf_unit, child)?;
1471 }
1472 tag => {
1473 debug!("unknown variant child tag: {}", tag);
1474 }
1475 }
1476 }
1477
1478 if unit.language == Some(gimli::DW_LANG_Rust) && variant.members.len() == 1 {
1483 if let Some(offset) = variant.members[0].ty.get() {
1484 let offset = gimli::UnitSectionOffset::DebugInfoOffset(gimli::DebugInfoOffset(offset));
1485 if let Some(offset) = offset.to_unit_offset(dwarf_unit) {
1486 let mut tree = dwarf_unit.entries_tree(Some(offset))?;
1487 let node = tree.root()?;
1488 if node.entry().tag() == gimli::DW_TAG_structure_type {
1489 if let Some(attr) = node.entry().attr_value(gimli::DW_AT_name)? {
1491 variant.name = dwarf.string(dwarf_unit, attr);
1492 }
1493
1494 variant.members.clear();
1496 let mut iter = node.children();
1497 while let Some(child) = iter.next()? {
1498 if child.entry().tag() == gimli::DW_TAG_member {
1499 parse_member(
1500 &mut variant.members,
1501 unit,
1502 dwarf,
1503 dwarf_unit,
1504 namespace,
1505 child,
1506 )?;
1507 }
1508 }
1509 }
1510 }
1511 }
1512 }
1513
1514 variants.push(variant);
1515 Ok(())
1516}
1517
1518fn parse_member<'input, Endian>(
1519 members: &mut Vec<Member<'input>>,
1520 unit: &mut Unit<'input>,
1521 dwarf: &DwarfDebugInfo<'input, Endian>,
1522 dwarf_unit: &DwarfUnit<'input, Endian>,
1523 namespace: &Option<Arc<Namespace<'input>>>,
1524 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
1525) -> Result<()>
1526where
1527 Endian: gimli::Endianity,
1528{
1529 let mut member = Member::default();
1530 let offset = node.entry().offset();
1531 let offset = offset.to_unit_section_offset(dwarf_unit);
1532 member.offset = offset.into();
1533 let mut bit_offset = None;
1534 let mut byte_size = None;
1535 let mut declaration = false;
1536
1537 let mut attrs = node.entry().attrs();
1538 while let Some(attr) = attrs.next()? {
1539 match attr.name() {
1540 gimli::DW_AT_name => {
1541 member.name = dwarf.string(dwarf_unit, attr.value());
1542 }
1543 gimli::DW_AT_type => {
1544 if let Some(offset) = parse_type_offset(dwarf_unit, &attr) {
1545 member.ty = offset;
1546 }
1547 }
1548 gimli::DW_AT_data_member_location => {
1549 if let Some(offset) = parse_data_member_location(dwarf_unit, &attr) {
1550 member.bit_offset = offset;
1551 }
1552 }
1553 gimli::DW_AT_data_bit_offset => {
1554 if let Some(bit_offset) = attr.udata_value() {
1555 member.bit_offset = bit_offset;
1556 }
1557 }
1558 gimli::DW_AT_bit_offset => {
1559 bit_offset = attr.udata_value();
1560 }
1561 gimli::DW_AT_byte_size => {
1562 byte_size = attr.udata_value();
1563 }
1564 gimli::DW_AT_bit_size => {
1565 if let Some(bit_size) = attr.udata_value() {
1566 member.bit_size = Size::new(bit_size);
1567 }
1568 }
1569 gimli::DW_AT_declaration => {
1570 declaration = true;
1571 }
1572 gimli::DW_AT_decl_file
1573 | gimli::DW_AT_decl_line
1574 | gimli::DW_AT_decl_column
1575 | gimli::DW_AT_external
1576 | gimli::DW_AT_accessibility
1577 | gimli::DW_AT_artificial
1578 | gimli::DW_AT_const_value
1579 | gimli::DW_AT_alignment
1580 | gimli::DW_AT_sibling => {}
1581 _ => {
1582 debug!(
1583 "unknown member attribute: {} {:?}",
1584 attr.name(),
1585 attr.value()
1586 );
1587 }
1588 }
1589 }
1590
1591 if declaration {
1592 let variable = parse_variable(unit, dwarf, dwarf_unit, namespace.clone(), node)?;
1596 if variable.specification.is_some() {
1597 debug!(
1598 "specification on variable declaration at offset 0x{:x}",
1599 variable.offset.0
1600 );
1601 }
1602 unit.variables.push(variable.variable);
1603 return Ok(());
1604 }
1605
1606 if let (Some(bit_offset), Some(bit_size)) = (bit_offset, member.bit_size.get()) {
1607 if dwarf.endian.is_big_endian() {
1614 member.bit_offset = member.bit_offset.wrapping_add(bit_offset);
1617 } else {
1618 if let Some(byte_size) = byte_size {
1620 member.bit_offset = member.bit_offset.wrapping_add(byte_size * 8);
1622 member.bit_offset = member
1624 .bit_offset
1625 .wrapping_sub(bit_offset.wrapping_add(bit_size));
1626 } else {
1627 debug!("missing byte_size for bit field offset");
1631 }
1632 }
1633 } else if byte_size.is_some() {
1634 debug!("ignored member byte_size");
1636 }
1637
1638 let mut iter = node.children();
1639 while let Some(child) = iter.next()? {
1640 match child.entry().tag() {
1641 tag => {
1642 debug!("unknown member child tag: {}", tag);
1643 }
1644 }
1645 }
1646 members.push(member);
1647 Ok(())
1648}
1649
1650fn parse_inheritance<'input, Endian>(
1651 inherits: &mut Vec<Inherit>,
1652 dwarf_unit: &DwarfUnit<'input, Endian>,
1653 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
1654) -> Result<()>
1655where
1656 Endian: gimli::Endianity,
1657{
1658 let mut inherit = Inherit::default();
1659
1660 let mut attrs = node.entry().attrs();
1661 while let Some(attr) = attrs.next()? {
1662 match attr.name() {
1663 gimli::DW_AT_type => {
1664 if let Some(offset) = parse_type_offset(dwarf_unit, &attr) {
1665 inherit.ty = offset;
1666 }
1667 }
1668 gimli::DW_AT_data_member_location => {
1669 if let Some(offset) = parse_data_member_location(dwarf_unit, &attr) {
1670 inherit.bit_offset = offset;
1671 }
1672 }
1673 gimli::DW_AT_accessibility | gimli::DW_AT_virtuality | gimli::DW_AT_sibling => {}
1674 _ => {
1675 debug!(
1676 "unknown inheritance attribute: {} {:?}",
1677 attr.name(),
1678 attr.value()
1679 );
1680 }
1681 }
1682 }
1683
1684 let mut iter = node.children();
1685 while let Some(child) = iter.next()? {
1686 match child.entry().tag() {
1687 tag => {
1688 debug!("unknown inheritance child tag: {}", tag);
1689 }
1690 }
1691 }
1692 inherits.push(inherit);
1693 Ok(())
1694}
1695
1696fn parse_data_member_location<Endian>(
1697 dwarf_unit: &DwarfUnit<Endian>,
1698 attr: &gimli::Attribute<Reader<Endian>>,
1699) -> Option<u64>
1700where
1701 Endian: gimli::Endianity,
1702{
1703 match attr.value() {
1704 gimli::AttributeValue::Udata(v) => return Some(v * 8),
1705 gimli::AttributeValue::Sdata(v) => {
1706 if v >= 0 {
1707 return Some((v as u64) * 8);
1708 } else {
1709 debug!("DW_AT_data_member_location is negative: {}", v)
1710 }
1711 }
1712 gimli::AttributeValue::Exprloc(expr) => {
1713 if let Some(offset) = evaluate_member_location(&dwarf_unit.header, expr) {
1714 return Some(offset);
1715 }
1716 }
1717 gimli::AttributeValue::LocationListsRef(offset) => {
1718 if dwarf_unit.header.version() == 3 {
1719 return Some(offset.0 as u64 * 8);
1723 } else {
1724 debug!("loclist for member: {:?}", attr.value());
1725 }
1726 }
1727 _ => {
1728 debug!("unknown DW_AT_data_member_location: {:?}", attr.value());
1729 }
1730 }
1731 None
1732}
1733
1734fn parse_enumeration_type<'input, Endian>(
1735 offset: TypeOffset,
1736 unit: &mut Unit<'input>,
1737 dwarf: &DwarfDebugInfo<'input, Endian>,
1738 dwarf_unit: &DwarfUnit<'input, Endian>,
1739 subprograms: &mut Vec<DwarfSubprogram<'input>>,
1740 variables: &mut Vec<DwarfVariable<'input>>,
1741 namespace: &Option<Arc<Namespace<'input>>>,
1742 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
1743) -> Result<EnumerationType<'input>>
1744where
1745 Endian: gimli::Endianity,
1746{
1747 let mut ty = EnumerationType {
1748 offset,
1749 namespace: namespace.clone(),
1750 ..Default::default()
1751 };
1752
1753 let mut attrs = node.entry().attrs();
1754 while let Some(attr) = attrs.next()? {
1755 match attr.name() {
1756 gimli::DW_AT_name => {
1757 ty.name = dwarf.string(dwarf_unit, attr.value());
1758 }
1759 gimli::DW_AT_byte_size => {
1760 if let Some(byte_size) = attr.udata_value() {
1761 ty.byte_size = Size::new(byte_size);
1762 }
1763 }
1764 gimli::DW_AT_declaration => {
1765 if let gimli::AttributeValue::Flag(flag) = attr.value() {
1766 ty.declaration = flag;
1767 }
1768 }
1769 gimli::DW_AT_decl_file => parse_source_file(dwarf, dwarf_unit, &attr, &mut ty.source),
1770 gimli::DW_AT_decl_line => parse_source_line(&attr, &mut ty.source),
1771 gimli::DW_AT_decl_column => parse_source_column(&attr, &mut ty.source),
1772 gimli::DW_AT_sibling
1773 | gimli::DW_AT_encoding
1774 | gimli::DW_AT_type
1775 | gimli::DW_AT_alignment
1776 | gimli::DW_AT_enum_class => {}
1777 _ => debug!(
1778 "unknown enumeration attribute: {} {:?}",
1779 attr.name(),
1780 attr.value()
1781 ),
1782 }
1783 }
1784
1785 let namespace = Some(Namespace::new(&ty.namespace, ty.name, NamespaceKind::Type));
1786 let mut iter = node.children();
1787 while let Some(child) = iter.next()? {
1788 match child.entry().tag() {
1789 gimli::DW_TAG_subprogram => {
1790 parse_subprogram(
1791 unit,
1792 dwarf,
1793 dwarf_unit,
1794 subprograms,
1795 variables,
1796 &namespace,
1797 child,
1798 )?;
1799 }
1800 gimli::DW_TAG_enumerator => {}
1801 tag => {
1802 debug!("unknown enumeration child tag: {}", tag);
1803 }
1804 }
1805 }
1806 Ok(ty)
1807}
1808
1809fn parse_enumerators<'input, Endian>(
1810 dwarf: &DwarfDebugInfo<'input, Endian>,
1811 dwarf_unit: &DwarfUnit<'input, Endian>,
1812 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
1813) -> Result<Vec<Enumerator<'input>>>
1814where
1815 Endian: gimli::Endianity,
1816{
1817 let mut enumerators = Vec::new();
1818 let mut iter = node.children();
1819 while let Some(child) = iter.next()? {
1820 match child.entry().tag() {
1821 gimli::DW_TAG_enumerator => {
1822 enumerators.push(parse_enumerator(dwarf, dwarf_unit, child)?);
1823 }
1824 _ => {}
1825 }
1826 }
1827 Ok(enumerators)
1828}
1829
1830fn parse_enumerator<'input, Endian>(
1831 dwarf: &DwarfDebugInfo<'input, Endian>,
1832 dwarf_unit: &DwarfUnit<'input, Endian>,
1833 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
1834) -> Result<Enumerator<'input>>
1835where
1836 Endian: gimli::Endianity,
1837{
1838 let mut enumerator = Enumerator::default();
1839
1840 let mut attrs = node.entry().attrs();
1841 while let Some(attr) = attrs.next()? {
1842 match attr.name() {
1843 gimli::DW_AT_name => {
1844 enumerator.name = dwarf.string(dwarf_unit, attr.value());
1845 }
1846 gimli::DW_AT_const_value => {
1847 if let Some(value) = attr.sdata_value() {
1848 enumerator.value = Some(value);
1849 } else {
1850 debug!("unknown enumerator const_value: {:?}", attr.value());
1851 }
1852 }
1853 _ => debug!(
1854 "unknown enumerator attribute: {} {:?}",
1855 attr.name(),
1856 attr.value()
1857 ),
1858 }
1859 }
1860
1861 let mut iter = node.children();
1862 while let Some(child) = iter.next()? {
1863 match child.entry().tag() {
1864 tag => {
1865 debug!("unknown enumerator child tag: {}", tag);
1866 }
1867 }
1868 }
1869 Ok(enumerator)
1870}
1871
1872fn parse_array_type<'input, Endian>(
1873 _dwarf: &DwarfDebugInfo<'input, Endian>,
1874 dwarf_unit: &DwarfUnit<'input, Endian>,
1875 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
1876) -> Result<ArrayType<'input>>
1877where
1878 Endian: gimli::Endianity,
1879{
1880 let mut array = ArrayType::default();
1881
1882 let mut attrs = node.entry().attrs();
1883 while let Some(attr) = attrs.next()? {
1884 match attr.name() {
1885 gimli::DW_AT_type => {
1886 if let Some(offset) = parse_type_offset(dwarf_unit, &attr) {
1887 array.ty = offset;
1888 }
1889 }
1890 gimli::DW_AT_byte_size => {
1891 if let Some(byte_size) = attr.udata_value() {
1892 array.byte_size = Size::new(byte_size);
1893 }
1894 }
1895 gimli::DW_AT_name | gimli::DW_AT_GNU_vector | gimli::DW_AT_sibling => {}
1896 _ => debug!(
1897 "unknown array attribute: {} {:?}",
1898 attr.name(),
1899 attr.value()
1900 ),
1901 }
1902 }
1903
1904 let mut counts = Vec::new();
1905 let mut iter = node.children();
1906 while let Some(child) = iter.next()? {
1907 match child.entry().tag() {
1908 gimli::DW_TAG_subrange_type => {
1909 let mut count = None;
1910 let mut lower = None;
1911 let mut upper = None;
1912 let mut attrs = child.entry().attrs();
1913 while let Some(attr) = attrs.next()? {
1914 match attr.name() {
1915 gimli::DW_AT_count => {
1916 count = attr.udata_value();
1917 }
1918 gimli::DW_AT_lower_bound => {
1919 lower = attr.udata_value();
1920 }
1921 gimli::DW_AT_upper_bound => {
1922 upper = attr.udata_value();
1923 }
1924 gimli::DW_AT_type => {}
1925 _ => debug!(
1926 "unknown array subrange attribute: {} {:?}",
1927 attr.name(),
1928 attr.value()
1929 ),
1930 }
1931 }
1932 if count.is_none() {
1933 if let Some(upper) = upper {
1934 let lower = lower.unwrap_or(0);
1936 count = u64::checked_sub(upper, lower)
1937 .and_then(|count| u64::checked_add(count, 1));
1938 if count.is_none() {
1939 debug!("overflow for array bound: {}", upper);
1940 }
1941 }
1942 }
1943 if let Some(count) = count {
1944 counts.push(Size::new(count));
1945 } else {
1946 counts.push(Size::none());
1948 }
1949 }
1950 tag => {
1951 debug!("unknown array child tag: {}", tag);
1952 }
1953 }
1954 }
1955 if counts.len() == 1 {
1956 array.count = counts[0];
1957 } else if !counts.is_empty() {
1958 array.counts = counts.into_boxed_slice();
1959 }
1960 Ok(array)
1961}
1962
1963fn parse_subrange_type<'input, Endian>(
1964 dwarf: &DwarfDebugInfo<'input, Endian>,
1965 dwarf_unit: &DwarfUnit<'input, Endian>,
1966 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
1967) -> Result<SubrangeType<'input>>
1968where
1969 Endian: gimli::Endianity,
1970{
1971 let mut subrange = SubrangeType::default();
1973 let mut count = None;
1974
1975 let mut attrs = node.entry().attrs();
1976 while let Some(attr) = attrs.next()? {
1977 match attr.name() {
1978 gimli::DW_AT_name => {
1979 subrange.name = dwarf.string(dwarf_unit, attr.value());
1980 }
1981 gimli::DW_AT_type => {
1982 if let Some(offset) = parse_type_offset(dwarf_unit, &attr) {
1983 subrange.ty = offset;
1984 }
1985 }
1986 gimli::DW_AT_lower_bound => {
1987 if let Some(lower) = attr.udata_value() {
1988 subrange.lower = Some(lower);
1989 }
1990 }
1991 gimli::DW_AT_upper_bound => {
1992 if let Some(upper) = attr.udata_value() {
1993 subrange.upper = Some(upper);
1994 }
1995 }
1996 gimli::DW_AT_count => {
1997 if let Some(v) = attr.udata_value() {
1998 count = Some(v);
1999 }
2000 }
2001 gimli::DW_AT_byte_size => {
2002 if let Some(byte_size) = attr.udata_value() {
2003 subrange.byte_size = Size::new(byte_size);
2004 }
2005 }
2006 gimli::DW_AT_artificial => {}
2007 _ => debug!(
2008 "unknown subrange attribute: {} {:?}",
2009 attr.name(),
2010 attr.value()
2011 ),
2012 }
2013 }
2014
2015 if let (Some(lower), Some(count)) = (subrange.lower, count) {
2016 subrange.upper = Some(lower + count);
2017 }
2018
2019 let mut iter = node.children();
2020 while let Some(child) = iter.next()? {
2021 match child.entry().tag() {
2022 tag => {
2023 debug!("unknown subrange child tag: {}", tag);
2024 }
2025 }
2026 }
2027 Ok(subrange)
2028}
2029
2030fn parse_subroutine_type<'input, Endian>(
2031 dwarf: &DwarfDebugInfo<'input, Endian>,
2032 dwarf_unit: &DwarfUnit<'input, Endian>,
2033 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
2034) -> Result<FunctionType<'input>>
2035where
2036 Endian: gimli::Endianity,
2037{
2038 let mut function = FunctionType {
2039 byte_size: Size::new(u64::from(dwarf_unit.header.address_size())),
2042 ..Default::default()
2043 };
2044
2045 let mut attrs = node.entry().attrs();
2046 while let Some(attr) = attrs.next()? {
2047 match attr.name() {
2048 gimli::DW_AT_type => {
2049 if let Some(offset) = parse_type_offset(dwarf_unit, &attr) {
2050 function.return_type = offset;
2051 }
2052 }
2053 gimli::DW_AT_name | gimli::DW_AT_prototyped | gimli::DW_AT_sibling => {}
2054 _ => debug!(
2055 "unknown subroutine attribute: {} {:?}",
2056 attr.name(),
2057 attr.value()
2058 ),
2059 }
2060 }
2061
2062 let mut iter = node.children();
2063 while let Some(child) = iter.next()? {
2064 match child.entry().tag() {
2065 gimli::DW_TAG_formal_parameter => {
2066 parse_parameter_type(&mut function.parameters, dwarf, dwarf_unit, child)?;
2067 }
2068 tag => {
2069 debug!("unknown subroutine child tag: {}", tag);
2070 }
2071 }
2072 }
2073 Ok(function)
2074}
2075
2076fn parse_unspecified_type<'input, Endian>(
2077 dwarf: &DwarfDebugInfo<'input, Endian>,
2078 dwarf_unit: &DwarfUnit<'input, Endian>,
2079 namespace: &Option<Arc<Namespace<'input>>>,
2080 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
2081) -> Result<UnspecifiedType<'input>>
2082where
2083 Endian: gimli::Endianity,
2084{
2085 let mut ty = UnspecifiedType {
2086 namespace: namespace.clone(),
2087 ..Default::default()
2088 };
2089
2090 let mut attrs = node.entry().attrs();
2091 while let Some(attr) = attrs.next()? {
2092 match attr.name() {
2093 gimli::DW_AT_name => {
2094 ty.name = dwarf.string(dwarf_unit, attr.value());
2095 }
2096 _ => debug!(
2097 "unknown unspecified type attribute: {} {:?}",
2098 attr.name(),
2099 attr.value()
2100 ),
2101 }
2102 }
2103
2104 let mut iter = node.children();
2105 while let Some(child) = iter.next()? {
2106 match child.entry().tag() {
2107 tag => {
2108 debug!("unknown unspecified type child tag: {}", tag);
2109 }
2110 }
2111 }
2112 Ok(ty)
2113}
2114
2115fn parse_pointer_to_member_type<'input, Endian>(
2116 _dwarf: &DwarfDebugInfo<'input, Endian>,
2117 dwarf_unit: &DwarfUnit<'input, Endian>,
2118 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
2119) -> Result<PointerToMemberType>
2120where
2121 Endian: gimli::Endianity,
2122{
2123 let mut ty = PointerToMemberType {
2124 address_size: Some(u64::from(dwarf_unit.header.address_size())),
2125 ..Default::default()
2126 };
2127
2128 let mut attrs = node.entry().attrs();
2129 while let Some(attr) = attrs.next()? {
2130 match attr.name() {
2131 gimli::DW_AT_type => {
2132 if let Some(offset) = parse_type_offset(dwarf_unit, &attr) {
2133 ty.ty = offset;
2134 }
2135 }
2136 gimli::DW_AT_containing_type => {
2137 if let Some(offset) = parse_type_offset(dwarf_unit, &attr) {
2138 ty.containing_ty = offset;
2139 }
2140 }
2141 gimli::DW_AT_byte_size => {
2142 if let Some(byte_size) = attr.udata_value() {
2143 ty.byte_size = Size::new(byte_size);
2144 }
2145 }
2146 _ => debug!(
2147 "unknown ptr_to_member type attribute: {} {:?}",
2148 attr.name(),
2149 attr.value()
2150 ),
2151 }
2152 }
2153
2154 let mut iter = node.children();
2155 while let Some(child) = iter.next()? {
2156 match child.entry().tag() {
2157 tag => {
2158 debug!("unknown ptr_to_member type child tag: {}", tag);
2159 }
2160 }
2161 }
2162 Ok(ty)
2163}
2164
2165fn parse_subprogram<'input, Endian>(
2166 unit: &mut Unit<'input>,
2167 dwarf: &DwarfDebugInfo<'input, Endian>,
2168 dwarf_unit: &DwarfUnit<'input, Endian>,
2169 subprograms: &mut Vec<DwarfSubprogram<'input>>,
2170 variables: &mut Vec<DwarfVariable<'input>>,
2171 namespace: &Option<Arc<Namespace<'input>>>,
2172 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
2173) -> Result<()>
2174where
2175 Endian: gimli::Endianity,
2176{
2177 let offset = node.entry().offset();
2178 let mut function = Function {
2179 id: Id::new(0),
2180 offset: offset.to_unit_section_offset(dwarf_unit).into(),
2181 namespace: namespace.clone(),
2182 name: None,
2183 symbol_name: None,
2184 linkage_name: None,
2185 source: Source::default(),
2186 address: Address::none(),
2187 size: Size::none(),
2188 ranges: Vec::new(),
2189 inline: false,
2190 declaration: false,
2191 parameters: Vec::new(),
2192 return_type: TypeOffset::none(),
2193 };
2194
2195 let mut specification = None;
2196 let mut abstract_origin = false;
2197 let mut high_pc = None;
2198 let mut size = None;
2199 let mut ranges = None;
2200
2201 let entry = node.entry();
2202 let mut attrs = entry.attrs();
2203 while let Some(attr) = attrs.next()? {
2204 match attr.name() {
2205 gimli::DW_AT_name => {
2206 function.name = dwarf.string(dwarf_unit, attr.value());
2207 }
2208 gimli::DW_AT_linkage_name | gimli::DW_AT_MIPS_linkage_name => {
2209 function.linkage_name = dwarf.string(dwarf_unit, attr.value());
2210 }
2211 gimli::DW_AT_decl_file => {
2212 parse_source_file(dwarf, dwarf_unit, &attr, &mut function.source)
2213 }
2214 gimli::DW_AT_decl_line => parse_source_line(&attr, &mut function.source),
2215 gimli::DW_AT_decl_column => parse_source_column(&attr, &mut function.source),
2216 gimli::DW_AT_inline => {
2217 if let gimli::AttributeValue::Inline(val) = attr.value() {
2218 match val {
2219 gimli::DW_INL_inlined | gimli::DW_INL_declared_inlined => {
2220 function.inline = true
2221 }
2222 _ => function.inline = false,
2223 }
2224 }
2225 }
2226 gimli::DW_AT_low_pc => {
2227 if let gimli::AttributeValue::Addr(addr) = attr.value() {
2228 if addr != 0 || unit.low_pc == Some(0) {
2229 function.address = Address::new(addr);
2230 }
2231 }
2232 }
2233 gimli::DW_AT_high_pc => match attr.value() {
2234 gimli::AttributeValue::Addr(addr) => high_pc = Some(addr),
2235 gimli::AttributeValue::Udata(val) => {
2236 if val != 0 {
2237 size = Some(val);
2238 }
2239 }
2240 _ => {}
2241 },
2242 gimli::DW_AT_ranges => {
2243 if let gimli::AttributeValue::RangeListsRef(val) = attr.value() {
2244 ranges = Some(val);
2245 }
2246 }
2247 gimli::DW_AT_type => {
2248 if let Some(offset) = parse_type_offset(dwarf_unit, &attr) {
2249 function.return_type = offset;
2250 }
2251 }
2252 gimli::DW_AT_specification | gimli::DW_AT_abstract_origin => {
2253 if let Some(offset) = parse_function_offset(dwarf_unit, &attr) {
2254 specification = Some(offset);
2255 abstract_origin = attr.name() == gimli::DW_AT_abstract_origin;
2256 }
2257 }
2258 gimli::DW_AT_declaration => {
2259 if let gimli::AttributeValue::Flag(flag) = attr.value() {
2260 function.declaration = flag;
2261 }
2262 }
2263 gimli::DW_AT_frame_base => {
2264 }
2266 gimli::DW_AT_external
2267 | gimli::DW_AT_call_all_calls
2268 | gimli::DW_AT_call_all_tail_calls
2269 | gimli::DW_AT_GNU_all_call_sites
2270 | gimli::DW_AT_GNU_all_tail_call_sites
2271 | gimli::DW_AT_prototyped
2272 | gimli::DW_AT_accessibility
2273 | gimli::DW_AT_explicit
2274 | gimli::DW_AT_artificial
2275 | gimli::DW_AT_object_pointer
2276 | gimli::DW_AT_virtuality
2277 | gimli::DW_AT_vtable_elem_location
2278 | gimli::DW_AT_containing_type
2279 | gimli::DW_AT_main_subprogram
2280 | gimli::DW_AT_noreturn
2281 | gimli::DW_AT_APPLE_optimized
2282 | gimli::DW_AT_APPLE_omit_frame_ptr
2283 | gimli::DW_AT_sibling => {}
2284 _ => debug!(
2285 "unknown subprogram attribute: {} {:?}",
2286 attr.name(),
2287 attr.value()
2288 ),
2289 }
2290 }
2291
2292 if let Some(offset) = ranges {
2293 let offset = dwarf.read.ranges_offset_from_raw(dwarf_unit, offset);
2294 let mut ranges = dwarf.read.ranges(dwarf_unit, offset)?;
2295 let mut size = 0;
2296 while let Some(range) = ranges.next()? {
2297 if range.end > range.begin {
2298 size += range.end - range.begin;
2299 function.ranges.push(Range {
2300 begin: range.begin,
2301 end: range.end,
2302 });
2303 }
2304 }
2305 function.size = Size::new(size);
2306 function.address = Address::new(function.ranges.first().map(|r| r.begin).unwrap_or(0));
2307 } else if let Some(address) = function.address.get() {
2308 if let Some(high_pc) = high_pc {
2309 if high_pc > address {
2310 function.size = Size::new(high_pc - address);
2311 function.ranges.push(Range {
2312 begin: address,
2313 end: high_pc,
2314 });
2315 }
2316 } else if let Some(size) = size {
2317 function.size = Size::new(size);
2318 function.ranges.push(Range {
2319 begin: address,
2320 end: address.wrapping_add(size),
2321 });
2322 }
2323 }
2324
2325 if let Some(specification) = specification {
2326 subprograms.push(DwarfSubprogram {
2327 offset,
2328 specification,
2329 abstract_origin,
2330 function,
2331 });
2332 return Ok(());
2333 }
2334
2335 parse_subprogram_children(
2336 unit,
2337 dwarf,
2338 dwarf_unit,
2339 subprograms,
2340 variables,
2341 &mut function,
2342 node.children(),
2343 )?;
2344 unit.functions.push(function);
2345 Ok(())
2346}
2347
2348fn inherit_subprogram<'input>(
2349 functions: &BTreeMap<FunctionOffset, Function<'input>>,
2350 function: &mut Function<'input>,
2351 specification: FunctionOffset,
2352 abstract_origin: bool,
2353) -> bool {
2354 let specification = match functions.get(&specification) {
2355 Some(val) => val,
2356 None => return false,
2357 };
2358
2359 function.namespace = specification.namespace.clone();
2360 if function.name.is_none() {
2361 function.name = specification.name;
2362 }
2363 if function.linkage_name.is_none() {
2364 function.linkage_name = specification.linkage_name;
2365 }
2366 if function.source.is_none() {
2367 function.source = specification.source.clone();
2368 }
2369 if function.return_type.is_none() {
2370 function.return_type = specification.return_type;
2371 }
2372 if abstract_origin {
2373 function.parameters = specification.parameters.clone();
2375 } else {
2376 }
2378
2379 true
2380}
2381
2382fn parse_subprogram_children<'input, Endian>(
2383 unit: &mut Unit<'input>,
2384 dwarf: &DwarfDebugInfo<'input, Endian>,
2385 dwarf_unit: &DwarfUnit<'input, Endian>,
2386 subprograms: &mut Vec<DwarfSubprogram<'input>>,
2387 variables: &mut Vec<DwarfVariable<'input>>,
2388 function: &mut Function<'input>,
2389 mut iter: gimli::EntriesTreeIter<Reader<'input, Endian>>,
2390) -> Result<()>
2391where
2392 Endian: gimli::Endianity,
2393{
2394 let namespace = Some(Namespace::new(
2395 &function.namespace,
2396 function.name,
2397 NamespaceKind::Function,
2398 ));
2399 while let Some(child) = iter.next()? {
2400 match child.entry().tag() {
2401 gimli::DW_TAG_formal_parameter => {
2402 parse_parameter_type(&mut function.parameters, dwarf, dwarf_unit, child)?;
2403 }
2404 gimli::DW_TAG_variable => {
2405 }
2407 gimli::DW_TAG_inlined_subroutine => {
2408 parse_inlined_subroutine(child)?;
2409 }
2410 gimli::DW_TAG_lexical_block => {
2411 parse_lexical_block(
2412 unit,
2413 dwarf,
2414 dwarf_unit,
2415 subprograms,
2416 variables,
2417 &namespace,
2418 child,
2419 )?;
2420 }
2421 gimli::DW_TAG_subprogram => {
2422 parse_subprogram(
2423 unit,
2424 dwarf,
2425 dwarf_unit,
2426 subprograms,
2427 variables,
2428 &namespace,
2429 child,
2430 )?;
2431 }
2432 gimli::DW_TAG_unspecified_parameters
2433 | gimli::DW_TAG_template_type_parameter
2434 | gimli::DW_TAG_template_value_parameter
2435 | gimli::DW_TAG_GNU_template_parameter_pack
2436 | gimli::DW_TAG_label
2437 | gimli::DW_TAG_imported_declaration
2438 | gimli::DW_TAG_imported_module
2439 | gimli::DW_TAG_call_site
2440 | gimli::DW_TAG_GNU_call_site => {}
2441 tag => {
2442 if !parse_type(
2443 unit,
2444 dwarf,
2445 dwarf_unit,
2446 subprograms,
2447 variables,
2448 &namespace,
2449 child,
2450 )? {
2451 debug!("unknown subprogram child tag: {}", tag);
2452 }
2453 }
2454 }
2455 }
2456 Ok(())
2457}
2458
2459fn parse_parameter_type<'input, Endian>(
2460 parameters: &mut Vec<ParameterType<'input>>,
2461 dwarf: &DwarfDebugInfo<'input, Endian>,
2462 dwarf_unit: &DwarfUnit<'input, Endian>,
2463 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
2464) -> Result<()>
2465where
2466 Endian: gimli::Endianity,
2467{
2468 let mut parameter = ParameterType::default();
2469 let offset = node.entry().offset();
2470 let offset = offset.to_unit_section_offset(dwarf_unit);
2471 parameter.offset = offset.into();
2472 let mut abstract_origin = None;
2473
2474 let mut attrs = node.entry().attrs();
2475 while let Some(attr) = attrs.next()? {
2476 match attr.name() {
2477 gimli::DW_AT_abstract_origin => {
2478 if let Some(offset) = parse_parameter_offset(dwarf_unit, &attr) {
2479 abstract_origin = Some(offset);
2480 }
2481 }
2482 gimli::DW_AT_name => {
2483 parameter.name = dwarf.string(dwarf_unit, attr.value());
2484 }
2485 gimli::DW_AT_type => {
2486 if let Some(offset) = parse_type_offset(dwarf_unit, &attr) {
2487 parameter.ty = offset;
2488 }
2489 }
2490 gimli::DW_AT_location
2491 | gimli::DW_AT_decl_file
2492 | gimli::DW_AT_decl_line
2493 | gimli::DW_AT_decl_column
2494 | gimli::DW_AT_artificial
2495 | gimli::DW_AT_const_value
2496 | gimli::DW_AT_GNU_locviews
2497 | gimli::DW_AT_sibling => {}
2498 _ => debug!(
2499 "unknown parameter attribute: {} {:?}",
2500 attr.name(),
2501 attr.value()
2502 ),
2503 }
2504 }
2505
2506 let mut iter = node.children();
2507 while let Some(child) = iter.next()? {
2508 match child.entry().tag() {
2509 tag => {
2510 debug!("unknown parameter child tag: {}", tag);
2511 }
2512 }
2513 }
2514
2515 if let Some(abstract_origin) = abstract_origin {
2516 if let Some(index) = parameters.iter().position(|x| x.offset == abstract_origin) {
2518 let p = &mut parameters[index];
2519 if parameter.name.is_some() {
2520 p.name = parameter.name;
2521 }
2522 if parameter.ty.is_some() {
2523 p.ty = parameter.ty;
2524 }
2525 return Ok(());
2526 } else {
2527 let unit_offset = offset
2528 .to_unit_offset(dwarf_unit)
2529 .unwrap_or(gimli::UnitOffset(0));
2530 let offset = match offset {
2531 gimli::UnitSectionOffset::DebugInfoOffset(offset) => offset.0,
2532 _ => panic!("unexpected offset"),
2533 };
2534 let header_offset = match dwarf_unit.header.offset() {
2535 gimli::UnitSectionOffset::DebugInfoOffset(offset) => offset.0,
2536 _ => panic!("unexpected offset"),
2537 };
2538 debug!(
2539 "missing parameter abstract origin: 0x{:08x}(0x{:08x}+0x{:08x})",
2540 offset, header_offset, unit_offset.0
2541 );
2542 }
2543 }
2544
2545 parameters.push(parameter);
2546 Ok(())
2547}
2548
2549fn parse_parameter<'input, Endian>(
2550 parameters: &mut Vec<Parameter<'input>>,
2551 dwarf: &DwarfDebugInfo<'input, Endian>,
2552 dwarf_unit: &DwarfUnit<'input, Endian>,
2553 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
2554) -> Result<()>
2555where
2556 Endian: gimli::Endianity,
2557{
2558 let mut parameter = Parameter::default();
2559 let offset = node.entry().offset();
2560 let offset = offset.to_unit_section_offset(dwarf_unit);
2561 parameter.offset = offset.into();
2562 let mut abstract_origin = None;
2563
2564 let mut attrs = node.entry().attrs();
2565 while let Some(attr) = attrs.next()? {
2566 match attr.name() {
2567 gimli::DW_AT_abstract_origin => {
2568 if let Some(offset) = parse_parameter_offset(dwarf_unit, &attr) {
2569 abstract_origin = Some(offset);
2570 }
2571 }
2572 gimli::DW_AT_name => {
2573 parameter.name = dwarf.string(dwarf_unit, attr.value());
2574 }
2575 gimli::DW_AT_type => {
2576 if let Some(offset) = parse_type_offset(dwarf_unit, &attr) {
2577 parameter.ty = offset;
2578 }
2579 }
2580 gimli::DW_AT_location => {
2581 match attr.value() {
2582 gimli::AttributeValue::Exprloc(expr) => {
2583 evaluate_parameter_location(
2584 &dwarf_unit.header,
2585 Range::all(),
2586 expr,
2587 &mut parameter,
2588 );
2589 }
2590 gimli::AttributeValue::LocationListsRef(offset) => {
2591 let mut locations = dwarf.read.locations(dwarf_unit, offset)?;
2592 while let Some(location) = locations.next()? {
2593 evaluate_parameter_location(
2595 &dwarf_unit.header,
2596 location.range.into(),
2597 location.data,
2598 &mut parameter,
2599 );
2600 }
2601 }
2602 _ => {
2603 debug!("unknown parameter DW_AT_location: {:?}", attr.value());
2604 }
2605 }
2606 }
2607 gimli::DW_AT_decl_file
2608 | gimli::DW_AT_decl_line
2609 | gimli::DW_AT_decl_column
2610 | gimli::DW_AT_artificial
2611 | gimli::DW_AT_const_value
2612 | gimli::DW_AT_GNU_locviews
2613 | gimli::DW_AT_sibling => {}
2614 _ => debug!(
2615 "unknown parameter attribute: {} {:?}",
2616 attr.name(),
2617 attr.value()
2618 ),
2619 }
2620 }
2621
2622 let mut iter = node.children();
2623 while let Some(child) = iter.next()? {
2624 match child.entry().tag() {
2625 tag => {
2626 debug!("unknown parameter child tag: {}", tag);
2627 }
2628 }
2629 }
2630
2631 if let Some(abstract_origin) = abstract_origin {
2632 if let Some(index) = parameters.iter().position(|x| x.offset == abstract_origin) {
2634 let p = &mut parameters[index];
2635 if parameter.name.is_some() {
2636 p.name = parameter.name;
2637 }
2638 if parameter.ty.is_some() {
2639 p.ty = parameter.ty;
2640 }
2641 if !parameter.locations.is_empty() {
2642 p.locations.extend(¶meter.locations);
2643 }
2644 return Ok(());
2645 } else {
2646 let unit_offset = offset
2647 .to_unit_offset(dwarf_unit)
2648 .unwrap_or(gimli::UnitOffset(0));
2649 let offset = match offset {
2650 gimli::UnitSectionOffset::DebugInfoOffset(offset) => offset.0,
2651 _ => panic!("unexpected offset"),
2652 };
2653 let header_offset = match dwarf_unit.header.offset() {
2654 gimli::UnitSectionOffset::DebugInfoOffset(offset) => offset.0,
2655 _ => panic!("unexpected offset"),
2656 };
2657 debug!(
2658 "missing parameter abstract origin: 0x{:08x}(0x{:08x}+0x{:08x})",
2659 offset, header_offset, unit_offset.0
2660 );
2661 }
2662 }
2663
2664 parameters.push(parameter);
2665 Ok(())
2666}
2667
2668fn parse_lexical_block<'input, Endian>(
2669 unit: &mut Unit<'input>,
2670 dwarf: &DwarfDebugInfo<'input, Endian>,
2671 dwarf_unit: &DwarfUnit<'input, Endian>,
2672 subprograms: &mut Vec<DwarfSubprogram<'input>>,
2673 variables: &mut Vec<DwarfVariable<'input>>,
2674 namespace: &Option<Arc<Namespace<'input>>>,
2675 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
2676) -> Result<()>
2677where
2678 Endian: gimli::Endianity,
2679{
2680 let mut attrs = node.entry().attrs();
2681 while let Some(attr) = attrs.next()? {
2682 match attr.name() {
2683 gimli::DW_AT_low_pc
2684 | gimli::DW_AT_high_pc
2685 | gimli::DW_AT_ranges
2686 | gimli::DW_AT_abstract_origin
2687 | gimli::DW_AT_sibling => {}
2688 _ => debug!(
2689 "unknown lexical_block attribute: {} {:?}",
2690 attr.name(),
2691 attr.value()
2692 ),
2693 }
2694 }
2695
2696 let mut iter = node.children();
2697 while let Some(child) = iter.next()? {
2698 match child.entry().tag() {
2699 gimli::DW_TAG_variable => {
2700 }
2702 gimli::DW_TAG_inlined_subroutine => {
2703 parse_inlined_subroutine(child)?;
2704 }
2705 gimli::DW_TAG_lexical_block => {
2706 parse_lexical_block(
2707 unit,
2708 dwarf,
2709 dwarf_unit,
2710 subprograms,
2711 variables,
2712 namespace,
2713 child,
2714 )?;
2715 }
2716 gimli::DW_TAG_subprogram => {
2717 parse_subprogram(
2718 unit,
2719 dwarf,
2720 dwarf_unit,
2721 subprograms,
2722 variables,
2723 namespace,
2724 child,
2725 )?;
2726 }
2727 gimli::DW_TAG_formal_parameter
2728 | gimli::DW_TAG_label
2729 | gimli::DW_TAG_imported_declaration
2730 | gimli::DW_TAG_imported_module
2731 | gimli::DW_TAG_call_site
2732 | gimli::DW_TAG_GNU_call_site => {}
2733 tag => {
2734 if !parse_type(
2735 unit,
2736 dwarf,
2737 dwarf_unit,
2738 subprograms,
2739 variables,
2740 namespace,
2741 child,
2742 )? {
2743 debug!("unknown lexical_block child tag: {}", tag);
2744 }
2745 }
2746 }
2747 }
2748 Ok(())
2749}
2750
2751fn parse_inlined_subroutine<Endian>(node: gimli::EntriesTreeNode<Reader<Endian>>) -> Result<()>
2753where
2754 Endian: gimli::Endianity,
2755{
2756 let mut iter = node.children();
2757 while let Some(child) = iter.next()? {
2758 match child.entry().tag() {
2759 gimli::DW_TAG_formal_parameter | gimli::DW_TAG_variable => {
2760 }
2762 gimli::DW_TAG_inlined_subroutine => {
2763 parse_inlined_subroutine(child)?;
2764 }
2765 gimli::DW_TAG_lexical_block => {
2766 parse_inlined_lexical_block(child)?;
2767 }
2768 gimli::DW_TAG_label | gimli::DW_TAG_call_site | gimli::DW_TAG_GNU_call_site => {}
2769 tag => {
2770 debug!("unknown inlined_subroutine child tag: {}", tag);
2771 }
2772 }
2773 }
2774 Ok(())
2775}
2776
2777fn parse_inlined_lexical_block<Endian>(node: gimli::EntriesTreeNode<Reader<Endian>>) -> Result<()>
2779where
2780 Endian: gimli::Endianity,
2781{
2782 let mut attrs = node.entry().attrs();
2783 while let Some(attr) = attrs.next()? {
2784 match attr.name() {
2785 gimli::DW_AT_low_pc
2786 | gimli::DW_AT_high_pc
2787 | gimli::DW_AT_ranges
2788 | gimli::DW_AT_abstract_origin
2789 | gimli::DW_AT_sibling => {}
2790 _ => debug!(
2791 "unknown inlined lexical_block attribute: {} {:?}",
2792 attr.name(),
2793 attr.value()
2794 ),
2795 }
2796 }
2797
2798 let mut iter = node.children();
2799 while let Some(child) = iter.next()? {
2800 match child.entry().tag() {
2801 gimli::DW_TAG_inlined_subroutine => {
2802 parse_inlined_subroutine(child)?;
2803 }
2804 gimli::DW_TAG_lexical_block => {
2805 parse_inlined_lexical_block(child)?;
2806 }
2807 gimli::DW_TAG_formal_parameter
2808 | gimli::DW_TAG_variable
2809 | gimli::DW_TAG_label
2810 | gimli::DW_TAG_call_site
2811 | gimli::DW_TAG_GNU_call_site
2812 | gimli::DW_TAG_imported_module => {}
2813 tag => {
2814 debug!("unknown inlined lexical_block child tag: {}", tag);
2815 }
2816 }
2817 }
2818 Ok(())
2819}
2820
2821fn parse_subprogram_details<'input, Endian>(
2822 hash: &FileHash<'input>,
2823 dwarf: &DwarfDebugInfo<'input, Endian>,
2824 dwarf_unit: &DwarfUnit<'input, Endian>,
2825 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
2826) -> Result<FunctionDetails<'input>>
2827where
2828 Endian: gimli::Endianity,
2829{
2830 let mut abstract_origin = None;
2831
2832 let entry = node.entry();
2833 let mut attrs = entry.attrs();
2834 while let Some(attr) = attrs.next()? {
2835 match attr.name() {
2836 gimli::DW_AT_abstract_origin => {
2837 if let Some(offset) = parse_function_offset(dwarf_unit, &attr) {
2838 abstract_origin = Some(offset);
2839 }
2840 }
2841 _ => {}
2842 }
2843 }
2844
2845 let mut details = abstract_origin
2847 .and_then(|offset| dwarf.get_function_details(offset, hash))
2848 .unwrap_or_else(|| FunctionDetails {
2849 parameters: Vec::new(),
2850 variables: Vec::new(),
2851 inlined_functions: Vec::new(),
2852 });
2853
2854 parse_subprogram_children_details(hash, dwarf, dwarf_unit, &mut details, node.children())?;
2855 Ok(details)
2856}
2857
2858fn parse_subprogram_children_details<'input, Endian>(
2859 hash: &FileHash<'input>,
2860 dwarf: &DwarfDebugInfo<'input, Endian>,
2861 dwarf_unit: &DwarfUnit<'input, Endian>,
2862 function: &mut FunctionDetails<'input>,
2863 mut iter: gimli::EntriesTreeIter<Reader<'input, Endian>>,
2864) -> Result<()>
2865where
2866 Endian: gimli::Endianity,
2867{
2868 while let Some(child) = iter.next()? {
2869 match child.entry().tag() {
2870 gimli::DW_TAG_formal_parameter => {
2871 parse_parameter(&mut function.parameters, dwarf, dwarf_unit, child)?;
2872 }
2873 gimli::DW_TAG_variable => {
2874 parse_local_variable(&mut function.variables, dwarf, dwarf_unit, child)?;
2875 }
2876 gimli::DW_TAG_inlined_subroutine => {
2877 function
2878 .inlined_functions
2879 .push(parse_inlined_subroutine_details(
2880 hash, dwarf, dwarf_unit, child,
2881 )?);
2882 }
2883 gimli::DW_TAG_lexical_block => {
2884 parse_lexical_block_details(
2885 &mut function.inlined_functions,
2886 &mut function.variables,
2887 hash,
2888 dwarf,
2889 dwarf_unit,
2890 child,
2891 )?;
2892 }
2893 _ => {}
2895 }
2896 }
2897 Ok(())
2898}
2899
2900fn parse_lexical_block_details<'input, Endian>(
2901 inlined_functions: &mut Vec<InlinedFunction<'input>>,
2902 local_variables: &mut Vec<LocalVariable<'input>>,
2903 hash: &FileHash<'input>,
2904 dwarf: &DwarfDebugInfo<'input, Endian>,
2905 dwarf_unit: &DwarfUnit<'input, Endian>,
2906 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
2907) -> Result<()>
2908where
2909 Endian: gimli::Endianity,
2910{
2911 let mut iter = node.children();
2914 while let Some(child) = iter.next()? {
2915 match child.entry().tag() {
2916 gimli::DW_TAG_variable => {
2917 parse_local_variable(local_variables, dwarf, dwarf_unit, child)?;
2918 }
2919 gimli::DW_TAG_inlined_subroutine => {
2920 inlined_functions.push(parse_inlined_subroutine_details(
2921 hash, dwarf, dwarf_unit, child,
2922 )?);
2923 }
2924 gimli::DW_TAG_lexical_block => {
2925 parse_lexical_block_details(
2926 inlined_functions,
2927 local_variables,
2928 hash,
2929 dwarf,
2930 dwarf_unit,
2931 child,
2932 )?;
2933 }
2934 _ => {}
2936 }
2937 }
2938 Ok(())
2939}
2940
2941fn parse_inlined_subroutine_details<'input, Endian>(
2942 hash: &FileHash<'input>,
2943 dwarf: &DwarfDebugInfo<'input, Endian>,
2944 dwarf_unit: &DwarfUnit<'input, Endian>,
2945 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
2946) -> Result<InlinedFunction<'input>>
2947where
2948 Endian: gimli::Endianity,
2949{
2950 let mut function = InlinedFunction::default();
2951 let mut low_pc = None;
2952 let mut high_pc = None;
2953 let mut size = None;
2954 let mut ranges = None;
2955 let mut attrs = node.entry().attrs();
2956 while let Some(attr) = attrs.next()? {
2957 match attr.name() {
2958 gimli::DW_AT_abstract_origin => {
2959 if let Some(offset) = parse_function_offset(dwarf_unit, &attr) {
2960 function.abstract_origin = offset;
2961 }
2962 }
2963 gimli::DW_AT_low_pc => {
2964 if let gimli::AttributeValue::Addr(addr) = attr.value() {
2965 low_pc = Some(addr);
2966 }
2967 }
2968 gimli::DW_AT_high_pc => match attr.value() {
2969 gimli::AttributeValue::Addr(addr) => high_pc = Some(addr),
2970 gimli::AttributeValue::Udata(val) => size = Some(val),
2971 _ => {}
2972 },
2973 gimli::DW_AT_ranges => {
2974 if let gimli::AttributeValue::RangeListsRef(val) = attr.value() {
2975 ranges = Some(val);
2976 }
2977 }
2978 gimli::DW_AT_call_file => {
2979 parse_source_file(dwarf, dwarf_unit, &attr, &mut function.call_source)
2980 }
2981 gimli::DW_AT_call_line => parse_source_line(&attr, &mut function.call_source),
2982 gimli::DW_AT_call_column => parse_source_column(&attr, &mut function.call_source),
2983 gimli::DW_AT_entry_pc | gimli::DW_AT_sibling => {}
2984 _ => debug!(
2985 "unknown inlined_subroutine attribute: {} {:?}",
2986 attr.name(),
2987 attr.value()
2988 ),
2989 }
2990 }
2991
2992 if function.abstract_origin.is_some() {
2993 if let Some(details) = dwarf.get_function_details(function.abstract_origin, hash) {
2994 function.parameters = details.parameters;
2995 function.variables = details.variables;
2996 if !function.inlined_functions.is_empty() {
2997 debug!("abstract origin with inlined functions");
2998 }
2999 } else {
3000 debug!("inlined_subroutine with invalid abstract origin");
3001 }
3002 } else {
3003 debug!("inlined_subroutine with no abstract origin");
3004 }
3005
3006 if let Some(offset) = ranges {
3007 let mut size = 0;
3008 let offset = dwarf.read.ranges_offset_from_raw(dwarf_unit, offset);
3009 let mut ranges = dwarf.read.ranges(dwarf_unit, offset)?;
3010 while let Some(range) = ranges.next()? {
3011 if range.end > range.begin {
3012 size += range.end.wrapping_sub(range.begin);
3013 function.ranges.push(Range {
3014 begin: range.begin,
3015 end: range.end,
3016 });
3017 }
3018 }
3019 function.size = Size::new(size);
3020 } else if let Some(size) = size {
3021 if let Some(low_pc) = low_pc {
3022 function.ranges.push(Range {
3023 begin: low_pc,
3024 end: low_pc.wrapping_add(size),
3025 });
3026 }
3027 function.size = Size::new(size);
3028 } else if let (Some(low_pc), Some(high_pc)) = (low_pc, high_pc) {
3029 if high_pc > low_pc {
3030 function.ranges.push(Range {
3031 begin: low_pc,
3032 end: high_pc,
3033 });
3034 }
3035 function.size = Size::new(high_pc.wrapping_sub(low_pc));
3036 } else {
3037 debug!("unknown inlined_subroutine size");
3038 }
3039
3040 let mut iter = node.children();
3041 while let Some(child) = iter.next()? {
3042 match child.entry().tag() {
3043 gimli::DW_TAG_formal_parameter => {
3044 parse_parameter(&mut function.parameters, dwarf, dwarf_unit, child)?;
3045 }
3046 gimli::DW_TAG_variable => {
3047 parse_local_variable(&mut function.variables, dwarf, dwarf_unit, child)?;
3048 }
3049 gimli::DW_TAG_inlined_subroutine => {
3050 function
3051 .inlined_functions
3052 .push(parse_inlined_subroutine_details(
3053 hash, dwarf, dwarf_unit, child,
3054 )?);
3055 }
3056 gimli::DW_TAG_lexical_block => {
3057 parse_lexical_block_details(
3058 &mut function.inlined_functions,
3059 &mut function.variables,
3060 hash,
3061 dwarf,
3062 dwarf_unit,
3063 child,
3064 )?;
3065 }
3066 gimli::DW_TAG_label | gimli::DW_TAG_call_site | gimli::DW_TAG_GNU_call_site => {}
3067 tag => {
3068 debug!("unknown inlined_subroutine child tag: {}", tag);
3069 }
3070 }
3071 }
3072 Ok(function)
3073}
3074
3075fn parse_variable<'input, Endian>(
3076 _unit: &mut Unit<'input>,
3077 dwarf: &DwarfDebugInfo<'input, Endian>,
3078 dwarf_unit: &DwarfUnit<'input, Endian>,
3079 namespace: Option<Arc<Namespace<'input>>>,
3080 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
3081) -> Result<DwarfVariable<'input>>
3082where
3083 Endian: gimli::Endianity,
3084{
3085 let offset = node.entry().offset();
3086 let mut specification = None;
3087 let mut variable = Variable {
3088 offset: offset.to_unit_section_offset(dwarf_unit).into(),
3089 namespace,
3090 ..Default::default()
3091 };
3092
3093 let mut attrs = node.entry().attrs();
3094 while let Some(attr) = attrs.next()? {
3095 match attr.name() {
3096 gimli::DW_AT_name => {
3097 variable.name = dwarf.string(dwarf_unit, attr.value());
3098 }
3099 gimli::DW_AT_linkage_name | gimli::DW_AT_MIPS_linkage_name => {
3100 variable.linkage_name = dwarf.string(dwarf_unit, attr.value());
3101 }
3102 gimli::DW_AT_type => {
3103 if let Some(offset) = parse_type_offset(dwarf_unit, &attr) {
3104 variable.ty = offset;
3105 }
3106 }
3107 gimli::DW_AT_specification => {
3108 if let Some(offset) = parse_variable_offset(dwarf_unit, &attr) {
3109 specification = Some(offset);
3110 }
3111 }
3112 gimli::DW_AT_declaration => {
3113 if let gimli::AttributeValue::Flag(flag) = attr.value() {
3114 variable.declaration = flag;
3115 }
3116 }
3117 gimli::DW_AT_decl_file => {
3118 parse_source_file(dwarf, dwarf_unit, &attr, &mut variable.source)
3119 }
3120 gimli::DW_AT_decl_line => parse_source_line(&attr, &mut variable.source),
3121 gimli::DW_AT_decl_column => parse_source_column(&attr, &mut variable.source),
3122 gimli::DW_AT_location => match attr.value() {
3123 gimli::AttributeValue::Exprloc(expr) => {
3124 if let Some((address, size)) =
3125 evaluate_variable_location(&dwarf_unit.header, expr)
3126 {
3127 variable.address = address;
3128 if size.is_some() {
3129 variable.size = size;
3130 }
3131 }
3132 }
3133 gimli::AttributeValue::LocationListsRef(..) => {
3134 debug!("loclist for variable: {:?}", attr.value());
3135 }
3136 _ => {
3137 debug!("unknown variable DW_AT_location: {:?}", attr.value());
3138 }
3139 },
3140 gimli::DW_AT_abstract_origin
3141 | gimli::DW_AT_artificial
3142 | gimli::DW_AT_const_value
3143 | gimli::DW_AT_external
3144 | gimli::DW_AT_accessibility
3145 | gimli::DW_AT_alignment => {}
3146 _ => debug!(
3147 "unknown variable attribute: {} {:?}",
3148 attr.name(),
3149 attr.value()
3150 ),
3151 }
3152 }
3153
3154 let mut iter = node.children();
3155 while let Some(child) = iter.next()? {
3156 match child.entry().tag() {
3157 tag => {
3158 debug!("unknown variable child tag: {}", tag);
3159 }
3160 }
3161 }
3162
3163 Ok(DwarfVariable {
3164 offset,
3165 specification,
3166 variable,
3167 })
3168}
3169
3170fn parse_local_variable<'input, Endian>(
3171 variables: &mut Vec<LocalVariable<'input>>,
3172 dwarf: &DwarfDebugInfo<'input, Endian>,
3173 dwarf_unit: &DwarfUnit<'input, Endian>,
3174 node: gimli::EntriesTreeNode<Reader<'input, Endian>>,
3175) -> Result<()>
3176where
3177 Endian: gimli::Endianity,
3178{
3179 let mut variable = LocalVariable::default();
3180 let offset = node.entry().offset();
3181 let offset = offset.to_unit_section_offset(dwarf_unit);
3182 variable.offset = offset.into();
3183 let mut abstract_origin = None;
3184
3185 let mut attrs = node.entry().attrs();
3186 while let Some(attr) = attrs.next()? {
3187 match attr.name() {
3188 gimli::DW_AT_abstract_origin => {
3189 if let Some(offset) = parse_variable_offset(dwarf_unit, &attr) {
3190 abstract_origin = Some(offset);
3191 }
3192 }
3193 gimli::DW_AT_name => {
3194 variable.name = dwarf.string(dwarf_unit, attr.value());
3195 }
3196 gimli::DW_AT_type => {
3197 if let Some(offset) = parse_type_offset(dwarf_unit, &attr) {
3198 variable.ty = offset;
3199 }
3200 }
3201 gimli::DW_AT_decl_file => {
3202 parse_source_file(dwarf, dwarf_unit, &attr, &mut variable.source)
3203 }
3204 gimli::DW_AT_decl_line => parse_source_line(&attr, &mut variable.source),
3205 gimli::DW_AT_decl_column => parse_source_column(&attr, &mut variable.source),
3206 gimli::DW_AT_location => {
3207 match attr.value() {
3208 gimli::AttributeValue::Exprloc(expr) => {
3209 evaluate_local_variable_location(
3210 &dwarf_unit.header,
3211 Range::all(),
3212 expr,
3213 &mut variable,
3214 );
3215 }
3216 gimli::AttributeValue::LocationListsRef(offset) => {
3217 let mut locations = dwarf.read.locations(dwarf_unit, offset)?;
3218 while let Some(location) = locations.next()? {
3219 evaluate_local_variable_location(
3221 &dwarf_unit.header,
3222 location.range.into(),
3223 location.data,
3224 &mut variable,
3225 );
3226 }
3227 }
3228 _ => {
3229 debug!("unknown local variable DW_AT_location: {:?}", attr.value());
3230 }
3231 }
3232 }
3233 gimli::DW_AT_alignment
3234 | gimli::DW_AT_artificial
3235 | gimli::DW_AT_const_value
3236 | gimli::DW_AT_external
3237 | gimli::DW_AT_GNU_locviews => {}
3238 _ => debug!(
3239 "unknown local variable attribute: {} {:?}",
3240 attr.name(),
3241 attr.value()
3242 ),
3243 }
3244 }
3245
3246 let mut iter = node.children();
3247 while let Some(child) = iter.next()? {
3248 match child.entry().tag() {
3249 tag => {
3250 debug!("unknown variable child tag: {}", tag);
3251 }
3252 }
3253 }
3254
3255 if let Some(abstract_origin) = abstract_origin {
3256 if let Some(index) = variables.iter().position(|x| x.offset == abstract_origin) {
3258 let v = &mut variables[index];
3259 if variable.name.is_some() {
3260 v.name = variable.name;
3261 }
3262 if variable.ty.is_some() {
3263 v.ty = variable.ty;
3264 }
3265 if variable.source.is_some() {
3266 v.source = variable.source;
3267 }
3268 if variable.address.is_some() {
3269 v.address = variable.address;
3270 }
3271 if variable.size.is_some() {
3272 v.size = variable.size;
3273 }
3274 if !variable.locations.is_empty() {
3275 v.locations.extend(&variable.locations);
3276 }
3277 return Ok(());
3278 } else {
3279 let unit_offset = offset
3280 .to_unit_offset(dwarf_unit)
3281 .unwrap_or(gimli::UnitOffset(0));
3282 let offset = match offset {
3283 gimli::UnitSectionOffset::DebugInfoOffset(offset) => offset.0,
3284 _ => panic!("unexpected offset"),
3285 };
3286 let header_offset = match dwarf_unit.header.offset() {
3287 gimli::UnitSectionOffset::DebugInfoOffset(offset) => offset.0,
3288 _ => panic!("unexpected offset"),
3289 };
3290 debug!(
3291 "missing variable abstract origin: 0x{:08x}(0x{:08x}+0x{:08x})",
3292 offset, header_offset, unit_offset.0
3293 );
3294 }
3295 }
3296
3297 variables.push(variable);
3298 Ok(())
3299}
3300
3301fn evaluate_member_location<'input, Endian>(
3302 unit: &gimli::UnitHeader<Reader<'input, Endian>>,
3303 expression: gimli::Expression<Reader<'input, Endian>>,
3304) -> Option<u64>
3305where
3306 Endian: gimli::Endianity,
3307{
3308 let pieces = evaluate(unit, expression, true);
3309 if pieces.len() != 1 {
3310 debug!("unsupported number of evaluation pieces: {:?}", pieces);
3311 return None;
3312 }
3313 match pieces[0].location {
3314 gimli::Location::Address { address } => Some(address * 8),
3315 gimli::Location::Register { .. } => None,
3316 _ => {
3317 debug!("unknown DW_AT_data_member_location result: {:?}", pieces);
3318 None
3319 }
3320 }
3321}
3322
3323fn evaluate_variable_location<'input, Endian>(
3324 unit: &gimli::UnitHeader<Reader<'input, Endian>>,
3325 expression: gimli::Expression<Reader<'input, Endian>>,
3326) -> Option<(Address, Size)>
3327where
3328 Endian: gimli::Endianity,
3329{
3330 let pieces = evaluate(unit, expression, false);
3331 let mut result = None;
3332 for piece in &*pieces {
3333 match piece.location {
3334 gimli::Location::Address { address } => {
3335 if result.is_some() {
3336 debug!(
3337 "unsupported DW_AT_location with multiple addresses: {:?}",
3338 pieces
3339 );
3340 } else {
3341 let address = Address::new(address);
3342 let size = match piece.size_in_bits.map(|x| (x + 7) / 8) {
3343 Some(size) => Size::new(size),
3344 None => Size::none(),
3345 };
3346 result = Some((address, size));
3347 }
3348 }
3349 gimli::Location::Empty
3350 | gimli::Location::Register { .. }
3351 | gimli::Location::Value { .. }
3352 | gimli::Location::ImplicitPointer { .. } => {}
3353 _ => debug!("unknown DW_AT_location piece: {:?}", piece),
3354 }
3355 }
3356 result
3357}
3358
3359fn evaluate_local_variable_location<'input, Endian>(
3360 unit: &gimli::UnitHeader<Reader<'input, Endian>>,
3361 range: Range,
3362 expression: gimli::Expression<Reader<'input, Endian>>,
3363 variable: &mut LocalVariable<'input>,
3364) where
3365 Endian: gimli::Endianity,
3366{
3367 let pieces = match evaluate_simple(unit, expression, false) {
3368 Ok(locations) => locations,
3369 Err(_e) => {
3370 return;
3373 }
3374 };
3375
3376 for piece in &pieces {
3377 if piece.is_value {
3378 continue;
3379 }
3380 if let Location::Address { address } = piece.location {
3382 if variable.address.is_some() {
3383 if address != variable.address {
3384 debug!(
3386 "unsupported DW_AT_location with multiple addresses: {:?}",
3387 pieces
3388 );
3389 }
3390 } else {
3391 variable.address = address;
3392 if let Some(bit_size) = piece.bit_size.get() {
3393 variable.size = Size::new((bit_size + 7) / 8);
3394 }
3395 }
3396 }
3397 }
3398
3399 variable
3400 .locations
3401 .extend(pieces.into_iter().map(|piece| (range, piece)));
3402}
3403
3404fn evaluate_parameter_location<'input, Endian>(
3405 unit: &gimli::UnitHeader<Reader<'input, Endian>>,
3406 range: Range,
3407 expression: gimli::Expression<Reader<'input, Endian>>,
3408 parameter: &mut Parameter<'input>,
3409) where
3410 Endian: gimli::Endianity,
3411{
3412 let pieces = match evaluate_simple(unit, expression, false) {
3413 Ok(locations) => locations,
3414 Err(_e) => {
3415 return;
3418 }
3419 };
3420
3421 parameter
3422 .locations
3423 .extend(pieces.into_iter().map(|piece| (range, piece)));
3424}
3425
3426fn evaluate_simple<'input, Endian>(
3427 unit: &gimli::UnitHeader<Reader<'input, Endian>>,
3428 expression: gimli::Expression<Reader<'input, Endian>>,
3429 _object_address: bool,
3430) -> Result<Vec<Piece>>
3431where
3432 Endian: gimli::Endianity + 'input,
3433{
3434 let encoding = unit.encoding();
3435 let addr_mask = if encoding.address_size == 8 {
3436 !0u64
3437 } else {
3438 (1 << (8 * u64::from(encoding.address_size))) - 1
3439 };
3440 let mut bytes = expression.0;
3441
3442 let mut pieces = Vec::new();
3443 let mut next_bit_offset = 0;
3444 let mut add_piece = |pieces: &mut Vec<Piece>,
3445 location: Location,
3446 location_offset: u64,
3447 is_value: bool,
3448 bit_size: Size| {
3449 let bit_offset = next_bit_offset;
3450 next_bit_offset += bit_size.get().unwrap_or(0);
3451 pieces.push(Piece {
3452 bit_offset,
3453 bit_size,
3454 location,
3455 location_offset,
3456 is_value,
3457 });
3458 };
3459
3460 let mut stack = Vec::new();
3461 let pop = |stack: &mut Vec<Location>| match stack.pop() {
3462 Some(value) => Ok(value),
3463 None => Err(gimli::Error::NotEnoughStackItems),
3464 };
3465
3466 let mut location = None;
3467 while !bytes.is_empty() {
3468 match gimli::Operation::parse(&mut bytes, encoding)? {
3469 gimli::Operation::Nop => {}
3470 gimli::Operation::Register { register } => {
3471 location = Some((
3472 Location::Register {
3473 register: register.into(),
3474 },
3475 false,
3476 ));
3477 }
3478 gimli::Operation::ImplicitValue { .. } => {
3479 location = Some((Location::Other, true));
3481 }
3482 gimli::Operation::ImplicitPointer { .. } => {
3483 location = Some((Location::Other, false));
3485 }
3486 gimli::Operation::StackValue => {
3487 location = Some((pop(&mut stack)?, true));
3488 }
3489 gimli::Operation::EntryValue { .. }
3490 | gimli::Operation::ParameterRef { .. }
3491 | gimli::Operation::TypedLiteral { .. }
3492 | gimli::Operation::PushObjectAddress => {
3493 stack.push(Location::Other);
3495 }
3496 gimli::Operation::UnsignedConstant { value } => {
3497 stack.push(Location::Literal { value });
3498 }
3499 gimli::Operation::SignedConstant { value } => {
3500 stack.push(Location::Literal {
3501 value: value as u64,
3502 });
3503 }
3504 gimli::Operation::RegisterOffset {
3505 register, offset, ..
3506 } => {
3507 stack.push(Location::RegisterOffset {
3509 register: register.into(),
3510 offset,
3511 });
3512 }
3513 gimli::Operation::FrameOffset { offset } => {
3514 stack.push(Location::FrameOffset { offset });
3515 }
3516 gimli::Operation::CallFrameCFA => {
3517 stack.push(Location::CfaOffset { offset: 0 });
3518 }
3519 gimli::Operation::Address { address } => {
3520 stack.push(Location::Address {
3521 address: Address::new(address),
3522 });
3523 }
3524 gimli::Operation::AddressIndex { .. } | gimli::Operation::ConstantIndex { .. } => {
3525 stack.push(Location::Other);
3527 }
3528 gimli::Operation::TLS => {
3529 let location = match pop(&mut stack)? {
3530 Location::Literal { value } => Location::TlsOffset { offset: value },
3531 Location::Other => Location::Other,
3532 location => {
3533 debug!("unsupported TLS: {:?}", location);
3534 Location::Other
3535 }
3536 };
3537 stack.push(location);
3538 }
3539 gimli::Operation::Piece {
3540 size_in_bits,
3541 bit_offset,
3542 } => {
3543 let location = stack.pop().unwrap_or(Location::Empty);
3544 add_piece(
3545 &mut pieces,
3546 location,
3547 bit_offset.unwrap_or(0),
3548 false,
3549 Size::new(size_in_bits),
3550 );
3551 }
3552 gimli::Operation::Drop => {
3553 pop(&mut stack)?;
3554 }
3555 gimli::Operation::Swap => {
3556 let one = pop(&mut stack)?;
3557 let two = pop(&mut stack)?;
3558 stack.push(one);
3559 stack.push(two);
3560 }
3561 gimli::Operation::Rot => {
3562 let one = pop(&mut stack)?;
3563 let two = pop(&mut stack)?;
3564 let three = pop(&mut stack)?;
3565 stack.push(one);
3566 stack.push(three);
3567 stack.push(two);
3568 }
3569 gimli::Operation::Pick { index } => {
3570 let index = index as usize;
3571 if index >= stack.len() {
3572 return Err(gimli::Error::NotEnoughStackItems.into());
3573 }
3574 let location = stack[stack.len() - index - 1];
3575 stack.push(location);
3576 }
3577 gimli::Operation::PlusConstant { value: constant } => {
3578 let location = match pop(&mut stack)? {
3579 Location::Literal { value } => {
3580 let value = value.wrapping_add(constant) & addr_mask;
3581 Location::Literal { value }
3582 }
3583 Location::RegisterOffset { register, offset } => {
3584 let offset = ((offset as u64).wrapping_add(constant) & addr_mask) as i64;
3585 Location::RegisterOffset { register, offset }
3586 }
3587 Location::FrameOffset { offset } => {
3588 let offset = ((offset as u64).wrapping_add(constant) & addr_mask) as i64;
3589 Location::FrameOffset { offset }
3590 }
3591 Location::CfaOffset { offset } => {
3592 let offset = ((offset as u64).wrapping_add(constant) & addr_mask) as i64;
3593 Location::CfaOffset { offset }
3594 }
3595 Location::Other => Location::Other,
3596 location => {
3597 debug!("unsupported PlusConstant: {:?}", location);
3598 Location::Other
3599 }
3600 };
3601 stack.push(location);
3602 }
3603 gimli::Operation::Plus => {
3604 let one = pop(&mut stack)?;
3605 let two = pop(&mut stack)?;
3606 match (one, two) {
3607 (Location::Other, _) | (_, Location::Other) => Location::Other,
3608 (Location::RegisterOffset { .. }, Location::RegisterOffset { .. }) => {
3609 Location::Other
3611 }
3612 location => {
3613 debug!("unsupported Plus: {:?}", location);
3614 Location::Other
3615 }
3616 };
3617 }
3618 gimli::Operation::Minus => {
3619 let one = pop(&mut stack)?;
3620 let two = pop(&mut stack)?;
3621 match (one, two) {
3622 (Location::Other, _) | (_, Location::Other) => Location::Other,
3623 (Location::RegisterOffset { .. }, Location::RegisterOffset { .. }) => {
3624 Location::Other
3626 }
3627 (Location::Literal { value }, Location::FrameOffset { offset }) => {
3628 Location::FrameOffset {
3629 offset: offset - value as i64,
3630 }
3631 }
3632 location => {
3633 debug!("unsupported Minus: {:?}", location);
3634 Location::Other
3635 }
3636 };
3637 }
3638 gimli::Operation::Neg
3639 | gimli::Operation::Not
3640 | gimli::Operation::Abs
3641 | gimli::Operation::Convert { .. }
3642 | gimli::Operation::Reinterpret { .. } => {
3643 pop(&mut stack)?;
3645 stack.push(Location::Other);
3646 }
3647 gimli::Operation::Mul
3648 | gimli::Operation::Div
3649 | gimli::Operation::Mod
3650 | gimli::Operation::Shl
3651 | gimli::Operation::Shr
3652 | gimli::Operation::Shra
3653 | gimli::Operation::And
3654 | gimli::Operation::Or
3655 | gimli::Operation::Xor
3656 | gimli::Operation::Eq
3657 | gimli::Operation::Ne
3658 | gimli::Operation::Gt
3659 | gimli::Operation::Ge
3660 | gimli::Operation::Lt
3661 | gimli::Operation::Le => {
3662 pop(&mut stack)?;
3664 pop(&mut stack)?;
3665 stack.push(Location::Other);
3666 }
3667 gimli::Operation::Deref { space, .. } => {
3668 pop(&mut stack)?;
3670 if space {
3671 pop(&mut stack)?;
3672 }
3673 stack.push(Location::Other);
3674 }
3675 gimli::Operation::Bra { .. }
3676 | gimli::Operation::Skip { .. }
3677 | gimli::Operation::Call { .. } => {
3678 return Ok(pieces);
3682 }
3683 gimli::Operation::WasmLocal { .. }
3684 | gimli::Operation::WasmGlobal { .. }
3685 | gimli::Operation::WasmStack { .. } => {
3686 location = Some((Location::Other, false));
3688 }
3689 }
3690 if let Some((location, is_value)) = location {
3691 if bytes.is_empty() {
3692 if !pieces.is_empty() {
3693 return Err(gimli::Error::InvalidPiece.into());
3694 }
3695 add_piece(&mut pieces, location, 0, is_value, Size::none());
3696 } else {
3697 match gimli::Operation::parse(&mut bytes, encoding)? {
3698 gimli::Operation::Piece {
3699 size_in_bits,
3700 bit_offset,
3701 } => {
3702 add_piece(
3703 &mut pieces,
3704 location,
3705 bit_offset.unwrap_or(0),
3706 is_value,
3707 Size::new(size_in_bits),
3708 );
3709 }
3710 _ => {
3711 return Err(gimli::Error::InvalidPiece.into());
3712 }
3713 }
3714 }
3715 }
3716 location = None;
3717 }
3718 if pieces.is_empty() {
3719 if let Some(location) = stack.pop() {
3720 add_piece(&mut pieces, location, 0, false, Size::none());
3721 }
3722 }
3723 Ok(pieces)
3724}
3725
3726fn evaluate<'input, Endian>(
3727 unit: &gimli::UnitHeader<Reader<'input, Endian>>,
3728 expression: gimli::Expression<Reader<'input, Endian>>,
3729 object_address: bool,
3730) -> Vec<gimli::Piece<Reader<'input, Endian>>>
3731where
3732 Endian: gimli::Endianity + 'input,
3733{
3734 let mut evaluation = expression.evaluation(unit.encoding());
3735 if object_address {
3736 evaluation.set_object_address(0);
3737 evaluation.set_initial_value(0);
3738 }
3739 let mut result = evaluation.evaluate();
3740 loop {
3741 match result {
3742 Ok(gimli::EvaluationResult::Complete) => {
3743 return evaluation.result();
3744 }
3745 Ok(gimli::EvaluationResult::RequiresRelocatedAddress(address)) => {
3746 result = evaluation.resume_with_relocated_address(address);
3747 }
3748 Ok(_x) => {
3749 debug!("incomplete evaluation: {:?}", _x);
3750 return Vec::new();
3751 }
3752 Err(e) => {
3753 debug!("evaluation failed: {}", e);
3754 return Vec::new();
3755 }
3756 }
3757 }
3758}
3759
3760impl From<gimli::Range> for Range {
3761 #[inline]
3762 fn from(range: gimli::Range) -> Range {
3763 Range {
3764 begin: range.begin,
3765 end: range.end,
3766 }
3767 }
3768}
3769
3770impl From<gimli::Register> for Register {
3771 #[inline]
3772 fn from(register: gimli::Register) -> Register {
3773 Register(register.0)
3774 }
3775}
3776
3777impl From<gimli::UnitSectionOffset> for FunctionOffset {
3778 #[inline]
3779 fn from(o: gimli::UnitSectionOffset) -> FunctionOffset {
3780 let o = match o {
3781 gimli::UnitSectionOffset::DebugInfoOffset(o) => o,
3782 _ => panic!("unexpected offset {:?}", o),
3783 };
3784 FunctionOffset::new(o.0)
3785 }
3786}
3787
3788impl From<gimli::UnitSectionOffset> for ParameterOffset {
3789 #[inline]
3790 fn from(o: gimli::UnitSectionOffset) -> ParameterOffset {
3791 let o = match o {
3792 gimli::UnitSectionOffset::DebugInfoOffset(o) => o,
3793 _ => panic!("unexpected offset {:?}", o),
3794 };
3795 ParameterOffset::new(o.0)
3796 }
3797}
3798
3799impl From<gimli::UnitSectionOffset> for MemberOffset {
3800 #[inline]
3801 fn from(o: gimli::UnitSectionOffset) -> MemberOffset {
3802 let o = match o {
3803 gimli::UnitSectionOffset::DebugInfoOffset(o) => o,
3804 _ => panic!("unexpected offset {:?}", o),
3805 };
3806 MemberOffset::new(o.0)
3807 }
3808}
3809
3810impl From<gimli::UnitSectionOffset> for TypeOffset {
3811 #[inline]
3812 fn from(o: gimli::UnitSectionOffset) -> TypeOffset {
3813 let o = match o {
3814 gimli::UnitSectionOffset::DebugInfoOffset(o) => o,
3815 _ => panic!("unexpected offset {:?}", o),
3816 };
3817 TypeOffset::new(o.0)
3818 }
3819}
3820
3821impl From<gimli::UnitSectionOffset> for VariableOffset {
3822 #[inline]
3823 fn from(o: gimli::UnitSectionOffset) -> VariableOffset {
3824 let o = match o {
3825 gimli::UnitSectionOffset::DebugInfoOffset(o) => o,
3826 _ => panic!("unexpected offset {:?}", o),
3827 };
3828 VariableOffset::new(o.0)
3829 }
3830}
3831
3832fn parse_debug_info_offset<'input, Endian>(
3833 dwarf_unit: &DwarfUnit<'input, Endian>,
3834 attr: &gimli::Attribute<Reader<'input, Endian>>,
3835) -> Option<gimli::UnitSectionOffset>
3836where
3837 Endian: gimli::Endianity,
3838{
3839 match attr.value() {
3840 gimli::AttributeValue::UnitRef(offset) => Some(offset.to_unit_section_offset(dwarf_unit)),
3841 gimli::AttributeValue::DebugInfoRef(offset) => {
3842 Some(gimli::UnitSectionOffset::DebugInfoOffset(offset))
3843 }
3844 other => {
3845 debug!("unknown offset: {:?}", other);
3846 None
3847 }
3848 }
3849}
3850
3851fn parse_function_offset<'input, Endian>(
3852 dwarf_unit: &DwarfUnit<'input, Endian>,
3853 attr: &gimli::Attribute<Reader<'input, Endian>>,
3854) -> Option<FunctionOffset>
3855where
3856 Endian: gimli::Endianity,
3857{
3858 parse_debug_info_offset(dwarf_unit, attr).map(|x| x.into())
3859}
3860
3861fn parse_parameter_offset<'input, Endian>(
3862 dwarf_unit: &DwarfUnit<'input, Endian>,
3863 attr: &gimli::Attribute<Reader<'input, Endian>>,
3864) -> Option<ParameterOffset>
3865where
3866 Endian: gimli::Endianity,
3867{
3868 parse_debug_info_offset(dwarf_unit, attr).map(|x| x.into())
3869}
3870
3871fn parse_member_offset<'input, Endian>(
3872 dwarf_unit: &DwarfUnit<'input, Endian>,
3873 attr: &gimli::Attribute<Reader<'input, Endian>>,
3874) -> Option<MemberOffset>
3875where
3876 Endian: gimli::Endianity,
3877{
3878 parse_debug_info_offset(dwarf_unit, attr).map(|x| x.into())
3879}
3880
3881fn parse_type_offset<'input, Endian>(
3882 dwarf_unit: &DwarfUnit<'input, Endian>,
3883 attr: &gimli::Attribute<Reader<'input, Endian>>,
3884) -> Option<TypeOffset>
3885where
3886 Endian: gimli::Endianity,
3887{
3888 parse_debug_info_offset(dwarf_unit, attr).map(|x| x.into())
3889}
3890
3891fn parse_variable_offset<'input, Endian>(
3892 dwarf_unit: &DwarfUnit<'input, Endian>,
3893 attr: &gimli::Attribute<Reader<'input, Endian>>,
3894) -> Option<VariableOffset>
3895where
3896 Endian: gimli::Endianity,
3897{
3898 parse_debug_info_offset(dwarf_unit, attr).map(|x| x.into())
3899}
3900
3901fn parse_source_file<'input, Endian>(
3902 dwarf: &DwarfDebugInfo<'input, Endian>,
3903 dwarf_unit: &DwarfUnit<'input, Endian>,
3904 attr: &gimli::Attribute<Reader<'input, Endian>>,
3905 source: &mut Source<'input>,
3906) where
3907 Endian: gimli::Endianity,
3908{
3909 match attr.value() {
3910 gimli::AttributeValue::FileIndex(val) => {
3911 if val != 0 {
3912 if let Some(line) = &dwarf_unit.line_program {
3913 if let Some(entry) = line.header().file(val) {
3914 source.file = dwarf.string(dwarf_unit, entry.path_name());
3915 if let Some(directory) = entry.directory(line.header()) {
3916 source.directory = dwarf.string(dwarf_unit, directory);
3917 } else {
3918 debug!("invalid directory index {}", entry.directory_index());
3919 }
3920 } else {
3921 debug!("invalid file index {}", val);
3922 }
3923 }
3924 }
3925 }
3926 val => {
3927 debug!("unknown DW_AT_decl_file attribute value: {:?}", val);
3928 }
3929 }
3930}
3931
3932fn parse_source_line<Endian>(attr: &gimli::Attribute<Reader<Endian>>, source: &mut Source)
3933where
3934 Endian: gimli::Endianity,
3935{
3936 match attr.value() {
3937 gimli::AttributeValue::Udata(val) => {
3938 if val != 0 {
3939 if val <= u64::from(u32::MAX) {
3940 source.line = val as u32;
3941 } else {
3942 debug!("large source line: {}", val);
3943 }
3944 }
3945 }
3946 val => {
3947 debug!("unknown DW_AT_decl_line attribute value: {:?}", val);
3948 }
3949 }
3950}
3951
3952fn parse_source_column<Endian>(attr: &gimli::Attribute<Reader<Endian>>, source: &mut Source)
3953where
3954 Endian: gimli::Endianity,
3955{
3956 match attr.value() {
3957 gimli::AttributeValue::Udata(val) => {
3958 if val != 0 {
3959 if val <= u64::from(u32::MAX) {
3960 source.column = val as u32;
3961 } else {
3962 debug!("large source column: {}", val);
3963 }
3964 }
3965 }
3966 val => {
3967 debug!("unknown DW_AT_decl_column attribute value: {:?}", val);
3968 }
3969 }
3970}
3971
3972struct DwarfFrame<R: gimli::Reader<Offset = usize>> {
3973 debug_frame: DebugFrameTable<R>,
3974 eh_frame: EhFrameTable<R>,
3975}
3976
3977impl<R: gimli::Reader<Offset = usize>> DwarfFrame<R> {
3978 fn new(
3979 debug_frame: gimli::DebugFrame<R>,
3980 eh_frame: gimli::EhFrame<R>,
3981 bases: gimli::BaseAddresses,
3982 ) -> Self {
3983 DwarfFrame {
3984 debug_frame: DebugFrameTable::new(debug_frame),
3985 eh_frame: EhFrameTable::new(eh_frame, bases),
3986 }
3987 }
3988
3989 fn get_cfi(&self, range: Range) -> Option<Vec<Cfi>> {
3990 let cfi = self
3991 .eh_frame
3992 .get_cfi(range)
3993 .or_else(|| self.debug_frame.get_cfi(range));
3994 if cfi.is_none() {
3995 debug!("no FDE for 0x{:x}[0x{:x}]", range.begin, range.size());
3996 }
3997 cfi
3998 }
3999}
4000
4001struct DebugFrameTable<R: gimli::Reader<Offset = usize>> {
4002 debug_frame: gimli::DebugFrame<R>,
4003 bases: gimli::BaseAddresses,
4004 fdes: FdeOffsetTable,
4005}
4006
4007impl<R: gimli::Reader<Offset = usize>> DebugFrameTable<R> {
4008 fn new(debug_frame: gimli::DebugFrame<R>) -> Self {
4009 let bases = gimli::BaseAddresses::default();
4010 let fdes = FdeOffsetTable::new(&debug_frame, &bases);
4011 DebugFrameTable {
4012 debug_frame,
4013 bases,
4014 fdes,
4015 }
4016 }
4017
4018 fn get_cfi(&self, range: Range) -> Option<Vec<Cfi>> {
4019 get_cfi(&self.debug_frame, &self.bases, &self.fdes, range)
4020 }
4021}
4022
4023struct EhFrameTable<R: gimli::Reader<Offset = usize>> {
4024 eh_frame: gimli::EhFrame<R>,
4025 bases: gimli::BaseAddresses,
4026 fdes: FdeOffsetTable,
4027}
4028
4029impl<R: gimli::Reader<Offset = usize>> EhFrameTable<R> {
4030 fn new(eh_frame: gimli::EhFrame<R>, bases: gimli::BaseAddresses) -> Self {
4031 let fdes = FdeOffsetTable::new(&eh_frame, &bases);
4032 EhFrameTable {
4033 eh_frame,
4034 bases,
4035 fdes,
4036 }
4037 }
4038
4039 fn get_cfi(&self, range: Range) -> Option<Vec<Cfi>> {
4040 get_cfi(&self.eh_frame, &self.bases, &self.fdes, range)
4041 }
4042}
4043
4044struct FdeOffsetTable {
4045 offsets: Vec<(Range, usize)>,
4046}
4047
4048impl FdeOffsetTable {
4049 fn new<R: gimli::Reader<Offset = usize>, S: gimli::UnwindSection<R>>(
4050 section: &S,
4051 bases: &gimli::BaseAddresses,
4052 ) -> Self
4053 where
4054 S::Offset: gimli::UnwindOffset,
4055 {
4056 let mut offsets = Vec::new();
4057 let mut entries = section.entries(bases);
4058 while let Ok(Some(entry)) = entries.next() {
4059 match entry {
4060 gimli::CieOrFde::Cie(_) => {}
4061 gimli::CieOrFde::Fde(partial) => {
4062 if let Ok(fde) = partial.parse(S::cie_from_offset) {
4063 let range = Range {
4064 begin: fde.initial_address(),
4065 end: fde.initial_address() + fde.len(),
4066 };
4067 offsets.push((range, fde.offset()));
4068 }
4069 }
4070 }
4071 }
4072 offsets.sort_by_key(|x| x.0);
4073 FdeOffsetTable { offsets }
4074 }
4075
4076 fn find(&self, address: u64) -> Option<usize> {
4077 let index = match self.offsets.binary_search_by_key(&address, |x| x.0.begin) {
4079 Ok(x) => Some(x),
4080 Err(x) => {
4081 if x > 0 {
4082 Some(x - 1)
4083 } else {
4084 None
4085 }
4086 }
4087 };
4088 if let Some(index) = index {
4089 let (range, offset) = self.offsets[index];
4090 if range.begin <= address && range.end > address {
4091 return Some(offset);
4092 }
4093 }
4094 None
4095 }
4096}
4097
4098fn get_cfi<R: gimli::Reader, S: gimli::UnwindSection<R>>(
4099 section: &S,
4100 bases: &gimli::BaseAddresses,
4101 fdes: &FdeOffsetTable,
4102 range: Range,
4103) -> Option<Vec<Cfi>>
4104where
4105 S::Offset: gimli::UnwindOffset,
4106{
4107 let address = range.begin;
4108 let size = range.size();
4109 let fde_offset = S::Offset::from(fdes.find(address)?);
4110 let fde = section
4111 .fde_from_offset(bases, fde_offset, S::cie_from_offset)
4112 .ok()?;
4113
4114 if (address, size) != (fde.initial_address(), fde.len()) {
4115 debug!(
4116 "FDE address mismatch: want function 0x{:x}[0x{:x}], found FDE 0x{:x}[0x{:x}]",
4117 address,
4118 size,
4119 fde.initial_address(),
4120 fde.len(),
4121 );
4122 }
4123
4124 let mut cfi = Vec::new();
4125 cfi.push((Address::none(), CfiDirective::StartProc));
4126 if let Some(personality) = fde.personality() {
4127 let address = match personality {
4129 gimli::Pointer::Direct(x) => Address::new(x),
4130 gimli::Pointer::Indirect(x) => Address::new(x),
4131 };
4132 cfi.push((Address::none(), CfiDirective::Personality(address)));
4133 }
4134 if let Some(lsda) = fde.lsda() {
4135 let address = match lsda {
4137 gimli::Pointer::Direct(x) => Address::new(x),
4138 gimli::Pointer::Indirect(x) => Address::new(x),
4139 };
4140 cfi.push((Address::none(), CfiDirective::Lsda(address)));
4141 }
4142 if fde.is_signal_trampoline() {
4143 cfi.push((Address::none(), CfiDirective::SignalFrame));
4144 }
4145
4146 let cie = fde.cie();
4147 let mut address = 0;
4148 let mut instructions = cie.instructions(section, bases);
4149 while let Ok(Some(instruction)) = instructions.next() {
4150 if let Some(directive) = convert_cfi(cie, instruction, &mut address) {
4151 cfi.push((Address::none(), directive))
4152 }
4153 }
4154
4155 let mut address = fde.initial_address();
4156 let mut instructions = fde.instructions(section, bases);
4157 while let Ok(Some(instruction)) = instructions.next() {
4158 if let Some(directive) = convert_cfi(cie, instruction, &mut address) {
4159 cfi.push((Address::new(address), directive))
4160 }
4161 }
4162
4163 cfi.push((
4164 Address::new(fde.initial_address() + fde.len()),
4165 CfiDirective::EndProc,
4166 ));
4167 Some(cfi)
4168}
4169
4170fn convert_cfi<R: gimli::Reader>(
4171 cie: &gimli::CommonInformationEntry<R>,
4172 instruction: gimli::CallFrameInstruction<R::Offset>,
4173 loc: &mut u64,
4174) -> Option<CfiDirective> {
4175 match instruction {
4176 gimli::CallFrameInstruction::SetLoc { address } => {
4177 *loc = address;
4178 None
4179 }
4180 gimli::CallFrameInstruction::AdvanceLoc { delta } => {
4181 *loc += delta as u64 * cie.code_alignment_factor();
4182 None
4183 }
4184 gimli::CallFrameInstruction::DefCfa { register, offset } => {
4185 Some(CfiDirective::DefCfa(register.into(), offset as i64))
4186 }
4187 gimli::CallFrameInstruction::DefCfaSf {
4188 register,
4189 factored_offset,
4190 } => {
4191 let offset = factored_offset * cie.data_alignment_factor();
4192 Some(CfiDirective::DefCfa(register.into(), offset))
4193 }
4194 gimli::CallFrameInstruction::DefCfaRegister { register } => {
4195 Some(CfiDirective::DefCfaRegister(register.into()))
4196 }
4197 gimli::CallFrameInstruction::DefCfaOffset { offset } => {
4198 Some(CfiDirective::DefCfaOffset(offset as i64))
4199 }
4200 gimli::CallFrameInstruction::DefCfaOffsetSf { factored_offset } => {
4201 let offset = factored_offset * cie.data_alignment_factor();
4202 Some(CfiDirective::DefCfaOffset(offset))
4203 }
4204 gimli::CallFrameInstruction::Offset {
4205 register,
4206 factored_offset,
4207 } => {
4208 let offset = factored_offset as i64 * cie.data_alignment_factor();
4209 Some(CfiDirective::Offset(register.into(), offset))
4210 }
4211 gimli::CallFrameInstruction::OffsetExtendedSf {
4212 register,
4213 factored_offset,
4214 } => {
4215 let offset = factored_offset * cie.data_alignment_factor();
4216 Some(CfiDirective::Offset(register.into(), offset))
4217 }
4218 gimli::CallFrameInstruction::ValOffset {
4219 register,
4220 factored_offset,
4221 } => {
4222 let offset = factored_offset as i64 * cie.data_alignment_factor();
4223 Some(CfiDirective::ValOffset(register.into(), offset))
4224 }
4225 gimli::CallFrameInstruction::ValOffsetSf {
4226 register,
4227 factored_offset,
4228 } => {
4229 let offset = factored_offset * cie.data_alignment_factor();
4230 Some(CfiDirective::ValOffset(register.into(), offset))
4231 }
4232 gimli::CallFrameInstruction::Register {
4233 dest_register,
4234 src_register,
4235 } => Some(CfiDirective::Register(
4236 dest_register.into(),
4237 src_register.into(),
4238 )),
4239 gimli::CallFrameInstruction::Undefined { register } => {
4240 Some(CfiDirective::Undefined(register.into()))
4241 }
4242 gimli::CallFrameInstruction::SameValue { register } => {
4243 Some(CfiDirective::SameValue(register.into()))
4244 }
4245 gimli::CallFrameInstruction::Restore { register } => {
4246 Some(CfiDirective::Restore(register.into()))
4247 }
4248 gimli::CallFrameInstruction::RememberState => Some(CfiDirective::RememberState),
4249 gimli::CallFrameInstruction::RestoreState => Some(CfiDirective::RestoreState),
4250 gimli::CallFrameInstruction::Nop => None,
4251 _ => {
4252 debug!("Unhandled CFI: {:?}", instruction);
4253 Some(CfiDirective::Other)
4254 }
4255 }
4256}