ddbug_parser/file/
dwarf.rs

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                        // Use the explicit addend too, because it may have the symbol value.
124                        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    // All remaining methods simply delegate to `self.reader`.
182
183    #[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        // FIXME: make this more efficient for large numbers of units
285        // FIXME: cache lookups
286        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, &section);
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    // Find ranges from attributes in order of preference:
508    // DW_AT_stmt_list, DW_AT_ranges, DW_AT_high_pc, DW_AT_size.
509    // TODO: include variables in ranges.
510    // TODO: copy logic from addr2line
511    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                    // Sequences starting at 0 are probably invalid.
519                    // TODO: is this always desired?
520                    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    // Ignore low_pc attribute if there is any range.
558    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    // Convert functions to BTreeMap
596    // TODO: it'd be cleaner if parse_subprogram() added functions to a BTreeMap initially,
597    // so that we didn't have to keep updating it.
598    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            // And keep going, because parse_subprogram_children() may have added more.
661        }
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    // Convert variables to BTreeMap
679    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                    // Delay handling specification in case it comes later.
771                    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
839/*
840fn is_type_tag(tag: gimli::DwTag) -> bool {
841    match tag {
842        gimli::DW_TAG_typedef |
843        gimli::DW_TAG_class_type | gimli::DW_TAG_structure_type |
844        gimli::DW_TAG_union_type |
845        gimli::DW_TAG_enumeration_type |
846        gimli::DW_TAG_unspecified_type |
847        gimli::DW_TAG_base_type |
848        gimli::DW_TAG_array_type |
849        gimli::DW_TAG_subroutine_type |
850        gimli::DW_TAG_ptr_to_member_type |
851        gimli::DW_TAG_pointer_type |
852        gimli::DW_TAG_reference_type |
853        gimli::DW_TAG_const_type |
854        gimli::DW_TAG_packed_type |
855        gimli::DW_TAG_volatile_type |
856        gimli::DW_TAG_restrict_type |
857        gimli::DW_TAG_shared_type |
858        gimli::DW_TAG_rvalue_reference_type |
859        gimli::DW_TAG_atomic_type => true,
860        _ => false,
861    }
862}
863*/
864
865fn 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        // TODO: distinguish between class and structure
886        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        // Parse unnamed types for validation, but don't store them.
920        _ => 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                // Treat any members in the variant_part the same as any other member.
1399                // TODO: maybe set a field to indicate which variant part it belongs to.
1400                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            // subrange type encountered here for Ada.
1466            // TODO: not sure which types are valid here.
1467            // Maybe need to call parse_type(), but don't have all the parameters
1468            // needed for it yet.
1469            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    // Rust uses a single struct member for its variants, and the size of this
1479    // struct is set to be the same as the size of the enum. This makes it hard
1480    // to see the exact layout of the enum, so it's more helpful to treat the
1481    // struct members as being owned by the variant instead.
1482    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                    // Rust gives the struct a name that matches the variant.
1490                    if let Some(attr) = node.entry().attr_value(gimli::DW_AT_name)? {
1491                        variant.name = dwarf.string(dwarf_unit, attr);
1492                    }
1493
1494                    // Parse the struct's members as our own.
1495                    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        // This is a C++ static data member. Parse it as a variable instead.
1593        // Note: the DWARF 5 standard says static members should use DW_TAG_variable,
1594        // but at least clang 3.7.1 uses DW_TAG_member.
1595        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        // DWARF version 2/3, but allowed in later versions for compatibility.
1608        // The data member is a bit field contained in an anonymous object.
1609        // member.bit_offset starts as the offset of the anonymous object.
1610        // byte_size is the size of the anonymous object.
1611        // bit_offset is the offset from the anonymous object MSB to the bit field MSB.
1612        // bit_size is the size of the bit field.
1613        if dwarf.endian.is_big_endian() {
1614            // For big endian, the MSB is the first bit, so we simply add bit_offset,
1615            // and byte_size is unneeded.
1616            member.bit_offset = member.bit_offset.wrapping_add(bit_offset);
1617        } else {
1618            // For little endian, we have to work backwards, so we need byte_size.
1619            if let Some(byte_size) = byte_size {
1620                // First find the offset of the MSB of the anonymous object.
1621                member.bit_offset = member.bit_offset.wrapping_add(byte_size * 8);
1622                // Then go backwards to the LSB of the bit field.
1623                member.bit_offset = member
1624                    .bit_offset
1625                    .wrapping_sub(bit_offset.wrapping_add(bit_size));
1626            } else {
1627                // DWARF version 2/3 says the byte_size can be inferred,
1628                // but it is unclear when this would be useful.
1629                // Delay implementing this until needed.
1630                debug!("missing byte_size for bit field offset");
1631            }
1632        }
1633    } else if byte_size.is_some() {
1634        // TODO: should this set member.bit_size?
1635        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                // HACK: while gimli is technically correct, in my experience this
1720                // is more likely to be a constant. This can happen for large
1721                // structs.
1722                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                        // TODO: use default lower bound for language
1935                        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                    // Unknown dimensions.
1947                    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    // TODO: lower bound default should depend on language
1972    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        // Go treats subroutine types as pointers.
2040        // Not sure if this is valid for all languages.
2041        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                // FIXME
2265            }
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        // We inherit all children, and then extend them when parsing our children.
2374        function.parameters = specification.parameters.clone();
2375    } else {
2376        // TODO: inherit children from specifications?
2377    }
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                // Handled in details.
2406            }
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        // TODO: use a hash?
2517        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                            // TODO: use location.range too
2594                            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        // TODO: use a hash?
2633        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(&parameter.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                // Handled in details.
2701            }
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
2751// Only checks for unknown attributes and tags.
2752fn 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                // Handled in details.
2761            }
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
2777// Only checks for unknown attributes and tags.
2778fn 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    // FIXME: limit recursion
2846    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            // Checking for unknown tags is done in `parse_subprogram_children`.
2894            _ => {}
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    // Checking for unknown attributes is done in `parse_lexical_block`.
2912
2913    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            // Checking for unknown tags is done in `parse_lexical_block`.
2935            _ => {}
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                            // TODO: use location.range too
3220                            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        // TODO: use a hash?
3257        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            // This happens a lot, not sure if bugs or bad DWARF.
3371            //debug!("simple evaluation failed: {}: {:?}", _e, expression.0);
3372            return;
3373        }
3374    };
3375
3376    for piece in &pieces {
3377        if piece.is_value {
3378            continue;
3379        }
3380        // Can this be Literal too?
3381        if let Location::Address { address } = piece.location {
3382            if variable.address.is_some() {
3383                if address != variable.address {
3384                    // TODO: combine address ranges?
3385                    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            // This happens a lot, not sure if bugs or bad DWARF.
3416            //debug!("simple evaluation failed: {}: {:?}", _e, expression.0);
3417            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                // Unimplemented.
3480                location = Some((Location::Other, true));
3481            }
3482            gimli::Operation::ImplicitPointer { .. } => {
3483                // Unimplemented.
3484                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                // Unimplemented.
3494                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                // TODO: compare this against CFA, and push CfaOffset instead if it matches
3508                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                // Unimplemented.
3526                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                        // Seen in practice, but we can't handle this yet.
3610                        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                        // Seen in practice, but we can't handle this yet.
3625                        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                // Unimplemented unary operations.
3644                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                // Unimplemented binary operations.
3663                pop(&mut stack)?;
3664                pop(&mut stack)?;
3665                stack.push(Location::Other);
3666            }
3667            gimli::Operation::Deref { space, .. } => {
3668                // Unimplemented.
3669                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                // Unimplemented.
3679                // We can't even push Location::Other for Bra.
3680                // Skip and Call could be implemented if needed.
3681                return Ok(pieces);
3682            }
3683            gimli::Operation::WasmLocal { .. }
3684            | gimli::Operation::WasmGlobal { .. }
3685            | gimli::Operation::WasmStack { .. } => {
3686                // Unimplemented.
3687                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        // FIXME: doesn't handle overlapping
4078        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        // TODO: better handling of indirect
4128        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        // TODO: better handling of indirect
4136        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}