Skip to main content

ghostscope_compiler/ebpf/codegen/
expr_error.rs

1use super::*;
2
3impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
4    /// Generate ExprError instruction with expression string index and error code/flags
5    pub fn generate_expr_error(
6        &mut self,
7        expr_string_index: u16,
8        error_code_iv: inkwell::values::IntValue<'ctx>,
9        flags_iv: inkwell::values::IntValue<'ctx>,
10        failing_addr_iv: inkwell::values::IntValue<'ctx>,
11    ) -> Result<()> {
12        // Reserve space in accumulation buffer for this instruction
13        let inst_buffer = self
14            .reserve_instruction_region_or_return_zero(
15                (INSTRUCTION_HEADER_SIZE + EXPR_ERROR_DATA_SIZE) as u64,
16            )?
17            .into_value_after_runtime_returns();
18
19        // Store instruction type at offset 0
20        let inst_type_val = self
21            .context
22            .i8_type()
23            .const_int(InstructionType::ExprError as u64, false);
24        self.builder
25            .build_store(inst_buffer, inst_type_val)
26            .map_err(|e| CodeGenError::LLVMError(format!("Failed to store inst_type: {e}")))?;
27
28        // data_length
29        // SAFETY: inst_buffer points at a reserved ExprError instruction region
30        // and data_length is within InstructionHeader.
31        let data_length_ptr = unsafe {
32            self.builder
33                .build_gep(
34                    self.context.i8_type(),
35                    inst_buffer,
36                    &[self
37                        .context
38                        .i32_type()
39                        .const_int(INSTRUCTION_HEADER_DATA_LENGTH_OFFSET as u64, false)],
40                    "exprerr_data_length_ptr",
41                )
42                .map_err(|e| {
43                    CodeGenError::LLVMError(format!("Failed to get data_length GEP: {e}"))
44                })?
45        };
46        let data_length_i16_ptr = self
47            .builder
48            .build_pointer_cast(
49                data_length_ptr,
50                self.context.ptr_type(AddressSpace::default()),
51                "exprerr_data_length_i16_ptr",
52            )
53            .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast data_length ptr: {e}")))?;
54        let data_length_val = self
55            .context
56            .i16_type()
57            .const_int(EXPR_ERROR_DATA_SIZE as u64, false);
58        self.builder
59            .build_store(data_length_i16_ptr, data_length_val)
60            .map_err(|e| CodeGenError::LLVMError(format!("Failed to store data_length: {e}")))?;
61
62        // Payload fields after header
63        // SAFETY: the payload immediately follows InstructionHeader in the
64        // reserved ExprError instruction region.
65        let si_ptr = unsafe {
66            self.builder
67                .build_gep(
68                    self.context.i8_type(),
69                    inst_buffer,
70                    &[self.context.i32_type().const_int(
71                        (INSTRUCTION_HEADER_SIZE + EXPR_ERROR_DATA_STRING_INDEX_OFFSET) as u64,
72                        false,
73                    )],
74                    "exprerr_si_ptr",
75                )
76                .map_err(|e| {
77                    CodeGenError::LLVMError(format!("Failed to get string_index GEP: {e}"))
78                })?
79        };
80        let si_i16_ptr = self
81            .builder
82            .build_pointer_cast(
83                si_ptr,
84                self.context.ptr_type(AddressSpace::default()),
85                "exprerr_si_i16_ptr",
86            )
87            .map_err(|e| {
88                CodeGenError::LLVMError(format!("Failed to cast string_index ptr: {e}"))
89            })?;
90        let si_val = self
91            .context
92            .i16_type()
93            .const_int(expr_string_index as u64, false);
94        self.builder
95            .build_store(si_i16_ptr, si_val)
96            .map_err(|e| CodeGenError::LLVMError(format!("Failed to store string_index: {e}")))?;
97
98        // SAFETY: error_code offset is within ExprErrorData in the reserved payload.
99        let ec_ptr = unsafe {
100            self.builder
101                .build_gep(
102                    self.context.i8_type(),
103                    inst_buffer,
104                    &[self.context.i32_type().const_int(
105                        (INSTRUCTION_HEADER_SIZE + EXPR_ERROR_DATA_ERROR_CODE_OFFSET) as u64,
106                        false,
107                    )],
108                    "exprerr_ec_ptr",
109                )
110                .map_err(|e| {
111                    CodeGenError::LLVMError(format!("Failed to get error_code GEP: {e}"))
112                })?
113        };
114        // Truncate/extend runtime error code to i8
115        let ec_i8 = if error_code_iv.get_type().get_bit_width() == 8 {
116            error_code_iv
117        } else if error_code_iv.get_type().get_bit_width() > 8 {
118            self.builder
119                .build_int_truncate(error_code_iv, self.context.i8_type(), "ec_trunc")
120                .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
121        } else {
122            self.builder
123                .build_int_z_extend(error_code_iv, self.context.i8_type(), "ec_zext")
124                .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
125        };
126        self.builder
127            .build_store(ec_ptr, ec_i8)
128            .map_err(|e| CodeGenError::LLVMError(format!("Failed to store error_code: {e}")))?;
129        // SAFETY: flags offset is within ExprErrorData in the reserved payload.
130        let fl_ptr = unsafe {
131            self.builder
132                .build_gep(
133                    self.context.i8_type(),
134                    inst_buffer,
135                    &[self.context.i32_type().const_int(
136                        (INSTRUCTION_HEADER_SIZE + EXPR_ERROR_DATA_FLAGS_OFFSET) as u64,
137                        false,
138                    )],
139                    "exprerr_flags_ptr",
140                )
141                .map_err(|e| CodeGenError::LLVMError(format!("Failed to get flags GEP: {e}")))?
142        };
143        // Truncate/extend runtime flags to i8
144        let fl_i8 = if flags_iv.get_type().get_bit_width() == 8 {
145            flags_iv
146        } else if flags_iv.get_type().get_bit_width() > 8 {
147            self.builder
148                .build_int_truncate(flags_iv, self.context.i8_type(), "fl_trunc")
149                .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
150        } else {
151            self.builder
152                .build_int_z_extend(flags_iv, self.context.i8_type(), "fl_zext")
153                .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
154        };
155        self.builder
156            .build_store(fl_ptr, fl_i8)
157            .map_err(|e| CodeGenError::LLVMError(format!("Failed to store flags: {e}")))?;
158
159        // SAFETY: failing_addr offset is within ExprErrorData in the reserved payload.
160        let addr_ptr = unsafe {
161            self.builder
162                .build_gep(
163                    self.context.i8_type(),
164                    inst_buffer,
165                    &[self.context.i32_type().const_int(
166                        (INSTRUCTION_HEADER_SIZE + EXPR_ERROR_DATA_FAILING_ADDR_OFFSET) as u64,
167                        false,
168                    )],
169                    "exprerr_addr_ptr",
170                )
171                .map_err(|e| CodeGenError::LLVMError(format!("Failed to get addr GEP: {e}")))?
172        };
173        let addr_i64 = if failing_addr_iv.get_type().get_bit_width() == 64 {
174            failing_addr_iv
175        } else if failing_addr_iv.get_type().get_bit_width() > 64 {
176            self.builder
177                .build_int_truncate(failing_addr_iv, self.context.i64_type(), "addr_trunc")
178                .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
179        } else {
180            self.builder
181                .build_int_z_extend(failing_addr_iv, self.context.i64_type(), "addr_zext")
182                .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
183        };
184        let addr_ptr_cast = self
185            .builder
186            .build_pointer_cast(
187                addr_ptr,
188                self.context.ptr_type(AddressSpace::default()),
189                "exprerr_addr_i64_ptr",
190            )
191            .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
192        self.builder
193            .build_store(addr_ptr_cast, addr_i64)
194            .map_err(|e| CodeGenError::LLVMError(format!("Failed to store failing_addr: {e}")))?;
195
196        // Already accumulated; EndInstruction will send the whole event
197        Ok(())
198    }
199}