stackdump_core/
device_memory.rs

1//! Module containing the definitions for device memory, a summation of all available memory that was captured
2
3use crate::{memory_region::MemoryRegion, register_data::RegisterData};
4use std::{error::Error, fmt::Display, ops::Range, rc::Rc};
5
6/// An error to signal that a register is not present
7#[derive(Debug, Clone, Copy)]
8pub struct MissingRegisterError(gimli::Register);
9impl Display for MissingRegisterError {
10    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
11        write!(
12            f,
13            "Missing register: {}",
14            gimli::Arm::register_name(self.0)
15                .map(|n| n.to_string())
16                .unwrap_or_else(|| format!("{}", self.0 .0))
17        )
18    }
19}
20impl Error for MissingRegisterError {}
21
22/// An error to signal that memory could not be read
23#[derive(Debug, Clone)]
24pub struct MemoryReadError(pub Rc<dyn Error>);
25impl Display for MemoryReadError {
26    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
27        write!(f, "Memory read error: {}", self.0)
28    }
29}
30impl Error for MemoryReadError {}
31impl PartialEq for MemoryReadError {
32    fn eq(&self, other: &Self) -> bool {
33        self.0.to_string() == other.0.to_string()
34    }
35}
36
37/// Object containing all memory regions (we have available) of the device
38pub struct DeviceMemory<'memory, RB: funty::Integral> {
39    // Register data must be mutable for stack unwinding
40    register_data: Vec<Box<dyn RegisterData<RB> + 'memory>>,
41    memory_regions: Vec<Box<dyn MemoryRegion + 'memory>>,
42}
43
44impl<'memory, RB: funty::Integral> DeviceMemory<'memory, RB> {
45    /// Creates a new instance of the device memory
46    pub fn new() -> Self {
47        Self {
48            register_data: Vec::new(),
49            memory_regions: Vec::new(),
50        }
51    }
52
53    /// Adds a memory region to the device memory
54    pub fn add_memory_region<M: MemoryRegion + 'memory>(&mut self, region: M) {
55        self.memory_regions.push(Box::new(region));
56    }
57
58    /// Adds register data to the device memory
59    pub fn add_register_data<RD: RegisterData<RB> + 'memory>(&mut self, data: RD) {
60        self.register_data.push(Box::new(data));
61    }
62
63    /// Returns the slice of memory that can be found at the given address_range.
64    /// If the given address range is not fully within one of the captured regions present in the device memory, then None is returned.
65    pub fn read_slice(
66        &self,
67        address_range: Range<u64>,
68    ) -> Result<Option<Vec<u8>>, MemoryReadError> {
69        for mr in self.memory_regions.iter() {
70            if let Some(v) = mr.read(address_range.clone())? {
71                return Ok(Some(v));
72            }
73        }
74
75        Ok(None)
76    }
77
78    /// Reads a byte from the given address if it is present in one of the captured regions present in the device memory
79    pub fn read_u8(&self, address: u64) -> Result<Option<u8>, MemoryReadError> {
80        for mr in self.memory_regions.iter() {
81            if let Some(v) = mr.read_u8(address)? {
82                return Ok(Some(v));
83            }
84        }
85
86        Ok(None)
87    }
88
89    /// Reads a u32 from the given address if it is present in one of the captured regions present in the device memory
90    pub fn read_u32(
91        &self,
92        address: u64,
93        endianness: gimli::RunTimeEndian,
94    ) -> Result<Option<u32>, MemoryReadError> {
95        for mr in self.memory_regions.iter() {
96            if let Some(v) = mr.read_u32(address, endianness)? {
97                return Ok(Some(v));
98            }
99        }
100
101        Ok(None)
102    }
103
104    /// Try to get the value of the given register. Returns an error if the register is not present in any of the register collections.
105    pub fn register(&self, register: gimli::Register) -> Result<RB, MissingRegisterError> {
106        self.register_data
107            .iter()
108            .find_map(|registers| registers.register(register))
109            .ok_or(MissingRegisterError(register))
110    }
111
112    /// Try to get a reference to the given register. Returns an error if the register is not present in any of the register collections.
113    pub fn register_ref(&self, register: gimli::Register) -> Result<&RB, MissingRegisterError> {
114        self.register_data
115            .iter()
116            .find_map(|registers| registers.register_ref(register))
117            .ok_or(MissingRegisterError(register))
118    }
119
120    /// Try to get a mutable reference to the given register. Returns an error if the register is not present in any of the register collections.
121    pub fn register_mut(
122        &mut self,
123        register: gimli::Register,
124    ) -> Result<&mut RB, MissingRegisterError> {
125        self.register_data
126            .iter_mut()
127            .find_map(|registers| registers.register_mut(register))
128            .ok_or(MissingRegisterError(register))
129    }
130}
131
132impl<'memory, RB: funty::Integral> Default for DeviceMemory<'memory, RB> {
133    fn default() -> Self {
134        Self::new()
135    }
136}