1use crate::{PhysicalAddress, VirtualAddress, VmResult};
2use alloc::{format, string::String, vec::Vec};
3use core::ops::ControlFlow;
4
5#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
6pub struct Module(pub VirtualAddress);
7
8#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
9pub struct Thread(pub VirtualAddress);
10
11#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
12pub struct Process(pub VirtualAddress);
13
14#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
15pub struct Vma(pub VirtualAddress);
16
17#[derive(Debug, Clone, Copy)]
18pub struct VmaFlags(pub u64);
19
20impl VmaFlags {
21 pub const READ: Self = Self(0x1);
22 pub const WRITE: Self = Self(0x2);
23 pub const EXEC: Self = Self(0x4);
24
25 #[inline]
26 pub fn is_read(self) -> bool {
27 self.0 & Self::READ.0 != 0
28 }
29
30 #[inline]
31 pub fn is_write(self) -> bool {
32 self.0 & Self::WRITE.0 != 0
33 }
34
35 #[inline]
36 pub fn is_exec(self) -> bool {
37 self.0 & Self::EXEC.0 != 0
38 }
39}
40
41impl core::ops::BitOr for VmaFlags {
42 type Output = Self;
43
44 #[inline]
45 fn bitor(self, rhs: Self) -> Self {
46 Self(self.0 | rhs.0)
47 }
48}
49
50impl core::ops::BitOrAssign for VmaFlags {
51 #[inline]
52 fn bitor_assign(&mut self, rhs: Self) {
53 self.0 |= rhs.0
54 }
55}
56
57#[inline]
58fn find<'a, T: Copy>(
59 result: &'a mut Option<T>,
60 mut predicate: impl FnMut(T) -> VmResult<bool> + 'a,
61) -> impl FnMut(T) -> VmResult<ControlFlow<()>> + 'a {
62 move |item| {
63 Ok(if predicate(item)? {
64 *result = Some(item);
65 ControlFlow::Break(())
66 } else {
67 ControlFlow::Continue(())
68 })
69 }
70}
71
72#[inline]
73#[allow(clippy::needless_lifetimes)]
74fn push_to<'a, T>(vec: &'a mut Vec<T>) -> impl FnMut(T) -> VmResult<ControlFlow<()>> + 'a {
75 move |item| {
76 vec.push(item);
77 Ok(ControlFlow::Continue(()))
78 }
79}
80
81#[derive(Debug, Clone)]
82pub struct StackFrame {
83 pub start: Option<VirtualAddress>,
84 pub size: Option<u64>,
85 pub stack_pointer: VirtualAddress,
86 pub instruction_pointer: VirtualAddress,
87 pub module: Option<Module>,
88}
89
90pub trait Os: crate::HasVcpus {
91 fn read_virtual_memory(
92 &self,
93 mmu_addr: PhysicalAddress,
94 addr: VirtualAddress,
95 buf: &mut [u8],
96 ) -> VmResult<()>;
97
98 fn try_read_virtual_memory(
99 &self,
100 mmu_addr: PhysicalAddress,
101 addr: VirtualAddress,
102 buf: &mut [u8],
103 ) -> VmResult<()>;
104
105 fn read_process_memory(
106 &self,
107 _proc: Process,
108 mmu_addr: PhysicalAddress,
109 addr: VirtualAddress,
110 buf: &mut [u8],
111 ) -> VmResult<()> {
112 self.read_virtual_memory(mmu_addr, addr, buf)
113 }
114
115 fn try_read_process_memory(
116 &self,
117 _proc: Process,
118 mmu_addr: PhysicalAddress,
119 addr: VirtualAddress,
120 buf: &mut [u8],
121 ) -> VmResult<()> {
122 self.try_read_virtual_memory(mmu_addr, addr, buf)
123 }
124
125 fn read_kernel_memory(&self, addr: VirtualAddress, buf: &mut [u8]) -> VmResult<()> {
126 self.read_virtual_memory(self.kernel_pgd(), addr, buf)
127 }
128
129 fn kernel_pgd(&self) -> PhysicalAddress;
130
131 fn for_each_kernel_module(
132 &self,
133 f: &mut dyn FnMut(Module) -> VmResult<ControlFlow<()>>,
134 ) -> VmResult<()>;
135
136 fn init_process(&self) -> VmResult<Process>;
137 fn current_thread(&self, vcpu: crate::VcpuId) -> VmResult<Thread>;
138 fn current_process(&self, vcpu: crate::VcpuId) -> VmResult<Process> {
139 let thread = self.current_thread(vcpu)?;
140 self.thread_process(thread)
141 }
142 fn find_process_by_name(&self, name: &str) -> VmResult<Option<Process>> {
143 let mut proc = None;
144 self.for_each_process(&mut find(&mut proc, |p| Ok(self.process_name(p)? == name)))?;
145 Ok(proc)
146 }
147 fn find_process_by_id(&self, pid: u64) -> VmResult<Option<Process>> {
148 let mut proc = None;
149 self.for_each_process(&mut find(&mut proc, |p| Ok(self.process_id(p)? == pid)))?;
150 Ok(proc)
151 }
152
153 fn process_is_kernel(&self, proc: Process) -> VmResult<bool>;
154 fn process_id(&self, proc: Process) -> VmResult<u64>;
155 fn process_name(&self, proc: Process) -> VmResult<String>;
156 fn process_pgd(&self, proc: Process) -> VmResult<PhysicalAddress>;
157 fn process_path(&self, proc: Process) -> VmResult<Option<String>>;
158 fn process_parent(&self, proc: Process) -> VmResult<Process>;
159 fn process_parent_id(&self, proc: Process) -> VmResult<u64>;
160 fn process_for_each_child(
161 &self,
162 proc: Process,
163 f: &mut dyn FnMut(Process) -> VmResult<ControlFlow<()>>,
164 ) -> VmResult<()>;
165 fn process_collect_children(&self, proc: Process) -> VmResult<Vec<Process>> {
166 let mut procs = Vec::new();
167 self.process_for_each_child(proc, &mut push_to(&mut procs))?;
168 Ok(procs)
169 }
170 fn process_for_each_thread(
171 &self,
172 proc: Process,
173 f: &mut dyn FnMut(Thread) -> VmResult<ControlFlow<()>>,
174 ) -> VmResult<()>;
175 fn process_collect_threads(&self, proc: Process) -> VmResult<Vec<Thread>> {
176 let mut threads = Vec::new();
177 self.process_for_each_thread(proc, &mut push_to(&mut threads))?;
178 Ok(threads)
179 }
180 fn process_for_each_module(
181 &self,
182 proc: Process,
183 f: &mut dyn FnMut(Module) -> VmResult<ControlFlow<()>>,
184 ) -> VmResult<()>;
185
186 fn process_collect_modules(&self, proc: Process) -> VmResult<Vec<Module>> {
187 let mut modules = Vec::new();
188 self.process_for_each_module(proc, &mut push_to(&mut modules))?;
189 Ok(modules)
190 }
191 fn for_each_process(
192 &self,
193 f: &mut dyn FnMut(Process) -> VmResult<ControlFlow<()>>,
194 ) -> VmResult<()>;
195 fn collect_processes(&self) -> VmResult<Vec<Process>> {
196 let mut procs = Vec::new();
197 self.for_each_process(&mut push_to(&mut procs))?;
198 Ok(procs)
199 }
200 fn process_for_each_vma(
201 &self,
202 proc: Process,
203 f: &mut dyn FnMut(Vma) -> VmResult<ControlFlow<()>>,
204 ) -> VmResult<()>;
205 fn process_collect_vmas(&self, proc: Process) -> VmResult<Vec<Vma>> {
206 let mut vmas = Vec::new();
207 self.process_for_each_vma(proc, &mut push_to(&mut vmas))?;
208 Ok(vmas)
209 }
210
211 fn process_find_vma_by_address(
212 &self,
213 proc: Process,
214 addr: VirtualAddress,
215 ) -> VmResult<Option<Vma>> {
216 let mut vma = None;
217 self.process_for_each_vma(proc, &mut find(&mut vma, |v| self.vma_contains(v, addr)))?;
218 Ok(vma)
219 }
220
221 fn process_callstack(
222 &self,
223 proc: Process,
224 f: &mut dyn FnMut(&StackFrame) -> VmResult<ControlFlow<()>>,
225 ) -> VmResult<()> {
226 #[allow(clippy::never_loop)]
228 let (instruction_pointer, stack_pointer, base_pointer) = 'res: loop {
229 for vcpu in self.iter_vcpus() {
230 if self.current_process(vcpu)? == proc {
231 break 'res (
232 self.instruction_pointer(vcpu)?,
233 self.stack_pointer(vcpu)?,
234 self.base_pointer(vcpu)?,
235 );
236 }
237 }
238
239 return Err(crate::VmError::new("Not a running process"));
240 };
241
242 self.process_callstack_with_regs(proc, instruction_pointer, stack_pointer, base_pointer, f)
243 }
244
245 fn process_callstack_with_regs(
246 &self,
247 proc: Process,
248 instruction_pointer: VirtualAddress,
249 stack_pointer: VirtualAddress,
250 base_pointer: Option<VirtualAddress>,
251 f: &mut dyn FnMut(&StackFrame) -> VmResult<ControlFlow<()>>,
252 ) -> VmResult<()>;
253
254 fn thread_process(&self, thread: Thread) -> VmResult<Process>;
255 fn thread_id(&self, thread: Thread) -> VmResult<u64>;
256 fn thread_name(&self, thread: Thread) -> VmResult<Option<String>>;
257
258 fn vma_path(&self, vma: Vma) -> VmResult<Option<String>>;
259 fn vma_start(&self, vma: Vma) -> VmResult<VirtualAddress>;
260 fn vma_end(&self, vma: Vma) -> VmResult<VirtualAddress>;
261 fn vma_flags(&self, vma: Vma) -> VmResult<VmaFlags>;
262 fn vma_contains(&self, vma: Vma, addr: VirtualAddress) -> VmResult<bool> {
263 Ok(self.vma_start(vma)? <= addr && addr < self.vma_end(vma)?)
264 }
265
266 fn module_span(
267 &self,
268 module: Module,
269 proc: Process,
270 ) -> VmResult<(VirtualAddress, VirtualAddress)>;
271
272 #[inline]
273 fn module_contains(
274 &self,
275 module: Module,
276 proc: Process,
277 addr: VirtualAddress,
278 ) -> VmResult<bool> {
279 let (start, end) = self.module_span(module, proc)?;
280 Ok((start..end).contains(&addr))
281 }
282 fn module_name(&self, module: Module, proc: Process) -> VmResult<String>;
283 fn module_path(&self, module: Module, proc: Process) -> VmResult<String>;
284 fn find_module_by_address(
285 &self,
286 proc: Process,
287 addr: VirtualAddress,
288 ) -> VmResult<Option<Module>> {
289 let mut result = None;
290
291 {
292 let mut find = find(&mut result, |m| self.module_contains(m, proc, addr));
293 if addr.is_kernel() {
294 self.for_each_kernel_module(&mut find)?;
295 } else {
296 self.process_for_each_module(proc, &mut find)?;
297 }
298 }
299
300 Ok(result)
301 }
302
303 fn module_symbols(
304 &self,
305 proc: Process,
306 module: Module,
307 ) -> VmResult<Option<&crate::ModuleSymbols>>;
308
309 fn module_resolve_symbol_exact(
310 &self,
311 addr: VirtualAddress,
312 proc: Process,
313 module: Module,
314 ) -> VmResult<Option<&str>> {
315 let syms = match self.module_symbols(proc, module)? {
316 Some(syms) => syms,
317 None => return Ok(None),
318 };
319
320 let (mod_start, mod_end) = self.module_span(module, proc)?;
321 if !(mod_start..mod_end).contains(&addr) {
322 return Err(crate::VmError::new("address not in module"));
323 }
324 let addr = VirtualAddress((addr - mod_start) as u64);
325
326 Ok(syms.get_symbol(addr))
327 }
328
329 fn module_resolve_symbol(
330 &self,
331 addr: VirtualAddress,
332 proc: Process,
333 module: Module,
334 ) -> VmResult<Option<(&str, u64)>> {
335 let syms = match self.module_symbols(proc, module)? {
336 Some(syms) => syms,
337 None => return Ok(None),
338 };
339
340 let (mod_start, mod_end) = self.module_span(module, proc)?;
341 if !(mod_start..mod_end).contains(&addr) {
342 return Err(crate::VmError::new("address not in module"));
343 }
344 let addr = VirtualAddress((addr - mod_start) as u64);
345
346 Ok(syms.get_symbol_inexact(addr))
347 }
348
349 fn resolve_symbol_exact(&self, addr: VirtualAddress, proc: Process) -> VmResult<Option<&str>> {
350 match self.find_module_by_address(proc, addr)? {
351 Some(module) => self.module_resolve_symbol_exact(addr, proc, module),
352 None => Ok(None),
353 }
354 }
355
356 fn resolve_symbol(&self, addr: VirtualAddress, proc: Process) -> VmResult<Option<(&str, u64)>> {
357 match self.find_module_by_address(proc, addr)? {
358 Some(module) => self.module_resolve_symbol(addr, proc, module),
359 None => Ok(None),
360 }
361 }
362
363 fn format_symbol(
364 &self,
365 proc: Process,
366 addr: VirtualAddress,
367 demangle: bool,
368 ) -> VmResult<String> {
369 match self.find_module_by_address(proc, addr)? {
370 Some(module) => self.format_symbol_with_module(proc, module, addr, None, demangle),
371 None => format_symbol_without_module(self, proc, addr, None),
372 }
373 }
374
375 fn format_symbol_with_module(
376 &self,
377 proc: Process,
378 module: Module,
379 addr: VirtualAddress,
380 fun_start: Option<VirtualAddress>,
381 demangle: bool,
382 ) -> VmResult<String> {
383 let (mod_start, _) = self.module_span(module, proc)?;
384 let mod_name = self.module_name(module, proc)?;
385
386 let symbol = match fun_start {
387 Some(fun_start) => self
388 .module_resolve_symbol_exact(fun_start, proc, module)
389 .map(|s| s.map(|s| (s, (addr - fun_start) as u64))),
390 None => self.module_resolve_symbol(addr, proc, module),
391 };
392 let symbol = symbol.unwrap_or_else(|err| {
393 log::error!("{err}");
394 None
395 });
396
397 fn do_format(
398 addr: VirtualAddress,
399 fun_start: Option<VirtualAddress>,
400 symbol: Option<(&str, u64)>,
401 mod_name: String,
402 mod_start: VirtualAddress,
403 demangle: bool,
404 ) -> String {
405 let symbol = symbol.map(|(s, o)| {
406 (
407 if demangle {
408 crate::symbols::demangle(s)
409 } else {
410 alloc::borrow::Cow::Borrowed(s)
411 },
412 o,
413 )
414 });
415
416 match (symbol, fun_start) {
417 (Some((symbol, 0)), _) => format!("{mod_name}!{symbol}"),
418 (Some((symbol, offset)), _) => format!("{mod_name}!{symbol}+{offset:#x}"),
419 (None, Some(fun_start)) => match addr - fun_start {
420 0 => format!("{mod_name}!{:#x}", fun_start - mod_start),
421 offset => format!("{mod_name}!{:#x}+{offset:#x}", fun_start - mod_start),
422 },
423 (None, None) => format!("{mod_name}!{:#x}", addr - mod_start),
424 }
425 }
426
427 Ok(do_format(
428 addr, fun_start, symbol, mod_name, mod_start, demangle,
429 ))
430 }
431
432 fn format_stackframe_symbol(
433 &self,
434 proc: Process,
435 frame: &StackFrame,
436 demangle: bool,
437 ) -> VmResult<String> {
438 let addr = frame.instruction_pointer;
439 match frame.module {
440 Some(module) => {
441 self.format_symbol_with_module(proc, module, addr, frame.start, demangle)
442 }
443 None => format_symbol_without_module(self, proc, addr, frame.start),
444 }
445 }
446}
447
448fn format_symbol_without_module<O: Os + ?Sized>(
449 os: &O,
450 proc: Process,
451 addr: VirtualAddress,
452 fun_start: Option<VirtualAddress>,
453) -> VmResult<String> {
454 let vma_start = match os.process_find_vma_by_address(proc, addr)? {
455 Some(vma) => Some(os.vma_start(vma)?),
456 None => None,
457 };
458
459 fn do_format(
460 addr: VirtualAddress,
461 fun_start: Option<VirtualAddress>,
462 vma_start: Option<VirtualAddress>,
463 ) -> String {
464 let fun_start = fun_start.map(|start| (start, addr - start));
465
466 match (vma_start, fun_start) {
467 (Some(vma_start), Some((fun_start, 0))) => {
468 let fun_offset = vma_start - fun_start;
469 format!("{vma_start:#x}!{fun_offset:#x}")
470 }
471 (Some(vma_start), Some((fun_start, offset))) => {
472 let fun_offset = vma_start - fun_start;
473 format!("{vma_start:#x}!{fun_offset:#x}+{offset:#x}")
474 }
475 (Some(vma_start), None) => format!("{vma_start:#x}!{:#x}", addr - vma_start),
476 (None, Some((fun_start, 0))) => format!("{fun_start:#x}"),
477 (None, Some((fun_start, offset))) => format!("{fun_start:#x}+{offset:#x}"),
478 (None, None) => format!("{addr:#x}"),
479 }
480 }
481
482 Ok(do_format(addr, fun_start, vma_start))
483}