Skip to content

Commit 03c1090

Browse files
committed
aya: use Pid for perf event scopes
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.
1 parent 0739126 commit 03c1090

7 files changed

Lines changed: 114 additions & 17 deletions

File tree

aya/src/programs/mod.rs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ use std::{
7777
borrow::Cow,
7878
ffi::CString,
7979
io,
80+
num::NonZeroU32,
8081
os::fd::{AsFd, BorrowedFd},
8182
path::{Path, PathBuf},
8283
sync::Arc,
@@ -270,6 +271,32 @@ impl AsFd for ProgramFd {
270271
}
271272
}
272273

274+
/// A non-zero process identifier.
275+
///
276+
/// This type represents a real process ID. Kernel sentinel values such as `0`
277+
/// are modeled separately by the APIs that accept them.
278+
#[derive(Debug, Clone, Copy)]
279+
pub struct Pid(NonZeroU32);
280+
281+
impl Pid {
282+
/// Creates a process identifier from a raw PID.
283+
///
284+
/// Returns `None` if `pid` is zero.
285+
pub fn new(pid: u32) -> Option<Self> {
286+
NonZeroU32::new(pid).map(Self)
287+
}
288+
289+
/// Returns the identifier of the current process.
290+
pub fn current() -> Self {
291+
Self(NonZeroU32::new(std::process::id()).unwrap())
292+
}
293+
294+
/// Returns the raw PID value.
295+
pub const fn get(self) -> u32 {
296+
self.0.get()
297+
}
298+
}
299+
273300
/// A [`Program`] identifier.
274301
pub struct ProgramId(u32);
275302

