1#![deny(unsafe_code)]
2#![warn(missing_docs)]
3pub mod lzo;
11pub mod object_reader;
12pub mod pagefile;
13pub mod proto_pte;
14pub mod test_builders;
15pub mod vas;
16
17#[non_exhaustive]
19#[derive(Debug, thiserror::Error)]
20pub enum Error {
21 #[error("physical memory error: {0}")]
23 Physical(#[from] memf_format::Error),
24
25 #[error("symbol error: {0}")]
27 Symbol(#[from] memf_symbols::Error),
28
29 #[error("page not present at virtual address {0:#018x}")]
31 PageNotPresent(u64),
32
33 #[error("partial read: got {got} of {requested} bytes at {addr:#018x}")]
35 PartialRead {
36 addr: u64,
38 requested: usize,
40 got: usize,
42 },
43
44 #[error("missing symbol or field: {0}")]
46 MissingSymbol(String),
47
48 #[error("type size mismatch: expected {expected}, got {got}")]
50 SizeMismatch {
51 expected: usize,
53 got: usize,
55 },
56
57 #[error("list walk exceeded {0} iterations (possible cycle)")]
59 ListCycle(usize),
60
61 #[error("page at {vaddr:#018x} paged out to pagefile {pagefile_num} offset {page_offset:#x}")]
63 PagedOut {
64 vaddr: u64,
66 pagefile_num: u8,
68 page_offset: u64,
70 },
71
72 #[error("prototype PTE at {0:#018x} (not yet supported)")]
74 PrototypePte(u64),
75}
76
77pub type Result<T> = std::result::Result<T, Error>;
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 #[test]
85 fn error_display_page_not_present() {
86 let e = Error::PageNotPresent(0xFFFF_8000_0000_1000);
87 assert!(e.to_string().contains("0xffff800000001000"));
88 }
89
90 #[test]
91 fn error_display_partial_read() {
92 let e = Error::PartialRead {
93 addr: 0x1000,
94 requested: 8,
95 got: 4,
96 };
97 assert!(e.to_string().contains("4 of 8"));
98 }
99
100 #[test]
101 fn error_display_list_cycle() {
102 let e = Error::ListCycle(10000);
103 assert!(e.to_string().contains("10000"));
104 }
105
106 #[test]
107 fn error_display_missing_symbol() {
108 let e = Error::MissingSymbol("task_struct.pid".into());
109 assert!(e.to_string().contains("task_struct.pid"));
110 }
111
112 #[test]
113 fn error_display_size_mismatch() {
114 let e = Error::SizeMismatch {
115 expected: 8,
116 got: 4,
117 };
118 let msg = e.to_string();
119 assert!(msg.contains('8'));
120 assert!(msg.contains('4'));
121 }
122
123 #[test]
124 fn error_from_physical() {
125 let phys_err = memf_format::Error::UnknownFormat;
126 let e: Error = Error::from(phys_err);
127 assert!(matches!(e, Error::Physical(_)));
128 assert!(e.to_string().contains("unknown dump format"));
129 }
130
131 #[test]
132 fn error_from_symbol() {
133 let sym_err = memf_symbols::Error::NotFound("init_task".into());
134 let e: Error = Error::from(sym_err);
135 assert!(matches!(e, Error::Symbol(_)));
136 assert!(e.to_string().contains("init_task"));
137 }
138
139 #[test]
140 fn error_from_io_via_physical() {
141 let io_err = std::io::Error::new(std::io::ErrorKind::NotFound, "file gone");
142 let phys_err = memf_format::Error::from(io_err);
143 let e: Error = Error::from(phys_err);
144 assert!(matches!(e, Error::Physical(_)));
145 }
146
147 #[test]
148 fn error_display_paged_out() {
149 let e = Error::PagedOut {
150 vaddr: 0xFFFF_8000_0000_2000,
151 pagefile_num: 0,
152 page_offset: 0x1234,
153 };
154 let msg = e.to_string();
155 assert!(msg.contains("0xffff800000002000"));
156 assert!(msg.contains("pagefile 0"));
157 assert!(msg.contains("0x1234"));
158 }
159
160 #[test]
161 fn error_display_prototype_pte() {
162 let e = Error::PrototypePte(0xFFFF_8000_DEAD_0000);
163 let msg = e.to_string();
164 assert!(msg.contains("0xffff8000dead0000"));
165 assert!(msg.contains("prototype PTE"));
166 }
167}