1use super::context::{CodeGenError, EbpfContext, Result};
6use crate::script::{BinaryOp, Expr};
7use aya_ebpf_bindings::bindings::bpf_func_id::BPF_FUNC_probe_read_user;
8use ghostscope_dwarf::TypeInfo as DwarfType;
9use inkwell::values::BasicValueEnum;
10use inkwell::AddressSpace;
11use tracing::debug;
12
13impl<'ctx> EbpfContext<'ctx> {
16 fn unwrap_dwarf_type_aliases(mut t: &DwarfType) -> &DwarfType {
17 loop {
18 match t {
19 DwarfType::TypedefType {
20 underlying_type, ..
21 } => t = underlying_type.as_ref(),
22 DwarfType::QualifiedType {
23 underlying_type, ..
24 } => t = underlying_type.as_ref(),
25 _ => break,
26 }
27 }
28 t
29 }
30
31 fn is_dwarf_aggregate_expr(&mut self, expr: &Expr) -> bool {
32 if let Ok(Some(var)) = self.query_dwarf_for_complex_expr(expr) {
33 if let Some(ref ty) = var.dwarf_type {
34 return matches!(
35 Self::unwrap_dwarf_type_aliases(ty),
36 DwarfType::StructType { .. }
37 | DwarfType::UnionType { .. }
38 | DwarfType::ArrayType { .. }
39 );
40 }
41 }
42 false
43 }
44
45 fn is_pointer_like_expr(&mut self, expr: &Expr) -> bool {
52 use crate::script::Expr as E;
53 match expr {
54 E::AddressOf(_) => return true,
55 E::String(_) => return true,
56 E::Variable(name) => {
57 if self.alias_variable_exists(name) {
58 return true;
59 }
60 }
61 _ => {}
62 }
63
64 if let Ok(Some(var)) = self.query_dwarf_for_complex_expr(expr) {
65 if let Some(ref ty) = var.dwarf_type {
66 let t = Self::unwrap_dwarf_type_aliases(ty);
67 if matches!(
68 t,
69 DwarfType::PointerType { .. } | DwarfType::ArrayType { .. }
70 ) {
71 return true;
72 }
73 }
74 }
75 false
76 }
77 fn ensure_dwarf_pointer_arg(&mut self, e: &Expr, where_ctx: &str) -> Result<()> {
80 if matches!(e, Expr::AddressOf(_)) {
82 return Ok(());
83 }
84 match self.query_dwarf_for_complex_expr(e) {
85 Ok(Some(var)) => {
86 let Some(mut ty) = var.dwarf_type.as_ref() else {
87 return Err(CodeGenError::TypeError(format!(
88 "{where_ctx}: DWARF variable has no type information"
89 )));
90 };
91 loop {
93 match ty {
94 DwarfType::TypedefType {
95 underlying_type, ..
96 } => ty = underlying_type.as_ref(),
97 DwarfType::QualifiedType {
98 underlying_type, ..
99 } => ty = underlying_type.as_ref(),
100 _ => break,
101 }
102 }
103 if !matches!(
104 ty,
105 DwarfType::PointerType { .. } | DwarfType::ArrayType { .. }
106 ) {
107 return Err(CodeGenError::TypeError(format!(
108 "{where_ctx}: only pointer or array DWARF variables are supported"
109 )));
110 }
111 Ok(())
112 }
113 Ok(None) | Err(_) => match self.compile_expr(e) {
115 Ok(BasicValueEnum::PointerValue(_)) => Ok(()),
116 _ => Err(CodeGenError::TypeError(format!(
117 "{where_ctx}: expression is not a pointer"
118 ))),
119 },
120 }
121 }
122
123 pub(crate) fn resolve_ptr_i64_from_expr(
126 &mut self,
127 e: &Expr,
128 ) -> Result<inkwell::values::IntValue<'ctx>> {
129 let mut visited = std::collections::HashSet::new();
130 self.resolve_ptr_i64_from_expr_internal(e, &mut visited, 0)
131 }
132
133 fn resolve_ptr_i64_from_expr_internal(
134 &mut self,
135 e: &Expr,
136 visited: &mut std::collections::HashSet<String>,
137 depth: usize,
138 ) -> Result<inkwell::values::IntValue<'ctx>> {
139 use crate::script::ast::BinaryOp as BO;
140 use crate::script::ast::Expr as E;
141 use inkwell::values::BasicValueEnum::*;
142 const MAX_DEPTH: usize = 64;
143 if depth > MAX_DEPTH {
144 return Err(CodeGenError::TypeError(
145 "alias expansion depth exceeded (cycle?)".into(),
146 ));
147 }
148 if let E::Variable(name) = e {
150 if self.alias_variable_exists(name) {
151 if !visited.insert(name.clone()) {
152 return Err(CodeGenError::TypeError(format!(
153 "alias cycle detected for '{name}'"
154 )));
155 }
156 if let Some(target) = self.get_alias_variable(name) {
157 let r = self.resolve_ptr_i64_from_expr_internal(&target, visited, depth + 1);
158 visited.remove(name);
159 return r;
160 }
161 }
162 }
163 if let E::AddressOf(inner) = e {
165 let resolved_inner: &E = if let E::Variable(name) = inner.as_ref() {
167 if self.alias_variable_exists(name) {
168 if let Some(target) = self.get_alias_variable(name) {
170 if let Some(var) = self.query_dwarf_for_complex_expr(&target)? {
171 let module_hint = self.current_resolved_var_module_path.clone();
172 let status_ptr = if self.condition_context_active {
173 Some(self.get_or_create_cond_error_global())
174 } else {
175 None
176 };
177 return self.evaluation_result_to_address_with_hint(
178 &var.evaluation_result,
179 status_ptr,
180 module_hint.as_deref(),
181 );
182 } else {
183 return Err(CodeGenError::TypeError(
184 "cannot take address of unresolved expression".into(),
185 ));
186 }
187 } else {
188 return Err(CodeGenError::TypeError(
189 "cannot take address of unresolved expression".into(),
190 ));
191 }
192 } else {
193 inner.as_ref()
194 }
195 } else {
196 inner.as_ref()
197 };
198
199 if let Some(var) = self.query_dwarf_for_complex_expr(resolved_inner)? {
200 let module_hint = self.current_resolved_var_module_path.clone();
201 let status_ptr = if self.condition_context_active {
202 Some(self.get_or_create_cond_error_global())
203 } else {
204 None
205 };
206 return self.evaluation_result_to_address_with_hint(
207 &var.evaluation_result,
208 status_ptr,
209 module_hint.as_deref(),
210 );
211 } else {
212 return Err(CodeGenError::TypeError(
213 "cannot take address of unresolved expression".into(),
214 ));
215 }
216 }
217
218 if let E::BinaryOp { left, op, right } = e {
220 if matches!(op, BO::Add) {
221 let is_nonneg_lit = |x: &E| matches!(x, E::Int(v) if *v >= 0);
222 if is_nonneg_lit(right) {
224 if let Ok(base) =
225 self.resolve_ptr_i64_from_expr_internal(left, visited, depth + 1)
226 {
227 if let E::Int(k) = &**right {
228 let off = self.context.i64_type().const_int(*k as u64, false);
229 return self
230 .builder
231 .build_int_add(base, off, "ptr_add")
232 .map_err(|e| CodeGenError::Builder(e.to_string()));
233 }
234 }
235 }
236 if is_nonneg_lit(left) {
238 if let Ok(base) =
239 self.resolve_ptr_i64_from_expr_internal(right, visited, depth + 1)
240 {
241 if let E::Int(k) = &**left {
242 let off = self.context.i64_type().const_int(*k as u64, false);
243 return self
244 .builder
245 .build_int_add(base, off, "ptr_add")
246 .map_err(|e| CodeGenError::Builder(e.to_string()));
247 }
248 }
249 }
250 }
251 }
252 if let Ok(Some(var)) = self.query_dwarf_for_complex_expr(e) {
255 if let Some(mut dty) = var.dwarf_type.as_ref() {
256 loop {
258 match dty {
259 DwarfType::TypedefType {
260 underlying_type, ..
261 } => dty = underlying_type.as_ref(),
262 DwarfType::QualifiedType {
263 underlying_type, ..
264 } => dty = underlying_type.as_ref(),
265 _ => break,
266 }
267 }
268 match dty {
269 DwarfType::PointerType { .. } => {
270 let val_any = self.evaluate_result_to_llvm_value(
271 &var.evaluation_result,
272 dty,
273 &var.name,
274 self.get_compile_time_context()?.pc_address,
275 )?;
276 match val_any {
277 IntValue(iv) => Ok(iv),
278 PointerValue(pv) => self
279 .builder
280 .build_ptr_to_int(pv, self.context.i64_type(), "ptr_as_i64")
281 .map_err(|e| CodeGenError::Builder(e.to_string())),
282 _ => Err(CodeGenError::TypeError(
283 "DWARF value is not pointer/integer".into(),
284 )),
285 }
286 }
287 DwarfType::ArrayType { .. } => {
288 let module_hint = self.current_resolved_var_module_path.clone();
290 let status_ptr = if self.condition_context_active {
291 Some(self.get_or_create_cond_error_global())
292 } else {
293 None
294 };
295 self.evaluation_result_to_address_with_hint(
296 &var.evaluation_result,
297 status_ptr,
298 module_hint.as_deref(),
299 )
300 }
301 _ => Err(CodeGenError::TypeError(
302 "DWARF value is not pointer/array".into(),
303 )),
304 }
305 } else {
306 let module_hint = self.current_resolved_var_module_path.clone();
307 let status_ptr = if self.condition_context_active {
308 Some(self.get_or_create_cond_error_global())
309 } else {
310 None
311 };
312 self.evaluation_result_to_address_with_hint(
313 &var.evaluation_result,
314 status_ptr,
315 module_hint.as_deref(),
316 )
317 }
318 } else {
319 Err(CodeGenError::TypeError(
321 "expression is not a pointer/address".into(),
322 ))
323 }
324 }
325 fn compile_memcmp_builtin(
328 &mut self,
329 a_expr: &Expr,
330 b_expr: &Expr,
331 len_expr: &Expr,
332 ) -> Result<BasicValueEnum<'ctx>> {
333 self.register_cache.clear();
338
339 let len_val = self.compile_expr(len_expr)?;
343 let len_iv = match len_val {
344 BasicValueEnum::IntValue(iv) => iv,
345 _ => {
346 return Err(CodeGenError::TypeError(
347 "memcmp length must be an integer expression".into(),
348 ))
349 }
350 };
351 let i32_ty = self.context.i32_type();
352 let len_i32 = if len_iv.get_type().get_bit_width() > 32 {
353 self.builder
354 .build_int_truncate(len_iv, i32_ty, "memcmp_len_trunc")
355 .map_err(|e| CodeGenError::Builder(e.to_string()))?
356 } else if len_iv.get_type().get_bit_width() < 32 {
357 self.builder
358 .build_int_z_extend(len_iv, i32_ty, "memcmp_len_zext")
359 .map_err(|e| CodeGenError::Builder(e.to_string()))?
360 } else {
361 len_iv
362 };
363 let zero_i32 = i32_ty.const_zero();
364 let is_neg = self
365 .builder
366 .build_int_compare(
367 inkwell::IntPredicate::SLT,
368 len_i32,
369 zero_i32,
370 "memcmp_len_neg",
371 )
372 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
373 let len_nn = self
374 .builder
375 .build_select(is_neg, zero_i32, len_i32, "memcmp_len_nn")
376 .map_err(|e| CodeGenError::Builder(e.to_string()))?
377 .into_int_value();
378 let cap = self.compile_options.compare_cap;
379 let cap_const = i32_ty.const_int(cap as u64, false);
380 let gt = self
381 .builder
382 .build_int_compare(
383 inkwell::IntPredicate::UGT,
384 len_nn,
385 cap_const,
386 "memcmp_len_gt",
387 )
388 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
389 let sel_len = self
390 .builder
391 .build_select(gt, cap_const, len_nn, "memcmp_len_sel")
392 .map_err(|e| CodeGenError::Builder(e.to_string()))?
393 .into_int_value();
394
395 let len_is_zero = self
397 .builder
398 .build_int_compare(
399 inkwell::IntPredicate::EQ,
400 sel_len,
401 i32_ty.const_zero(),
402 "memcmp_len_is_zero",
403 )
404 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
405 let curr_block = self.builder.get_insert_block().unwrap();
406 let func = curr_block.get_parent().unwrap();
407 let zero_b = self.context.append_basic_block(func, "memcmp_len_zero");
408 let nz_b = self.context.append_basic_block(func, "memcmp_len_nz");
409 let cont_b = self.context.append_basic_block(func, "memcmp_len_cont");
410 self.builder
411 .build_conditional_branch(len_is_zero, zero_b, nz_b)
412 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
413
414 self.builder.position_at_end(zero_b);
416 let bool_true = self.context.bool_type().const_int(1, false);
417 self.builder
418 .build_unconditional_branch(cont_b)
419 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
420 let zero_block = self.builder.get_insert_block().unwrap();
421
422 self.builder.position_at_end(nz_b);
424
425 let (arr_a_ty, buf_a) = self.get_or_create_i8_buffer(cap, "_gs_bi_memcmp_a");
427 let (arr_b_ty, buf_b) = self.get_or_create_i8_buffer(cap, "_gs_bi_memcmp_b");
428 let ptr_ty = self.context.ptr_type(AddressSpace::default());
429
430 let parse_hex_bytes = |e: &Expr| -> Option<Vec<u8>> {
432 if let Expr::BuiltinCall { name, args } = e {
433 if name == "hex" && args.len() == 1 {
434 if let Expr::String(s) = &args[0] {
435 if s.is_empty() {
437 return Some(Vec::new());
438 }
439 let mut out = Vec::with_capacity(s.len() / 2);
440 let mut i = 0usize;
441 while i + 1 < s.len() {
442 let v = u8::from_str_radix(&s[i..i + 2], 16).ok()?;
443 out.push(v);
444 i += 2;
445 }
446 return Some(out);
447 }
448 }
449 }
450 None
451 };
452
453 if parse_hex_bytes(a_expr).is_none() {
456 self.ensure_dwarf_pointer_arg(a_expr, "memcmp arg0")?;
457 }
458 let ok_a = if let Some(bytes) = parse_hex_bytes(a_expr) {
459 let i32_ty = self.context.i32_type();
460 let idx0 = i32_ty.const_zero();
461 for i in 0..(cap as usize) {
462 let idx_i = i32_ty.const_int(i as u64, false);
463 let pa = unsafe {
464 self.builder
465 .build_gep(arr_a_ty, buf_a, &[idx0, idx_i], &format!("hex_a_i{i}"))
466 .map_err(|e| CodeGenError::Builder(e.to_string()))?
467 };
468 let byte = if i < bytes.len() { bytes[i] } else { 0 } as u64;
469 let bv = self.context.i8_type().const_int(byte, false);
470 self.builder
471 .build_store(pa, bv)
472 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
473 }
474 self.context.bool_type().const_int(1, false)
475 } else {
476 let ptr_a = self.resolve_ptr_i64_from_expr(a_expr)?;
478 let offsets_found_a = self.load_offsets_found_flag()?;
479 let dst_a = self
480 .builder
481 .build_bit_cast(buf_a, ptr_ty, "memcmp_dst_a")
482 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
483 let base_src_a = self
484 .builder
485 .build_int_to_ptr(ptr_a, ptr_ty, "memcmp_src_a")
486 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
487 let null_ptr = ptr_ty.const_null();
488 let src_a = self
489 .builder
490 .build_select::<BasicValueEnum<'ctx>, _>(
491 offsets_found_a,
492 base_src_a.into(),
493 null_ptr.into(),
494 "memcmp_src_a_or_null",
495 )
496 .map_err(|e| CodeGenError::Builder(e.to_string()))?
497 .into_pointer_value();
498 let zero_i32 = self.context.i32_type().const_zero();
499 let effective_len_a = self
500 .builder
501 .build_select::<BasicValueEnum<'ctx>, _>(
502 offsets_found_a,
503 sel_len.into(),
504 zero_i32.into(),
505 "memcmp_len_a_or_zero",
506 )
507 .map_err(|e| CodeGenError::Builder(e.to_string()))?
508 .into_int_value();
509 let ret_a = self
510 .create_bpf_helper_call(
511 BPF_FUNC_probe_read_user as u64,
512 &[dst_a, effective_len_a.into(), src_a.into()],
513 self.context.i64_type().into(),
514 "probe_read_user_memcmp_a",
515 )?
516 .into_int_value();
517 let i64_ty = self.context.i64_type();
518 let eq_a = self
519 .builder
520 .build_int_compare(
521 inkwell::IntPredicate::EQ,
522 ret_a,
523 i64_ty.const_zero(),
524 "memcmp_ok_a",
525 )
526 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
527 self.builder
528 .build_and(eq_a, offsets_found_a, "memcmp_ok_a")
529 .map_err(|e| CodeGenError::Builder(e.to_string()))?
530 };
531
532 if parse_hex_bytes(b_expr).is_none() {
534 self.ensure_dwarf_pointer_arg(b_expr, "memcmp arg1")?;
535 }
536 let ok_b = if let Some(bytes) = parse_hex_bytes(b_expr) {
537 let i32_ty = self.context.i32_type();
538 let idx0 = i32_ty.const_zero();
539 for i in 0..(cap as usize) {
540 let idx_i = i32_ty.const_int(i as u64, false);
541 let pb = unsafe {
542 self.builder
543 .build_gep(arr_b_ty, buf_b, &[idx0, idx_i], &format!("hex_b_i{i}"))
544 .map_err(|e| CodeGenError::Builder(e.to_string()))?
545 };
546 let byte = if i < bytes.len() { bytes[i] } else { 0 } as u64;
547 let bv = self.context.i8_type().const_int(byte, false);
548 self.builder
549 .build_store(pb, bv)
550 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
551 }
552 self.context.bool_type().const_int(1, false)
553 } else {
554 let ptr_b = self.resolve_ptr_i64_from_expr(b_expr)?;
556 let offsets_found_b = self.load_offsets_found_flag()?;
557 let dst_b = self
558 .builder
559 .build_bit_cast(buf_b, ptr_ty, "memcmp_dst_b")
560 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
561 let base_src_b = self
562 .builder
563 .build_int_to_ptr(ptr_b, ptr_ty, "memcmp_src_b")
564 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
565 let null_ptr = ptr_ty.const_null();
566 let src_b = self
567 .builder
568 .build_select::<BasicValueEnum<'ctx>, _>(
569 offsets_found_b,
570 base_src_b.into(),
571 null_ptr.into(),
572 "memcmp_src_b_or_null",
573 )
574 .map_err(|e| CodeGenError::Builder(e.to_string()))?
575 .into_pointer_value();
576 let zero_i32 = self.context.i32_type().const_zero();
577 let effective_len_b = self
578 .builder
579 .build_select::<BasicValueEnum<'ctx>, _>(
580 offsets_found_b,
581 sel_len.into(),
582 zero_i32.into(),
583 "memcmp_len_b_or_zero",
584 )
585 .map_err(|e| CodeGenError::Builder(e.to_string()))?
586 .into_int_value();
587 let ret_b = self
588 .create_bpf_helper_call(
589 BPF_FUNC_probe_read_user as u64,
590 &[dst_b, effective_len_b.into(), src_b.into()],
591 self.context.i64_type().into(),
592 "probe_read_user_memcmp_b",
593 )?
594 .into_int_value();
595 let i64_ty = self.context.i64_type();
596 let eq_b = self
597 .builder
598 .build_int_compare(
599 inkwell::IntPredicate::EQ,
600 ret_b,
601 i64_ty.const_zero(),
602 "memcmp_ok_b",
603 )
604 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
605 self.builder
606 .build_and(eq_b, offsets_found_b, "memcmp_ok_b")
607 .map_err(|e| CodeGenError::Builder(e.to_string()))?
608 };
609
610 let status_ok = self
611 .builder
612 .build_and(ok_a, ok_b, "memcmp_status_ok")
613 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
614
615 if self.condition_context_active {
617 let not_a = self
618 .builder
619 .build_not(ok_a, "memcmp_fail_a")
620 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
621 let not_b = self
622 .builder
623 .build_not(ok_b, "memcmp_fail_b")
624 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
625 let any_fail = self
626 .builder
627 .build_or(not_a, not_b, "memcmp_any_fail")
628 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
629 let cur_block = self.builder.get_insert_block().unwrap();
630 let func = cur_block.get_parent().unwrap();
631 let set_b = self.context.append_basic_block(func, "memcmp_set_err");
632 let cont_b = self.context.append_basic_block(func, "memcmp_cont");
633 self.builder
634 .build_conditional_branch(any_fail, set_b, cont_b)
635 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
636 self.builder.position_at_end(set_b);
637 let _ = self.set_condition_error_if_unset(2u8);
639 let not_a_val = self
641 .builder
642 .build_not(ok_a, "memcmp_fail_a_val")
643 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
644 let not_b_val = self
645 .builder
646 .build_not(ok_b, "memcmp_fail_b_val")
647 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
648 let cur_fn = self
649 .builder
650 .get_insert_block()
651 .unwrap()
652 .get_parent()
653 .unwrap();
654 let set_a_bb = self.context.append_basic_block(cur_fn, "set_addr_a");
655 let check_b_bb = self.context.append_basic_block(cur_fn, "check_fail_b");
656 let set_b_bb = self.context.append_basic_block(cur_fn, "set_addr_b");
657 let after_set_bb = self.context.append_basic_block(cur_fn, "after_set_addr");
658
659 self.builder
661 .build_conditional_branch(not_a_val, set_a_bb, check_b_bb)
662 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
663
664 self.builder.position_at_end(set_a_bb);
666 if let Some(pa) = match parse_hex_bytes(a_expr) {
667 Some(_) => None,
668 None => Some(self.resolve_ptr_i64_from_expr(a_expr)?),
669 } {
670 let _ = self.set_condition_error_addr_if_unset(pa);
671 }
672 self.builder
673 .build_unconditional_branch(after_set_bb)
674 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
675
676 self.builder.position_at_end(check_b_bb);
678 self.builder
679 .build_conditional_branch(not_b_val, set_b_bb, after_set_bb)
680 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
681 self.builder.position_at_end(set_b_bb);
682 if let Some(pb) = match parse_hex_bytes(b_expr) {
683 Some(_) => None,
684 None => Some(self.resolve_ptr_i64_from_expr(b_expr)?),
685 } {
686 let _ = self.set_condition_error_addr_if_unset(pb);
687 }
688 self.builder
689 .build_unconditional_branch(after_set_bb)
690 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
691 self.builder.position_at_end(after_set_bb);
692 let i8t = self.context.i8_type();
694 let b_a = self
695 .builder
696 .build_int_z_extend(
697 self.builder
698 .build_not(ok_a, "fa")
699 .map_err(|e| CodeGenError::Builder(e.to_string()))?,
700 i8t,
701 "fa8",
702 )
703 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
704 let b_b1 = self
705 .builder
706 .build_int_z_extend(
707 self.builder
708 .build_not(ok_b, "fb")
709 .map_err(|e| CodeGenError::Builder(e.to_string()))?,
710 i8t,
711 "fb8",
712 )
713 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
714 let sh1 = self
715 .builder
716 .build_left_shift(b_b1, i8t.const_int(1, false), "b_b_shift")
717 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
718 let b_c = self
720 .builder
721 .build_int_z_extend(gt, i8t, "clamped8")
722 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
723 let sh2 = self
724 .builder
725 .build_left_shift(b_c, i8t.const_int(2, false), "b_c_shift")
726 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
727 let b_z = self
729 .builder
730 .build_int_z_extend(len_is_zero, i8t, "len0_8")
731 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
732 let sh3 = self
733 .builder
734 .build_left_shift(b_z, i8t.const_int(3, false), "b_z_shift")
735 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
736 let f01 = self
737 .builder
738 .build_or(b_a, sh1, "f01")
739 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
740 let f012 = self
741 .builder
742 .build_or(f01, sh2, "f012")
743 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
744 let flags = self
745 .builder
746 .build_or(f012, sh3, "flags")
747 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
748 let _ = self.or_condition_error_flags(flags);
749 self.builder
750 .build_unconditional_branch(cont_b)
751 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
752 self.builder.position_at_end(cont_b);
753 }
754
755 let i32_ty = self.context.i32_type();
757 let idx0 = i32_ty.const_zero();
758 let mut acc = self.context.i8_type().const_zero();
759 for i in 0..cap as usize {
760 let idx_i = i32_ty.const_int(i as u64, false);
761 let active = self
763 .builder
764 .build_int_compare(
765 inkwell::IntPredicate::ULT,
766 idx_i,
767 sel_len,
768 &format!("memcmp_i{i}_active"),
769 )
770 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
771 let pa = unsafe {
773 self.builder
774 .build_gep(arr_a_ty, buf_a, &[idx0, idx_i], &format!("memcmp_a_i{i}"))
775 .map_err(|e| CodeGenError::Builder(e.to_string()))?
776 };
777 let va = self
778 .builder
779 .build_load(self.context.i8_type(), pa, &format!("ld_a_{i}"))
780 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
781 let va = match va {
782 BasicValueEnum::IntValue(iv) => iv,
783 _ => return Err(CodeGenError::LLVMError("memcmp load a != i8".into())),
784 };
785 let pb = unsafe {
787 self.builder
788 .build_gep(arr_b_ty, buf_b, &[idx0, idx_i], &format!("memcmp_b_i{i}"))
789 .map_err(|e| CodeGenError::Builder(e.to_string()))?
790 };
791 let vb = self
792 .builder
793 .build_load(self.context.i8_type(), pb, &format!("ld_b_{i}"))
794 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
795 let vb = match vb {
796 BasicValueEnum::IntValue(iv) => iv,
797 _ => return Err(CodeGenError::LLVMError("memcmp load b != i8".into())),
798 };
799 let diff = self
800 .builder
801 .build_xor(va, vb, &format!("memcmp_diff_{i}"))
802 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
803 let zero8 = self.context.i8_type().const_zero();
804 let masked = self
805 .builder
806 .build_select(active, diff, zero8, &format!("memcmp_masked_{i}"))
807 .map_err(|e| CodeGenError::Builder(e.to_string()))?
808 .into_int_value();
809 acc = self
810 .builder
811 .build_or(acc, masked, &format!("memcmp_acc_{i}"))
812 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
813 }
814 let eq_bytes = self
815 .builder
816 .build_int_compare(
817 inkwell::IntPredicate::EQ,
818 acc,
819 self.context.i8_type().const_zero(),
820 "memcmp_acc_zero",
821 )
822 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
823 let nz_result = self
824 .builder
825 .build_and(status_ok, eq_bytes, "memcmp_and")
826 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
827
828 self.builder
829 .build_unconditional_branch(cont_b)
830 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
831 let nz_block = self.builder.get_insert_block().unwrap();
832
833 self.builder.position_at_end(cont_b);
835 let phi = self
836 .builder
837 .build_phi(self.context.bool_type(), "memcmp_phi")
838 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
839 phi.add_incoming(&[(&bool_true, zero_block), (&nz_result, nz_block)]);
840 Ok(phi.as_basic_value())
841 }
842 fn compile_strncmp_builtin(
844 &mut self,
845 dwarf_expr: &Expr,
846 lit: &str,
847 n: u32,
848 ) -> Result<BasicValueEnum<'ctx>> {
849 let immediate_bytes_opt = match dwarf_expr {
852 Expr::Variable(name) => {
853 if self
854 .get_variable_type(name)
855 .is_some_and(|t| matches!(t, crate::script::VarType::String))
856 {
857 self.get_string_variable_bytes(name).cloned()
858 } else {
859 None
860 }
861 }
862 Expr::String(s) => {
863 let mut b = s.as_bytes().to_vec();
864 b.push(0);
865 Some(b)
866 }
867 _ => None,
868 };
869
870 if let Some(bytes) = immediate_bytes_opt {
871 let lit_bytes = lit.as_bytes();
873 let cap = self.compile_options.compare_cap as usize;
874 let n_usize = std::cmp::min(n as usize, cap);
875 let content_len = bytes.iter().position(|&b| b == 0).unwrap_or(bytes.len());
877 let cmp_len = std::cmp::min(n_usize, std::cmp::min(content_len, lit_bytes.len()));
878 let equal =
879 bytes.get(0..cmp_len).unwrap_or(&[]) == lit_bytes.get(0..cmp_len).unwrap_or(&[]);
880 let bool_val = self
881 .context
882 .bool_type()
883 .const_int(if equal { 1 } else { 0 }, false);
884 return Ok(bool_val.into());
885 }
886
887 let ptr_i64 = match self.query_dwarf_for_complex_expr(dwarf_expr)? {
890 Some(var) => {
891 if let Some(mut ty) = var.dwarf_type.as_ref() {
892 loop {
893 match ty {
894 DwarfType::TypedefType {
895 underlying_type, ..
896 } => ty = underlying_type.as_ref(),
897 DwarfType::QualifiedType {
898 underlying_type, ..
899 } => ty = underlying_type.as_ref(),
900 _ => break,
901 }
902 }
903 match ty {
904 DwarfType::PointerType { .. } => {
905 let val_any = self.evaluate_result_to_llvm_value(
906 &var.evaluation_result,
907 ty,
908 &var.name,
909 self.get_compile_time_context()?.pc_address,
910 )?;
911 match val_any {
912 BasicValueEnum::IntValue(iv) => iv,
913 BasicValueEnum::PointerValue(pv) => self
914 .builder
915 .build_ptr_to_int(pv, self.context.i64_type(), "ptr_as_i64")
916 .map_err(|e| CodeGenError::Builder(e.to_string()))?,
917 _ => {
918 return Err(CodeGenError::TypeError(
919 "strncmp requires pointer/integer value for pointer; got unsupported DWARF value".into(),
920 ))
921 }
922 }
923 }
924 DwarfType::ArrayType { .. } => {
925 let module_hint = self.current_resolved_var_module_path.clone();
926 let status_ptr = if self.condition_context_active {
927 Some(self.get_or_create_cond_error_global())
928 } else {
929 None
930 };
931 self.evaluation_result_to_address_with_hint(
932 &var.evaluation_result,
933 status_ptr,
934 module_hint.as_deref(),
935 )?
936 }
937 _ => {
938 return Err(CodeGenError::TypeError(
940 "strncmp requires the non-string side to be an address expression (pointer/array)".into(),
941 ));
942 }
943 }
944 } else {
945 return Err(CodeGenError::TypeError(
946 "strncmp non-string side lacks DWARF type info".into(),
947 ));
948 }
949 }
950 None => {
951 self.resolve_ptr_i64_from_expr(dwarf_expr).map_err(|_| {
953 CodeGenError::TypeError(
954 "strncmp requires at least one string argument, and the other side must be an address expression (DWARF pointer/array or alias)".to_string(),
955 )
956 })?
957 }
958 };
959
960 let cap = self.compile_options.compare_cap;
962 let max_n = std::cmp::min(n, cap);
963 let lit_len = std::cmp::min(lit.len() as u32, cap);
964 let cmp_len = std::cmp::min(max_n, lit_len);
965
966 let (buf_global, status, arr_ty) =
968 self.read_user_bytes_into_buffer(ptr_i64, cmp_len, "_gs_bi_strncmp")?;
969 let status_ok = self
970 .builder
971 .build_int_compare(
972 inkwell::IntPredicate::EQ,
973 status,
974 self.context.i64_type().const_zero(),
975 "rd_ok",
976 )
977 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
978
979 if self.condition_context_active {
981 let cur_block = self.builder.get_insert_block().unwrap();
982 let func = cur_block.get_parent().unwrap();
983 let set_b = self.context.append_basic_block(func, "strncmp_set_err");
984 let cont_b = self.context.append_basic_block(func, "strncmp_cont");
985 let not_ok = self
986 .builder
987 .build_not(status_ok, "rd_fail")
988 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
989 self.builder
990 .build_conditional_branch(not_ok, set_b, cont_b)
991 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
992 self.builder.position_at_end(set_b);
993 let _ = self.set_condition_error_if_unset(2u8);
995 let _ = self.set_condition_error_addr_if_unset(ptr_i64);
996 let one = self.context.i8_type().const_int(1, false);
998 let _ = self.or_condition_error_flags(one);
999 self.builder
1000 .build_unconditional_branch(cont_b)
1001 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1002 self.builder.position_at_end(cont_b);
1003 }
1004
1005 let i32_ty = self.context.i32_type();
1007 let idx0 = i32_ty.const_zero();
1008 let mut acc = self.context.i8_type().const_zero();
1009 for (i, b) in lit.as_bytes().iter().take(cmp_len as usize).enumerate() {
1010 let idx_i = i32_ty.const_int(i as u64, false);
1011 let ptr_i = unsafe {
1012 self.builder
1013 .build_gep(arr_ty, buf_global, &[idx0, idx_i], "ch_ptr")
1014 .map_err(|e| CodeGenError::Builder(e.to_string()))?
1015 };
1016 let ch = self
1017 .builder
1018 .build_load(self.context.i8_type(), ptr_i, "ch")
1019 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1020 let ch = match ch {
1021 BasicValueEnum::IntValue(iv) => iv,
1022 _ => return Err(CodeGenError::LLVMError("load did not return i8".into())),
1023 };
1024 let expect = self.context.i8_type().const_int(*b as u64, false);
1025 let diff = self
1026 .builder
1027 .build_xor(ch, expect, "diff")
1028 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1029 acc = self
1030 .builder
1031 .build_or(acc, diff, "acc_or")
1032 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1033 }
1034 let eq_bytes = self
1035 .builder
1036 .build_int_compare(
1037 inkwell::IntPredicate::EQ,
1038 acc,
1039 self.context.i8_type().const_zero(),
1040 "acc_zero",
1041 )
1042 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1043
1044 let result = self
1045 .builder
1046 .build_and(status_ok, eq_bytes, "strncmp_and")
1047 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1048 Ok(result.into())
1049 }
1050 pub fn compile_expr(&mut self, expr: &Expr) -> Result<BasicValueEnum<'ctx>> {
1052 match expr {
1053 Expr::Int(value) => {
1054 let int_value = self.context.i64_type().const_int(*value as u64, true);
1056 debug!(
1057 "compile_expr: Int literal {} compiled to IntValue with bit width {}",
1058 value,
1059 int_value.get_type().get_bit_width()
1060 );
1061 Ok(int_value.into())
1062 }
1063 Expr::Float(_value) => Err(CodeGenError::TypeError(
1064 "Floating point expressions are not supported".to_string(),
1065 )),
1066 Expr::String(value) => {
1067 let string_value = self.context.const_string(value.as_bytes(), true);
1069 let global = self
1070 .module
1071 .add_global(string_value.get_type(), None, "str_const");
1072 global.set_initializer(&string_value);
1073
1074 let ptr_type = self.context.ptr_type(AddressSpace::default());
1075 let cast_ptr = self
1076 .builder
1077 .build_bit_cast(global.as_pointer_value(), ptr_type, "str_ptr")
1078 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1079 Ok(cast_ptr)
1080 }
1081 Expr::Bool(value) => {
1082 let b = self
1084 .context
1085 .bool_type()
1086 .const_int(if *value { 1 } else { 0 }, false);
1087 Ok(b.into())
1088 }
1089 Expr::UnaryNot(inner) => {
1090 let v = self.compile_expr(inner)?;
1092 let iv = match v {
1093 BasicValueEnum::IntValue(iv) => iv,
1094 _ => {
1095 return Err(CodeGenError::TypeError(
1096 "Logical NOT requires integer/boolean operand".to_string(),
1097 ))
1098 }
1099 };
1100 let zero = iv.get_type().const_zero();
1101 let res = self
1102 .builder
1103 .build_int_compare(inkwell::IntPredicate::EQ, iv, zero, "not_eq0")
1104 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1105 Ok(res.into())
1106 }
1107 Expr::Variable(var_name) => {
1108 debug!("compile_expr: Compiling variable expression: {}", var_name);
1109
1110 if self.alias_variable_exists(var_name) {
1112 debug!(
1113 "compile_expr: '{}' is an alias variable; resolving to runtime address",
1114 var_name
1115 );
1116 let aliased = self
1117 .get_alias_variable(var_name)
1118 .expect("alias existence just checked");
1119 let addr_i64 = self.resolve_ptr_i64_from_expr(&aliased)?;
1121 let ptr_ty = self.context.ptr_type(AddressSpace::default());
1122 let as_ptr = self
1123 .builder
1124 .build_int_to_ptr(addr_i64, ptr_ty, "alias_as_ptr")
1125 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1126 return Ok(as_ptr.into());
1127 }
1128
1129 if self.variable_exists(var_name) {
1131 debug!("compile_expr: Found script variable: {}", var_name);
1132 let loaded_value = self.load_variable(var_name)?;
1133 debug!(
1134 "compile_expr: Loaded variable '{}' with type: {:?}",
1135 var_name,
1136 loaded_value.get_type()
1137 );
1138 match &loaded_value {
1139 BasicValueEnum::IntValue(iv) => debug!(
1140 "compile_expr: Variable '{}' is IntValue with bit width {}",
1141 var_name,
1142 iv.get_type().get_bit_width()
1143 ),
1144 BasicValueEnum::FloatValue(_) => {
1145 debug!("compile_expr: Variable '{}' is FloatValue", var_name)
1146 }
1147 BasicValueEnum::PointerValue(_) => {
1148 debug!("compile_expr: Variable '{}' is PointerValue", var_name)
1149 }
1150 _ => debug!("compile_expr: Variable '{}' is other type", var_name),
1151 }
1152 return Ok(loaded_value);
1153 }
1154
1155 debug!(
1157 "Variable '{}' not found in script variables, checking DWARF",
1158 var_name
1159 );
1160 match self.query_dwarf_for_variable(var_name) {
1162 Ok(Some(_)) => self.compile_dwarf_expression(expr),
1163 Ok(None) => Err(CodeGenError::VariableNotInScope(var_name.clone())),
1164 Err(e) => Err(CodeGenError::DwarfError(e.to_string())),
1165 }
1166 }
1167 Expr::SpecialVar(name) => {
1168 let sanitized = name.trim_start_matches('$');
1170 self.handle_special_variable(sanitized)
1171 }
1172 Expr::BuiltinCall { name, args } => match name.as_str() {
1173 "memcmp" => {
1174 if args.len() != 3 {
1175 return Err(CodeGenError::TypeError("memcmp expects 3 arguments".into()));
1176 }
1177 self.compile_memcmp_builtin(&args[0], &args[1], &args[2])
1178 }
1179 "strncmp" => {
1180 if args.len() != 3 {
1181 return Err(CodeGenError::TypeError(
1182 "strncmp expects 3 arguments".into(),
1183 ));
1184 }
1185 let n = match &args[2] {
1186 Expr::Int(v) if *v >= 0 => *v as u32,
1187 _ => {
1188 return Err(CodeGenError::TypeError(
1189 "strncmp length must be a non-negative integer literal".into(),
1190 ))
1191 }
1192 };
1193 fn extract_script_string<'a>(
1195 this: &mut EbpfContext<'a>,
1196 e: &Expr,
1197 ) -> Option<String> {
1198 match e {
1199 Expr::String(s) => Some(s.clone()),
1200 Expr::Variable(name) => this
1201 .get_variable_type(name)
1202 .is_some_and(|t| matches!(t, crate::script::VarType::String))
1203 .then(|| {
1204 this.get_string_variable_bytes(name).map(|b| {
1205 let cut = b.iter().position(|&x| x == 0).unwrap_or(b.len());
1206 String::from_utf8_lossy(&b[..cut]).to_string()
1207 })
1208 })
1209 .flatten(),
1210 _ => None,
1211 }
1212 }
1213 let left_str = extract_script_string(self, &args[0]);
1214 let right_str = extract_script_string(self, &args[1]);
1215 match (left_str, right_str) {
1216 (Some(ls), Some(rs)) => {
1217 let ln = n as usize;
1219 let eq = ls.as_bytes().iter().take(ln).eq(rs.as_bytes().iter().take(ln));
1220 let bv = self.context.bool_type().const_int(eq as u64, false);
1221 Ok(bv.into())
1222 }
1223 (Some(ls), None) => self.compile_strncmp_builtin(&args[1], &ls, n),
1224 (None, Some(rs)) => self.compile_strncmp_builtin(&args[0], &rs, n),
1225 (None, None) => Err(CodeGenError::TypeError(
1226 "strncmp requires at least one string argument (string literal or script string variable) as the first or second parameter".into(),
1227 )),
1228 }
1229 }
1230 "starts_with" => {
1231 if args.len() != 2 {
1232 return Err(CodeGenError::TypeError(
1233 "starts_with expects 2 arguments".into(),
1234 ));
1235 }
1236 fn extract_script_string<'a>(
1238 this: &mut EbpfContext<'a>,
1239 e: &Expr,
1240 ) -> Option<String> {
1241 match e {
1242 Expr::String(s) => Some(s.clone()),
1243 Expr::Variable(name) => this
1244 .get_variable_type(name)
1245 .is_some_and(|t| matches!(t, crate::script::VarType::String))
1246 .then(|| {
1247 this.get_string_variable_bytes(name).map(|b| {
1248 let cut = b.iter().position(|&x| x == 0).unwrap_or(b.len());
1249 String::from_utf8_lossy(&b[..cut]).to_string()
1250 })
1251 })
1252 .flatten(),
1253 _ => None,
1254 }
1255 }
1256 let s0 = extract_script_string(self, &args[0]);
1257 let s1 = extract_script_string(self, &args[1]);
1258 match (s0, s1) {
1259 (Some(a), Some(b)) => {
1260 let ok = a.as_bytes().starts_with(b.as_bytes());
1262 let bv = self.context.bool_type().const_int(ok as u64, false);
1263 Ok(bv.into())
1264 }
1265 (Some(a), None) => self.compile_strncmp_builtin(&args[1], &a, a.len() as u32),
1266 (None, Some(b)) => self.compile_strncmp_builtin(&args[0], &b, b.len() as u32),
1267 (None, None) => Err(CodeGenError::TypeError(
1268 "starts_with requires at least one string argument (string literal or script string variable) as the first or second parameter".into(),
1269 )),
1270 }
1271 }
1272 _ => Err(CodeGenError::NotImplemented(format!(
1273 "Unknown builtin function: {name}"
1274 ))),
1275 },
1276 Expr::BinaryOp { left, op, right } => {
1277 let is_arith = matches!(
1279 op,
1280 BinaryOp::Add | BinaryOp::Subtract | BinaryOp::Multiply | BinaryOp::Divide
1281 );
1282 let is_ordered = matches!(
1283 op,
1284 BinaryOp::LessThan
1285 | BinaryOp::LessEqual
1286 | BinaryOp::GreaterThan
1287 | BinaryOp::GreaterEqual
1288 );
1289 if (is_arith || is_ordered)
1290 && (self.is_dwarf_aggregate_expr(left) || self.is_dwarf_aggregate_expr(right))
1291 {
1292 return Err(CodeGenError::TypeError(
1293 "Unsupported arithmetic/ordered comparison involving struct/union/array. Select a scalar field (e.g., 'obj.field'), or use '&expr + <non-negative literal>' in an alias/address context if you need a raw address."
1294 .to_string(),
1295 ));
1296 }
1297
1298 if is_ordered
1300 && (self.is_pointer_like_expr(left) || self.is_pointer_like_expr(right))
1301 {
1302 return Err(CodeGenError::TypeError(
1303 "Pointer ordered comparison ('<', '<=', '>', '>=') is not supported. Use '==' or '!=' to compare addresses. If you need to adjust an address, use '&expr + <non-negative literal>' in an alias/address context; to compare values, select a scalar field (e.g., 'obj.field')."
1304 .to_string(),
1305 ));
1306 }
1307 if matches!(op, BinaryOp::Equal | BinaryOp::NotEqual) {
1309 if let (Expr::String(lit), other) = (&**left, &**right) {
1310 return self.compile_string_comparison(
1311 other,
1312 lit,
1313 matches!(op, BinaryOp::Equal),
1314 );
1315 } else if let (other, Expr::String(lit)) = (&**left, &**right) {
1316 return self.compile_string_comparison(
1317 other,
1318 lit,
1319 matches!(op, BinaryOp::Equal),
1320 );
1321 }
1322 }
1323 if matches!(op, BinaryOp::LogicalOr) {
1325 let lhs_val = self.compile_expr(left)?;
1327 let lhs_int = match lhs_val {
1328 BasicValueEnum::IntValue(iv) => iv,
1329 BasicValueEnum::PointerValue(pv) => self
1330 .builder
1331 .build_ptr_to_int(pv, self.context.i64_type(), "lor_lhs_ptr_as_i64")
1332 .map_err(|e| CodeGenError::Builder(e.to_string()))?,
1333 _ => {
1334 return Err(CodeGenError::TypeError(
1335 "Logical OR requires integer or pointer operands".to_string(),
1336 ))
1337 }
1338 };
1339 let lhs_zero = lhs_int.get_type().const_zero();
1340 let lhs_bool = self
1341 .builder
1342 .build_int_compare(
1343 inkwell::IntPredicate::NE,
1344 lhs_int,
1345 lhs_zero,
1346 "lor_lhs_nz",
1347 )
1348 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1349
1350 let curr_block = self.builder.get_insert_block().ok_or_else(|| {
1352 CodeGenError::LLVMError("No current basic block".to_string())
1353 })?;
1354 let func = curr_block
1355 .get_parent()
1356 .ok_or_else(|| CodeGenError::LLVMError("No parent function".to_string()))?;
1357 let rhs_block = self.context.append_basic_block(func, "lor_rhs");
1358 let merge_block = self.context.append_basic_block(func, "lor_merge");
1359
1360 self.builder
1362 .build_conditional_branch(lhs_bool, merge_block, rhs_block)
1363 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
1364
1365 self.builder.position_at_end(rhs_block);
1367 let rhs_val = self.compile_expr(right)?;
1368 let rhs_int = match rhs_val {
1369 BasicValueEnum::IntValue(iv) => iv,
1370 BasicValueEnum::PointerValue(pv) => self
1371 .builder
1372 .build_ptr_to_int(pv, self.context.i64_type(), "lor_rhs_ptr_as_i64")
1373 .map_err(|e| CodeGenError::Builder(e.to_string()))?,
1374 _ => {
1375 return Err(CodeGenError::TypeError(
1376 "Logical OR requires integer or pointer operands".to_string(),
1377 ))
1378 }
1379 };
1380 let rhs_zero = rhs_int.get_type().const_zero();
1381 let rhs_bool = self
1382 .builder
1383 .build_int_compare(
1384 inkwell::IntPredicate::NE,
1385 rhs_int,
1386 rhs_zero,
1387 "lor_rhs_nz",
1388 )
1389 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1390 let rhs_end_block = self.builder.get_insert_block().ok_or_else(|| {
1392 CodeGenError::LLVMError("No current basic block after RHS".to_string())
1393 })?;
1394 self.builder
1395 .build_unconditional_branch(merge_block)
1396 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
1397
1398 self.builder.position_at_end(merge_block);
1400 let i1 = self.context.bool_type();
1401 let phi = self
1402 .builder
1403 .build_phi(i1, "lor_phi")
1404 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
1405 let one = i1.const_int(1, false);
1406 phi.add_incoming(&[(&one, curr_block), (&rhs_bool, rhs_end_block)]);
1407 return Ok(phi.as_basic_value());
1408 } else if matches!(op, BinaryOp::LogicalAnd) {
1409 let lhs_val = self.compile_expr(left)?;
1411 let lhs_int = match lhs_val {
1412 BasicValueEnum::IntValue(iv) => iv,
1413 BasicValueEnum::PointerValue(pv) => self
1414 .builder
1415 .build_ptr_to_int(pv, self.context.i64_type(), "land_lhs_ptr_as_i64")
1416 .map_err(|e| CodeGenError::Builder(e.to_string()))?,
1417 _ => {
1418 return Err(CodeGenError::TypeError(
1419 "Logical AND requires integer or pointer operands".to_string(),
1420 ))
1421 }
1422 };
1423 let lhs_zero = lhs_int.get_type().const_zero();
1424 let lhs_bool = self
1425 .builder
1426 .build_int_compare(
1427 inkwell::IntPredicate::NE,
1428 lhs_int,
1429 lhs_zero,
1430 "land_lhs_nz",
1431 )
1432 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1433
1434 let curr_block = self.builder.get_insert_block().ok_or_else(|| {
1436 CodeGenError::LLVMError("No current basic block".to_string())
1437 })?;
1438 let func = curr_block
1439 .get_parent()
1440 .ok_or_else(|| CodeGenError::LLVMError("No parent function".to_string()))?;
1441 let rhs_block = self.context.append_basic_block(func, "land_rhs");
1442 let merge_block = self.context.append_basic_block(func, "land_merge");
1443
1444 self.builder
1446 .build_conditional_branch(lhs_bool, rhs_block, merge_block)
1447 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
1448
1449 self.builder.position_at_end(rhs_block);
1451 let rhs_val = self.compile_expr(right)?;
1452 let rhs_int = match rhs_val {
1453 BasicValueEnum::IntValue(iv) => iv,
1454 BasicValueEnum::PointerValue(pv) => self
1455 .builder
1456 .build_ptr_to_int(pv, self.context.i64_type(), "land_rhs_ptr_as_i64")
1457 .map_err(|e| CodeGenError::Builder(e.to_string()))?,
1458 _ => {
1459 return Err(CodeGenError::TypeError(
1460 "Logical AND requires integer or pointer operands".to_string(),
1461 ))
1462 }
1463 };
1464 let rhs_zero = rhs_int.get_type().const_zero();
1465 let rhs_bool = self
1466 .builder
1467 .build_int_compare(
1468 inkwell::IntPredicate::NE,
1469 rhs_int,
1470 rhs_zero,
1471 "land_rhs_nz",
1472 )
1473 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1474 let rhs_end_block = self.builder.get_insert_block().ok_or_else(|| {
1475 CodeGenError::LLVMError("No current basic block after RHS".to_string())
1476 })?;
1477 self.builder
1478 .build_unconditional_branch(merge_block)
1479 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
1480
1481 self.builder.position_at_end(merge_block);
1483 let i1 = self.context.bool_type();
1484 let phi = self
1485 .builder
1486 .build_phi(i1, "land_phi")
1487 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
1488 let zero = i1.const_zero();
1489 phi.add_incoming(&[(&rhs_bool, rhs_end_block), (&zero, curr_block)]);
1490 return Ok(phi.as_basic_value());
1491 }
1492
1493 let left_val = self.compile_expr(left)?;
1495 let right_val = self.compile_expr(right)?;
1496 self.compile_binary_op(left_val, op.clone(), right_val)
1497 }
1498 Expr::MemberAccess(_, _) => {
1499 self.compile_dwarf_expression(expr)
1501 }
1502 Expr::PointerDeref(_) => {
1503 self.compile_dwarf_expression(expr)
1505 }
1506 Expr::AddressOf(inner) => {
1507 let target_inner: &Expr = if let Expr::Variable(var_name) = inner.as_ref() {
1510 if self.alias_variable_exists(var_name) {
1511 let aliased = self
1513 .get_alias_variable(var_name)
1514 .expect("alias existence just checked");
1515 let var =
1518 self.query_dwarf_for_complex_expr(&aliased)?
1519 .ok_or_else(|| {
1520 super::context::CodeGenError::TypeError(
1521 "cannot take address of unresolved expression".to_string(),
1522 )
1523 })?;
1524 let module_hint = self.current_resolved_var_module_path.clone();
1525 match self.evaluation_result_to_address_with_hint(
1526 &var.evaluation_result,
1527 None,
1528 module_hint.as_deref(),
1529 ) {
1530 Ok(addr_i64) => {
1531 let ptr_ty = self.context.ptr_type(AddressSpace::default());
1532 let as_ptr = self
1533 .builder
1534 .build_int_to_ptr(addr_i64, ptr_ty, "addr_as_ptr")
1535 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1536 return Ok(as_ptr.into());
1537 }
1538 Err(_) => {
1539 return Err(super::context::CodeGenError::TypeError(
1540 "cannot take address of rvalue".to_string(),
1541 ));
1542 }
1543 }
1544 } else {
1545 inner.as_ref()
1546 }
1547 } else {
1548 inner.as_ref()
1549 };
1550
1551 let var = self
1552 .query_dwarf_for_complex_expr(target_inner)?
1553 .ok_or_else(|| {
1554 super::context::CodeGenError::TypeError(
1555 "cannot take address of unresolved expression".to_string(),
1556 )
1557 })?;
1558 let module_hint = self.current_resolved_var_module_path.clone();
1560 match self.evaluation_result_to_address_with_hint(
1561 &var.evaluation_result,
1562 None,
1563 module_hint.as_deref(),
1564 ) {
1565 Ok(addr_i64) => {
1566 let ptr_ty = self.context.ptr_type(AddressSpace::default());
1567 let as_ptr = self
1568 .builder
1569 .build_int_to_ptr(addr_i64, ptr_ty, "addr_as_ptr")
1570 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1571 Ok(as_ptr.into())
1572 }
1573 Err(_) => Err(super::context::CodeGenError::TypeError(
1574 "cannot take address of rvalue".to_string(),
1575 )),
1576 }
1577 }
1578 Expr::ArrayAccess(_, _) => {
1579 self.compile_dwarf_expression(expr)
1581 }
1582 Expr::ChainAccess(_) => {
1583 self.compile_dwarf_expression(expr)
1585 }
1586 }
1587 }
1588
1589 pub fn handle_special_variable(&mut self, name: &str) -> Result<BasicValueEnum<'ctx>> {
1591 match name {
1592 "pid" => {
1593 let pid_tgid = self.get_current_pid_tgid()?;
1595 let pid_mask = self.context.i64_type().const_int(0xFFFFFFFF, false);
1596 let pid = self
1597 .builder
1598 .build_and(pid_tgid, pid_mask, "pid")
1599 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1600 Ok(pid.into())
1601 }
1602 "tid" => {
1603 let pid_tgid = self.get_current_pid_tgid()?;
1605 let tid = self
1606 .builder
1607 .build_right_shift(
1608 pid_tgid,
1609 self.context.i64_type().const_int(32, false),
1610 false,
1611 "tid",
1612 )
1613 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1614 Ok(tid.into())
1615 }
1616 "timestamp" => {
1617 let ts = self.get_current_timestamp()?;
1619 Ok(ts.into())
1620 }
1621 _ => {
1622 let supported = ["$pid", "$tid", "$timestamp"].join(", ");
1623 Err(CodeGenError::NotImplemented(format!(
1624 "Unknown special variable '${name}'. Supported: {supported}"
1625 )))
1626 }
1627 }
1628 }
1629
1630 pub fn compile_binary_op(
1632 &mut self,
1633 left: BasicValueEnum<'ctx>,
1634 op: BinaryOp,
1635 right: BasicValueEnum<'ctx>,
1636 ) -> Result<BasicValueEnum<'ctx>> {
1637 use inkwell::values::BasicValueEnum::*;
1638
1639 debug!("compile_binary_op: op={:?}", op);
1641 debug!("compile_binary_op: left type = {:?}", left.get_type());
1642 debug!("compile_binary_op: right type = {:?}", right.get_type());
1643 match &left {
1644 IntValue(iv) => debug!(
1645 "compile_binary_op: left is IntValue with bit width {}",
1646 iv.get_type().get_bit_width()
1647 ),
1648 FloatValue(_) => debug!("compile_binary_op: left is FloatValue"),
1649 PointerValue(_) => debug!("compile_binary_op: left is PointerValue"),
1650 _ => debug!("compile_binary_op: left is other type"),
1651 }
1652 match &right {
1653 IntValue(iv) => debug!(
1654 "compile_binary_op: right is IntValue with bit width {}",
1655 iv.get_type().get_bit_width()
1656 ),
1657 FloatValue(_) => debug!("compile_binary_op: right is FloatValue"),
1658 PointerValue(_) => debug!("compile_binary_op: right is PointerValue"),
1659 _ => debug!("compile_binary_op: right is other type"),
1660 }
1661
1662 match (left, right) {
1663 (IntValue(left_int), IntValue(right_int)) => {
1664 let result = match op {
1665 BinaryOp::Add => self
1666 .builder
1667 .build_int_add(left_int, right_int, "add")
1668 .map_err(|e| CodeGenError::Builder(e.to_string()))?,
1669 BinaryOp::Subtract => self
1670 .builder
1671 .build_int_sub(left_int, right_int, "sub")
1672 .map_err(|e| CodeGenError::Builder(e.to_string()))?,
1673 BinaryOp::Multiply => self
1674 .builder
1675 .build_int_mul(left_int, right_int, "mul")
1676 .map_err(|e| CodeGenError::Builder(e.to_string()))?,
1677 BinaryOp::Divide => self
1678 .builder
1679 .build_int_signed_div(left_int, right_int, "div")
1680 .map_err(|e| CodeGenError::Builder(e.to_string()))?,
1681 BinaryOp::Equal => {
1683 let result = self
1684 .builder
1685 .build_int_compare(inkwell::IntPredicate::EQ, left_int, right_int, "eq")
1686 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1687 return Ok(result.into());
1688 }
1689 BinaryOp::NotEqual => {
1690 let result = self
1691 .builder
1692 .build_int_compare(inkwell::IntPredicate::NE, left_int, right_int, "ne")
1693 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1694 return Ok(result.into());
1695 }
1696 BinaryOp::LessThan => {
1697 let result = self
1698 .builder
1699 .build_int_compare(
1700 inkwell::IntPredicate::SLT,
1701 left_int,
1702 right_int,
1703 "lt",
1704 )
1705 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1706 return Ok(result.into());
1707 }
1708 BinaryOp::LessEqual => {
1709 let result = self
1710 .builder
1711 .build_int_compare(
1712 inkwell::IntPredicate::SLE,
1713 left_int,
1714 right_int,
1715 "le",
1716 )
1717 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1718 return Ok(result.into());
1719 }
1720 BinaryOp::GreaterThan => {
1721 let result = self
1722 .builder
1723 .build_int_compare(
1724 inkwell::IntPredicate::SGT,
1725 left_int,
1726 right_int,
1727 "gt",
1728 )
1729 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1730 return Ok(result.into());
1731 }
1732 BinaryOp::GreaterEqual => {
1733 let result = self
1734 .builder
1735 .build_int_compare(
1736 inkwell::IntPredicate::SGE,
1737 left_int,
1738 right_int,
1739 "ge",
1740 )
1741 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1742 return Ok(result.into());
1743 }
1744 BinaryOp::LogicalAnd => {
1746 let lz = left_int.get_type().const_zero();
1747 let rz = right_int.get_type().const_zero();
1748 let lbool = self
1749 .builder
1750 .build_int_compare(inkwell::IntPredicate::NE, left_int, lz, "lhs_nz")
1751 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1752 let rbool = self
1753 .builder
1754 .build_int_compare(inkwell::IntPredicate::NE, right_int, rz, "rhs_nz")
1755 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1756 let result = self
1757 .builder
1758 .build_and(lbool, rbool, "and_bool")
1759 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1760 return Ok(result.into());
1761 }
1762 BinaryOp::LogicalOr => {
1763 let lz = left_int.get_type().const_zero();
1764 let rz = right_int.get_type().const_zero();
1765 let lbool = self
1766 .builder
1767 .build_int_compare(inkwell::IntPredicate::NE, left_int, lz, "lhs_nz")
1768 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1769 let rbool = self
1770 .builder
1771 .build_int_compare(inkwell::IntPredicate::NE, right_int, rz, "rhs_nz")
1772 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1773 let result = self
1774 .builder
1775 .build_or(lbool, rbool, "or_bool")
1776 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1777 return Ok(result.into());
1778 }
1779 };
1780 Ok(result.into())
1781 }
1782 (PointerValue(lp), IntValue(ri)) | (IntValue(ri), PointerValue(lp)) => {
1784 match op {
1785 BinaryOp::Equal | BinaryOp::NotEqual => {
1786 let lpi64 = self
1787 .builder
1788 .build_ptr_to_int(lp, self.context.i64_type(), "ptr_as_i64")
1789 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1790 let rbw = ri.get_type().get_bit_width();
1792 let ri64 = if rbw < 64 {
1793 self.builder
1794 .build_int_z_extend(ri, self.context.i64_type(), "rhs_zext_i64")
1795 .map_err(|e| CodeGenError::Builder(e.to_string()))?
1796 } else if rbw > 64 {
1797 self.builder
1798 .build_int_truncate(ri, self.context.i64_type(), "rhs_trunc_i64")
1799 .map_err(|e| CodeGenError::Builder(e.to_string()))?
1800 } else {
1801 ri
1802 };
1803 let pred = if matches!(op, BinaryOp::Equal) {
1804 inkwell::IntPredicate::EQ
1805 } else {
1806 inkwell::IntPredicate::NE
1807 };
1808 let cmp = self
1809 .builder
1810 .build_int_compare(pred, lpi64, ri64, "ptr_cmp")
1811 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1812 Ok(cmp.into())
1813 }
1814 _ => Err(CodeGenError::TypeError(
1815 "Unsupported operation between aggregate address/pointer and integer: only '==' and '!=' are allowed. If you meant to offset an address, use '&expr + <non-negative literal>' in an alias/address context, or access a scalar field.".to_string(),
1816 )),
1817 }
1818 }
1819 (PointerValue(lp), PointerValue(rp)) => match op {
1820 BinaryOp::Equal | BinaryOp::NotEqual => {
1821 let lpi64 = self
1822 .builder
1823 .build_ptr_to_int(lp, self.context.i64_type(), "l_ptr_as_i64")
1824 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1825 let rpi64 = self
1826 .builder
1827 .build_ptr_to_int(rp, self.context.i64_type(), "r_ptr_as_i64")
1828 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1829 let pred = if matches!(op, BinaryOp::Equal) {
1830 inkwell::IntPredicate::EQ
1831 } else {
1832 inkwell::IntPredicate::NE
1833 };
1834 let cmp = self
1835 .builder
1836 .build_int_compare(pred, lpi64, rpi64, "ptr_ptr_cmp")
1837 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1838 Ok(cmp.into())
1839 }
1840 _ => Err(CodeGenError::TypeError(
1841 "Pointer ordered comparison ('<', '<=', '>', '>=') is not supported. Use '==' or '!=' to compare addresses. If you need to adjust an address, use '&expr + <non-negative literal>' in an alias/address context; to compare values, select a scalar field (e.g., 'obj.field')."
1842 .to_string(),
1843 )),
1844 },
1845 (FloatValue(left_float), FloatValue(right_float)) => match op {
1846 BinaryOp::Add => {
1847 let result = self
1848 .builder
1849 .build_float_add(left_float, right_float, "add")
1850 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1851 Ok(result.into())
1852 }
1853 BinaryOp::Subtract => {
1854 let result = self
1855 .builder
1856 .build_float_sub(left_float, right_float, "sub")
1857 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1858 Ok(result.into())
1859 }
1860 BinaryOp::Multiply => {
1861 let result = self
1862 .builder
1863 .build_float_mul(left_float, right_float, "mul")
1864 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1865 Ok(result.into())
1866 }
1867 BinaryOp::Divide => {
1868 let result = self
1869 .builder
1870 .build_float_div(left_float, right_float, "div")
1871 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1872 Ok(result.into())
1873 }
1874 BinaryOp::Equal => {
1876 let result = self
1877 .builder
1878 .build_float_compare(
1879 inkwell::FloatPredicate::OEQ,
1880 left_float,
1881 right_float,
1882 "eq",
1883 )
1884 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1885 Ok(result.into())
1886 }
1887 BinaryOp::NotEqual => {
1888 let result = self
1889 .builder
1890 .build_float_compare(
1891 inkwell::FloatPredicate::ONE,
1892 left_float,
1893 right_float,
1894 "ne",
1895 )
1896 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1897 Ok(result.into())
1898 }
1899 BinaryOp::LessThan => {
1900 let result = self
1901 .builder
1902 .build_float_compare(
1903 inkwell::FloatPredicate::OLT,
1904 left_float,
1905 right_float,
1906 "lt",
1907 )
1908 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1909 Ok(result.into())
1910 }
1911 BinaryOp::LessEqual => {
1912 let result = self
1913 .builder
1914 .build_float_compare(
1915 inkwell::FloatPredicate::OLE,
1916 left_float,
1917 right_float,
1918 "le",
1919 )
1920 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1921 Ok(result.into())
1922 }
1923 BinaryOp::GreaterThan => {
1924 let result = self
1925 .builder
1926 .build_float_compare(
1927 inkwell::FloatPredicate::OGT,
1928 left_float,
1929 right_float,
1930 "gt",
1931 )
1932 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1933 Ok(result.into())
1934 }
1935 BinaryOp::GreaterEqual => {
1936 let result = self
1937 .builder
1938 .build_float_compare(
1939 inkwell::FloatPredicate::OGE,
1940 left_float,
1941 right_float,
1942 "ge",
1943 )
1944 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
1945 Ok(result.into())
1946 }
1947 _ => Err(CodeGenError::NotImplemented(format!(
1948 "Float binary operation {op:?} not implemented"
1949 ))),
1950 },
1951 _ => Err(CodeGenError::TypeError(format!(
1952 "Type mismatch in binary operation {op:?}"
1953 ))),
1954 }
1955 }
1956
1957 pub fn compile_member_access(
1959 &mut self,
1960 obj_expr: &Expr,
1961 field: &str,
1962 ) -> Result<BasicValueEnum<'ctx>> {
1963 let member_access_expr = Expr::MemberAccess(Box::new(obj_expr.clone()), field.to_string());
1965 self.compile_dwarf_expression(&member_access_expr)
1966 }
1967
1968 pub fn compile_pointer_deref(&mut self, expr: &Expr) -> Result<BasicValueEnum<'ctx>> {
1970 let pointer_deref_expr = Expr::PointerDeref(Box::new(expr.clone()));
1972 self.compile_dwarf_expression(&pointer_deref_expr)
1973 }
1974
1975 pub fn compile_array_access(
1977 &mut self,
1978 array_expr: &Expr,
1979 index_expr: &Expr,
1980 ) -> Result<BasicValueEnum<'ctx>> {
1981 let array_access_expr =
1983 Expr::ArrayAccess(Box::new(array_expr.clone()), Box::new(index_expr.clone()));
1984 self.compile_dwarf_expression(&array_access_expr)
1985 }
1986
1987 pub fn compile_chain_access(&mut self, chain: &[String]) -> Result<BasicValueEnum<'ctx>> {
1989 let chain_access_expr = Expr::ChainAccess(chain.to_vec());
1991 self.compile_dwarf_expression(&chain_access_expr)
1992 }
1993
1994 pub fn compile_dwarf_expression(
1996 &mut self,
1997 expr: &crate::script::Expr,
1998 ) -> Result<BasicValueEnum<'ctx>> {
1999 debug!(
2000 "compile_dwarf_expression: Compiling complex expression: {:?}",
2001 expr
2002 );
2003
2004 let compile_context = self.get_compile_time_context()?.clone();
2006 let variable_with_eval = match self.query_dwarf_for_complex_expr(expr)? {
2007 Some(var) => var,
2008 None => {
2009 let expr_str = Self::expr_to_debug_string(expr);
2010 return Err(CodeGenError::VariableNotFound(expr_str));
2011 }
2012 };
2013
2014 let dwarf_type = variable_with_eval.dwarf_type.as_ref().ok_or_else(|| {
2015 CodeGenError::DwarfError("Expression has no DWARF type information".to_string())
2016 })?;
2017
2018 debug!(
2019 "compile_dwarf_expression: Found DWARF info for expression '{}' with type: {:?}",
2020 variable_with_eval.name, dwarf_type
2021 );
2022
2023 self.evaluate_result_to_llvm_value(
2025 &variable_with_eval.evaluation_result,
2026 dwarf_type,
2027 &variable_with_eval.name,
2028 compile_context.pc_address,
2029 )
2030 }
2031
2032 fn expr_to_debug_string(expr: &crate::script::Expr) -> String {
2034 use crate::script::Expr;
2035
2036 match expr {
2037 Expr::Variable(name) => name.clone(),
2038 Expr::MemberAccess(obj, field) => {
2039 format!("{}.{}", Self::expr_to_debug_string(obj), field)
2040 }
2041 Expr::ArrayAccess(arr, _) => format!("{}[index]", Self::expr_to_debug_string(arr)),
2042 Expr::ChainAccess(chain) => chain.join("."),
2043 Expr::PointerDeref(expr) => format!("*{}", Self::expr_to_debug_string(expr)),
2044 _ => "expr".to_string(),
2045 }
2046 }
2047}
2048
2049impl<'ctx> EbpfContext<'ctx> {
2050 fn compile_string_comparison(
2053 &mut self,
2054 dwarf_expr: &Expr,
2055 lit: &str,
2056 is_equal: bool,
2057 ) -> Result<BasicValueEnum<'ctx>> {
2058 use ghostscope_dwarf::TypeInfo as TI;
2059
2060 let var = self
2062 .query_dwarf_for_complex_expr(dwarf_expr)?
2063 .ok_or_else(|| {
2064 CodeGenError::TypeError(
2065 "string comparison requires DWARF variable/expression".into(),
2066 )
2067 })?;
2068 let dwarf_type_opt = var.dwarf_type.as_ref();
2070
2071 enum ParsedKind {
2072 PtrChar,
2073 ArrChar(Option<u32>),
2074 Other,
2075 }
2076 fn parse_type_name(name: &str) -> ParsedKind {
2077 let lower = name.to_lowercase();
2078 let has_char = lower.contains("char");
2079 let is_ptr = lower.contains('*');
2080 if has_char && is_ptr {
2081 return ParsedKind::PtrChar;
2082 }
2083 if has_char && lower.contains('[') {
2084 let mut n: Option<u32> = None;
2086 if let Some(start) = lower.find('[') {
2087 if let Some(end) = lower[start + 1..].find(']') {
2088 let inside = &lower[start + 1..start + 1 + end];
2089 let digits: String =
2090 inside.chars().filter(|c| c.is_ascii_digit()).collect();
2091 if !digits.is_empty() {
2092 if let Ok(v) = digits.parse::<u32>() {
2093 n = Some(v);
2094 }
2095 }
2096 }
2097 }
2098 return ParsedKind::ArrChar(n);
2099 }
2100 ParsedKind::Other
2101 }
2102
2103 fn unwrap_aliases(t: &TI) -> &TI {
2105 let mut cur = t;
2106 loop {
2107 match cur {
2108 TI::TypedefType {
2109 underlying_type, ..
2110 } => cur = underlying_type.as_ref(),
2111 TI::QualifiedType {
2112 underlying_type, ..
2113 } => cur = underlying_type.as_ref(),
2114 _ => break,
2115 }
2116 }
2117 cur
2118 }
2119
2120 let module_hint = self.current_resolved_var_module_path.clone();
2122 let status_ptr = if self.condition_context_active {
2123 Some(self.get_or_create_cond_error_global())
2124 } else {
2125 None
2126 };
2127 let addr = self.evaluation_result_to_address_with_hint(
2128 &var.evaluation_result,
2129 status_ptr,
2130 module_hint.as_deref(),
2131 )?;
2132
2133 let lit_bytes = lit.as_bytes();
2134 let lit_len = lit_bytes.len() as u32;
2135 let one = self.context.bool_type().const_int(1, false);
2136 let zero = self.context.bool_type().const_zero();
2137
2138 let result = match dwarf_type_opt.map(unwrap_aliases) {
2140 Some(TI::PointerType { target_type, .. }) => {
2142 let base = unwrap_aliases(target_type.as_ref());
2144 let is_char_like = matches!(base, TI::BaseType { name, size, .. } if name.contains("char") && *size == 1);
2145 if !is_char_like {
2146 return Err(CodeGenError::TypeError(
2147 "automatic string comparison only supports char*".into(),
2148 ));
2149 }
2150
2151 let val_any = self.evaluate_result_to_llvm_value(
2153 &var.evaluation_result,
2154 var.dwarf_type.as_ref().unwrap(),
2155 &var.name,
2156 self.get_compile_time_context()?.pc_address,
2157 )?;
2158 let ptr_i64 = match val_any {
2159 BasicValueEnum::IntValue(iv) => iv,
2160 BasicValueEnum::PointerValue(pv) => self
2161 .builder
2162 .build_ptr_to_int(pv, self.context.i64_type(), "ptr_as_i64")
2163 .map_err(|e| CodeGenError::Builder(e.to_string()))?,
2164 _ => {
2165 return Err(CodeGenError::TypeError(
2166 "pointer value must be integer or pointer".into(),
2167 ))
2168 }
2169 };
2170 let need = lit_len + 1;
2171 let (buf_global, ret_len, arr_ty) =
2172 self.read_user_cstr_into_buffer(ptr_i64, need, "_gs_strbuf")?;
2173
2174 let i64_ty = self.context.i64_type();
2176 let expect_len = i64_ty.const_int(need as u64, false);
2177 let len_ok = self
2178 .builder
2179 .build_int_compare(inkwell::IntPredicate::EQ, ret_len, expect_len, "str_len_ok")
2180 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2181
2182 let i32_ty = self.context.i32_type();
2184 let idx0 = i32_ty.const_zero();
2185 let idx_l = i32_ty.const_int(lit_len as u64, false);
2186 let char_ptr = unsafe {
2187 self.builder
2188 .build_gep(arr_ty, buf_global, &[idx0, idx_l], "nul_ptr")
2189 .map_err(|e| CodeGenError::Builder(e.to_string()))?
2190 };
2191 let c = self
2192 .builder
2193 .build_load(self.context.i8_type(), char_ptr, "c_l")
2194 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2195 let c = match c {
2196 BasicValueEnum::IntValue(iv) => iv,
2197 _ => return Err(CodeGenError::LLVMError("load did not return i8".into())),
2198 };
2199 let nul_ok = self
2200 .builder
2201 .build_int_compare(
2202 inkwell::IntPredicate::EQ,
2203 c,
2204 self.context.i8_type().const_zero(),
2205 "nul_ok",
2206 )
2207 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2208
2209 let mut acc = self.context.i8_type().const_zero();
2211 for (i, b) in lit_bytes.iter().enumerate() {
2212 let idx_i = i32_ty.const_int(i as u64, false);
2213 let ptr_i = unsafe {
2214 self.builder
2215 .build_gep(arr_ty, buf_global, &[idx0, idx_i], "ch_ptr")
2216 .map_err(|e| CodeGenError::Builder(e.to_string()))?
2217 };
2218 let ch = self
2219 .builder
2220 .build_load(self.context.i8_type(), ptr_i, "ch")
2221 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2222 let ch = match ch {
2223 BasicValueEnum::IntValue(iv) => iv,
2224 _ => return Err(CodeGenError::LLVMError("load did not return i8".into())),
2225 };
2226 let expect = self.context.i8_type().const_int(*b as u64, false);
2227 let diff = self
2228 .builder
2229 .build_xor(ch, expect, "diff")
2230 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2231 acc = self
2232 .builder
2233 .build_or(acc, diff, "acc_or")
2234 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2235 }
2236 let eq_bytes = self
2237 .builder
2238 .build_int_compare(
2239 inkwell::IntPredicate::EQ,
2240 acc,
2241 self.context.i8_type().const_zero(),
2242 "acc_zero",
2243 )
2244 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2245 let ok1 = self
2246 .builder
2247 .build_and(len_ok, nul_ok, "ok_len_nul")
2248 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2249 self.builder
2250 .build_and(ok1, eq_bytes, "str_eq")
2251 .map_err(|e| CodeGenError::Builder(e.to_string()))?
2252 }
2253 Some(TI::ArrayType {
2255 element_type,
2256 element_count,
2257 total_size,
2258 }) => {
2259 let elem = unwrap_aliases(element_type.as_ref());
2260 let is_char_like = matches!(elem, TI::BaseType { name, size, .. } if name.contains("char") && *size == 1);
2261 if !is_char_like {
2262 return Err(CodeGenError::TypeError(
2263 "automatic string comparison only supports char[N]".into(),
2264 ));
2265 }
2266 let n_opt = element_count.or_else(|| total_size.map(|ts| ts));
2268 let n = if let Some(nv) = n_opt { nv as u32 } else { 0 };
2269 if n == 0 {
2270 return Err(CodeGenError::TypeError(
2271 "array size unknown for char[N] comparison".into(),
2272 ));
2273 }
2274 if lit_len + 1 > n {
2276 return Ok((if is_equal { zero } else { one }).into());
2278 }
2279 let (buf_global, status, arr_ty) =
2281 self.read_user_bytes_into_buffer(addr, lit_len + 1, "_gs_arrbuf")?;
2282 let status_ok = self
2284 .builder
2285 .build_int_compare(
2286 inkwell::IntPredicate::EQ,
2287 status,
2288 self.context.i64_type().const_zero(),
2289 "rd_ok",
2290 )
2291 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2292 let i32_ty = self.context.i32_type();
2294 let idx0 = i32_ty.const_zero();
2295 let idx_l = i32_ty.const_int(lit_len as u64, false);
2296 let char_ptr = unsafe {
2297 self.builder
2298 .build_gep(arr_ty, buf_global, &[idx0, idx_l], "nul_ptr")
2299 .map_err(|e| CodeGenError::Builder(e.to_string()))?
2300 };
2301 let c = self
2302 .builder
2303 .build_load(self.context.i8_type(), char_ptr, "c_l")
2304 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2305 let c = match c {
2306 BasicValueEnum::IntValue(iv) => iv,
2307 _ => return Err(CodeGenError::LLVMError("load did not return i8".into())),
2308 };
2309 let nul_ok = self
2310 .builder
2311 .build_int_compare(
2312 inkwell::IntPredicate::EQ,
2313 c,
2314 self.context.i8_type().const_zero(),
2315 "nul_ok",
2316 )
2317 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2318 let mut acc = self.context.i8_type().const_zero();
2320 for (i, b) in lit_bytes.iter().enumerate() {
2321 let idx_i = i32_ty.const_int(i as u64, false);
2322 let ptr_i = unsafe {
2323 self.builder
2324 .build_gep(arr_ty, buf_global, &[idx0, idx_i], "ch_ptr")
2325 .map_err(|e| CodeGenError::Builder(e.to_string()))?
2326 };
2327 let ch = self
2328 .builder
2329 .build_load(self.context.i8_type(), ptr_i, "ch")
2330 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2331 let ch = match ch {
2332 BasicValueEnum::IntValue(iv) => iv,
2333 _ => return Err(CodeGenError::LLVMError("load did not return i8".into())),
2334 };
2335 let expect = self.context.i8_type().const_int(*b as u64, false);
2336 let diff = self
2337 .builder
2338 .build_xor(ch, expect, "diff")
2339 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2340 acc = self
2341 .builder
2342 .build_or(acc, diff, "acc_or")
2343 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2344 }
2345 let eq_bytes = self
2346 .builder
2347 .build_int_compare(
2348 inkwell::IntPredicate::EQ,
2349 acc,
2350 self.context.i8_type().const_zero(),
2351 "acc_zero",
2352 )
2353 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2354 let ok1 = self
2355 .builder
2356 .build_and(status_ok, nul_ok, "ok_len_nul")
2357 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2358 self.builder
2359 .build_and(ok1, eq_bytes, "arr_eq")
2360 .map_err(|e| CodeGenError::Builder(e.to_string()))?
2361 }
2362 None => {
2363 match parse_type_name(&var.type_name) {
2365 ParsedKind::PtrChar => {
2366 let ptr_any = self
2368 .generate_memory_read(addr, ghostscope_dwarf::MemoryAccessSize::U64)?;
2369 let ptr_i64 = match ptr_any {
2370 BasicValueEnum::IntValue(iv) => iv,
2371 _ => {
2372 return Err(CodeGenError::LLVMError(
2373 "pointer load did not return integer".to_string(),
2374 ))
2375 }
2376 };
2377 let need = lit_len + 1;
2378 let (buf_global, ret_len, arr_ty) =
2379 self.read_user_cstr_into_buffer(ptr_i64, need, "_gs_strbuf")?;
2380
2381 let i64_ty = self.context.i64_type();
2382 let expect_len = i64_ty.const_int(need as u64, false);
2383 let len_ok = self
2384 .builder
2385 .build_int_compare(
2386 inkwell::IntPredicate::EQ,
2387 ret_len,
2388 expect_len,
2389 "str_len_ok",
2390 )
2391 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2392
2393 let i32_ty = self.context.i32_type();
2394 let idx0 = i32_ty.const_zero();
2395 let idx_l = i32_ty.const_int(lit_len as u64, false);
2396 let char_ptr = unsafe {
2397 self.builder
2398 .build_gep(arr_ty, buf_global, &[idx0, idx_l], "nul_ptr")
2399 .map_err(|e| CodeGenError::Builder(e.to_string()))?
2400 };
2401 let c = self
2402 .builder
2403 .build_load(self.context.i8_type(), char_ptr, "c_l")
2404 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2405 let c = match c {
2406 BasicValueEnum::IntValue(iv) => iv,
2407 _ => {
2408 return Err(CodeGenError::LLVMError(
2409 "load did not return i8".into(),
2410 ))
2411 }
2412 };
2413 let nul_ok = self
2414 .builder
2415 .build_int_compare(
2416 inkwell::IntPredicate::EQ,
2417 c,
2418 self.context.i8_type().const_zero(),
2419 "nul_ok",
2420 )
2421 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2422
2423 let mut acc = self.context.i8_type().const_zero();
2424 for (i, b) in lit_bytes.iter().enumerate() {
2425 let idx_i = i32_ty.const_int(i as u64, false);
2426 let ptr_i = unsafe {
2427 self.builder
2428 .build_gep(arr_ty, buf_global, &[idx0, idx_i], "ch_ptr")
2429 .map_err(|e| CodeGenError::Builder(e.to_string()))?
2430 };
2431 let ch = self
2432 .builder
2433 .build_load(self.context.i8_type(), ptr_i, "ch")
2434 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2435 let ch = match ch {
2436 BasicValueEnum::IntValue(iv) => iv,
2437 _ => {
2438 return Err(CodeGenError::LLVMError(
2439 "load did not return i8".into(),
2440 ))
2441 }
2442 };
2443 let expect = self.context.i8_type().const_int(*b as u64, false);
2444 let diff = self
2445 .builder
2446 .build_xor(ch, expect, "diff")
2447 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2448 acc = self
2449 .builder
2450 .build_or(acc, diff, "acc_or")
2451 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2452 }
2453 let eq_bytes = self
2454 .builder
2455 .build_int_compare(
2456 inkwell::IntPredicate::EQ,
2457 acc,
2458 self.context.i8_type().const_zero(),
2459 "acc_zero",
2460 )
2461 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2462 let ok1 = self
2463 .builder
2464 .build_and(len_ok, nul_ok, "ok_len_nul")
2465 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2466 self.builder
2467 .build_and(ok1, eq_bytes, "str_eq")
2468 .map_err(|e| CodeGenError::Builder(e.to_string()))?
2469 }
2470 ParsedKind::ArrChar(n_opt) => {
2471 if let Some(n) = n_opt {
2473 if lit_len + 1 > n {
2474 return Ok((if is_equal { zero } else { one }).into());
2475 }
2476 }
2477 let (buf_global, status, arr_ty) =
2478 self.read_user_bytes_into_buffer(addr, lit_len + 1, "_gs_arrbuf")?;
2479 let status_ok = self
2480 .builder
2481 .build_int_compare(
2482 inkwell::IntPredicate::EQ,
2483 status,
2484 self.context.i64_type().const_zero(),
2485 "rd_ok",
2486 )
2487 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2488 let i32_ty = self.context.i32_type();
2489 let idx0 = i32_ty.const_zero();
2490 let idx_l = i32_ty.const_int(lit_len as u64, false);
2491 let char_ptr = unsafe {
2492 self.builder
2493 .build_gep(arr_ty, buf_global, &[idx0, idx_l], "nul_ptr")
2494 .map_err(|e| CodeGenError::Builder(e.to_string()))?
2495 };
2496 let c = self
2497 .builder
2498 .build_load(self.context.i8_type(), char_ptr, "c_l")
2499 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2500 let c = match c {
2501 BasicValueEnum::IntValue(iv) => iv,
2502 _ => {
2503 return Err(CodeGenError::LLVMError(
2504 "load did not return i8".into(),
2505 ))
2506 }
2507 };
2508 let nul_ok = self
2509 .builder
2510 .build_int_compare(
2511 inkwell::IntPredicate::EQ,
2512 c,
2513 self.context.i8_type().const_zero(),
2514 "nul_ok",
2515 )
2516 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2517 let mut acc = self.context.i8_type().const_zero();
2518 for (i, b) in lit_bytes.iter().enumerate() {
2519 let idx_i = i32_ty.const_int(i as u64, false);
2520 let ptr_i = unsafe {
2521 self.builder
2522 .build_gep(arr_ty, buf_global, &[idx0, idx_i], "ch_ptr")
2523 .map_err(|e| CodeGenError::Builder(e.to_string()))?
2524 };
2525 let ch = self
2526 .builder
2527 .build_load(self.context.i8_type(), ptr_i, "ch")
2528 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2529 let ch = match ch {
2530 BasicValueEnum::IntValue(iv) => iv,
2531 _ => {
2532 return Err(CodeGenError::LLVMError(
2533 "load did not return i8".into(),
2534 ))
2535 }
2536 };
2537 let expect = self.context.i8_type().const_int(*b as u64, false);
2538 let diff = self
2539 .builder
2540 .build_xor(ch, expect, "diff")
2541 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2542 acc = self
2543 .builder
2544 .build_or(acc, diff, "acc_or")
2545 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2546 }
2547 let eq_bytes = self
2548 .builder
2549 .build_int_compare(
2550 inkwell::IntPredicate::EQ,
2551 acc,
2552 self.context.i8_type().const_zero(),
2553 "acc_zero",
2554 )
2555 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2556 let ok1 = self
2557 .builder
2558 .build_and(status_ok, nul_ok, "ok_len_nul")
2559 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2560 self.builder
2561 .build_and(ok1, eq_bytes, "arr_eq")
2562 .map_err(|e| CodeGenError::Builder(e.to_string()))?
2563 }
2564 ParsedKind::Other => {
2565 return Err(CodeGenError::TypeError(format!(
2566 "string comparison unsupported for type name '{}' without DWARF type",
2567 var.type_name
2568 )));
2569 }
2570 }
2571 }
2572 Some(_) => {
2573 return Err(CodeGenError::TypeError(
2574 "string comparison only supports char* or char[N]".into(),
2575 ));
2576 }
2577 };
2578
2579 let final_bool = if is_equal {
2581 result
2582 } else {
2583 self.builder
2584 .build_not(result, "not_eq")
2585 .map_err(|e| CodeGenError::Builder(e.to_string()))?
2586 };
2587 Ok(final_bool.into())
2588 }
2589}