Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
5cbd9a5
Add bpf_get_prandom_u32 helper
r41k0u Oct 26, 2025
0006e26
Add passing test for bpf_get_prandom_u32 implementation
r41k0u Oct 26, 2025
5bf60d6
Add BPF_PROBE_READ to HelperIDs
r41k0u Nov 1, 2025
2257c17
Implement BPF_PROBE_READ helper
r41k0u Nov 1, 2025
ec2ea83
Fix imports and type issues for bpf_probe_read
r41k0u Nov 1, 2025
70a04f5
Add passing test for bpf_probe_read helper
r41k0u Nov 1, 2025
82cac8f
Add BPF_GET_SMP_PROCESSOR_ID to HelperIDs
r41k0u Nov 1, 2025
19deded
Implement BPF_GET_SMP_PROCESSOR_ID helper
r41k0u Nov 1, 2025
dabb8bf
Fix imports for BPF_GET_SMP_PROCESSOR_ID
r41k0u Nov 1, 2025
f9ee43e
Add passing test smp_processor_id.py for helpers
r41k0u Nov 1, 2025
8b28a92
Add helpful TODO to PID_TGID emitter
r41k0u Nov 1, 2025
b7c1e92
Add BPF_GET_CURRENT_UID_GID to HelperIDs
r41k0u Nov 1, 2025
5b7769d
Implement bpf_get_current_uid_gid_emitter
r41k0u Nov 1, 2025
4884ed7
Fix imports for bpf_get_current_uid_gid
r41k0u Nov 1, 2025
4efd322
Add passing uid_gid helper test
r41k0u Nov 1, 2025
c5de92b
Add BPF_SKB_STORE_BYTES to HelperIDs
r41k0u Nov 1, 2025
f757a32
Implement bpf_skb_store_bytes_emitter
r41k0u Nov 1, 2025
67c9d9b
Fix imports for bpf_skb_store_bytes
r41k0u Nov 1, 2025
5e37178
Fix the number of args for skb_store_bytes by making the first arg im…
r41k0u Nov 3, 2025
33e18f6
Introduce HelperSignature in HelperHandlerRegistry
r41k0u Nov 3, 2025
d8cddb9
Add signature extraction to HelperHandlerRegistry
r41k0u Nov 3, 2025
752f564
Change count_temps_in_call to return hashmap of types
r41k0u Nov 4, 2025
123a92a
Change allocation pass to generate typed temp variables
r41k0u Nov 4, 2025
963e2a8
Change ScratchPoolManager to use typed scratch space
r41k0u Nov 4, 2025
7d29790
Make use of new get_next_temp in helpers
r41k0u Nov 4, 2025
3078d42
Add typed scratch space support to the bpf_skb_store_bytes helper
r41k0u Nov 4, 2025
338d499
Fix count_temps_in_call to only look for Pointer args of a helper_sig
r41k0u Nov 5, 2025
3e6cea2
Move get_struct_char_array_ptr from helper/printk_formatter to helper…
r41k0u Nov 5, 2025
5b36726
Make bpf_skb_store_bytes work
r41k0u Nov 5, 2025
2e37726
Add signature relection for all helper handlers except print
r41k0u Nov 6, 2025
3ccd3f7
Add expected types for pointer creation of args in probe_read handler
r41k0u Nov 6, 2025
2f4a7d2
Remove get_struct_char_array_ptr in favour of get_char_array_ptr_and_…
r41k0u Nov 7, 2025
be62972
Fix ScratchPoolManager::counter
r41k0u Nov 7, 2025
b5a3494
Fix typo in get_or_create_ptr_from_arg
r41k0u Nov 7, 2025
6c85b24
Init sz in get_or_create_ptr_from_arg
r41k0u Nov 7, 2025
cf99b3b
Fix call to get_or_create_ptr_from_arg for probe_read_str
r41k0u Nov 7, 2025
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
30 changes: 23 additions & 7 deletions pythonbpf/allocation_pass.py
Original file line number Diff line number Diff line change
Expand Up @@ -199,17 +199,33 @@ def _allocate_for_binop(builder, var_name, local_sym_tab):
logger.info(f"Pre-allocated {var_name} for binop result")


def _get_type_name(ir_type):
"""Get a string representation of an IR type."""
if isinstance(ir_type, ir.IntType):
return f"i{ir_type.width}"
elif isinstance(ir_type, ir.PointerType):
return "ptr"
elif isinstance(ir_type, ir.ArrayType):
return f"[{ir_type.count}x{_get_type_name(ir_type.element)}]"
else:
return str(ir_type).replace(" ", "")


