aya: use NonZeroU32 for perf event process scope#1547
aya: use NonZeroU32 for perf event process scope#1547swananan wants to merge 3 commits intoaya-rs:mainfrom
Conversation
✅ Deploy Preview for aya-rs-docs ready!Built without sensitive environment variables
To edit notification comments on pull requests, go to your Netlify project configuration. |
tamird
left a comment
There was a problem hiding this comment.
@tamird reviewed 4 files and all commit messages, and made 2 comments.
Reviewable status: 4 of 5 files reviewed, 2 unresolved discussions (waiting on swananan).
aya/src/sys/perf_event.rs line 273 at r1 (raw file):
const EVENT_ID: u64 = 123; // `override_syscall` takes a `fn` pointer that can't capture, so per-case
would life be easier if you could change it to take Box<Fn<....>>?
test/integration-test/src/tests/perf_event_bp.rs line 124 at r1 (raw file):
let pid = std::process::id(); let scope_pid = NonZeroU32::new(pid).unwrap();
can this just be called pid?
181ad12 to
88181de
Compare
swananan
left a comment
There was a problem hiding this comment.
@swananan made 2 comments.
Reviewable status: 2 of 6 files reviewed, 2 unresolved discussions (waiting on tamird).
aya/src/sys/perf_event.rs line 273 at r1 (raw file):
Previously, tamird (Tamir Duberstein) wrote…
would life be easier if you could change it to take
Box<Fn<....>>?
Done.
test/integration-test/src/tests/perf_event_bp.rs line 124 at r1 (raw file):
Previously, tamird (Tamir Duberstein) wrote…
can this just be called pid?
Done.
tamird
left a comment
There was a problem hiding this comment.
@tamird reviewed 3 files and all commit messages, made 1 comment, and resolved 2 discussions.
Reviewable status: 5 of 6 files reviewed, 1 unresolved discussion (waiting on swananan).
aya/src/sys/perf_event.rs line 170 at r2 (raw file):
pub(crate) fn perf_event_open_trace_point( event_id: u64, pid: Option<u32>,
how come we aren't plumbing this all the way up?
swananan
left a comment
There was a problem hiding this comment.
@swananan made 1 comment.
Reviewable status: 5 of 6 files reviewed, 1 unresolved discussion (waiting on tamird).
aya/src/sys/perf_event.rs line 170 at r2 (raw file):
Previously, tamird (Tamir Duberstein) wrote…
how come we aren't plumbing this all the way up?
Right — UProbe::attach is the only public API that exposes pidtoday. I assume you mean adding pid to TracePoint::attach.
Looking at libbpf as reference, bpf_program__attach_tracepoint doesn't expose pid either; perf-level pid filtering doesn't constrain BPF execution on the tracepoint path anyway, so users would filter with bpf_get_current_pid_tgid() inside the program. I'd leave TracePoint::attach as-is. WDYT?
88181de to
9c32f80
Compare
swananan
left a comment
There was a problem hiding this comment.
@swananan made 1 comment.
Reviewable status: 5 of 6 files reviewed, 1 unresolved discussion (waiting on tamird).
aya/src/sys/perf_event.rs line 170 at r2 (raw file):
Previously, swananan (swananan) wrote…
Right —
UProbe::attachis the only public API that exposespidtoday. I assume you mean addingpidtoTracePoint::attach.Looking at libbpf as reference,
bpf_program__attach_tracepointdoesn't exposepideither; perf-level pid filtering doesn't constrain BPF execution on the tracepoint path anyway, so users would filter withbpf_get_current_pid_tgid()inside the program. I'd leaveTracePoint::attachas-is. WDYT?
I rethought this a bit. Plumbing a scope only into perf_event_open_trace_point doesn’t seem to buy us much: plain tracepoints don’t need it, uprobes already translate their scope before this point, and kprobes don’t need this distinction. So I’d prefer to keep this helper scoped to the raw perf_event pid mapping.
tamird
left a comment
There was a problem hiding this comment.
@tamird made 1 comment.
Reviewable status: 5 of 6 files reviewed, 1 unresolved discussion (waiting on swananan).
aya/src/sys/perf_event.rs line 170 at r2 (raw file):
Previously, swananan (swananan) wrote…
I rethought this a bit. Plumbing a scope only into
perf_event_open_trace_pointdoesn’t seem to buy us much: plain tracepoints don’t need it, uprobes already translate their scope before this point, and kprobes don’t need this distinction. So I’d prefer to keep this helper scoped to the raw perf_event pid mapping.
I wasn't clear enough. What I really meant was that UProbe::attach takes a UProbeScope, translates it to an Option<u32> and then here we translate it again to PerfEventScope. My suggestion is to plumb PerfEventScope up so that the conversion from UProbeScope to PerfEventScope can happen directly.
swananan
left a comment
There was a problem hiding this comment.
@swananan made 1 comment.
Reviewable status: 5 of 10 files reviewed, 1 unresolved discussion (waiting on tamird).
aya/src/sys/perf_event.rs line 170 at r2 (raw file):
Previously, tamird (Tamir Duberstein) wrote…
I wasn't clear enough. What I really meant was that
UProbe::attachtakes aUProbeScope, translates it to anOption<u32>and then here we translate it again toPerfEventScope. My suggestion is to plumbPerfEventScopeup so that the conversion fromUProbeScopetoPerfEventScopecan happen directly.
Got it, that makes sense.
tamird
left a comment
There was a problem hiding this comment.
LGTM. @alessandrod had thoughts on NonZero in the public API, so will let him voice those here.
@tamird reviewed 5 files and all commit messages, made 1 comment, and resolved 1 discussion.
Reviewable status:complete! all files reviewed, all discussions resolved (waiting on swananan).
|
As I mentioned on discord, I'm not a fan of NonZeroU32 in public APIs. If we're fixing up this corner of the API, I'd do something like: and then the scope APIs also look weird, instead of having CallingProcess OneProcess etc we could have and I think this covers all combinations? |
|
The kernel exposes "calling process", IMO we should retain the ability to express that. I don't have strong feelings on the newtype wrapper around NonZeroU32, but if we introduce it then we should also use it in Maybe we should make these enums more opaque and control ingress with constructors. But IMO something like |
By this argument no fallible APIs are good because in the name they don’t express why they’re fallible. NonZeroU32 is bad for a number of reasons, starting from the name: the fact that a pid is a u32 is an implementation detail. Ack on having a Current variant, but seems like the process and the cpu id should be decoupled |
|
You can't decouple them because when you say "all processes" you must specify a CPU.
No, they are just worse than the ones that say in the name why they are fallible. But I struggle to understand your beef with |
not sure we need to rehash the history of PID handling, even posix does pid_t in the year of the lord 2026. It's "just" a typedef but it clearly communicates that you're dealing with a pid and not an arbitrary integer. Abstractions are cool!
Right now I remember this curse |
of course they are, but |
And so do we in master. If we're trying to abstract more, the next step is a pid abstraction, not "still u32 but not zero ok!!" |
|
Right but it is not an abstraction! If the user wants to target any pid that isn't the current process, there is no way for us to do that without exposing |
Introduce a Pid newtype backed by NonZeroU32 so public APIs communicate PID semantics while preventing pid 0 from being represented as OneProcess. PerfEventScope::OneProcess now takes Pid. pid 0 remains the perf_event_open sentinel for the calling process, which is represented by CallingProcess instead. Route Some(0) to CallingProcess in perf_event_open_trace_point so the pid=0 sentinel is preserved through the typed scope. None continues to map to all-processes CPU 0. Add syscall-level coverage for the pid/cpu mappings and update the breakpoint integration test.
Update UProbeScope::OneProcess to take Pid instead of exposing NonZeroU32 directly. This keeps the uprobe process scope API aligned with PerfEventScope while preserving the non-zero PID invariant. Update the uprobe scope integration test and public API fixture.
Remove the intermediate Option<u32> pid plumbing from probe attachment paths and pass PerfEventScope through to the perf_event helpers directly. This keeps the UProbeScope to PerfEventScope conversion in UProbe::attach, where both the process scope and /proc/<pid>/maps lookup semantics are visible. These kprobe, uprobe, and tracepoint attach paths are backed by perf_event. For all-processes attachment, perf_event_open requires an explicit CPU, so use CPU 0 only to open the backing perf event. Process-scoped uprobes continue to use cpu=-1 through PerfEventScope.
391d058 to
1a6d44e
Compare
|
Thanks, I missed the some of the discord context earlier😂, now I updated the PR accordingly:
|
Summary
Follow-up on the recent PR #1543
Testings
perf_event_open_trace_pointis only reachable on kernels < 4.17. aya CI runs ≥ 5.10, so uprobe e2e tests on CI never enter this branch. Coverage is provided by a mocked-syscall unit test driving all three pid-scope cases (None/Some(0)/Some(non-zero)) throughoverride_syscall.Added/updated tests?
We strongly encourage you to add a test for your changes.
have not been included
Checklist
cargo +nightly fmt.You can find failing lints with
cargo xtask clippy.cargo test.cargo xtask public-api --bless.(Optional) What GIF best describes this PR or how it makes you feel?
This change is