perf_event_open_sys/
attr.rs

1//! This module contains a chain of deref structs which contain fields from
2//! the unnamed unions within the [`perf_event_attr`] struct. This deref chain
3//! allows users to access the relevant inline union fields directly, the same
4//! as they would in C. By extension, that allows certain changes which would
5//! be non-breaking in C but breaking changes in bindgen-generated Rust to
6//! instead be non-breaking.
7//!
8//! The way it works is that we have several structs which manually place
9//! fields at the appropriate offset. [`perf_event_attr`] derefs to one and
10//! the chain continues on from there. All derefs are done by pointer casts
11//! on `self` so the whole sequence should compile down to a no-op.
12//!
13//! Note that there is a limitation on how many deref impls rust-analyzer is
14//! willing to traverse for autocompletion. Empirically, that limit seems to
15//! be 9. Multiple fields are batched together here to ensure that the whole
16//! chain of deref impls remains visible to autocomplete.
17
18#![allow(non_camel_case_types)]
19
20use std::mem::{self, MaybeUninit};
21use std::ops::{Deref, DerefMut};
22
23use memoffset::offset_of;
24
25use crate::bindings::{self, perf_event_attr};
26
27#[repr(C)]
28pub struct AttrDeref1 {
29    _pad1: [MaybeUninit<u8>; Layout1::PAD1],
30    pub sample_period: u64,
31    _pad2: [MaybeUninit<u8>; Layout1::PAD2],
32    pub wakeup_events: u32,
33    _pad3: [MaybeUninit<u8>; Layout1::PAD3],
34    pub bp_addr: u64,
35    _pad4: [MaybeUninit<u8>; Layout1::PAD4],
36    pub bp_len: u64,
37    _pad5: [MaybeUninit<u8>; Layout1::PAD5],
38}
39
40#[repr(C)]
41pub struct AttrDeref2 {
42    _pad1: [MaybeUninit<u8>; Layout1::PAD1],
43    pub sample_freq: u64,
44    _pad2: [MaybeUninit<u8>; Layout1::PAD2],
45    pub wakeup_watermark: u32,
46    _pad3: [MaybeUninit<u8>; Layout1::PAD3],
47    pub kprobe_func: u64,
48    _pad4: [MaybeUninit<u8>; Layout1::PAD4],
49    pub kprobe_addr: u64,
50    _pad5: [MaybeUninit<u8>; Layout1::PAD5],
51}
52
53#[repr(C)]
54pub struct AttrDeref3 {
55    _pad1: [MaybeUninit<u8>; Layout2::PAD1],
56    pub uprobe_path: u64,
57    _pad2: [MaybeUninit<u8>; Layout2::PAD2],
58    pub probe_offset: u64,
59    _pad3: [MaybeUninit<u8>; Layout2::PAD3],
60}
61
62#[repr(C)]
63pub struct AttrDeref4 {
64    _pad1: [MaybeUninit<u8>; Layout2::PAD1],
65    pub config1: u64,
66    _pad2: [MaybeUninit<u8>; Layout2::PAD2],
67    pub config2: u64,
68    _pad3: [MaybeUninit<u8>; Layout2::PAD3],
69}
70
71macro_rules! deref_cast {
72    ($source:ident => $target:ident) => {
73        impl Deref for $source {
74            type Target = $target;
75
76            #[inline]
77            fn deref(&self) -> &Self::Target {
78                const _: () = {
79                    assert!(mem::size_of::<$source>() == mem::size_of::<$target>());
80                };
81
82                unsafe { &*(self as *const Self as *const Self::Target) }
83            }
84        }
85
86        impl DerefMut for $source {
87            #[inline]
88            fn deref_mut(&mut self) -> &mut Self::Target {
89                unsafe { &mut *(self as *mut Self as *mut Self::Target) }
90            }
91        }
92    };
93}
94
95deref_cast!(perf_event_attr => AttrDeref1);
96deref_cast!(AttrDeref1 => AttrDeref2);
97deref_cast!(AttrDeref2 => AttrDeref3);
98deref_cast!(AttrDeref3 => AttrDeref4);
99
100enum Offsets {}
101
102impl Offsets {
103    const OFF1: usize = offset_of!(perf_event_attr, __bindgen_anon_1);
104    const OFF2: usize = offset_of!(perf_event_attr, __bindgen_anon_2);
105    const OFF3: usize = offset_of!(perf_event_attr, __bindgen_anon_3);
106    const OFF4: usize = offset_of!(perf_event_attr, __bindgen_anon_4);
107
108    const END1: usize = Self::OFF1 + mem::size_of::<bindings::perf_event_attr__bindgen_ty_1>();
109    const END2: usize = Self::OFF2 + mem::size_of::<bindings::perf_event_attr__bindgen_ty_2>();
110    const END3: usize = Self::OFF3 + mem::size_of::<bindings::perf_event_attr__bindgen_ty_3>();
111    const END4: usize = Self::OFF4 + mem::size_of::<bindings::perf_event_attr__bindgen_ty_4>();
112}
113
114/// Layout with fields from all 4 unions
115enum Layout1 {}
116
117impl Layout1 {
118    const PAD1: usize = Offsets::OFF1;
119    const PAD2: usize = Offsets::OFF2 - Offsets::END1;
120    const PAD3: usize = Offsets::OFF3 - Offsets::END2;
121    const PAD4: usize = Offsets::OFF4 - Offsets::END3;
122    const PAD5: usize = mem::size_of::<perf_event_attr>() - Offsets::END4;
123}
124
125/// Layout with fields from only the last 2 unions
126enum Layout2 {}
127
128impl Layout2 {
129    const PAD1: usize = Offsets::OFF3;
130    const PAD2: usize = Offsets::OFF4 - Offsets::END3;
131    const PAD3: usize = mem::size_of::<perf_event_attr>() - Offsets::END4;
132}