correct error size calculation for arrays

This commit is contained in:
2025-10-18 22:13:59 +05:30
parent 1b4272b408
commit dc1b243e82
3 changed files with 43 additions and 22 deletions

View File

@ -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 @staticmethod
def _compute_array_size(base_type: Any, count: int) -> int: def _compute_array_size(base_type: Any, count: int) -> int:
# Extract size from base_type if possible # 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""" """Create a struct member with the given name, type, and offset"""
base_type, type_size = base_type_with_size base_type, type_size = base_type_with_size
return self.module.add_debug_info( return self.module.add_debug_info(

View File

@ -2,12 +2,15 @@ from pythonbpf.debuginfo import DebugInfoGenerator, dwarf_constants as dc
from ..dependency_node import DependencyNode from ..dependency_node import DependencyNode
import ctypes import ctypes
import logging import logging
from typing import List, Any, Tuple, Optional from typing import List, Any, Tuple
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
def debug_info_generation( 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: ) -> Any:
""" """
Generate DWARF debug information for a struct defined in a DependencyNode. Generate DWARF debug information for a struct defined in a DependencyNode.
@ -54,11 +57,11 @@ def debug_info_generation(
def _get_field_debug_type( def _get_field_debug_type(
field_name: str, field_name: str,
field, field,
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]: ) -> 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.
@ -77,8 +80,12 @@ def _get_field_debug_type(
if field.ctype_complex_type is not None: if field.ctype_complex_type is not None:
if issubclass(field.ctype_complex_type, ctypes.Array): if issubclass(field.ctype_complex_type, ctypes.Array):
# Handle array types # Handle array types
element_type, base_type_size = _get_basic_debug_type(field.containing_type, generator) element_type, base_type_size = _get_basic_debug_type(
return generator.create_array_type(element_type, field.type_size), field.type_size * base_type_size 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): elif issubclass(field.ctype_complex_type, ctypes._Pointer):
# Handle pointer types # Handle pointer types
pointee_type, _ = _get_basic_debug_type(field.containing_type, generator) 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: elif ctype == ctypes.c_longlong or ctype == ctypes.c_int64:
return generator.get_basic_type("long long", 64, dc.DW_ATE_signed), 64 return generator.get_basic_type("long long", 64, dc.DW_ATE_signed), 64
elif ctype == ctypes.c_ulonglong or ctype == ctypes.c_uint64: 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: elif ctype == ctypes.c_float:
return generator.get_basic_type("float", 32, dc.DW_ATE_float), 32 return generator.get_basic_type("float", 32, dc.DW_ATE_float), 32
elif ctype == ctypes.c_double: 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 char_type = generator.get_basic_type("char", 8, dc.DW_ATE_signed_char), 8
return generator.create_pointer_type(char_type) return generator.create_pointer_type(char_type)
elif ctype == ctypes.c_void_p: elif ctype == ctypes.c_void_p:
void_type = generator.module.add_debug_info( void_type = generator.module.add_debug_info("DIBasicType", {"name": "void"})
"DIBasicType", {"name": "void"}
)
return generator.create_pointer_type(void_type), 64 return generator.create_pointer_type(void_type), 64
else: else:
return generator.get_uint64_type(), 64 return generator.get_uint64_type(), 64

View File

@ -1,22 +1,20 @@
from pythonbpf import bpf, map, section, bpfglobal, compile_to_ir, compile from pythonbpf import bpf, section, bpfglobal, compile_to_ir, compile
from pythonbpf.maps import HashMap
from pythonbpf.helper import XDP_PASS
from vmlinux import TASK_COMM_LEN # noqa: F401 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 vmlinux import struct_trace_event_raw_sys_enter # noqa: F401
from ctypes import c_int64 from ctypes import c_int64
# Instructions to how to run this program # Instructions to how to run this program
# 1. Install PythonBPF: pip install pythonbpf # 1. Install PythonBPF: pip install pythonbpf
# 2. Run the program: python examples/xdp_pass.py # 2. Run the program: python examples/xdp_pass.py
# 3. Run the program with sudo: sudo tools/check.sh run examples/xdp_pass.o # 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 # 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 # 5. send traffic through the device and observe effects
@bpf @bpf
@section("xdp") @section("tracepoint/syscalls/sys_enter_execve")
def hello_world(ctx: struct_xdp_md) -> c_int64: def hello_world(ctx: struct_trace_event_raw_sys_enter) -> c_int64:
return XDP_PASS print("Hello, World!")
return c_int64(0)
@bpf @bpf