Skip to main content

type_crawler/types/
struct_decl.rs

1use std::fmt::Display;
2
3use crate::{
4    Env, Field, TypeKind, Types,
5    error::{
6        AlignofSnafu, InvalidAstSnafu, InvalidFieldsSnafu, OffsetofSnafu, ParseError, SizeofSnafu,
7        UnsupportedEntitySnafu, UnsupportedTypeSnafu,
8    },
9};
10
11#[derive(Debug, Clone, PartialEq, Eq)]
12pub struct StructDecl {
13    pub(crate) name: Option<String>,
14    pub(crate) base_types: Vec<String>,
15    pub(crate) fields: Vec<StructField>,
16    size: usize,
17    alignment: usize,
18    is_class: bool,
19}
20
21#[derive(Debug, Clone, PartialEq, Eq)]
22pub struct StructField {
23    /// Offset in bits
24    offset: usize,
25    field: Field,
26}
27
28impl StructDecl {
29    pub fn new(
30        env: &Env,
31        types: &Types,
32        name: Option<String>,
33        ty: clang::Type,
34    ) -> Result<Self, ParseError> {
35        if ty.get_kind() != clang::TypeKind::Record {
36            return InvalidAstSnafu { message: format!("Expected Record, found: {ty:?}") }.fail();
37        }
38
39        let mut base_types = Vec::new();
40        let Some(node) = ty.get_declaration() else {
41            return InvalidAstSnafu { message: format!("Record type without declaration: {ty:?}") }
42                .fail();
43        };
44        for child in node.get_children() {
45            if child.get_kind() != clang::EntityKind::BaseSpecifier {
46                continue;
47            }
48            let base_type = child.get_type().ok_or_else(|| {
49                InvalidAstSnafu { message: format!("BaseSpecifier without type: {child:?}") }
50                    .build()
51            })?;
52            let base_name = base_type.get_display_name();
53            base_types.push(base_name);
54        }
55
56        let is_class = node.get_kind() == clang::EntityKind::ClassDecl;
57
58        let display_name = name.as_deref().unwrap_or("<anon>");
59
60        let record_fields = ty.get_fields().ok_or_else(|| {
61            UnsupportedTypeSnafu { message: format!("Record type without fields: {ty:?}") }.build()
62        })?;
63        if record_fields.is_empty() {
64            let declaration = ty.get_declaration().ok_or_else(|| {
65                InvalidAstSnafu { message: format!("Record type without declaration: {ty:?}") }
66                    .build()
67            })?;
68
69            let decl_children = declaration.get_children();
70            let invalid_fields = decl_children
71                .iter()
72                .enumerate()
73                .filter(|(_, c)| {
74                    c.get_kind() == clang::EntityKind::FieldDecl && c.is_invalid_declaration()
75                })
76                .collect::<Vec<_>>();
77            if !invalid_fields.is_empty() {
78                return InvalidFieldsSnafu {
79                    field_names: invalid_fields
80                        .iter()
81                        .map(|(i, c)| c.get_name().unwrap_or_else(|| format!("<index#{i}>")))
82                        .collect::<Vec<_>>(),
83                    struct_name: display_name.to_string(),
84                }
85                .fail();
86            }
87        }
88
89        let mut fields = Vec::<StructField>::new();
90        for field in &record_fields {
91            match field.get_kind() {
92                clang::EntityKind::FieldDecl => {
93                    let offset = Self::get_offset_of_field(display_name, field)?;
94                    fields.push(StructField { offset, field: Field::new(env, types, field)? });
95                }
96                _ => {
97                    return UnsupportedEntitySnafu {
98                        at: format!("struct/class {display_name}"),
99                        message: format!(
100                            "Unsupported entity kind in struct/class: {:?}",
101                            field.get_kind()
102                        ),
103                    }
104                    .fail();
105                }
106            }
107        }
108
109        let size = ty.get_sizeof().or_else(|e| {
110            if record_fields.is_empty() {
111                Ok(1)
112            } else {
113                SizeofSnafu { type_name: display_name.to_string(), error: e }.fail()
114            }
115        })?;
116        let alignment = ty.get_alignof().or_else(|e| {
117            if record_fields.is_empty() {
118                Ok(1)
119            } else {
120                AlignofSnafu { type_name: display_name.to_string(), error: e }.fail()
121            }
122        })?;
123
124        Ok(Self { name, base_types, fields, size, alignment, is_class })
125    }
126
127    fn get_offset_of_field(struct_name: &str, node: &clang::Entity) -> Result<usize, ParseError> {
128        node.get_offset_of_field().map_err(|e| {
129            OffsetofSnafu {
130                field_name: node.get_name().unwrap_or_default(),
131                struct_name: struct_name.to_string(),
132                error: e,
133            }
134            .build()
135        })
136    }
137
138    pub fn size(&self) -> usize {
139        self.size
140    }
141
142    pub fn alignment(&self) -> usize {
143        self.alignment
144    }
145
146    pub fn is_forward_decl(&self) -> bool {
147        self.fields.is_empty()
148    }
149
150    pub fn base_types(&self) -> &[String] {
151        &self.base_types
152    }
153
154    pub fn fields(&self) -> &[StructField] {
155        &self.fields
156    }
157
158    pub fn get_field<'a>(&'a self, types: &'a Types, name: &str) -> Option<&'a StructField> {
159        self.fields.iter().find(|f| f.name() == Some(name)).or_else(|| {
160            self.base_types
161                .iter()
162                .filter_map(|base| types.get(base))
163                .filter_map(|base| base.expand_named(types))
164                .filter_map(|base| match base {
165                    TypeKind::Struct(struct_decl) => struct_decl.get_field(types, name),
166                    TypeKind::Class(class_decl) => class_decl.get_field(types, name),
167                    _ => None,
168                })
169                .next()
170        })
171    }
172
173    pub fn name(&self) -> Option<&str> {
174        self.name.as_deref()
175    }
176
177    pub fn is_class(&self) -> bool {
178        self.is_class
179    }
180}
181
182impl StructField {
183    pub fn offset_bytes(&self) -> usize {
184        self.offset / 8
185    }
186
187    pub fn offset_bits(&self) -> usize {
188        self.offset
189    }
190
191    pub fn name(&self) -> Option<&str> {
192        self.field.name()
193    }
194
195    pub fn kind(&self) -> &super::TypeKind {
196        self.field.kind()
197    }
198
199    pub fn constant(&self) -> bool {
200        self.field.constant()
201    }
202
203    pub fn volatile(&self) -> bool {
204        self.field.volatile()
205    }
206
207    pub fn bit_field_width(&self) -> Option<u8> {
208        self.field.bit_field_width()
209    }
210
211    pub fn size(&self, types: &Types) -> usize {
212        self.field.size(types)
213    }
214}
215
216impl Display for StructDecl {
217    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
218        write!(f, "{}", self.name.as_deref().unwrap_or("<anon>"))?;
219        if !self.base_types.is_empty() {
220            write!(f, " : ")?;
221            let mut iter = self.base_types.iter();
222            write!(f, "{}", iter.next().unwrap())?;
223            for base in iter {
224                write!(f, ", {base}")?;
225            }
226        }
227        writeln!(f, " {{")?;
228        for field in &self.fields {
229            writeln!(f, "  ({:#x}) {}", field.offset_bytes(), field.field)?;
230        }
231        write!(f, "}}")?;
232        Ok(())
233    }
234}