Skip to content

Commit b47063c

Browse files
r41k0uclaude
andcommitted
Core: Resolve plain-ctypes context parameter in helper args
process_func_body only entered the context parameter into local_sym_tab when its annotation was a vmlinux struct, so a program declared as `def prog(ctx: c_void_p)` had no `ctx` symbol at all. Passing `ctx` to a helper that takes a raw pointer -- probe_read(dst, size, ctx) -- failed with "Variable 'ctx' not found in local symbol table". Register the parameter for plain ctypes annotations too, keeping `var` as None: that is the established sentinel meaning "this symbol is the context parameter, read it from func.args[0]" (see VmlinuxHandler.handle_vmlinux_struct_field). Metadata holds the annotated Python type, mirroring the vmlinux branch. Teach the consumer side accordingly: get_or_create_ptr_from_arg now recognises the sentinel and hands back the function's first argument instead of an alloca. The special case lives at the call site rather than inside get_var_ptr_from_name so that helper stays a pure symbol table lookup -- the call site already has `func` and `builder` in scope, and get_var_ptr_from_name has no other callers to update. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent c2de7da commit b47063c

2 files changed

Lines changed: 31 additions & 3 deletions

File tree

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
@@ -50,8 +50,20 @@ def get_or_create_ptr_from_arg(
5050
logger.info(f"Getting pointer from arg: {ast.dump(arg)}")
5151
sz = None
5252
if isinstance(arg, ast.Name):
53-
# Stack space is already allocated
54-
ptr = get_var_ptr_from_name(arg.id, local_sym_tab)
53+
symbol = local_sym_tab.get(arg.id) if local_sym_tab else None
54+
if symbol is not None and symbol.var is None:
55+
# A None `var` marks the context parameter (see process_func_body):
56+
# it arrives as the function's first argument, not as a stack slot,
57+
# so there is no alloca to hand back. Use the argument itself.
58+
if not func.args:
59+
raise ValueError(
60+
f"'{arg.id}' is the context parameter but "
61+
f"'{func.name}' takes no arguments"
62+
)
63+
ptr = builder.bitcast(func.args[0], ir.PointerType())
64+
else:
65+
# Stack space is already allocated
66+
ptr = get_var_ptr_from_name(arg.id, local_sym_tab)
5567
elif isinstance(arg, ast.Constant) and isinstance(arg.value, int):
5668
int_width = 64 # Default to i64
5769
if expected_type and isinstance(expected_type, ir.IntType):

0 commit comments

Comments
 (0)