1*fae6e9adSlinfeng use crate::include::bindings::linux_bpf::{ 2*fae6e9adSlinfeng perf_event_attr, perf_event_header, perf_event_sample_format, perf_sw_ids, perf_type_id, 3*fae6e9adSlinfeng }; 4*fae6e9adSlinfeng use crate::syscall::user_access::check_and_clone_cstr; 5*fae6e9adSlinfeng use alloc::string::String; 6*fae6e9adSlinfeng use num_traits::FromPrimitive; 7*fae6e9adSlinfeng use system_error::SystemError; 8*fae6e9adSlinfeng 9*fae6e9adSlinfeng bitflags! { 10*fae6e9adSlinfeng pub struct PerfEventOpenFlags: u32 { 11*fae6e9adSlinfeng const PERF_FLAG_FD_NO_GROUP = 1; 12*fae6e9adSlinfeng const PERF_FLAG_FD_OUTPUT = 2; 13*fae6e9adSlinfeng const PERF_FLAG_PID_CGROUP = 4; 14*fae6e9adSlinfeng const PERF_FLAG_FD_CLOEXEC = 8; 15*fae6e9adSlinfeng } 16*fae6e9adSlinfeng } 17*fae6e9adSlinfeng 18*fae6e9adSlinfeng /// The `PerfEventIoc` enum is used to define the ioctl commands for perf events. 19*fae6e9adSlinfeng /// 20*fae6e9adSlinfeng /// See https://elixir.bootlin.com/linux/v6.1/source/include/uapi/linux/perf_event.h#L544 21*fae6e9adSlinfeng #[repr(u32)] 22*fae6e9adSlinfeng #[derive(Debug, Copy, Clone, FromPrimitive)] 23*fae6e9adSlinfeng pub enum PerfEventIoc { 24*fae6e9adSlinfeng /// Equivalent to [crate::include::bindings::linux_bpf::AYA_PERF_EVENT_IOC_ENABLE]. 25*fae6e9adSlinfeng Enable = 9216, 26*fae6e9adSlinfeng /// Equivalent to [crate::include::bindings::linux_bpf::AYA_PERF_EVENT_IOC_DISABLE]. 27*fae6e9adSlinfeng Disable = 9217, 28*fae6e9adSlinfeng /// Equivalent to [crate::include::bindings::linux_bpf::AYA_PERF_EVENT_IOC_SET_BPF]. 29*fae6e9adSlinfeng SetBpf = 1074013192, 30*fae6e9adSlinfeng } 31*fae6e9adSlinfeng 32*fae6e9adSlinfeng #[derive(Debug, Clone)] 33*fae6e9adSlinfeng #[allow(unused)] 34*fae6e9adSlinfeng /// `perf_event_open` syscall arguments. 35*fae6e9adSlinfeng pub struct PerfProbeArgs { 36*fae6e9adSlinfeng pub config: perf_sw_ids, 37*fae6e9adSlinfeng pub name: String, 38*fae6e9adSlinfeng pub offset: u64, 39*fae6e9adSlinfeng pub size: u32, 40*fae6e9adSlinfeng pub type_: perf_type_id, 41*fae6e9adSlinfeng pub pid: i32, 42*fae6e9adSlinfeng pub cpu: i32, 43*fae6e9adSlinfeng pub group_fd: i32, 44*fae6e9adSlinfeng pub flags: PerfEventOpenFlags, 45*fae6e9adSlinfeng pub sample_type: Option<perf_event_sample_format>, 46*fae6e9adSlinfeng } 47*fae6e9adSlinfeng 48*fae6e9adSlinfeng impl PerfProbeArgs { 49*fae6e9adSlinfeng pub fn try_from( 50*fae6e9adSlinfeng attr: &perf_event_attr, 51*fae6e9adSlinfeng pid: i32, 52*fae6e9adSlinfeng cpu: i32, 53*fae6e9adSlinfeng group_fd: i32, 54*fae6e9adSlinfeng flags: u32, 55*fae6e9adSlinfeng ) -> Result<Self, SystemError> { 56*fae6e9adSlinfeng let ty = perf_type_id::from_u32(attr.type_).ok_or(SystemError::EINVAL)?; 57*fae6e9adSlinfeng let config = perf_sw_ids::from_u32(attr.config as u32).ok_or(SystemError::EINVAL)?; 58*fae6e9adSlinfeng let name = if ty == perf_type_id::PERF_TYPE_MAX { 59*fae6e9adSlinfeng let name_ptr = unsafe { attr.__bindgen_anon_3.config1 } as *const u8; 60*fae6e9adSlinfeng let name = check_and_clone_cstr(name_ptr, None)?; 61*fae6e9adSlinfeng name.into_string().map_err(|_| SystemError::EINVAL)? 62*fae6e9adSlinfeng } else { 63*fae6e9adSlinfeng String::new() 64*fae6e9adSlinfeng }; 65*fae6e9adSlinfeng let sample_ty = perf_event_sample_format::from_u32(attr.sample_type as u32); 66*fae6e9adSlinfeng let args = PerfProbeArgs { 67*fae6e9adSlinfeng config, 68*fae6e9adSlinfeng name, 69*fae6e9adSlinfeng offset: unsafe { attr.__bindgen_anon_4.config2 }, 70*fae6e9adSlinfeng size: attr.size, 71*fae6e9adSlinfeng type_: ty, 72*fae6e9adSlinfeng pid, 73*fae6e9adSlinfeng cpu, 74*fae6e9adSlinfeng group_fd, 75*fae6e9adSlinfeng flags: PerfEventOpenFlags::from_bits_truncate(flags), 76*fae6e9adSlinfeng sample_type: sample_ty, 77*fae6e9adSlinfeng }; 78*fae6e9adSlinfeng Ok(args) 79*fae6e9adSlinfeng } 80*fae6e9adSlinfeng } 81*fae6e9adSlinfeng 82*fae6e9adSlinfeng /// The event type in our particular use case will be `PERF_RECORD_SAMPLE` or `PERF_RECORD_LOST`. 83*fae6e9adSlinfeng /// `PERF_RECORD_SAMPLE` indicating that there is an actual sample after this header. 84*fae6e9adSlinfeng /// And `PERF_RECORD_LOST` indicating that there is a record lost header following the perf event header. 85*fae6e9adSlinfeng #[repr(C)] 86*fae6e9adSlinfeng #[derive(Debug)] 87*fae6e9adSlinfeng pub struct LostSamples { 88*fae6e9adSlinfeng pub header: perf_event_header, 89*fae6e9adSlinfeng pub id: u64, 90*fae6e9adSlinfeng pub count: u64, 91*fae6e9adSlinfeng } 92*fae6e9adSlinfeng 93*fae6e9adSlinfeng impl LostSamples { 94*fae6e9adSlinfeng pub fn as_bytes(&self) -> &[u8] { 95*fae6e9adSlinfeng unsafe { core::slice::from_raw_parts(self as *const Self as *const u8, size_of::<Self>()) } 96*fae6e9adSlinfeng } 97*fae6e9adSlinfeng } 98*fae6e9adSlinfeng 99*fae6e9adSlinfeng #[repr(C)] 100*fae6e9adSlinfeng #[derive(Debug)] 101*fae6e9adSlinfeng pub struct SampleHeader { 102*fae6e9adSlinfeng pub header: perf_event_header, 103*fae6e9adSlinfeng pub size: u32, 104*fae6e9adSlinfeng } 105*fae6e9adSlinfeng 106*fae6e9adSlinfeng impl SampleHeader { 107*fae6e9adSlinfeng pub fn as_bytes(&self) -> &[u8] { 108*fae6e9adSlinfeng unsafe { core::slice::from_raw_parts(self as *const Self as *const u8, size_of::<Self>()) } 109*fae6e9adSlinfeng } 110*fae6e9adSlinfeng } 111*fae6e9adSlinfeng 112*fae6e9adSlinfeng #[repr(C)] 113*fae6e9adSlinfeng #[derive(Debug)] 114*fae6e9adSlinfeng pub struct PerfSample<'a> { 115*fae6e9adSlinfeng pub s_hdr: SampleHeader, 116*fae6e9adSlinfeng pub value: &'a [u8], 117*fae6e9adSlinfeng } 118*fae6e9adSlinfeng 119*fae6e9adSlinfeng impl<'a> PerfSample<'a> { 120*fae6e9adSlinfeng pub fn calculate_size(value_size: usize) -> usize { 121*fae6e9adSlinfeng size_of::<SampleHeader>() + value_size 122*fae6e9adSlinfeng } 123*fae6e9adSlinfeng } 124