diff --git a/pythonbpf/debuginfo/debug_info_generator.py b/pythonbpf/debuginfo/debug_info_generator.py index 1848ecc..62f0cc3 100644 --- a/pythonbpf/debuginfo/debug_info_generator.py +++ b/pythonbpf/debuginfo/debug_info_generator.py @@ -81,6 +81,20 @@ class DebugInfoGenerator: }, ) + def create_array_type_vmlinux(self, type_info: Any, count: int) -> Any: + """Create an array type of the given base type with specified count""" + base_type, type_sizing = type_info + subrange = self.module.add_debug_info("DISubrange", {"count": count}) + return self.module.add_debug_info( + "DICompositeType", + { + "tag": dc.DW_TAG_array_type, + "baseType": base_type, + "size": type_sizing, + "elements": [subrange], + }, + ) + @staticmethod def _compute_array_size(base_type: Any, count: int) -> int: # Extract size from base_type if possible @@ -101,7 +115,9 @@ class DebugInfoGenerator: }, ) - def create_struct_member_vmlinux(self, name: str, base_type_with_size: Any, offset: int) -> Any: + def create_struct_member_vmlinux( + self, name: str, base_type_with_size: Any, offset: int + ) -> Any: """Create a struct member with the given name, type, and offset""" base_type, type_size = base_type_with_size return self.module.add_debug_info( diff --git a/pythonbpf/vmlinux_parser/ir_gen/debug_info_gen.py b/pythonbpf/vmlinux_parser/ir_gen/debug_info_gen.py index 15b21c5..0ec6be3 100644 --- a/pythonbpf/vmlinux_parser/ir_gen/debug_info_gen.py +++ b/pythonbpf/vmlinux_parser/ir_gen/debug_info_gen.py @@ -2,12 +2,15 @@ from pythonbpf.debuginfo import DebugInfoGenerator, dwarf_constants as dc from ..dependency_node import DependencyNode import ctypes import logging -from typing import List, Any, Tuple, Optional +from typing import List, Any, Tuple logger = logging.getLogger(__name__) + def debug_info_generation( - struct: DependencyNode, llvm_module, generated_debug_info: List[Tuple[DependencyNode, Any]] + struct: DependencyNode, + llvm_module, + generated_debug_info: List[Tuple[DependencyNode, Any]], ) -> Any: """ Generate DWARF debug information for a struct defined in a DependencyNode. @@ -54,11 +57,11 @@ def debug_info_generation( def _get_field_debug_type( - field_name: str, - field, - generator: DebugInfoGenerator, - parent_struct: DependencyNode, - generated_debug_info: List[Tuple[DependencyNode, Any]] + field_name: str, + field, + generator: DebugInfoGenerator, + parent_struct: DependencyNode, + generated_debug_info: List[Tuple[DependencyNode, Any]], ) -> tuple[Any, int]: """ Determine the appropriate debug type for a field based on its Python/ctypes type. @@ -77,8 +80,12 @@ def _get_field_debug_type( if field.ctype_complex_type is not None: if issubclass(field.ctype_complex_type, ctypes.Array): # Handle array types - element_type, base_type_size = _get_basic_debug_type(field.containing_type, generator) - return generator.create_array_type(element_type, field.type_size), field.type_size * base_type_size + element_type, base_type_size = _get_basic_debug_type( + field.containing_type, generator + ) + return generator.create_array_type_vmlinux( + (element_type, base_type_size * field.type_size), field.type_size + ), field.type_size * base_type_size elif issubclass(field.ctype_complex_type, ctypes._Pointer): # Handle pointer types pointee_type, _ = _get_basic_debug_type(field.containing_type, generator) @@ -136,7 +143,9 @@ def _get_basic_debug_type(ctype, generator: DebugInfoGenerator) -> Any: elif ctype == ctypes.c_longlong or ctype == ctypes.c_int64: return generator.get_basic_type("long long", 64, dc.DW_ATE_signed), 64 elif ctype == ctypes.c_ulonglong or ctype == ctypes.c_uint64: - return generator.get_basic_type("unsigned long long", 64, dc.DW_ATE_unsigned), 64 + return generator.get_basic_type( + "unsigned long long", 64, dc.DW_ATE_unsigned + ), 64 elif ctype == ctypes.c_float: return generator.get_basic_type("float", 32, dc.DW_ATE_float), 32 elif ctype == ctypes.c_double: @@ -147,9 +156,7 @@ def _get_basic_debug_type(ctype, generator: DebugInfoGenerator) -> Any: char_type = generator.get_basic_type("char", 8, dc.DW_ATE_signed_char), 8 return generator.create_pointer_type(char_type) elif ctype == ctypes.c_void_p: - void_type = generator.module.add_debug_info( - "DIBasicType", {"name": "void"} - ) + void_type = generator.module.add_debug_info("DIBasicType", {"name": "void"}) return generator.create_pointer_type(void_type), 64 else: return generator.get_uint64_type(), 64 diff --git a/tests/passing_tests/vmlinux/xdp_pass.py b/tests/passing_tests/vmlinux/xdp_pass.py index 4ba2fea..6211b05 100644 --- a/tests/passing_tests/vmlinux/xdp_pass.py +++ b/tests/passing_tests/vmlinux/xdp_pass.py @@ -1,22 +1,20 @@ -from pythonbpf import bpf, map, section, bpfglobal, compile_to_ir, compile -from pythonbpf.maps import HashMap -from pythonbpf.helper import XDP_PASS +from pythonbpf import bpf, section, bpfglobal, compile_to_ir, compile from vmlinux import TASK_COMM_LEN # noqa: F401 -from vmlinux import struct_xdp_md from vmlinux import struct_trace_event_raw_sys_enter # noqa: F401 from ctypes import c_int64 + # Instructions to how to run this program # 1. Install PythonBPF: pip install pythonbpf # 2. Run the program: python examples/xdp_pass.py # 3. Run the program with sudo: sudo tools/check.sh run examples/xdp_pass.o # 4. Attach object file to any network device with something like ./check.sh xdp examples/xdp_pass.o tailscale0 # 5. send traffic through the device and observe effects - @bpf -@section("xdp") -def hello_world(ctx: struct_xdp_md) -> c_int64: - return XDP_PASS +@section("tracepoint/syscalls/sys_enter_execve") +def hello_world(ctx: struct_trace_event_raw_sys_enter) -> c_int64: + print("Hello, World!") + return c_int64(0) @bpf