Skip to main content

vmi_driver_kdmp/
lib.rs

1//! VMI driver for kernel memory dump.
2
3mod arch;
4
5use std::path::Path;
6
7use kdmp_parser::{gxa::Gpa, map::MappedFileReader, parse::KernelDumpParser, phys::Reader};
8use vmi_core::{
9    Gfn, Pa, Va, VcpuId, VmiDriver, VmiError, VmiInfo, VmiMappedPage,
10    driver::{VmiQueryRegisters, VmiRead},
11};
12
13pub use self::arch::{
14    ArchAdapter,
15    header64::{ExceptionRecord64, Header64},
16};
17
18/// VMI driver for kernel memory dump.
19pub struct VmiKdmpDriver<Arch>
20where
21    Arch: ArchAdapter,
22{
23    pub(crate) dump: KernelDumpParser,
24    _marker: std::marker::PhantomData<Arch>,
25}
26
27impl<Arch> VmiKdmpDriver<Arch>
28where
29    Arch: ArchAdapter,
30{
31    /// Creates a new VMI driver for kernel memory dump.
32    pub fn new(path: impl AsRef<Path>) -> Result<Self, VmiError> {
33        let reader = MappedFileReader::new(path)?;
34        let dump = KernelDumpParser::with_reader(reader).map_err(map_kdmp_error)?;
35
36        Ok(Self {
37            dump,
38            _marker: std::marker::PhantomData,
39        })
40    }
41
42    /// Returns the dump header.
43    pub fn header(&self) -> Arch::Header {
44        Arch::header(self)
45    }
46}
47
48impl<Arch> VmiDriver for VmiKdmpDriver<Arch>
49where
50    Arch: ArchAdapter,
51{
52    type Architecture = Arch;
53
54    fn info(&self) -> Result<VmiInfo, VmiError> {
55        Ok(VmiInfo {
56            page_size: 4096,
57            page_shift: 12,
58            max_gfn: Gfn(0),
59            vcpus: 0,
60        })
61    }
62}
63
64impl<Arch> VmiRead for VmiKdmpDriver<Arch>
65where
66    Arch: ArchAdapter,
67{
68    fn read_page(&self, gfn: Gfn) -> Result<VmiMappedPage, VmiError> {
69        let reader = Reader::new(&self.dump);
70
71        let mut content = [0u8; 4096];
72        reader
73            .read_exact(Gpa::new(gfn.0 << 12), &mut content)
74            .map_err(map_kdmp_error)?;
75
76        Ok(VmiMappedPage::new(Vec::from(content)))
77    }
78}
79
80impl<Arch> VmiQueryRegisters for VmiKdmpDriver<Arch>
81where
82    Arch: ArchAdapter,
83{
84    fn registers(&self, vcpu: VcpuId) -> Result<Arch::Registers, VmiError> {
85        Arch::registers(self, vcpu)
86    }
87}
88
89/// Converts a [`kdmp_parser`] error into a [`VmiError`], translating page-read
90/// failures into page faults so callers see a [`VmiError::Translation`]
91/// instead of an opaque driver error.
92pub(crate) fn map_kdmp_error(err: kdmp_parser::error::Error) -> VmiError {
93    match err {
94        kdmp_parser::error::Error::PageRead(kdmp_parser::error::PageReadError::NotPresent {
95            gva,
96            ..
97        }) => VmiError::translation((Va(u64::from(gva)), Pa(0))),
98        kdmp_parser::error::Error::PageRead(kdmp_parser::error::PageReadError::NotInDump {
99            gva: Some((gva, _)),
100            ..
101        }) => VmiError::translation((Va(u64::from(gva)), Pa(0))),
102        other => VmiError::driver(other),
103    }
104}