ghostscope_protocol/
type_info.rs

1//! Type information system for GhostScope
2//!
3//! This module defines a comprehensive type system for representing type information from DWARF.
4//! These types preserve the full richness of debugging information needed for accurate
5//! memory reading and data formatting.
6
7use serde::{Deserialize, Serialize};
8use std::collections::HashMap;
9use std::fmt;
10
11/// Type information with full fidelity from DWARF debugging data
12#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13pub enum TypeInfo {
14    /// Base/primitive type (int, float, char, etc.)
15    BaseType {
16        name: String,
17        size: u64,
18        encoding: u16, // Store DwAte as u16 for serialization
19    },
20
21    /// Pointer type
22    PointerType {
23        target_type: Box<TypeInfo>,
24        size: u64,
25    },
26
27    /// Array type
28    ArrayType {
29        element_type: Box<TypeInfo>,
30        element_count: Option<u64>,
31        total_size: Option<u64>,
32    },
33
34    /// Struct/class type
35    StructType {
36        name: String,
37        size: u64,
38        members: Vec<StructMember>,
39    },
40
41    /// Union type
42    UnionType {
43        name: String,
44        size: u64,
45        members: Vec<StructMember>,
46    },
47
48    /// Enum type
49    EnumType {
50        name: String,
51        size: u64,
52        base_type: Box<TypeInfo>,
53        variants: Vec<EnumVariant>,
54    },
55
56    /// Typedef (type alias)
57    TypedefType {
58        name: String,
59        underlying_type: Box<TypeInfo>,
60    },
61
62    /// Qualified type (const, volatile, restrict)
63    QualifiedType {
64        qualifier: TypeQualifier,
65        underlying_type: Box<TypeInfo>,
66    },
67
68    /// Function type
69    FunctionType {
70        return_type: Option<Box<TypeInfo>>,
71        parameters: Vec<TypeInfo>,
72    },
73
74    /// Bitfield type: a view over an underlying integer type with bit offset/size
75    BitfieldType {
76        underlying_type: Box<TypeInfo>,
77        bit_offset: u8,
78        bit_size: u8,
79    },
80
81    /// Unresolved or unknown type
82    UnknownType { name: String },
83
84    /// Optimized out type (variable was optimized away by compiler)
85    OptimizedOut { name: String },
86}
87
88/// Struct/union member information
89#[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/// Enum variant information
99#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
100pub struct EnumVariant {
101    pub name: String,
102    pub value: i64,
103}
104
105/// Type qualifiers
106#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
107pub enum TypeQualifier {
108    Const,
109    Volatile,
110    Restrict,
111}
112
113impl TypeInfo {
114    /// Get the size in bytes of this type
115    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, // Function pointer size
130            TypeInfo::BitfieldType {
131                underlying_type, ..
132            } => underlying_type.size(),
133            TypeInfo::UnknownType { .. } => 0,
134            TypeInfo::OptimizedOut { .. } => 0, // Optimized out has no size
135        }
136    }
137
138    /// Format base type with encoding information (shared utility)
139    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    /// Format qualifier string (shared utility)
194    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    /// Get the type name for display
203    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    /// Check if this is a signed integer type
265    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    /// Check if this is an unsigned integer type
285    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    /// Check if this is a floating point type
305    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    /// Check if this is a pointer type
322    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    /// Check if this is an array type
336    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    /// Get the underlying type, skipping typedefs and qualifiers
350    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    /// Create a signed integer base type (compatibility method for compiler)
366    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    /// Create a floating point base type (compatibility method for compiler)
382    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
396/// Type cache for performance optimization
397pub 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}