Skip to content

Commit 88181de

Browse files
committed
aya: use NonZeroU32 for perf event process scope
PerfEventScope::OneProcess can no longer represent pid 0, which is the kernel sentinel for the calling process. This is a breaking change to PerfEventScope; downstream callers that constructed OneProcess { pid: 0 } should switch to CallingProcess. 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 and public API fixture.
1 parent 759087b commit 88181de

6 files changed

Lines changed: 69 additions & 15 deletions

File tree

aya/src/programs/perf_event.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Perf event programs.
22
3-
use std::os::fd::AsFd as _;
3+
use std::{num::NonZeroU32, os::fd::AsFd as _};
44

55
use aya_obj::generated::{
66
HW_BREAKPOINT_LEN_1, HW_BREAKPOINT_LEN_2, HW_BREAKPOINT_LEN_4, HW_BREAKPOINT_LEN_8,
@@ -372,7 +372,7 @@ pub enum PerfEventScope {
372372
/// one process
373373
OneProcess {
374374
/// process id
375-
pid: u32,
375+
pid: NonZeroU32,
376376
/// cpu id or any cpu if None
377377
cpu: Option<u32>,
378378
},

aya/src/sys/fake.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@ use std::{cell::RefCell, ffi::c_void, io, ptr};
22

33
use super::{SysResult, Syscall};
44

5-
type SyscallFn = unsafe fn(Syscall<'_>) -> SysResult;
5+
type SyscallFn = dyn for<'a> Fn(Syscall<'a>) -> SysResult;
66

77
#[cfg(test)]
88
thread_local! {
9-
pub(crate) static TEST_SYSCALL: RefCell<SyscallFn> = RefCell::new(test_syscall);
9+
pub(crate) static TEST_SYSCALL: RefCell<Box<SyscallFn>> = RefCell::new(Box::new(test_syscall));
1010
pub(crate) static TEST_MMAP_RET: RefCell<*mut c_void> = const { RefCell::new(ptr::null_mut()) };
1111
}
1212

1313
#[cfg(test)]
14-
unsafe fn test_syscall(_call: Syscall<'_>) -> SysResult {
14+
fn test_syscall(_call: Syscall<'_>) -> SysResult {
1515
Err((-1, io::Error::from_raw_os_error(libc::EINVAL)))
1616
}
1717

1818
#[cfg(test)]
19-
pub(crate) fn override_syscall(call: unsafe fn(Syscall<'_>) -> SysResult) {
20-
TEST_SYSCALL.with(|test_impl| *test_impl.borrow_mut() = call);
19+
pub(crate) fn override_syscall(call: impl for<'a> Fn(Syscall<'a>) -> SysResult + 'static) {
20+
TEST_SYSCALL.with(|test_impl| *test_impl.borrow_mut() = Box::new(call));
2121
}

aya/src/sys/mod.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@ pub(crate) enum PerfEventIoctlRequest<'a> {
3535
SetBpf(BorrowedFd<'a>),
3636
}
3737

38-
#[cfg_attr(test, expect(dead_code, reason = "test stubs cut above this"))]
3938
pub(crate) enum Syscall<'a> {
4039
Ebpf {
4140
cmd: bpf_cmd,
@@ -99,7 +98,7 @@ impl std::fmt::Debug for Syscall<'_> {
9998
fn syscall(call: Syscall<'_>) -> SysResult {
10099
#[cfg(test)]
101100
{
102-
TEST_SYSCALL.with(|test_impl| unsafe { test_impl.borrow()(call) })
101+
TEST_SYSCALL.with(|test_impl| test_impl.borrow()(call))
103102
}
104103

105104
#[cfg(not(test))]

aya/src/sys/perf_event.rs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::{
22
ffi::{CString, OsStr, c_long, c_uint},
33
io, mem,
4+
num::NonZeroU32,
45
os::fd::{BorrowedFd, FromRawFd as _},
56
};
67

@@ -125,7 +126,9 @@ pub(crate) fn perf_event_open(
125126

126127
let (pid, cpu) = match scope {
127128
PerfEventScope::CallingProcess { cpu } => (0, cpu.map_or(-1, |cpu| cpu as i32)),
128-
PerfEventScope::OneProcess { pid, cpu } => (pid as i32, cpu.map_or(-1, |cpu| cpu as i32)),
129+
PerfEventScope::OneProcess { pid, cpu } => {
130+
(pid.get() as i32, cpu.map_or(-1, |cpu| cpu as i32))
131+
}
129132
PerfEventScope::AllProcessesOneCpu { cpu } => (-1, cpu as i32),
130133
};
131134

@@ -166,9 +169,10 @@ pub(crate) fn perf_event_open_trace_point(
166169
event_id: u64,
167170
pid: Option<u32>,
168171
) -> io::Result<crate::MockableFd> {
169-
let scope = match pid {
170-
Some(pid) => PerfEventScope::OneProcess { pid, cpu: None },
172+
let scope = match pid.map(NonZeroU32::new) {
171173
None => PerfEventScope::AllProcessesOneCpu { cpu: 0 },
174+
Some(None) => PerfEventScope::CallingProcess { cpu: None },
175+
Some(Some(pid)) => PerfEventScope::OneProcess { pid, cpu: None },
172176
};
173177
perf_event_open(
174178
PerfEventConfig::TracePoint { event_id },
@@ -253,3 +257,47 @@ impl TryFrom<u32> for perf_event_type {
253257
}
254258
}
255259
*/
260+
261+
#[cfg(test)]
262+
mod tests {
263+
use std::os::fd::AsRawFd as _;
264+
265+
use libc::pid_t;
266+
use test_case::test_case;
267+
268+
use super::{PERF_FLAG_FD_CLOEXEC, perf_event_open_trace_point};
269+
use crate::sys::{Syscall, override_syscall};
270+
271+
const EVENT_ID: u64 = 123;
272+
273+
#[test_case(None, -1, 0; "all_processes")]
274+
#[test_case(Some(0), 0, -1; "calling_process")]
275+
#[test_case(Some(42), 42, -1; "one_process")]
276+
fn perf_event_open_trace_point_maps_pid_scope(
277+
pid: Option<u32>,
278+
expected_pid: pid_t,
279+
expected_cpu: i32,
280+
) {
281+
override_syscall(move |call| match call {
282+
Syscall::PerfEventOpen {
283+
attr,
284+
pid: actual_pid,
285+
cpu: actual_cpu,
286+
group,
287+
flags,
288+
} => {
289+
assert_eq!(attr.config, EVENT_ID);
290+
assert_eq!(unsafe { attr.__bindgen_anon_1.sample_period }, 0);
291+
assert_eq!(actual_pid, expected_pid);
292+
assert_eq!(actual_cpu, expected_cpu);
293+
assert_eq!(group, -1);
294+
assert_eq!(flags, PERF_FLAG_FD_CLOEXEC);
295+
Ok(crate::MockableFd::mock_signed_fd().into())
296+
}
297+
call => panic!("unexpected syscall: {call:?}"),
298+
});
299+
300+
let fd = perf_event_open_trace_point(EVENT_ID, pid).unwrap();
301+
assert_eq!(fd.as_raw_fd(), crate::MockableFd::mock_signed_fd());
302+
}
303+
}

test/integration-test/src/tests/perf_event_bp.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,10 @@
1-
use std::{collections::HashMap, fs, io::ErrorKind, num::ParseIntError, path::PathBuf};
1+
use std::{
2+
collections::HashMap,
3+
fs,
4+
io::ErrorKind,
5+
num::{NonZeroU32, ParseIntError},
6+
path::PathBuf,
7+
};
28

39
use assert_matches::assert_matches;
410
use aya::{
@@ -114,7 +120,7 @@ where
114120
let mut one_process_scopes = Vec::new();
115121
let mut all_processes_one_cpu_scopes = Vec::new();
116122

117-
let pid = std::process::id();
123+
let pid = NonZeroU32::new(std::process::id()).unwrap();
118124
for cpu in online_cpus().unwrap() {
119125
calling_process_scopes.push(PerfEventScope::CallingProcess { cpu: Some(cpu) });
120126
one_process_scopes.push(PerfEventScope::OneProcess {
@@ -171,6 +177,7 @@ where
171177

172178
trigger();
173179

180+
let pid = pid.get();
174181
let lookup = map.get(&pid, 0);
175182
if attached {
176183
let recorded =

xtask/public-api/aya.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3625,7 +3625,7 @@ pub aya::programs::perf_event::PerfEventScope::CallingProcess
36253625
pub aya::programs::perf_event::PerfEventScope::CallingProcess::cpu: core::option::Option<u32>
36263626
pub aya::programs::perf_event::PerfEventScope::OneProcess
36273627
pub aya::programs::perf_event::PerfEventScope::OneProcess::cpu: core::option::Option<u32>
3628-
pub aya::programs::perf_event::PerfEventScope::OneProcess::pid: u32
3628+
pub aya::programs::perf_event::PerfEventScope::OneProcess::pid: core::num::nonzero::NonZeroU32
36293629
impl core::clone::Clone for aya::programs::perf_event::PerfEventScope
36303630
pub fn aya::programs::perf_event::PerfEventScope::clone(&self) -> aya::programs::perf_event::PerfEventScope
36313631
impl core::fmt::Debug for aya::programs::perf_event::PerfEventScope

0 commit comments

Comments
 (0)