def allocate_temp_pool(builder, max_temps, local_sym_tab):
"""Allocate the temporary scratch space pool for helper arguments."""
if max_temps == 0:
if not max_temps:
logger.info("No temp pool allocation needed")
return

logger.info(f"Allocating temp pool of {max_temps} variables")
for i in range(max_temps):
temp_name = f"__helper_temp_{i}"
temp_var = builder.alloca(ir.IntType(64), name=temp_name)
temp_var.align = 8
local_sym_tab[temp_name] = LocalSymbol(temp_var, ir.IntType(64))
for tmp_type, cnt in max_temps.items():
type_name = _get_type_name(tmp_type)
logger.info(f"Allocating temp pool of {cnt} variables of type {type_name}")
for i in range(cnt):
temp_name = f"__helper_temp_{type_name}_{i}"
temp_var = builder.alloca(tmp_type, name=temp_name)
temp_var.align = _get_alignment(tmp_type)
local_sym_tab[temp_name] = LocalSymbol(temp_var, tmp_type)
logger.debug(f"Allocated temp variable: {temp_name}")


def _allocate_for_name(builder, var_name, rval, local_sym_tab):
Expand Down
32 changes: 23 additions & 9 deletions pythonbpf/functions/functions_pass.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
def count_temps_in_call(call_node, local_sym_tab):
"""Count the number of temporary variables needed for a function call."""

count = 0
count = {}
is_helper = False

# NOTE: We exclude print calls for now
Expand All @@ -43,21 +43,28 @@ def count_temps_in_call(call_node, local_sym_tab):
and call_node.func.id != "print"
):
is_helper = True
func_name = call_node.func.id
elif isinstance(call_node.func, ast.Attribute):
if HelperHandlerRegistry.has_handler(call_node.func.attr):
is_helper = True
func_name = call_node.func.attr

if not is_helper:
return 0
return {} # No temps needed

for arg in call_node.args:
for arg_idx in range(len(call_node.args)):
# NOTE: Count all non-name arguments
# For struct fields, if it is being passed as an argument,
# The struct object should already exist in the local_sym_tab
if not isinstance(arg, ast.Name) and not (
arg = call_node.args[arg_idx]
if isinstance(arg, ast.Name) or (
isinstance(arg, ast.Attribute) and arg.value.id in local_sym_tab
):
count += 1
continue
param_type = HelperHandlerRegistry.get_param_type(func_name, arg_idx)
if isinstance(param_type, ir.PointerType):
pointee_type = param_type.pointee
count[pointee_type] = count.get(pointee_type, 0) + 1

return count

Expand Down Expand Up @@ -93,11 +100,15 @@ def handle_if_allocation(
def allocate_mem(
module, builder, body, func, ret_type, map_sym_tab, local_sym_tab, structs_sym_tab
):
max_temps_needed = 0
max_temps_needed = {}

def merge_type_counts(count_dict):
nonlocal max_temps_needed
for typ, cnt in count_dict.items():
max_temps_needed[typ] = max(max_temps_needed.get(typ, 0), cnt)

def update_max_temps_for_stmt(stmt):
nonlocal max_temps_needed
temps_needed = 0

if isinstance(stmt, ast.If):
for s in stmt.body:
Expand All @@ -106,10 +117,13 @@ def update_max_temps_for_stmt(stmt):
update_max_temps_for_stmt(s)
return

stmt_temps = {}
for node in ast.walk(stmt):
if isinstance(node, ast.Call):
temps_needed += count_temps_in_call(node, local_sym_tab)
max_temps_needed = max(max_temps_needed, temps_needed)
call_temps = count_temps_in_call(node, local_sym_tab)
for typ, cnt in call_temps.items():
stmt_temps[typ] = stmt_temps.get(typ, 0) + cnt
merge_type_counts(stmt_temps)

for stmt in body:
update_max_temps_for_stmt(stmt)
Expand Down
20 changes: 19 additions & 1 deletion pythonbpf/helper/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,20 @@
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
from .helpers import ktime, pid, deref, comm, probe_read_str, XDP_DROP, XDP_PASS
from .helpers import (
ktime,
pid,
deref,
comm,
probe_read_str,
random,
probe_read,
smp_processor_id,
uid,
skb_store_bytes,
XDP_DROP,
XDP_PASS,
)


# Register the helper handler with expr module
Expand Down Expand Up @@ -65,6 +78,11 @@ def helper_call_handler(
"deref",
"comm",
"probe_read_str",
"random",
"probe_read",
"smp_processor_id",
"uid",
"skb_store_bytes",
"XDP_DROP",
"XDP_PASS",
]
Loading