Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions pythonbpf/allocation_pass.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,9 +340,15 @@ def _allocate_for_attribute(

struct_type: type = local_sym_tab[struct_var].metadata
if not struct_type or struct_type not in structs_sym_tab:
if VmlinuxHandlerRegistry.is_vmlinux_struct(struct_type.__name__):
# `metadata` only names a struct for struct-typed symbols. For anything
# else (None, an IR type, or a plain ctypes class such as a `c_void_p`
# context parameter) there is no vmlinux struct name to look up, so guard
# the attribute access instead of blowing up with an AttributeError.
vmlinux_struct_name = getattr(struct_type, "__name__", None)
if vmlinux_struct_name and VmlinuxHandlerRegistry.is_vmlinux_struct(
vmlinux_struct_name
):
# Handle vmlinux struct field access
vmlinux_struct_name = struct_type.__name__
if not VmlinuxHandlerRegistry.has_field(vmlinux_struct_name, field_name):
logger.error(
f"Field '{field_name}' not found in vmlinux struct '{vmlinux_struct_name}'"
Expand Down
18 changes: 17 additions & 1 deletion pythonbpf/functions/functions_pass.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
from llvmlite import ir
import ast
import ctypes
import logging

from pythonbpf.helper import (
HelperHandlerRegistry,
)
from pythonbpf.type_deducer import ctypes_to_ir
from pythonbpf.type_deducer import ctypes_to_ir, is_ctypes
from pythonbpf.expr import (
eval_expr,
handle_expr,
Expand Down Expand Up @@ -325,13 +326,28 @@ def process_func_body(
f"Unsupported annotation type: {ast.dump(context_arg.annotation)}"
)

# NOTE: `var` is None for the context parameter. It is the sentinel
# that tells consumers the symbol is an incoming function argument
# (`func.args[0]`) rather than a stack slot they can load from.
if VmlinuxHandlerRegistry.is_vmlinux_struct(context_type_name):
resolved_type = VmlinuxHandlerRegistry.get_struct_type(
context_type_name
)
context_type = LocalSymbol(None, None, resolved_type)
local_sym_tab[context_name] = context_type
logger.info(f"Added argument '{context_name}' to local symbol table")
elif is_ctypes(context_type_name):
# Plain ctypes annotation, e.g. `ctx: c_void_p`. Register it so
# helpers that take the raw context (probe_read, ...) can resolve
# the name. Metadata is the annotated Python type, mirroring the
# vmlinux branch above.
context_type = LocalSymbol(
None,
ir.PointerType(),
getattr(ctypes, context_type_name, None),
)
local_sym_tab[context_name] = context_type
logger.info(f"Added argument '{context_name}' to local symbol table")

# pre-allocate dynamic variables
local_sym_tab = allocate_mem(
Expand Down
16 changes: 14 additions & 2 deletions pythonbpf/helper/helper_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,20 @@ def get_or_create_ptr_from_arg(
logger.info(f"Getting pointer from arg: {ast.dump(arg)}")
sz = None
if isinstance(arg, ast.Name):
# Stack space is already allocated
ptr = get_var_ptr_from_name(arg.id, local_sym_tab)
symbol = local_sym_tab.get(arg.id) if local_sym_tab else None
if symbol is not None and symbol.var is None:
# A None `var` marks the context parameter (see process_func_body):
# it arrives as the function's first argument, not as a stack slot,
# so there is no alloca to hand back. Use the argument itself.
if not func.args:
raise ValueError(
f"'{arg.id}' is the context parameter but "
f"'{func.name}' takes no arguments"
)
ptr = builder.bitcast(func.args[0], ir.PointerType())
else:
# Stack space is already allocated
ptr = get_var_ptr_from_name(arg.id, local_sym_tab)
elif isinstance(arg, ast.Constant) and isinstance(arg.value, int):
int_width = 64 # Default to i64
if expected_type and isinstance(expected_type, ir.IntType):
Expand Down
Loading