aya/src/programs/perf_event.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use aya_obj::generated::{
1111

1212
use crate::{
1313
programs::{
14-
ProgramData, ProgramError, ProgramType, impl_try_from_fdlink, impl_try_into_fdlink,
14+
Pid, ProgramData, ProgramError, ProgramType, impl_try_from_fdlink, impl_try_into_fdlink,
1515
links::define_link_wrapper,
1616
load_program_without_attach_type,
1717
perf_attach::{PerfLinkIdInner, PerfLinkInner, perf_attach},
@@ -372,7 +372,7 @@ pub enum PerfEventScope {
372372
/// one process
373373
OneProcess {
374374
/// process id
375-
pid: u32,
375+
pid: Pid,
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: 58 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ use aya_obj::generated::{
1616
use libc::pid_t;
1717

1818
use super::{PerfEventIoctlRequest, Syscall, syscall};
19-
use crate::programs::perf_event::{
20-
BreakpointConfig, PerfEventConfig, PerfEventScope, SamplePolicy, WakeupPolicy,
21-
perf_type_id_to_u32,
19+
use crate::programs::{
20+
Pid,
21+
perf_event::{
22+
BreakpointConfig, PerfEventConfig, PerfEventScope, SamplePolicy, WakeupPolicy,
23+
perf_type_id_to_u32,
24+
},
2225
};
2326

2427
pub(crate) fn perf_event_open(
@@ -125,7 +128,9 @@ pub(crate) fn perf_event_open(
125128

126129
let (pid, cpu) = match scope {
127130
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)),
131+
PerfEventScope::OneProcess { pid, cpu } => {
132+
(pid.get() as i32, cpu.map_or(-1, |cpu| cpu as i32))
133+
}
129134
PerfEventScope::AllProcessesOneCpu { cpu } => (-1, cpu as i32),
130135
};
131136

@@ -167,8 +172,12 @@ pub(crate) fn perf_event_open_trace_point(
167172
pid: Option<u32>,
168173
) -> io::Result<crate::MockableFd> {
169174
let scope = match pid {
170-
Some(pid) => PerfEventScope::OneProcess { pid, cpu: None },
171175
None => PerfEventScope::AllProcessesOneCpu { cpu: 0 },
176+
Some(0) => PerfEventScope::CallingProcess { cpu: None },
177+
Some(pid) => PerfEventScope::OneProcess {
178+
pid: Pid::new(pid).unwrap(),
179+
cpu: None,
180+
},
172181
};
173182
perf_event_open(
174183
PerfEventConfig::TracePoint { event_id },
@@ -253,3 +262,47 @@ impl TryFrom<u32> for perf_event_type {
253262
}
254263
}
255264
*/
265+
266+
#[cfg(test)]
267+
mod tests {
268+
use std::os::fd::AsRawFd as _;
269+
270+
use libc::pid_t;
271+
use test_case::test_case;
272+
273+
use super::{PERF_FLAG_FD_CLOEXEC, perf_event_open_trace_point};
274+
use crate::sys::{Syscall, override_syscall};
275+
276+
const EVENT_ID: u64 = 123;
277+
278+
#[test_case(None, -1, 0; "all_processes")]
279+
#[test_case(Some(0), 0, -1; "calling_process")]
280+
#[test_case(Some(42), 42, -1; "one_process")]
281+
fn perf_event_open_trace_point_maps_pid_scope(
282+
pid: Option<u32>,
283+
expected_pid: pid_t,
284+
expected_cpu: i32,
285+
) {
286+
override_syscall(move |call| match call {
287+
Syscall::PerfEventOpen {
288+
attr,
289+
pid: actual_pid,
290+
cpu: actual_cpu,
291+
group,
292+
flags,
293+
} => {
294+
assert_eq!(attr.config, EVENT_ID);
295+
assert_eq!(unsafe { attr.__bindgen_anon_1.sample_period }, 0);
296+
assert_eq!(actual_pid, expected_pid);
297+
assert_eq!(actual_cpu, expected_cpu);
298+
assert_eq!(group, -1);
299+
assert_eq!(flags, PERF_FLAG_FD_CLOEXEC);
300+
Ok(crate::MockableFd::mock_signed_fd().into())
301+
}
302+
call => panic!("unexpected syscall: {call:?}"),
303+
});
304+
305+
let fd = perf_event_open_trace_point(EVENT_ID, pid).unwrap();
306+
assert_eq!(fd.as_raw_fd(), crate::MockableFd::mock_signed_fd());
307+
}
308+
}

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

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use assert_matches::assert_matches;
44
use aya::{
55
Ebpf, maps,
66
programs::{
7-
ProgramError,
7+
Pid, ProgramError,
88
perf_event::{
99
BreakpointConfig, PerfBreakpointLength, PerfBreakpointType, PerfEventConfig,
1010
PerfEventScope, SamplePolicy,
@@ -114,7 +114,7 @@ where
114114
let mut one_process_scopes = Vec::new();
115115
let mut all_processes_one_cpu_scopes = Vec::new();
116116

117-
let pid = std::process::id();
117+
let pid = Pid::current();
118118
for cpu in online_cpus().unwrap() {
119119
calling_process_scopes.push(PerfEventScope::CallingProcess { cpu: Some(cpu) });
120120
one_process_scopes.push(PerfEventScope::OneProcess {
@@ -171,6 +171,7 @@ where
171171

172172
trigger();
173173

174+
let pid = pid.get();
174175
let lookup = map.get(&pid, 0);
175176
if attached {
176177
let recorded =

xtask/public-api/aya.txt

Lines changed: 18 additions & 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: aya::programs::Pid
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
@@ -6299,6 +6299,23 @@ impl core::marker::Unpin for aya::programs::perf_event::PerfEvent
62996299
impl core::marker::UnsafeUnpin for aya::programs::perf_event::PerfEvent
63006300
impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::perf_event::PerfEvent
63016301
impl core::panic::unwind_safe::UnwindSafe for aya::programs::perf_event::PerfEvent
6302+
pub struct aya::programs::Pid(_)
6303+
impl aya::programs::Pid
6304+
pub fn aya::programs::Pid::current() -> Self
6305+
pub const fn aya::programs::Pid::get(self) -> u32
6306+
pub fn aya::programs::Pid::new(pid: u32) -> core::option::Option<Self>
6307+
impl core::clone::Clone for aya::programs::Pid
6308+
pub fn aya::programs::Pid::clone(&self) -> aya::programs::Pid
6309+
impl core::fmt::Debug for aya::programs::Pid
6310+
pub fn aya::programs::Pid::fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result
6311+
impl core::marker::Copy for aya::programs::Pid
6312+
impl core::marker::Freeze for aya::programs::Pid
6313+
impl core::marker::Send for aya::programs::Pid
6314+
impl core::marker::Sync for aya::programs::Pid
6315+
impl core::marker::Unpin for aya::programs::Pid
6316+
impl core::marker::UnsafeUnpin for aya::programs::Pid
6317+
impl core::panic::unwind_safe::RefUnwindSafe for aya::programs::Pid
6318+
impl core::panic::unwind_safe::UnwindSafe for aya::programs::Pid
63026319
pub struct aya::programs::ProgramFd(_)
63036320
impl aya::programs::ProgramFd
63046321
pub fn aya::programs::ProgramFd::try_clone(&self) -> std::io::error::Result<Self>

0 commit comments

Comments
 (0)