From 740eed45e1431c8e0cce165daccd42a703a54984 Mon Sep 17 00:00:00 2001 From: varun-r-mallya Date: Thu, 20 Nov 2025 14:17:57 +0530 Subject: [PATCH] add placeholder debug info to shut llvmlite up about NoneType --- pythonbpf/vmlinux_parser/class_handler.py | 18 ++--- .../vmlinux_parser/ir_gen/debug_info_gen.py | 75 ++++++++++++------- tests/failing_tests/vmlinux/requests2.py | 2 +- 3 files changed, 57 insertions(+), 38 deletions(-) diff --git a/pythonbpf/vmlinux_parser/class_handler.py b/pythonbpf/vmlinux_parser/class_handler.py index 3970459..0c66ba2 100644 --- a/pythonbpf/vmlinux_parser/class_handler.py +++ b/pythonbpf/vmlinux_parser/class_handler.py @@ -44,9 +44,9 @@ def unwrap_pointer_type(type_obj: Any) -> Any: def process_vmlinux_class( - node, - llvm_module, - handler: DependencyHandler, + node, + llvm_module, + handler: DependencyHandler, ): symbols_in_module, imported_module = get_module_symbols("vmlinux") if node.name in symbols_in_module: @@ -57,10 +57,10 @@ def process_vmlinux_class( def process_vmlinux_post_ast( - elem_type_class, - llvm_handler, - handler: DependencyHandler, - processing_stack=None, + elem_type_class, + llvm_handler, + handler: DependencyHandler, + processing_stack=None, ): # Initialize processing stack on first call if processing_stack is None: @@ -140,7 +140,7 @@ def process_vmlinux_post_ast( # Process pointer to ctype if isinstance(elem_type, type) and issubclass( - elem_type, ctypes._Pointer + elem_type, ctypes._Pointer ): # Get the pointed-to type pointed_type = elem_type._type_ @@ -153,7 +153,7 @@ def process_vmlinux_post_ast( # Process function pointers (CFUNCTYPE) elif hasattr(elem_type, "_restype_") and hasattr( - elem_type, "_argtypes_" + elem_type, "_argtypes_" ): # This is a CFUNCTYPE or similar logger.info( diff --git a/pythonbpf/vmlinux_parser/ir_gen/debug_info_gen.py b/pythonbpf/vmlinux_parser/ir_gen/debug_info_gen.py index 5730670..eb7636f 100644 --- a/pythonbpf/vmlinux_parser/ir_gen/debug_info_gen.py +++ b/pythonbpf/vmlinux_parser/ir_gen/debug_info_gen.py @@ -21,7 +21,7 @@ def debug_info_generation( generated_debug_info: List of tuples (struct, debug_info) to track generated debug info Returns: - The generated global variable debug info + The generated global variable debug info, or None for unsupported types """ # Set up debug info generator generator = DebugInfoGenerator(llvm_module) @@ -31,29 +31,44 @@ def debug_info_generation( if existing_struct.name == struct.name: return debug_info + # Check if this is a union (not supported yet) + if not struct.name.startswith("struct_"): + logger.warning(f"Skipping debug info generation for union: {struct.name}") + # Create a minimal forward declaration for unions + union_type = generator.create_struct_type( + [], struct.__sizeof__() * 8, is_distinct=True + ) + return union_type + # Process all fields and create members for the struct members = [] for field_name, field in struct.fields.items(): - # Get appropriate debug type for this field - field_type = _get_field_debug_type( - field_name, field, generator, struct, generated_debug_info - ) - # Create struct member with proper offset - member = generator.create_struct_member_vmlinux( - field_name, field_type, field.offset * 8 - ) - members.append(member) + try: + # Get appropriate debug type for this field + field_type = _get_field_debug_type( + field_name, field, generator, struct, generated_debug_info + ) + + # Ensure field_type is a tuple + if not isinstance(field_type, tuple) or len(field_type) != 2: + logger.error(f"Invalid field_type for {field_name}: {field_type}") + continue + + # Create struct member with proper offset + member = generator.create_struct_member_vmlinux( + field_name, field_type, field.offset * 8 + ) + members.append(member) + except Exception as e: + logger.error(f"Failed to process field {field_name} in {struct.name}: {e}") + continue + + struct_name = struct.name.removeprefix("struct_") + # Create struct type with all members + struct_type = generator.create_struct_type_with_name( + struct_name, members, struct.__sizeof__() * 8, is_distinct=True + ) - if struct.name.startswith("struct_"): - struct_name = struct.name.removeprefix("struct_") - # Create struct type with all members - struct_type = generator.create_struct_type_with_name( - struct_name, members, struct.__sizeof__() * 8, is_distinct=True - ) - else: - logger.warning("Blindly handling Unions present in vmlinux dependencies") - struct_type = None - # raise ValueError("Unions are not supported in the current version") return struct_type @@ -63,7 +78,7 @@ def _get_field_debug_type( generator: DebugInfoGenerator, parent_struct: DependencyNode, generated_debug_info: List[Tuple[DependencyNode, Any]], -) -> tuple[Any, int] | None: +) -> tuple[Any, int]: """ Determine the appropriate debug type for a field based on its Python/ctypes type. @@ -75,14 +90,16 @@ def _get_field_debug_type( generated_debug_info: List of already generated debug info Returns: - The debug info type for this field + A tuple of (debug_type, size_in_bits) """ - # Handle complex types (arrays, pointers) + # Handle complex types (arrays, pointers, function pointers) if field.ctype_complex_type is not None: - # TODO: Check if this is a CFUNCTYPE (function pointer), but sadly it just checks callable for now + # Handle function pointer types (CFUNCTYPE) if callable(field.ctype_complex_type): - # Handle function pointer types, create a void pointer as a placeholder - return generator.create_pointer_type(None), 64 + # Function pointers are represented as void pointers + logger.info(f"Field {field_name} is a function pointer, using void pointer") + void_ptr = generator.create_pointer_type(None, 64) + return void_ptr, 64 elif issubclass(field.ctype_complex_type, ctypes.Array): # Handle array types element_type, base_type_size = _get_basic_debug_type( @@ -105,11 +122,13 @@ def _get_field_debug_type( for existing_struct, debug_info in generated_debug_info: if existing_struct.name == struct_name: # Use existing debug info - return debug_info, existing_struct.__sizeof__() + return debug_info, existing_struct.__sizeof__() * 8 # If not found, create a forward declaration # This will be completed when the actual struct is processed - logger.warning("Forward declaration in struct created") + logger.warning( + f"Forward declaration created for {struct_name} in {parent_struct.name}" + ) forward_type = generator.create_struct_type([], 0, is_distinct=True) return forward_type, 0 diff --git a/tests/failing_tests/vmlinux/requests2.py b/tests/failing_tests/vmlinux/requests2.py index 3ced648..63e90c7 100644 --- a/tests/failing_tests/vmlinux/requests2.py +++ b/tests/failing_tests/vmlinux/requests2.py @@ -1,4 +1,4 @@ -from vmlinux import struct_pt_regs, struct_request +from vmlinux import struct_pt_regs from pythonbpf import bpf, section, bpfglobal, compile_to_ir import logging from ctypes import c_int64