diff --git a/aya/src/maps/perf/perf_buffer.rs b/aya/src/maps/perf/perf_buffer.rs index 2a7989e7..8729dc1b 100644 --- a/aya/src/maps/perf/perf_buffer.rs +++ b/aya/src/maps/perf/perf_buffer.rs @@ -8,7 +8,6 @@ use std::{ use aya_obj::generated::{ perf_event_header, perf_event_mmap_page, perf_event_type::{PERF_RECORD_LOST, PERF_RECORD_SAMPLE}, - PERF_EVENT_IOC_DISABLE, PERF_EVENT_IOC_ENABLE, }; use bytes::BytesMut; use libc::{MAP_SHARED, PROT_READ, PROT_WRITE}; @@ -16,7 +15,7 @@ use thiserror::Error; use crate::{ maps::MMap, - sys::{perf_event_ioctl, perf_event_open_bpf, SysResult, SyscallError}, + sys::{perf_event_ioctl, perf_event_open_bpf, PerfEventIoctlRequest, SyscallError}, }; /// Perf buffer error. @@ -120,8 +119,8 @@ impl PerfBuffer { fd, }; - perf_event_ioctl(perf_buf.fd.as_fd(), PERF_EVENT_IOC_ENABLE, 0) - .map_err(|(_, io_error)| PerfBufferError::PerfEventEnableError { io_error })?; + perf_event_ioctl(perf_buf.fd.as_fd(), PerfEventIoctlRequest::Enable) + .map_err(|io_error| PerfBufferError::PerfEventEnableError { io_error })?; Ok(perf_buf) } @@ -260,7 +259,7 @@ impl AsFd for PerfBuffer { impl Drop for PerfBuffer { fn drop(&mut self) { - let _: SysResult = perf_event_ioctl(self.fd.as_fd(), PERF_EVENT_IOC_DISABLE, 0); + let _: io::Result<()> = perf_event_ioctl(self.fd.as_fd(), PerfEventIoctlRequest::Disable); } } @@ -289,9 +288,8 @@ mod tests { fn fake_mmap(buf: &mut MMappedBuf) { let buf: *mut _ = buf; override_syscall(|call| match call { - Syscall::PerfEventOpen { .. } | Syscall::PerfEventIoctl { .. } => { - Ok(crate::MockableFd::mock_signed_fd().into()) - } + Syscall::PerfEventOpen { .. } => Ok(crate::MockableFd::mock_signed_fd().into()), + Syscall::PerfEventIoctl { .. } => Ok(0), call => panic!("unexpected syscall: {:?}", call), }); TEST_MMAP_RET.with(|ret| *ret.borrow_mut() = buf.cast()); diff --git a/aya/src/programs/perf_attach.rs b/aya/src/programs/perf_attach.rs index 2b8fbfcc..0dd0e25c 100644 --- a/aya/src/programs/perf_attach.rs +++ b/aya/src/programs/perf_attach.rs @@ -1,11 +1,11 @@ //! Perf attach links. -use std::os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, RawFd}; - -use aya_obj::generated::{ - bpf_attach_type::BPF_PERF_EVENT, PERF_EVENT_IOC_DISABLE, PERF_EVENT_IOC_ENABLE, - PERF_EVENT_IOC_SET_BPF, +use std::{ + io, + os::fd::{AsFd as _, AsRawFd as _, BorrowedFd, RawFd}, }; +use aya_obj::generated::bpf_attach_type::BPF_PERF_EVENT; + use crate::{ programs::{ id_as_key, @@ -14,7 +14,7 @@ use crate::{ }, sys::{ bpf_link_create, is_bpf_cookie_supported, perf_event_ioctl, BpfLinkCreateArgs, LinkTarget, - SysResult, SyscallError, + PerfEventIoctlRequest, SyscallError, }, FEATURES, }; @@ -71,7 +71,7 @@ impl Link for PerfLink { fn detach(self) -> Result<(), ProgramError> { let Self { perf_fd, event } = self; - let _: SysResult = perf_event_ioctl(perf_fd.as_fd(), PERF_EVENT_IOC_DISABLE, 0); + let _: io::Result<()> = perf_event_ioctl(perf_fd.as_fd(), PerfEventIoctlRequest::Disable); if let Some(event) = event { let _: Result<_, _> = detach_debug_fs(event); } @@ -121,13 +121,13 @@ fn perf_attach_either( fd: crate::MockableFd, event: Option, ) -> Result { - perf_event_ioctl(fd.as_fd(), PERF_EVENT_IOC_SET_BPF, prog_fd.as_raw_fd()).map_err( - |(_, io_error)| SyscallError { + perf_event_ioctl(fd.as_fd(), PerfEventIoctlRequest::SetBpf(prog_fd)).map_err(|io_error| { + SyscallError { call: "PERF_EVENT_IOC_SET_BPF", io_error, - }, - )?; - perf_event_ioctl(fd.as_fd(), PERF_EVENT_IOC_ENABLE, 0).map_err(|(_, io_error)| { + } + })?; + perf_event_ioctl(fd.as_fd(), PerfEventIoctlRequest::Enable).map_err(|io_error| { SyscallError { call: "PERF_EVENT_IOC_ENABLE", io_error, diff --git a/aya/src/sys/mod.rs b/aya/src/sys/mod.rs index 04ec669a..5c7d173f 100644 --- a/aya/src/sys/mod.rs +++ b/aya/src/sys/mod.rs @@ -9,15 +9,14 @@ mod fake; use std::{ ffi::{c_int, c_long, c_void}, - io, mem, - os::fd::{AsRawFd as _, BorrowedFd, OwnedFd}, + io, + os::fd::{BorrowedFd, OwnedFd}, }; use aya_obj::generated::{bpf_attr, bpf_cmd, perf_event_attr}; pub(crate) use bpf::*; #[cfg(test)] pub(crate) use fake::*; -use libc::{pid_t, SYS_bpf, SYS_ioctl, SYS_perf_event_open}; #[doc(hidden)] pub use netlink::netlink_set_link_up; pub(crate) use netlink::*; @@ -26,6 +25,15 @@ use thiserror::Error; pub(crate) type SysResult = Result; +#[cfg_attr(test, expect(dead_code))] +#[derive(Debug)] +pub(crate) enum PerfEventIoctlRequest<'a> { + Enable, + Disable, + SetBpf(BorrowedFd<'a>), +} + +#[cfg_attr(test, expect(dead_code))] pub(crate) enum Syscall<'a> { Ebpf { cmd: bpf_cmd, @@ -33,15 +41,14 @@ pub(crate) enum Syscall<'a> { }, PerfEventOpen { attr: perf_event_attr, - pid: pid_t, + pid: libc::pid_t, cpu: i32, group: i32, flags: u32, }, PerfEventIoctl { fd: BorrowedFd<'a>, - request: u32, - arg: c_int, + request: PerfEventIoctlRequest<'a>, }, } @@ -78,11 +85,10 @@ impl std::fmt::Debug for Syscall<'_> { .field("group", group) .field("flags", flags) .finish(), - Self::PerfEventIoctl { fd, request, arg } => f + Self::PerfEventIoctl { fd, request } => f .debug_struct("Syscall::PerfEventIoctl") .field("fd", fd) .field("request", request) - .field("arg", arg) .finish(), } } @@ -90,14 +96,16 @@ impl std::fmt::Debug for Syscall<'_> { fn syscall(call: Syscall<'_>) -> SysResult { #[cfg(test)] - return TEST_SYSCALL.with(|test_impl| unsafe { test_impl.borrow()(call) }); + { + TEST_SYSCALL.with(|test_impl| unsafe { test_impl.borrow()(call) }) + } - #[cfg_attr(test, allow(unreachable_code))] + #[cfg(not(test))] { let ret = unsafe { match call { Syscall::Ebpf { cmd, attr } => { - libc::syscall(SYS_bpf, cmd, attr, mem::size_of::()) + libc::syscall(libc::SYS_bpf, cmd, attr, std::mem::size_of::()) } Syscall::PerfEventOpen { attr, @@ -105,9 +113,29 @@ fn syscall(call: Syscall<'_>) -> SysResult { cpu, group, flags, - } => libc::syscall(SYS_perf_event_open, &attr, pid, cpu, group, flags), - Syscall::PerfEventIoctl { fd, request, arg } => { - libc::syscall(SYS_ioctl, fd.as_raw_fd(), request, arg) + } => libc::syscall(libc::SYS_perf_event_open, &attr, pid, cpu, group, flags), + Syscall::PerfEventIoctl { fd, request } => { + use std::os::fd::AsRawFd as _; + + let fd = fd.as_raw_fd(); + match request { + PerfEventIoctlRequest::Enable => libc::syscall( + libc::SYS_ioctl, + fd, + aya_obj::generated::PERF_EVENT_IOC_ENABLE, + ), + PerfEventIoctlRequest::Disable => libc::syscall( + libc::SYS_ioctl, + fd, + aya_obj::generated::PERF_EVENT_IOC_DISABLE, + ), + PerfEventIoctlRequest::SetBpf(bpf_fd) => libc::syscall( + libc::SYS_ioctl, + fd, + aya_obj::generated::PERF_EVENT_IOC_SET_BPF, + bpf_fd.as_raw_fd(), + ), + } } } }; @@ -128,11 +156,17 @@ pub(crate) unsafe fn mmap( fd: BorrowedFd<'_>, offset: libc::off_t, ) -> *mut c_void { + #[cfg(test)] + { + TEST_MMAP_RET.with(|ret| *ret.borrow()) + } + #[cfg(not(test))] - return libc::mmap(addr, len, prot, flags, fd.as_raw_fd(), offset); + { + use std::os::fd::AsRawFd as _; - #[cfg(test)] - TEST_MMAP_RET.with(|ret| *ret.borrow()) + libc::mmap(addr, len, prot, flags, fd.as_raw_fd(), offset) + } } #[cfg_attr(test, allow(unused_variables))] diff --git a/aya/src/sys/perf_event.rs b/aya/src/sys/perf_event.rs index b4f4c2ef..58b98b46 100644 --- a/aya/src/sys/perf_event.rs +++ b/aya/src/sys/perf_event.rs @@ -13,7 +13,7 @@ use aya_obj::generated::{ }; use libc::pid_t; -use super::{syscall, SysResult, Syscall}; +use super::{syscall, PerfEventIoctlRequest, Syscall}; #[allow(clippy::too_many_arguments)] pub(crate) fn perf_event_open( @@ -104,8 +104,18 @@ pub(crate) fn perf_event_open_trace_point( perf_event_sys(attr, pid, cpu, PERF_FLAG_FD_CLOEXEC) } -pub(crate) fn perf_event_ioctl(fd: BorrowedFd<'_>, request: u32, arg: c_int) -> SysResult { - syscall(Syscall::PerfEventIoctl { fd, request, arg }) +pub(crate) fn perf_event_ioctl( + fd: BorrowedFd<'_>, + request: PerfEventIoctlRequest<'_>, +) -> io::Result<()> { + syscall(Syscall::PerfEventIoctl { fd, request }) + .map(|code| { + assert_eq!(code, 0); + }) + .map_err(|(code, io_error)| { + assert_eq!(code, -1); + io_error + }) } fn perf_event_sys(