Skip to main content

padlock_dwarf/
type_resolver.rs

1// padlock-dwarf/src/type_resolver.rs
2
3use gimli::{Reader, Unit, UnitOffset};
4use padlock_core::ir::TypeInfo;
5
6use crate::extractor::Extractor;
7
8impl<'a, R: Reader> Extractor<'a, R> {
9    /// Follow a type reference and return (size, align, TypeInfo).
10    pub fn resolve_type(
11        &self,
12        unit: &Unit<R>,
13        offset: UnitOffset<R::Offset>,
14    ) -> anyhow::Result<(usize, usize, TypeInfo)> {
15        let mut entries = unit.entries_at_offset(offset)?;
16        let (_, entry) = entries
17            .next_dfs()?
18            .ok_or_else(|| anyhow::anyhow!("no DIE at offset"))?;
19
20        match entry.tag() {
21            gimli::DW_TAG_base_type => {
22                let name = self
23                    .attr_string(unit, entry, gimli::DW_AT_name)?
24                    .unwrap_or_default();
25                let size = self.attr_usize(entry, gimli::DW_AT_byte_size)?.unwrap_or(0);
26                let align = self
27                    .attr_usize(entry, gimli::DW_AT_alignment)?
28                    .unwrap_or(size);
29
30                Ok((size, align, TypeInfo::Primitive { name, size, align }))
31            }
32
33            gimli::DW_TAG_pointer_type | gimli::DW_TAG_reference_type => {
34                let size = self.arch.pointer_size;
35                Ok((size, size, TypeInfo::Pointer { size, align: size }))
36            }
37
38            gimli::DW_TAG_typedef => {
39                let inner_offset = match entry.attr_value(gimli::DW_AT_type)? {
40                    Some(gimli::AttributeValue::UnitRef(off)) => off,
41                    _ => return Err(anyhow::anyhow!("typedef with no type")),
42                };
43                self.resolve_type(unit, inner_offset)
44            }
45
46            gimli::DW_TAG_const_type
47            | gimli::DW_TAG_volatile_type
48            | gimli::DW_TAG_restrict_type => {
49                let inner_offset = match entry.attr_value(gimli::DW_AT_type)? {
50                    Some(gimli::AttributeValue::UnitRef(off)) => off,
51                    _ => return Err(anyhow::anyhow!("qualifier with no type")),
52                };
53                self.resolve_type(unit, inner_offset)
54            }
55
56            gimli::DW_TAG_array_type => {
57                let elem_offset = match entry.attr_value(gimli::DW_AT_type)? {
58                    Some(gimli::AttributeValue::UnitRef(off)) => off,
59                    _ => return Err(anyhow::anyhow!("array with no element type")),
60                };
61                let (elem_size, elem_align, elem_ty) = self.resolve_type(unit, elem_offset)?;
62
63                let count = self.extract_array_count(unit, entry)?;
64                let total = elem_size * count;
65
66                Ok((
67                    total,
68                    elem_align,
69                    TypeInfo::Array {
70                        element: Box::new(elem_ty),
71                        count,
72                        size: total,
73                        align: elem_align,
74                    },
75                ))
76            }
77
78            gimli::DW_TAG_structure_type => {
79                if let Some(layout) = self.extract_struct(unit, entry)? {
80                    let size = layout.total_size;
81                    let align = layout.align;
82                    Ok((size, align, TypeInfo::Struct(Box::new(layout))))
83                } else {
84                    let size = self.attr_usize(entry, gimli::DW_AT_byte_size)?.unwrap_or(0);
85                    Ok((
86                        size,
87                        size,
88                        TypeInfo::Opaque {
89                            name: "<incomplete>".to_string(),
90                            size,
91                            align: size,
92                        },
93                    ))
94                }
95            }
96
97            gimli::DW_TAG_enumeration_type => {
98                let size = self.attr_usize(entry, gimli::DW_AT_byte_size)?.unwrap_or(4);
99                let name = self
100                    .attr_string(unit, entry, gimli::DW_AT_name)?
101                    .unwrap_or_default();
102                Ok((
103                    size,
104                    size,
105                    TypeInfo::Opaque {
106                        name,
107                        size,
108                        align: size,
109                    },
110                ))
111            }
112
113            _ => {
114                let size = self.attr_usize(entry, gimli::DW_AT_byte_size)?.unwrap_or(0);
115                Ok((
116                    size,
117                    size,
118                    TypeInfo::Opaque {
119                        name: format!("<{:?}>", entry.tag()),
120                        size,
121                        align: size,
122                    },
123                ))
124            }
125        }
126    }
127}