1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
//! Module containing the definitions for device memory, a summation of all available memory that was captured

use crate::{
    memory_region::MemoryRegion,
    register_data::{RegisterBacking, RegisterData},
};
use std::{fmt::Display, ops::Range};

/// An error to signal that a register is not present
#[derive(Debug, Clone, Copy)]
pub struct MissingRegisterError(gimli::Register);
impl Display for MissingRegisterError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "Missing register: {}",
            gimli::Arm::register_name(self.0)
                .map(|n| n.to_string())
                .unwrap_or_else(|| format!("{}", self.0 .0))
        )
    }
}
impl std::error::Error for MissingRegisterError {}

/// Object containing all memory regions (we have available) of the device
pub struct DeviceMemory<RB: RegisterBacking> {
    register_data: Vec<Box<dyn RegisterData<RB>>>,
    memory_regions: Vec<Box<dyn MemoryRegion>>,
}

impl<RB: RegisterBacking> DeviceMemory<RB> {
    /// Creates a new instance of the device memory
    pub fn new() -> Self {
        Self {
            register_data: Vec::new(),
            memory_regions: Vec::new(),
        }
    }

    /// Adds a memory region to the device memory
    pub fn add_memory_region<M: MemoryRegion + 'static>(&mut self, region: M) {
        self.memory_regions.push(Box::new(region));
    }
    /// Adds a memory region to the device memory
    pub fn add_memory_region_boxed(&mut self, region: Box<dyn MemoryRegion>) {
        self.memory_regions.push(region);
    }
    /// Adds register data to the device memory
    pub fn add_register_data<RD: RegisterData<RB> + 'static>(&mut self, data: RD) {
        self.register_data.push(Box::new(data));
    }
    /// Adds register data to the device memory
    pub fn add_register_data_boxed(&mut self, data: Box<dyn RegisterData<RB>>) {
        self.register_data.push(data);
    }

    /// Returns the slice of memory that can be found at the given address_range.
    /// If the given address range is not fully within one of the captured regions present in the device memory, then None is returned.
    pub fn read_slice(&self, address_range: Range<u64>) -> Option<&[u8]> {
        self.memory_regions
            .iter()
            .find_map(|mr| mr.read_slice(address_range.clone()))
    }

    /// Reads a byte from the given address if it is present in one of the captured regions present in the device memory
    pub fn read_u8(&self, address: u64) -> Option<u8> {
        self.memory_regions
            .iter()
            .find_map(|mr| mr.read_u8(address))
    }

    /// Reads a u32 from the given address if it is present in one of the captured regions present in the device memory
    pub fn read_u32(&self, address: u64, endianness: gimli::RunTimeEndian) -> Option<u32> {
        self.memory_regions
            .iter()
            .find_map(|mr| mr.read_u32(address, endianness))
    }

    /// Try to get the value of the given register. Returns an error if the register is not present in any of the register collections.
    pub fn register(&self, register: gimli::Register) -> Result<RB, MissingRegisterError> {
        self.register_data
            .iter()
            .find_map(|registers| registers.register(register))
            .ok_or(MissingRegisterError(register))
    }

    /// Try to get a reference to the given register. Returns an error if the register is not present in any of the register collections.
    pub fn register_ref(&self, register: gimli::Register) -> Result<&RB, MissingRegisterError> {
        self.register_data
            .iter()
            .find_map(|registers| registers.register_ref(register))
            .ok_or(MissingRegisterError(register))
    }

    /// 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.
    pub fn register_mut(
        &mut self,
        register: gimli::Register,
    ) -> Result<&mut RB, MissingRegisterError> {
        self.register_data
            .iter_mut()
            .find_map(|registers| registers.register_mut(register))
            .ok_or(MissingRegisterError(register))
    }
}

impl<RB: RegisterBacking> Default for DeviceMemory<RB> {
    fn default() -> Self {
        Self::new()
    }
}