perf_event_open/sample/record/bpf.rs
1use super::RecordId;
2
3#[cfg(feature = "linux-5.1")]
4const BPF_TAG_SIZE: u32 = crate::ffi::bindings::BPF_TAG_SIZE;
5// NOTE: There is no `BPF_TAG_SIZE` before Linux 5.1, if the tag size changes
6// in the future we need to ensure ABI compatibility.
7#[cfg(not(feature = "linux-5.1"))]
8const BPF_TAG_SIZE: u32 = 8;
9
10/// BPF event.
11///
12/// # Examples
13///
14/// Running this example may require root privileges.
15///
16/// ```rust, no_run
17/// # tokio_test::block_on(async {
18/// use std::sync::atomic::{AtomicBool, Ordering};
19/// use std::sync::mpsc::channel;
20/// use std::thread;
21///
22/// use perf_event_open::config::{Cpu, Opts, Proc, WakeUpOn};
23/// use perf_event_open::count::Counter;
24/// use perf_event_open::event::sw::Software;
25///
26/// static WAIT: AtomicBool = AtomicBool::new(true);
27///
28/// let (tid_tx, tid_rx) = channel();
29/// thread::spawn(move || {
30/// tid_tx.send(unsafe { libc::gettid() }).unwrap();
31///
32/// while WAIT.load(Ordering::Relaxed) {
33/// std::hint::spin_loop();
34/// }
35///
36/// // Load a BPF program to trigger a `BpfEvent` record.
37/// aya::Ebpf::load_file("HelloWorld.bpf.o").unwrap();
38/// });
39///
40/// let event = Software::Dummy;
41/// let target = (Proc(tid_rx.recv().unwrap() as _), Cpu::ALL);
42///
43/// let mut opts = Opts::default();
44/// opts.wake_up.on = WakeUpOn::Bytes(1);
45/// opts.extra_record.bpf_event = true;
46///
47/// let counter = Counter::new(event, target, opts).unwrap();
48/// let sampler = counter.sampler(5).unwrap();
49///
50/// counter.enable().unwrap();
51/// WAIT.store(false, Ordering::Relaxed);
52///
53/// let mut iter = sampler.iter().into_async().unwrap();
54/// while let Some(it) = iter.next().await {
55/// println!("{:-?}", it);
56/// }
57/// # });
58/// ```
59///
60/// Since `linux-5.1`: <https://github.com/torvalds/linux/commit/6ee52e2a3fe4ea35520720736e6791df1fb67106>
61#[derive(Clone)]
62#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
63pub struct BpfEvent {
64 /// Record IDs.
65 pub record_id: Option<RecordId>,
66
67 /// BPF event type.
68 pub ty: Type,
69 /// BPF program ID.
70 pub id: u32,
71 /// BPF program tag.
72 pub tag: [u8; BPF_TAG_SIZE as _],
73 /// Flags.
74 pub flags: u16,
75}
76
77impl BpfEvent {
78 #[cfg(feature = "linux-5.1")]
79 pub(crate) unsafe fn from_ptr(
80 mut ptr: *const u8,
81 sample_id_all: Option<super::SampleType>,
82 ) -> Self {
83 use super::SampleType;
84 use crate::ffi::{bindings as b, deref_offset};
85
86 // https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L1175
87 // struct {
88 // struct perf_event_header header;
89 // u16 type;
90 // u16 flags;
91 // u32 id;
92 // u8 tag[BPF_TAG_SIZE];
93 // struct sample_id sample_id;
94 // };
95
96 let ty = match deref_offset::<u16>(&mut ptr) as _ {
97 b::PERF_BPF_EVENT_PROG_LOAD => Type::ProgLoad,
98 b::PERF_BPF_EVENT_PROG_UNLOAD => Type::ProgUnload,
99 b::PERF_BPF_EVENT_UNKNOWN => Type::Unknown,
100 _ => Type::Unknown, // For compatibility, not ABI.
101 };
102 let flags = deref_offset(&mut ptr);
103 let id = deref_offset(&mut ptr);
104 let tag = deref_offset(&mut ptr);
105 let record_id = sample_id_all.map(|SampleType(ty)| RecordId::from_ptr(ptr, ty));
106
107 Self {
108 record_id,
109 ty,
110 id,
111 tag,
112 flags,
113 }
114 }
115}
116
117super::from!(BpfEvent);
118
119super::debug!(BpfEvent {
120 {record_id?},
121 {ty},
122 {id},
123 {tag},
124 {flags},
125});
126
127// https://github.com/torvalds/linux/blob/v6.13/include/uapi/linux/perf_event.h#L1245
128/// BPF event type.
129#[derive(Clone, Debug)]
130#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
131pub enum Type {
132 // PERF_BPF_EVENT_PROG_LOAD
133 /// BPF program load.
134 ProgLoad,
135 // PERF_BPF_EVENT_PROG_UNLOAD
136 /// BPF program unload.
137 ProgUnload,
138 // PERF_BPF_EVENT_UNKNOWN
139 /// Unknown.
140 Unknown,
141}