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