Skip to main content

libipt/event/
mod.rs

1use libipt_sys::{
2    pt_event, pt_event_type_ptev_async_branch, pt_event_type_ptev_async_disabled,
3    pt_event_type_ptev_async_paging, pt_event_type_ptev_async_vmcs, pt_event_type_ptev_cbr,
4    pt_event_type_ptev_disabled, pt_event_type_ptev_enabled, pt_event_type_ptev_exec_mode,
5    pt_event_type_ptev_exstop, pt_event_type_ptev_mnt, pt_event_type_ptev_mwait,
6    pt_event_type_ptev_overflow, pt_event_type_ptev_paging, pt_event_type_ptev_ptwrite,
7    pt_event_type_ptev_pwre, pt_event_type_ptev_pwrx, pt_event_type_ptev_stop,
8    pt_event_type_ptev_tick, pt_event_type_ptev_tsx, pt_event_type_ptev_vmcs,
9};
10use std::fmt::{Debug, Formatter};
11
12mod enabled;
13pub use enabled::*;
14mod disabled;
15pub use disabled::*;
16mod branch;
17pub use branch::*;
18mod paging;
19pub use paging::*;
20mod overflow;
21pub use overflow::*;
22mod exec_mode;
23pub use exec_mode::*;
24mod tsx;
25pub use tsx::*;
26mod vmcs;
27pub use vmcs::*;
28mod exstop;
29pub use exstop::*;
30mod mwait;
31pub use mwait::*;
32mod pwre;
33pub use pwre::*;
34mod pwrx;
35pub use pwrx::*;
36mod ptwrite;
37pub use ptwrite::*;
38mod tick;
39pub use tick::*;
40mod mnt;
41pub use mnt::*;
42mod cbr;
43pub use cbr::*;
44mod stop;
45pub use stop::*;
46
47mod qry;
48pub use qry::*;
49
50#[derive(Debug, Clone)]
51pub enum EventType {
52    Enabled(Enabled),
53    Disabled(Disabled),
54    AsnycDisabled(AsyncDisabled),
55    AsyncBranch(AsyncBranch),
56    Paging(Paging),
57    AsyncPaging(AsyncPaging),
58    Overflow(Overflow),
59    ExecMode(ExecMode),
60    Tsx(Tsx),
61    Vmcs(Vmcs),
62    AsyncVmcs(AsyncVmcs),
63    Exstop(Exstop),
64    Mwait(Mwait),
65    Pwre(Pwre),
66    Pwrx(Pwrx),
67    Ptwrite(Ptwrite),
68    Tick(Tick),
69    Mnt(Mnt),
70    Cbr(Cbr),
71    Stop(Stop),
72}
73
74impl From<Event> for EventType {
75    fn from(event: Event) -> EventType {
76        event.event_type()
77    }
78}
79
80#[derive(Clone, Copy)]
81#[repr(transparent)]
82pub struct Event(pub(crate) pt_event);
83
84impl Event {
85    /// A flag indicating that the event IP has been suppressed.
86    #[must_use]
87    pub fn ip_suppressed(&self) -> bool {
88        self.0.ip_suppressed() > 0
89    }
90
91    /// A flag indicating that the event is for status update.
92    #[must_use]
93    pub fn status_update(&self) -> bool {
94        self.0.status_update() > 0
95    }
96
97    /// The time stamp count of the event.
98    ///
99    /// Returns `None` if tsc information is not available
100    #[must_use]
101    pub fn tsc(&self) -> Option<u64> {
102        if self.0.has_tsc() > 0 {
103            Some(self.0.tsc)
104        } else {
105            None
106        }
107    }
108
109    /// The number of lost mtc packets.
110    ///
111    /// This gives an idea about the quality of the \@tsc.
112    /// The more packets were dropped, the less precise timing is.
113    #[must_use]
114    pub const fn lost_mtc(&self) -> u32 {
115        self.0.lost_mtc
116    }
117
118    /// The number of lost cyc packets.
119    ///
120    /// This gives an idea about the quality of the \@tsc.
121    /// The more packets were dropped, the less precise timing is.
122    #[must_use]
123    pub const fn lost_cyc(&self) -> u32 {
124        self.0.lost_cyc
125    }
126
127    /// Event specific data.
128    #[must_use]
129    #[allow(non_upper_case_globals)]
130    pub const fn event_type(self) -> EventType {
131        match self.0.type_ {
132            pt_event_type_ptev_async_branch => EventType::AsyncBranch(AsyncBranch { event: self }),
133            pt_event_type_ptev_async_disabled => {
134                EventType::AsnycDisabled(AsyncDisabled { event: self })
135            }
136            pt_event_type_ptev_async_paging => EventType::AsyncPaging(AsyncPaging { event: self }),
137            pt_event_type_ptev_async_vmcs => EventType::AsyncVmcs(AsyncVmcs { event: self }),
138            pt_event_type_ptev_cbr => EventType::Cbr(Cbr { event: self }),
139            pt_event_type_ptev_disabled => EventType::Disabled(Disabled { event: self }),
140            pt_event_type_ptev_enabled => EventType::Enabled(Enabled { event: self }),
141            pt_event_type_ptev_exec_mode => EventType::ExecMode(ExecMode { event: self }),
142            pt_event_type_ptev_exstop => EventType::Exstop(Exstop { event: self }),
143            pt_event_type_ptev_mnt => EventType::Mnt(Mnt { event: self }),
144            pt_event_type_ptev_mwait => EventType::Mwait(Mwait { event: self }),
145            pt_event_type_ptev_overflow => EventType::Overflow(Overflow { event: self }),
146            pt_event_type_ptev_paging => EventType::Paging(Paging { event: self }),
147            pt_event_type_ptev_ptwrite => EventType::Ptwrite(Ptwrite { event: self }),
148            pt_event_type_ptev_pwre => EventType::Pwre(Pwre { event: self }),
149            pt_event_type_ptev_pwrx => EventType::Pwrx(Pwrx { event: self }),
150            pt_event_type_ptev_tick => EventType::Tick(Tick { event: self }),
151            pt_event_type_ptev_tsx => EventType::Tsx(Tsx { event: self }),
152            pt_event_type_ptev_vmcs => EventType::Vmcs(Vmcs { event: self }),
153            pt_event_type_ptev_stop => EventType::Stop(Stop { event: self }),
154            _ => unreachable!(),
155        }
156    }
157
158    pub(crate) fn fmt_common_fields(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
159        write!(
160            f,
161            "ip_suppressed : {:?}, status_update: {:?}, tsc: {:?}, lost_mtc: {:?}, lost_cyc: {:?},",
162            self.ip_suppressed(),
163            self.status_update(),
164            self.tsc(),
165            self.lost_mtc(),
166            self.lost_cyc(),
167        )
168    }
169}
170
171impl Debug for Event {
172    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
173        self.event_type().fmt(f)
174    }
175}
176
177#[cfg(test)]
178mod test {
179    use super::*;
180    use libipt_sys::pt_event_type_ptev_stop;
181    use std::mem;
182
183    #[test]
184    fn test_create_event() {
185        let evt = pt_event {
186            type_: pt_event_type_ptev_stop,
187            tsc: 1,
188            lost_mtc: 2,
189            lost_cyc: 3,
190            _bitfield_1: pt_event::new_bitfield_1(1, 0, 1),
191            variant: unsafe { mem::zeroed() },
192            reserved: [0; 2],
193            _bitfield_align_1: [],
194        };
195
196        let evt = Event(evt);
197        assert!(evt.ip_suppressed());
198        assert!(!evt.status_update());
199
200        assert_eq!(evt.tsc(), Some(1));
201        assert_eq!(evt.lost_mtc(), 2);
202        assert_eq!(evt.lost_cyc(), 3);
203
204        assert!(matches!(EventType::from(evt), EventType::Stop(Stop { .. })));
205    }
206}