Skip to main content

ghostscope_compiler/ebpf/codegen/
types.rs

1use super::*;
2
3impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
4    /// Resolve variable with correct priority: script variables first, then DWARF variables
5    /// This method is copied from protocol.rs to maintain functionality
6    pub fn resolve_variable_with_priority(&mut self, var_name: &str) -> Result<(u16, TypeKind)> {
7        info!("Resolving variable '{}' with correct priority", var_name);
8
9        // Step 1: Check if it's a script-defined variable first
10        if self.variable_exists(var_name) {
11            info!("Found script variable: {}", var_name);
12
13            // Get the variable's LLVM value to infer type
14            let loaded_value = self.load_variable(var_name)?;
15            let type_encoding = self.infer_type_from_llvm_value(&loaded_value);
16
17            // Add to TraceContext
18            let var_name_index = self.trace_context.add_variable_name(var_name.to_string());
19
20            return Ok((var_name_index, type_encoding));
21        }
22
23        // Step 2: If not found in script variables, try DWARF variables
24        info!(
25            "Variable '{}' not found in script variables, checking DWARF",
26            var_name
27        );
28
29        let compile_context = self.get_compile_time_context()?.clone();
30        let read_plan = match self.query_dwarf_for_variable(var_name)? {
31            Some(var) => var,
32            None => {
33                return Err(CodeGenError::VariableNotFound(format!(
34                    "Variable '{}' not found in script or DWARF at PC 0x{:x} in module '{}'",
35                    var_name, compile_context.pc_address, compile_context.module_path
36                )));
37            }
38        };
39
40        // Convert DWARF type information to TypeKind using existing method
41        let dwarf_type = read_plan.dwarf_type.as_ref().ok_or_else(|| {
42            CodeGenError::DwarfError("Variable has no DWARF type information".to_string())
43        })?;
44        let type_encoding = TypeKind::from(dwarf_type);
45
46        // Add to StringTable
47        let var_name_index = self.trace_context.add_variable_name(var_name.to_string());
48
49        info!(
50            "DWARF variable '{}' resolved successfully with type: {:?}",
51            var_name, type_encoding
52        );
53
54        Ok((var_name_index, type_encoding))
55    }
56
57    /// Synthesize a DWARF-like TypeInfo for a basic TypeKind (for script variables)
58    pub(super) fn synthesize_typeinfo_for_typekind(
59        &self,
60        kind: TypeKind,
61    ) -> ghostscope_dwarf::TypeInfo {
62        use ghostscope_dwarf::constants::{
63            DW_ATE_boolean, DW_ATE_float, DW_ATE_signed, DW_ATE_signed_char, DW_ATE_unsigned,
64        };
65        use ghostscope_dwarf::TypeInfo as TI;
66
67        match kind {
68            TypeKind::Bool => TI::BaseType {
69                name: "bool".to_string(),
70                size: 1,
71                encoding: DW_ATE_boolean.0 as u16,
72            },
73            TypeKind::F32 => TI::BaseType {
74                name: "f32".to_string(),
75                size: 4,
76                encoding: DW_ATE_float.0 as u16,
77            },
78            TypeKind::F64 => TI::BaseType {
79                name: "f64".to_string(),
80                size: 8,
81                encoding: DW_ATE_float.0 as u16,
82            },
83            TypeKind::I8 => TI::BaseType {
84                name: "i8".to_string(),
85                size: 1,
86                encoding: DW_ATE_signed_char.0 as u16,
87            },
88            TypeKind::I16 => TI::BaseType {
89                name: "i16".to_string(),
90                size: 2,
91                encoding: DW_ATE_signed.0 as u16,
92            },
93            TypeKind::I32 => TI::BaseType {
94                name: "i32".to_string(),
95                size: 4,
96                encoding: DW_ATE_signed.0 as u16,
97            },
98            TypeKind::I64 => TI::BaseType {
99                name: "i64".to_string(),
100                size: 8,
101                encoding: DW_ATE_signed.0 as u16,
102            },
103            TypeKind::U8 | TypeKind::Char => TI::BaseType {
104                name: "u8".to_string(),
105                size: 1,
106                encoding: DW_ATE_unsigned.0 as u16,
107            },
108            TypeKind::U16 => TI::BaseType {
109                name: "u16".to_string(),
110                size: 2,
111                encoding: DW_ATE_unsigned.0 as u16,
112            },
113            TypeKind::U32 => TI::BaseType {
114                name: "u32".to_string(),
115                size: 4,
116                encoding: DW_ATE_unsigned.0 as u16,
117            },
118            TypeKind::U64 => TI::BaseType {
119                name: "u64".to_string(),
120                size: 8,
121                encoding: DW_ATE_unsigned.0 as u16,
122            },
123            TypeKind::Pointer | TypeKind::CString | TypeKind::String | TypeKind::Unknown => {
124                // Use void* as a reasonable default for pointers/strings in script land
125                TI::PointerType {
126                    target_type: Box::new(TI::UnknownType {
127                        name: "void".to_string(),
128                    }),
129                    size: 8,
130                }
131            }
132            TypeKind::NullPointer => TI::PointerType {
133                target_type: Box::new(TI::UnknownType {
134                    name: "void".to_string(),
135                }),
136                size: 8,
137            },
138            _ => TI::BaseType {
139                name: "i64".to_string(),
140                size: 8,
141                encoding: DW_ATE_signed.0 as u16,
142            },
143        }
144    }
145
146    pub(super) fn add_synthesized_type_index_for_kind(&mut self, kind: TypeKind) -> u16 {
147        let ti = self.synthesize_typeinfo_for_typekind(kind);
148        self.trace_context.add_type(ti)
149    }
150
151    /// Infer TypeKind from LLVM value type
152    /// Copied from protocol.rs
153    pub(super) fn infer_type_from_llvm_value(&self, value: &BasicValueEnum<'_>) -> TypeKind {
154        match value {
155            BasicValueEnum::IntValue(int_val) => {
156                match int_val.get_type().get_bit_width() {
157                    1 => TypeKind::Bool,
158                    8 => TypeKind::I8, // Default to signed for script variables
159                    16 => TypeKind::I16,
160                    32 => TypeKind::I32,
161                    64 => TypeKind::I64,
162                    _ => TypeKind::I64, // Default fallback
163                }
164            }
165            BasicValueEnum::FloatValue(float_val) => {
166                match float_val.get_type() {
167                    t if t == self.context.f32_type() => TypeKind::F32,
168                    t if t == self.context.f64_type() => TypeKind::F64,
169                    _ => TypeKind::F64, // Default fallback
170                }
171            }
172            BasicValueEnum::PointerValue(_) => TypeKind::Pointer,
173            _ => TypeKind::I64, // Conservative default
174        }
175    }
176}