Skip to content

Commit c4c0c58

Browse files
Merge pull request #94 from pythonbpf/fix/probe-read-ctx-not-found
register ctx in the local_sym_tab with the type `void *` if no struct annotation is given
2 parents 50d0678 + d7a7636 commit c4c0c58

3 files changed

Lines changed: 39 additions & 5 deletions

File tree

pythonbpf/allocation_pass.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -340,9 +340,15 @@ def _allocate_for_attribute(
340340

341341
struct_type: type = local_sym_tab[struct_var].metadata
342342
if not struct_type or struct_type not in structs_sym_tab:
343-
if VmlinuxHandlerRegistry.is_vmlinux_struct(struct_type.__name__):
343+
# `metadata` only names a struct for struct-typed symbols. For anything
344+
# else (None, an IR type, or a plain ctypes class such as a `c_void_p`
345+
# context parameter) there is no vmlinux struct name to look up, so guard
346+
# the attribute access instead of blowing up with an AttributeError.
347+
vmlinux_struct_name = getattr(struct_type, "__name__", None)
348+
if vmlinux_struct_name and VmlinuxHandlerRegistry.is_vmlinux_struct(
349+
vmlinux_struct_name
350+
):
344351
# Handle vmlinux struct field access
345-
vmlinux_struct_name = struct_type.__name__
346352
if not VmlinuxHandlerRegistry.has_field(vmlinux_struct_name, field_name):
347353
logger.error(
348354
f"Field '{field_name}' not found in vmlinux struct '{vmlinux_struct_name}'"

pythonbpf/functions/functions_pass.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
from llvmlite import ir
22
import ast
3+
import ctypes
34
import logging
45

56
from pythonbpf.helper import (
67
HelperHandlerRegistry,
78
)
8-
from pythonbpf.type_deducer import ctypes_to_ir
9+
from pythonbpf.type_deducer import ctypes_to_ir, is_ctypes
910
from pythonbpf.expr import (
1011
eval_expr,
1112
handle_expr,
@@ -325,13 +326,28 @@ def process_func_body(
325326
f"Unsupported annotation type: {ast.dump(context_arg.annotation)}"
326327
)
327328

329+
# NOTE: `var` is None for the context parameter. It is the sentinel
330+
# that tells consumers the symbol is an incoming function argument
331+
# (`func.args[0]`) rather than a stack slot they can load from.
328332
if VmlinuxHandlerRegistry.is_vmlinux_struct(context_type_name):
329333
resolved_type = VmlinuxHandlerRegistry.get_struct_type(
330334
context_type_name
331335
)
332336
context_type = LocalSymbol(None, None, resolved_type)
333337
local_sym_tab[context_name] = context_type
334338
logger.info(f"Added argument '{context_name}' to local symbol table")
339+
elif is_ctypes(context_type_name):
340+
# Plain ctypes annotation, e.g. `ctx: c_void_p`. Register it so
341+
# helpers that take the raw context (probe_read, ...) can resolve
342+
# the name. Metadata is the annotated Python type, mirroring the
343+
# vmlinux branch above.
344+
context_type = LocalSymbol(
345+
None,
346+
ir.PointerType(),
347+
getattr(ctypes, context_type_name, None),
348+
)
349+
local_sym_tab[context_name] = context_type
350+
logger.info(f"Added argument '{context_name}' to local symbol table")
335351

336352
# pre-allocate dynamic variables
337353
local_sym_tab = allocate_mem(

pythonbpf/helper/helper_utils.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,20 @@ def get_or_create_ptr_from_arg(
5252
logger.info(f"Getting pointer from arg: {ast.dump(arg)}")
5353
sz = None
5454
if isinstance(arg, ast.Name):
55-
# Stack space is already allocated
56-
ptr = get_var_ptr_from_name(arg.id, local_sym_tab)
55+
symbol = local_sym_tab.get(arg.id) if local_sym_tab else None
56+
if symbol is not None and symbol.var is None:
57+
# A None `var` marks the context parameter (see process_func_body):
58+
# it arrives as the function's first argument, not as a stack slot,
59+
# so there is no alloca to hand back. Use the argument itself.
60+
if not func.args:
61+
raise ValueError(
62+
f"'{arg.id}' is the context parameter but "
63+
f"'{func.name}' takes no arguments"
64+
)
65+
ptr = builder.bitcast(func.args[0], ir.PointerType())
66+
else:
67+
# Stack space is already allocated
68+
ptr = get_var_ptr_from_name(arg.id, local_sym_tab)
5769
elif isinstance(arg, ast.Constant) and isinstance(arg.value, int):
5870
int_width = 64 # Default to i64
5971
if expected_type and isinstance(expected_type, ir.IntType):

0 commit comments

Comments
 (0)