1use super::context::{CodeGenError, EbpfContext, Result};
7use aya_ebpf_bindings::bindings::bpf_func_id::{
8 BPF_FUNC_get_current_pid_tgid, BPF_FUNC_ktime_get_ns, BPF_FUNC_map_lookup_elem,
9 BPF_FUNC_perf_event_output, BPF_FUNC_probe_read_user, BPF_FUNC_probe_read_user_str,
10 BPF_FUNC_ringbuf_output,
11};
12use ghostscope_dwarf::MemoryAccessSize;
13use ghostscope_platform::register_mapping;
14use inkwell::types::{BasicType, BasicTypeEnum};
15use inkwell::values::{BasicMetadataValueEnum, BasicValueEnum, IntValue, PointerValue};
16use inkwell::AddressSpace;
17
18impl<'ctx> EbpfContext<'ctx> {
19 pub fn get_or_create_i8_buffer(
21 &mut self,
22 size: u32,
23 name_prefix: &str,
24 ) -> (
25 inkwell::types::ArrayType<'ctx>,
26 inkwell::values::PointerValue<'ctx>,
27 ) {
28 let array_ty = self.context.i8_type().array_type(size);
29 let name = format!("{name_prefix}_{size}");
30 let global_ptr = match self.module.get_global(&name) {
31 Some(g) => g.as_pointer_value(),
32 None => {
33 let g = self
34 .module
35 .add_global(array_ty, Some(AddressSpace::default()), &name);
36 g.set_initializer(&array_ty.const_zero());
37 g.as_pointer_value()
38 }
39 };
40 (array_ty, global_ptr)
41 }
42
43 pub fn read_user_cstr_into_buffer(
46 &mut self,
47 src_addr: inkwell::values::IntValue<'ctx>,
48 size: u32,
49 name_prefix: &str,
50 ) -> Result<(
51 inkwell::values::PointerValue<'ctx>,
52 inkwell::values::IntValue<'ctx>,
53 inkwell::types::ArrayType<'ctx>,
54 )> {
55 let (arr_ty, buf_global) = self.get_or_create_i8_buffer(size, name_prefix);
56
57 let ptr_ty = self.context.ptr_type(AddressSpace::default());
58 let dst_ptr = self
60 .builder
61 .build_bit_cast(buf_global, ptr_ty, "dst_ptr")
62 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
63 let src_ptr = self
64 .builder
65 .build_int_to_ptr(src_addr, ptr_ty, "src_ptr")
66 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
67
68 let i64_ty = self.context.i64_type();
70 let i32_ty = self.context.i32_type();
71 let args: [inkwell::values::BasicValueEnum; 3] = [
72 dst_ptr,
73 i32_ty.const_int(size as u64, false).into(),
74 inkwell::values::BasicValueEnum::PointerValue(src_ptr),
75 ];
76 let ret = self.create_bpf_helper_call(
77 BPF_FUNC_probe_read_user_str as u64,
78 &args,
79 i64_ty.into(),
80 "probe_read_user_str",
81 )?;
82 let len = if let inkwell::values::BasicValueEnum::IntValue(iv) = ret {
83 iv
84 } else {
85 return Err(CodeGenError::LLVMError(
86 "probe_read_user_str did not return integer".to_string(),
87 ));
88 };
89 Ok((buf_global, len, arr_ty))
90 }
91
92 pub fn read_user_bytes_into_buffer(
95 &mut self,
96 src_addr: inkwell::values::IntValue<'ctx>,
97 size: u32,
98 name_prefix: &str,
99 ) -> Result<(
100 inkwell::values::PointerValue<'ctx>,
101 inkwell::values::IntValue<'ctx>,
102 inkwell::types::ArrayType<'ctx>,
103 )> {
104 let (arr_ty, buf_global) = self.get_or_create_i8_buffer(size, name_prefix);
105 let ptr_ty = self.context.ptr_type(AddressSpace::default());
106 let i32_ty = self.context.i32_type();
107 let i64_ty = self.context.i64_type();
108 let dst_ptr = self
110 .builder
111 .build_bit_cast(buf_global, ptr_ty, "dst_ptr")
112 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
113 let src_ptr = self
114 .builder
115 .build_int_to_ptr(src_addr, ptr_ty, "src_ptr")
116 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
117
118 let args: [inkwell::values::BasicValueEnum; 3] = [
119 dst_ptr,
120 i32_ty.const_int(size as u64, false).into(),
121 inkwell::values::BasicValueEnum::PointerValue(src_ptr),
122 ];
123 let ret = self.create_bpf_helper_call(
125 BPF_FUNC_probe_read_user as u64,
126 &args,
127 i64_ty.into(),
128 "probe_read_user",
129 )?;
130 let status = if let inkwell::values::BasicValueEnum::IntValue(iv) = ret {
131 iv
132 } else {
133 return Err(CodeGenError::LLVMError(
134 "probe_read_user did not return integer".to_string(),
135 ));
136 };
137 Ok((buf_global, status, arr_ty))
138 }
139 pub fn generate_runtime_address_from_offsets(
142 &mut self,
143 link_addr: IntValue<'ctx>,
144 section_type: u8,
145 module_cookie: u64,
146 ) -> Result<(IntValue<'ctx>, IntValue<'ctx>)> {
147 let i64_type = self.context.i64_type();
148 let ptr_type = self.context.ptr_type(AddressSpace::default());
149
150 let map_global = self
152 .module
153 .get_global("proc_module_offsets")
154 .ok_or_else(|| {
155 CodeGenError::LLVMError("proc_module_offsets map not found".to_string())
156 })?;
157 let map_ptr = map_global.as_pointer_value();
158 let map_ptr_cast = self
159 .builder
160 .build_bit_cast(map_ptr, ptr_type, "map_ptr")
161 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
162
163 let i32_type = self.context.i32_type();
166 let key_arr_ty = i32_type.array_type(4);
167 let key_alloca = self.pm_key_alloca.ok_or_else(|| {
168 CodeGenError::LLVMError("pm_key not allocated in entry block".to_string())
169 })?;
170 let zero = i32_type.const_zero();
172 let base_i32_ptr = unsafe {
173 self.builder
174 .build_gep(key_arr_ty, key_alloca, &[zero, zero], "pm_key_i32_ptr")
175 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
176 };
177
178 let helper_id = i64_type.const_int(BPF_FUNC_get_current_pid_tgid as u64, false);
180 let helper_fn_type = i64_type.fn_type(&[], false);
181 let helper_fn_ptr = self
182 .builder
183 .build_int_to_ptr(helper_id, ptr_type, "get_pid_fn")
184 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
185 let pid_tgid = self
186 .builder
187 .build_indirect_call(helper_fn_type, helper_fn_ptr, &[], "pid_tgid")
188 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
189 .try_as_basic_value()
190 .left()
191 .ok_or_else(|| {
192 CodeGenError::LLVMError("get_current_pid_tgid returned void".to_string())
193 })?;
194 let pid = if let BasicValueEnum::IntValue(v) = pid_tgid {
195 let shifted = self
197 .builder
198 .build_right_shift(v, i64_type.const_int(32, false), false, "pid_shift")
199 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
200 self.builder
201 .build_int_truncate(shifted, i32_type, "pid32")
202 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
203 } else {
204 return Err(CodeGenError::LLVMError(
205 "pid_tgid is not IntValue".to_string(),
206 ));
207 };
208
209 self.builder
211 .build_store(base_i32_ptr, pid)
212 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
213
214 let idx1 = i32_type.const_int(1, false);
216 let pad_ptr = unsafe {
217 self.builder
218 .build_gep(self.context.i32_type(), base_i32_ptr, &[idx1], "pad_ptr")
219 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
220 };
221 self.builder
222 .build_store(pad_ptr, self.context.i32_type().const_zero())
223 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
224
225 let cookie_lo = i32_type.const_int(module_cookie & 0xffff_ffff, false);
227 let cookie_hi = i32_type.const_int(module_cookie >> 32, false);
228 let idx2 = i32_type.const_int(2, false);
229 let idx3 = i32_type.const_int(3, false);
230 let cookie_lo_ptr = unsafe {
232 self.builder
233 .build_gep(
234 self.context.i32_type(),
235 base_i32_ptr,
236 &[idx2],
237 "cookie_lo_ptr",
238 )
239 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
240 };
241 let cookie_hi_ptr = unsafe {
242 self.builder
243 .build_gep(
244 self.context.i32_type(),
245 base_i32_ptr,
246 &[idx3],
247 "cookie_hi_ptr",
248 )
249 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
250 };
251 self.builder
252 .build_store(cookie_lo_ptr, cookie_lo)
253 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
254 self.builder
255 .build_store(cookie_hi_ptr, cookie_hi)
256 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
257
258 let lookup_id = i64_type.const_int(BPF_FUNC_map_lookup_elem as u64, false);
260 let lookup_fn_type = ptr_type.fn_type(&[ptr_type.into(), ptr_type.into()], false);
261 let lookup_fn_ptr = self
262 .builder
263 .build_int_to_ptr(lookup_id, ptr_type, "lookup_fn")
264 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
265 let key_arg = self
267 .builder
268 .build_bit_cast(key_alloca, ptr_type, "key_arg")
269 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
270 let args: Vec<BasicMetadataValueEnum> = vec![map_ptr_cast.into(), key_arg.into()];
271 let val_ptr_any = self
272 .builder
273 .build_indirect_call(lookup_fn_type, lookup_fn_ptr, &args, "val_ptr_any")
274 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
275 .try_as_basic_value()
276 .left()
277 .ok_or_else(|| CodeGenError::LLVMError("map_lookup_elem returned void".to_string()))?;
278
279 let null_ptr = ptr_type.const_null();
280 let found_block = self.context.append_basic_block(
281 self.builder
282 .get_insert_block()
283 .unwrap()
284 .get_parent()
285 .unwrap(),
286 "found_offsets",
287 );
288 let miss_block = self.context.append_basic_block(
289 self.builder
290 .get_insert_block()
291 .unwrap()
292 .get_parent()
293 .unwrap(),
294 "miss_offsets",
295 );
296 let cont_block = self.context.append_basic_block(
297 self.builder
298 .get_insert_block()
299 .unwrap()
300 .get_parent()
301 .unwrap(),
302 "cont_offsets",
303 );
304
305 let val_ptr = if let BasicValueEnum::PointerValue(p) = val_ptr_any {
307 p
308 } else {
309 null_ptr
310 };
311 let is_null = self
312 .builder
313 .build_int_compare(
314 inkwell::IntPredicate::EQ,
315 self.builder
316 .build_ptr_to_int(val_ptr, i64_type, "val_ptr_i64")
317 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?,
318 i64_type.const_zero(),
319 "is_null_offsets",
320 )
321 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
322 self.builder
323 .build_conditional_branch(is_null, miss_block, found_block)
324 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
325
326 self.builder.position_at_end(found_block);
328 let i64_ptr_ty = self.context.ptr_type(AddressSpace::default());
331 let val_u64_ptr = self
332 .builder
333 .build_pointer_cast(val_ptr, i64_ptr_ty, "val_u64_ptr")
334 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
335 let load_field = |idx: u64,
336 ctx: &mut EbpfContext<'ctx>,
337 base: PointerValue<'ctx>|
338 -> Result<IntValue<'ctx>> {
339 let idx_i32 = ctx.context.i32_type().const_int(idx, false);
341 let field_ptr = unsafe {
342 ctx.builder
343 .build_gep(ctx.context.i64_type(), base, &[idx_i32], "field_ptr_i64")
344 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
345 };
346 let loaded = ctx
347 .builder
348 .build_load(ctx.context.i64_type(), field_ptr, "loaded_offset")
349 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
350 if let BasicValueEnum::IntValue(iv) = loaded {
351 Ok(iv)
352 } else {
353 Err(CodeGenError::LLVMError("offset load failed".to_string()))
354 }
355 };
356 let st = section_type;
357 let off_text = load_field(0, self, val_u64_ptr)?;
358 let off_rodata = load_field(1, self, val_u64_ptr)?;
359 let off_data = load_field(2, self, val_u64_ptr)?;
360 let off_bss = load_field(3, self, val_u64_ptr)?;
361 let st_val = i32_type.const_int(st as u64, false);
366 let eq_text = self
367 .builder
368 .build_int_compare(
369 inkwell::IntPredicate::EQ,
370 st_val,
371 i32_type.const_int(0, false),
372 "is_text",
373 )
374 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
375 let eq_ro = self
376 .builder
377 .build_int_compare(
378 inkwell::IntPredicate::EQ,
379 st_val,
380 i32_type.const_int(1, false),
381 "is_ro",
382 )
383 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
384 let eq_da = self
385 .builder
386 .build_int_compare(
387 inkwell::IntPredicate::EQ,
388 st_val,
389 i32_type.const_int(2, false),
390 "is_da",
391 )
392 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
393
394 let tmp_any = self
395 .builder
396 .build_select(eq_da, off_data, off_bss, "sel_data_bss")
397 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
398 let tmp = tmp_any.into_int_value();
399
400 let tmp2_any = self
401 .builder
402 .build_select(eq_ro, off_rodata, tmp, "sel_rodata_else")
403 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
404 let tmp2 = tmp2_any.into_int_value();
405
406 let off_final_any = self
407 .builder
408 .build_select(eq_text, off_text, tmp2, "sel_text_else")
409 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
410 let off_final = off_final_any.into_int_value();
411 let rt_addr = self
412 .builder
413 .build_int_add(link_addr, off_final, "runtime_addr")
414 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
415 self.builder
416 .build_unconditional_branch(cont_block)
417 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
418
419 self.builder.position_at_end(miss_block);
421 self.builder
422 .build_unconditional_branch(cont_block)
423 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
424
425 self.builder.position_at_end(cont_block);
427 let phi = self
428 .builder
429 .build_phi(i64_type, "addr_phi")
430 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
431 phi.add_incoming(&[(&rt_addr, found_block), (&link_addr, miss_block)]);
432 let final_addr = phi.as_basic_value().into_int_value();
433
434 let i1_type = self.context.bool_type();
436 let one = i1_type.const_int(1, false);
437 let zero = i1_type.const_int(0, false);
438 let flag_phi = self
439 .builder
440 .build_phi(i1_type, "off_found_phi")
441 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
442 flag_phi.add_incoming(&[(&one, found_block), (&zero, miss_block)]);
443 let found_flag = flag_phi.as_basic_value().into_int_value();
444
445 self.store_offsets_found_flag(found_flag)?;
446 Ok((final_addr, found_flag))
447 }
448 pub fn load_register_value(
450 &mut self,
451 reg_num: u16,
452 pt_regs_ptr: PointerValue<'ctx>,
453 ) -> Result<BasicValueEnum<'ctx>> {
454 if let Some(cached_value) = self.register_cache.get(®_num) {
456 return Ok((*cached_value).into());
457 }
458
459 let pt_regs_offset = self.dwarf_reg_to_pt_regs_offset(reg_num)?;
461
462 let i64_type = self.context.i64_type();
464 let offset_value = i64_type.const_int(pt_regs_offset as u64, false);
465
466 let reg_ptr = unsafe {
467 self.builder
468 .build_gep(
469 i64_type,
470 pt_regs_ptr,
471 &[offset_value],
472 &format!("reg_{reg_num}_ptr"),
473 )
474 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
475 };
476
477 let reg_value = self
479 .builder
480 .build_load(i64_type, reg_ptr, &format!("reg_{reg_num}"))
481 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
482
483 if let BasicValueEnum::IntValue(int_val) = reg_value {
484 self.register_cache.insert(reg_num, int_val);
486 Ok(reg_value)
487 } else {
488 Err(CodeGenError::RegisterMappingError(format!(
489 "Failed to load register {reg_num} as integer"
490 )))
491 }
492 }
493
494 pub fn generate_memory_read(
496 &mut self,
497 addr: IntValue<'ctx>,
498 size: MemoryAccessSize,
499 ) -> Result<BasicValueEnum<'ctx>> {
500 let i64_type = self.context.i64_type();
501 let ptr_type = self.context.ptr_type(AddressSpace::default());
502 let zero_const = i64_type.const_zero();
503 let offsets_found = self.load_offsets_found_flag()?;
504 let not_found = self
505 .builder
506 .build_not(offsets_found, "offsets_miss")
507 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
508
509 let result_size = size.bytes();
510 let buffer_name = format!("_temp_read_buffer_{result_size}");
511 let global_buffer = match self.module.get_global(&buffer_name) {
512 Some(existing) => existing.as_pointer_value(),
513 None => {
514 let array_type = self.context.i8_type().array_type(result_size as u32);
515 let global =
516 self.module
517 .add_global(array_type, Some(AddressSpace::default()), &buffer_name);
518 global.set_initializer(&array_type.const_zero());
519 global.as_pointer_value()
520 }
521 };
522
523 let stack_ptr = global_buffer;
524 let dst_ptr = self
525 .builder
526 .build_bit_cast(stack_ptr, ptr_type, "dst_ptr")
527 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
528 let base_src_ptr = self
529 .builder
530 .build_int_to_ptr(addr, ptr_type, "src_ptr")
531 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
532 let null_ptr = ptr_type.const_null();
533 let src_ptr = self
534 .builder
535 .build_select::<BasicValueEnum<'ctx>, _>(
536 offsets_found,
537 base_src_ptr.into(),
538 null_ptr.into(),
539 "src_or_null",
540 )
541 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
542 .into_pointer_value();
543
544 let i32_type = self.context.i32_type();
545 let helper_id = i64_type.const_int(BPF_FUNC_probe_read_user as u64, false);
546 let helper_fn_type =
547 i32_type.fn_type(&[ptr_type.into(), i32_type.into(), ptr_type.into()], false);
548 let helper_fn_ptr = self
549 .builder
550 .build_int_to_ptr(helper_id, ptr_type, "probe_read_user_fn")
551 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
552 let size_val = i32_type.const_int(result_size as u64, false);
553 let zero_i32 = i32_type.const_zero();
554 let effective_size = self
555 .builder
556 .build_select::<BasicValueEnum<'ctx>, _>(
557 offsets_found,
558 size_val.into(),
559 zero_i32.into(),
560 "size_or_zero",
561 )
562 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
563 .into_int_value();
564 let call_args: Vec<BasicMetadataValueEnum> =
565 vec![dst_ptr.into(), effective_size.into(), src_ptr.into()];
566
567 let _ = self
568 .builder
569 .build_indirect_call(
570 helper_fn_type,
571 helper_fn_ptr,
572 &call_args,
573 "probe_read_result",
574 )
575 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
576
577 let result_type: BasicTypeEnum = match size {
578 MemoryAccessSize::U8 => self.context.i8_type().into(),
579 MemoryAccessSize::U16 => self.context.i16_type().into(),
580 MemoryAccessSize::U32 => self.context.i32_type().into(),
581 MemoryAccessSize::U64 => self.context.i64_type().into(),
582 };
583 let typed_ptr = self
584 .builder
585 .build_bit_cast(
586 stack_ptr,
587 self.context.ptr_type(AddressSpace::default()),
588 "typed_ptr",
589 )
590 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
591 let loaded_value = if let BasicValueEnum::PointerValue(ptr) = typed_ptr {
592 self.builder
593 .build_load(result_type, ptr, "loaded_value")
594 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
595 } else {
596 return Err(CodeGenError::MemoryAccessError(
597 "Failed to cast result pointer".to_string(),
598 ));
599 };
600
601 let loaded_i64 = if let BasicValueEnum::IntValue(int_val) = loaded_value {
602 if int_val.get_type().get_bit_width() < 64 {
603 self.builder
604 .build_int_z_extend(int_val, i64_type, "extended")
605 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
606 } else {
607 int_val
608 }
609 } else {
610 return Err(CodeGenError::MemoryAccessError(
611 "Expected integer value from memory read".to_string(),
612 ));
613 };
614
615 let i8_type = self.context.i8_type();
617 let miss_i8 = self
618 .builder
619 .build_int_z_extend(not_found, i8_type, "miss_i8")
620 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
621 let fail_ptr = self.get_or_create_flag_global("_gs_any_fail");
622 let cur_fail = self
623 .builder
624 .build_load(i8_type, fail_ptr, "cur_fail")
625 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
626 .into_int_value();
627 let new_fail = self
628 .builder
629 .build_or(cur_fail, miss_i8, "fail_or_miss")
630 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
631 self.builder
632 .build_store(fail_ptr, new_fail)
633 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
634
635 let zero_bv: BasicValueEnum = zero_const.into();
636 let val_bv: BasicValueEnum = loaded_i64.into();
637 let sel = self
638 .builder
639 .build_select::<BasicValueEnum<'ctx>, _>(
640 offsets_found,
641 val_bv,
642 zero_bv,
643 "offset_value_or_zero",
644 )
645 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
646 Ok(sel)
647 }
648
649 pub fn generate_memory_read_with_status(
652 &mut self,
653 addr: IntValue<'ctx>,
654 size: MemoryAccessSize,
655 ) -> Result<BasicValueEnum<'ctx>> {
656 let i64_type = self.context.i64_type();
657 let ptr_type = self.context.ptr_type(AddressSpace::default());
658 let zero_const = i64_type.const_zero();
659
660 let offsets_found = self.load_offsets_found_flag()?;
661 let not_found = self
662 .builder
663 .build_not(offsets_found, "offsets_miss_cf")
664 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
665
666 let result_size = size.bytes();
667 let buffer_name = format!("_temp_read_buffer_{result_size}");
668 let global_buffer = match self.module.get_global(&buffer_name) {
669 Some(existing) => existing.as_pointer_value(),
670 None => {
671 let array_type = self.context.i8_type().array_type(result_size as u32);
672 let global =
673 self.module
674 .add_global(array_type, Some(AddressSpace::default()), &buffer_name);
675 global.set_initializer(&array_type.const_zero());
676 global.as_pointer_value()
677 }
678 };
679
680 let dst_ptr = self
681 .builder
682 .build_bit_cast(global_buffer, ptr_type, "dst_ptr")
683 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
684 let base_src_ptr = self
685 .builder
686 .build_int_to_ptr(addr, ptr_type, "src_ptr")
687 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
688 let null_ptr = ptr_type.const_null();
689 let src_ptr = self
690 .builder
691 .build_select::<BasicValueEnum<'ctx>, _>(
692 offsets_found,
693 base_src_ptr.into(),
694 null_ptr.into(),
695 "src_or_null_cf",
696 )
697 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
698 .into_pointer_value();
699
700 let i32_type = self.context.i32_type();
701 let helper_id = i64_type.const_int(BPF_FUNC_probe_read_user as u64, false);
702 let helper_fn_type =
703 i32_type.fn_type(&[ptr_type.into(), i32_type.into(), ptr_type.into()], false);
704 let helper_fn_ptr = self
705 .builder
706 .build_int_to_ptr(helper_id, ptr_type, "probe_read_user_fn")
707 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
708 let size_val = i32_type.const_int(result_size as u64, false);
709 let zero_i32 = i32_type.const_zero();
710 let effective_size = self
711 .builder
712 .build_select::<BasicValueEnum<'ctx>, _>(
713 offsets_found,
714 size_val.into(),
715 zero_i32.into(),
716 "size_or_zero_cf",
717 )
718 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
719 .into_int_value();
720 let call_args: Vec<BasicMetadataValueEnum> =
721 vec![dst_ptr.into(), effective_size.into(), src_ptr.into()];
722
723 let call_site = self
724 .builder
725 .build_indirect_call(
726 helper_fn_type,
727 helper_fn_ptr,
728 &call_args,
729 "probe_read_result_cf",
730 )
731 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
732 let ret_iv = call_site.try_as_basic_value().left().ok_or_else(|| {
733 CodeGenError::LLVMError("Expected integer return from helper".to_string())
734 })?;
735 let ret_i32 = ret_iv.into_int_value();
736
737 let read_fail = self
738 .builder
739 .build_int_compare(
740 inkwell::IntPredicate::NE,
741 ret_i32,
742 i32_type.const_zero(),
743 "read_fail",
744 )
745 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
746 let combined_fail = self
747 .builder
748 .build_or(read_fail, not_found, "combined_fail")
749 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
750
751 let cur_block = self.builder.get_insert_block().unwrap();
752 let func = cur_block.get_parent().unwrap();
753 let set_block = self.context.append_basic_block(func, "set_cond_err");
754 let cont_block = self.context.append_basic_block(func, "read_cont");
755 self.builder
756 .build_conditional_branch(combined_fail, set_block, cont_block)
757 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
758 self.builder.position_at_end(set_block);
759 let _ = self.set_condition_error_if_unset(2u8);
760 let _ = self.set_condition_error_addr_if_unset(addr);
761 self.builder
762 .build_unconditional_branch(cont_block)
763 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
764 self.builder.position_at_end(cont_block);
765
766 let result_type: BasicTypeEnum = match size {
767 MemoryAccessSize::U8 => self.context.i8_type().into(),
768 MemoryAccessSize::U16 => self.context.i16_type().into(),
769 MemoryAccessSize::U32 => self.context.i32_type().into(),
770 MemoryAccessSize::U64 => self.context.i64_type().into(),
771 };
772 let typed_ptr = self
773 .builder
774 .build_bit_cast(
775 global_buffer,
776 self.context.ptr_type(AddressSpace::default()),
777 "typed_ptr",
778 )
779 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
780 let loaded_value = self
781 .builder
782 .build_load(result_type, typed_ptr.into_pointer_value(), "loaded_value")
783 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
784 let loaded_i64 = if let BasicValueEnum::IntValue(iv) = loaded_value {
785 if iv.get_type().get_bit_width() < 64 {
786 self.builder
787 .build_int_z_extend(iv, i64_type, "ext_i64")
788 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
789 } else {
790 iv
791 }
792 } else {
793 return Err(CodeGenError::MemoryAccessError(
794 "Expected integer value from memory read".to_string(),
795 ));
796 };
797
798 let zero_bv: BasicValueEnum = zero_const.into();
799 let val_bv: BasicValueEnum = loaded_i64.into();
800 let sel_bv = self
801 .builder
802 .build_select::<BasicValueEnum<'ctx>, _>(combined_fail, zero_bv, val_bv, "val_or_zero")
803 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
804
805 let i8_type = self.context.i8_type();
806 let combined_fail_i8 = self
807 .builder
808 .build_int_z_extend(combined_fail, i8_type, "combined_fail_i8")
809 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
810 let fail_ptr = self.get_or_create_flag_global("_gs_any_fail");
811 let cur_fail = self
812 .builder
813 .build_load(i8_type, fail_ptr, "cur_fail_cf")
814 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
815 .into_int_value();
816 let new_fail = self
817 .builder
818 .build_or(cur_fail, combined_fail_i8, "fail_or_miss_cf")
819 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
820 self.builder
821 .build_store(fail_ptr, new_fail)
822 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
823
824 Ok(sel_bv)
825 }
826 pub fn dwarf_reg_to_pt_regs_offset(&self, dwarf_reg: u16) -> Result<usize> {
828 let byte_offset = register_mapping::dwarf_reg_to_pt_regs_byte_offset(dwarf_reg)
830 .ok_or_else(|| {
831 CodeGenError::RegisterMappingError(format!(
832 "Unsupported DWARF register: {dwarf_reg}"
833 ))
834 })?;
835
836 let u64_index = byte_offset / core::mem::size_of::<u64>();
838 Ok(u64_index)
839 }
840
841 pub fn create_bpf_helper_call(
844 &mut self,
845 helper_id: u64,
846 args: &[BasicValueEnum<'ctx>],
847 return_type: BasicTypeEnum<'ctx>,
848 call_name: &str,
849 ) -> Result<BasicValueEnum<'ctx>> {
850 use inkwell::types::BasicMetadataTypeEnum;
851
852 let arg_types: Vec<BasicMetadataTypeEnum> =
854 args.iter().map(|arg| arg.get_type().into()).collect();
855 let fn_type = return_type.fn_type(&arg_types, false);
856
857 let i64_type = self.context.i64_type();
859 let ptr_type = self.context.ptr_type(AddressSpace::default());
860
861 let helper_id_val = i64_type.const_int(helper_id, false);
862 let helper_fn_ptr = self
863 .builder
864 .build_int_to_ptr(helper_id_val, ptr_type, "helper_fn")
865 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
866
867 let metadata_args: Vec<BasicMetadataValueEnum> =
869 args.iter().map(|arg| (*arg).into()).collect();
870
871 let call_result = self
873 .builder
874 .build_indirect_call(fn_type, helper_fn_ptr, &metadata_args, call_name)
875 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
876
877 Ok(call_result.try_as_basic_value().left().unwrap_or_else(|| {
879 return_type.const_zero()
881 }))
882 }
883
884 pub fn get_current_timestamp(&mut self) -> Result<IntValue<'ctx>> {
886 let i64_type = self.context.i64_type();
887
888 let timestamp = self.create_bpf_helper_call(
890 BPF_FUNC_ktime_get_ns as u64,
891 &[],
892 i64_type.into(),
893 "timestamp",
894 )?;
895
896 if let BasicValueEnum::IntValue(int_val) = timestamp {
897 Ok(int_val)
898 } else {
899 Err(CodeGenError::LLVMError(
900 "bpf_ktime_get_ns did not return integer".to_string(),
901 ))
902 }
903 }
904
905 pub fn get_current_pid_tgid(&mut self) -> Result<IntValue<'ctx>> {
907 let i64_type = self.context.i64_type();
908
909 let pid_tgid = self.create_bpf_helper_call(
911 BPF_FUNC_get_current_pid_tgid as u64,
912 &[],
913 i64_type.into(),
914 "pid_tgid",
915 )?;
916
917 if let BasicValueEnum::IntValue(int_val) = pid_tgid {
918 Ok(int_val)
919 } else {
920 Err(CodeGenError::LLVMError(
921 "bpf_get_current_pid_tgid did not return integer".to_string(),
922 ))
923 }
924 }
925
926 pub fn create_event_output(&mut self, data: PointerValue<'ctx>, size: u64) -> Result<()> {
929 match self.compile_options.event_map_type {
930 crate::EventMapType::RingBuf => self.create_ringbuf_output_internal(data, size),
931 crate::EventMapType::PerfEventArray => {
932 self.create_perf_event_output_internal(data, size)
933 }
934 }
935 }
936
937 fn create_ringbuf_output_internal(
939 &mut self,
940 data: PointerValue<'ctx>,
941 size: u64,
942 ) -> Result<()> {
943 let i64_type = self.context.i64_type();
944
945 let ringbuf_global = self
947 .map_manager
948 .get_ringbuf_map(&self.module, "ringbuf")
949 .map_err(|e| {
950 CodeGenError::MemoryAccessError(format!("Failed to get ringbuf map: {e}"))
951 })?;
952
953 let args = [
955 ringbuf_global.into(),
956 data.into(),
957 i64_type.const_int(size, false).into(),
958 i64_type.const_zero().into(), ];
960
961 let _result = self.create_bpf_helper_call(
962 BPF_FUNC_ringbuf_output as u64,
963 &args,
964 i64_type.into(),
965 "ringbuf_output",
966 )?;
967
968 Ok(())
969 }
970
971 pub fn create_ringbuf_output_dynamic(
973 &mut self,
974 data: PointerValue<'ctx>,
975 size: IntValue<'ctx>,
976 ) -> Result<()> {
977 let i64_type = self.context.i64_type();
978
979 let ringbuf_global = self
981 .map_manager
982 .get_ringbuf_map(&self.module, "ringbuf")
983 .map_err(|e| {
984 CodeGenError::MemoryAccessError(format!("Failed to get ringbuf map: {e}"))
985 })?;
986
987 let args = [
989 ringbuf_global.into(),
990 data.into(),
991 size.into(),
992 i64_type.const_zero().into(), ];
994
995 let _result = self.create_bpf_helper_call(
996 BPF_FUNC_ringbuf_output as u64,
997 &args,
998 i64_type.into(),
999 "ringbuf_output",
1000 )?;
1001
1002 Ok(())
1003 }
1004
1005 pub fn lookup_percpu_value_ptr(
1007 &mut self,
1008 map_name: &str,
1009 key_const: u32,
1010 ) -> Result<PointerValue<'ctx>> {
1011 let ptr_ty = self.context.ptr_type(AddressSpace::default());
1012 let i32_ty = self.context.i32_type();
1013 let map_global = self
1014 .map_manager
1015 .get_map(&self.module, map_name)
1016 .map_err(|e| CodeGenError::LLVMError(format!("Map not found {map_name}: {e}")))?;
1017 let map_ptr = self
1018 .builder
1019 .build_bit_cast(map_global, ptr_ty, "map_ptr")
1020 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
1021
1022 let key_arr_ty = i32_ty.array_type(4);
1024 let key_alloca = self.pm_key_alloca.ok_or_else(|| {
1025 CodeGenError::LLVMError("pm_key not allocated in entry block".to_string())
1026 })?;
1027 let zero = i32_ty.const_zero();
1028 let base_i32_ptr = unsafe {
1029 self.builder
1030 .build_gep(key_arr_ty, key_alloca, &[zero, zero], "percpu_key_i32_ptr")
1031 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
1032 };
1033 self.builder
1034 .build_store(base_i32_ptr, i32_ty.const_int(key_const as u64, false))
1035 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
1036 let key_ptr = self
1037 .builder
1038 .build_bit_cast(base_i32_ptr, ptr_ty, "key_ptr")
1039 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
1040
1041 let ret = self.create_bpf_helper_call(
1043 BPF_FUNC_map_lookup_elem as u64,
1044 &[map_ptr, key_ptr],
1045 ptr_ty.into(),
1046 "map_lookup_elem",
1047 )?;
1048 let val_ptr = if let BasicValueEnum::PointerValue(p) = ret {
1049 p
1050 } else {
1051 return Err(CodeGenError::LLVMError(
1052 "map_lookup_elem did not return pointer".to_string(),
1053 ));
1054 };
1055 Ok(val_ptr)
1056 }
1057
1058 fn create_perf_event_output_internal(
1060 &mut self,
1061 data: PointerValue<'ctx>,
1062 size: u64,
1063 ) -> Result<()> {
1064 let size_val = self.context.i64_type().const_int(size, false);
1065 self.create_perf_event_output_dynamic(data, size_val)
1066 }
1067
1068 pub fn create_perf_event_output_dynamic(
1070 &mut self,
1071 data: PointerValue<'ctx>,
1072 size: IntValue<'ctx>,
1073 ) -> Result<()> {
1074 let i64_type = self.context.i64_type();
1075
1076 let ctx_param = self
1078 .builder
1079 .get_insert_block()
1080 .and_then(|bb| bb.get_parent())
1081 .and_then(|func| func.get_first_param())
1082 .ok_or_else(|| {
1083 CodeGenError::LLVMError("Failed to get context parameter".to_string())
1084 })?;
1085
1086 let events_global = self
1088 .map_manager
1089 .get_perf_map(&self.module, "events")
1090 .map_err(|e| {
1091 CodeGenError::MemoryAccessError(format!("Failed to get perf event map: {e}"))
1092 })?;
1093
1094 let args = [
1097 ctx_param,
1098 events_global.into(),
1099 i64_type.const_int(0xFFFFFFFF_u64, false).into(), data.into(),
1101 size.into(),
1102 ];
1103
1104 let _result = self.create_bpf_helper_call(
1105 BPF_FUNC_perf_event_output as u64,
1106 &args,
1107 i64_type.into(),
1108 "perf_event_output",
1109 )?;
1110
1111 Ok(())
1112 }
1113}