1use super::context::{CodeGenError, EbpfContext, Result};
7use crate::script::{PrintStatement, Program, Statement};
8use aya_ebpf_bindings::bindings::bpf_func_id::BPF_FUNC_probe_read_user;
9use ghostscope_protocol::trace_event::{
10 BacktraceData, EndInstructionData, InstructionHeader, PrintComplexFormatData,
11 PrintComplexVariableData, PrintStringIndexData, PrintVariableIndexData, VariableStatus,
12};
13use ghostscope_protocol::{InstructionType, TraceContext, TypeKind};
14use inkwell::values::{BasicValueEnum, IntValue};
15use inkwell::AddressSpace;
16use std::collections::HashMap;
17use tracing::{debug, info, warn};
18
19#[derive(Debug, Clone)]
21struct PrintVarRuntimeMeta {
22 var_name_index: u16,
23 type_index: u16,
24 access_path: String,
25 data_len_limit: usize,
26}
27
28#[derive(Debug, Clone)]
30enum ComplexArgSource<'ctx> {
31 RuntimeRead {
32 eval_result: ghostscope_dwarf::EvaluationResult,
33 dwarf_type: ghostscope_dwarf::TypeInfo,
34 module_for_offsets: Option<String>,
35 },
36 MemDump {
38 src_addr: inkwell::values::IntValue<'ctx>,
39 len: usize,
40 },
41 MemDumpDynamic {
43 src_addr: inkwell::values::IntValue<'ctx>,
44 len_value: inkwell::values::IntValue<'ctx>,
45 max_len: usize,
46 },
47 ImmediateBytes {
48 bytes: Vec<u8>,
49 },
50 AddressValue {
51 eval_result: ghostscope_dwarf::EvaluationResult,
52 module_for_offsets: Option<String>,
53 },
54 ComputedInt {
56 value: inkwell::values::IntValue<'ctx>,
57 byte_len: usize, },
59}
60
61#[derive(Debug, Clone)]
63struct ComplexArg<'ctx> {
64 var_name_index: u16,
65 type_index: u16,
66 access_path: Vec<u8>,
67 data_len: usize,
68 source: ComplexArgSource<'ctx>,
69}
70
71const DYNAMIC_READ_ERROR_PAYLOAD_LEN: usize = 12;
72
73fn print_complex_format_instruction_budget(
74 max_trace_event_size: usize,
75 bytes_reserved_so_far: usize,
76) -> usize {
77 let end_instruction_size =
78 std::mem::size_of::<InstructionHeader>() + std::mem::size_of::<EndInstructionData>();
79 let event_budget = max_trace_event_size
80 .saturating_sub(bytes_reserved_so_far)
81 .saturating_sub(end_instruction_size);
82 let instruction_budget_cap = std::mem::size_of::<InstructionHeader>() + u16::MAX as usize;
83 event_budget.min(instruction_budget_cap)
84}
85
86fn distribute_budget_fairly(caps: &[usize], budget: usize) -> Vec<usize> {
87 let mut allocations = vec![0; caps.len()];
88 let mut active: Vec<usize> = caps
89 .iter()
90 .enumerate()
91 .filter_map(|(idx, cap)| (*cap > 0).then_some(idx))
92 .collect();
93 let mut remaining = budget;
94
95 while remaining > 0 && !active.is_empty() {
96 let share = remaining / active.len();
97 if share == 0 {
98 for &idx in active.iter().take(remaining) {
99 allocations[idx] += 1;
100 }
101 break;
102 }
103
104 let mut consumed = 0usize;
105 let mut next_active = Vec::with_capacity(active.len());
106 for idx in active {
107 let cap_left = caps[idx].saturating_sub(allocations[idx]);
108 let take = share.min(cap_left);
109 allocations[idx] += take;
110 consumed += take;
111 if allocations[idx] < caps[idx] {
112 next_active.push(idx);
113 }
114 }
115
116 if consumed == 0 {
117 break;
118 }
119
120 remaining = remaining.saturating_sub(consumed);
121 active = next_active;
122 }
123
124 allocations
125}
126
127fn allocate_dynamic_payload_reservations(max_lens: &[usize], available: usize) -> Vec<usize> {
128 if max_lens.is_empty() || available == 0 {
129 return vec![0; max_lens.len()];
130 }
131
132 let base_caps = vec![DYNAMIC_READ_ERROR_PAYLOAD_LEN; max_lens.len()];
133 let base_budget = available.min(DYNAMIC_READ_ERROR_PAYLOAD_LEN.saturating_mul(max_lens.len()));
134 let mut reservations = distribute_budget_fairly(&base_caps, base_budget);
135 let remaining_budget = available.saturating_sub(reservations.iter().sum::<usize>());
136 if remaining_budget == 0 {
137 return reservations;
138 }
139
140 let extra_caps: Vec<usize> = max_lens
141 .iter()
142 .zip(reservations.iter())
143 .map(|(max_len, reserved)| {
144 max_len
145 .max(&DYNAMIC_READ_ERROR_PAYLOAD_LEN)
146 .saturating_sub(*reserved)
147 })
148 .collect();
149 let extras = distribute_budget_fairly(&extra_caps, remaining_budget);
150 for (reservation, extra) in reservations.iter_mut().zip(extras) {
151 *reservation += extra;
152 }
153
154 reservations
155}
156
157impl<'ctx, 'dw> EbpfContext<'ctx, 'dw> {
158 const UNKNOWN_CHAR_ARRAY_READ_FALLBACK: usize = 256;
159
160 fn build_errno_i32(&self, ret: IntValue<'ctx>, name: &str) -> Result<IntValue<'ctx>> {
161 let i32_ty = self.context.i32_type();
162 match ret.get_type().get_bit_width().cmp(&32) {
163 std::cmp::Ordering::Greater => self
164 .builder
165 .build_int_truncate(ret, i32_ty, name)
166 .map_err(|e| CodeGenError::LLVMError(e.to_string())),
167 std::cmp::Ordering::Less => self
168 .builder
169 .build_int_s_extend(ret, i32_ty, name)
170 .map_err(|e| CodeGenError::LLVMError(e.to_string())),
171 std::cmp::Ordering::Equal => Ok(ret),
172 }
173 }
174
175 fn resolve_expr_to_arg(&mut self, expr: &crate::script::ast::Expr) -> Result<ComplexArg<'ctx>> {
179 use crate::script::ast::Expr as E;
180 match expr {
181 E::Variable(name) if self.alias_variable_exists(name) => {
183 let aliased = self.get_alias_variable(name).expect("alias exists");
184 let addr_i64 = self.resolve_ptr_i64_from_expr(&aliased)?;
185 let var_name_index = self.trace_context.add_variable_name(name.clone());
186 Ok(ComplexArg {
187 var_name_index,
188 type_index: self.add_synthesized_type_index_for_kind(TypeKind::Pointer),
189 access_path: Vec::new(),
190 data_len: 8,
191 source: ComplexArgSource::ComputedInt {
192 value: addr_i64,
193 byte_len: 8,
194 },
195 })
196 }
197 E::Variable(name) if self.variable_exists(name) => {
199 let val = self.load_variable(name)?;
200 let var_name_index = self.trace_context.add_variable_name(name.clone());
201 if self
203 .get_variable_type(name)
204 .is_some_and(|t| matches!(t, crate::script::VarType::String))
205 {
206 let bytes_opt = self.get_string_variable_bytes(name).cloned();
207 if let Some(bytes) = bytes_opt {
208 let char_type = ghostscope_dwarf::TypeInfo::BaseType {
210 name: "char".to_string(),
211 size: 1,
212 encoding: ghostscope_dwarf::constants::DW_ATE_unsigned_char.0 as u16,
213 };
214 let array_type = ghostscope_dwarf::TypeInfo::ArrayType {
215 element_type: Box::new(char_type),
216 element_count: Some(bytes.len() as u64),
217 total_size: Some(bytes.len() as u64),
218 };
219 return Ok(ComplexArg {
220 var_name_index,
221 type_index: self.trace_context.add_type(array_type),
222 access_path: Vec::new(),
223 data_len: bytes.len(),
224 source: ComplexArgSource::ImmediateBytes { bytes },
225 });
226 }
227 }
228 match val {
229 BasicValueEnum::IntValue(iv) => {
230 let bitw = iv.get_type().get_bit_width();
232 let (kind, byte_len) = if bitw == 1 {
233 (TypeKind::Bool, 1)
234 } else if bitw <= 8 {
235 (TypeKind::I8, 1)
236 } else if bitw <= 16 {
237 (TypeKind::I16, 2)
238 } else if bitw <= 32 {
239 (TypeKind::I32, 4)
240 } else {
241 (TypeKind::I64, 8)
242 };
243 Ok(ComplexArg {
244 var_name_index,
245 type_index: self.add_synthesized_type_index_for_kind(kind),
246 access_path: Vec::new(),
247 data_len: byte_len,
248 source: ComplexArgSource::ComputedInt {
249 value: iv,
250 byte_len,
251 },
252 })
253 }
254 BasicValueEnum::PointerValue(pv) => {
255 let iv = self
257 .builder
258 .build_ptr_to_int(pv, self.context.i64_type(), "ptr_to_i64")
259 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
260 Ok(ComplexArg {
261 var_name_index,
262 type_index: self.add_synthesized_type_index_for_kind(TypeKind::Pointer),
263 access_path: Vec::new(),
264 data_len: 8,
265 source: ComplexArgSource::ComputedInt {
266 value: iv,
267 byte_len: 8,
268 },
269 })
270 }
271 _ => Err(CodeGenError::TypeError(
272 "Unsupported script variable type for print".to_string(),
273 )),
274 }
275 }
276
277 E::String(s) => {
279 let mut bytes = s.as_bytes().to_vec();
280 bytes.push(0);
281 let char_type = ghostscope_dwarf::TypeInfo::BaseType {
282 name: "char".to_string(),
283 size: 1,
284 encoding: ghostscope_dwarf::constants::DW_ATE_unsigned_char.0 as u16,
285 };
286 let array_type = ghostscope_dwarf::TypeInfo::ArrayType {
287 element_type: Box::new(char_type),
288 element_count: Some(bytes.len() as u64),
289 total_size: Some(bytes.len() as u64),
290 };
291 Ok(ComplexArg {
292 var_name_index: self
293 .trace_context
294 .add_variable_name("__str_literal".to_string()),
295 type_index: self.trace_context.add_type(array_type),
296 access_path: Vec::new(),
297 data_len: bytes.len(),
298 source: ComplexArgSource::ImmediateBytes { bytes },
299 })
300 }
301
302 E::Int(v) => {
304 let mut bytes = Vec::with_capacity(8);
305 bytes.extend_from_slice(&(*v).to_le_bytes());
306 let int_type = ghostscope_dwarf::TypeInfo::BaseType {
307 name: "i64".to_string(),
308 size: 8,
309 encoding: ghostscope_dwarf::constants::DW_ATE_signed.0 as u16,
310 };
311 Ok(ComplexArg {
312 var_name_index: self
313 .trace_context
314 .add_variable_name("__int_literal".to_string()),
315 type_index: self.trace_context.add_type(int_type),
316 access_path: Vec::new(),
317 data_len: 8,
318 source: ComplexArgSource::ImmediateBytes { bytes },
319 })
320 }
321
322 E::AddressOf(inner) => {
324 let var = self
325 .query_dwarf_for_complex_expr(inner)?
326 .ok_or_else(|| CodeGenError::VariableNotFound(format!("{inner:?}")))?;
327 let inner_ty = var.dwarf_type.as_ref().ok_or_else(|| {
328 CodeGenError::DwarfError("Expression has no DWARF type information".to_string())
329 })?;
330 let ptr_ty = ghostscope_dwarf::TypeInfo::PointerType {
331 target_type: Box::new(inner_ty.clone()),
332 size: 8,
333 };
334 let module_hint = self.take_module_hint();
335 Ok(ComplexArg {
336 var_name_index: self
337 .trace_context
338 .add_variable_name(self.expr_to_name(expr)),
339 type_index: self.trace_context.add_type(ptr_ty),
340 access_path: Vec::new(),
341 data_len: 8,
342 source: ComplexArgSource::AddressValue {
343 eval_result: var.evaluation_result.clone(),
344 module_for_offsets: module_hint,
345 },
346 })
347 }
348
349 expr @ (E::MemberAccess(_, _)
351 | E::ArrayAccess(_, _)
352 | E::PointerDeref(_)
353 | E::ChainAccess(_)) => {
354 let var = self
355 .query_dwarf_for_complex_expr(expr)?
356 .ok_or_else(|| CodeGenError::VariableNotFound(format!("{expr:?}")))?;
357 if matches!(
358 var.evaluation_result,
359 ghostscope_dwarf::EvaluationResult::Optimized
360 ) {
361 let ti = ghostscope_protocol::type_info::TypeInfo::OptimizedOut {
362 name: var.name.clone(),
363 };
364 return Ok(ComplexArg {
365 var_name_index: self.trace_context.add_variable_name(var.name.clone()),
366 type_index: self.trace_context.add_type(ti),
367 access_path: Vec::new(),
368 data_len: 0,
369 source: ComplexArgSource::ImmediateBytes { bytes: Vec::new() },
370 });
371 }
372 let dwarf_type = var.dwarf_type.as_ref().ok_or_else(|| {
373 CodeGenError::DwarfError("Expression has no DWARF type information".to_string())
374 })?;
375 let data_len = Self::compute_read_size_for_type(dwarf_type);
376 if data_len == 0 {
377 return Err(CodeGenError::TypeSizeNotAvailable(var.name));
378 }
379 let module_hint = self.take_module_hint();
382 Ok(ComplexArg {
383 var_name_index: self.trace_context.add_variable_name(var.name.clone()),
384 type_index: self.trace_context.add_type(dwarf_type.clone()),
385 access_path: Vec::new(),
386 data_len,
387 source: ComplexArgSource::RuntimeRead {
388 eval_result: var.evaluation_result.clone(),
389 dwarf_type: dwarf_type.clone(),
390 module_for_offsets: module_hint,
391 },
392 })
393 }
394
395 E::Variable(name) => {
397 if let Some(v) = self.query_dwarf_for_variable(name)? {
398 if let Some(ref t) = v.dwarf_type {
399 if matches!(
401 v.evaluation_result,
402 ghostscope_dwarf::EvaluationResult::Optimized
403 ) {
404 let ti = ghostscope_protocol::type_info::TypeInfo::OptimizedOut {
405 name: v.name.clone(),
406 };
407 return Ok(ComplexArg {
408 var_name_index: self
409 .trace_context
410 .add_variable_name(v.name.clone()),
411 type_index: self.trace_context.add_type(ti),
412 access_path: Vec::new(),
413 data_len: 0,
414 source: ComplexArgSource::ImmediateBytes { bytes: Vec::new() },
415 });
416 }
417 let is_link_addr = matches!(
418 v.evaluation_result,
419 ghostscope_dwarf::EvaluationResult::MemoryLocation(
420 ghostscope_dwarf::LocationResult::Address(_)
421 )
422 );
423 if Self::is_simple_typeinfo(t) && !is_link_addr {
424 let compiled = self.compile_expr(expr)?;
426 match compiled {
427 BasicValueEnum::IntValue(iv) => {
428 let (kind, byte_len) = if matches!(
430 t,
431 ghostscope_dwarf::TypeInfo::PointerType { .. }
432 ) {
433 (TypeKind::Pointer, 8)
434 } else {
435 let bitw = iv.get_type().get_bit_width();
436 if bitw == 1 {
437 (TypeKind::Bool, 1)
438 } else if bitw <= 8 {
439 (TypeKind::I8, 1)
440 } else if bitw <= 16 {
441 (TypeKind::I16, 2)
442 } else if bitw <= 32 {
443 (TypeKind::I32, 4)
444 } else {
445 (TypeKind::I64, 8)
446 }
447 };
448 Ok(ComplexArg {
449 var_name_index: self
450 .trace_context
451 .add_variable_name(self.expr_to_name(expr)),
452 type_index: self.add_synthesized_type_index_for_kind(kind),
453 access_path: Vec::new(),
454 data_len: byte_len,
455 source: ComplexArgSource::ComputedInt {
456 value: iv,
457 byte_len,
458 },
459 })
460 }
461 BasicValueEnum::PointerValue(pv) => {
462 let iv = self
464 .builder
465 .build_ptr_to_int(pv, self.context.i64_type(), "ptr_to_i64")
466 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
467 Ok(ComplexArg {
468 var_name_index: self
469 .trace_context
470 .add_variable_name(self.expr_to_name(expr)),
471 type_index: self
472 .add_synthesized_type_index_for_kind(TypeKind::Pointer),
473 access_path: Vec::new(),
474 data_len: 8,
475 source: ComplexArgSource::ComputedInt {
476 value: iv,
477 byte_len: 8,
478 },
479 })
480 }
481 _ => {
482 let data_len = Self::compute_read_size_for_type(t);
484 if data_len == 0 {
485 return Err(CodeGenError::TypeSizeNotAvailable(v.name));
486 }
487 let module_hint = self.take_module_hint();
488 Ok(ComplexArg {
489 var_name_index: self
490 .trace_context
491 .add_variable_name(v.name.clone()),
492 type_index: self.trace_context.add_type(t.clone()),
493 access_path: Vec::new(),
494 data_len,
495 source: ComplexArgSource::RuntimeRead {
496 eval_result: v.evaluation_result.clone(),
497 dwarf_type: t.clone(),
498 module_for_offsets: module_hint,
499 },
500 })
501 }
502 }
503 } else {
504 let data_len = Self::compute_read_size_for_type(t);
507 if data_len == 0 {
508 return Err(CodeGenError::TypeSizeNotAvailable(v.name));
509 }
510 let module_hint = self.take_module_hint();
511 Ok(ComplexArg {
512 var_name_index: self
513 .trace_context
514 .add_variable_name(v.name.clone()),
515 type_index: self.trace_context.add_type(t.clone()),
516 access_path: Vec::new(),
517 data_len,
518 source: ComplexArgSource::RuntimeRead {
519 eval_result: v.evaluation_result.clone(),
520 dwarf_type: t.clone(),
521 module_for_offsets: module_hint,
522 },
523 })
524 }
525 } else {
526 Err(CodeGenError::DwarfError(
527 "Variable has no DWARF type information".to_string(),
528 ))
529 }
530 } else {
531 Err(CodeGenError::VariableNotInScope(name.clone()))
532 }
533 }
534
535 E::BinaryOp { left, op, right } => {
537 use crate::script::ast::BinaryOp as BO;
538 let (ptr_side, int_side, sign) = match (&**left, op, &**right) {
542 (l, BO::Add, E::Int(k)) => (l, *k, 1),
543 (E::Int(k), BO::Add, r) => (r, *k, 1),
544 (l, BO::Subtract, E::Int(k)) => (l, *k, -1),
545 _ => {
546 let compiled = self.compile_expr(expr)?;
548 if let BasicValueEnum::IntValue(iv) = compiled {
549 let bitw = iv.get_type().get_bit_width();
550 let (kind, byte_len) = if bitw == 1 {
551 (TypeKind::Bool, 1)
552 } else if bitw <= 8 {
553 (TypeKind::I8, 1)
554 } else if bitw <= 16 {
555 (TypeKind::I16, 2)
556 } else if bitw <= 32 {
557 (TypeKind::I32, 4)
558 } else {
559 (TypeKind::I64, 8)
560 };
561 return Ok(ComplexArg {
562 var_name_index: self
563 .trace_context
564 .add_variable_name(self.expr_to_name(expr)),
565 type_index: self.add_synthesized_type_index_for_kind(kind),
566 access_path: Vec::new(),
567 data_len: byte_len,
568 source: ComplexArgSource::ComputedInt {
569 value: iv,
570 byte_len,
571 },
572 });
573 } else {
574 return Err(CodeGenError::TypeError(
575 "Non-integer expression not supported in print".to_string(),
576 ));
577 }
578 }
579 };
580
581 if let Some(var) = self.query_dwarf_for_complex_expr(ptr_side)? {
583 if var.dwarf_type.is_some() {
584 let index = sign * int_side;
586 let (eval_result, elem_ty) =
587 self.compute_pointed_location_with_index(ptr_side, index)?;
588 let data_len = Self::compute_read_size_for_type(&elem_ty);
589 let module_hint = self.take_module_hint();
590 if data_len == 0 {
591 let ptr_ti = ghostscope_dwarf::TypeInfo::PointerType {
593 target_type: Box::new(elem_ty.clone()),
594 size: 8,
595 };
596 return Ok(ComplexArg {
597 var_name_index: self
598 .trace_context
599 .add_variable_name(self.expr_to_name(expr)),
600 type_index: self.trace_context.add_type(ptr_ti),
601 access_path: Vec::new(),
602 data_len: 8,
603 source: ComplexArgSource::AddressValue {
604 eval_result,
605 module_for_offsets: module_hint,
606 },
607 });
608 }
609 return Ok(ComplexArg {
610 var_name_index: self
611 .trace_context
612 .add_variable_name(self.expr_to_name(expr)),
613 type_index: self.trace_context.add_type(elem_ty.clone()),
614 access_path: Vec::new(),
615 data_len,
616 source: ComplexArgSource::RuntimeRead {
617 eval_result,
618 dwarf_type: elem_ty,
619 module_for_offsets: module_hint,
620 },
621 });
622 }
623 }
624
625 let compiled = self.compile_expr(expr)?;
627 if let BasicValueEnum::IntValue(iv) = compiled {
628 let bitw = iv.get_type().get_bit_width();
629 let (kind, byte_len) = if bitw == 1 {
630 (TypeKind::Bool, 1)
631 } else if bitw <= 8 {
632 (TypeKind::I8, 1)
633 } else if bitw <= 16 {
634 (TypeKind::I16, 2)
635 } else if bitw <= 32 {
636 (TypeKind::I32, 4)
637 } else {
638 (TypeKind::I64, 8)
639 };
640 Ok(ComplexArg {
641 var_name_index: self
642 .trace_context
643 .add_variable_name(self.expr_to_name(expr)),
644 type_index: self.add_synthesized_type_index_for_kind(kind),
645 access_path: Vec::new(),
646 data_len: byte_len,
647 source: ComplexArgSource::ComputedInt {
648 value: iv,
649 byte_len,
650 },
651 })
652 } else {
653 Err(CodeGenError::TypeError(
654 "Non-integer expression not supported in print".to_string(),
655 ))
656 }
657 }
658
659 other => {
661 let compiled = self.compile_expr(other)?;
662 if let BasicValueEnum::IntValue(iv) = compiled {
663 let bitw = iv.get_type().get_bit_width();
664 let (kind, byte_len) = if bitw == 1 {
665 (TypeKind::Bool, 1)
666 } else if bitw <= 8 {
667 (TypeKind::I8, 1)
668 } else if bitw <= 16 {
669 (TypeKind::I16, 2)
670 } else if bitw <= 32 {
671 (TypeKind::I32, 4)
672 } else {
673 (TypeKind::I64, 8)
674 };
675 Ok(ComplexArg {
676 var_name_index: self
677 .trace_context
678 .add_variable_name(self.expr_to_name(other)),
679 type_index: self.add_synthesized_type_index_for_kind(kind),
680 access_path: Vec::new(),
681 data_len: byte_len,
682 source: ComplexArgSource::ComputedInt {
683 value: iv,
684 byte_len,
685 },
686 })
687 } else {
688 Err(CodeGenError::TypeError(
689 "Non-integer expression not supported in print".to_string(),
690 ))
691 }
692 }
693 }
694 }
695
696 fn emit_print_from_arg(&mut self, arg: ComplexArg<'ctx>) -> Result<u16> {
698 match arg.source {
699 ComplexArgSource::ComputedInt { value, byte_len } => {
700 self.generate_print_complex_variable_computed(
701 arg.var_name_index,
702 arg.type_index,
703 byte_len,
704 value,
705 )?;
706 Ok(1)
707 }
708 ComplexArgSource::RuntimeRead {
709 eval_result,
710 ref dwarf_type,
711 module_for_offsets,
712 } => {
713 let meta = PrintVarRuntimeMeta {
714 var_name_index: arg.var_name_index,
715 type_index: arg.type_index,
716 access_path: String::new(),
717 data_len_limit: arg.data_len,
718 };
719 self.generate_print_complex_variable_runtime(
720 meta,
721 &eval_result,
722 dwarf_type,
723 module_for_offsets.as_deref(),
724 )?;
725 Ok(1)
726 }
727 ComplexArgSource::AddressValue { .. } | ComplexArgSource::ImmediateBytes { .. } => {
728 let fmt_idx = self.trace_context.add_string("{}".to_string());
730 self.generate_print_complex_format_instruction(fmt_idx, &[arg])?;
731 Ok(1)
732 }
733 ComplexArgSource::MemDump { .. } | ComplexArgSource::MemDumpDynamic { .. } => {
734 let fmt_idx = self.trace_context.add_string("{}".to_string());
736 self.generate_print_complex_format_instruction(fmt_idx, &[arg])?;
737 Ok(1)
738 }
739 }
740 }
741 fn generate_print_complex_variable_computed(
744 &mut self,
745 var_name_index: u16,
746 type_index: u16,
747 byte_len: usize,
748 value: IntValue<'ctx>,
749 ) -> Result<()> {
750 let header_size = std::mem::size_of::<InstructionHeader>();
752 let data_struct_size = std::mem::size_of::<PrintComplexVariableData>();
753 let access_path_len: usize = 0; let total_data_length = data_struct_size + access_path_len + byte_len;
755 let total_size = header_size + total_data_length;
756
757 let inst_buffer = self.reserve_instruction_region(total_size as u64);
759
760 let inst_type_val = self
762 .context
763 .i8_type()
764 .const_int(InstructionType::PrintComplexVariable as u64, false);
765 self.builder
766 .build_store(inst_buffer, inst_type_val)
767 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store inst_type: {e}")))?;
768
769 let data_length_ptr = unsafe {
771 self.builder
772 .build_gep(
773 self.context.i8_type(),
774 inst_buffer,
775 &[self.context.i32_type().const_int(1, false)],
776 "data_length_ptr",
777 )
778 .map_err(|e| {
779 CodeGenError::LLVMError(format!("Failed to get data_length GEP: {e}"))
780 })?
781 };
782 let data_length_ptr_cast = self
783 .builder
784 .build_pointer_cast(
785 data_length_ptr,
786 self.context.ptr_type(AddressSpace::default()),
787 "data_length_ptr_cast",
788 )
789 .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast data_length ptr: {e}")))?;
790 self.builder
791 .build_store(
792 data_length_ptr_cast,
793 self.context
794 .i16_type()
795 .const_int(total_data_length as u64, false),
796 )
797 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store data_length: {e}")))?;
798
799 let data_ptr = unsafe {
801 self.builder
802 .build_gep(
803 self.context.i8_type(),
804 inst_buffer,
805 &[self.context.i32_type().const_int(header_size as u64, false)],
806 "data_ptr",
807 )
808 .map_err(|e| CodeGenError::LLVMError(format!("Failed to get data GEP: {e}")))?
809 };
810
811 let var_name_index_val = self
813 .context
814 .i16_type()
815 .const_int(var_name_index as u64, false);
816 let var_name_index_off =
817 std::mem::offset_of!(PrintComplexVariableData, var_name_index) as u64;
818 let var_name_index_ptr_i8 = unsafe {
819 self.builder
820 .build_gep(
821 self.context.i8_type(),
822 data_ptr,
823 &[self.context.i32_type().const_int(var_name_index_off, false)],
824 "var_name_index_ptr_i8",
825 )
826 .map_err(|e| {
827 CodeGenError::LLVMError(format!("Failed to get var_name_index GEP: {e}"))
828 })?
829 };
830 let var_name_index_ptr_i16 = self
831 .builder
832 .build_pointer_cast(
833 var_name_index_ptr_i8,
834 self.context.ptr_type(AddressSpace::default()),
835 "var_name_index_ptr_i16",
836 )
837 .map_err(|e| {
838 CodeGenError::LLVMError(format!("Failed to cast var_name_index ptr: {e}"))
839 })?;
840 self.builder
841 .build_store(var_name_index_ptr_i16, var_name_index_val)
842 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store var_name_index: {e}")))?;
843
844 let type_index_offset = std::mem::offset_of!(PrintComplexVariableData, type_index) as u64;
846 let type_index_ptr_i8 = unsafe {
847 self.builder
848 .build_gep(
849 self.context.i8_type(),
850 data_ptr,
851 &[self.context.i32_type().const_int(type_index_offset, false)],
852 "type_index_ptr_i8",
853 )
854 .map_err(|e| {
855 CodeGenError::LLVMError(format!("Failed to get type_index GEP: {e}"))
856 })?
857 };
858 let type_index_ptr = self
859 .builder
860 .build_pointer_cast(
861 type_index_ptr_i8,
862 self.context.ptr_type(AddressSpace::default()),
863 "type_index_ptr_i16",
864 )
865 .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast type_index ptr: {e}")))?;
866 let type_index_val = self.context.i16_type().const_int(type_index as u64, false);
867 self.builder
868 .build_store(type_index_ptr, type_index_val)
869 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store type_index: {e}")))?;
870
871 let access_path_len_off =
873 std::mem::offset_of!(PrintComplexVariableData, access_path_len) as u64;
874 let access_path_len_ptr = unsafe {
875 self.builder
876 .build_gep(
877 self.context.i8_type(),
878 data_ptr,
879 &[self
880 .context
881 .i32_type()
882 .const_int(access_path_len_off, false)],
883 "access_path_len_ptr",
884 )
885 .map_err(|e| {
886 CodeGenError::LLVMError(format!("Failed to get access_path_len GEP: {e}"))
887 })?
888 };
889 self.builder
890 .build_store(access_path_len_ptr, self.context.i8_type().const_zero())
891 .map_err(|e| {
892 CodeGenError::LLVMError(format!("Failed to store access_path_len: {e}"))
893 })?;
894
895 let status_off = std::mem::offset_of!(PrintComplexVariableData, status) as u64;
897 let status_ptr = unsafe {
898 self.builder
899 .build_gep(
900 self.context.i8_type(),
901 data_ptr,
902 &[self.context.i32_type().const_int(status_off, false)],
903 "status_ptr",
904 )
905 .map_err(|e| CodeGenError::LLVMError(format!("Failed to get status GEP: {e}")))?
906 };
907 self.builder
908 .build_store(status_ptr, self.context.i8_type().const_zero())
909 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store status: {e}")))?;
910
911 let data_len_off = std::mem::offset_of!(PrintComplexVariableData, data_len) as u64;
913 let data_len_ptr = unsafe {
914 self.builder
915 .build_gep(
916 self.context.i8_type(),
917 data_ptr,
918 &[self.context.i32_type().const_int(data_len_off, false)],
919 "data_len_ptr",
920 )
921 .map_err(|e| CodeGenError::LLVMError(format!("Failed to get data_len GEP: {e}")))?
922 };
923 let data_len_ptr_cast = self
924 .builder
925 .build_pointer_cast(
926 data_len_ptr,
927 self.context.ptr_type(AddressSpace::default()),
928 "data_len_ptr_cast",
929 )
930 .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast data_len ptr: {e}")))?;
931 self.builder
932 .build_store(
933 data_len_ptr_cast,
934 self.context.i16_type().const_int(byte_len as u64, false),
935 )
936 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store data_len: {e}")))?;
937
938 let var_data_ptr = unsafe {
940 self.builder
941 .build_gep(
942 self.context.i8_type(),
943 data_ptr,
944 &[self
945 .context
946 .i32_type()
947 .const_int(data_struct_size as u64, false)],
948 "var_data_ptr",
949 )
950 .map_err(|e| CodeGenError::LLVMError(format!("Failed to get var_data GEP: {e}")))?
951 };
952
953 match byte_len {
955 1 => {
956 let bitw = value.get_type().get_bit_width();
957 let v = if bitw == 1 {
958 self.builder
960 .build_int_z_extend(value, self.context.i8_type(), "expr_zext_bool_i8")
961 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
962 } else if bitw < 8 {
963 self.builder
964 .build_int_s_extend(value, self.context.i8_type(), "expr_sext_i8")
965 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
966 } else if bitw > 8 {
967 self.builder
968 .build_int_truncate(value, self.context.i8_type(), "expr_trunc_i8")
969 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
970 } else {
971 value
972 };
973 self.builder
974 .build_store(var_data_ptr, v)
975 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
976 }
977 2 => {
978 let bitw = value.get_type().get_bit_width();
979 let v = if bitw < 16 {
980 self.builder
981 .build_int_s_extend(value, self.context.i16_type(), "expr_sext_i16")
982 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
983 } else if bitw > 16 {
984 self.builder
985 .build_int_truncate(value, self.context.i16_type(), "expr_trunc_i16")
986 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
987 } else {
988 value
989 };
990 let i16_ptr_ty = self.context.ptr_type(AddressSpace::default());
991 let cast_ptr = self
992 .builder
993 .build_pointer_cast(var_data_ptr, i16_ptr_ty, "expr_i16_ptr")
994 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
995 self.builder
996 .build_store(cast_ptr, v)
997 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
998 }
999 4 => {
1000 let bitw = value.get_type().get_bit_width();
1001 let v = if bitw < 32 {
1002 self.builder
1003 .build_int_s_extend(value, self.context.i32_type(), "expr_sext_i32")
1004 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
1005 } else if bitw > 32 {
1006 self.builder
1007 .build_int_truncate(value, self.context.i32_type(), "expr_trunc_i32")
1008 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
1009 } else {
1010 value
1011 };
1012 let i32_ptr_ty = self.context.ptr_type(AddressSpace::default());
1013 let cast_ptr = self
1014 .builder
1015 .build_pointer_cast(var_data_ptr, i32_ptr_ty, "expr_i32_ptr")
1016 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
1017 self.builder
1018 .build_store(cast_ptr, v)
1019 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
1020 }
1021 8 => {
1022 let v64 = if value.get_type().get_bit_width() < 64 {
1023 self.builder
1024 .build_int_s_extend(value, self.context.i64_type(), "expr_sext_i64")
1025 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
1026 } else {
1027 value
1028 };
1029 let i64_ptr_ty = self.context.ptr_type(AddressSpace::default());
1030 let cast_ptr = self
1031 .builder
1032 .build_pointer_cast(var_data_ptr, i64_ptr_ty, "expr_i64_ptr")
1033 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
1034 self.builder
1035 .build_store(cast_ptr, v64)
1036 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
1037 }
1038 n => {
1039 let v64 = if value.get_type().get_bit_width() < 64 {
1041 self.builder
1042 .build_int_s_extend(value, self.context.i64_type(), "expr_sext_fallback")
1043 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
1044 } else {
1045 value
1046 };
1047 for i in 0..n {
1048 let shift = self.context.i64_type().const_int((i * 8) as u64, false);
1049 let shifted = self
1050 .builder
1051 .build_right_shift(v64, shift, false, &format!("expr_shr_{i}"))
1052 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
1053 let byte = self
1054 .builder
1055 .build_int_truncate(
1056 shifted,
1057 self.context.i8_type(),
1058 &format!("expr_byte_{i}"),
1059 )
1060 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
1061 let byte_ptr = unsafe {
1062 self.builder
1063 .build_gep(
1064 self.context.i8_type(),
1065 var_data_ptr,
1066 &[self.context.i32_type().const_int(i as u64, false)],
1067 &format!("expr_byte_ptr_{i}"),
1068 )
1069 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
1070 };
1071 self.builder
1072 .build_store(byte_ptr, byte)
1073 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
1074 }
1075 }
1076 }
1077
1078 Ok(())
1080 }
1081 fn is_simple_typeinfo(t: &ghostscope_dwarf::TypeInfo) -> bool {
1085 use ghostscope_dwarf::TypeInfo as TI;
1086 match t {
1087 TI::BaseType { size, .. } => matches!(*size, 1 | 2 | 4 | 8),
1088 TI::EnumType { base_type, .. } => {
1089 let sz = base_type.size();
1090 matches!(sz, 1 | 2 | 4 | 8)
1091 }
1092 TI::PointerType { .. } => true,
1093 TI::TypedefType {
1094 underlying_type, ..
1095 }
1096 | TI::QualifiedType {
1097 underlying_type, ..
1098 } => Self::is_simple_typeinfo(underlying_type),
1099 _ => false,
1100 }
1101 }
1102
1103 fn is_char_byte_typeinfo(t: &ghostscope_dwarf::TypeInfo) -> bool {
1104 use ghostscope_dwarf::TypeInfo as TI;
1105 match t {
1106 TI::BaseType { size, encoding, .. } => {
1107 *size == 1
1108 && (*encoding == ghostscope_dwarf::constants::DW_ATE_unsigned_char.0 as u16
1109 || *encoding == ghostscope_dwarf::constants::DW_ATE_signed_char.0 as u16
1110 || *encoding == ghostscope_dwarf::constants::DW_ATE_unsigned.0 as u16
1111 || *encoding == ghostscope_dwarf::constants::DW_ATE_signed.0 as u16)
1112 }
1113 TI::TypedefType {
1114 underlying_type, ..
1115 }
1116 | TI::QualifiedType {
1117 underlying_type, ..
1118 } => Self::is_char_byte_typeinfo(underlying_type),
1119 _ => false,
1120 }
1121 }
1122
1123 fn compute_read_size_for_type(t: &ghostscope_dwarf::TypeInfo) -> usize {
1126 use ghostscope_dwarf::TypeInfo as TI;
1127 match t {
1128 TI::ArrayType {
1129 element_type,
1130 element_count,
1131 total_size,
1132 } => {
1133 if let Some(ts) = total_size {
1135 return *ts as usize;
1136 }
1137 let elem_size = element_type.size() as usize;
1139 if elem_size == 0 {
1140 return 0;
1141 }
1142 if let Some(cnt) = element_count {
1143 return elem_size * (*cnt as usize);
1144 }
1145 if Self::is_char_byte_typeinfo(element_type) {
1148 return Self::UNKNOWN_CHAR_ARRAY_READ_FALLBACK;
1149 }
1150 0
1151 }
1152 TI::TypedefType {
1153 underlying_type, ..
1154 }
1155 | TI::QualifiedType {
1156 underlying_type, ..
1157 } => Self::compute_read_size_for_type(underlying_type),
1158 _ => t.size() as usize,
1159 }
1160 }
1161
1162 fn unwrap_alias_candidate_dwarf_type(
1163 mut t: &ghostscope_dwarf::TypeInfo,
1164 ) -> &ghostscope_dwarf::TypeInfo {
1165 while let ghostscope_dwarf::TypeInfo::TypedefType {
1166 underlying_type, ..
1167 }
1168 | ghostscope_dwarf::TypeInfo::QualifiedType {
1169 underlying_type, ..
1170 } = t
1171 {
1172 t = underlying_type.as_ref();
1173 }
1174 t
1175 }
1176
1177 fn is_aliasable_dwarf_type(t: &ghostscope_dwarf::TypeInfo) -> bool {
1178 matches!(
1179 Self::unwrap_alias_candidate_dwarf_type(t),
1180 ghostscope_dwarf::TypeInfo::PointerType { .. }
1181 | ghostscope_dwarf::TypeInfo::ArrayType { .. }
1182 | ghostscope_dwarf::TypeInfo::StructType { .. }
1183 | ghostscope_dwarf::TypeInfo::UnionType { .. }
1184 )
1185 }
1186
1187 fn expr_to_name(&self, expr: &crate::script::ast::Expr) -> String {
1188 use crate::script::ast::Expr as E;
1189 fn inner(e: &E) -> String {
1190 match e {
1191 E::Variable(s) => s.clone(),
1192 E::MemberAccess(obj, field) => format!("{}.{field}", inner(obj)),
1193 E::ArrayAccess(arr, idx) => format!("{}[{}]", inner(arr), inner(idx)),
1194 E::PointerDeref(p) => format!("*{}", inner(p)),
1195 E::AddressOf(p) => format!("&{}", inner(p)),
1196 E::ChainAccess(v) => v.join("."),
1197 E::Int(v) => v.to_string(),
1198 E::String(s) => format!("\"{s}\""),
1199 E::Float(v) => format!("{v}"),
1200 E::UnaryNot(e1) => format!("!{}", inner(e1)),
1201 E::Bool(v) => v.to_string(),
1202 E::SpecialVar(s) => format!("${s}"),
1203 E::BuiltinCall { name, args } => {
1204 let arg_strs: Vec<String> = args.iter().map(inner).collect();
1205 format!("{}({})", name, arg_strs.join(", "))
1206 }
1207 E::BinaryOp { left, op, right } => {
1208 let op_str = match op {
1209 crate::script::ast::BinaryOp::Add => "+",
1210 crate::script::ast::BinaryOp::Subtract => "-",
1211 crate::script::ast::BinaryOp::Multiply => "*",
1212 crate::script::ast::BinaryOp::Divide => "/",
1213 crate::script::ast::BinaryOp::Equal => "==",
1214 crate::script::ast::BinaryOp::NotEqual => "!=",
1215 crate::script::ast::BinaryOp::LessThan => "<",
1216 crate::script::ast::BinaryOp::LessEqual => "<=",
1217 crate::script::ast::BinaryOp::GreaterThan => ">",
1218 crate::script::ast::BinaryOp::GreaterEqual => ">=",
1219 crate::script::ast::BinaryOp::LogicalAnd => "&&",
1220 crate::script::ast::BinaryOp::LogicalOr => "||",
1221 };
1222 format!("({}{}{})", inner(left), op_str, inner(right))
1223 }
1224 }
1225 }
1226 let s_full = inner(expr);
1227 const MAX_NAME: usize = 96;
1228 if s_full.chars().count() > MAX_NAME {
1229 let keep = MAX_NAME.saturating_sub(3);
1231 let mut acc = String::with_capacity(MAX_NAME);
1232 for (i, ch) in s_full.chars().enumerate() {
1233 if i >= keep {
1234 break;
1235 }
1236 acc.push(ch);
1237 }
1238 acc.push_str("...");
1239 acc
1240 } else {
1241 s_full
1242 }
1243 }
1244
1245 fn expr_contains_builtin(expr: &crate::script::ast::Expr) -> bool {
1246 use crate::script::ast::Expr as E;
1247
1248 match expr {
1249 E::BuiltinCall { .. } => true,
1250 E::UnaryNot(inner)
1251 | E::PointerDeref(inner)
1252 | E::AddressOf(inner)
1253 | E::MemberAccess(inner, _) => Self::expr_contains_builtin(inner),
1254 E::ArrayAccess(base, index) => {
1255 Self::expr_contains_builtin(base) || Self::expr_contains_builtin(index)
1256 }
1257 E::BinaryOp { left, right, .. } => {
1258 Self::expr_contains_builtin(left) || Self::expr_contains_builtin(right)
1259 }
1260 E::Int(_)
1261 | E::Float(_)
1262 | E::String(_)
1263 | E::Bool(_)
1264 | E::Variable(_)
1265 | E::ChainAccess(_)
1266 | E::SpecialVar(_) => false,
1267 }
1268 }
1269
1270 fn compile_print_expr_with_builtin_exprerror<T, F>(
1271 &mut self,
1272 expr: &crate::script::ast::Expr,
1273 compile: F,
1274 ) -> Result<T>
1275 where
1276 F: FnOnce(&mut Self) -> Result<T>,
1277 {
1278 if !Self::expr_contains_builtin(expr) {
1279 return compile(self);
1280 }
1281
1282 let prev_context_active = self.condition_context_active;
1283 if prev_context_active {
1284 return compile(self);
1285 }
1286
1287 let expr_index = self.trace_context.add_string(self.expr_to_name(expr));
1288 let entry_event_bytes = self.compile_time_event_bytes_upper_bound;
1289
1290 self.reset_condition_error()?;
1291 self.condition_context_active = true;
1292 let compiled = compile(self);
1293 self.condition_context_active = prev_context_active;
1294 let compiled = compiled?;
1295
1296 let current_function = self
1297 .builder
1298 .get_insert_block()
1299 .ok_or_else(|| CodeGenError::LLVMError("No current basic block".to_string()))?
1300 .get_parent()
1301 .ok_or_else(|| CodeGenError::LLVMError("No parent function".to_string()))?;
1302 let err_block = self
1303 .context
1304 .append_basic_block(current_function, "print_expr_err_block");
1305 let ok_block = self
1306 .context
1307 .append_basic_block(current_function, "print_expr_ok_block");
1308 let merge_block = self
1309 .context
1310 .append_basic_block(current_function, "print_expr_merge_block");
1311 let cond_err_pred = self.build_condition_error_predicate()?;
1312 self.builder
1313 .build_conditional_branch(cond_err_pred, err_block, ok_block)
1314 .map_err(|e| {
1315 CodeGenError::LLVMError(format!("Failed to branch on print expr error: {e}"))
1316 })?;
1317
1318 self.builder.position_at_end(err_block);
1319 self.compile_time_event_bytes_upper_bound = entry_event_bytes;
1320 self.emit_current_condition_exprerror(expr_index, "print_expr")?;
1321 let err_path_event_bytes = self.compile_time_event_bytes_upper_bound;
1322 self.builder
1323 .build_unconditional_branch(merge_block)
1324 .map_err(|e| {
1325 CodeGenError::LLVMError(format!(
1326 "Failed to branch from print expr error block: {e}"
1327 ))
1328 })?;
1329
1330 self.builder.position_at_end(ok_block);
1331 self.compile_time_event_bytes_upper_bound = entry_event_bytes;
1332 self.builder
1333 .build_unconditional_branch(merge_block)
1334 .map_err(|e| {
1335 CodeGenError::LLVMError(format!("Failed to branch from print expr ok block: {e}"))
1336 })?;
1337
1338 self.builder.position_at_end(merge_block);
1339 self.compile_time_event_bytes_upper_bound = entry_event_bytes.max(err_path_event_bytes);
1340 Ok(compiled)
1341 }
1342
1343 fn emit_current_condition_exprerror(
1344 &mut self,
1345 expr_index: u16,
1346 name_prefix: &str,
1347 ) -> Result<()> {
1348 let cond_err_ptr = self.get_or_create_cond_error_global();
1349 let err_code = self
1350 .builder
1351 .build_load(
1352 self.context.i8_type(),
1353 cond_err_ptr,
1354 &format!("{name_prefix}_err_code"),
1355 )
1356 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
1357 .into_int_value();
1358 let cond_err_addr_ptr = self.get_or_create_cond_error_addr_global();
1359 let err_addr = self
1360 .builder
1361 .build_load(
1362 self.context.i64_type(),
1363 cond_err_addr_ptr,
1364 &format!("{name_prefix}_err_addr"),
1365 )
1366 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
1367 .into_int_value();
1368 let cond_err_flags_ptr = self.get_or_create_cond_error_flags_global();
1369 let err_flags = self
1370 .builder
1371 .build_load(
1372 self.context.i8_type(),
1373 cond_err_flags_ptr,
1374 &format!("{name_prefix}_err_flags"),
1375 )
1376 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
1377 .into_int_value();
1378 self.generate_expr_error(expr_index, err_code, err_flags, err_addr)
1379 }
1380
1381 fn is_alias_candidate_expr(&mut self, expr: &crate::script::ast::Expr) -> bool {
1388 use crate::script::ast::BinaryOp as BO;
1389 use crate::script::ast::Expr as E;
1390 match expr {
1391 E::Variable(name) if self.alias_variable_exists(name) => true,
1393 E::AddressOf(_) => true,
1395 E::BinaryOp {
1397 left,
1398 op: BO::Add,
1399 right,
1400 } => {
1401 let is_const_nonneg = |e: &E| matches!(e, E::Int(v) if *v >= 0);
1402 (self.is_alias_candidate_expr(left) && is_const_nonneg(right))
1403 || (self.is_alias_candidate_expr(right) && is_const_nonneg(left))
1404 }
1405 other => self
1409 .query_dwarf_for_complex_expr(other)
1410 .ok()
1411 .flatten()
1412 .and_then(|var| var.dwarf_type)
1413 .is_some_and(|ty| Self::is_aliasable_dwarf_type(&ty)),
1414 }
1415 }
1416
1417 pub fn compile_program_with_staged_transmission(
1421 &mut self,
1422 program: &Program,
1423 _variable_types: HashMap<String, TypeKind>,
1424 ) -> Result<TraceContext> {
1425 info!("Compiling program with staged transmission system");
1426
1427 self.send_trace_event_header()?;
1429 info!("Sent TraceEventHeader");
1430
1431 let trace_id = self.current_trace_id.map(|id| id as u64).unwrap_or(0);
1433 self.send_trace_event_message(trace_id)?;
1434 info!("Sent TraceEventMessage");
1435
1436 self.store_flag_value("_gs_any_fail", 0)?;
1438 self.store_flag_value("_gs_any_success", 0)?;
1439
1440 let mut instruction_count = 0u16;
1442 for statement in &program.statements {
1443 instruction_count += self.compile_statement(statement)?;
1444 }
1445
1446 self.send_end_instruction(instruction_count)?;
1448 info!(
1449 "Sent EndInstruction with {} total instructions",
1450 instruction_count
1451 );
1452
1453 Ok(self.trace_context.clone())
1455 }
1456
1457 pub fn compile_statement(&mut self, statement: &Statement) -> Result<u16> {
1459 debug!("Compiling statement: {:?}", statement);
1460
1461 match statement {
1462 Statement::AliasDeclaration { name, target } => {
1463 info!("Registering alias variable: {} = {:?}", name, target);
1464 self.declare_name_in_current_scope(name)?;
1466 self.set_alias_variable(name, target.clone());
1467 Ok(0)
1468 }
1469 Statement::VarDeclaration { name, value } => {
1470 info!("Processing variable declaration: {} = {:?}", name, value);
1471 self.declare_name_in_current_scope(name)?;
1473 if self.is_alias_candidate_expr(value) {
1475 self.set_alias_variable(name, value.clone());
1476 tracing::debug!(var=%name, "Registered DWARF alias variable");
1477 Ok(0)
1478 } else {
1479 match value {
1482 crate::script::Expr::String(s) => {
1483 let mut bytes = s.as_bytes().to_vec();
1484 bytes.push(0); self.set_string_variable_bytes(name, bytes);
1486 }
1487 crate::script::Expr::Variable(ref nm) => {
1488 if self
1489 .get_variable_type(nm)
1490 .is_some_and(|t| matches!(t, crate::script::VarType::String))
1491 {
1492 if let Some(b) = self.get_string_variable_bytes(nm).cloned() {
1493 self.set_string_variable_bytes(name, b);
1494 }
1495 }
1496 }
1497 _ => {}
1498 }
1499 let compiled_value = self.compile_expr(value)?;
1500 if let BasicValueEnum::PointerValue(_) = compiled_value {
1502 let allow_string_var_copy = match value {
1504 crate::script::Expr::String(_) => true,
1505 crate::script::Expr::Variable(ref nm) => self
1506 .get_variable_type(nm)
1507 .is_some_and(|t| matches!(t, crate::script::VarType::String)),
1508 _ => false,
1509 };
1510 if !allow_string_var_copy {
1511 return Err(CodeGenError::TypeError(
1512 "script variables cannot store pointer values; use DWARF alias (let v = &expr) or keep it as a string".to_string(),
1513 ));
1514 }
1515 }
1516 self.store_variable(name, compiled_value)?;
1517 Ok(0) }
1519 }
1520 Statement::Print(print_stmt) => self.compile_print_statement(print_stmt),
1521 Statement::If {
1522 condition,
1523 then_body,
1524 else_body,
1525 } => {
1526 let entry_event_bytes = self.compile_time_event_bytes_upper_bound;
1527 let expr_text = self.expr_to_name(condition);
1530 let expr_index = self.trace_context.add_string(expr_text);
1531 self.condition_context_active = true;
1533 self.reset_condition_error()?;
1534
1535 let cond_value = self.compile_expr(condition)?;
1537
1538 let cond_bool = match cond_value {
1540 BasicValueEnum::IntValue(int_val) => {
1541 self.builder
1543 .build_int_compare(
1544 inkwell::IntPredicate::NE,
1545 int_val,
1546 int_val.get_type().const_zero(),
1547 "cond_bool",
1548 )
1549 .map_err(|e| {
1550 CodeGenError::LLVMError(format!("Failed to create condition: {e}"))
1551 })?
1552 }
1553 _ => {
1554 return Err(CodeGenError::LLVMError(
1555 "Condition must evaluate to integer".to_string(),
1556 ));
1557 }
1558 };
1559
1560 let current_function = self
1562 .builder
1563 .get_insert_block()
1564 .ok_or_else(|| CodeGenError::LLVMError("No current basic block".to_string()))?
1565 .get_parent()
1566 .ok_or_else(|| CodeGenError::LLVMError("No parent function".to_string()))?;
1567
1568 let then_block = self
1570 .context
1571 .append_basic_block(current_function, "then_block");
1572 let else_block = self
1573 .context
1574 .append_basic_block(current_function, "else_block");
1575 let merge_block = self
1576 .context
1577 .append_basic_block(current_function, "merge_block");
1578 let err_block = self
1579 .context
1580 .append_basic_block(current_function, "cond_err_block");
1581 let ok_block = self
1582 .context
1583 .append_basic_block(current_function, "cond_ok_block");
1584 self.condition_context_active = false;
1586
1587 let cond_err_pred = self.build_condition_error_predicate()?;
1589 self.builder
1590 .build_conditional_branch(cond_err_pred, err_block, ok_block)
1591 .map_err(|e| {
1592 CodeGenError::LLVMError(format!("Failed to branch on cond_err: {e}"))
1593 })?;
1594
1595 self.builder.position_at_end(err_block);
1597 self.compile_time_event_bytes_upper_bound = entry_event_bytes;
1598 self.emit_current_condition_exprerror(expr_index, "cond")?;
1599 let goto_else = matches!(else_body.as_deref(), Some(Statement::If { .. }));
1602 let err_path_event_bytes = self.compile_time_event_bytes_upper_bound;
1603 if goto_else {
1604 self.builder
1605 .build_unconditional_branch(else_block)
1606 .map_err(|e| {
1607 CodeGenError::LLVMError(format!(
1608 "Failed to branch to else on error: {e}"
1609 ))
1610 })?;
1611 } else {
1612 self.builder
1613 .build_unconditional_branch(merge_block)
1614 .map_err(|e| {
1615 CodeGenError::LLVMError(format!(
1616 "Failed to branch to merge on error: {e}"
1617 ))
1618 })?;
1619 }
1620
1621 self.builder.position_at_end(ok_block);
1623 self.compile_time_event_bytes_upper_bound = entry_event_bytes;
1624 self.builder
1625 .build_conditional_branch(cond_bool, then_block, else_block)
1626 .map_err(|e| {
1627 CodeGenError::LLVMError(format!("Failed to create branch: {e}"))
1628 })?;
1629
1630 self.builder.position_at_end(then_block);
1632 self.compile_time_event_bytes_upper_bound = entry_event_bytes;
1633 let mut then_instructions = 0u16;
1634 self.enter_scope();
1635 for stmt in then_body {
1636 then_instructions += self.compile_statement(stmt)?;
1637 }
1638 self.exit_scope();
1639 let then_event_bytes = self.compile_time_event_bytes_upper_bound;
1640 self.builder
1641 .build_unconditional_branch(merge_block)
1642 .map_err(|e| {
1643 CodeGenError::LLVMError(format!("Failed to branch to merge: {e}"))
1644 })?;
1645
1646 self.builder.position_at_end(else_block);
1648 let else_entry_event_bytes = if goto_else {
1649 entry_event_bytes.max(err_path_event_bytes)
1650 } else {
1651 entry_event_bytes
1652 };
1653 self.compile_time_event_bytes_upper_bound = else_entry_event_bytes;
1654 let mut else_instructions = 0u16;
1655 if let Some(else_stmt) = else_body {
1656 self.enter_scope();
1657 else_instructions += self.compile_statement(else_stmt)?;
1658 self.exit_scope();
1659 }
1660 self.builder
1661 .build_unconditional_branch(merge_block)
1662 .map_err(|e| {
1663 CodeGenError::LLVMError(format!("Failed to branch to merge: {e}"))
1664 })?;
1665 let else_event_bytes = self.compile_time_event_bytes_upper_bound;
1666
1667 self.builder.position_at_end(merge_block);
1669 self.compile_time_event_bytes_upper_bound = if goto_else {
1670 then_event_bytes.max(else_event_bytes)
1671 } else {
1672 then_event_bytes
1673 .max(else_event_bytes)
1674 .max(err_path_event_bytes)
1675 };
1676
1677 Ok(std::cmp::max(then_instructions, else_instructions))
1679 }
1680 Statement::Block(nested_statements) => {
1681 let mut total_instructions = 0u16;
1682 self.enter_scope();
1683 for stmt in nested_statements {
1684 total_instructions += self.compile_statement(stmt)?;
1685 }
1686 self.exit_scope();
1687 Ok(total_instructions)
1688 }
1689 Statement::TracePoint { pattern: _, body } => {
1690 let mut total_instructions = 0u16;
1691 self.enter_scope();
1693 for stmt in body {
1694 total_instructions += self.compile_statement(stmt)?;
1695 }
1696 self.exit_scope();
1697 Ok(total_instructions)
1698 }
1699 _ => {
1700 warn!("Unsupported statement type: {:?}", statement);
1701 Ok(0)
1702 }
1703 }
1704 }
1705
1706 pub fn compile_print_statement(&mut self, print_stmt: &PrintStatement) -> Result<u16> {
1708 info!("Compiling print statement: {:?}", print_stmt);
1709
1710 match print_stmt {
1711 PrintStatement::String(s) => {
1712 info!("Processing string literal: {}", s);
1713 let string_index = self.trace_context.add_string(s.to_string());
1715 self.generate_print_string_index(string_index)?;
1717 Ok(1) }
1719 PrintStatement::Variable(var_name) => {
1720 info!("Processing variable: {}", var_name);
1721 let expr = crate::script::Expr::Variable(var_name.clone());
1722 let arg = self.resolve_expr_to_arg(&expr)?;
1723 let n = self.emit_print_from_arg(arg)?;
1724 tracing::trace!(
1725 var_name = %var_name,
1726 instructions = n,
1727 "compile_print_statement: emitted via unified resolver"
1728 );
1729 Ok(n)
1730 }
1731 PrintStatement::ComplexVariable(expr) => {
1732 info!("Processing complex variable: {:?}", expr);
1733 let arg = self.compile_print_expr_with_builtin_exprerror(expr, |ctx| {
1734 ctx.resolve_expr_to_arg(expr)
1735 })?;
1736 let n = self.emit_print_from_arg(arg)?;
1737 tracing::trace!(
1738 instructions = n,
1739 "compile_print_statement: emitted via unified resolver"
1740 );
1741 Ok(n)
1742 }
1743 PrintStatement::Formatted { format, args } => {
1744 info!(
1745 "Processing formatted print: '{}' with {} args",
1746 format,
1747 args.len()
1748 );
1749 self.compile_formatted_print(format, args)
1750 }
1751 }
1752 }
1753
1754 fn compile_formatted_print(
1756 &mut self,
1757 format: &str,
1758 args: &[crate::script::ast::Expr],
1759 ) -> Result<u16> {
1760 info!(
1761 "Compiling formatted print: '{}' with {} arguments",
1762 format,
1763 args.len()
1764 );
1765 let format_string_index = self.trace_context.add_string(format.to_string());
1766 let mut complex_args: Vec<ComplexArg<'ctx>> = Vec::with_capacity(args.len());
1767
1768 #[derive(Clone, Copy, Debug, PartialEq)]
1770 enum Conv {
1771 Default,
1772 HexLower,
1773 HexUpper,
1774 Ptr,
1775 Ascii,
1776 }
1777 #[derive(Clone, Debug, PartialEq)]
1778 enum LenSpec {
1779 None,
1780 Static(usize),
1781 Star,
1782 Capture(String),
1783 }
1784
1785 fn parse_slots(fmt: &str) -> Vec<(Conv, LenSpec)> {
1786 let mut res = Vec::new();
1787 let mut it = fmt.chars().peekable();
1788 while let Some(ch) = it.next() {
1789 if ch == '{' {
1790 if it.peek() == Some(&'{') {
1791 it.next();
1792 continue;
1793 }
1794 let mut content = String::new();
1795 for c in it.by_ref() {
1796 if c == '}' {
1797 break;
1798 }
1799 content.push(c);
1800 }
1801 if content.is_empty() {
1802 res.push((Conv::Default, LenSpec::None));
1803 } else if let Some(rest) = content.strip_prefix(':') {
1804 let mut sit = rest.chars();
1805 let conv = match sit.next().unwrap_or(' ') {
1806 'x' => Conv::HexLower,
1807 'X' => Conv::HexUpper,
1808 'p' => Conv::Ptr,
1809 's' => Conv::Ascii,
1810 _ => Conv::Default,
1811 };
1812 let rest: String = sit.collect();
1813 let lens = if rest.is_empty() {
1814 LenSpec::None
1815 } else if let Some(r) = rest.strip_prefix('.') {
1816 if r == "*" {
1817 LenSpec::Star
1818 } else if let Some(s) = r.strip_suffix('$') {
1819 LenSpec::Capture(s.to_string())
1820 } else if r.chars().all(|c| c.is_ascii_digit()) {
1821 LenSpec::Static(r.parse::<usize>().unwrap_or(0))
1822 } else {
1823 LenSpec::None
1824 }
1825 } else {
1826 LenSpec::None
1827 };
1828 res.push((conv, lens));
1829 } else {
1830 res.push((Conv::Default, LenSpec::None));
1831 }
1832 }
1833 }
1834 res
1835 }
1836
1837 let slots = parse_slots(format);
1838 let mut ai = 0usize; for (conv, lens) in slots.into_iter() {
1840 match conv {
1841 Conv::Default => {
1842 if ai >= args.len() {
1843 break;
1844 }
1845 let expr = &args[ai];
1846 let a = self.compile_print_expr_with_builtin_exprerror(expr, |ctx| {
1847 ctx.resolve_expr_to_arg(expr)
1848 })?;
1849 complex_args.push(a);
1850 ai += 1;
1851 }
1852 Conv::Ptr => {
1853 if ai >= args.len() {
1854 break;
1855 }
1856 let expr = &args[ai];
1858 let val = self.compile_expr(expr)?;
1860 let iv = match val {
1861 BasicValueEnum::IntValue(iv) => iv,
1862 BasicValueEnum::PointerValue(pv) => self
1863 .builder
1864 .build_ptr_to_int(pv, self.context.i64_type(), "ptr_to_i64")
1865 .map_err(|e| CodeGenError::Builder(e.to_string()))?,
1866 _ => self
1867 .compile_dwarf_expression(expr)
1868 .and_then(|bv| match bv {
1869 BasicValueEnum::IntValue(iv) => Ok(iv),
1870 BasicValueEnum::PointerValue(pv) => self
1871 .builder
1872 .build_ptr_to_int(pv, self.context.i64_type(), "ptr_to_i64")
1873 .map_err(|e| CodeGenError::Builder(e.to_string())),
1874 _ => Err(CodeGenError::TypeError("pointer expected".into())),
1875 })?,
1876 };
1877 complex_args.push(ComplexArg {
1878 var_name_index: self
1879 .trace_context
1880 .add_variable_name(self.expr_to_name(expr)),
1881 type_index: self.add_synthesized_type_index_for_kind(TypeKind::Pointer),
1882 access_path: Vec::new(),
1883 data_len: 8,
1884 source: ComplexArgSource::ComputedInt {
1885 value: iv,
1886 byte_len: 8,
1887 },
1888 });
1889 ai += 1;
1890 }
1891 Conv::HexLower | Conv::HexUpper | Conv::Ascii => {
1892 let wants_ascii = matches!(conv, Conv::Ascii);
1895 match lens {
1896 LenSpec::Static(n) if ai < args.len() => {
1897 let expr = &args[ai];
1899 let val = self.compile_expr(expr).ok();
1901 let mut addr_iv: Option<IntValue> = match val {
1902 Some(BasicValueEnum::PointerValue(pv)) => Some(
1903 self.builder
1904 .build_ptr_to_int(pv, self.context.i64_type(), "ptr_to_i64")
1905 .map_err(|e| CodeGenError::Builder(e.to_string()))?,
1906 ),
1907 _ => None,
1908 };
1909 if addr_iv.is_none() {
1911 if let Some(BasicValueEnum::IntValue(iv)) = val {
1912 if let Some(var) = self.query_dwarf_for_complex_expr(expr)? {
1913 if let Some(ref t) = var.dwarf_type {
1914 if matches!(
1915 t,
1916 ghostscope_dwarf::TypeInfo::PointerType { .. }
1917 ) {
1918 addr_iv = Some(iv);
1919 }
1920 }
1921 }
1922 }
1923 }
1924 let addr_iv = if let Some(iv) = addr_iv {
1925 iv
1926 } else {
1927 let var =
1929 self.query_dwarf_for_complex_expr(expr)?.ok_or_else(|| {
1930 CodeGenError::VariableNotFound(format!("{expr:?}"))
1931 })?;
1932 let mod_hint = self.take_module_hint();
1933 self.evaluation_result_to_address_with_hint(
1934 &var.evaluation_result,
1935 None,
1936 mod_hint.as_deref(),
1937 )?
1938 };
1939 complex_args.push(ComplexArg {
1940 var_name_index: self
1941 .trace_context
1942 .add_variable_name(self.expr_to_name(expr)),
1943 type_index: self
1944 .trace_context
1945 .add_type(ghostscope_dwarf::TypeInfo::ArrayType {
1946 element_type: Box::new(ghostscope_dwarf::TypeInfo::BaseType {
1947 name: "u8".into(),
1948 size: 1,
1949 encoding: ghostscope_dwarf::constants::DW_ATE_unsigned_char
1950 .0
1951 as u16,
1952 }),
1953 element_count: Some(n as u64),
1954 total_size: Some(n as u64),
1955 }),
1956 access_path: Vec::new(),
1957 data_len: n,
1958 source: ComplexArgSource::MemDump {
1959 src_addr: addr_iv,
1960 len: n,
1961 },
1962 });
1963 ai += 1;
1964 }
1965 LenSpec::Star => {
1966 if ai + 1 >= args.len() {
1968 break;
1969 }
1970 let len_expr = &args[ai];
1972 let len_val = self.compile_expr(len_expr)?;
1973 let (len_iv, byte_len) = match len_val {
1974 BasicValueEnum::IntValue(iv) => (iv, 8usize),
1975 _ => {
1976 return Err(CodeGenError::TypeError(
1977 "length must be integer".into(),
1978 ))
1979 }
1980 };
1981 complex_args.push(ComplexArg {
1982 var_name_index: self
1983 .trace_context
1984 .add_variable_name("__len".into()),
1985 type_index: self.add_synthesized_type_index_for_kind(TypeKind::U64),
1986 access_path: Vec::new(),
1987 data_len: byte_len,
1988 source: ComplexArgSource::ComputedInt {
1989 value: len_iv,
1990 byte_len,
1991 },
1992 });
1993
1994 let val_expr = &args[ai + 1];
1996 let val = self.compile_expr(val_expr).ok();
1998 let mut addr_iv: Option<IntValue> = match val {
1999 Some(BasicValueEnum::PointerValue(pv)) => Some(
2000 self.builder
2001 .build_ptr_to_int(pv, self.context.i64_type(), "ptr_to_i64")
2002 .map_err(|e| CodeGenError::Builder(e.to_string()))?,
2003 ),
2004 _ => None,
2005 };
2006 if addr_iv.is_none() {
2007 if let Some(BasicValueEnum::IntValue(iv)) = val {
2008 if let Some(var) =
2009 self.query_dwarf_for_complex_expr(val_expr)?
2010 {
2011 if let Some(ref t) = var.dwarf_type {
2012 if matches!(
2013 t,
2014 ghostscope_dwarf::TypeInfo::PointerType { .. }
2015 ) {
2016 addr_iv = Some(iv);
2017 }
2018 }
2019 }
2020 }
2021 }
2022 let addr_iv = if let Some(iv) = addr_iv {
2023 iv
2024 } else {
2025 let var = self.query_dwarf_for_complex_expr(val_expr)?.ok_or_else(
2026 || CodeGenError::VariableNotFound(format!("{val_expr:?}")),
2027 )?;
2028 let mod_hint = self.take_module_hint();
2029 self.evaluation_result_to_address_with_hint(
2030 &var.evaluation_result,
2031 None,
2032 mod_hint.as_deref(),
2033 )?
2034 };
2035 let cap = self.compile_options.mem_dump_cap as usize;
2037 complex_args.push(ComplexArg {
2038 var_name_index: self
2039 .trace_context
2040 .add_variable_name(self.expr_to_name(val_expr)),
2041 type_index: self
2042 .trace_context
2043 .add_type(ghostscope_dwarf::TypeInfo::ArrayType {
2044 element_type: Box::new(ghostscope_dwarf::TypeInfo::BaseType {
2045 name: "u8".into(),
2046 size: 1,
2047 encoding: ghostscope_dwarf::constants::DW_ATE_unsigned_char
2048 .0
2049 as u16,
2050 }),
2051 element_count: Some(cap as u64),
2052 total_size: Some(cap as u64),
2053 }),
2054 access_path: Vec::new(),
2055 data_len: cap,
2056 source: ComplexArgSource::MemDumpDynamic {
2057 src_addr: addr_iv,
2058 len_value: len_iv,
2059 max_len: cap,
2060 },
2061 });
2062 ai += 2;
2063 }
2064 LenSpec::Capture(name) => {
2065 if ai >= args.len() {
2067 break;
2068 }
2069 if !self.variable_exists(&name) {
2070 return Err(CodeGenError::TypeError(format!(
2071 "capture length variable '{name}' not found"
2072 )));
2073 }
2074 let len_val = self.load_variable(&name)?;
2076 let (len_iv, byte_len) = match len_val {
2077 BasicValueEnum::IntValue(iv) => (iv, 8usize),
2078 BasicValueEnum::PointerValue(pv) => (
2079 self.builder
2080 .build_ptr_to_int(
2081 pv,
2082 self.context.i64_type(),
2083 "len_ptr_to_i64",
2084 )
2085 .map_err(|e| CodeGenError::Builder(e.to_string()))?,
2086 8usize,
2087 ),
2088 _ => {
2089 return Err(CodeGenError::TypeError(
2090 "length must be integer/pointer".into(),
2091 ))
2092 }
2093 };
2094 complex_args.push(ComplexArg {
2095 var_name_index: self.trace_context.add_variable_name(name.clone()),
2096 type_index: self.add_synthesized_type_index_for_kind(TypeKind::U64),
2097 access_path: Vec::new(),
2098 data_len: byte_len,
2099 source: ComplexArgSource::ComputedInt {
2100 value: len_iv,
2101 byte_len,
2102 },
2103 });
2104
2105 let val_expr = &args[ai];
2107 let val = self.compile_expr(val_expr).ok();
2108 let mut addr_iv: Option<IntValue> = match val {
2109 Some(BasicValueEnum::PointerValue(pv)) => Some(
2110 self.builder
2111 .build_ptr_to_int(pv, self.context.i64_type(), "ptr_to_i64")
2112 .map_err(|e| CodeGenError::Builder(e.to_string()))?,
2113 ),
2114 _ => None,
2115 };
2116 if addr_iv.is_none() {
2117 if let Some(BasicValueEnum::IntValue(iv)) = val {
2118 if let Some(var) =
2119 self.query_dwarf_for_complex_expr(val_expr)?
2120 {
2121 if let Some(ref t) = var.dwarf_type {
2122 if matches!(
2123 t,
2124 ghostscope_dwarf::TypeInfo::PointerType { .. }
2125 ) {
2126 addr_iv = Some(iv);
2127 }
2128 }
2129 }
2130 }
2131 }
2132 let addr_iv = if let Some(iv) = addr_iv {
2133 iv
2134 } else {
2135 let var = self.query_dwarf_for_complex_expr(val_expr)?.ok_or_else(
2136 || CodeGenError::VariableNotFound(format!("{val_expr:?}")),
2137 )?;
2138 let mod_hint = self.take_module_hint();
2139 self.evaluation_result_to_address_with_hint(
2140 &var.evaluation_result,
2141 None,
2142 mod_hint.as_deref(),
2143 )?
2144 };
2145 let cap = self.compile_options.mem_dump_cap as usize;
2146 complex_args.push(ComplexArg {
2147 var_name_index: self
2148 .trace_context
2149 .add_variable_name(self.expr_to_name(val_expr)),
2150 type_index: self
2151 .trace_context
2152 .add_type(ghostscope_dwarf::TypeInfo::ArrayType {
2153 element_type: Box::new(ghostscope_dwarf::TypeInfo::BaseType {
2154 name: "u8".into(),
2155 size: 1,
2156 encoding: ghostscope_dwarf::constants::DW_ATE_unsigned_char
2157 .0
2158 as u16,
2159 }),
2160 element_count: Some(cap as u64),
2161 total_size: Some(cap as u64),
2162 }),
2163 access_path: Vec::new(),
2164 data_len: cap,
2165 source: ComplexArgSource::MemDumpDynamic {
2166 src_addr: addr_iv,
2167 len_value: len_iv,
2168 max_len: cap,
2169 },
2170 });
2171 ai += 1;
2172 }
2173 _ => {
2174 if ai >= args.len() {
2176 break;
2177 }
2178 complex_args.push(self.resolve_expr_to_arg(&args[ai])?);
2179 ai += 1;
2180 }
2181 }
2182 let _ = wants_ascii; }
2184 }
2185 }
2186 self.generate_print_complex_format_instruction(format_string_index, &complex_args)?;
2187 Ok(1)
2188 }
2189
2190 pub fn resolve_variable_with_priority(&mut self, var_name: &str) -> Result<(u16, TypeKind)> {
2193 info!("Resolving variable '{}' with correct priority", var_name);
2194
2195 if self.variable_exists(var_name) {
2197 info!("Found script variable: {}", var_name);
2198
2199 let loaded_value = self.load_variable(var_name)?;
2201 let type_encoding = self.infer_type_from_llvm_value(&loaded_value);
2202
2203 let var_name_index = self.trace_context.add_variable_name(var_name.to_string());
2205
2206 return Ok((var_name_index, type_encoding));
2207 }
2208
2209 info!(
2211 "Variable '{}' not found in script variables, checking DWARF",
2212 var_name
2213 );
2214
2215 let compile_context = self.get_compile_time_context()?.clone();
2216 let variable_with_eval = match self.query_dwarf_for_variable(var_name)? {
2217 Some(var) => var,
2218 None => {
2219 return Err(CodeGenError::VariableNotFound(format!(
2220 "Variable '{}' not found in script or DWARF at PC 0x{:x} in module '{}'",
2221 var_name, compile_context.pc_address, compile_context.module_path
2222 )));
2223 }
2224 };
2225
2226 let dwarf_type = variable_with_eval.dwarf_type.as_ref().ok_or_else(|| {
2228 CodeGenError::DwarfError("Variable has no DWARF type information".to_string())
2229 })?;
2230 let type_encoding = TypeKind::from(dwarf_type);
2231
2232 let var_name_index = self.trace_context.add_variable_name(var_name.to_string());
2234
2235 info!(
2236 "DWARF variable '{}' resolved successfully with type: {:?}",
2237 var_name, type_encoding
2238 );
2239
2240 Ok((var_name_index, type_encoding))
2241 }
2242
2243 fn synthesize_typeinfo_for_typekind(&self, kind: TypeKind) -> ghostscope_dwarf::TypeInfo {
2245 use ghostscope_dwarf::constants::{
2246 DW_ATE_boolean, DW_ATE_float, DW_ATE_signed, DW_ATE_signed_char, DW_ATE_unsigned,
2247 };
2248 use ghostscope_dwarf::TypeInfo as TI;
2249
2250 match kind {
2251 TypeKind::Bool => TI::BaseType {
2252 name: "bool".to_string(),
2253 size: 1,
2254 encoding: DW_ATE_boolean.0 as u16,
2255 },
2256 TypeKind::F32 => TI::BaseType {
2257 name: "f32".to_string(),
2258 size: 4,
2259 encoding: DW_ATE_float.0 as u16,
2260 },
2261 TypeKind::F64 => TI::BaseType {
2262 name: "f64".to_string(),
2263 size: 8,
2264 encoding: DW_ATE_float.0 as u16,
2265 },
2266 TypeKind::I8 => TI::BaseType {
2267 name: "i8".to_string(),
2268 size: 1,
2269 encoding: DW_ATE_signed_char.0 as u16,
2270 },
2271 TypeKind::I16 => TI::BaseType {
2272 name: "i16".to_string(),
2273 size: 2,
2274 encoding: DW_ATE_signed.0 as u16,
2275 },
2276 TypeKind::I32 => TI::BaseType {
2277 name: "i32".to_string(),
2278 size: 4,
2279 encoding: DW_ATE_signed.0 as u16,
2280 },
2281 TypeKind::I64 => TI::BaseType {
2282 name: "i64".to_string(),
2283 size: 8,
2284 encoding: DW_ATE_signed.0 as u16,
2285 },
2286 TypeKind::U8 | TypeKind::Char => TI::BaseType {
2287 name: "u8".to_string(),
2288 size: 1,
2289 encoding: DW_ATE_unsigned.0 as u16,
2290 },
2291 TypeKind::U16 => TI::BaseType {
2292 name: "u16".to_string(),
2293 size: 2,
2294 encoding: DW_ATE_unsigned.0 as u16,
2295 },
2296 TypeKind::U32 => TI::BaseType {
2297 name: "u32".to_string(),
2298 size: 4,
2299 encoding: DW_ATE_unsigned.0 as u16,
2300 },
2301 TypeKind::U64 => TI::BaseType {
2302 name: "u64".to_string(),
2303 size: 8,
2304 encoding: DW_ATE_unsigned.0 as u16,
2305 },
2306 TypeKind::Pointer | TypeKind::CString | TypeKind::String | TypeKind::Unknown => {
2307 TI::PointerType {
2309 target_type: Box::new(TI::UnknownType {
2310 name: "void".to_string(),
2311 }),
2312 size: 8,
2313 }
2314 }
2315 TypeKind::NullPointer => TI::PointerType {
2316 target_type: Box::new(TI::UnknownType {
2317 name: "void".to_string(),
2318 }),
2319 size: 8,
2320 },
2321 _ => TI::BaseType {
2322 name: "i64".to_string(),
2323 size: 8,
2324 encoding: DW_ATE_signed.0 as u16,
2325 },
2326 }
2327 }
2328
2329 fn add_synthesized_type_index_for_kind(&mut self, kind: TypeKind) -> u16 {
2330 let ti = self.synthesize_typeinfo_for_typekind(kind);
2331 self.trace_context.add_type(ti)
2332 }
2333
2334 fn infer_type_from_llvm_value(&self, value: &BasicValueEnum<'_>) -> TypeKind {
2337 match value {
2338 BasicValueEnum::IntValue(int_val) => {
2339 match int_val.get_type().get_bit_width() {
2340 1 => TypeKind::Bool,
2341 8 => TypeKind::I8, 16 => TypeKind::I16,
2343 32 => TypeKind::I32,
2344 64 => TypeKind::I64,
2345 _ => TypeKind::I64, }
2347 }
2348 BasicValueEnum::FloatValue(float_val) => {
2349 match float_val.get_type() {
2350 t if t == self.context.f32_type() => TypeKind::F32,
2351 t if t == self.context.f64_type() => TypeKind::F64,
2352 _ => TypeKind::F64, }
2354 }
2355 BasicValueEnum::PointerValue(_) => TypeKind::Pointer,
2356 _ => TypeKind::I64, }
2358 }
2359
2360 fn generate_print_complex_format_instruction(
2362 &mut self,
2363 format_string_index: u16,
2364 complex_args: &[ComplexArg<'ctx>],
2365 ) -> Result<()> {
2366 use InstructionType::PrintComplexFormat as IT;
2367
2368 let instruction_budget = print_complex_format_instruction_budget(
2371 self.compile_options.max_trace_event_size as usize,
2372 self.compile_time_event_bytes_upper_bound,
2373 );
2374 let fixed_overhead = std::mem::size_of::<InstructionHeader>()
2375 + std::mem::size_of::<PrintComplexFormatData>();
2376
2377 let mut arg_count = 0u8;
2379 let mut headers_total = 0usize;
2380 let mut static_payload_total = 0usize;
2381 let mut dynamic_max_lens: Vec<usize> = Vec::new();
2382 let mut header_lens: Vec<usize> = Vec::with_capacity(complex_args.len());
2383 for a in complex_args {
2384 let header_len = 2 + 2 + 1 + 1 + 2 + a.access_path.len();
2386 header_lens.push(header_len);
2387 headers_total += header_len;
2388
2389 match &a.source {
2390 ComplexArgSource::ImmediateBytes { bytes } => static_payload_total += bytes.len(),
2391 ComplexArgSource::AddressValue { .. } => static_payload_total += 8,
2392 ComplexArgSource::RuntimeRead { .. } => {
2393 static_payload_total +=
2394 std::cmp::max(a.data_len, DYNAMIC_READ_ERROR_PAYLOAD_LEN)
2395 }
2396 ComplexArgSource::ComputedInt { byte_len, .. } => static_payload_total += *byte_len,
2397 ComplexArgSource::MemDump { len, .. } => {
2398 static_payload_total += std::cmp::max(*len, DYNAMIC_READ_ERROR_PAYLOAD_LEN)
2399 }
2400 ComplexArgSource::MemDumpDynamic { max_len, .. } => dynamic_max_lens.push(*max_len),
2401 }
2402 arg_count = arg_count.saturating_add(1);
2403 }
2404
2405 let remaining_for_payload = instruction_budget
2408 .saturating_sub(fixed_overhead)
2409 .saturating_sub(headers_total)
2410 .saturating_sub(static_payload_total);
2411 let dynamic_reservations =
2412 allocate_dynamic_payload_reservations(&dynamic_max_lens, remaining_for_payload);
2413 let mut dynamic_reservations_iter = dynamic_reservations.into_iter();
2414
2415 let mut effective_reserved: Vec<usize> = Vec::with_capacity(complex_args.len());
2418 for a in complex_args {
2419 let reserved = match &a.source {
2420 ComplexArgSource::ImmediateBytes { bytes } => bytes.len(),
2421 ComplexArgSource::AddressValue { .. } => 8,
2422 ComplexArgSource::RuntimeRead { .. } => {
2423 std::cmp::max(a.data_len, DYNAMIC_READ_ERROR_PAYLOAD_LEN)
2424 }
2425 ComplexArgSource::ComputedInt { byte_len, .. } => *byte_len,
2426 ComplexArgSource::MemDump { len, .. } => {
2427 std::cmp::max(*len, DYNAMIC_READ_ERROR_PAYLOAD_LEN)
2428 }
2429 ComplexArgSource::MemDumpDynamic { .. } => {
2430 dynamic_reservations_iter.next().unwrap_or(0)
2431 }
2432 };
2433 effective_reserved.push(reserved);
2434 }
2435
2436 let total_args_payload: usize =
2438 header_lens.iter().sum::<usize>() + effective_reserved.iter().sum::<usize>();
2439 let inst_data_size = std::mem::size_of::<PrintComplexFormatData>() + total_args_payload;
2440 let total_size = std::mem::size_of::<InstructionHeader>() + inst_data_size;
2441
2442 let buffer = self.reserve_instruction_region(total_size as u64);
2444
2445 let inst_type_val = self.context.i8_type().const_int(IT as u8 as u64, false);
2449 self.builder
2450 .build_store(buffer, inst_type_val)
2451 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store inst_type: {e}")))?;
2452 let data_length_ptr = unsafe {
2454 self.builder
2455 .build_gep(
2456 self.context.i8_type(),
2457 buffer,
2458 &[self.context.i32_type().const_int(1, false)],
2459 "data_length_ptr",
2460 )
2461 .map_err(|e| {
2462 CodeGenError::LLVMError(format!("Failed to get data_length GEP: {e}"))
2463 })?
2464 };
2465 let data_length_i16_ptr = self
2466 .builder
2467 .build_pointer_cast(
2468 data_length_ptr,
2469 self.context.ptr_type(AddressSpace::default()),
2470 "data_length_i16_ptr",
2471 )
2472 .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast data_length ptr: {e}")))?;
2473 let data_length_val = self
2474 .context
2475 .i16_type()
2476 .const_int(inst_data_size as u64, false);
2477 self.builder
2478 .build_store(data_length_i16_ptr, data_length_val)
2479 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store data_length: {e}")))?;
2480
2481 let data_ptr = unsafe {
2483 self.builder
2484 .build_gep(
2485 self.context.i8_type(),
2486 buffer,
2487 &[self.context.i32_type().const_int(4, false)],
2488 "pcf_data_ptr",
2489 )
2490 .map_err(|e| {
2491 CodeGenError::LLVMError(format!("Failed to get pcf_data_ptr GEP: {e}"))
2492 })?
2493 };
2494
2495 let fsi_ptr = self
2497 .builder
2498 .build_pointer_cast(
2499 data_ptr,
2500 self.context.ptr_type(AddressSpace::default()),
2501 "fsi_ptr",
2502 )
2503 .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast fsi_ptr: {e}")))?;
2504 let fsi_val = self
2505 .context
2506 .i16_type()
2507 .const_int(format_string_index as u64, false);
2508 self.builder
2509 .build_store(fsi_ptr, fsi_val)
2510 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store fsi: {e}")))?;
2511 let arg_cnt_ptr = unsafe {
2513 self.builder
2514 .build_gep(
2515 self.context.i8_type(),
2516 data_ptr,
2517 &[self.context.i32_type().const_int(2, false)],
2518 "arg_count_ptr",
2519 )
2520 .map_err(|e| CodeGenError::LLVMError(format!("Failed to get arg_count GEP: {e}")))?
2521 };
2522 self.builder
2523 .build_store(
2524 arg_cnt_ptr,
2525 self.context.i8_type().const_int(arg_count as u64, false),
2526 )
2527 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store arg_count: {e}")))?;
2528
2529 let mut offset = std::mem::size_of::<PrintComplexFormatData>();
2531 for (arg_index, a) in complex_args.iter().enumerate() {
2532 let reserved_len = effective_reserved[arg_index];
2534
2535 let arg_base = unsafe {
2537 self.builder
2538 .build_gep(
2539 self.context.i8_type(),
2540 data_ptr,
2541 &[self.context.i32_type().const_int(offset as u64, false)],
2542 "arg_base",
2543 )
2544 .map_err(|e| {
2545 CodeGenError::LLVMError(format!("Failed to get arg_base GEP: {e}"))
2546 })?
2547 };
2548
2549 let vni_cast = self
2551 .builder
2552 .build_pointer_cast(
2553 arg_base,
2554 self.context.ptr_type(AddressSpace::default()),
2555 "vni_cast",
2556 )
2557 .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast vni ptr: {e}")))?;
2558 self.builder
2559 .build_store(
2560 vni_cast,
2561 self.context
2562 .i16_type()
2563 .const_int(a.var_name_index as u64, false),
2564 )
2565 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store vni: {e}")))?;
2566
2567 let ti_ptr = unsafe {
2569 self.builder
2570 .build_gep(
2571 self.context.i8_type(),
2572 arg_base,
2573 &[self.context.i32_type().const_int(2, false)],
2574 "ti_ptr",
2575 )
2576 .map_err(|e| CodeGenError::LLVMError(format!("Failed to get ti GEP: {e}")))?
2577 };
2578 let ti_cast = self
2579 .builder
2580 .build_pointer_cast(
2581 ti_ptr,
2582 self.context.ptr_type(AddressSpace::default()),
2583 "ti_cast",
2584 )
2585 .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast ti ptr: {e}")))?;
2586 self.builder
2587 .build_store(
2588 ti_cast,
2589 self.context
2590 .i16_type()
2591 .const_int(a.type_index as u64, false),
2592 )
2593 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store ti: {e}")))?;
2594
2595 let apl_ptr = unsafe {
2597 self.builder
2598 .build_gep(
2599 self.context.i8_type(),
2600 arg_base,
2601 &[self.context.i32_type().const_int(5, false)],
2602 "status_ptr",
2603 )
2604 .map_err(|e| {
2605 CodeGenError::LLVMError(format!("Failed to get status GEP: {e}"))
2606 })?
2607 };
2608 self.builder
2609 .build_store(apl_ptr, self.context.i8_type().const_int(0, false))
2610 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store status: {e}")))?;
2611
2612 let apl_ptr2 = unsafe {
2614 self.builder
2615 .build_gep(
2616 self.context.i8_type(),
2617 arg_base,
2618 &[self.context.i32_type().const_int(4, false)],
2619 "apl_ptr",
2620 )
2621 .map_err(|e| CodeGenError::LLVMError(format!("Failed to get apl GEP: {e}")))?
2622 };
2623 self.builder
2624 .build_store(
2625 apl_ptr2,
2626 self.context
2627 .i8_type()
2628 .const_int(a.access_path.len() as u64, false),
2629 )
2630 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store apl: {e}")))?;
2631
2632 for (i, b) in a.access_path.iter().enumerate() {
2634 let byte_ptr = unsafe {
2635 self.builder
2636 .build_gep(
2637 self.context.i8_type(),
2638 arg_base,
2639 &[self.context.i32_type().const_int((6 + i) as u64, false)],
2640 &format!("ap_byte_{i}"),
2641 )
2642 .map_err(|e| {
2643 CodeGenError::LLVMError(format!("Failed to get ap byte GEP: {e}"))
2644 })?
2645 };
2646 self.builder
2647 .build_store(byte_ptr, self.context.i8_type().const_int(*b as u64, false))
2648 .map_err(|e| {
2649 CodeGenError::LLVMError(format!("Failed to store ap byte: {e}"))
2650 })?;
2651 }
2652
2653 let dl_ptr = unsafe {
2655 self.builder
2656 .build_gep(
2657 self.context.i8_type(),
2658 arg_base,
2659 &[self
2660 .context
2661 .i32_type()
2662 .const_int((6 + a.access_path.len()) as u64, false)],
2663 "dl_ptr",
2664 )
2665 .map_err(|e| CodeGenError::LLVMError(format!("Failed to get dl GEP: {e}")))?
2666 };
2667 let dl_cast = self
2668 .builder
2669 .build_pointer_cast(
2670 dl_ptr,
2671 self.context.ptr_type(AddressSpace::default()),
2672 "dl_cast",
2673 )
2674 .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast dl ptr: {e}")))?;
2675 self.builder
2676 .build_store(
2677 dl_cast,
2678 self.context
2679 .i16_type()
2680 .const_int(reserved_len as u64, false),
2681 )
2682 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store data_len: {e}")))?;
2683
2684 let var_data_ptr = unsafe {
2686 self.builder
2687 .build_gep(
2688 self.context.i8_type(),
2689 arg_base,
2690 &[self
2691 .context
2692 .i32_type()
2693 .const_int((8 + a.access_path.len()) as u64, false)],
2694 "var_data_ptr",
2695 )
2696 .map_err(|e| {
2697 CodeGenError::LLVMError(format!("Failed to get var_data GEP: {e}"))
2698 })?
2699 };
2700
2701 match &a.source {
2704 ComplexArgSource::ImmediateBytes { bytes, .. } => {
2705 for (i, b) in bytes.iter().enumerate() {
2706 let byte_ptr = unsafe {
2707 self.builder
2708 .build_gep(
2709 self.context.i8_type(),
2710 var_data_ptr,
2711 &[self.context.i32_type().const_int(i as u64, false)],
2712 &format!("var_byte_{i}"),
2713 )
2714 .map_err(|e| {
2715 CodeGenError::LLVMError(format!(
2716 "Failed to get var byte GEP: {e}"
2717 ))
2718 })?
2719 };
2720 self.builder
2721 .build_store(
2722 byte_ptr,
2723 self.context.i8_type().const_int(*b as u64, false),
2724 )
2725 .map_err(|e| {
2726 CodeGenError::LLVMError(format!("Failed to store var byte: {e}"))
2727 })?;
2728 }
2729 }
2731 ComplexArgSource::MemDump { src_addr, len } => {
2732 let ptr_ty = self.context.ptr_type(AddressSpace::default());
2734 let i64_ty = self.context.i64_type();
2735 let i32_ty = self.context.i32_type();
2736
2737 let dst_ptr = self
2739 .builder
2740 .build_pointer_cast(var_data_ptr, ptr_ty, "md_dst_ptr")
2741 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2742 let base_src_ptr = self
2743 .builder
2744 .build_int_to_ptr(*src_addr, ptr_ty, "md_src_ptr")
2745 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2746 let offsets_found = self.load_offsets_found_flag()?;
2747 let not_found = self
2748 .builder
2749 .build_not(offsets_found, "md_offsets_miss")
2750 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2751 let null_ptr = ptr_ty.const_null();
2752 let src_ptr = self
2753 .builder
2754 .build_select::<BasicValueEnum<'ctx>, _>(
2755 offsets_found,
2756 base_src_ptr.into(),
2757 null_ptr.into(),
2758 "md_src_or_null",
2759 )
2760 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
2761 .into_pointer_value();
2762 let len_const = i32_ty.const_int(*len as u64, false);
2763 let zero_i32 = i32_ty.const_zero();
2764 let effective_len = self
2765 .builder
2766 .build_select::<BasicValueEnum<'ctx>, _>(
2767 offsets_found,
2768 len_const.into(),
2769 zero_i32.into(),
2770 "md_len_or_zero",
2771 )
2772 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
2773 .into_int_value();
2774 let ret = self
2775 .create_bpf_helper_call(
2776 aya_ebpf_bindings::bindings::bpf_func_id::BPF_FUNC_probe_read_user
2777 as u64,
2778 &[dst_ptr.into(), effective_len.into(), src_ptr.into()],
2779 i64_ty.into(),
2780 "probe_read_user_memdump",
2781 )?
2782 .into_int_value();
2783
2784 let ok_pred = self
2786 .builder
2787 .build_int_compare(
2788 inkwell::IntPredicate::EQ,
2789 ret,
2790 i64_ty.const_zero(),
2791 "md_ok",
2792 )
2793 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
2794 let ok = self
2795 .builder
2796 .build_and(ok_pred, offsets_found, "md_ok_with_offsets")
2797 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2798 let curr = self.builder.get_insert_block().unwrap();
2799 let func = curr.get_parent().unwrap();
2800 let ok_b = self.context.append_basic_block(func, "md_ok");
2801 let err_b = self.context.append_basic_block(func, "md_err");
2802 let cont_b = self.context.append_basic_block(func, "md_cont");
2803 self.builder
2804 .build_conditional_branch(ok, ok_b, err_b)
2805 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2806 self.builder.position_at_end(ok_b);
2808 self.builder
2809 .build_unconditional_branch(cont_b)
2810 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2811 self.builder.position_at_end(err_b);
2813 let offsets_err_b = self.context.append_basic_block(func, "md_offsets_err");
2814 let helper_err_b = self.context.append_basic_block(func, "md_helper_err");
2815 self.builder
2816 .build_conditional_branch(not_found, offsets_err_b, helper_err_b)
2817 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2818 self.builder.position_at_end(offsets_err_b);
2819 self.builder
2820 .build_store(
2821 apl_ptr,
2822 self.context
2823 .i8_type()
2824 .const_int(VariableStatus::OffsetsUnavailable as u64, false),
2825 )
2826 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2827 self.mark_any_fail()?;
2828 self.builder
2829 .build_unconditional_branch(cont_b)
2830 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2831 self.builder.position_at_end(helper_err_b);
2832 self.builder
2833 .build_store(
2834 apl_ptr,
2835 self.context
2836 .i8_type()
2837 .const_int(VariableStatus::ReadError as u64, false),
2838 )
2839 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2840 let errno_ptr = self
2842 .builder
2843 .build_pointer_cast(
2844 var_data_ptr,
2845 self.context.ptr_type(AddressSpace::default()),
2846 "errno_ptr",
2847 )
2848 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2849 let errno = self.build_errno_i32(ret, "errno_i32")?;
2850 self.builder
2851 .build_store(errno_ptr, errno)
2852 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2853 let addr_ptr_i8 = unsafe {
2854 self.builder
2855 .build_gep(
2856 self.context.i8_type(),
2857 var_data_ptr,
2858 &[self.context.i32_type().const_int(4, false)],
2859 "addr_ptr_i8",
2860 )
2861 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
2862 };
2863 let addr_ptr = self
2864 .builder
2865 .build_pointer_cast(
2866 addr_ptr_i8,
2867 self.context.ptr_type(AddressSpace::default()),
2868 "addr_ptr",
2869 )
2870 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2871 self.builder
2872 .build_store(addr_ptr, *src_addr)
2873 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2874 self.mark_any_fail()?;
2875 self.builder
2876 .build_unconditional_branch(cont_b)
2877 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2878 self.builder.position_at_end(cont_b);
2879 }
2880 ComplexArgSource::MemDumpDynamic {
2881 src_addr,
2882 len_value,
2883 max_len: _,
2884 } => {
2885 let eff_max_len = effective_reserved[arg_index] as u32;
2887 let i32_ty = self.context.i32_type();
2889 let rlen_i32 = if len_value.get_type().get_bit_width() > 32 {
2890 self.builder
2891 .build_int_truncate(*len_value, i32_ty, "mdd_len_trunc")
2892 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
2893 } else if len_value.get_type().get_bit_width() < 32 {
2894 self.builder
2895 .build_int_z_extend(*len_value, i32_ty, "mdd_len_zext")
2896 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
2897 } else {
2898 *len_value
2899 };
2900 let zero_i32 = i32_ty.const_zero();
2902 let is_neg = self
2903 .builder
2904 .build_int_compare(
2905 inkwell::IntPredicate::SLT,
2906 rlen_i32,
2907 zero_i32,
2908 "mdd_len_neg",
2909 )
2910 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2911 let rlen_nn = self
2912 .builder
2913 .build_select(is_neg, zero_i32, rlen_i32, "mdd_len_nn")
2914 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
2915 .into_int_value();
2916
2917 let max_const = i32_ty.const_int(eff_max_len as u64, false);
2919 let gt = self
2920 .builder
2921 .build_int_compare(inkwell::IntPredicate::UGT, rlen_nn, max_const, "mdd_gt")
2922 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2923 let sel_len = self
2924 .builder
2925 .build_select(gt, max_const, rlen_nn, "mdd_rlen")
2926 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
2927 .into_int_value();
2928
2929 let curr = self.builder.get_insert_block().unwrap();
2931 let func = curr.get_parent().unwrap();
2932 let zero_b = self.context.append_basic_block(func, "mdd_len_zero");
2933 let read_b = self.context.append_basic_block(func, "mdd_len_read");
2934 let cont_b = self.context.append_basic_block(func, "mdd_cont");
2935 let is_zero = self
2936 .builder
2937 .build_int_compare(
2938 inkwell::IntPredicate::EQ,
2939 sel_len,
2940 i32_ty.const_zero(),
2941 "mdd_len_zero",
2942 )
2943 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2944 self.builder
2945 .build_conditional_branch(is_zero, zero_b, read_b)
2946 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2947
2948 self.builder.position_at_end(zero_b);
2950 self.builder
2951 .build_store(
2952 apl_ptr,
2953 self.context
2954 .i8_type()
2955 .const_int(VariableStatus::ZeroLength as u64, false),
2956 )
2957 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2958 self.builder
2959 .build_unconditional_branch(cont_b)
2960 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2961
2962 self.builder.position_at_end(read_b);
2964 let dst_ptr = self
2965 .builder
2966 .build_bit_cast(
2967 var_data_ptr,
2968 self.context.ptr_type(AddressSpace::default()),
2969 "mdd_dst_ptr",
2970 )
2971 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2972 let ptr_ty = self.context.ptr_type(AddressSpace::default());
2973 let base_src_ptr = self
2974 .builder
2975 .build_int_to_ptr(*src_addr, ptr_ty, "mdd_src_ptr")
2976 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2977 let offsets_found = self.load_offsets_found_flag()?;
2978 let not_found = self
2979 .builder
2980 .build_not(offsets_found, "mdd_dyn_offsets_miss")
2981 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
2982 let null_ptr = ptr_ty.const_null();
2983 let src_ptr = self
2984 .builder
2985 .build_select::<BasicValueEnum<'ctx>, _>(
2986 offsets_found,
2987 base_src_ptr.into(),
2988 null_ptr.into(),
2989 "mdd_src_or_null",
2990 )
2991 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
2992 .into_pointer_value();
2993 let zero_i32 = self.context.i32_type().const_zero();
2994 let effective_len = self
2995 .builder
2996 .build_select::<BasicValueEnum<'ctx>, _>(
2997 offsets_found,
2998 sel_len.into(),
2999 zero_i32.into(),
3000 "mdd_len_or_zero",
3001 )
3002 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
3003 .into_int_value();
3004 let ret = self
3005 .create_bpf_helper_call(
3006 BPF_FUNC_probe_read_user as u64,
3007 &[dst_ptr, effective_len.into(), src_ptr.into()],
3008 self.context.i64_type().into(),
3009 "probe_read_user_dyn",
3010 )?
3011 .into_int_value();
3012 let ok_pred = self
3013 .builder
3014 .build_int_compare(
3015 inkwell::IntPredicate::EQ,
3016 ret,
3017 self.context.i64_type().const_zero(),
3018 "mdd_ok",
3019 )
3020 .map_err(|e| CodeGenError::Builder(e.to_string()))?;
3021 let ok = self
3022 .builder
3023 .build_and(ok_pred, offsets_found, "mdd_ok_with_offsets")
3024 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3025 let ok_b = self.context.append_basic_block(func, "mdd_ok");
3026 let err_b = self.context.append_basic_block(func, "mdd_err");
3027 self.builder
3028 .build_conditional_branch(ok, ok_b, err_b)
3029 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3030 self.builder.position_at_end(ok_b);
3032 self.builder
3033 .build_unconditional_branch(cont_b)
3034 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3035 self.builder.position_at_end(err_b);
3037 let offsets_err_b = self.context.append_basic_block(func, "mdd_offsets_err");
3038 let helper_err_b = self.context.append_basic_block(func, "mdd_helper_err");
3039 self.builder
3040 .build_conditional_branch(not_found, offsets_err_b, helper_err_b)
3041 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3042 self.builder.position_at_end(offsets_err_b);
3043 self.builder
3044 .build_store(
3045 apl_ptr,
3046 self.context
3047 .i8_type()
3048 .const_int(VariableStatus::OffsetsUnavailable as u64, false),
3049 )
3050 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3051 self.mark_any_fail()?;
3052 self.builder
3053 .build_unconditional_branch(cont_b)
3054 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3055 self.builder.position_at_end(helper_err_b);
3056 self.builder
3057 .build_store(
3058 apl_ptr,
3059 self.context
3060 .i8_type()
3061 .const_int(VariableStatus::ReadError as u64, false),
3062 )
3063 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3064 if eff_max_len >= 4 {
3065 let errno_ptr = self
3066 .builder
3067 .build_pointer_cast(
3068 var_data_ptr,
3069 self.context.ptr_type(AddressSpace::default()),
3070 "mdd_errno_ptr",
3071 )
3072 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3073 let errno = self.build_errno_i32(ret, "mdd_errno_i32")?;
3074 self.builder
3075 .build_store(errno_ptr, errno)
3076 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3077 }
3078 if eff_max_len as usize >= DYNAMIC_READ_ERROR_PAYLOAD_LEN {
3079 let addr_ptr_i8 = unsafe {
3080 self.builder
3081 .build_gep(
3082 self.context.i8_type(),
3083 var_data_ptr,
3084 &[self.context.i32_type().const_int(4, false)],
3085 "mdd_addr_ptr_i8",
3086 )
3087 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
3088 };
3089 let addr_ptr = self
3090 .builder
3091 .build_pointer_cast(
3092 addr_ptr_i8,
3093 self.context.ptr_type(AddressSpace::default()),
3094 "mdd_addr_ptr",
3095 )
3096 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3097 self.builder
3098 .build_store(addr_ptr, *src_addr)
3099 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3100 }
3101 self.mark_any_fail()?;
3102 self.builder
3103 .build_unconditional_branch(cont_b)
3104 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3105 self.builder.position_at_end(cont_b);
3106 }
3107 ComplexArgSource::ComputedInt { value, byte_len } => {
3108 match *byte_len {
3111 1 => {
3112 let bitw = value.get_type().get_bit_width();
3113 let v = if bitw == 1 {
3114 self.builder
3116 .build_int_z_extend(
3117 *value,
3118 self.context.i8_type(),
3119 "expr_zext_bool_i8",
3120 )
3121 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
3122 } else if bitw < 8 {
3123 self.builder
3124 .build_int_s_extend(
3125 *value,
3126 self.context.i8_type(),
3127 "expr_sext_i8",
3128 )
3129 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
3130 } else if bitw > 8 {
3131 self.builder
3133 .build_int_truncate(
3134 *value,
3135 self.context.i8_type(),
3136 "expr_trunc_i8",
3137 )
3138 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
3139 } else {
3140 *value
3142 };
3143 self.builder
3145 .build_store(var_data_ptr, v)
3146 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3147 }
3148 2 => {
3149 let bitw = value.get_type().get_bit_width();
3150 let v = if bitw < 16 {
3151 self.builder
3152 .build_int_s_extend(
3153 *value,
3154 self.context.i16_type(),
3155 "expr_sext_i16",
3156 )
3157 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
3158 } else if bitw > 16 {
3159 self.builder
3160 .build_int_truncate(
3161 *value,
3162 self.context.i16_type(),
3163 "expr_trunc_i16",
3164 )
3165 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
3166 } else {
3167 *value
3169 };
3170 let i16_ptr_ty = self.context.ptr_type(AddressSpace::default());
3171 let cast_ptr = self
3172 .builder
3173 .build_pointer_cast(var_data_ptr, i16_ptr_ty, "expr_i16_ptr")
3174 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3175 self.builder
3176 .build_store(cast_ptr, v)
3177 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3178 }
3179 4 => {
3180 let bitw = value.get_type().get_bit_width();
3181 let v = if bitw < 32 {
3182 self.builder
3183 .build_int_s_extend(
3184 *value,
3185 self.context.i32_type(),
3186 "expr_sext_i32",
3187 )
3188 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
3189 } else if bitw > 32 {
3190 self.builder
3191 .build_int_truncate(
3192 *value,
3193 self.context.i32_type(),
3194 "expr_trunc_i32",
3195 )
3196 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
3197 } else {
3198 *value
3200 };
3201 let i32_ptr_ty = self.context.ptr_type(AddressSpace::default());
3202 let cast_ptr = self
3203 .builder
3204 .build_pointer_cast(var_data_ptr, i32_ptr_ty, "expr_i32_ptr")
3205 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3206 self.builder
3207 .build_store(cast_ptr, v)
3208 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3209 }
3210 8 => {
3211 let v64 = if value.get_type().get_bit_width() < 64 {
3212 self.builder
3213 .build_int_s_extend(
3214 *value,
3215 self.context.i64_type(),
3216 "expr_sext",
3217 )
3218 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
3219 } else {
3220 *value
3221 };
3222 let i64_ptr_ty = self.context.ptr_type(AddressSpace::default());
3223 let cast_ptr = self
3224 .builder
3225 .build_pointer_cast(var_data_ptr, i64_ptr_ty, "expr_i64_ptr")
3226 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3227 self.builder
3228 .build_store(cast_ptr, v64)
3229 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3230 }
3231 n => {
3232 let v64 = if value.get_type().get_bit_width() < 64 {
3235 self.builder
3236 .build_int_z_extend(
3237 *value,
3238 self.context.i64_type(),
3239 "expr_zext_fallback",
3240 )
3241 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
3242 } else {
3243 *value
3244 };
3245 for i in 0..n {
3246 let shift =
3248 self.context.i64_type().const_int((i * 8) as u64, false);
3249 let shifted = self
3250 .builder
3251 .build_right_shift(v64, shift, false, &format!("expr_shr_{i}"))
3252 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3253 let byte = self
3254 .builder
3255 .build_int_truncate(
3256 shifted,
3257 self.context.i8_type(),
3258 &format!("expr_byte_{i}"),
3259 )
3260 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3261 let byte_ptr = unsafe {
3262 self.builder
3263 .build_gep(
3264 self.context.i8_type(),
3265 var_data_ptr,
3266 &[self.context.i32_type().const_int(i as u64, false)],
3267 &format!("expr_byte_ptr_{i}"),
3268 )
3269 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
3270 };
3271 self.builder
3272 .build_store(byte_ptr, byte)
3273 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3274 }
3275 }
3276 }
3277 }
3278 ComplexArgSource::RuntimeRead {
3279 eval_result,
3280 dwarf_type,
3281 module_for_offsets,
3282 } => {
3283 let ptr_type = self.context.ptr_type(AddressSpace::default());
3285 let i32_type = self.context.i32_type();
3286 let i64_type = self.context.i64_type();
3287 let dst_ptr = self
3288 .builder
3289 .build_bit_cast(var_data_ptr, ptr_type, "dst_ptr")
3290 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3291 let size_val = i32_type.const_int(a.data_len as u64, false);
3292 let src_addr = self.evaluation_result_to_address_with_hint(
3294 eval_result,
3295 Some(apl_ptr),
3296 module_for_offsets.as_deref(),
3297 )?;
3298 let offsets_found = self.load_offsets_found_flag()?;
3299 let current_block = self.builder.get_insert_block().unwrap();
3300 let current_fn = current_block.get_parent().unwrap();
3301 let cont2_block = self.context.append_basic_block(current_fn, "after_read");
3302 let skip_block = self.context.append_basic_block(current_fn, "offsets_skip");
3303 let found_block = self.context.append_basic_block(current_fn, "offsets_found");
3304 self.builder
3305 .build_conditional_branch(offsets_found, found_block, skip_block)
3306 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3307
3308 self.builder.position_at_end(skip_block);
3310 self.mark_any_fail()?;
3311 self.builder
3312 .build_unconditional_branch(cont2_block)
3313 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3314
3315 self.builder.position_at_end(found_block);
3317 let src_ptr = self
3318 .builder
3319 .build_int_to_ptr(src_addr, ptr_type, "src_ptr")
3320 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3321
3322 let zero64 = i64_type.const_zero();
3325 let is_null = self
3326 .builder
3327 .build_int_compare(inkwell::IntPredicate::EQ, src_addr, zero64, "is_null")
3328 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3329 let null_block = self.context.append_basic_block(current_fn, "null_deref");
3330 let read_block = self.context.append_basic_block(current_fn, "read_user");
3331 self.builder
3332 .build_conditional_branch(is_null, null_block, read_block)
3333 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3334
3335 self.builder.position_at_end(null_block);
3337 self.builder
3338 .build_store(
3339 apl_ptr,
3340 self.context
3341 .i8_type()
3342 .const_int(VariableStatus::NullDeref as u64, false),
3343 )
3344 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3345 self.mark_any_fail()?;
3346 self.builder
3347 .build_unconditional_branch(cont2_block)
3348 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3349
3350 self.builder.position_at_end(read_block);
3352 let ret = self
3353 .create_bpf_helper_call(
3354 BPF_FUNC_probe_read_user as u64,
3355 &[dst_ptr, size_val.into(), src_ptr.into()],
3356 i32_type.into(),
3357 "probe_read_user",
3358 )?
3359 .into_int_value();
3360 let is_err = self
3361 .builder
3362 .build_int_compare(
3363 inkwell::IntPredicate::SLT,
3364 ret,
3365 i32_type.const_zero(),
3366 "ret_lt_zero",
3367 )
3368 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3369 let err_block = self.context.append_basic_block(current_fn, "read_err");
3370 let ok_block = self.context.append_basic_block(current_fn, "read_ok");
3371 self.builder
3372 .build_conditional_branch(is_err, err_block, ok_block)
3373 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3374
3375 self.builder.position_at_end(err_block);
3377 self.builder
3378 .build_store(
3379 apl_ptr,
3380 self.context
3381 .i8_type()
3382 .const_int(VariableStatus::ReadError as u64, false),
3383 )
3384 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3385 let i32_ptr = self
3387 .builder
3388 .build_pointer_cast(
3389 var_data_ptr,
3390 self.context.ptr_type(AddressSpace::default()),
3391 "errno_ptr",
3392 )
3393 .map_err(|e| {
3394 CodeGenError::LLVMError(format!("Failed to cast errno ptr: {e}"))
3395 })?;
3396 self.builder.build_store(i32_ptr, ret).map_err(|e| {
3397 CodeGenError::LLVMError(format!("Failed to store errno: {e}"))
3398 })?;
3399 let addr_ptr_i8 = unsafe {
3401 self.builder
3402 .build_gep(
3403 self.context.i8_type(),
3404 var_data_ptr,
3405 &[i32_type.const_int(4, false)],
3406 "addr_ptr_i8",
3407 )
3408 .map_err(|e| {
3409 CodeGenError::LLVMError(format!("Failed to get addr gep: {e}"))
3410 })?
3411 };
3412 let addr_ptr = self
3413 .builder
3414 .build_pointer_cast(
3415 addr_ptr_i8,
3416 self.context.ptr_type(AddressSpace::default()),
3417 "addr_ptr",
3418 )
3419 .map_err(|e| {
3420 CodeGenError::LLVMError(format!("Failed to cast addr ptr: {e}"))
3421 })?;
3422 let src_as_i64 = src_addr;
3423 self.builder
3424 .build_store(addr_ptr, src_as_i64)
3425 .map_err(|e| {
3426 CodeGenError::LLVMError(format!("Failed to store addr: {e}"))
3427 })?;
3428 self.mark_any_fail()?;
3429 self.builder
3430 .build_unconditional_branch(cont2_block)
3431 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3432
3433 self.builder.position_at_end(ok_block);
3435 if a.data_len < dwarf_type.size() as usize {
3436 self.builder
3437 .build_store(
3438 apl_ptr,
3439 self.context
3440 .i8_type()
3441 .const_int(VariableStatus::Truncated as u64, false),
3442 )
3443 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3444 self.mark_any_success()?;
3445 self.mark_any_fail()?;
3446 } else {
3447 self.mark_any_success()?;
3448 }
3449 self.builder
3450 .build_unconditional_branch(cont2_block)
3451 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3452
3453 self.builder.position_at_end(cont2_block);
3454 }
3455 ComplexArgSource::AddressValue {
3456 eval_result,
3457 module_for_offsets,
3458 } => {
3459 let addr = self.evaluation_result_to_address_with_hint(
3461 eval_result,
3462 Some(apl_ptr),
3463 module_for_offsets.as_deref(),
3464 )?;
3465 let cast_ptr = self
3466 .builder
3467 .build_pointer_cast(
3468 var_data_ptr,
3469 self.context.ptr_type(AddressSpace::default()),
3470 "addr_store_ptr",
3471 )
3472 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3473 self.builder
3474 .build_store(cast_ptr, addr)
3475 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3476 }
3478 }
3479 offset += 2 + 2 + 1 + 1 + a.access_path.len() + 2 + reserved_len;
3481 }
3482
3483 Ok(())
3485 }
3486
3487 pub fn generate_print_string_index(&mut self, string_index: u16) -> Result<()> {
3489 info!(
3490 "Generating PrintStringIndex instruction: index={}",
3491 string_index
3492 );
3493
3494 let inst_buffer = self.reserve_instruction_region(
3497 (std::mem::size_of::<InstructionHeader>() + std::mem::size_of::<PrintStringIndexData>())
3498 as u64,
3499 );
3500
3501 let _inst_size = self.context.i64_type().const_int(
3503 (std::mem::size_of::<PrintStringIndexData>()
3504 + std::mem::size_of::<ghostscope_protocol::trace_event::InstructionHeader>())
3505 as u64,
3506 false,
3507 );
3508 let inst_type_ptr = unsafe {
3513 self.builder
3514 .build_gep(
3515 self.context.i8_type(),
3516 inst_buffer,
3517 &[self.context.i32_type().const_int(
3518 std::mem::offset_of!(InstructionHeader, inst_type) as u64,
3519 false,
3520 )],
3521 "inst_type_ptr",
3522 )
3523 .map_err(|e| CodeGenError::LLVMError(format!("Failed to get inst_type GEP: {e}")))?
3524 };
3525 let inst_type_val = self
3526 .context
3527 .i8_type()
3528 .const_int(InstructionType::PrintStringIndex as u64, false);
3529 self.builder
3530 .build_store(inst_type_ptr, inst_type_val)
3531 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store inst_type: {e}")))?;
3532
3533 let data_length_ptr = unsafe {
3534 self.builder
3535 .build_gep(
3536 self.context.i8_type(),
3537 inst_buffer,
3538 &[self.context.i32_type().const_int(
3539 std::mem::offset_of!(InstructionHeader, data_length) as u64,
3540 false,
3541 )],
3542 "data_length_ptr",
3543 )
3544 .map_err(|e| {
3545 CodeGenError::LLVMError(format!("Failed to get data_length GEP: {e}"))
3546 })?
3547 };
3548 let data_length_i16_ptr = self
3549 .builder
3550 .build_pointer_cast(
3551 data_length_ptr,
3552 self.context.ptr_type(AddressSpace::default()),
3553 "data_length_i16_ptr",
3554 )
3555 .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast data_length ptr: {e}")))?;
3556 let data_length_val = self
3557 .context
3558 .i16_type()
3559 .const_int(std::mem::size_of::<PrintStringIndexData>() as u64, false);
3560 self.builder
3561 .build_store(data_length_i16_ptr, data_length_val)
3562 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store data_length: {e}")))?;
3563
3564 let string_index_ptr = unsafe {
3566 self.builder
3567 .build_gep(
3568 self.context.i8_type(),
3569 inst_buffer,
3570 &[self
3571 .context
3572 .i32_type()
3573 .const_int(std::mem::size_of::<InstructionHeader>() as u64, false)],
3574 "string_index_ptr",
3575 )
3576 .map_err(|e| {
3577 CodeGenError::LLVMError(format!("Failed to get string_index GEP: {e}"))
3578 })?
3579 };
3580 let string_index_i16_ptr = self
3581 .builder
3582 .build_pointer_cast(
3583 string_index_ptr,
3584 self.context.ptr_type(AddressSpace::default()),
3585 "string_index_i16_ptr",
3586 )
3587 .map_err(|e| {
3588 CodeGenError::LLVMError(format!("Failed to cast string_index ptr: {e}"))
3589 })?;
3590 let string_index_val = self
3591 .context
3592 .i16_type()
3593 .const_int(string_index as u64, false);
3594 self.builder
3595 .build_store(string_index_i16_ptr, string_index_val)
3596 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store string_index: {e}")))?;
3597
3598 Ok(())
3600 }
3601
3602 pub fn generate_expr_error(
3604 &mut self,
3605 expr_string_index: u16,
3606 error_code_iv: inkwell::values::IntValue<'ctx>,
3607 flags_iv: inkwell::values::IntValue<'ctx>,
3608 failing_addr_iv: inkwell::values::IntValue<'ctx>,
3609 ) -> Result<()> {
3610 let inst_buffer = self.reserve_instruction_region(
3612 (std::mem::size_of::<InstructionHeader>()
3613 + std::mem::size_of::<ghostscope_protocol::trace_event::ExprErrorData>())
3614 as u64,
3615 );
3616
3617 let inst_type_val = self
3619 .context
3620 .i8_type()
3621 .const_int(InstructionType::ExprError as u64, false);
3622 self.builder
3623 .build_store(inst_buffer, inst_type_val)
3624 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store inst_type: {e}")))?;
3625
3626 let data_length_ptr = unsafe {
3628 self.builder
3629 .build_gep(
3630 self.context.i8_type(),
3631 inst_buffer,
3632 &[self.context.i32_type().const_int(
3633 std::mem::offset_of!(InstructionHeader, data_length) as u64,
3634 false,
3635 )],
3636 "exprerr_data_length_ptr",
3637 )
3638 .map_err(|e| {
3639 CodeGenError::LLVMError(format!("Failed to get data_length GEP: {e}"))
3640 })?
3641 };
3642 let data_length_i16_ptr = self
3643 .builder
3644 .build_pointer_cast(
3645 data_length_ptr,
3646 self.context.ptr_type(AddressSpace::default()),
3647 "exprerr_data_length_i16_ptr",
3648 )
3649 .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast data_length ptr: {e}")))?;
3650 let data_length_val = self.context.i16_type().const_int(
3651 std::mem::size_of::<ghostscope_protocol::trace_event::ExprErrorData>() as u64,
3652 false,
3653 );
3654 self.builder
3655 .build_store(data_length_i16_ptr, data_length_val)
3656 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store data_length: {e}")))?;
3657
3658 let si_ptr = unsafe {
3661 self.builder
3662 .build_gep(
3663 self.context.i8_type(),
3664 inst_buffer,
3665 &[self
3666 .context
3667 .i32_type()
3668 .const_int(std::mem::size_of::<InstructionHeader>() as u64, false)],
3669 "exprerr_si_ptr",
3670 )
3671 .map_err(|e| {
3672 CodeGenError::LLVMError(format!("Failed to get string_index GEP: {e}"))
3673 })?
3674 };
3675 let si_i16_ptr = self
3676 .builder
3677 .build_pointer_cast(
3678 si_ptr,
3679 self.context.ptr_type(AddressSpace::default()),
3680 "exprerr_si_i16_ptr",
3681 )
3682 .map_err(|e| {
3683 CodeGenError::LLVMError(format!("Failed to cast string_index ptr: {e}"))
3684 })?;
3685 let si_val = self
3686 .context
3687 .i16_type()
3688 .const_int(expr_string_index as u64, false);
3689 self.builder
3690 .build_store(si_i16_ptr, si_val)
3691 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store string_index: {e}")))?;
3692
3693 let ec_ptr = unsafe {
3695 self.builder
3696 .build_gep(
3697 self.context.i8_type(),
3698 inst_buffer,
3699 &[self
3700 .context
3701 .i32_type()
3702 .const_int((std::mem::size_of::<InstructionHeader>() + 2) as u64, false)],
3703 "exprerr_ec_ptr",
3704 )
3705 .map_err(|e| {
3706 CodeGenError::LLVMError(format!("Failed to get error_code GEP: {e}"))
3707 })?
3708 };
3709 let ec_i8 = if error_code_iv.get_type().get_bit_width() == 8 {
3711 error_code_iv
3712 } else if error_code_iv.get_type().get_bit_width() > 8 {
3713 self.builder
3714 .build_int_truncate(error_code_iv, self.context.i8_type(), "ec_trunc")
3715 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
3716 } else {
3717 self.builder
3718 .build_int_z_extend(error_code_iv, self.context.i8_type(), "ec_zext")
3719 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
3720 };
3721 self.builder
3722 .build_store(ec_ptr, ec_i8)
3723 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store error_code: {e}")))?;
3724 let fl_ptr = unsafe {
3725 self.builder
3726 .build_gep(
3727 self.context.i8_type(),
3728 inst_buffer,
3729 &[self
3730 .context
3731 .i32_type()
3732 .const_int((std::mem::size_of::<InstructionHeader>() + 3) as u64, false)],
3733 "exprerr_flags_ptr",
3734 )
3735 .map_err(|e| CodeGenError::LLVMError(format!("Failed to get flags GEP: {e}")))?
3736 };
3737 let fl_i8 = if flags_iv.get_type().get_bit_width() == 8 {
3739 flags_iv
3740 } else if flags_iv.get_type().get_bit_width() > 8 {
3741 self.builder
3742 .build_int_truncate(flags_iv, self.context.i8_type(), "fl_trunc")
3743 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
3744 } else {
3745 self.builder
3746 .build_int_z_extend(flags_iv, self.context.i8_type(), "fl_zext")
3747 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
3748 };
3749 self.builder
3750 .build_store(fl_ptr, fl_i8)
3751 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store flags: {e}")))?;
3752
3753 let addr_ptr = unsafe {
3755 self.builder
3756 .build_gep(
3757 self.context.i8_type(),
3758 inst_buffer,
3759 &[self
3760 .context
3761 .i32_type()
3762 .const_int((std::mem::size_of::<InstructionHeader>() + 4) as u64, false)],
3763 "exprerr_addr_ptr",
3764 )
3765 .map_err(|e| CodeGenError::LLVMError(format!("Failed to get addr GEP: {e}")))?
3766 };
3767 let addr_i64 = if failing_addr_iv.get_type().get_bit_width() == 64 {
3768 failing_addr_iv
3769 } else if failing_addr_iv.get_type().get_bit_width() > 64 {
3770 self.builder
3771 .build_int_truncate(failing_addr_iv, self.context.i64_type(), "addr_trunc")
3772 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
3773 } else {
3774 self.builder
3775 .build_int_z_extend(failing_addr_iv, self.context.i64_type(), "addr_zext")
3776 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?
3777 };
3778 let addr_ptr_cast = self
3779 .builder
3780 .build_pointer_cast(
3781 addr_ptr,
3782 self.context.ptr_type(AddressSpace::default()),
3783 "exprerr_addr_i64_ptr",
3784 )
3785 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
3786 self.builder
3787 .build_store(addr_ptr_cast, addr_i64)
3788 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store failing_addr: {e}")))?;
3789
3790 Ok(())
3792 }
3793
3794 pub fn generate_print_variable_index(
3796 &mut self,
3797 var_name_index: u16,
3798 type_encoding: TypeKind,
3799 var_name: &str,
3800 ) -> Result<()> {
3801 info!(
3802 "Generating PrintVariableIndex instruction: var_name_index={}, type={:?}, var_name={}",
3803 var_name_index, type_encoding, var_name
3804 );
3805
3806 let type_index = match self.query_dwarf_for_variable(var_name)? {
3808 Some(var) => match var.dwarf_type {
3809 Some(ref t) => self.trace_context.add_type(t.clone()),
3810 None => self.add_synthesized_type_index_for_kind(type_encoding),
3811 },
3812 None => {
3813 self.add_synthesized_type_index_for_kind(type_encoding)
3815 }
3816 };
3817
3818 self.generate_successful_variable_instruction(
3819 var_name_index,
3820 type_encoding,
3821 type_index,
3822 var_name,
3823 )
3824 }
3825
3826 fn generate_successful_variable_instruction(
3828 &mut self,
3829 var_name_index: u16,
3830 type_encoding: TypeKind,
3831 type_index: u16,
3832 var_name: &str,
3833 ) -> Result<()> {
3834 let data_size = match type_encoding {
3836 TypeKind::U8 | TypeKind::I8 | TypeKind::Bool | TypeKind::Char => 1,
3837 TypeKind::U16 | TypeKind::I16 => 2,
3838 TypeKind::U32 | TypeKind::I32 | TypeKind::F32 => 4,
3839 TypeKind::U64 | TypeKind::I64 | TypeKind::F64 | TypeKind::Pointer => 8,
3840 _ => 8, };
3842
3843 let inst_buffer = self.reserve_instruction_region(
3845 (std::mem::size_of::<InstructionHeader>()
3846 + std::mem::size_of::<PrintVariableIndexData>()
3847 + data_size as usize) as u64,
3848 );
3849
3850 let inst_type_val = self
3854 .context
3855 .i8_type()
3856 .const_int(InstructionType::PrintVariableIndex as u64, false);
3857 self.builder
3858 .build_store(inst_buffer, inst_type_val)
3859 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store inst_type: {e}")))?;
3860
3861 let data_length_ptr = unsafe {
3863 self.builder
3864 .build_gep(
3865 self.context.i8_type(),
3866 inst_buffer,
3867 &[self.context.i32_type().const_int(
3868 std::mem::offset_of!(InstructionHeader, data_length) as u64,
3869 false,
3870 )],
3871 "data_length_ptr",
3872 )
3873 .map_err(|e| {
3874 CodeGenError::LLVMError(format!("Failed to get data_length GEP: {e}"))
3875 })?
3876 };
3877 let data_length_i16_ptr = self
3878 .builder
3879 .build_pointer_cast(
3880 data_length_ptr,
3881 self.context.ptr_type(AddressSpace::default()),
3882 "data_length_i16_ptr",
3883 )
3884 .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast data_length ptr: {e}")))?;
3885 let total_data_length = std::mem::size_of::<PrintVariableIndexData>() + data_size as usize;
3886 let data_length_val = self
3887 .context
3888 .i16_type()
3889 .const_int(total_data_length as u64, false);
3890 self.builder
3891 .build_store(data_length_i16_ptr, data_length_val)
3892 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store data_length: {e}")))?;
3893
3894 let variable_data_start = unsafe {
3896 self.builder
3897 .build_gep(
3898 self.context.i8_type(),
3899 inst_buffer,
3900 &[self
3901 .context
3902 .i32_type()
3903 .const_int(std::mem::size_of::<InstructionHeader>() as u64, false)],
3904 "variable_data_start",
3905 )
3906 .map_err(|e| {
3907 CodeGenError::LLVMError(format!("Failed to get variable_data_start GEP: {e}"))
3908 })?
3909 };
3910
3911 let var_name_index_ptr = unsafe {
3913 self.builder
3914 .build_gep(
3915 self.context.i8_type(),
3916 variable_data_start,
3917 &[self.context.i32_type().const_int(
3918 std::mem::offset_of!(PrintVariableIndexData, var_name_index) as u64,
3919 false,
3920 )],
3921 "var_name_index_ptr",
3922 )
3923 .map_err(|e| {
3924 CodeGenError::LLVMError(format!("Failed to get var_name_index GEP: {e}"))
3925 })?
3926 };
3927 let var_name_index_i16_ptr = self
3928 .builder
3929 .build_pointer_cast(
3930 var_name_index_ptr,
3931 self.context.ptr_type(AddressSpace::default()),
3932 "var_name_index_i16_ptr",
3933 )
3934 .map_err(|e| {
3935 CodeGenError::LLVMError(format!("Failed to cast var_name_index ptr: {e}"))
3936 })?;
3937 let var_name_index_val = self
3938 .context
3939 .i16_type()
3940 .const_int(var_name_index as u64, false);
3941 self.builder
3942 .build_store(var_name_index_i16_ptr, var_name_index_val)
3943 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store var_name_index: {e}")))?;
3944
3945 let type_encoding_ptr = unsafe {
3947 self.builder
3948 .build_gep(
3949 self.context.i8_type(),
3950 variable_data_start,
3951 &[self.context.i32_type().const_int(
3952 std::mem::offset_of!(PrintVariableIndexData, type_encoding) as u64,
3953 false,
3954 )],
3955 "type_encoding_ptr",
3956 )
3957 .map_err(|e| {
3958 CodeGenError::LLVMError(format!("Failed to get type_encoding GEP: {e}"))
3959 })?
3960 };
3961 let type_encoding_val = self
3962 .context
3963 .i8_type()
3964 .const_int(type_encoding as u8 as u64, false);
3965 self.builder
3966 .build_store(type_encoding_ptr, type_encoding_val)
3967 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store type_encoding: {e}")))?;
3968
3969 let data_len_ptr = unsafe {
3971 self.builder
3972 .build_gep(
3973 self.context.i8_type(),
3974 variable_data_start,
3975 &[self.context.i32_type().const_int(
3976 std::mem::offset_of!(PrintVariableIndexData, data_len) as u64,
3977 false,
3978 )],
3979 "data_len_ptr",
3980 )
3981 .map_err(|e| CodeGenError::LLVMError(format!("Failed to get data_len GEP: {e}")))?
3982 };
3983 let data_len_i16_ptr = self
3984 .builder
3985 .build_pointer_cast(
3986 data_len_ptr,
3987 self.context.ptr_type(AddressSpace::default()),
3988 "data_len_i16_ptr",
3989 )
3990 .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast data_len ptr: {e}")))?;
3991 let data_len_val = self.context.i16_type().const_int(data_size as u64, false); self.builder
3993 .build_store(data_len_i16_ptr, data_len_val)
3994 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store data_len: {e}")))?;
3995
3996 let type_index_ptr = unsafe {
3998 self.builder
3999 .build_gep(
4000 self.context.i8_type(),
4001 variable_data_start,
4002 &[self.context.i32_type().const_int(
4003 std::mem::offset_of!(PrintVariableIndexData, type_index) as u64,
4004 false,
4005 )],
4006 "type_index_ptr",
4007 )
4008 .map_err(|e| {
4009 CodeGenError::LLVMError(format!("Failed to get type_index GEP: {e}"))
4010 })?
4011 };
4012 let type_index_i16_ptr = self
4013 .builder
4014 .build_pointer_cast(
4015 type_index_ptr,
4016 self.context.ptr_type(AddressSpace::default()),
4017 "type_index_i16_ptr",
4018 )
4019 .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast type_index ptr: {e}")))?;
4020 let type_index_val = self.context.i16_type().const_int(type_index as u64, false);
4021 self.builder
4022 .build_store(type_index_i16_ptr, type_index_val)
4023 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store type_index: {e}")))?;
4024
4025 let status_ptr = unsafe {
4027 self.builder
4028 .build_gep(
4029 self.context.i8_type(),
4030 variable_data_start,
4031 &[self.context.i32_type().const_int(
4032 std::mem::offset_of!(PrintVariableIndexData, status) as u64,
4033 false,
4034 )],
4035 "status_ptr",
4036 )
4037 .map_err(|e| CodeGenError::LLVMError(format!("Failed to get status GEP: {e}")))?
4038 };
4039 let status_val = self
4040 .context
4041 .i8_type()
4042 .const_int(VariableStatus::Ok as u64, false);
4043 self.builder
4044 .build_store(status_ptr, status_val)
4045 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store status: {e}")))?;
4046
4047 let var_data = self.resolve_variable_value(var_name, type_encoding, Some(status_ptr))?;
4048
4049 let var_data_ptr = unsafe {
4051 self.builder
4052 .build_gep(
4053 self.context.i8_type(),
4054 variable_data_start,
4055 &[self
4056 .context
4057 .i32_type()
4058 .const_int(std::mem::size_of::<PrintVariableIndexData>() as u64, false)],
4059 "var_data_ptr",
4060 )
4061 .map_err(|e| CodeGenError::LLVMError(format!("Failed to get var_data GEP: {e}")))?
4062 };
4063
4064 match data_size {
4067 1 => {
4068 let truncated = match var_data {
4070 BasicValueEnum::IntValue(int_val) => self
4071 .builder
4072 .build_int_truncate(int_val, self.context.i8_type(), "truncated_i8")
4073 .map_err(|e| {
4074 CodeGenError::LLVMError(format!("Failed to truncate to i8: {e}"))
4075 })?,
4076 _ => {
4077 return Err(CodeGenError::LLVMError(
4078 "Expected integer value for integer type".to_string(),
4079 ));
4080 }
4081 };
4082 self.builder
4083 .build_store(var_data_ptr, truncated)
4084 .map_err(|e| {
4085 CodeGenError::LLVMError(format!("Failed to store i8 data: {e}"))
4086 })?;
4087 }
4088 2 => {
4089 let truncated = match var_data {
4091 BasicValueEnum::IntValue(int_val) => self
4092 .builder
4093 .build_int_truncate(int_val, self.context.i16_type(), "truncated_i16")
4094 .map_err(|e| {
4095 CodeGenError::LLVMError(format!("Failed to truncate to i16: {e}"))
4096 })?,
4097 _ => {
4098 return Err(CodeGenError::LLVMError(
4099 "Expected integer value for integer type".to_string(),
4100 ));
4101 }
4102 };
4103 let i16_ptr = self
4104 .builder
4105 .build_pointer_cast(
4106 var_data_ptr,
4107 self.context.ptr_type(AddressSpace::default()),
4108 "i16_ptr",
4109 )
4110 .map_err(|e| {
4111 CodeGenError::LLVMError(format!("Failed to cast to i16 ptr: {e}"))
4112 })?;
4113 self.builder.build_store(i16_ptr, truncated).map_err(|e| {
4114 CodeGenError::LLVMError(format!("Failed to store i16 data: {e}"))
4115 })?;
4116 }
4117 4 => {
4118 match var_data {
4120 BasicValueEnum::IntValue(int_val) => {
4121 let truncated = self
4122 .builder
4123 .build_int_truncate(int_val, self.context.i32_type(), "truncated_i32")
4124 .map_err(|e| {
4125 CodeGenError::LLVMError(format!("Failed to truncate to i32: {e}"))
4126 })?;
4127 let i32_ptr = self
4128 .builder
4129 .build_pointer_cast(
4130 var_data_ptr,
4131 self.context.ptr_type(AddressSpace::default()),
4132 "i32_ptr",
4133 )
4134 .map_err(|e| {
4135 CodeGenError::LLVMError(format!("Failed to cast to i32 ptr: {e}"))
4136 })?;
4137 self.builder.build_store(i32_ptr, truncated).map_err(|e| {
4138 CodeGenError::LLVMError(format!("Failed to store i32 data: {e}"))
4139 })?;
4140 }
4141 BasicValueEnum::FloatValue(float_val) => {
4142 let f32_ptr = self
4143 .builder
4144 .build_pointer_cast(
4145 var_data_ptr,
4146 self.context.ptr_type(AddressSpace::default()),
4147 "f32_ptr",
4148 )
4149 .map_err(|e| {
4150 CodeGenError::LLVMError(format!("Failed to cast to f32 ptr: {e}"))
4151 })?;
4152 self.builder.build_store(f32_ptr, float_val).map_err(|e| {
4153 CodeGenError::LLVMError(format!("Failed to store f32 data: {e}"))
4154 })?;
4155 }
4156 _ => {
4157 return Err(CodeGenError::LLVMError(
4158 "Expected integer or float value for 4-byte type".to_string(),
4159 ));
4160 }
4161 }
4162 }
4163 8 => {
4164 match var_data {
4166 BasicValueEnum::IntValue(int_val) => {
4167 let i64_ptr = self
4168 .builder
4169 .build_pointer_cast(
4170 var_data_ptr,
4171 self.context.ptr_type(AddressSpace::default()),
4172 "i64_ptr",
4173 )
4174 .map_err(|e| {
4175 CodeGenError::LLVMError(format!("Failed to cast to i64 ptr: {e}"))
4176 })?;
4177 self.builder.build_store(i64_ptr, int_val).map_err(|e| {
4178 CodeGenError::LLVMError(format!("Failed to store i64 data: {e}"))
4179 })?;
4180 }
4181 BasicValueEnum::FloatValue(float_val) => {
4182 let f64_ptr = self
4183 .builder
4184 .build_pointer_cast(
4185 var_data_ptr,
4186 self.context.ptr_type(AddressSpace::default()),
4187 "f64_ptr",
4188 )
4189 .map_err(|e| {
4190 CodeGenError::LLVMError(format!("Failed to cast to f64 ptr: {e}"))
4191 })?;
4192 self.builder.build_store(f64_ptr, float_val).map_err(|e| {
4193 CodeGenError::LLVMError(format!("Failed to store f64 data: {e}"))
4194 })?;
4195 }
4196 BasicValueEnum::PointerValue(ptr_val) => {
4197 let ptr_int = self
4199 .builder
4200 .build_ptr_to_int(ptr_val, self.context.i64_type(), "ptr_as_int")
4201 .map_err(|e| {
4202 CodeGenError::LLVMError(format!(
4203 "Failed to convert ptr to int: {e}"
4204 ))
4205 })?;
4206 let i64_ptr = self
4207 .builder
4208 .build_pointer_cast(
4209 var_data_ptr,
4210 self.context.ptr_type(AddressSpace::default()),
4211 "i64_ptr",
4212 )
4213 .map_err(|e| {
4214 CodeGenError::LLVMError(format!("Failed to cast to i64 ptr: {e}"))
4215 })?;
4216 self.builder.build_store(i64_ptr, ptr_int).map_err(|e| {
4217 CodeGenError::LLVMError(format!("Failed to store pointer data: {e}"))
4218 })?;
4219 }
4220 _ => {
4221 return Err(CodeGenError::LLVMError(
4222 "Expected integer, float, or pointer value for 8-byte type".to_string(),
4223 ));
4224 }
4225 }
4226 }
4227 _ => {
4228 return Err(CodeGenError::LLVMError(format!(
4229 "Unsupported data size: {data_size}"
4230 )));
4231 }
4232 }
4233
4234 Ok(())
4236 }
4237
4238 pub fn generate_backtrace_instruction(&mut self, depth: u8) -> Result<()> {
4243 info!("Generating Backtrace instruction: depth={}", depth);
4244
4245 let inst_buffer = self.reserve_instruction_region(
4247 (std::mem::size_of::<InstructionHeader>() + std::mem::size_of::<BacktraceData>())
4248 as u64,
4249 );
4250
4251 let inst_type_ptr = unsafe {
4253 self.builder
4254 .build_gep(
4255 self.context.i8_type(),
4256 inst_buffer,
4257 &[self.context.i32_type().const_int(
4258 std::mem::offset_of!(InstructionHeader, inst_type) as u64,
4259 false,
4260 )],
4261 "bt_inst_type_ptr",
4262 )
4263 .map_err(|e| CodeGenError::LLVMError(format!("Failed to get inst_type GEP: {e}")))?
4264 };
4265 let inst_type_val = self
4266 .context
4267 .i8_type()
4268 .const_int(InstructionType::Backtrace as u64, false);
4269 self.builder
4270 .build_store(inst_type_ptr, inst_type_val)
4271 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store inst_type: {e}")))?;
4272
4273 let data_length_ptr = unsafe {
4275 self.builder
4276 .build_gep(
4277 self.context.i8_type(),
4278 inst_buffer,
4279 &[self.context.i32_type().const_int(
4280 std::mem::offset_of!(InstructionHeader, data_length) as u64,
4281 false,
4282 )],
4283 "bt_data_length_ptr",
4284 )
4285 .map_err(|e| {
4286 CodeGenError::LLVMError(format!("Failed to get data_length GEP: {e}"))
4287 })?
4288 };
4289 let data_length_i16_ptr = self
4290 .builder
4291 .build_pointer_cast(
4292 data_length_ptr,
4293 self.context.ptr_type(AddressSpace::default()),
4294 "bt_data_length_i16_ptr",
4295 )
4296 .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast data_length ptr: {e}")))?;
4297 let dl_val = self
4298 .context
4299 .i16_type()
4300 .const_int(std::mem::size_of::<BacktraceData>() as u64, false);
4301 self.builder
4302 .build_store(data_length_i16_ptr, dl_val)
4303 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store data_length: {e}")))?;
4304
4305 Ok(())
4307 }
4308
4309 fn resolve_variable_value(
4311 &mut self,
4312 var_name: &str,
4313 type_encoding: TypeKind,
4314 status_ptr: Option<inkwell::values::PointerValue<'ctx>>,
4315 ) -> Result<BasicValueEnum<'ctx>> {
4316 info!(
4317 "Resolving variable value: {} ({:?})",
4318 var_name, type_encoding
4319 );
4320
4321 if self.variable_exists(var_name) {
4323 info!("Found script variable for '{}', loading value", var_name);
4324 return self.load_variable(var_name);
4325 }
4326
4327 match self.query_dwarf_for_variable(var_name)? {
4329 Some(var_info) => {
4330 info!(
4331 "Found DWARF variable: {} = {:?}",
4332 var_name, var_info.evaluation_result
4333 );
4334
4335 let dwarf_type = var_info.dwarf_type.as_ref().ok_or_else(|| {
4337 CodeGenError::DwarfError(format!(
4338 "Variable '{var_name}' has no type information in DWARF"
4339 ))
4340 })?;
4341
4342 let compile_context = self.get_compile_time_context()?;
4343 self.evaluate_result_to_llvm_value(
4344 &var_info.evaluation_result,
4345 dwarf_type,
4346 var_name,
4347 compile_context.pc_address,
4348 status_ptr,
4349 )
4350 }
4351 None => {
4352 let compile_context = self.get_compile_time_context()?;
4353 warn!(
4354 "Variable '{}' not found in DWARF at address 0x{:x}",
4355 var_name, compile_context.pc_address
4356 );
4357 Err(CodeGenError::VariableNotFound(var_name.to_string()))
4358 }
4359 }
4360 }
4361
4362 fn generate_print_complex_variable_runtime(
4364 &mut self,
4365 meta: PrintVarRuntimeMeta,
4366 eval_result: &ghostscope_dwarf::EvaluationResult,
4367 dwarf_type: &ghostscope_dwarf::TypeInfo,
4368 module_hint: Option<&str>,
4369 ) -> Result<()> {
4370 tracing::trace!(
4371 var_name_index = meta.var_name_index,
4372 type_index = meta.type_index,
4373 access_path = %meta.access_path,
4374 type_size = dwarf_type.size(),
4375 data_len_limit = meta.data_len_limit,
4376 eval = ?eval_result,
4377 "generate_print_complex_variable_runtime: begin"
4378 );
4379 let access_path_bytes = meta.access_path.as_bytes();
4383 let access_path_len = std::cmp::min(access_path_bytes.len(), 255); let type_size = dwarf_type.size() as usize;
4385 let mut data_len = std::cmp::min(type_size, meta.data_len_limit);
4386 if data_len > u16::MAX as usize {
4387 data_len = u16::MAX as usize;
4388 }
4389
4390 let header_size = std::mem::size_of::<InstructionHeader>();
4391 let data_struct_size = std::mem::size_of::<PrintComplexVariableData>();
4392 let reserved_payload = std::cmp::max(data_len, 12);
4394 let total_data_length = data_struct_size + access_path_len + reserved_payload;
4395 let total_size = header_size + total_data_length;
4396 tracing::trace!(
4397 header_size,
4398 data_struct_size,
4399 access_path_len,
4400 data_len,
4401 total_data_length,
4402 total_size,
4403 "generate_print_complex_variable_runtime: sizes computed"
4404 );
4405
4406 let inst_buffer = self.reserve_instruction_region(total_size as u64);
4408
4409 let inst_type_val = self
4413 .context
4414 .i8_type()
4415 .const_int(InstructionType::PrintComplexVariable as u64, false);
4416 self.builder
4417 .build_store(inst_buffer, inst_type_val)
4418 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store inst_type: {e}")))?;
4419 tracing::trace!(
4420 "generate_print_complex_variable_runtime: wrote inst_type=PrintComplexVariable"
4421 );
4422
4423 let data_length_ptr = unsafe {
4426 self.builder
4427 .build_gep(
4428 self.context.i8_type(),
4429 inst_buffer,
4430 &[self.context.i32_type().const_int(1, false)],
4431 "data_length_ptr",
4432 )
4433 .map_err(|e| {
4434 CodeGenError::LLVMError(format!("Failed to get data_length GEP: {e}"))
4435 })?
4436 };
4437 let data_length_ptr_cast = self
4438 .builder
4439 .build_pointer_cast(
4440 data_length_ptr,
4441 self.context.ptr_type(AddressSpace::default()),
4442 "data_length_ptr_cast",
4443 )
4444 .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast data_length ptr: {e}")))?;
4445 self.builder
4446 .build_store(
4447 data_length_ptr_cast,
4448 self.context
4449 .i16_type()
4450 .const_int(total_data_length as u64, false),
4451 )
4452 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store data_length: {e}")))?;
4453 tracing::trace!(
4454 data_length = total_data_length,
4455 "generate_print_complex_variable_runtime: wrote data_length"
4456 );
4457
4458 let data_ptr = unsafe {
4460 self.builder
4461 .build_gep(
4462 self.context.i8_type(),
4463 inst_buffer,
4464 &[self.context.i32_type().const_int(header_size as u64, false)],
4465 "data_ptr",
4466 )
4467 .map_err(|e| CodeGenError::LLVMError(format!("Failed to get data GEP: {e}")))?
4468 };
4469
4470 let var_name_index_val = self
4472 .context
4473 .i16_type()
4474 .const_int(meta.var_name_index as u64, false);
4475 let var_name_index_off =
4477 std::mem::offset_of!(PrintComplexVariableData, var_name_index) as u64;
4478 let var_name_index_ptr_i8 = unsafe {
4479 self.builder
4480 .build_gep(
4481 self.context.i8_type(),
4482 data_ptr,
4483 &[self.context.i32_type().const_int(var_name_index_off, false)],
4484 "var_name_index_ptr_i8",
4485 )
4486 .map_err(|e| {
4487 CodeGenError::LLVMError(format!("Failed to get var_name_index GEP: {e}"))
4488 })?
4489 };
4490 let var_name_index_ptr_i16 = self
4491 .builder
4492 .build_pointer_cast(
4493 var_name_index_ptr_i8,
4494 self.context.ptr_type(AddressSpace::default()),
4495 "var_name_index_ptr_i16",
4496 )
4497 .map_err(|e| {
4498 CodeGenError::LLVMError(format!("Failed to cast var_name_index ptr: {e}"))
4499 })?;
4500 self.builder
4501 .build_store(var_name_index_ptr_i16, var_name_index_val)
4502 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store var_name_index: {e}")))?;
4503 tracing::trace!(
4504 var_name_index = meta.var_name_index,
4505 "generate_print_complex_variable_runtime: wrote var_name_index"
4506 );
4507
4508 let type_index_offset = std::mem::offset_of!(PrintComplexVariableData, type_index) as u64;
4511 let type_index_ptr_i8 = unsafe {
4512 self.builder
4513 .build_gep(
4514 self.context.i8_type(),
4515 data_ptr,
4516 &[self.context.i32_type().const_int(type_index_offset, false)],
4517 "type_index_ptr_i8",
4518 )
4519 .map_err(|e| {
4520 CodeGenError::LLVMError(format!("Failed to get type_index GEP: {e}"))
4521 })?
4522 };
4523 let type_index_ptr = self
4524 .builder
4525 .build_pointer_cast(
4526 type_index_ptr_i8,
4527 self.context.ptr_type(AddressSpace::default()),
4528 "type_index_ptr_i16",
4529 )
4530 .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast type_index ptr: {e}")))?;
4531 let type_index_val = self
4532 .context
4533 .i16_type()
4534 .const_int(meta.type_index as u64, false);
4535 self.builder
4536 .build_store(type_index_ptr, type_index_val)
4537 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store type_index: {e}")))?;
4538 tracing::trace!(
4539 type_index = meta.type_index,
4540 "generate_print_complex_variable_runtime: wrote type_index"
4541 );
4542
4543 let access_path_len_off =
4546 std::mem::offset_of!(PrintComplexVariableData, access_path_len) as u64;
4547 let access_path_len_ptr = unsafe {
4548 self.builder
4549 .build_gep(
4550 self.context.i8_type(),
4551 data_ptr,
4552 &[self
4553 .context
4554 .i32_type()
4555 .const_int(access_path_len_off, false)],
4556 "access_path_len_ptr",
4557 )
4558 .map_err(|e| {
4559 CodeGenError::LLVMError(format!("Failed to get access_path_len GEP: {e}"))
4560 })?
4561 };
4562 self.builder
4563 .build_store(
4564 access_path_len_ptr,
4565 self.context
4566 .i8_type()
4567 .const_int(access_path_len as u64, false),
4568 )
4569 .map_err(|e| {
4570 CodeGenError::LLVMError(format!("Failed to store access_path_len: {e}"))
4571 })?;
4572 tracing::trace!(
4573 access_path_len,
4574 "generate_print_complex_variable_runtime: wrote access_path_len"
4575 );
4576
4577 let status_off = std::mem::offset_of!(PrintComplexVariableData, status) as u64;
4579 let status_ptr = unsafe {
4580 self.builder
4581 .build_gep(
4582 self.context.i8_type(),
4583 data_ptr,
4584 &[self.context.i32_type().const_int(status_off, false)],
4585 "status_ptr",
4586 )
4587 .map_err(|e| CodeGenError::LLVMError(format!("Failed to get status GEP: {e}")))?
4588 };
4589 self.builder
4590 .build_store(
4591 status_ptr,
4592 self.context
4593 .i8_type()
4594 .const_int(VariableStatus::Ok as u64, false),
4595 )
4596 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store status: {e}")))?;
4597
4598 let data_len_off = std::mem::offset_of!(PrintComplexVariableData, data_len) as u64;
4602 let data_len_ptr = unsafe {
4603 self.builder
4604 .build_gep(
4605 self.context.i8_type(),
4606 data_ptr,
4607 &[self.context.i32_type().const_int(data_len_off, false)],
4608 "data_len_ptr",
4609 )
4610 .map_err(|e| CodeGenError::LLVMError(format!("Failed to get data_len GEP: {e}")))?
4611 };
4612 let data_len_ptr_cast = self
4613 .builder
4614 .build_pointer_cast(
4615 data_len_ptr,
4616 self.context.ptr_type(AddressSpace::default()),
4617 "data_len_ptr_i16",
4618 )
4619 .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast data_len ptr: {e}")))?;
4620 self.builder
4621 .build_store(
4622 data_len_ptr_cast,
4623 self.context.i16_type().const_int(data_len as u64, false),
4624 )
4625 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store data_len: {e}")))?;
4626 tracing::trace!(
4627 data_len,
4628 "generate_print_complex_variable_runtime: wrote data_len"
4629 );
4630
4631 let access_path_ptr = unsafe {
4635 self.builder
4636 .build_gep(
4637 self.context.i8_type(),
4638 data_ptr,
4639 &[self.context.i32_type().const_int(
4640 std::mem::size_of::<PrintComplexVariableData>() as u64,
4641 false,
4642 )],
4643 "access_path_ptr",
4644 )
4645 .map_err(|e| {
4646 CodeGenError::LLVMError(format!("Failed to get access_path GEP: {e}"))
4647 })?
4648 };
4649
4650 for (i, &byte) in access_path_bytes.iter().enumerate().take(access_path_len) {
4652 let byte_ptr = unsafe {
4653 self.builder
4654 .build_gep(
4655 self.context.i8_type(),
4656 access_path_ptr,
4657 &[self.context.i32_type().const_int(i as u64, false)],
4658 &format!("access_path_byte_{i}"),
4659 )
4660 .map_err(|e| {
4661 CodeGenError::LLVMError(format!("Failed to get access_path byte GEP: {e}"))
4662 })?
4663 };
4664 let byte_val = self.context.i8_type().const_int(byte as u64, false);
4665 self.builder.build_store(byte_ptr, byte_val).map_err(|e| {
4666 CodeGenError::LLVMError(format!("Failed to store access_path byte: {e}"))
4667 })?;
4668 }
4669 if access_path_len > 0 {
4670 tracing::trace!("generate_print_complex_variable_runtime: wrote access_path bytes");
4671 }
4672
4673 let variable_data_ptr = unsafe {
4675 self.builder
4676 .build_gep(
4677 self.context.i8_type(),
4678 access_path_ptr,
4679 &[self
4680 .context
4681 .i32_type()
4682 .const_int(access_path_len as u64, false)],
4683 "variable_data_ptr",
4684 )
4685 .map_err(|e| {
4686 CodeGenError::LLVMError(format!("Failed to get variable_data GEP: {e}"))
4687 })?
4688 };
4689
4690 let src_addr = self.evaluation_result_to_address_with_hint(
4693 eval_result,
4694 Some(status_ptr),
4695 module_hint,
4696 )?;
4697 tracing::trace!(src_addr = %{src_addr}, "generate_print_complex_variable_runtime: computed src_addr");
4698
4699 let ptr_type = self.context.ptr_type(AddressSpace::default());
4701 let i32_type = self.context.i32_type();
4702 let i64_type = self.context.i64_type();
4703 let dst_ptr = self
4704 .builder
4705 .build_bit_cast(variable_data_ptr, ptr_type, "dst_ptr")
4706 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4707 let size_val = i32_type.const_int(data_len as u64, false);
4708 let src_ptr = self
4709 .builder
4710 .build_int_to_ptr(src_addr, ptr_type, "src_ptr")
4711 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4712 let offsets_found = self.load_offsets_found_flag()?;
4713 let current_block = self.builder.get_insert_block().unwrap();
4714 let current_fn = current_block.get_parent().unwrap();
4715 let cont_block = self.context.append_basic_block(current_fn, "after_read");
4716 let skip_block = self.context.append_basic_block(current_fn, "offsets_skip");
4717 let found_block = self.context.append_basic_block(current_fn, "offsets_found");
4718 self.builder
4719 .build_conditional_branch(offsets_found, found_block, skip_block)
4720 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4721 self.builder.position_at_end(skip_block);
4722 self.mark_any_fail()?;
4723 self.builder
4724 .build_store(data_len_ptr_cast, self.context.i16_type().const_zero())
4725 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4726 self.builder
4727 .build_unconditional_branch(cont_block)
4728 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4729 self.builder.position_at_end(found_block);
4730
4731 let zero64 = i64_type.const_zero();
4733 let is_null = self
4734 .builder
4735 .build_int_compare(inkwell::IntPredicate::EQ, src_addr, zero64, "is_null")
4736 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4737 let null_block = self.context.append_basic_block(current_fn, "null_deref");
4738 let read_block = self.context.append_basic_block(current_fn, "read_user");
4739 self.builder
4740 .build_conditional_branch(is_null, null_block, read_block)
4741 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4742
4743 self.builder.position_at_end(null_block);
4745 self.builder
4746 .build_store(
4747 status_ptr,
4748 self.context
4749 .i8_type()
4750 .const_int(VariableStatus::NullDeref as u64, false),
4751 )
4752 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4753 self.builder
4755 .build_store(data_len_ptr_cast, self.context.i16_type().const_zero())
4756 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4757 self.mark_any_fail()?;
4759 self.builder
4760 .build_unconditional_branch(cont_block)
4761 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4762
4763 self.builder.position_at_end(read_block);
4765 let ret = self
4766 .create_bpf_helper_call(
4767 BPF_FUNC_probe_read_user as u64,
4768 &[dst_ptr, size_val.into(), src_ptr.into()],
4769 i32_type.into(),
4770 "probe_read_user",
4771 )?
4772 .into_int_value();
4773 let is_err = self
4774 .builder
4775 .build_int_compare(
4776 inkwell::IntPredicate::SLT,
4777 ret,
4778 i32_type.const_zero(),
4779 "ret_lt_zero",
4780 )
4781 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4782 let err_block = self.context.append_basic_block(current_fn, "read_err");
4783 let ok_block = self.context.append_basic_block(current_fn, "read_ok");
4784 self.builder
4785 .build_conditional_branch(is_err, err_block, ok_block)
4786 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4787
4788 self.builder.position_at_end(err_block);
4790 let cur_status1 = self
4792 .builder
4793 .build_load(self.context.i8_type(), status_ptr, "cur_status1")
4794 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4795 let is_ok1 = self
4796 .builder
4797 .build_int_compare(
4798 inkwell::IntPredicate::EQ,
4799 cur_status1.into_int_value(),
4800 self.context.i8_type().const_zero(),
4801 "status_is_ok1",
4802 )
4803 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4804 let readerr_val = self
4805 .context
4806 .i8_type()
4807 .const_int(VariableStatus::ReadError as u64, false)
4808 .into();
4809 let new_status1 = self
4810 .builder
4811 .build_select(is_ok1, readerr_val, cur_status1, "status_after_readerr")
4812 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4813 self.builder
4814 .build_store(status_ptr, new_status1)
4815 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4816 self.builder
4818 .build_store(
4819 data_len_ptr_cast,
4820 self.context.i16_type().const_int(12, false),
4821 )
4822 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4823 let errno_ptr = self
4825 .builder
4826 .build_pointer_cast(
4827 variable_data_ptr,
4828 self.context.ptr_type(AddressSpace::default()),
4829 "errno_ptr",
4830 )
4831 .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast errno ptr: {e}")))?;
4832 let errno = self.build_errno_i32(ret, "readerr_errno_i32")?;
4833 self.builder
4834 .build_store(errno_ptr, errno)
4835 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store errno: {e}")))?;
4836 let addr_ptr_i8 = unsafe {
4838 self.builder
4839 .build_gep(
4840 self.context.i8_type(),
4841 variable_data_ptr,
4842 &[self.context.i32_type().const_int(4, false)],
4843 "addr_ptr_i8",
4844 )
4845 .map_err(|e| CodeGenError::LLVMError(format!("Failed to get addr GEP: {e}")))?
4846 };
4847 let addr_ptr = self
4848 .builder
4849 .build_pointer_cast(
4850 addr_ptr_i8,
4851 self.context.ptr_type(AddressSpace::default()),
4852 "addr_ptr",
4853 )
4854 .map_err(|e| CodeGenError::LLVMError(format!("Failed to cast addr ptr: {e}")))?;
4855 self.builder
4856 .build_store(addr_ptr, src_addr)
4857 .map_err(|e| CodeGenError::LLVMError(format!("Failed to store addr: {e}")))?;
4858 self.mark_any_fail()?;
4860 self.builder
4861 .build_unconditional_branch(cont_block)
4862 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4863
4864 self.builder.position_at_end(ok_block);
4866 if data_len < dwarf_type.size() as usize {
4867 self.builder
4869 .build_store(
4870 status_ptr,
4871 self.context
4872 .i8_type()
4873 .const_int(VariableStatus::Truncated as u64, false),
4874 )
4875 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4876 self.mark_any_success()?;
4878 self.mark_any_fail()?;
4879 } else {
4880 self.mark_any_success()?;
4882 }
4883 self.builder
4884 .build_unconditional_branch(cont_block)
4885 .map_err(|e| CodeGenError::LLVMError(e.to_string()))?;
4886
4887 self.builder.position_at_end(cont_block);
4889
4890 Ok(())
4892 }
4893}
4894
4895#[cfg(test)]
4896mod tests {
4897 use super::*;
4898 use crate::CompileOptions;
4899 use ghostscope_protocol::trace_event::{TraceEventHeader, TraceEventMessage};
4900
4901 #[test]
4902 fn print_complex_format_budget_tracks_event_size() {
4903 let bytes_reserved_so_far =
4904 std::mem::size_of::<TraceEventHeader>() + std::mem::size_of::<TraceEventMessage>();
4905 let expected = 32768
4906 - (bytes_reserved_so_far
4907 + std::mem::size_of::<InstructionHeader>()
4908 + std::mem::size_of::<EndInstructionData>());
4909 assert_eq!(
4910 print_complex_format_instruction_budget(32768, bytes_reserved_so_far),
4911 expected
4912 );
4913 assert!(print_complex_format_instruction_budget(32768, bytes_reserved_so_far) > 4096);
4914 }
4915
4916 #[test]
4917 fn print_complex_format_budget_shrinks_after_prior_instructions() {
4918 let bytes_reserved_so_far = std::mem::size_of::<TraceEventHeader>()
4919 + std::mem::size_of::<TraceEventMessage>()
4920 + 2048;
4921 let base_budget = print_complex_format_instruction_budget(
4922 32768,
4923 std::mem::size_of::<TraceEventHeader>() + std::mem::size_of::<TraceEventMessage>(),
4924 );
4925 assert_eq!(
4926 print_complex_format_instruction_budget(32768, bytes_reserved_so_far),
4927 base_budget - 2048
4928 );
4929 }
4930
4931 #[test]
4932 fn dynamic_payload_reservations_share_budget_fairly() {
4933 let reservations = allocate_dynamic_payload_reservations(&[256, 256, 256, 256], 512);
4934 assert_eq!(reservations, vec![128, 128, 128, 128]);
4935 }
4936
4937 #[test]
4938 fn dynamic_payload_reservations_keep_error_headroom_when_possible() {
4939 let reservations = allocate_dynamic_payload_reservations(&[256, 256, 256], 36);
4940 assert_eq!(reservations, vec![12, 12, 12]);
4941 }
4942
4943 #[test]
4944 fn build_errno_i32_truncates_i64_errors() {
4945 let context = inkwell::context::Context::create();
4946 let opts = CompileOptions::default();
4947 let ctx =
4948 EbpfContext::new(&context, "test_mod", Some(0), &opts).expect("create EbpfContext");
4949 let fn_type = context.i32_type().fn_type(&[], false);
4950 let function = ctx.module.add_function("errno_test", fn_type, None);
4951 let block = context.append_basic_block(function, "entry");
4952 ctx.builder.position_at_end(block);
4953
4954 let errno = ctx
4955 .build_errno_i32(
4956 context.i64_type().const_int((-14i64) as u64, true),
4957 "errno_i32",
4958 )
4959 .expect("truncate errno");
4960 assert_eq!(errno.get_type().get_bit_width(), 32);
4961 }
4962
4963 #[test]
4964 fn computed_int_store_i64_compiles() {
4965 let context = inkwell::context::Context::create();
4966 let opts = CompileOptions::default();
4967 let mut ctx =
4968 EbpfContext::new(&context, "test_mod", Some(0), &opts).expect("create EbpfContext");
4969 let expr = crate::script::Expr::BinaryOp {
4971 left: Box::new(crate::script::Expr::Int(41)),
4972 op: crate::script::BinaryOp::Add,
4973 right: Box::new(crate::script::Expr::Int(1)),
4974 };
4975 let stmt =
4976 crate::script::Statement::Print(crate::script::PrintStatement::ComplexVariable(expr));
4977 let program = crate::script::Program::new();
4978 let res = ctx.compile_program(&program, "test_func", &[stmt], None, None, None);
4979 assert!(res.is_ok(), "Compilation failed: {:?}", res.err());
4980 }
4981
4982 #[test]
4983 fn computed_int_in_format_compiles() {
4984 let context = inkwell::context::Context::create();
4985 let opts = CompileOptions::default();
4986 let mut ctx =
4987 EbpfContext::new(&context, "test_mod", Some(0), &opts).expect("create EbpfContext");
4988 let expr = crate::script::Expr::BinaryOp {
4990 left: Box::new(crate::script::Expr::Int(1)),
4991 op: crate::script::BinaryOp::Add,
4992 right: Box::new(crate::script::Expr::Int(2)),
4993 };
4994 let stmt = crate::script::Statement::Print(crate::script::PrintStatement::Formatted {
4995 format: "sum:{}".to_string(),
4996 args: vec![expr],
4997 });
4998 let program = crate::script::Program::new();
4999 let res = ctx.compile_program(&program, "test_fmt", &[stmt], None, None, None);
5000 assert!(res.is_ok(), "Compilation failed: {:?}", res.err());
5001 }
5002
5003 #[test]
5004 fn memcmp_rejects_script_pointer_variable_now() {
5005 let context = inkwell::context::Context::create();
5006 let opts = CompileOptions::default();
5007 let mut ctx =
5008 EbpfContext::new(&context, "test_mod", Some(0), &opts).expect("create EbpfContext");
5009
5010 let decl = crate::script::Statement::VarDeclaration {
5012 name: "p".to_string(),
5013 value: crate::script::Expr::String("A".to_string()),
5014 };
5015
5016 let if_stmt = crate::script::Statement::If {
5018 condition: crate::script::Expr::BuiltinCall {
5019 name: "memcmp".to_string(),
5020 args: vec![
5021 crate::script::Expr::Variable("p".to_string()),
5022 crate::script::Expr::BuiltinCall {
5023 name: "hex".to_string(),
5024 args: vec![crate::script::Expr::String("41".to_string())],
5025 },
5026 crate::script::Expr::Int(1),
5027 ],
5028 },
5029 then_body: vec![crate::script::Statement::Print(
5030 crate::script::PrintStatement::String("OK".to_string()),
5031 )],
5032 else_body: None,
5033 };
5034
5035 let program = crate::script::Program::new();
5036 let res = ctx.compile_program(
5037 &program,
5038 "test_memcmp_ptr",
5039 &[decl, if_stmt],
5040 None,
5041 None,
5042 None,
5043 );
5044 assert!(
5045 res.is_err(),
5046 "Expected type error for script pointer variable in memcmp"
5047 );
5048 }
5049
5050 #[test]
5051 fn strncmp_requires_string_on_one_side_error_message() {
5052 let context = inkwell::context::Context::create();
5053 let opts = CompileOptions::default();
5054 let mut ctx = EbpfContext::new(&context, "test_mod", Some(0), &opts).expect("ctx");
5055
5056 let stmt = crate::script::Statement::If {
5058 condition: crate::script::Expr::BuiltinCall {
5059 name: "strncmp".to_string(),
5060 args: vec![
5061 crate::script::Expr::Int(42),
5062 crate::script::Expr::Int(43),
5063 crate::script::Expr::Int(2),
5064 ],
5065 },
5066 then_body: vec![crate::script::Statement::Print(
5067 crate::script::PrintStatement::String("OK".to_string()),
5068 )],
5069 else_body: None,
5070 };
5071 let program = crate::script::Program::new();
5072 let res = ctx.compile_program(&program, "test_strncmp_err", &[stmt], None, None, None);
5073 assert!(
5074 res.is_err(),
5075 "expected error when neither side is string (got {res:?})",
5076 );
5077 let msg = format!("{:?}", res.err());
5078 assert!(msg.contains("strncmp requires at least one string argument"));
5079 }
5080
5081 #[test]
5085 fn immutable_variable_redeclaration_rejected() {
5086 let context = inkwell::context::Context::create();
5087 let opts = CompileOptions::default();
5088 let mut ctx = EbpfContext::new(&context, "test_mod", Some(0), &opts).expect("ctx");
5089
5090 let d1 = crate::script::Statement::VarDeclaration {
5092 name: "x".to_string(),
5093 value: crate::script::Expr::Int(1),
5094 };
5095 let d2 = crate::script::Statement::VarDeclaration {
5096 name: "x".to_string(),
5097 value: crate::script::Expr::Int(2),
5098 };
5099 let program = crate::script::Program::new();
5100 let res = ctx.compile_program(&program, "immut", &[d1, d2], None, None, None);
5101 assert!(res.is_err(), "expected immutability error, got {res:?}");
5102 let msg = format!("{:?}", res.err());
5103 assert!(
5104 msg.contains("Redeclaration in the same scope") || msg.contains("immutable variable"),
5105 "unexpected error msg: {msg}"
5106 );
5107 }
5108
5109 #[test]
5110 fn immutable_alias_rebinding_rejected() {
5111 let context = inkwell::context::Context::create();
5112 let opts = CompileOptions::default();
5113 let mut ctx = EbpfContext::new(&context, "test_mod", Some(0), &opts).expect("ctx");
5114
5115 let a1 = crate::script::Statement::AliasDeclaration {
5117 name: "p".to_string(),
5118 target: crate::script::Expr::AddressOf(Box::new(crate::script::Expr::Variable(
5119 "arr".to_string(),
5120 ))),
5121 };
5122 let a2 = crate::script::Statement::AliasDeclaration {
5123 name: "p".to_string(),
5124 target: crate::script::Expr::AddressOf(Box::new(crate::script::Expr::Variable(
5125 "arr".to_string(),
5126 ))),
5127 };
5128 let program = crate::script::Program::new();
5129 let res = ctx.compile_program(&program, "immut_alias", &[a1, a2], None, None, None);
5130 assert!(
5131 res.is_err(),
5132 "expected immutability error for alias, got {res:?}"
5133 );
5134 }
5135
5136 #[test]
5137 fn alias_to_alias_with_const_offset_is_alias_variable() {
5138 let context = inkwell::context::Context::create();
5139 let opts = CompileOptions::default();
5140 let mut ctx = EbpfContext::new(&context, "test_mod", Some(0), &opts).expect("ctx");
5141 let s1 = crate::script::Statement::AliasDeclaration {
5143 name: "base".to_string(),
5144 target: crate::script::Expr::AddressOf(Box::new(crate::script::Expr::ArrayAccess(
5145 Box::new(crate::script::Expr::Variable("buf".to_string())),
5146 Box::new(crate::script::Expr::Int(0)),
5147 ))),
5148 };
5149 let s2 = crate::script::Statement::VarDeclaration {
5150 name: "tail".to_string(),
5151 value: crate::script::Expr::BinaryOp {
5152 left: Box::new(crate::script::Expr::Variable("base".to_string())),
5153 op: crate::script::BinaryOp::Add,
5154 right: Box::new(crate::script::Expr::Int(16)),
5155 },
5156 };
5157 let program = crate::script::Program::new();
5158 let res = ctx.compile_program(&program, "alias_stage", &[s1, s2], None, None, None);
5160 assert!(res.is_ok(), "expected alias-to-alias staging to compile");
5161 }
5162
5163 #[test]
5164 fn alias_to_alias_copy_is_alias_variable() {
5165 let context = inkwell::context::Context::create();
5166 let opts = CompileOptions::default();
5167 let mut ctx = EbpfContext::new(&context, "test_mod", Some(0), &opts).expect("ctx");
5168 let a = crate::script::Statement::AliasDeclaration {
5170 name: "a".to_string(),
5171 target: crate::script::Expr::AddressOf(Box::new(crate::script::Expr::MemberAccess(
5172 Box::new(crate::script::Expr::Variable("G_STATE".to_string())),
5173 "lib".to_string(),
5174 ))),
5175 };
5176 let b = crate::script::Statement::VarDeclaration {
5177 name: "b".to_string(),
5178 value: crate::script::Expr::Variable("a".to_string()),
5179 };
5180 let program = crate::script::Program::new();
5181 let res = ctx.compile_program(&program, "alias_copy", &[a, b], None, None, None);
5182 assert!(res.is_ok(), "expected alias-to-alias copy to compile");
5183 }
5184
5185 #[test]
5186 fn alias_self_reference_is_rejected_with_cycle_error() {
5187 let context = inkwell::context::Context::create();
5188 let opts = CompileOptions::default();
5189 let mut ctx = EbpfContext::new(&context, "test_mod", Some(0), &opts).expect("ctx");
5190
5191 let a = crate::script::Statement::AliasDeclaration {
5193 name: "a".to_string(),
5194 target: crate::script::Expr::AddressOf(Box::new(crate::script::Expr::Variable(
5195 "a".to_string(),
5196 ))),
5197 };
5198 let p = crate::script::Statement::Print(crate::script::PrintStatement::ComplexVariable(
5199 crate::script::Expr::Variable("a".to_string()),
5200 ));
5201 let program = crate::script::Program::new();
5202 let res = ctx.compile_program(&program, "alias_self", &[a, p], None, None, None);
5203 assert!(res.is_err(), "expected cycle error, got {res:?}");
5204 let msg = format!("{:?}", res.err());
5205 assert!(
5206 msg.contains("alias cycle") || msg.contains("depth exceeded"),
5207 "unexpected error: {msg}"
5208 );
5209 }
5210
5211 #[test]
5212 fn alias_mutual_cycle_is_rejected_with_cycle_error() {
5213 let context = inkwell::context::Context::create();
5214 let opts = CompileOptions::default();
5215 let mut ctx = EbpfContext::new(&context, "test_mod", Some(0), &opts).expect("ctx");
5216
5217 let a = crate::script::Statement::AliasDeclaration {
5219 name: "a".to_string(),
5220 target: crate::script::Expr::AddressOf(Box::new(crate::script::Expr::Variable(
5221 "b".to_string(),
5222 ))),
5223 };
5224 let b = crate::script::Statement::AliasDeclaration {
5225 name: "b".to_string(),
5226 target: crate::script::Expr::AddressOf(Box::new(crate::script::Expr::Variable(
5227 "a".to_string(),
5228 ))),
5229 };
5230 let p = crate::script::Statement::Print(crate::script::PrintStatement::ComplexVariable(
5231 crate::script::Expr::Variable("a".to_string()),
5232 ));
5233 let program = crate::script::Program::new();
5234 let res = ctx.compile_program(&program, "alias_cycle", &[a, b, p], None, None, None);
5235 assert!(res.is_err(), "expected cycle error, got {res:?}");
5236 let msg = format!("{:?}", res.err());
5237 assert!(
5238 msg.contains("alias cycle") || msg.contains("depth exceeded"),
5239 "unexpected error: {msg}"
5240 );
5241 }
5242
5243 #[test]
5244 fn strncmp_folds_with_script_string_and_literal_true() {
5245 let context = inkwell::context::Context::create();
5246 let opts = CompileOptions::default();
5247 let mut ctx = EbpfContext::new(&context, "test_mod", Some(0), &opts).expect("ctx");
5248
5249 let decl = crate::script::Statement::VarDeclaration {
5251 name: "s".to_string(),
5252 value: crate::script::Expr::String("ABC".to_string()),
5253 };
5254 let program = crate::script::Program::new();
5255 let res = ctx.compile_program(&program, "decl", &[decl], None, None, None);
5256 assert!(res.is_ok());
5257
5258 let expr = crate::script::Expr::BuiltinCall {
5260 name: "strncmp".to_string(),
5261 args: vec![
5262 crate::script::Expr::Variable("s".to_string()),
5263 crate::script::Expr::String("ABD".to_string()),
5264 crate::script::Expr::Int(2),
5265 ],
5266 };
5267 let v = ctx.compile_expr(&expr).expect("compile expr");
5268 match v {
5269 inkwell::values::BasicValueEnum::IntValue(iv) => {
5270 assert_eq!(iv.get_type().get_bit_width(), 1);
5271 let s = format!("{iv}");
5273 assert!(s.contains("i1 true") || s.contains("true"));
5274 }
5275 other => panic!("expected IntValue i1, got {other:?}"),
5276 }
5277 }
5278
5279 #[test]
5280 fn starts_with_folds_with_two_literals() {
5281 let context = inkwell::context::Context::create();
5282 let opts = CompileOptions::default();
5283 let mut ctx = EbpfContext::new(&context, "test_mod", Some(0), &opts).expect("ctx");
5284
5285 let expr = crate::script::Expr::BuiltinCall {
5287 name: "starts_with".to_string(),
5288 args: vec![
5289 crate::script::Expr::String("abcdef".to_string()),
5290 crate::script::Expr::String("abc".to_string()),
5291 ],
5292 };
5293 let v = ctx.compile_expr(&expr).expect("compile expr");
5294 match v {
5295 inkwell::values::BasicValueEnum::IntValue(iv) => {
5296 assert_eq!(iv.get_type().get_bit_width(), 1);
5297 let s = format!("{iv}");
5298 assert!(s.contains("i1 true") || s.contains("true"));
5299 }
5300 _ => panic!("expected i1"),
5301 }
5302 }
5303
5304 #[test]
5305 fn starts_with_requires_one_string_side_error() {
5306 let context = inkwell::context::Context::create();
5307 let opts = CompileOptions::default();
5308 let mut ctx = EbpfContext::new(&context, "test_mod", Some(0), &opts).expect("ctx");
5309
5310 let expr = crate::script::Expr::BuiltinCall {
5312 name: "starts_with".to_string(),
5313 args: vec![crate::script::Expr::Int(1), crate::script::Expr::Int(2)],
5314 };
5315 let res = ctx.compile_expr(&expr);
5316 assert!(res.is_err(), "expected error");
5317 let msg = format!("{:?}", res.err());
5318 assert!(msg.contains("starts_with requires at least one string argument"));
5319 }
5320
5321 #[test]
5322 fn shadowing_rejected_in_inner_scope() {
5323 let context = inkwell::context::Context::create();
5324 let opts = CompileOptions::default();
5325 let mut ctx = EbpfContext::new(&context, "test_mod", Some(0), &opts).expect("ctx");
5326
5327 let d1 = crate::script::Statement::VarDeclaration {
5329 name: "x".to_string(),
5330 value: crate::script::Expr::Int(1),
5331 };
5332 let inner =
5333 crate::script::Statement::Block(vec![crate::script::Statement::VarDeclaration {
5334 name: "x".to_string(),
5335 value: crate::script::Expr::Int(2),
5336 }]);
5337 let program = crate::script::Program::new();
5338 let res = ctx.compile_program(&program, "shadow", &[d1, inner], None, None, None);
5339 assert!(res.is_err(), "expected shadowing error");
5340 let msg = format!("{:?}", res.err());
5341 assert!(
5342 msg.contains("Shadowing is not allowed") || msg.contains("shadow"),
5343 "unexpected: {msg}"
5344 );
5345 }
5346
5347 #[test]
5348 fn out_of_scope_use_is_rejected() {
5349 let context = inkwell::context::Context::create();
5350 let opts = CompileOptions::default();
5351 let mut ctx = EbpfContext::new(&context, "test_mod", Some(0), &opts).expect("ctx");
5352
5353 let block =
5355 crate::script::Statement::Block(vec![crate::script::Statement::VarDeclaration {
5356 name: "y".to_string(),
5357 value: crate::script::Expr::Int(2),
5358 }]);
5359 let print_y = crate::script::Statement::Print(crate::script::PrintStatement::Variable(
5360 "y".to_string(),
5361 ));
5362 let program = crate::script::Program::new();
5363 let res = ctx.compile_program(
5364 &program,
5365 "out_of_scope",
5366 &[block, print_y],
5367 None,
5368 None,
5369 None,
5370 );
5371 assert!(
5372 res.is_err(),
5373 "expected out-of-scope or missing analyzer error"
5374 );
5375 }
5376
5377 #[test]
5378 fn memcmp_rejects_bare_integer_pointer_argument() {
5379 let context = inkwell::context::Context::create();
5380 let opts = CompileOptions::default();
5381 let mut ctx =
5382 EbpfContext::new(&context, "test_mod", Some(0), &opts).expect("create EbpfContext");
5383
5384 let decl = crate::script::Statement::VarDeclaration {
5386 name: "q".to_string(),
5387 value: crate::script::Expr::Int(0xdeadbeef),
5388 };
5389
5390 let if_stmt = crate::script::Statement::If {
5392 condition: crate::script::Expr::BuiltinCall {
5393 name: "memcmp".to_string(),
5394 args: vec![
5395 crate::script::Expr::Variable("q".to_string()),
5396 crate::script::Expr::BuiltinCall {
5397 name: "hex".to_string(),
5398 args: vec![crate::script::Expr::String("00".to_string())],
5399 },
5400 crate::script::Expr::Int(1),
5401 ],
5402 },
5403 then_body: vec![crate::script::Statement::Print(
5404 crate::script::PrintStatement::String("X".to_string()),
5405 )],
5406 else_body: None,
5407 };
5408
5409 let program = crate::script::Program::new();
5410 let res = ctx.compile_program(
5411 &program,
5412 "test_memcmp_int_ptr",
5413 &[decl, if_stmt],
5414 None,
5415 None,
5416 None,
5417 );
5418 assert!(res.is_err(), "Expected compilation error but got Ok");
5419 }
5420
5421 #[test]
5422 fn expr_to_name_truncates_utf8_safely() {
5423 let context = inkwell::context::Context::create();
5424 let opts = CompileOptions::default();
5425 let ctx = EbpfContext::new(&context, "test_mod", Some(0), &opts).expect("create ctx");
5426 let mut chain: Vec<String> = Vec::new();
5428 for _ in 0..50 {
5429 chain.push("错误".to_string());
5431 }
5432 let expr = crate::script::Expr::ChainAccess(chain);
5433 let s = ctx.expr_to_name(&expr);
5434 assert!(s.ends_with("..."));
5436 assert!(s.chars().count() <= 96);
5437 }
5438
5439 #[test]
5440 fn pointer_int_arithmetic_is_rejected_with_friendly_error() {
5441 let context = inkwell::context::Context::create();
5442 let opts = CompileOptions::default();
5443 let mut ctx = EbpfContext::new(&context, "ptr_arith", Some(0), &opts).expect("ctx");
5444 ctx.create_basic_ebpf_function("f").expect("fn");
5445
5446 let ptr_ty = ctx.context.ptr_type(inkwell::AddressSpace::default());
5448 let null_ptr = ptr_ty.const_null();
5449 ctx.store_variable("p", null_ptr.into()).expect("store ptr");
5450
5451 let expr = crate::script::Expr::BinaryOp {
5453 left: Box::new(crate::script::Expr::Variable("p".to_string())),
5454 op: crate::script::BinaryOp::Add,
5455 right: Box::new(crate::script::Expr::Int(1)),
5456 };
5457 let res = ctx.compile_expr(&expr);
5458 assert!(res.is_err(), "expected pointer-int arithmetic error");
5459 let msg = format!("{:?}", res.err());
5460 assert!(
5461 msg.contains("pointer and integer")
5462 || msg.contains("Unsupported operation between pointer and integer"),
5463 "unexpected error message: {msg}"
5464 );
5465 }
5466}