Skip to main content

ghostscope_compiler/ebpf/codegen/
statements.rs

1use super::*;
2
3impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
4    /// Main entry point: compile program with staged transmission system
5    pub fn compile_program_with_staged_transmission(
6        &mut self,
7        program: &Program,
8        _variable_types: HashMap<String, TypeKind>,
9    ) -> Result<TraceContext> {
10        info!("Compiling program with staged transmission system");
11
12        // Step 1: Send TraceEventHeader
13        self.send_trace_event_header()?;
14        info!("Sent TraceEventHeader");
15
16        // Step 2: Send TraceEventMessage with dynamic trace_id
17        let trace_id = self.current_trace_id.map(|id| id as u64).unwrap_or(0);
18        self.send_trace_event_message(trace_id)?;
19        info!("Sent TraceEventMessage");
20
21        // Reset per-event execution status flags
22        self.store_flag_value("_gs_any_fail", 0)?;
23        self.store_flag_value("_gs_any_success", 0)?;
24
25        // Step 3: Process each statement and generate LLVM IR on-demand
26        let mut instruction_count = 0u16;
27        for statement in &program.statements {
28            instruction_count += self.compile_statement(statement)?;
29        }
30
31        // Step 4: Write EndInstruction and either emit immediately or hand off
32        // emission to the bt tail-call finalizer.
33        self.write_end_instruction(instruction_count)?;
34        self.finish_event_after_instructions()?;
35        info!(
36            "Sent EndInstruction with {} total instructions",
37            instruction_count
38        );
39
40        // Step 5: Return the trace context for user-space parsing
41        Ok(self.trace_context.clone())
42    }
43
44    /// Compile a statement and return the number of instructions generated
45    pub fn compile_statement(&mut self, statement: &Statement) -> Result<u16> {
46        debug!("Compiling statement: {:?}", statement);
47
48        match statement {
49            Statement::AliasDeclaration { name, target } => {
50                info!("Registering alias variable: {} = {:?}", name, target);
51                // Declare in current scope (no redeclaration or shadowing)
52                self.declare_name_in_current_scope(name)?;
53                self.set_alias_variable(name, target.clone());
54                Ok(0)
55            }
56            Statement::VarDeclaration { name, value } => {
57                info!("Processing variable declaration: {} = {:?}", name, value);
58                // Declare in current scope (no redeclaration or shadowing)
59                self.declare_name_in_current_scope(name)?;
60                // Decide whether this is an alias binding (DWARF-backed address/reference)
61                if self.is_alias_candidate_expr(value) {
62                    self.set_alias_variable(name, value.clone());
63                    tracing::debug!(var=%name, "Registered DWARF alias variable");
64                    Ok(0)
65                } else {
66                    // Compile the value expression and store as concrete variable
67                    // Special-case: string literal and string var copy — record bytes for content printing
68                    match value {
69                        crate::script::Expr::String(s) => {
70                            let mut bytes = s.as_bytes().to_vec();
71                            bytes.push(0); // NUL terminate for display convenience
72                            self.set_string_variable_bytes(name, bytes);
73                        }
74                        crate::script::Expr::Variable(ref nm) => {
75                            if self
76                                .get_variable_type(nm)
77                                .is_some_and(|t| matches!(t, crate::script::VarType::String))
78                            {
79                                if let Some(b) = self.get_string_variable_bytes(nm).cloned() {
80                                    self.set_string_variable_bytes(name, b);
81                                }
82                            }
83                        }
84                        _ => {}
85                    }
86                    let compiled_value = self.compile_expr(value)?;
87                    // Disallow storing pointer values in script variables, except for string literals
88                    if let BasicValueEnum::PointerValue(_) = compiled_value {
89                        // Allow if RHS is a string literal OR a string variable (VarType::String)
90                        let allow_string_var_copy = match value {
91                            crate::script::Expr::String(_) => true,
92                            crate::script::Expr::Variable(ref nm) => self
93                                .get_variable_type(nm)
94                                .is_some_and(|t| matches!(t, crate::script::VarType::String)),
95                            _ => false,
96                        };
97                        if !allow_string_var_copy {
98                            return Err(CodeGenError::TypeError(
99                                "script variables cannot store pointer values; use DWARF alias (let v = &expr) or keep it as a string".to_string(),
100                            ));
101                        }
102                    }
103                    self.store_variable(name, compiled_value)?;
104                    Ok(0) // VarDeclaration doesn't generate instructions
105                }
106            }
107            Statement::Print(print_stmt) => self.compile_print_statement(print_stmt),
108            Statement::Backtrace(backtrace_stmt) => {
109                self.generate_backtrace_instruction(backtrace_stmt)?;
110                Ok(1)
111            }
112            Statement::If {
113                condition,
114                then_body,
115                else_body,
116            } => {
117                let entry_event_bytes = self.compile_time_event_bytes_upper_bound;
118                // Prepare condition context (runtime error capture)
119                // Pretty expression text for warning
120                let expr_text = self.expr_to_name(condition);
121                let expr_index = self.trace_context.add_string(expr_text);
122                // Activate condition context (compile-time flag) and reset runtime error byte
123                self.condition_context_active = true;
124                self.reset_condition_error()?;
125
126                // Compile condition expression
127                let cond_value = self.compile_expr(condition)?;
128
129                // Convert condition to i1 (boolean) for branching
130                let cond_bool = match cond_value {
131                    BasicValueEnum::IntValue(int_val) => {
132                        // Convert integer to boolean (non-zero = true)
133                        self.builder
134                            .build_int_compare(
135                                inkwell::IntPredicate::NE,
136                                int_val,
137                                int_val.get_type().const_zero(),
138                                "cond_bool",
139                            )
140                            .map_err(|e| {
141                                CodeGenError::LLVMError(format!("Failed to create condition: {e}"))
142                            })?
143                    }
144                    _ => {
145                        return Err(CodeGenError::LLVMError(
146                            "Condition must evaluate to integer".to_string(),
147                        ));
148                    }
149                };
150
151                // Get current function from builder
152                let current_function = self
153                    .builder
154                    .get_insert_block()
155                    .ok_or_else(|| CodeGenError::LLVMError("No current basic block".to_string()))?
156                    .get_parent()
157                    .ok_or_else(|| CodeGenError::LLVMError("No parent function".to_string()))?;
158
159                // Create basic blocks for error/noerror and then/else paths
160                let then_block = self
161                    .context
162                    .append_basic_block(current_function, "then_block");
163                let else_block = self
164                    .context
165                    .append_basic_block(current_function, "else_block");
166                let merge_block = self
167                    .context
168                    .append_basic_block(current_function, "merge_block");
169                let err_block = self
170                    .context
171                    .append_basic_block(current_function, "cond_err_block");
172                let ok_block = self
173                    .context
174                    .append_basic_block(current_function, "cond_ok_block");
175                // After cond compiled, deactivate compile-time flag
176                self.condition_context_active = false;
177
178                // First branch: did runtime errors occur while evaluating the condition?
179                let cond_err_pred = self.build_condition_error_predicate()?;
180                self.builder
181                    .build_conditional_branch(cond_err_pred, err_block, ok_block)
182                    .map_err(|e| {
183                        CodeGenError::LLVMError(format!("Failed to branch on cond_err: {e}"))
184                    })?;
185
186                // Error path: emit ExprError and decide destination
187                self.builder.position_at_end(err_block);
188                self.compile_time_event_bytes_upper_bound = entry_event_bytes;
189                self.emit_current_condition_exprerror(expr_index, "cond")?;
190                // Decide where to go on error: if else_body is If (else-if), go to else_block to continue;
191                // otherwise, skip else (suppress) and jump to merge.
192                let goto_else = matches!(else_body.as_deref(), Some(Statement::If { .. }));
193                let err_path_event_bytes = self.compile_time_event_bytes_upper_bound;
194                if goto_else {
195                    self.builder
196                        .build_unconditional_branch(else_block)
197                        .map_err(|e| {
198                            CodeGenError::LLVMError(format!(
199                                "Failed to branch to else on error: {e}"
200                            ))
201                        })?;
202                } else {
203                    self.builder
204                        .build_unconditional_branch(merge_block)
205                        .map_err(|e| {
206                            CodeGenError::LLVMError(format!(
207                                "Failed to branch to merge on error: {e}"
208                            ))
209                        })?;
210                }
211
212                // No-error path: branch on boolean condition
213                self.builder.position_at_end(ok_block);
214                self.compile_time_event_bytes_upper_bound = entry_event_bytes;
215                self.builder
216                    .build_conditional_branch(cond_bool, then_block, else_block)
217                    .map_err(|e| {
218                        CodeGenError::LLVMError(format!("Failed to create branch: {e}"))
219                    })?;
220
221                // Build then block
222                self.builder.position_at_end(then_block);
223                self.compile_time_event_bytes_upper_bound = entry_event_bytes;
224                let mut then_instructions = 0u16;
225                self.enter_scope();
226                for stmt in then_body {
227                    then_instructions += self.compile_statement(stmt)?;
228                }
229                self.exit_scope();
230                let then_event_bytes = self.compile_time_event_bytes_upper_bound;
231                self.builder
232                    .build_unconditional_branch(merge_block)
233                    .map_err(|e| {
234                        CodeGenError::LLVMError(format!("Failed to branch to merge: {e}"))
235                    })?;
236
237                // Build else block
238                self.builder.position_at_end(else_block);
239                let else_entry_event_bytes = if goto_else {
240                    entry_event_bytes.max(err_path_event_bytes)
241                } else {
242                    entry_event_bytes
243                };
244                self.compile_time_event_bytes_upper_bound = else_entry_event_bytes;
245                let mut else_instructions = 0u16;
246                if let Some(else_stmt) = else_body {
247                    self.enter_scope();
248                    else_instructions += self.compile_statement(else_stmt)?;
249                    self.exit_scope();
250                }
251                self.builder
252                    .build_unconditional_branch(merge_block)
253                    .map_err(|e| {
254                        CodeGenError::LLVMError(format!("Failed to branch to merge: {e}"))
255                    })?;
256                let else_event_bytes = self.compile_time_event_bytes_upper_bound;
257
258                // Continue with merge block
259                self.builder.position_at_end(merge_block);
260                self.compile_time_event_bytes_upper_bound = if goto_else {
261                    then_event_bytes.max(else_event_bytes)
262                } else {
263                    then_event_bytes
264                        .max(else_event_bytes)
265                        .max(err_path_event_bytes)
266                };
267
268                // Return the maximum instructions from either branch
269                Ok(std::cmp::max(then_instructions, else_instructions))
270            }
271            Statement::Block(nested_statements) => {
272                let mut total_instructions = 0u16;
273                self.enter_scope();
274                for stmt in nested_statements {
275                    total_instructions += self.compile_statement(stmt)?;
276                }
277                self.exit_scope();
278                Ok(total_instructions)
279            }
280            Statement::TracePoint { pattern: _, body } => {
281                let mut total_instructions = 0u16;
282                // Start a new scope for the trace body
283                self.enter_scope();
284                for stmt in body {
285                    total_instructions += self.compile_statement(stmt)?;
286                }
287                self.exit_scope();
288                Ok(total_instructions)
289            }
290            _ => {
291                warn!("Unsupported statement type: {:?}", statement);
292                Ok(0)
293            }
294        }
295    }
296
297    /// Compile print statement and generate LLVM IR on-demand
298    pub fn compile_print_statement(&mut self, print_stmt: &PrintStatement) -> Result<u16> {
299        info!("Compiling print statement: {:?}", print_stmt);
300
301        match print_stmt {
302            PrintStatement::String(s) => {
303                info!("Processing string literal: {}", s);
304                // 1. Add string to TraceContext
305                let string_index = self.trace_context.add_string(s.to_string());
306                // 2. Generate eBPF code for PrintStringIndex
307                self.generate_print_string_index(string_index)?;
308                Ok(1) // Generated 1 instruction
309            }
310            PrintStatement::Variable(var_name) => {
311                info!("Processing variable: {}", var_name);
312                let expr = crate::script::Expr::Variable(var_name.clone());
313                let arg = self.resolve_expr_to_arg(&expr)?;
314                let n = self.emit_print_from_arg(arg)?;
315                tracing::trace!(
316                    var_name = %var_name,
317                    instructions = n,
318                    "compile_print_statement: emitted via unified resolver"
319                );
320                Ok(n)
321            }
322            PrintStatement::ComplexVariable(expr) => {
323                info!("Processing complex variable: {:?}", expr);
324                let arg = self.compile_print_expr_with_builtin_exprerror(expr, |ctx| {
325                    ctx.resolve_expr_to_arg(expr)
326                })?;
327                let n = self.emit_print_from_arg(arg)?;
328                tracing::trace!(
329                    instructions = n,
330                    "compile_print_statement: emitted via unified resolver"
331                );
332                Ok(n)
333            }
334            PrintStatement::Formatted { format, args } => {
335                info!(
336                    "Processing formatted print: '{}' with {} args",
337                    format,
338                    args.len()
339                );
340                self.compile_formatted_print(format, args)
341            }
342        }
343    }
344}