From a124476583a379c9737d501980172b426012c432 Mon Sep 17 00:00:00 2001 From: Pragyansh Chaturvedi Date: Sat, 20 Sep 2025 04:30:08 +0530 Subject: [PATCH] big overhaul of debug info and params passed to maps --- demo/pybpf1.py | 2 +- demo/pybpf2.py | 2 +- demo/pybpf3.py | 2 +- examples/execve2.py | 2 +- examples/execve3.py | 16 +++---- examples/execve4.py | 2 +- examples/execve5.py | 2 +- pythonbpf/codegen.py | 9 ++-- pythonbpf/maps.py | 12 +++--- pythonbpf/maps_pass.py | 97 +++++++++++++++++++----------------------- 10 files changed, 69 insertions(+), 77 deletions(-) diff --git a/demo/pybpf1.py b/demo/pybpf1.py index 435fc10..409e553 100644 --- a/demo/pybpf1.py +++ b/demo/pybpf1.py @@ -14,7 +14,7 @@ from ctypes import c_void_p, c_int64 @bpf @map def count() -> HashMap: - return HashMap(key_type=c_int64, value_type=c_int64, max_entries=1) + return HashMap(key=c_int64, value=c_int64, max_entries=1) @bpf diff --git a/demo/pybpf2.py b/demo/pybpf2.py index 51b91e6..94e0d6a 100644 --- a/demo/pybpf2.py +++ b/demo/pybpf2.py @@ -13,7 +13,7 @@ from ctypes import c_void_p, c_int64, c_uint64 @bpf @map def last() -> HashMap: - return HashMap(key_type=c_uint64, value_type=c_uint64, max_entries=3) + return HashMap(key=c_uint64, value=c_uint64, max_entries=3) @bpf diff --git a/demo/pybpf3.py b/demo/pybpf3.py index 427df54..13897c1 100644 --- a/demo/pybpf3.py +++ b/demo/pybpf3.py @@ -13,7 +13,7 @@ from ctypes import c_void_p, c_int64, c_uint64 @bpf @map def last() -> HashMap: - return HashMap(key_type=c_uint64, value_type=c_uint64, max_entries=3) + return HashMap(key=c_uint64, value=c_uint64, max_entries=3) @bpf diff --git a/examples/execve2.py b/examples/execve2.py index c0bbc2a..fadc396 100644 --- a/examples/execve2.py +++ b/examples/execve2.py @@ -7,7 +7,7 @@ from pythonbpf.maps import HashMap @bpf @map def last() -> HashMap: - return HashMap(key_type=c_uint64, value_type=c_uint64, max_entries=1) + return HashMap(key=c_uint64, value=c_uint64, max_entries=1) @bpf diff --git a/examples/execve3.py b/examples/execve3.py index 88ed105..f636a34 100644 --- a/examples/execve3.py +++ b/examples/execve3.py @@ -8,7 +8,7 @@ from ctypes import c_void_p, c_int64, c_int32, c_uint64 @bpf @map def last() -> HashMap: - return HashMap(key_type=c_uint64, value_type=c_uint64, max_entries=3) + return HashMap(key=c_uint64, value=c_uint64, max_entries=3) @bpf @@ -25,23 +25,23 @@ def hello_again(ctx: c_void_p) -> c_int64: print("exited") key = 0 delta = 0 + dddelta = 0 tsp = last().lookup(key) if True: delta = ktime() ddelta = deref(delta) - if ddelta < 1000000000: + ttsp = deref(deref(tsp)) + dddelta = ddelta - ttsp + if dddelta < 1000000000: print("execve called within last second") last().delete(key) ts = ktime() last().update(key, ts) - + va = 8 - nm = 5 ^ va + nm = 5 + va al = 6 & 3 - ru = (nm + al) + al - print(f"this is a variable {ru}") -# st = "st" -# last().update(key, ts) + print(f"this is a variable {nm}") return c_int64(0) diff --git a/examples/execve4.py b/examples/execve4.py index 31dbd2d..9c44b1f 100644 --- a/examples/execve4.py +++ b/examples/execve4.py @@ -8,7 +8,7 @@ from ctypes import c_void_p, c_int64, c_int32, c_uint64 @bpf @map def last() -> HashMap: - return HashMap(key_type=c_uint64, value_type=c_uint64, max_entries=3) + return HashMap(key=c_uint64, value=c_uint64, max_entries=3) @bpf diff --git a/examples/execve5.py b/examples/execve5.py index e016728..45d51b0 100644 --- a/examples/execve5.py +++ b/examples/execve5.py @@ -7,7 +7,7 @@ from ctypes import c_void_p, c_int64, c_int32, c_uint64 @bpf @map def events() -> PerfEventArray: - return PerfEventArray(key_type=c_uint64, value_type=c_uint64) + return PerfEventArray(key_size=c_int32, value_size=c_int32) @bpf @section("tracepoint/syscalls/sys_enter_clone") diff --git a/pythonbpf/codegen.py b/pythonbpf/codegen.py index 0b36bcd..589f0d1 100644 --- a/pythonbpf/codegen.py +++ b/pythonbpf/codegen.py @@ -9,6 +9,7 @@ import subprocess import inspect from pathlib import Path + def find_bpf_chunks(tree): """Find all functions decorated with @bpf in the AST.""" bpf_functions = [] @@ -49,7 +50,7 @@ def compile_to_ir(filename: str, output: str): "filename": filename, "directory": os.path.dirname(filename) }) - + module._debug_compile_unit = module.add_debug_info("DICompileUnit", { # type: ignore "language": 29, # DW_LANG_C11 "file": module._file_metadata, # type: ignore @@ -61,7 +62,8 @@ def compile_to_ir(filename: str, output: str): "nameTableKind": 0 }, is_distinct=True) - module.add_named_metadata("llvm.dbg.cu", module._debug_compile_unit) # type: ignore + module.add_named_metadata( + "llvm.dbg.cu", module._debug_compile_unit) # type: ignore processor(source, filename, module) @@ -95,6 +97,7 @@ def compile_to_ir(filename: str, output: str): return output + def compile(): # Look one level up the stack to the caller of this function caller_frame = inspect.stack()[1] @@ -110,4 +113,4 @@ def compile(): str(ll_file), "-o", str(o_file) ], check=True) - print(f"Object written to {o_file}") + print(f"Object written to {o_file}, {ll_file} can be removed") diff --git a/pythonbpf/maps.py b/pythonbpf/maps.py index 4a1136b..25bc360 100644 --- a/pythonbpf/maps.py +++ b/pythonbpf/maps.py @@ -1,7 +1,7 @@ class HashMap: - def __init__(self, key_type, value_type, max_entries): - self.key_type = key_type - self.value_type = value_type + def __init__(self, key, value, max_entries): + self.key = key + self.value = value self.max_entries = max_entries self.entries = {} @@ -26,7 +26,7 @@ class HashMap: class PerfEventArray: - def __init__(self, key_type, value_type): - self.key_type = key_type - self.value_type = value_type + def __init__(self, key_size, value_size): + self.key_type = key_size + self.value_type = value_size self.entries = {} diff --git a/pythonbpf/maps_pass.py b/pythonbpf/maps_pass.py index 6157ccc..38deecb 100644 --- a/pythonbpf/maps_pass.py +++ b/pythonbpf/maps_pass.py @@ -30,16 +30,12 @@ BPF_MAP_MAPPINGS = { def create_bpf_map(module, map_name, map_params): """Create a BPF map in the module with the given parameters and debug info""" - map_type_str = map_params.get("map_type", "HASH") + map_type_str = map_params.get("type", "HASH") map_type = BPF_MAP_MAPPINGS.get(map_type_str) # Create the anonymous struct type for BPF map - map_struct_type = ir.LiteralStructType([ - ir.PointerType(), - ir.PointerType(), - ir.PointerType(), - ir.PointerType() - ]) + map_struct_type = ir.LiteralStructType( + [ir.PointerType() for _ in range(len(map_params))]) # Create the global variable map_global = ir.GlobalVariable(module, map_struct_type, name=map_name) @@ -79,7 +75,7 @@ def create_map_debug_info(module, map_global, map_name, map_params): # Create array type for map type field (array of 1 unsigned int) array_subrange = module.add_debug_info( - "DISubrange", {"count": BPF_MAP_MAPPINGS[map_params.get("map_type", "HASH")]}) + "DISubrange", {"count": BPF_MAP_MAPPINGS[map_params.get("type", "HASH")]}) array_type = module.add_debug_info("DICompositeType", { "tag": dc.DW_TAG_array_type, "baseType": uint_type, @@ -96,13 +92,15 @@ def create_map_debug_info(module, map_global, map_name, map_params): key_ptr = module.add_debug_info("DIDerivedType", { "tag": dc.DW_TAG_pointer_type, - "baseType": uint_type, # Adjust based on actual key type + # Adjust based on actual key type + "baseType": array_type if "key_size" in map_params else uint_type, "size": 64 }) value_ptr = module.add_debug_info("DIDerivedType", { "tag": dc.DW_TAG_pointer_type, - "baseType": ulong_type, # Adjust based on actual value type + # Adjust based on actual value type + "baseType": array_type if "value_size" in map_params else ulong_type, "size": 64 }) @@ -110,15 +108,26 @@ def create_map_debug_info(module, map_global, map_name, map_params): # Create struct members # scope field does not appear for some reason - type_member = module.add_debug_info("DIDerivedType", { - "tag": dc.DW_TAG_member, - "name": "type", - "file": file_metadata, - "baseType": type_ptr, - "size": 64, - "offset": 0 - }) - elements_arr.append(type_member) + cnt = 0 + for elem in map_params: + if elem == "max_entries": + continue + if elem == "type": + ptr = type_ptr + elif "key" in elem: + ptr = key_ptr + else: + ptr = value_ptr + member = module.add_debug_info("DIDerivedType", { + "tag": dc.DW_TAG_member, + "name": elem, + "file": file_metadata, + "baseType": ptr, + "size": 64, + "offset": cnt * 64 + }) + elements_arr.append(member) + cnt += 1 if "max_entries" in map_params: array_subrange_max_entries = module.add_debug_info( @@ -140,30 +149,10 @@ def create_map_debug_info(module, map_global, map_name, map_params): "file": file_metadata, "baseType": max_entries_ptr, "size": 64, - "offset": 64 + "offset": cnt * 64 }) elements_arr.append(max_entries_member) - key_member = module.add_debug_info("DIDerivedType", { - "tag": dc.DW_TAG_member, - "name": "key", - "file": file_metadata, - "baseType": key_ptr, - "size": 64, - "offset": 128 - }) - elements_arr.append(key_member) - - value_member = module.add_debug_info("DIDerivedType", { - "tag": dc.DW_TAG_member, - "name": "value", - "file": file_metadata, - "baseType": value_ptr, - "size": 64, - "offset": 192 - }) - elements_arr.append(value_member) - # Create the struct type struct_type = module.add_debug_info("DICompositeType", { "tag": dc.DW_TAG_structure_type, @@ -196,23 +185,23 @@ def create_map_debug_info(module, map_global, map_name, map_params): def process_hash_map(map_name, rval, module): print(f"Creating HashMap map: {map_name}") - map_params: dict[str, object] = {"map_type": "HASH"} + map_params: dict[str, object] = {"type": "HASH"} # Assuming order: key_type, value_type, max_entries if len(rval.args) >= 1 and isinstance(rval.args[0], ast.Name): - map_params["key_type"] = rval.args[0].id + map_params["key"] = rval.args[0].id if len(rval.args) >= 2 and isinstance(rval.args[1], ast.Name): - map_params["value_type"] = rval.args[1].id + map_params["value"] = rval.args[1].id if len(rval.args) >= 3 and isinstance(rval.args[2], ast.Constant): const_val = rval.args[2].value if isinstance(const_val, (int, str)): # safe check map_params["max_entries"] = const_val for keyword in rval.keywords: - if keyword.arg == "key_type" and isinstance(keyword.value, ast.Name): - map_params["key_type"] = keyword.value.id - elif keyword.arg == "value_type" and isinstance(keyword.value, ast.Name): - map_params["value_type"] = keyword.value.id + if keyword.arg == "key" and isinstance(keyword.value, ast.Name): + map_params["key"] = keyword.value.id + elif keyword.arg == "value" and isinstance(keyword.value, ast.Name): + map_params["value"] = keyword.value.id elif keyword.arg == "max_entries" and isinstance(keyword.value, ast.Constant): const_val = keyword.value.value if isinstance(const_val, (int, str)): @@ -224,18 +213,18 @@ def process_hash_map(map_name, rval, module): def process_perf_event_map(map_name, rval, module): print(f"Creating PerfEventArray map: {map_name}") - map_params = {"map_type": "PERF_EVENT_ARRAY"} + map_params = {"type": "PERF_EVENT_ARRAY"} if len(rval.args) >= 1 and isinstance(rval.args[0], ast.Name): - map_params["key_type"] = rval.args[0].id + map_params["key_size"] = rval.args[0].id if len(rval.args) >= 2 and isinstance(rval.args[1], ast.Name): - map_params["value_type"] = rval.args[1].id + map_params["value_size"] = rval.args[1].id for keyword in rval.keywords: - if keyword.arg == "key_type" and isinstance(keyword.value, ast.Name): - map_params["key_type"] = keyword.value.id - elif keyword.arg == "value_type" and isinstance(keyword.value, ast.Name): - map_params["value_type"] = keyword.value.id + if keyword.arg == "key_size" and isinstance(keyword.value, ast.Name): + map_params["key_size"] = keyword.value.id + elif keyword.arg == "value_size" and isinstance(keyword.value, ast.Name): + map_params["value_size"] = keyword.value.id print(f"Map parameters: {map_params}") return create_bpf_map(module, map_name, map_params)