Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
89 changes: 78 additions & 11 deletions src/emit/ebpf_c/tracepoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 } => {
Expand Down Expand Up @@ -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 } => {
Expand Down
63 changes: 41 additions & 22 deletions src/ir/unit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -403,37 +403,56 @@ fn lower_statement(
));
};

// Look up field offset across all events
// Look up field offset + size across all events
let mut field_offset: Option<u32> = None;
let mut field_size: Option<u32> = 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"
.to_string(),
));
}

// 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,
});
}
Expand Down Expand Up @@ -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)
Expand All @@ -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!(
Expand Down
21 changes: 21 additions & 0 deletions src/sema/event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,5 +182,26 @@ pub fn compute_field_offset(event: &EventDecl, field_name: &str) -> Option<u32>
offset += size;
}

None
}

pub fn compute_field_size(event: &EventDecl, field_name: &str) -> Option<u32> {
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
}
Loading