libipt/event/
exec_mode.rs

1// Certain casts are required only on Windows. Inform Clippy to ignore them.
2#![allow(clippy::unnecessary_cast)]
3
4use crate::error::{PtError, PtErrorCode};
5use crate::event::Event;
6use derive_more::Deref;
7use libipt_sys::{
8    pt_event_type_ptev_exec_mode, pt_exec_mode_ptem_16bit, pt_exec_mode_ptem_32bit,
9    pt_exec_mode_ptem_64bit, pt_exec_mode_ptem_unknown,
10};
11use num_enum::TryFromPrimitive;
12use std::convert::TryFrom;
13use std::fmt::{Debug, Formatter};
14
15#[derive(Clone, Copy, TryFromPrimitive, Debug, PartialEq)]
16#[repr(u32)]
17pub enum ExecModeType {
18    Bit16 = pt_exec_mode_ptem_16bit as u32,
19    Bit32 = pt_exec_mode_ptem_32bit as u32,
20    Bit64 = pt_exec_mode_ptem_64bit as u32,
21    Unknown = pt_exec_mode_ptem_unknown as u32,
22}
23
24/// An execution mode change
25#[derive(Clone, Copy, Deref)]
26#[repr(transparent)]
27pub struct ExecMode {
28    pub(super) event: Event,
29}
30impl ExecMode {
31    /// The address at which the event is effective
32    #[must_use]
33    pub const fn ip(&self) -> u64 {
34        unsafe { self.event.0.variant.exec_mode.ip }
35    }
36
37    /// The execution mode
38    #[must_use]
39    pub fn mode(&self) -> ExecModeType {
40        ExecModeType::try_from(unsafe { self.event.0.variant.exec_mode.mode } as u32).unwrap()
41    }
42}
43
44impl Debug for ExecMode {
45    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
46        write!(f, "ExecMode {{")?;
47        self.fmt_common_fields(f)?;
48        write!(f, "ip: 0x{:x?}, mode: {:?} }}", self.ip(), self.mode())
49    }
50}
51
52impl TryFrom<Event> for ExecMode {
53    type Error = PtError;
54
55    fn try_from(event: Event) -> Result<Self, Self::Error> {
56        if event.0.type_ == pt_event_type_ptev_exec_mode {
57            Ok(Self { event })
58        } else {
59            Err(PtErrorCode::Invalid.into())
60        }
61    }
62}
63
64#[cfg(test)]
65mod test {
66    use super::super::EventType;
67    use super::*;
68    use crate::event::Event;
69    use libipt_sys::{pt_event, pt_event_type_ptev_exec_mode};
70    use std::mem;
71
72    #[test]
73    fn test_exec_mode_payload() {
74        let mut evt: pt_event = unsafe { mem::zeroed() };
75        evt.type_ = pt_event_type_ptev_exec_mode;
76
77        evt.variant.exec_mode.ip = 11;
78        evt.variant.exec_mode.mode = pt_exec_mode_ptem_32bit;
79
80        let payload: EventType = Event(evt).into();
81        match payload {
82            EventType::ExecMode(e) => {
83                assert_eq!(e.ip(), 11);
84                assert_eq!(e.mode(), ExecModeType::Bit32);
85            }
86            _ => unreachable!("oof"),
87        }
88    }
89}