nyx_lite/
hw_breakpoints.rs

1#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
2pub enum HwBreakpointMode {
3    Exec,
4    Write,
5    ReadWrite,
6}
7
8impl HwBreakpointMode {
9    pub fn bits(&self) -> u64 {
10        match self {
11            Self::Exec => 0b00,
12            Self::Write => 0b01,
13            Self::ReadWrite => 0b11,
14        }
15    }
16}
17
18#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
19pub struct HwBreakpoint {
20    pub addr: u64,
21    pub size: usize,
22    pub mode: HwBreakpointMode,
23}
24
25impl HwBreakpoint {
26    pub fn apply_dr7(&self, bp_index: usize, dr7: u64) -> u64 {
27        assert!(bp_index < 4);
28        const L: usize = 0;
29        const G: usize = 1;
30        const RW: usize = 16; // & 17
31        const LEN: usize = 18; // & 19
32        let mask = (1 << L | 1 << G) << (bp_index * 2) | ((3 << RW | 3 << LEN) << bp_index * 4);
33        let dr7 = dr7 & !(mask << bp_index);
34        let dr7 = dr7
35            | ((1 << L | 1 << G) << bp_index * 2)
36            | (self.mode.bits() << RW | self.size_bits() << LEN) << bp_index * 4;
37        const LE_AND_LG: usize = 8; // &9
38        let dr7 = dr7 | 0b11 << LE_AND_LG; // LE and LG are set unconditionally
39        return dr7;
40    }
41    pub fn size_bits(&self) -> u64 {
42        return match self.size {
43            1 => 0b00,
44            2 => 0b01,
45            4 => 0b11,
46            8 => 0b10,
47            _ => panic!("invalid hw breakpoint size"),
48        };
49    }
50}
51
52pub struct HwBreakpoints {
53    pub bps: [Option<HwBreakpoint>; 4],
54}
55
56impl HwBreakpoints {
57    pub fn new() -> Self {
58        return Self {
59            bps: [None, None, None, None],
60        };
61    }
62    pub fn enable(&mut self, i: usize, addr: u64, size: usize, mode: HwBreakpointMode) {
63        if mode == HwBreakpointMode::Exec {
64            assert_eq!(size, 1);
65        }
66        self.bps[i] = Some(HwBreakpoint { addr, size, mode })
67    }
68    pub fn enable_access(&mut self, i: usize, addr: u64, size: usize) {
69        self.enable(i, addr, size, HwBreakpointMode::ReadWrite);
70    }
71    pub fn enable_write(&mut self, i: usize, addr: u64, size: usize) {
72        self.enable(i, addr, size, HwBreakpointMode::Write);
73    }
74    pub fn enable_exec(&mut self, i: usize, addr: u64) {
75        self.enable(i, addr, 1, HwBreakpointMode::Exec);
76    }
77
78    pub fn disable(&mut self, i: usize) {
79        self.bps[i] = None;
80    }
81    pub fn addr(&self, i: usize) -> u64 {
82        if let Some(ref bp) = self.bps[i] {
83            return bp.addr;
84        }
85        return 0;
86    }
87    pub fn compute_dr7(&self) -> u64 {
88        let mut dr7 = 0;
89        for i in 0..4 {
90            if let Some(ref bp) = self.bps[i] {
91                dr7 = bp.apply_dr7(i, dr7);
92            }
93        }
94        return dr7;
95    }
96
97    pub fn any_active(&self) -> bool {
98        self.bps.iter().any(|b| b.is_some())
99    }
100}