stackdump_capture_probe/
lib.rs

1use probe_rs::MemoryInterface;
2use stackdump_core::{
3    device_memory::MemoryReadError, memory_region::MemoryRegion, register_data::VecRegisterData,
4};
5use std::{cell::RefCell, rc::Rc};
6
7pub struct StackdumpCapturer<'a, 'probe>(RefCell<&'a mut probe_rs::Core<'probe>>);
8
9impl<'a, 'probe> StackdumpCapturer<'a, 'probe> {
10    pub fn new(core: &'a mut probe_rs::Core<'probe>) -> Self {
11        Self(RefCell::new(core))
12    }
13
14    pub fn capture_core_registers(&mut self) -> Result<VecRegisterData<u32>, probe_rs::Error> {
15        let mut register_data = Vec::new();
16        let registers = self.0.get_mut().registers();
17
18        for register in registers.all_registers() {
19            register_data.push(self.0.get_mut().read_core_reg(register)?)
20        }
21
22        let starting_register = match self.0.get_mut().architecture() {
23            probe_rs::Architecture::Arm => stackdump_core::gimli::Arm::R0,
24            probe_rs::Architecture::Riscv => stackdump_core::gimli::RiscV::X0,
25            probe_rs::Architecture::Xtensa => {
26                return Err(probe_rs::Error::NotImplemented(
27                    "register capture for Xtensa",
28                ))
29            }
30        };
31
32        Ok(VecRegisterData::new(starting_register, register_data))
33    }
34
35    pub fn capture_fpu_registers(
36        &mut self,
37    ) -> Result<Option<VecRegisterData<u32>>, probe_rs::Error> {
38        let registers = self.0.get_mut().registers();
39
40        match registers.fpu_registers() {
41            Some(fpu_registers) => {
42                let mut register_data = Vec::new();
43
44                for register in fpu_registers {
45                    register_data.push(self.0.get_mut().read_core_reg(register)?)
46                }
47
48                let starting_register = match self.0.get_mut().architecture() {
49                    probe_rs::Architecture::Arm => stackdump_core::gimli::Arm::S0,
50                    probe_rs::Architecture::Riscv => stackdump_core::gimli::RiscV::F0,
51                    probe_rs::Architecture::Xtensa => {
52                        return Err(probe_rs::Error::NotImplemented(
53                            "register capture for Xtensa",
54                        ))
55                    }
56                };
57
58                Ok(Some(VecRegisterData::new(starting_register, register_data)))
59            }
60            None => Ok(None),
61        }
62    }
63}
64
65impl<'a, 'probe> MemoryRegion for StackdumpCapturer<'a, 'probe> {
66    fn range(&self) -> std::ops::Range<u64> {
67        0..u64::MAX // Any memory that is out there is available to us
68    }
69
70    fn read(
71        &self,
72        address_range: std::ops::Range<u64>,
73    ) -> Result<Option<Vec<u8>>, MemoryReadError> {
74        let mut buffer = vec![0; address_range.clone().count()];
75
76        match self
77            .0
78            .borrow_mut()
79            .read(address_range.start as _, &mut buffer)
80        {
81            Ok(_) => Ok(Some(buffer)),
82            Err(e) => Err(MemoryReadError(Rc::new(e))),
83        }
84    }
85}