perf_event_open_sys/
functions.rs

1//! Wrappers for the `perf_event_open` system call and related ioctls.
2//!
3//! This module provides Rust bindings for the `perf_event_open`
4//! system call, as well as its associated ioctl calls, based on the
5//! types in `bindings`.
6//!
7//! Normally, one would just get such things from the `libc` crate,
8//! but the GNU C Library does not provide a C binding for the
9//! `perf_event_open` system call, and the Rust `libc` crate follows
10//! its lead. So we need to fill in the gap here.
11//!
12//! This module is only compiled on Linux. The `bindings` declarations
13//! are useful on other platforms for parsing perf files.
14
15use crate::bindings;
16
17use libc::pid_t;
18use std::os::raw::{c_int, c_ulong};
19
20/// The `perf_event_open` system call.
21///
22/// See the [`perf_event_open(2) man page`][man] for details.
23///
24/// On error, this returns -1, and the C `errno` value (accessible via
25/// `std::io::Error::last_os_error`) is set to indicate the error.
26///
27/// Note: The `attrs` argument needs to be a `*mut` because if the `size` field
28/// is too small or too large, the kernel writes the size it was expecing back
29/// into that field. It might do other things as well.
30///
31/// # Safety
32///
33/// The `attrs` argument must point to a properly initialized
34/// `perf_event_attr` struct. The measurements and other behaviors its
35/// contents request must be safe.
36///
37/// [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
38pub unsafe fn perf_event_open(
39    attrs: *mut bindings::perf_event_attr,
40    pid: pid_t,
41    cpu: c_int,
42    group_fd: c_int,
43    flags: c_ulong,
44) -> c_int {
45    libc::syscall(
46        bindings::__NR_perf_event_open as libc::c_long,
47        attrs as *const bindings::perf_event_attr,
48        pid,
49        cpu,
50        group_fd,
51        flags,
52    ) as c_int
53}
54
55#[allow(dead_code, non_snake_case)]
56pub mod ioctls {
57    //! Ioctls for use with `perf_event_open` file descriptors.
58    //!
59    //! See the [`perf_event_open(2)`][man] man page for details.
60    //!
61    //! On error, these return `-1` and set the C `errno` value.
62    //!
63    //! [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html
64    use crate::bindings::{self, perf_event_attr, perf_event_query_bpf};
65    use std::os::raw::{c_char, c_int, c_uint, c_ulong};
66
67    macro_rules! define_ioctls {
68        ( $( $args:tt )* ) => {
69            $(
70                define_ioctl!($args);
71            )*
72        }
73    }
74
75    macro_rules! define_ioctl {
76        ({ $name:ident, $ioctl:ident, $arg_type:ty }) => {
77            #[allow(clippy::missing_safety_doc)]
78            pub unsafe fn $name(fd: c_int, arg: $arg_type) -> c_int {
79                untyped_ioctl(fd, bindings::$ioctl, arg)
80            }
81        };
82    }
83
84    define_ioctls! {
85        { ENABLE, ENABLE, c_uint }
86        { DISABLE, DISABLE, c_uint }
87        { REFRESH, REFRESH, c_int }
88        { RESET, RESET, c_uint }
89        { PERIOD, PERIOD, u64 }
90        { SET_OUTPUT, SET_OUTPUT, c_int }
91        { SET_FILTER, SET_FILTER, *mut c_char }
92        { ID, ID, *mut u64 }
93        { SET_BPF, SET_BPF, u32 }
94        { PAUSE_OUTPUT, PAUSE_OUTPUT, u32 }
95        { QUERY_BPF, QUERY_BPF, *mut perf_event_query_bpf }
96        { MODIFY_ATTRIBUTES, MODIFY_ATTRIBUTES, *mut perf_event_attr }
97    }
98
99    unsafe fn untyped_ioctl<A>(fd: c_int, ioctl: bindings::perf_event_ioctls, arg: A) -> c_int {
100        #[cfg(any(target_env = "musl", target_os = "android"))]
101        return libc::ioctl(fd, ioctl as c_int, arg);
102
103        #[cfg(not(any(target_env = "musl", target_os = "android")))]
104        libc::ioctl(fd, ioctl as c_ulong, arg)
105    }
106}