mirror of
https://github.com/varun-r-mallya/Python-BPF.git
synced 2026-03-18 19:21:29 +00:00
PythonBPF: Add Compilation Context to allow parallel compilation of multiple bpf programs
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
from .helper_registry import HelperHandlerRegistry
|
||||
from .helper_utils import reset_scratch_pool
|
||||
|
||||
from .bpf_helper_handler import (
|
||||
handle_helper_call,
|
||||
emit_probe_read_kernel_str_call,
|
||||
@ -28,9 +28,7 @@ def _register_helper_handler():
|
||||
"""Register helper call handler with the expression evaluator"""
|
||||
from pythonbpf.expr.expr_pass import CallHandlerRegistry
|
||||
|
||||
def helper_call_handler(
|
||||
call, module, builder, func, local_sym_tab, map_sym_tab, structs_sym_tab
|
||||
):
|
||||
def helper_call_handler(call, compilation_context, builder, func, local_sym_tab):
|
||||
"""Check if call is a helper and handle it"""
|
||||
import ast
|
||||
|
||||
@ -39,17 +37,16 @@ def _register_helper_handler():
|
||||
if HelperHandlerRegistry.has_handler(call.func.id):
|
||||
return handle_helper_call(
|
||||
call,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab,
|
||||
map_sym_tab,
|
||||
structs_sym_tab,
|
||||
)
|
||||
|
||||
# Check for method calls (e.g., map.lookup())
|
||||
elif isinstance(call.func, ast.Attribute):
|
||||
method_name = call.func.attr
|
||||
map_sym_tab = compilation_context.map_sym_tab
|
||||
|
||||
# Handle: my_map.lookup(key)
|
||||
if isinstance(call.func.value, ast.Name):
|
||||
@ -58,12 +55,10 @@ def _register_helper_handler():
|
||||
if HelperHandlerRegistry.has_handler(method_name):
|
||||
return handle_helper_call(
|
||||
call,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab,
|
||||
map_sym_tab,
|
||||
structs_sym_tab,
|
||||
)
|
||||
|
||||
return None
|
||||
@ -76,7 +71,6 @@ _register_helper_handler()
|
||||
|
||||
__all__ = [
|
||||
"HelperHandlerRegistry",
|
||||
"reset_scratch_pool",
|
||||
"handle_helper_call",
|
||||
"emit_probe_read_kernel_str_call",
|
||||
"emit_probe_read_kernel_call",
|
||||
|
||||
@ -50,12 +50,10 @@ class BPFHelperID(Enum):
|
||||
def bpf_ktime_get_ns_emitter(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""
|
||||
Emit LLVM IR for bpf_ktime_get_ns helper function call.
|
||||
@ -77,12 +75,10 @@ def bpf_ktime_get_ns_emitter(
|
||||
def bpf_get_current_cgroup_id(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""
|
||||
Emit LLVM IR for bpf_get_current_cgroup_id helper function call.
|
||||
@ -104,12 +100,10 @@ def bpf_get_current_cgroup_id(
|
||||
def bpf_map_lookup_elem_emitter(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""
|
||||
Emit LLVM IR for bpf_map_lookup_elem helper function call.
|
||||
@ -119,7 +113,7 @@ def bpf_map_lookup_elem_emitter(
|
||||
f"Map lookup expects exactly one argument (key), got {len(call.args)}"
|
||||
)
|
||||
key_ptr = get_or_create_ptr_from_arg(
|
||||
func, module, call.args[0], builder, local_sym_tab, map_sym_tab, struct_sym_tab
|
||||
func, compilation_context, call.args[0], builder, local_sym_tab
|
||||
)
|
||||
map_void_ptr = builder.bitcast(map_ptr, ir.PointerType())
|
||||
|
||||
@ -147,12 +141,10 @@ def bpf_map_lookup_elem_emitter(
|
||||
def bpf_printk_emitter(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""Emit LLVM IR for bpf_printk helper function call."""
|
||||
if not hasattr(func, "_fmt_counter"):
|
||||
@ -165,16 +157,18 @@ def bpf_printk_emitter(
|
||||
if isinstance(call.args[0], ast.JoinedStr):
|
||||
args = handle_fstring_print(
|
||||
call.args[0],
|
||||
module,
|
||||
compilation_context.module,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab,
|
||||
struct_sym_tab,
|
||||
compilation_context.structs_sym_tab,
|
||||
)
|
||||
elif isinstance(call.args[0], ast.Constant) and isinstance(call.args[0].value, str):
|
||||
# TODO: We are only supporting single arguments for now.
|
||||
# In case of multiple args, the first one will be taken.
|
||||
args = simple_string_print(call.args[0].value, module, builder, func)
|
||||
args = simple_string_print(
|
||||
call.args[0].value, compilation_context.module, builder, func
|
||||
)
|
||||
else:
|
||||
raise NotImplementedError(
|
||||
"Only simple strings or f-strings are supported in bpf_printk."
|
||||
@ -203,12 +197,10 @@ def bpf_printk_emitter(
|
||||
def bpf_map_update_elem_emitter(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""
|
||||
Emit LLVM IR for bpf_map_update_elem helper function call.
|
||||
@ -224,10 +216,10 @@ def bpf_map_update_elem_emitter(
|
||||
flags_arg = call.args[2] if len(call.args) > 2 else None
|
||||
|
||||
key_ptr = get_or_create_ptr_from_arg(
|
||||
func, module, key_arg, builder, local_sym_tab, map_sym_tab, struct_sym_tab
|
||||
func, compilation_context, key_arg, builder, local_sym_tab
|
||||
)
|
||||
value_ptr = get_or_create_ptr_from_arg(
|
||||
func, module, value_arg, builder, local_sym_tab, map_sym_tab, struct_sym_tab
|
||||
func, compilation_context, value_arg, builder, local_sym_tab
|
||||
)
|
||||
flags_val = get_flags_val(flags_arg, builder, local_sym_tab)
|
||||
|
||||
@ -262,12 +254,10 @@ def bpf_map_update_elem_emitter(
|
||||
def bpf_map_delete_elem_emitter(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""
|
||||
Emit LLVM IR for bpf_map_delete_elem helper function call.
|
||||
@ -278,7 +268,7 @@ def bpf_map_delete_elem_emitter(
|
||||
f"Map delete expects exactly one argument (key), got {len(call.args)}"
|
||||
)
|
||||
key_ptr = get_or_create_ptr_from_arg(
|
||||
func, module, call.args[0], builder, local_sym_tab, map_sym_tab, struct_sym_tab
|
||||
func, compilation_context, call.args[0], builder, local_sym_tab
|
||||
)
|
||||
map_void_ptr = builder.bitcast(map_ptr, ir.PointerType())
|
||||
|
||||
@ -306,12 +296,10 @@ def bpf_map_delete_elem_emitter(
|
||||
def bpf_get_current_comm_emitter(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""
|
||||
Emit LLVM IR for bpf_get_current_comm helper function call.
|
||||
@ -327,7 +315,7 @@ def bpf_get_current_comm_emitter(
|
||||
|
||||
# Extract buffer pointer and size
|
||||
buf_ptr, buf_size = get_buffer_ptr_and_size(
|
||||
buf_arg, builder, local_sym_tab, struct_sym_tab
|
||||
buf_arg, builder, local_sym_tab, compilation_context
|
||||
)
|
||||
|
||||
# Validate it's a char array
|
||||
@ -367,12 +355,10 @@ def bpf_get_current_comm_emitter(
|
||||
def bpf_get_current_pid_tgid_emitter(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""
|
||||
Emit LLVM IR for bpf_get_current_pid_tgid helper function call.
|
||||
@ -394,12 +380,10 @@ def bpf_get_current_pid_tgid_emitter(
|
||||
def bpf_perf_event_output_handler(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""
|
||||
Emit LLVM IR for bpf_perf_event_output helper function call.
|
||||
@ -412,7 +396,9 @@ def bpf_perf_event_output_handler(
|
||||
data_arg = call.args[0]
|
||||
ctx_ptr = func.args[0] # First argument to the function is ctx
|
||||
|
||||
data_ptr, size_val = get_data_ptr_and_size(data_arg, local_sym_tab, struct_sym_tab)
|
||||
data_ptr, size_val = get_data_ptr_and_size(
|
||||
data_arg, local_sym_tab, compilation_context.structs_sym_tab
|
||||
)
|
||||
|
||||
# BPF_F_CURRENT_CPU is -1 in 32 bit
|
||||
flags_val = ir.Constant(ir.IntType(64), 0xFFFFFFFF)
|
||||
@ -445,12 +431,10 @@ def bpf_perf_event_output_handler(
|
||||
def bpf_ringbuf_output_emitter(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""
|
||||
Emit LLVM IR for bpf_ringbuf_output helper function call.
|
||||
@ -461,7 +445,9 @@ def bpf_ringbuf_output_emitter(
|
||||
f"Ringbuf output expects exactly one argument, got {len(call.args)}"
|
||||
)
|
||||
data_arg = call.args[0]
|
||||
data_ptr, size_val = get_data_ptr_and_size(data_arg, local_sym_tab, struct_sym_tab)
|
||||
data_ptr, size_val = get_data_ptr_and_size(
|
||||
data_arg, local_sym_tab, compilation_context.structs_sym_tab
|
||||
)
|
||||
flags_val = ir.Constant(ir.IntType(64), 0)
|
||||
|
||||
map_void_ptr = builder.bitcast(map_ptr, ir.PointerType())
|
||||
@ -496,38 +482,32 @@ def bpf_ringbuf_output_emitter(
|
||||
def handle_output_helper(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""
|
||||
Route output helper to the appropriate emitter based on map type.
|
||||
"""
|
||||
match map_sym_tab[map_ptr.name].type:
|
||||
match compilation_context.map_sym_tab[map_ptr.name].type:
|
||||
case BPFMapType.PERF_EVENT_ARRAY:
|
||||
return bpf_perf_event_output_handler(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab,
|
||||
struct_sym_tab,
|
||||
map_sym_tab,
|
||||
)
|
||||
case BPFMapType.RINGBUF:
|
||||
return bpf_ringbuf_output_emitter(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab,
|
||||
struct_sym_tab,
|
||||
map_sym_tab,
|
||||
)
|
||||
case _:
|
||||
logger.error("Unsupported map type for output helper.")
|
||||
@ -572,12 +552,10 @@ def emit_probe_read_kernel_str_call(builder, dst_ptr, dst_size, src_ptr):
|
||||
def bpf_probe_read_kernel_str_emitter(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""Emit LLVM IR for bpf_probe_read_kernel_str helper."""
|
||||
|
||||
@ -588,12 +566,12 @@ def bpf_probe_read_kernel_str_emitter(
|
||||
|
||||
# Get destination buffer (char array -> i8*)
|
||||
dst_ptr, dst_size = get_or_create_ptr_from_arg(
|
||||
func, module, call.args[0], builder, local_sym_tab, map_sym_tab, struct_sym_tab
|
||||
func, compilation_context, call.args[0], builder, local_sym_tab
|
||||
)
|
||||
|
||||
# Get source pointer (evaluate expression)
|
||||
src_ptr, src_type = get_ptr_from_arg(
|
||||
call.args[1], func, module, builder, local_sym_tab, map_sym_tab, struct_sym_tab
|
||||
call.args[1], func, compilation_context, builder, local_sym_tab
|
||||
)
|
||||
|
||||
# Emit the helper call
|
||||
@ -641,12 +619,10 @@ def emit_probe_read_kernel_call(builder, dst_ptr, dst_size, src_ptr):
|
||||
def bpf_probe_read_kernel_emitter(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""Emit LLVM IR for bpf_probe_read_kernel helper."""
|
||||
|
||||
@ -657,12 +633,12 @@ def bpf_probe_read_kernel_emitter(
|
||||
|
||||
# Get destination buffer (char array -> i8*)
|
||||
dst_ptr, dst_size = get_or_create_ptr_from_arg(
|
||||
func, module, call.args[0], builder, local_sym_tab, map_sym_tab, struct_sym_tab
|
||||
func, compilation_context, call.args[0], builder, local_sym_tab
|
||||
)
|
||||
|
||||
# Get source pointer (evaluate expression)
|
||||
src_ptr, src_type = get_ptr_from_arg(
|
||||
call.args[1], func, module, builder, local_sym_tab, map_sym_tab, struct_sym_tab
|
||||
call.args[1], func, compilation_context, builder, local_sym_tab
|
||||
)
|
||||
|
||||
# Emit the helper call
|
||||
@ -680,12 +656,10 @@ def bpf_probe_read_kernel_emitter(
|
||||
def bpf_get_prandom_u32_emitter(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""
|
||||
Emit LLVM IR for bpf_get_prandom_u32 helper function call.
|
||||
@ -710,12 +684,10 @@ def bpf_get_prandom_u32_emitter(
|
||||
def bpf_probe_read_emitter(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""
|
||||
Emit LLVM IR for bpf_probe_read helper function
|
||||
@ -726,31 +698,25 @@ def bpf_probe_read_emitter(
|
||||
return
|
||||
dst_ptr = get_or_create_ptr_from_arg(
|
||||
func,
|
||||
module,
|
||||
compilation_context,
|
||||
call.args[0],
|
||||
builder,
|
||||
local_sym_tab,
|
||||
map_sym_tab,
|
||||
struct_sym_tab,
|
||||
ir.IntType(8),
|
||||
)
|
||||
size_val = get_int_value_from_arg(
|
||||
call.args[1],
|
||||
func,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
local_sym_tab,
|
||||
map_sym_tab,
|
||||
struct_sym_tab,
|
||||
)
|
||||
src_ptr = get_or_create_ptr_from_arg(
|
||||
func,
|
||||
module,
|
||||
compilation_context,
|
||||
call.args[2],
|
||||
builder,
|
||||
local_sym_tab,
|
||||
map_sym_tab,
|
||||
struct_sym_tab,
|
||||
ir.IntType(8),
|
||||
)
|
||||
fn_type = ir.FunctionType(
|
||||
@ -783,12 +749,10 @@ def bpf_probe_read_emitter(
|
||||
def bpf_get_smp_processor_id_emitter(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""
|
||||
Emit LLVM IR for bpf_get_smp_processor_id helper function call.
|
||||
@ -810,12 +774,10 @@ def bpf_get_smp_processor_id_emitter(
|
||||
def bpf_get_current_uid_gid_emitter(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""
|
||||
Emit LLVM IR for bpf_get_current_uid_gid helper function call.
|
||||
@ -846,12 +808,10 @@ def bpf_get_current_uid_gid_emitter(
|
||||
def bpf_skb_store_bytes_emitter(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""
|
||||
Emit LLVM IR for bpf_skb_store_bytes helper function call.
|
||||
@ -875,30 +835,24 @@ def bpf_skb_store_bytes_emitter(
|
||||
offset_val = get_int_value_from_arg(
|
||||
call.args[0],
|
||||
func,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
local_sym_tab,
|
||||
map_sym_tab,
|
||||
struct_sym_tab,
|
||||
)
|
||||
from_ptr = get_or_create_ptr_from_arg(
|
||||
func,
|
||||
module,
|
||||
compilation_context,
|
||||
call.args[1],
|
||||
builder,
|
||||
local_sym_tab,
|
||||
map_sym_tab,
|
||||
struct_sym_tab,
|
||||
args_signature[2],
|
||||
)
|
||||
len_val = get_int_value_from_arg(
|
||||
call.args[2],
|
||||
func,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
local_sym_tab,
|
||||
map_sym_tab,
|
||||
struct_sym_tab,
|
||||
)
|
||||
if len(call.args) == 4:
|
||||
flags_val = get_flags_val(call.args[3], builder, local_sym_tab)
|
||||
@ -940,12 +894,10 @@ def bpf_skb_store_bytes_emitter(
|
||||
def bpf_ringbuf_reserve_emitter(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""
|
||||
Emit LLVM IR for bpf_ringbuf_reserve helper function call.
|
||||
@ -960,11 +912,9 @@ def bpf_ringbuf_reserve_emitter(
|
||||
size_val = get_int_value_from_arg(
|
||||
call.args[0],
|
||||
func,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
local_sym_tab,
|
||||
map_sym_tab,
|
||||
struct_sym_tab,
|
||||
)
|
||||
|
||||
map_void_ptr = builder.bitcast(map_ptr, ir.PointerType())
|
||||
@ -991,12 +941,10 @@ def bpf_ringbuf_reserve_emitter(
|
||||
def bpf_ringbuf_submit_emitter(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""
|
||||
Emit LLVM IR for bpf_ringbuf_submit helper function call.
|
||||
@ -1013,12 +961,10 @@ def bpf_ringbuf_submit_emitter(
|
||||
|
||||
data_ptr = get_or_create_ptr_from_arg(
|
||||
func,
|
||||
module,
|
||||
compilation_context,
|
||||
data_arg,
|
||||
builder,
|
||||
local_sym_tab,
|
||||
map_sym_tab,
|
||||
struct_sym_tab,
|
||||
ir.PointerType(ir.IntType(8)),
|
||||
)
|
||||
|
||||
@ -1050,12 +996,10 @@ def bpf_ringbuf_submit_emitter(
|
||||
def bpf_get_stack_emitter(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
):
|
||||
"""
|
||||
Emit LLVM IR for bpf_get_stack helper function call.
|
||||
@ -1068,7 +1012,7 @@ def bpf_get_stack_emitter(
|
||||
buf_arg = call.args[0]
|
||||
flags_arg = call.args[1] if len(call.args) == 2 else None
|
||||
buf_ptr, buf_size = get_buffer_ptr_and_size(
|
||||
buf_arg, builder, local_sym_tab, struct_sym_tab
|
||||
buf_arg, builder, local_sym_tab, compilation_context
|
||||
)
|
||||
flags_val = get_flags_val(flags_arg, builder, local_sym_tab)
|
||||
if isinstance(flags_val, int):
|
||||
@ -1098,12 +1042,10 @@ def bpf_get_stack_emitter(
|
||||
|
||||
def handle_helper_call(
|
||||
call,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab=None,
|
||||
map_sym_tab=None,
|
||||
struct_sym_tab=None,
|
||||
):
|
||||
"""Process a BPF helper function call and emit the appropriate LLVM IR."""
|
||||
|
||||
@ -1117,14 +1059,14 @@ def handle_helper_call(
|
||||
return handler(
|
||||
call,
|
||||
map_ptr,
|
||||
module,
|
||||
compilation_context,
|
||||
builder,
|
||||
func,
|
||||
local_sym_tab,
|
||||
struct_sym_tab,
|
||||
map_sym_tab,
|
||||
)
|
||||
|
||||
map_sym_tab = compilation_context.map_sym_tab
|
||||
|
||||
# Handle direct function calls (e.g., print(), ktime())
|
||||
if isinstance(call.func, ast.Name):
|
||||
return invoke_helper(call.func.id)
|
||||
|
||||
@ -3,7 +3,6 @@ import logging
|
||||
|
||||
from llvmlite import ir
|
||||
from pythonbpf.expr import (
|
||||
get_operand_value,
|
||||
eval_expr,
|
||||
access_struct_field,
|
||||
)
|
||||
@ -11,56 +10,38 @@ from pythonbpf.expr import (
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ScratchPoolManager:
|
||||
"""Manage the temporary helper variables in local_sym_tab"""
|
||||
|
||||
def __init__(self):
|
||||
self._counters = {}
|
||||
|
||||
@property
|
||||
def counter(self):
|
||||
return sum(self._counters.values())
|
||||
|
||||
def reset(self):
|
||||
self._counters.clear()
|
||||
logger.debug("Scratch pool counter reset to 0")
|
||||
|
||||
def _get_type_name(self, ir_type):
|
||||
if isinstance(ir_type, ir.PointerType):
|
||||
return "ptr"
|
||||
elif isinstance(ir_type, ir.IntType):
|
||||
return f"i{ir_type.width}"
|
||||
elif isinstance(ir_type, ir.ArrayType):
|
||||
return f"[{ir_type.count}x{self._get_type_name(ir_type.element)}]"
|
||||
else:
|
||||
return str(ir_type).replace(" ", "")
|
||||
|
||||
def get_next_temp(self, local_sym_tab, expected_type=None):
|
||||
# Default to i64 if no expected type provided
|
||||
type_name = self._get_type_name(expected_type) if expected_type else "i64"
|
||||
if type_name not in self._counters:
|
||||
self._counters[type_name] = 0
|
||||
|
||||
counter = self._counters[type_name]
|
||||
temp_name = f"__helper_temp_{type_name}_{counter}"
|
||||
self._counters[type_name] += 1
|
||||
|
||||
if temp_name not in local_sym_tab:
|
||||
raise ValueError(
|
||||
f"Scratch pool exhausted or inadequate: {temp_name}. "
|
||||
f"Type: {type_name} Counter: {counter}"
|
||||
)
|
||||
|
||||
logger.debug(f"Using {temp_name} for type {type_name}")
|
||||
return local_sym_tab[temp_name].var, temp_name
|
||||
# NOTE: ScratchPoolManager is now in context.py
|
||||
|
||||
|
||||
_temp_pool_manager = ScratchPoolManager() # Singleton instance
|
||||
def get_ptr_from_arg(arg, compilation_context, builder, local_sym_tab):
|
||||
"""Helper to get a pointer value from an argument."""
|
||||
# This is a bit duplicative of logic in eval_expr but simplified for helpers
|
||||
# We might need to handle more cases here or defer to eval_expr
|
||||
|
||||
# Simple check for name
|
||||
if isinstance(arg, ast.Name):
|
||||
if arg.id in local_sym_tab:
|
||||
sym = local_sym_tab[arg.id]
|
||||
if isinstance(sym.ir_type, ir.PointerType):
|
||||
return builder.load(sym.var)
|
||||
# If it's an array/struct we might need GEP depending on how it was allocated
|
||||
# For now assume load returns the pointer/value
|
||||
return builder.load(sym.var)
|
||||
|
||||
def reset_scratch_pool():
|
||||
"""Reset the scratch pool counter"""
|
||||
_temp_pool_manager.reset()
|
||||
# Use eval_expr for general case
|
||||
val = eval_expr(
|
||||
None,
|
||||
compilation_context.module,
|
||||
builder,
|
||||
arg,
|
||||
local_sym_tab,
|
||||
compilation_context.map_sym_tab,
|
||||
compilation_context.structs_sym_tab,
|
||||
)
|
||||
if val and isinstance(val[0].type, ir.PointerType):
|
||||
return val[0]
|
||||
|
||||
return None
|
||||
|
||||
|
||||
# ============================================================================
|
||||
@ -75,11 +56,15 @@ def get_var_ptr_from_name(var_name, local_sym_tab):
|
||||
raise ValueError(f"Variable '{var_name}' not found in local symbol table")
|
||||
|
||||
|
||||
def create_int_constant_ptr(value, builder, local_sym_tab, int_width=64):
|
||||
def create_int_constant_ptr(
|
||||
value, builder, compilation_context, local_sym_tab, int_width=64
|
||||
):
|
||||
"""Create a pointer to an integer constant."""
|
||||
|
||||
int_type = ir.IntType(int_width)
|
||||
ptr, temp_name = _temp_pool_manager.get_next_temp(local_sym_tab, int_type)
|
||||
ptr, temp_name = compilation_context.scratch_pool.get_next_temp(
|
||||
local_sym_tab, int_type
|
||||
)
|
||||
logger.info(f"Using temp variable '{temp_name}' for int constant {value}")
|
||||
const_val = ir.Constant(int_type, value)
|
||||
builder.store(const_val, ptr)
|
||||
@ -88,12 +73,10 @@ def create_int_constant_ptr(value, builder, local_sym_tab, int_width=64):
|
||||
|
||||
def get_or_create_ptr_from_arg(
|
||||
func,
|
||||
module,
|
||||
compilation_context,
|
||||
arg,
|
||||
builder,
|
||||
local_sym_tab,
|
||||
map_sym_tab,
|
||||
struct_sym_tab=None,
|
||||
expected_type=None,
|
||||
):
|
||||
"""Extract or create pointer from the call arguments."""
|
||||
@ -102,16 +85,22 @@ def get_or_create_ptr_from_arg(
|
||||
sz = None
|
||||
if isinstance(arg, ast.Name):
|
||||
# Stack space is already allocated
|
||||
ptr = get_var_ptr_from_name(arg.id, local_sym_tab)
|
||||
if arg.id in local_sym_tab:
|
||||
ptr = local_sym_tab[arg.id].var
|
||||
else:
|
||||
raise ValueError(f"Variable '{arg.id}' not found")
|
||||
elif isinstance(arg, ast.Constant) and isinstance(arg.value, int):
|
||||
int_width = 64 # Default to i64
|
||||
if expected_type and isinstance(expected_type, ir.IntType):
|
||||
int_width = expected_type.width
|
||||
ptr = create_int_constant_ptr(arg.value, builder, local_sym_tab, int_width)
|
||||
ptr = create_int_constant_ptr(
|
||||
arg.value, builder, compilation_context, local_sym_tab, int_width
|
||||
)
|
||||
elif isinstance(arg, ast.Attribute):
|
||||
# A struct field
|
||||
struct_name = arg.value.id
|
||||
field_name = arg.attr
|
||||
struct_sym_tab = compilation_context.structs_sym_tab
|
||||
|
||||
if not local_sym_tab or struct_name not in local_sym_tab:
|
||||
raise ValueError(f"Struct '{struct_name}' not found")
|
||||
@ -136,7 +125,7 @@ def get_or_create_ptr_from_arg(
|
||||
and field_type.element.width == 8
|
||||
):
|
||||
ptr, sz = get_char_array_ptr_and_size(
|
||||
arg, builder, local_sym_tab, struct_sym_tab, func
|
||||
arg, builder, local_sym_tab, compilation_context, func
|
||||
)
|
||||
if not ptr:
|
||||
raise ValueError("Failed to get char array pointer from struct field")
|
||||
@ -146,13 +135,15 @@ def get_or_create_ptr_from_arg(
|
||||
else:
|
||||
# NOTE: For any integer expression reaching this branch, it is probably a struct field or a binop
|
||||
# Evaluate the expression and store the result in a temp variable
|
||||
val = get_operand_value(
|
||||
func, module, arg, builder, local_sym_tab, map_sym_tab, struct_sym_tab
|
||||
)
|
||||
val = eval_expr(func, compilation_context, builder, arg, local_sym_tab)
|
||||
if val:
|
||||
val = val[0]
|
||||
if val is None:
|
||||
raise ValueError("Failed to evaluate expression for helper arg.")
|
||||
|
||||
ptr, temp_name = _temp_pool_manager.get_next_temp(local_sym_tab, expected_type)
|
||||
ptr, temp_name = compilation_context.scratch_pool.get_next_temp(
|
||||
local_sym_tab, expected_type
|
||||
)
|
||||
logger.info(f"Using temp variable '{temp_name}' for expression result")
|
||||
if (
|
||||
isinstance(val.type, ir.IntType)
|
||||
@ -188,8 +179,9 @@ def get_flags_val(arg, builder, local_sym_tab):
|
||||
)
|
||||
|
||||
|
||||
def get_data_ptr_and_size(data_arg, local_sym_tab, struct_sym_tab):
|
||||
def get_data_ptr_and_size(data_arg, local_sym_tab, compilation_context):
|
||||
"""Extract data pointer and size information for perf event output."""
|
||||
struct_sym_tab = compilation_context.structs_sym_tab
|
||||
if isinstance(data_arg, ast.Name):
|
||||
data_name = data_arg.id
|
||||
if local_sym_tab and data_name in local_sym_tab:
|
||||
@ -213,8 +205,9 @@ def get_data_ptr_and_size(data_arg, local_sym_tab, struct_sym_tab):
|
||||
)
|
||||
|
||||
|
||||
def get_buffer_ptr_and_size(buf_arg, builder, local_sym_tab, struct_sym_tab):
|
||||
def get_buffer_ptr_and_size(buf_arg, builder, local_sym_tab, compilation_context):
|
||||
"""Extract buffer pointer and size from either a struct field or variable."""
|
||||
struct_sym_tab = compilation_context.structs_sym_tab
|
||||
|
||||
# Case 1: Struct field (obj.field)
|
||||
if isinstance(buf_arg, ast.Attribute):
|
||||
@ -268,9 +261,10 @@ def get_buffer_ptr_and_size(buf_arg, builder, local_sym_tab, struct_sym_tab):
|
||||
|
||||
|
||||
def get_char_array_ptr_and_size(
|
||||
buf_arg, builder, local_sym_tab, struct_sym_tab, func=None
|
||||
buf_arg, builder, local_sym_tab, compilation_context, func=None
|
||||
):
|
||||
"""Get pointer to char array and its size."""
|
||||
struct_sym_tab = compilation_context.structs_sym_tab
|
||||
|
||||
# Struct field: obj.field
|
||||
if isinstance(buf_arg, ast.Attribute) and isinstance(buf_arg.value, ast.Name):
|
||||
@ -351,34 +345,10 @@ def _is_char_array(ir_type):
|
||||
)
|
||||
|
||||
|
||||
def get_ptr_from_arg(
|
||||
arg, func, module, builder, local_sym_tab, map_sym_tab, struct_sym_tab
|
||||
):
|
||||
"""Evaluate argument and return pointer value"""
|
||||
|
||||
result = eval_expr(
|
||||
func, module, builder, arg, local_sym_tab, map_sym_tab, struct_sym_tab
|
||||
)
|
||||
|
||||
if not result:
|
||||
raise ValueError("Failed to evaluate argument")
|
||||
|
||||
val, val_type = result
|
||||
|
||||
if not isinstance(val_type, ir.PointerType):
|
||||
raise ValueError(f"Expected pointer type, got {val_type}")
|
||||
|
||||
return val, val_type
|
||||
|
||||
|
||||
def get_int_value_from_arg(
|
||||
arg, func, module, builder, local_sym_tab, map_sym_tab, struct_sym_tab
|
||||
):
|
||||
def get_int_value_from_arg(arg, func, compilation_context, builder, local_sym_tab):
|
||||
"""Evaluate argument and return integer value"""
|
||||
|
||||
result = eval_expr(
|
||||
func, module, builder, arg, local_sym_tab, map_sym_tab, struct_sym_tab
|
||||
)
|
||||
result = eval_expr(func, compilation_context, builder, arg, local_sym_tab)
|
||||
|
||||
if not result:
|
||||
raise ValueError("Failed to evaluate argument")
|
||||
|
||||
Reference in New Issue
Block a user