From 8e58e24fc49356906606ef49d1c9268ec55387d5 Mon Sep 17 00:00:00 2001 From: mahesh bhatiya Date: Mon, 16 Mar 2026 22:09:13 +0530 Subject: [PATCH] Fix execve filename example and ringbuf codegen issues Emit bpf_ringbuf_submit for reserved events and treat ringbuf submit and helper calls as side-effecting. Lower event field accesses and assignments using correct offsets and sizes, returning pointers for fields used as buffers. Generate proper bpf_probe_read_user_str / bpf_probe_read_kernel_str calls with explicit arguments. --- src/emit/ebpf_c/tracepoint.rs | 89 ++++++++++++++++++++++++++++++----- src/ir/unit.rs | 63 ++++++++++++++++--------- src/sema/event.rs | 21 +++++++++ 3 files changed, 140 insertions(+), 33 deletions(-) diff --git a/src/emit/ebpf_c/tracepoint.rs b/src/emit/ebpf_c/tracepoint.rs index 08c7305..53b1b20 100644 --- a/src/emit/ebpf_c/tracepoint.rs +++ b/src/emit/ebpf_c/tracepoint.rs @@ -164,7 +164,11 @@ pub fn emit_tracepoint(out: &mut String, unit: &UnitIr, sec: &str) -> Result<(), let is_side_effect = matches!( inst.opcode, - Opcode::Store { .. } | Opcode::UpdateMap { .. } | Opcode::NullCheck + Opcode::Store { .. } + | Opcode::UpdateMap { .. } + | Opcode::NullCheck + | Opcode::HelperCall { .. } + | Opcode::RingBufSubmit { .. } ); if !is_side_effect && !res_used { @@ -241,15 +245,78 @@ pub fn emit_tracepoint(out: &mut String, unit: &UnitIr, sec: &str) -> Result<(), } Opcode::HelperCall { id } => { - let call_expr = match *id { - 5 => "bpf_ktime_get_ns()", - 14 => "bpf_get_current_pid_tgid()", - 15 => "bpf_get_current_uid_gid()", - 35 => "bpf_get_current_task()", - _ => "0", - }; - let res = res_name.unwrap(); - writeln!(out, " {} = {};", res, call_expr).map_err(err)?; + match *id { + 5 => { + let res = res_name.unwrap(); + writeln!(out, " {} = bpf_ktime_get_ns();", res).map_err(err)?; + } + 14 => { + let res = res_name.unwrap(); + writeln!(out, " {} = bpf_get_current_pid_tgid();", res).map_err(err)?; + } + 15 => { + let res = res_name.unwrap(); + writeln!(out, " {} = bpf_get_current_uid_gid();", res).map_err(err)?; + } + 35 => { + let res = res_name.unwrap(); + writeln!(out, " {} = bpf_get_current_task();", res).map_err(err)?; + } + 202 => { + // bpf_probe_read_user_str(void *dst, u32 size, const void *unsafe_ptr) + if inst.operands.len() != 3 { + return Err("internal error: helper 202 expects 3 operands".to_string()); + } + let dst = format_operand(&inst.operands[0]); + let size = format_operand(&inst.operands[1]); + let src = format_operand(&inst.operands[2]); + if let Some(res) = res_name { + writeln!( + out, + " {} = bpf_probe_read_user_str((void *){}, {}, (void *){});", + res, dst, size, src + ) + .map_err(err)?; + } else { + writeln!( + out, + " (void)bpf_probe_read_user_str((void *){}, {}, (void *){});", + dst, size, src + ) + .map_err(err)?; + } + } + 204 => { + // bpf_probe_read_kernel_str(void *dst, u32 size, const void *unsafe_ptr) + if inst.operands.len() != 3 { + return Err("internal error: helper 204 expects 3 operands".to_string()); + } + let dst = format_operand(&inst.operands[0]); + let size = format_operand(&inst.operands[1]); + let src = format_operand(&inst.operands[2]); + if let Some(res) = res_name { + writeln!( + out, + " {} = bpf_probe_read_kernel_str((void *){}, {}, (void *){});", + res, dst, size, src + ) + .map_err(err)?; + } else { + writeln!( + out, + " (void)bpf_probe_read_kernel_str((void *){}, {}, (void *){});", + dst, size, src + ) + .map_err(err)?; + } + } + other => { + return Err(format!( + "unsupported helper id {} in C emitter (needs explicit lowering)", + other + )); + } + } } Opcode::CallMap { map_name } => { @@ -363,7 +430,7 @@ pub fn emit_tracepoint(out: &mut String, unit: &UnitIr, sec: &str) -> Result<(), if let Some(ptr_op) = inst.operands.get(0) { let ptr = format_operand(ptr_op); - writeln!(out, " bpf_ringbuf_submit({}, 0);", ptr).map_err(err)?; + writeln!(out, " bpf_ringbuf_submit((void *){}, 0);", ptr).map_err(err)?; } } Opcode::CopyCtxToMem { offset, size } => { diff --git a/src/ir/unit.rs b/src/ir/unit.rs index a69446f..2744179 100644 --- a/src/ir/unit.rs +++ b/src/ir/unit.rs @@ -403,22 +403,41 @@ fn lower_statement( )); }; - // Look up field offset across all events + // Look up field offset + size across all events let mut field_offset: Option = None; + let mut field_size: Option = None; for (_, event_decl) in event_decls { if let Some(offset) = crate::sema::event::compute_field_offset(event_decl, field) { field_offset = Some(offset); + field_size = crate::sema::event::compute_field_size(event_decl, field); break; } } - let _offset = field_offset.ok_or_else(|| { + let offset = field_offset.ok_or_else(|| { LoweringError::UnitLowering(format!("Unknown field: {}", field)) })?; + let size = field_size.ok_or_else(|| { + LoweringError::UnitLowering(format!("Unknown field size: {}", field)) + })?; + + // Compute pointer to the field: base + offset + let field_ptr_var = if offset == 0 { + base_var + } else { + let ptr = ir.alloc_var(crate::ast::Type::U64); + block.instructions.push(Instruction { + result: ptr, + opcode: Opcode::Binary { op: BinaryOp::Add }, + operands: vec![Operand::Var(base_var), Operand::Immediate(offset as i64)], + result_type: crate::ast::Type::U64, + }); + ptr + }; - // For now, we only support simple field assignments (no compound ops on fields) + // support simple field assignments if !matches!(assign.op, crate::ast::AssignmentOp::Assign) { return Err(LoweringError::UnitLowering( "Compound assignment operators not supported on struct fields" @@ -426,14 +445,14 @@ fn lower_statement( )); } - // Create a store instruction for the field - // TODO: Currently we store at the base pointer with fixed size - // In the future, we should track field offsets and sizes per event type + // Create a store instruction for the field (correct offset + size) let result = ir.alloc_var(crate::ast::Type::U64); block.instructions.push(Instruction { result, - opcode: Opcode::Store { size: 8 }, - operands: vec![Operand::Var(base_var), value.clone()], + opcode: Opcode::Store { + size: (size as u8), + }, + operands: vec![Operand::Var(field_ptr_var), value.clone()], result_type: crate::ast::Type::U64, }); } @@ -961,7 +980,7 @@ fn lower_expr( } ExprKind::FieldAccess { base, field } => { - // Handle field access like evt.filename + // Handle field access like evt.filename (returns pointer to the field) let base_operand = lower_expr(base, ctx, ir, block, events, event_decls)?; // Get the variable ID (should be a pointer from reserve) @@ -982,21 +1001,21 @@ fn lower_expr( } } - let _offset = field_offset + let offset = field_offset .ok_or_else(|| LoweringError::UnitLowering(format!("Unknown field: {}", field)))?; - // Create a load instruction from the field - // TODO: Currently we load from base pointer with fixed size - // In the future, we should track field offsets and sizes per event type - let result = ir.alloc_var(crate::ast::Type::U64); - block.instructions.push(Instruction { - result, - opcode: Opcode::LoadKey, - operands: vec![Operand::Var(base_var)], - result_type: crate::ast::Type::U64, - }); - - Ok(Operand::Var(result)) + if offset == 0 { + Ok(Operand::Var(base_var)) + } else { + let result = ir.alloc_var(crate::ast::Type::U64); + block.instructions.push(Instruction { + result, + opcode: Opcode::Binary { op: BinaryOp::Add }, + operands: vec![Operand::Var(base_var), Operand::Immediate(offset as i64)], + result_type: crate::ast::Type::U64, + }); + Ok(Operand::Var(result)) + } } other => Err(LoweringError::UnitLowering(format!( diff --git a/src/sema/event.rs b/src/sema/event.rs index 19c6d53..bd32f47 100644 --- a/src/sema/event.rs +++ b/src/sema/event.rs @@ -182,5 +182,26 @@ pub fn compute_field_offset(event: &EventDecl, field_name: &str) -> Option offset += size; } + None +} + +pub fn compute_field_size(event: &EventDecl, field_name: &str) -> Option { + for field in &event.fields { + if field.name != field_name { + continue; + } + return Some(match &field.ty { + EventType::U32 | EventType::I32 => 4, + EventType::U64 | EventType::I64 => 8, + EventType::Bytes(len) => *len, + EventType::Array { elem, len } => { + let elem_size = match elem { + PrimitiveType::U32 | PrimitiveType::I32 => 4, + PrimitiveType::U64 | PrimitiveType::I64 => 8, + }; + elem_size * (*len) + } + }); + } None } \ No newline at end of file