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