add placeholder debug info to shut llvmlite up about NoneType

This commit is contained in:
2025-11-20 14:17:57 +05:30
parent c8801f4c3e
commit 740eed45e1
3 changed files with 57 additions and 38 deletions

View File

@ -44,9 +44,9 @@ def unwrap_pointer_type(type_obj: Any) -> Any:
def process_vmlinux_class( def process_vmlinux_class(
node, node,
llvm_module, llvm_module,
handler: DependencyHandler, handler: DependencyHandler,
): ):
symbols_in_module, imported_module = get_module_symbols("vmlinux") symbols_in_module, imported_module = get_module_symbols("vmlinux")
if node.name in symbols_in_module: if node.name in symbols_in_module:
@ -57,10 +57,10 @@ def process_vmlinux_class(
def process_vmlinux_post_ast( def process_vmlinux_post_ast(
elem_type_class, elem_type_class,
llvm_handler, llvm_handler,
handler: DependencyHandler, handler: DependencyHandler,
processing_stack=None, processing_stack=None,
): ):
# Initialize processing stack on first call # Initialize processing stack on first call
if processing_stack is None: if processing_stack is None:
@ -140,7 +140,7 @@ def process_vmlinux_post_ast(
# Process pointer to ctype # Process pointer to ctype
if isinstance(elem_type, type) and issubclass( if isinstance(elem_type, type) and issubclass(
elem_type, ctypes._Pointer elem_type, ctypes._Pointer
): ):
# Get the pointed-to type # Get the pointed-to type
pointed_type = elem_type._type_ pointed_type = elem_type._type_
@ -153,7 +153,7 @@ def process_vmlinux_post_ast(
# Process function pointers (CFUNCTYPE) # Process function pointers (CFUNCTYPE)
elif hasattr(elem_type, "_restype_") and hasattr( elif hasattr(elem_type, "_restype_") and hasattr(
elem_type, "_argtypes_" elem_type, "_argtypes_"
): ):
# This is a CFUNCTYPE or similar # This is a CFUNCTYPE or similar
logger.info( logger.info(

View File

@ -21,7 +21,7 @@ def debug_info_generation(
generated_debug_info: List of tuples (struct, debug_info) to track generated debug info generated_debug_info: List of tuples (struct, debug_info) to track generated debug info
Returns: Returns:
The generated global variable debug info The generated global variable debug info, or None for unsupported types
""" """
# Set up debug info generator # Set up debug info generator
generator = DebugInfoGenerator(llvm_module) generator = DebugInfoGenerator(llvm_module)
@ -31,29 +31,44 @@ def debug_info_generation(
if existing_struct.name == struct.name: if existing_struct.name == struct.name:
return debug_info 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 # Process all fields and create members for the struct
members = [] members = []
for field_name, field in struct.fields.items(): for field_name, field in struct.fields.items():
# Get appropriate debug type for this field try:
field_type = _get_field_debug_type( # Get appropriate debug type for this field
field_name, field, generator, struct, generated_debug_info 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 # Ensure field_type is a tuple
) if not isinstance(field_type, tuple) or len(field_type) != 2:
members.append(member) 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 return struct_type
@ -63,7 +78,7 @@ def _get_field_debug_type(
generator: DebugInfoGenerator, generator: DebugInfoGenerator,
parent_struct: DependencyNode, parent_struct: DependencyNode,
generated_debug_info: List[Tuple[DependencyNode, Any]], 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. 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 generated_debug_info: List of already generated debug info
Returns: 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: 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): if callable(field.ctype_complex_type):
# Handle function pointer types, create a void pointer as a placeholder # Function pointers are represented as void pointers
return generator.create_pointer_type(None), 64 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): elif issubclass(field.ctype_complex_type, ctypes.Array):
# Handle array types # Handle array types
element_type, base_type_size = _get_basic_debug_type( 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: for existing_struct, debug_info in generated_debug_info:
if existing_struct.name == struct_name: if existing_struct.name == struct_name:
# Use existing debug info # Use existing debug info
return debug_info, existing_struct.__sizeof__() return debug_info, existing_struct.__sizeof__() * 8
# If not found, create a forward declaration # If not found, create a forward declaration
# This will be completed when the actual struct is processed # 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) forward_type = generator.create_struct_type([], 0, is_distinct=True)
return forward_type, 0 return forward_type, 0

View File

@ -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 from pythonbpf import bpf, section, bpfglobal, compile_to_ir
import logging import logging
from ctypes import c_int64 from ctypes import c_int64