vmi_utils/bpm/controller/
breakpoint.rs

1use vmi_core::{
2    Architecture, Gfn, MemoryAccess, Pa, Registers as _, Va, View, VmiCore, VmiDriver, VmiError,
3    VmiEvent,
4    arch::{EventInterrupt as _, EventReason},
5};
6
7use super::TapController;
8use crate::interceptor::Interceptor;
9
10#[doc = include_str!("breakpoint.md")]
11pub struct BreakpointController<Driver>
12where
13    Driver: VmiDriver,
14    <Driver::Architecture as Architecture>::EventReason:
15        EventReason<Architecture = Driver::Architecture>,
16{
17    interceptor: Interceptor<Driver>,
18}
19
20impl<Driver> BreakpointController<Driver>
21where
22    Driver: VmiDriver,
23    <Driver::Architecture as Architecture>::EventReason:
24        EventReason<Architecture = Driver::Architecture>,
25{
26    /// Checks if the given event was caused by a software breakpoint.
27    pub fn is_breakpoint(
28        vmi: &VmiCore<Driver>,
29        event: &VmiEvent<Driver::Architecture>,
30    ) -> Result<bool, VmiError> {
31        let interrupt = match event.reason().as_software_breakpoint() {
32            Some(interrupt) => interrupt,
33            None => return Ok(false),
34        };
35
36        let va = Va(event.registers().instruction_pointer());
37        let pa = Driver::Architecture::pa_from_gfn(interrupt.gfn())
38            + Driver::Architecture::va_offset(va);
39
40        let mut content = vec![0; Driver::Architecture::BREAKPOINT.len()];
41        vmi.read(pa, &mut content)?;
42
43        Ok(content == Driver::Architecture::BREAKPOINT)
44    }
45}
46
47impl<Driver> TapController for BreakpointController<Driver>
48where
49    Driver: VmiDriver,
50    <Driver::Architecture as Architecture>::EventReason:
51        EventReason<Architecture = Driver::Architecture>,
52{
53    type Driver = Driver;
54
55    fn new() -> Self {
56        Self {
57            interceptor: Interceptor::new(),
58        }
59    }
60
61    fn check_event(&self, event: &VmiEvent<Driver::Architecture>) -> Option<(View, Gfn)> {
62        let interrupt = event.reason().as_software_breakpoint()?;
63        let view = event.view()?;
64
65        Some((view, interrupt.gfn()))
66    }
67
68    fn insert_breakpoint(
69        &mut self,
70        vmi: &VmiCore<Driver>,
71        pa: Pa,
72        view: View,
73    ) -> Result<(), VmiError> {
74        self.interceptor.insert_breakpoint(vmi, pa, view)?;
75        Ok(())
76    }
77
78    fn remove_breakpoint(
79        &mut self,
80        vmi: &VmiCore<Driver>,
81        pa: Pa,
82        view: View,
83    ) -> Result<(), VmiError> {
84        let breakpoint_was_removed = self.interceptor.remove_breakpoint(vmi, pa, view)?;
85        debug_assert_eq!(breakpoint_was_removed, Some(true));
86        Ok(())
87    }
88
89    fn monitor(&mut self, vmi: &VmiCore<Driver>, gfn: Gfn, view: View) -> Result<(), VmiError> {
90        vmi.set_memory_access(gfn, view, MemoryAccess::X)
91    }
92
93    fn unmonitor(&mut self, vmi: &VmiCore<Driver>, gfn: Gfn, view: View) -> Result<(), VmiError> {
94        vmi.set_memory_access(gfn, view, MemoryAccess::RWX)
95    }
96}