1use alloc::string::String;
2
3use bitflags::bitflags;
4use int_enum::IntEnum;
5
6use crate::{BpfError, BpfResult as Result, KernelAuxiliaryOps, linux_bpf::*};
7
8bitflags! {
9 #[derive(Debug, Clone, Copy)]
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#[repr(u32)]
22#[derive(Debug, Copy, Clone, PartialEq, Eq, IntEnum)]
23pub enum PerfEventIoc {
24 Enable = 9216,
26 Disable = 9217,
28 SetBpf = 1074013192,
30}
31
32#[allow(non_camel_case_types, missing_docs)]
33#[repr(u32)]
34#[derive(Debug, Copy, Clone, PartialEq, Eq, IntEnum)]
35pub enum PerfTypeId {
36 PERF_TYPE_HARDWARE = 0,
37 PERF_TYPE_SOFTWARE = 1,
38 PERF_TYPE_TRACEPOINT = 2,
39 PERF_TYPE_HW_CACHE = 3,
40 PERF_TYPE_RAW = 4,
41 PERF_TYPE_BREAKPOINT = 5,
42 PERF_TYPE_KPROBE = 6,
44 PERF_TYPE_UPROBE = 7,
45}
46
47#[derive(Debug, Clone)]
48#[allow(unused)]
49pub struct PerfProbeArgs {
51 pub config: PerfProbeConfig,
53 pub name: String,
55 pub offset: u64,
57 pub size: u32,
59 pub type_: PerfTypeId,
61 pub pid: i32,
63 pub cpu: i32,
65 pub group_fd: i32,
67 pub flags: PerfEventOpenFlags,
69 pub sample_type: Option<perf_event_sample_format>,
71}
72
73#[derive(Debug, Clone, Copy, PartialEq, Eq)]
75pub enum PerfProbeConfig {
76 PerfSwIds(perf_sw_ids),
78 Raw(u64),
80}
81
82impl PerfProbeArgs {
83 pub fn try_from_perf_attr<F: KernelAuxiliaryOps>(
85 attr: &perf_event_attr,
86 pid: i32,
87 cpu: i32,
88 group_fd: i32,
89 flags: u32,
90 ) -> Result<Self> {
91 let ty = PerfTypeId::try_from(attr.type_).map_err(|_| BpfError::EINVAL)?;
92 let config = match ty {
93 PerfTypeId::PERF_TYPE_KPROBE
94 | PerfTypeId::PERF_TYPE_UPROBE
95 | PerfTypeId::PERF_TYPE_TRACEPOINT => PerfProbeConfig::Raw(attr.config),
96 _ => {
97 let sw_id =
98 perf_sw_ids::try_from(attr.config as u32).map_err(|_| BpfError::EINVAL)?;
99 PerfProbeConfig::PerfSwIds(sw_id)
100 }
101 };
102
103 let name = if ty == PerfTypeId::PERF_TYPE_KPROBE || ty == PerfTypeId::PERF_TYPE_UPROBE {
104 let name_ptr = unsafe { attr.__bindgen_anon_3.config1 } as *const u8;
105
106 F::string_from_user_cstr(name_ptr)?
107 } else {
108 String::new()
109 };
110 let sample_ty = perf_event_sample_format::try_from(attr.sample_type as u32).ok();
111 let args = PerfProbeArgs {
112 config,
113 name,
114 offset: unsafe { attr.__bindgen_anon_4.config2 },
115 size: attr.size,
116 type_: ty,
117 pid,
118 cpu,
119 group_fd,
120 flags: PerfEventOpenFlags::from_bits_truncate(flags),
121 sample_type: sample_ty,
122 };
123 Ok(args)
124 }
125}
126
127#[repr(C)]
131#[derive(Debug)]
132pub struct LostSamples {
133 pub header: perf_event_header,
134 pub id: u64,
135 pub count: u64,
136}
137
138impl LostSamples {
139 pub fn as_bytes(&self) -> &[u8] {
140 unsafe { core::slice::from_raw_parts(self as *const Self as *const u8, size_of::<Self>()) }
141 }
142}
143
144#[repr(C)]
145#[derive(Debug)]
146pub struct SampleHeader {
147 pub header: perf_event_header,
148 pub size: u32,
149}
150
151impl SampleHeader {
152 pub fn as_bytes(&self) -> &[u8] {
153 unsafe { core::slice::from_raw_parts(self as *const Self as *const u8, size_of::<Self>()) }
154 }
155}
156
157#[repr(C)]
158#[derive(Debug)]
159pub struct PerfSample<'a> {
160 pub s_hdr: SampleHeader,
161 pub value: &'a [u8],
162}
163
164impl PerfSample<'_> {
165 pub fn calculate_size(value_size: usize) -> usize {
166 size_of::<SampleHeader>() + value_size
167 }
168}