use crate::{
core::{
architecture::{Architecture, Endianness},
error::{Error, ErrorKind, Result},
},
memory::{primitives::RawVirtualAddress, readable::Readable, virtual_address::VirtualAddress},
};
use std::cmp;
pub struct VirtualMemoryReader<'a> {
readable: &'a dyn Readable,
architecture: &'a dyn Architecture,
little_endian: bool,
}
impl<'a> VirtualMemoryReader<'a> {
pub fn new(readable: &'a dyn Readable, architecture: &'a dyn Architecture) -> Self {
Self {
readable,
architecture,
little_endian: architecture.endianness() == Endianness::Little,
}
}
pub fn read(&self, buffer: &mut [u8], virtual_address: VirtualAddress) -> Result<usize> {
let physical_address_range = self
.architecture
.translate_virtual_address(self.readable, virtual_address)?;
let bytes_readable = cmp::min(physical_address_range.len() as usize, buffer.len());
let physical_address = physical_address_range.address();
let dest_buffer = &mut buffer[..bytes_readable];
self.readable
.read(dest_buffer, physical_address)
.map_err(|memory_error| -> Error { memory_error.into() })
}
pub fn read_exact(
&self,
mut buffer: &mut [u8],
mut virtual_address: VirtualAddress,
) -> Result<()> {
let bytes_requested = buffer.len();
let mut total_bytes_read = 0;
while !buffer.is_empty() {
let bytes_read = self.read(buffer, virtual_address)?;
total_bytes_read += bytes_read;
if bytes_read == 0 {
return Err(Error::new(
ErrorKind::MemoryError,
&format!(
"Could not read more than {total_bytes_read} bytes (requested: {bytes_requested})",
),
));
}
virtual_address = virtual_address + bytes_read;
buffer = &mut buffer[bytes_read..];
}
Ok(())
}
pub fn len(&self) -> Result<u64> {
self.readable
.len()
.map_err(|memory_error| memory_error.into())
}
pub fn is_empty(&self) -> Result<bool> {
self.len().map(|len| len == 0)
}
pub fn read_u8(&self, virtual_address: VirtualAddress) -> Result<u8> {
let mut buffer = [0; 1];
self.read_exact(&mut buffer, virtual_address)?;
Ok(buffer[0])
}
pub fn read_u16(&self, virtual_address: VirtualAddress) -> Result<u16> {
let mut buffer = [0; 2];
self.read_exact(&mut buffer, virtual_address)?;
match self.little_endian {
true => Ok(u16::from_le_bytes(buffer)),
false => Ok(u16::from_be_bytes(buffer)),
}
}
pub fn read_u32(&self, virtual_address: VirtualAddress) -> Result<u32> {
let mut buffer = [0; 4];
self.read_exact(&mut buffer, virtual_address)?;
match self.little_endian {
true => Ok(u32::from_le_bytes(buffer)),
false => Ok(u32::from_be_bytes(buffer)),
}
}
pub fn read_u64(&self, virtual_address: VirtualAddress) -> Result<u64> {
let mut buffer = [0; 8];
self.read_exact(&mut buffer, virtual_address)?;
match self.little_endian {
true => Ok(u64::from_le_bytes(buffer)),
false => Ok(u64::from_be_bytes(buffer)),
}
}
pub fn read_i8(&self, virtual_address: VirtualAddress) -> Result<i8> {
self.read_u8(virtual_address).map(|value| value as i8)
}
pub fn read_i16(&self, virtual_address: VirtualAddress) -> Result<i16> {
self.read_u16(virtual_address).map(|value| value as i16)
}
pub fn read_i32(&self, virtual_address: VirtualAddress) -> Result<i32> {
self.read_u32(virtual_address).map(|value| value as i32)
}
pub fn read_i64(&self, virtual_address: VirtualAddress) -> Result<i64> {
self.read_u64(virtual_address).map(|value| value as i64)
}
pub fn read_vaddr(&self, virtual_address: VirtualAddress) -> Result<VirtualAddress> {
let raw_virtual_address = RawVirtualAddress::new(self.read_u64(virtual_address)?);
Ok(VirtualAddress::new(
virtual_address.root_page_table(),
raw_virtual_address,
))
}
}