1use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::fmt;
10
11#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13pub enum TypeInfo {
14 BaseType {
16 name: String,
17 size: u64,
18 encoding: u16, },
20
21 PointerType {
23 target_type: Box<TypeInfo>,
24 size: u64,
25 },
26
27 ArrayType {
29 element_type: Box<TypeInfo>,
30 element_count: Option<u64>,
31 total_size: Option<u64>,
32 },
33
34 StructType {
36 name: String,
37 size: u64,
38 members: Vec<StructMember>,
39 },
40
41 UnionType {
43 name: String,
44 size: u64,
45 members: Vec<StructMember>,
46 },
47
48 EnumType {
50 name: String,
51 size: u64,
52 base_type: Box<TypeInfo>,
53 variants: Vec<EnumVariant>,
54 },
55
56 TypedefType {
58 name: String,
59 underlying_type: Box<TypeInfo>,
60 },
61
62 QualifiedType {
64 qualifier: TypeQualifier,
65 underlying_type: Box<TypeInfo>,
66 },
67
68 FunctionType {
70 return_type: Option<Box<TypeInfo>>,
71 parameters: Vec<TypeInfo>,
72 },
73
74 BitfieldType {
76 underlying_type: Box<TypeInfo>,
77 bit_offset: u8,
78 bit_size: u8,
79 },
80
81 UnknownType { name: String },
83
84 OptimizedOut { name: String },
86}
87
88#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
90pub struct StructMember {
91 pub name: String,
92 pub member_type: TypeInfo,
93 pub offset: u64,
94 pub bit_offset: Option<u8>,
95 pub bit_size: Option<u8>,
96}
97
98#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
100pub struct EnumVariant {
101 pub name: String,
102 pub value: i64,
103}
104
105#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
107pub enum TypeQualifier {
108 Const,
109 Volatile,
110 Restrict,
111}
112
113impl TypeInfo {
114 pub fn size(&self) -> u64 {
116 match self {
117 TypeInfo::BaseType { size, .. } => *size,
118 TypeInfo::PointerType { size, .. } => *size,
119 TypeInfo::ArrayType { total_size, .. } => total_size.unwrap_or(0),
120 TypeInfo::StructType { size, .. } => *size,
121 TypeInfo::UnionType { size, .. } => *size,
122 TypeInfo::EnumType { size, .. } => *size,
123 TypeInfo::TypedefType {
124 underlying_type, ..
125 } => underlying_type.size(),
126 TypeInfo::QualifiedType {
127 underlying_type, ..
128 } => underlying_type.size(),
129 TypeInfo::FunctionType { .. } => 8, TypeInfo::BitfieldType {
131 underlying_type, ..
132 } => underlying_type.size(),
133 TypeInfo::UnknownType { .. } => 0,
134 TypeInfo::OptimizedOut { .. } => 0, }
136 }
137
138 fn format_base_type(name: &str, size: u64, encoding: u16) -> (String, String) {
140 let human_readable = if encoding == gimli::constants::DW_ATE_boolean.0 as u16 {
141 "bool".to_string()
142 } else if encoding == gimli::constants::DW_ATE_float.0 as u16 {
143 match size {
144 4 => "f32".to_string(),
145 8 => "f64".to_string(),
146 _ => format!("float{size}"),
147 }
148 } else if encoding == gimli::constants::DW_ATE_signed.0 as u16
149 || encoding == gimli::constants::DW_ATE_signed_char.0 as u16
150 {
151 match size {
152 1 => "i8".to_string(),
153 2 => "i16".to_string(),
154 4 => "i32".to_string(),
155 8 => "i64".to_string(),
156 _ => format!("i{}", size * 8),
157 }
158 } else if encoding == gimli::constants::DW_ATE_unsigned.0 as u16
159 || encoding == gimli::constants::DW_ATE_unsigned_char.0 as u16
160 {
161 match size {
162 1 => "u8".to_string(),
163 2 => "u16".to_string(),
164 4 => "u32".to_string(),
165 8 => "u64".to_string(),
166 _ => format!("u{}", size * 8),
167 }
168 } else {
169 name.to_string()
170 };
171
172 let encoding_str = if encoding == gimli::constants::DW_ATE_signed.0 as u16 {
173 "signed"
174 } else if encoding == gimli::constants::DW_ATE_unsigned.0 as u16 {
175 "unsigned"
176 } else if encoding == gimli::constants::DW_ATE_float.0 as u16 {
177 "float"
178 } else if encoding == gimli::constants::DW_ATE_boolean.0 as u16 {
179 "bool"
180 } else if encoding == gimli::constants::DW_ATE_address.0 as u16 {
181 "address"
182 } else if encoding == gimli::constants::DW_ATE_signed_char.0 as u16 {
183 "signed char"
184 } else if encoding == gimli::constants::DW_ATE_unsigned_char.0 as u16 {
185 "unsigned char"
186 } else {
187 "unknown"
188 };
189
190 (human_readable, encoding_str.to_string())
191 }
192
193 fn format_qualifier(qualifier: &TypeQualifier) -> &'static str {
195 match qualifier {
196 TypeQualifier::Const => "const",
197 TypeQualifier::Volatile => "volatile",
198 TypeQualifier::Restrict => "restrict",
199 }
200 }
201
202 pub fn type_name(&self) -> String {
204 match self {
205 TypeInfo::BaseType { name, .. } => name.clone(),
206 TypeInfo::PointerType { target_type, .. } => {
207 format!("{}*", target_type.type_name())
208 }
209 TypeInfo::ArrayType {
210 element_type,
211 element_count,
212 ..
213 } => {
214 if let Some(count) = element_count {
215 format!("{}[{}]", element_type.type_name(), count)
216 } else {
217 format!("{}[]", element_type.type_name())
218 }
219 }
220 TypeInfo::StructType { name, .. } => format!("struct {name}"),
221 TypeInfo::UnionType { name, .. } => format!("union {name}"),
222 TypeInfo::EnumType { name, .. } => format!("enum {name}"),
223 TypeInfo::TypedefType { name, .. } => name.clone(),
224 TypeInfo::QualifiedType {
225 qualifier,
226 underlying_type,
227 } => {
228 format!(
229 "{} {}",
230 Self::format_qualifier(qualifier),
231 underlying_type.type_name()
232 )
233 }
234 TypeInfo::FunctionType {
235 return_type,
236 parameters,
237 } => {
238 let return_str = return_type
239 .as_ref()
240 .map(|t| t.type_name())
241 .unwrap_or_else(|| "void".to_string());
242 let param_str = parameters
243 .iter()
244 .map(|p| p.type_name())
245 .collect::<Vec<_>>()
246 .join(", ");
247 format!("{return_str} ({param_str})")
248 }
249 TypeInfo::BitfieldType {
250 underlying_type,
251 bit_offset,
252 bit_size,
253 } => format!(
254 "bitfield<{}:{}> {}",
255 bit_offset,
256 bit_size,
257 underlying_type.type_name()
258 ),
259 TypeInfo::UnknownType { name } => name.clone(),
260 TypeInfo::OptimizedOut { name } => format!("<optimized_out> {name}"),
261 }
262 }
263
264 pub fn is_signed_int(&self) -> bool {
266 match self {
267 TypeInfo::BaseType { encoding, .. } => {
268 *encoding == gimli::constants::DW_ATE_signed.0 as u16
269 }
270 TypeInfo::TypedefType {
271 underlying_type, ..
272 } => underlying_type.is_signed_int(),
273 TypeInfo::QualifiedType {
274 underlying_type, ..
275 } => underlying_type.is_signed_int(),
276 TypeInfo::BitfieldType {
277 underlying_type, ..
278 } => underlying_type.is_signed_int(),
279 TypeInfo::OptimizedOut { .. } => false,
280 _ => false,
281 }
282 }
283
284 pub fn is_unsigned_int(&self) -> bool {
286 match self {
287 TypeInfo::BaseType { encoding, .. } => {
288 *encoding == gimli::constants::DW_ATE_unsigned.0 as u16
289 }
290 TypeInfo::TypedefType {
291 underlying_type, ..
292 } => underlying_type.is_unsigned_int(),
293 TypeInfo::QualifiedType {
294 underlying_type, ..
295 } => underlying_type.is_unsigned_int(),
296 TypeInfo::BitfieldType {
297 underlying_type, ..
298 } => underlying_type.is_unsigned_int(),
299 TypeInfo::OptimizedOut { .. } => false,
300 _ => false,
301 }
302 }
303
304 pub fn is_float(&self) -> bool {
306 match self {
307 TypeInfo::BaseType { encoding, .. } => {
308 *encoding == gimli::constants::DW_ATE_float.0 as u16
309 }
310 TypeInfo::TypedefType {
311 underlying_type, ..
312 } => underlying_type.is_float(),
313 TypeInfo::QualifiedType {
314 underlying_type, ..
315 } => underlying_type.is_float(),
316 TypeInfo::OptimizedOut { .. } => false,
317 _ => false,
318 }
319 }
320
321 pub fn is_pointer(&self) -> bool {
323 match self {
324 TypeInfo::PointerType { .. } => true,
325 TypeInfo::TypedefType {
326 underlying_type, ..
327 } => underlying_type.is_pointer(),
328 TypeInfo::QualifiedType {
329 underlying_type, ..
330 } => underlying_type.is_pointer(),
331 _ => false,
332 }
333 }
334
335 pub fn is_array(&self) -> bool {
337 match self {
338 TypeInfo::ArrayType { .. } => true,
339 TypeInfo::TypedefType {
340 underlying_type, ..
341 } => underlying_type.is_array(),
342 TypeInfo::QualifiedType {
343 underlying_type, ..
344 } => underlying_type.is_array(),
345 _ => false,
346 }
347 }
348
349 pub fn underlying_type(&self) -> &TypeInfo {
351 match self {
352 TypeInfo::TypedefType {
353 underlying_type, ..
354 } => underlying_type.underlying_type(),
355 TypeInfo::QualifiedType {
356 underlying_type, ..
357 } => underlying_type.underlying_type(),
358 TypeInfo::BitfieldType {
359 underlying_type, ..
360 } => underlying_type.underlying_type(),
361 _ => self,
362 }
363 }
364
365 pub fn signed_int(size: u64) -> Self {
367 TypeInfo::BaseType {
368 name: match size {
369 1 => "i8",
370 2 => "i16",
371 4 => "i32",
372 8 => "i64",
373 _ => "iN",
374 }
375 .to_string(),
376 size,
377 encoding: gimli::constants::DW_ATE_signed.0 as u16,
378 }
379 }
380
381 pub fn float(size: u64) -> Self {
383 TypeInfo::BaseType {
384 name: match size {
385 4 => "f32",
386 8 => "f64",
387 _ => "fN",
388 }
389 .to_string(),
390 size,
391 encoding: gimli::constants::DW_ATE_float.0 as u16,
392 }
393 }
394}
395
396pub type TypeCache = HashMap<gimli::UnitOffset, Option<TypeInfo>>;
398
399impl TypeInfo {}
400
401impl fmt::Display for TypeInfo {
402 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
403 match self {
404 TypeInfo::BaseType {
405 name,
406 size,
407 encoding,
408 } => {
409 let (human_readable, _) = Self::format_base_type(name, *size, *encoding);
410 write!(f, "{human_readable}")
411 }
412 TypeInfo::PointerType { target_type, .. } => {
413 write!(f, "*{target_type}")
414 }
415 TypeInfo::ArrayType {
416 element_type,
417 element_count,
418 ..
419 } => match element_count {
420 Some(n) => write!(f, "[{n} x {element_type}]"),
421 None => write!(f, "[]{element_type}"),
422 },
423 TypeInfo::StructType { name, .. } => {
424 if name.is_empty() {
425 write!(f, "struct")
426 } else {
427 write!(f, "struct {name}")
428 }
429 }
430 TypeInfo::UnionType { name, .. } => {
431 if name.is_empty() {
432 write!(f, "union")
433 } else {
434 write!(f, "union {name}")
435 }
436 }
437 TypeInfo::EnumType { name, .. } => {
438 if name.is_empty() {
439 write!(f, "enum")
440 } else {
441 write!(f, "enum {name}")
442 }
443 }
444 TypeInfo::BitfieldType {
445 underlying_type,
446 bit_offset,
447 bit_size,
448 } => {
449 write!(f, "bitfield<{bit_offset}:{bit_size}> {underlying_type}")
450 }
451 TypeInfo::TypedefType {
452 name,
453 underlying_type,
454 } => {
455 if name.is_empty() {
456 write!(f, "{underlying_type}")
457 } else {
458 write!(f, "{name}")
459 }
460 }
461 TypeInfo::QualifiedType {
462 qualifier,
463 underlying_type,
464 } => {
465 write!(
466 f,
467 "{} {}",
468 Self::format_qualifier(qualifier),
469 underlying_type
470 )
471 }
472 TypeInfo::FunctionType {
473 return_type,
474 parameters,
475 } => {
476 let params_str = parameters
477 .iter()
478 .map(|p| p.to_string())
479 .collect::<Vec<_>>()
480 .join(", ");
481 match return_type {
482 Some(ret) => write!(f, "fn({params_str}) -> {ret}"),
483 None => write!(f, "fn({params_str})"),
484 }
485 }
486 TypeInfo::UnknownType { name } => {
487 if name.is_empty() {
488 write!(f, "unknown")
489 } else {
490 write!(f, "{name}")
491 }
492 }
493 TypeInfo::OptimizedOut { name } => {
494 if name.is_empty() {
495 write!(f, "<optimized_out>")
496 } else {
497 write!(f, "<optimized_out> {name}")
498 }
499 }
500 }
501 }
502}