Skip to content

Commit 0459b3a

Browse files
r41k0uclaude
andcommitted
Tests: Add perf_skip as a nested-struct-access roadmap test
Ported faithfully from test_perf_skip.c, which reads the sampled instruction pointer out of a perf_event context: ctx.regs.ip. That is two levels of struct field access and PythonBPF supports one, so this lands as a strict expected failure describing the gap. _allocate_for_attribute in allocation_pass.py declines to allocate unless the attribute's base is a plain Name, so the nested form is skipped. One level on the same context works today -- ctx.sample_period compiles and llc's fine. Worth noting for whoever picks this up: the failure surfaces as 'SyntaxError: Undefined variable actual', naming the assignment target rather than the nested access responsible. The allocation pass declines quietly and the expression pass then trips over the missing symbol. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
1 parent 7911436 commit 0459b3a

2 files changed

Lines changed: 62 additions & 0 deletions

File tree

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
# Ported from Linux tools/testing/selftests/bpf/progs/test_perf_skip.c
2+
#
3+
# A perf_event program that reports whether the sampled instruction pointer is
4+
# the one userspace asked about. Upstream:
5+
#
6+
# uintptr_t ip;
7+
#
8+
# SEC("perf_event")
9+
# int handler(struct bpf_perf_event_data *data)
10+
# {
11+
# /* Skip events that have the correct ip. */
12+
# return ip != PT_REGS_IP(&data->regs);
13+
# }
14+
#
15+
# ROADMAP: this is a strict expected failure. `ctx.regs.ip` is two levels of
16+
# struct field access, and PythonBPF supports only one --
17+
# `_allocate_for_attribute` in allocation_pass.py bails out unless the
18+
# attribute's base is a plain Name. One level works today: `ctx.sample_period`
19+
# on this same context compiles fine.
20+
#
21+
# Note the failure surfaces as `SyntaxError: Undefined variable actual`, naming
22+
# the assignment target rather than the nested access that caused it -- the
23+
# allocation pass declines to allocate and logs at debug level, then the
24+
# expression pass fails later on the missing symbol. Worth improving alongside
25+
# nested access support.
26+
#
27+
# WORKAROUND(globals): upstream uses `uintptr_t ip` to receive the address to
28+
# compare against. PythonBPF has no global variable support yet, so it becomes a
29+
# one-entry HashMap keyed by 0. Replace with a real global once they land.
30+
31+
from pythonbpf import bpf, map, section, bpfglobal, compile
32+
from pythonbpf.maps import HashMap
33+
from vmlinux import struct_bpf_perf_event_data
34+
from ctypes import c_int64, c_int32, c_uint64
35+
36+
37+
# WORKAROUND(globals): stands in for `uintptr_t ip;`
38+
@bpf
39+
@map
40+
def expected_ip() -> HashMap:
41+
return HashMap(key=c_int32, value=c_uint64, max_entries=1)
42+
43+
44+
@bpf
45+
@section("perf_event")
46+
def handler(ctx: struct_bpf_perf_event_data) -> c_int64:
47+
want = expected_ip.lookup(0)
48+
actual = ctx.regs.ip
49+
if want == actual:
50+
return c_int64(0)
51+
return c_int64(1)
52+
53+
54+
@bpf
55+
@bpfglobal
56+
def LICENSE() -> str:
57+
return "GPL"
58+
59+
60+
compile()

tests/test_config.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,5 @@
3636
"kernel_selftest_equivalent/maps/array_map_lookup_update.py" = {reason = "ArrayMap / BPF_MAP_TYPE_ARRAY support is planned but not implemented yet", level = "ir"}
3737

3838
"kernel_selftest_equivalent/ringbuf/reserve_submit_discard.py" = {reason = "RingBuffer reserve/typed record/discard workflow is planned but not implemented yet", level = "ir"}
39+
40+
"kernel_selftest_equivalent/vmlinux/perf_skip.py" = {reason = "Nested struct field access (ctx.regs.ip) not supported; one level such as ctx.sample_period works", level = "ir"}

0 commit comments

Comments
 (0)