Skip to main content

ghostscope_compiler/ebpf/codegen/
print_string_index.rs

1use super::*;
2
3impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
4    /// Generate eBPF code for PrintStringIndex instruction
5    pub fn generate_print_string_index(&mut self, string_index: u16) -> Result<()> {
6        info!(
7            "Generating PrintStringIndex instruction: index={}",
8            string_index
9        );
10
11        // Allocate instruction structure on eBPF stack
12        // Reserve space in accumulation buffer for this instruction
13        let inst_buffer = self
14            .reserve_instruction_region_or_return_zero(
15                (std::mem::size_of::<InstructionHeader>()
16                    + std::mem::size_of::<PrintStringIndexData>()) as u64,
17            )?
18            .into_value_after_runtime_returns();
19
20        // Clear memory with static size
21        let _inst_size = self.context.i64_type().const_int(
22            (std::mem::size_of::<PrintStringIndexData>()
23                + std::mem::size_of::<ghostscope_protocol::trace_event::InstructionHeader>())
24                as u64,
25            false,
26        );
27        // Avoid memset on eBPF; global buffer is zero-initialized and we write fields explicitly.
28
29        // Fill instruction header using byte offsets
30        // inst_type at offset 0 (first field of InstructionHeader)
31        // SAFETY: inst_buffer points at a reserved PrintStringIndex instruction
32        // region and inst_type is within InstructionHeader.
33        let inst_type_ptr = unsafe {
34            self.builder
35                .build_gep(
36                    self.context.i8_type(),
37                    inst_buffer,
38                    &[self.context.i32_type().const_int(
39                        std::mem::offset_of!(InstructionHeader, inst_type) as u64,
40                        false,
41                    )],
42                    "inst_type_ptr",
43                )
44                .map_err(|e| CodeGenError::LLVMError(format!("Failed to get inst_type GEP: {e}")))?
45        };
46        let inst_type_val = self
47            .context
48            .i8_type()
49            .const_int(InstructionType::PrintStringIndex as u64, false);
50        self.builder
51            .build_store(inst_type_ptr, inst_type_val)
52            .map_err(|e| CodeGenError::LLVMError(format!("Failed to store inst_type: {e}")))?;
53
54        // SAFETY: inst_buffer points at a reserved PrintStringIndex instruction
55        // region and data_length is within InstructionHeader.
56        let data_length_ptr = unsafe {
57            self.builder
58                .build_gep(
59                    self.context.i8_type(),
60                    inst_buffer,
61                    &[self.context.i32_type().const_int(
62                        std::mem::offset_of!(InstructionHeader, data_length) as u64,
63                        false,
64                    )],
65                    "data_length_ptr",
66                )
67                .map_err(|e| {
68                    CodeGenError::LLVMError(format!("Failed to get data_length GEP: {e}"))
69                })?
70        };
71        let data_length_i16_ptr = self
72            .builder
73            .build_pointer_cast(
74                data_length_ptr,
75                self.context.ptr_type(AddressSpace::default()),
76                "data_length_i16_ptr",
77            )
78            .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast data_length ptr: {e}")))?;
79        let data_length_val = self
80            .context
81            .i16_type()
82            .const_int(std::mem::size_of::<PrintStringIndexData>() as u64, false);
83        self.builder
84            .build_store(data_length_i16_ptr, data_length_val)
85            .map_err(|e| CodeGenError::LLVMError(format!("Failed to store data_length: {e}")))?;
86
87        // Fill string index data (after InstructionHeader)
88        // SAFETY: the string index payload starts immediately after InstructionHeader
89        // in the reserved PrintStringIndex instruction region.
90        let string_index_ptr = unsafe {
91            self.builder
92                .build_gep(
93                    self.context.i8_type(),
94                    inst_buffer,
95                    &[self
96                        .context
97                        .i32_type()
98                        .const_int(std::mem::size_of::<InstructionHeader>() as u64, false)],
99                    "string_index_ptr",
100                )
101                .map_err(|e| {
102                    CodeGenError::LLVMError(format!("Failed to get string_index GEP: {e}"))
103                })?
104        };
105        let string_index_i16_ptr = self
106            .builder
107            .build_pointer_cast(
108                string_index_ptr,
109                self.context.ptr_type(AddressSpace::default()),
110                "string_index_i16_ptr",
111            )
112            .map_err(|e| {
113                CodeGenError::LLVMError(format!("Failed to cast string_index ptr: {e}"))
114            })?;
115        let string_index_val = self
116            .context
117            .i16_type()
118            .const_int(string_index as u64, false);
119        self.builder
120            .build_store(string_index_i16_ptr, string_index_val)
121            .map_err(|e| CodeGenError::LLVMError(format!("Failed to store string_index: {e}")))?;
122
123        // Already accumulated; EndInstruction will send the whole event
124        Ok(())
125    }
126}