stackdump_trace/variables/type_value_tree_building/
enumeration.rs

1use crate::{
2    error::TraceError,
3    get_entry_type_reference_tree_recursive,
4    gimli_extensions::{AttributeExt, DebuggingInformationEntryExt},
5    type_value_tree::{
6        value::Value,
7        variable_type::{Archetype, VariableType},
8        TypeValue, TypeValueTree,
9    },
10    variables::{build_type_value_tree, get_entry_name},
11    DefaultReader,
12};
13use gimli::{Abbreviations, DebugInfoOffset, Dwarf, Unit};
14use std::collections::HashMap;
15
16pub fn build_enumeration<W: funty::Integral>(
17    dwarf: &Dwarf<DefaultReader>,
18    unit: &Unit<DefaultReader, usize>,
19    abbreviations: &Abbreviations,
20    node: gimli::EntriesTreeNode<DefaultReader>,
21    type_cache: &mut HashMap<DebugInfoOffset, Result<TypeValueTree<W>, TraceError>>,
22) -> Result<TypeValueTree<W>, TraceError> {
23    let mut type_value_tree = TypeValueTree::new(TypeValue::default());
24    let mut type_value = type_value_tree.root_mut();
25    let entry = node.entry();
26
27    // This is an enum type (like a C-style enum).
28    // Enums have a name and also an underlying_type (which is usually an integer).
29    // The entry also has a child `DW_TAG_enumerator` for each variant.
30
31    let name = get_entry_name(dwarf, unit, entry)?;
32
33    get_entry_type_reference_tree_recursive!(
34        underlying_type_tree = (dwarf, unit, abbreviations, entry)
35    );
36    let mut underlying_type_tree = underlying_type_tree.map(|mut type_tree| {
37        type_tree
38            .root()
39            .map(|root| build_type_value_tree(dwarf, unit, abbreviations, root, type_cache))
40    })???;
41    underlying_type_tree.root_mut().data_mut().name = "base".into();
42    let underlying_type_bitrange = underlying_type_tree.root().data().bit_range.clone();
43
44    type_value.data_mut().variable_type.name = name;
45    type_value.data_mut().variable_type.archetype = Archetype::Enumeration;
46    type_value.data_mut().bit_range = underlying_type_bitrange.clone();
47
48    type_value.push_back(underlying_type_tree);
49
50    let mut children = node.children();
51    while let Ok(Some(child)) = children.next() {
52        let enumerator_entry = child.entry();
53
54        // Each child is a DW_TAG_enumerator or DW_TAG_subprogram
55        if enumerator_entry.tag() != gimli::constants::DW_TAG_enumerator {
56            continue;
57        }
58
59        // Each variant has a name and an integer value.
60        // If the enum has that value, then the enum is of that variant.
61        // This does of course not work for flag enums.
62
63        let enumerator_name = get_entry_name(dwarf, unit, enumerator_entry)?;
64        let const_value = enumerator_entry
65            .required_attr(&unit.header, gimli::constants::DW_AT_const_value)?
66            .required_sdata_value()?;
67
68        type_value.push_back(TypeValueTree::new(TypeValue {
69            name: enumerator_name,
70            variable_type: VariableType {
71                archetype: Archetype::Enumerator,
72                ..Default::default()
73            },
74            bit_range: underlying_type_bitrange.clone(),
75            variable_value: Ok(Value::Int(const_value as i128)),
76        }));
77    }
78
79    Ok(type_value_tree)
80}