3 Commits

Author SHA1 Message Date
c8801f4c3e nonetype not parsed 2025-11-19 23:35:10 +05:30
49740598ea format chore 2025-11-13 09:31:10 +05:30
73bbf00e7c add tests 2025-11-13 09:29:53 +05:30
6 changed files with 138 additions and 70 deletions

View File

@ -195,24 +195,9 @@ def process_vmlinux_post_ast(
if hasattr(base_type, "__name__") if hasattr(base_type, "__name__")
else str(base_type) else str(base_type)
) )
# ONLY add vmlinux types as dependencies
new_dep_node.add_dependent(base_type_name) new_dep_node.add_dependent(base_type_name)
elif base_type_module == ctypes.__name__ or base_type_module is None:
# Handle ctypes or types with no module (like some internal ctypes types)
if isinstance(elem_type, type):
if issubclass(elem_type, ctypes.Array):
ctype_complex_type = ctypes.Array
elif issubclass(elem_type, ctypes._Pointer):
ctype_complex_type = ctypes._Pointer
else:
raise ImportError(
"Non Array and Pointer type ctype imports not supported in current version"
)
else:
raise TypeError("Unsupported ctypes subclass")
else:
raise ImportError(
f"Unsupported module of {base_type}: {base_type_module}"
)
logger.debug( logger.debug(
f"{containing_type} containing type of parent {elem_name} with {elem_type} and ctype {ctype_complex_type} and length {type_length}" f"{containing_type} containing type of parent {elem_name} with {elem_type} and ctype {ctype_complex_type} and length {type_length}"
) )
@ -226,10 +211,14 @@ def process_vmlinux_post_ast(
new_dep_node.set_field_type(elem_name, elem_type) new_dep_node.set_field_type(elem_name, elem_type)
# Check the containing_type module to decide whether to recurse # Check the containing_type module to decide whether to recurse
containing_type_module = getattr(containing_type, "__module__", None) containing_type_module = getattr(
containing_type, "__module__", None
)
if containing_type_module == "vmlinux": if containing_type_module == "vmlinux":
# Also unwrap containing_type to get base type name # Also unwrap containing_type to get base type name
base_containing_type = unwrap_pointer_type(containing_type) base_containing_type = unwrap_pointer_type(
containing_type
)
containing_type_name = ( containing_type_name = (
base_containing_type.__name__ base_containing_type.__name__
if hasattr(base_containing_type, "__name__") if hasattr(base_containing_type, "__name__")
@ -259,13 +248,53 @@ def process_vmlinux_post_ast(
processing_stack, processing_stack,
) )
new_dep_node.set_field_ready(elem_name, True) new_dep_node.set_field_ready(elem_name, True)
elif containing_type_module == ctypes.__name__ or containing_type_module is None: elif (
logger.debug(f"Processing ctype internal{containing_type}") containing_type_module == ctypes.__name__
or containing_type_module is None
):
logger.debug(
f"Processing ctype internal{containing_type}"
)
new_dep_node.set_field_ready(elem_name, True) new_dep_node.set_field_ready(elem_name, True)
else: else:
raise TypeError( raise TypeError(
f"Module not supported in recursive resolution: {containing_type_module}" f"Module not supported in recursive resolution: {containing_type_module}"
) )
elif (
base_type_module == ctypes.__name__
or base_type_module is None
):
# Handle ctypes or types with no module (like some internal ctypes types)
# DO NOT add ctypes as dependencies - just set field metadata and mark ready
logger.debug(
f"Base type {base_type} is ctypes - NOT adding as dependency, just processing field"
)
if isinstance(elem_type, type):
if issubclass(elem_type, ctypes.Array):
ctype_complex_type = ctypes.Array
elif issubclass(elem_type, ctypes._Pointer):
ctype_complex_type = ctypes._Pointer
else:
raise ImportError(
"Non Array and Pointer type ctype imports not supported in current version"
)
else:
raise TypeError("Unsupported ctypes subclass")
# Set field metadata but DO NOT add dependency or recurse
new_dep_node.set_field_containing_type(
elem_name, containing_type
)
new_dep_node.set_field_type_size(elem_name, type_length)
new_dep_node.set_field_ctype_complex_type(
elem_name, ctype_complex_type
)
new_dep_node.set_field_type(elem_name, elem_type)
new_dep_node.set_field_ready(elem_name, True)
else:
raise ImportError(
f"Unsupported module of {base_type}: {base_type_module}"
)
else: else:
new_dep_node.add_dependent( new_dep_node.add_dependent(
elem_type.__name__ elem_type.__name__

View File

@ -79,7 +79,7 @@ def _get_field_debug_type(
""" """
# Handle complex types (arrays, pointers) # Handle complex types (arrays, 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 # TODO: Check if this is a CFUNCTYPE (function pointer), but sadly it just checks callable for now
if callable(field.ctype_complex_type): if callable(field.ctype_complex_type):
# Handle function pointer types, create a void pointer as a placeholder # Handle function pointer types, create a void pointer as a placeholder
return generator.create_pointer_type(None), 64 return generator.create_pointer_type(None), 64

View File

@ -14,6 +14,7 @@ class IRGenerator:
# This field keeps track of the non_struct names to avoid duplicate name errors. # This field keeps track of the non_struct names to avoid duplicate name errors.
type_number = 0 type_number = 0
unprocessed_store = [] unprocessed_store = []
# get the assignments dict and add this stuff to it. # get the assignments dict and add this stuff to it.
def __init__(self, llvm_module, handler: DependencyHandler, assignments): def __init__(self, llvm_module, handler: DependencyHandler, assignments):
self.llvm_module = llvm_module self.llvm_module = llvm_module
@ -187,13 +188,17 @@ class IRGenerator:
while hasattr(base_containing_type, "_type_"): while hasattr(base_containing_type, "_type_"):
next_type = base_containing_type._type_ next_type = base_containing_type._type_
# Stop if _type_ is a string (like 'c' for c_char) # Stop if _type_ is a string (like 'c' for c_char)
#TODO: stacked pointers not handl;ing ctypes check here as well # TODO: stacked pointers not handl;ing ctypes check here as well
if isinstance(next_type, str): if isinstance(next_type, str):
break break
base_containing_type = next_type base_containing_type = next_type
# Get the base struct name # Get the base struct name
base_struct_name = base_containing_type.__name__ if hasattr(base_containing_type, "__name__") else str(base_containing_type) base_struct_name = (
base_containing_type.__name__
if hasattr(base_containing_type, "__name__")
else str(base_containing_type)
)
# Look up the size using the base struct name # Look up the size using the base struct name
containing_type_size = self.handler[base_struct_name].current_offset containing_type_size = self.handler[base_struct_name].current_offset
@ -212,14 +217,23 @@ class IRGenerator:
else: else:
for i in range(0, array_size): for i in range(0, array_size):
field_co_re_name, returned = self._struct_name_generator( field_co_re_name, returned = self._struct_name_generator(
struct, field, field_index, True, i, containing_type_size struct,
field,
field_index,
True,
i,
containing_type_size,
) )
globvar = ir.GlobalVariable( globvar = ir.GlobalVariable(
self.llvm_module, ir.IntType(64), name=field_co_re_name self.llvm_module, ir.IntType(64), name=field_co_re_name
) )
globvar.linkage = "external" globvar.linkage = "external"
globvar.set_metadata("llvm.preserve.access.index", debug_info) globvar.set_metadata(
self.generated_field_names[struct.name][field_name] = globvar "llvm.preserve.access.index", debug_info
)
self.generated_field_names[struct.name][field_name] = (
globvar
)
field_index += 1 field_index += 1
else: else:
field_co_re_name, returned = self._struct_name_generator( field_co_re_name, returned = self._struct_name_generator(

View File

@ -0,0 +1,22 @@
from vmlinux import XDP_PASS
from pythonbpf import bpf, section, bpfglobal, compile_to_ir
import logging
from ctypes import c_int64, c_void_p
@bpf
@section("kprobe/blk_mq_start_request")
def example(ctx: c_void_p) -> c_int64:
d = XDP_PASS # This gives an error, but
e = XDP_PASS + 0 # this does not
print(f"test1 {e} test2 {d}")
return c_int64(0)
@bpf
@bpfglobal
def LICENSE() -> str:
return "GPL"
compile_to_ir("assignment_handling.py", "assignment_handling.ll", loglevel=logging.INFO)

View File

@ -1,15 +1,16 @@
from vmlinux import struct_request, struct_pt_regs, XDP_PASS from vmlinux import struct_request, 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
@bpf @bpf
@section("kprobe/blk_mq_start_request") @section("kprobe/blk_mq_start_request")
def example(ctx: struct_pt_regs): def example(ctx: struct_pt_regs) -> c_int64:
req = struct_request(ctx.di) req = struct_request(ctx.di)
c = req.__data_len c = req.__data_len
d = XDP_PASS print(f"data length {c}")
print(f"data length {c} and test {d}") return c_int64(0)
@bpf @bpf

View File

@ -1,13 +1,15 @@
from vmlinux import struct_kobj_type from vmlinux import struct_pt_regs, struct_request
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_void_p from ctypes import c_int64
@bpf @bpf
@section("kprobe/blk_mq_start_request") @section("kprobe/blk_mq_start_request")
def example(ctx: c_void_p): def example(ctx: struct_pt_regs) -> c_int64:
print(f"data lengt") req = ctx.di
print(f"data length {req}")
return c_int64(0)
@bpf @bpf
@ -16,4 +18,4 @@ def LICENSE() -> str:
return "GPL" return "GPL"
compile_to_ir("requests.py", "requests.ll", loglevel=logging.INFO) compile_to_ir("requests2.py", "requests2.ll", loglevel=logging.INFO)