use std::prelude::v1::*;
use super::{mem_data::*, phys_mem::*};
use crate::prelude::v1::{Result, *};
pub mod arch_overlay;
pub mod batcher;
pub mod cached_view;
pub mod remap_view;
#[cfg(feature = "std")]
pub mod cursor;
pub use arch_overlay::ArchOverlayView;
pub use batcher::Batchable;
pub use batcher::MemoryViewBatcher;
pub use cached_view::CachedView;
pub use remap_view::RemapView;
#[cfg(feature = "std")]
pub use cursor::MemoryCursor;
#[cfg_attr(feature = "plugins", cglue_trait)]
#[cglue_forward]
#[int_result(PartialResult)]
pub trait MemoryView: Send {
#[int_result]
fn read_raw_iter(&mut self, data: ReadRawMemOps) -> Result<()>;
#[int_result]
fn write_raw_iter(&mut self, data: WriteRawMemOps) -> Result<()>;
fn metadata(&self) -> MemoryViewMetadata;
#[int_result]
#[vtbl_only]
#[custom_impl(
// Types within the C interface other than self and additional wrappers.
{
inp: CIterator<ReadData<'a>>,
out: Option<&mut ReadCallback<'b, 'a>>,
out_fail: Option<&mut ReadCallback<'b, 'a>>,
},
// Unwrapped return type
Result<()>,
// Conversion in trait impl to C arguments (signature names are expected).
{},
// This is the body of C impl minus the automatic wrapping.
{
MemOps::with_raw(
inp.map(|CTup2(a, b)| CTup3(a, a, b)),
out,
out_fail,
|data| this.read_raw_iter(data),
)
},
// This part is processed in the trait impl after the call returns (impl_func_ret,
// nothing extra needs to happen here).
{},
)]
fn read_iter<'a, 'b>(
&mut self,
inp: impl Iterator<Item = ReadData<'a>>,
out: Option<&mut ReadCallback<'b, 'a>>,
out_fail: Option<&mut ReadCallback<'b, 'a>>,
) -> Result<()> {
MemOps::with_raw(
inp.map(|CTup2(a, b)| CTup3(a, a, b)),
out,
out_fail,
|data| self.read_raw_iter(data),
)
}
fn read_raw_list(&mut self, data: &mut [ReadData]) -> PartialResult<()> {
let mut out = Ok(());
let callback = &mut |CTup2(_, mut d): ReadData| {
out = Err(PartialError::PartialVirtualRead(()));
for v in d.iter_mut() {
*v = 0;
}
true
};
let iter = data
.iter_mut()
.map(|CTup2(d1, d2)| CTup3(*d1, *d1, d2.into()));
MemOps::with_raw(iter, None, Some(&mut callback.into()), |data| {
self.read_raw_iter(data)
})?;
out
}
#[inline]
fn read_raw_into(&mut self, addr: Address, out: &mut [u8]) -> PartialResult<()> {
self.read_raw_list(&mut [CTup2(addr, out.into())])
}
#[skip_func]
#[inline]
fn read_raw(&mut self, addr: Address, len: usize) -> PartialResult<Vec<u8>> {
let mut buf = vec![0u8; len];
self.read_raw_into(addr, &mut buf).map_data(|_| buf)
}
#[skip_func]
#[inline]
fn read_into<T: Pod + ?Sized>(&mut self, addr: Address, out: &mut T) -> PartialResult<()>
where
Self: Sized,
{
self.read_raw_into(addr, out.as_bytes_mut())
}
#[skip_func]
fn read<T: Pod + Sized>(&mut self, addr: Address) -> PartialResult<T>
where
Self: Sized,
{
const STACK_THRESHOLD: usize = 2048;
if std::mem::size_of::<T>() <= STACK_THRESHOLD {
let mut uninit = std::mem::MaybeUninit::<T>::uninit();
unsafe {
std::ptr::write_bytes(uninit.as_mut_ptr(), 0, 1);
}
let buf = unsafe {
std::slice::from_raw_parts_mut(
uninit.as_mut_ptr() as *mut u8,
std::mem::size_of::<T>(),
)
};
self.read_raw_into(addr, buf).map_data(|_| {
unsafe { uninit.assume_init() }
})
} else {
let mut buf = vec![0u8; std::mem::size_of::<T>()];
self.read_raw_into(addr, &mut buf).map_data(|_| {
unsafe { std::ptr::read(buf.as_ptr() as *const T) }
})
}
}
#[skip_func]
#[inline]
fn read_addr32(&mut self, addr: Address) -> PartialResult<Address>
where
Self: Sized,
{
self.read::<u32>(addr).map_data(|d| d.into())
}
#[skip_func]
#[inline]
fn read_addr64(&mut self, addr: Address) -> PartialResult<Address>
where
Self: Sized,
{
self.read::<u64>(addr).map_data(|d| d.into())
}
#[skip_func]
fn read_addr_arch(&mut self, arch: ArchitectureObj, addr: Address) -> PartialResult<Address>
where
Self: Sized,
{
match arch.bits() {
64 => self.read_addr64(addr),
32 => self.read_addr32(addr),
_ => Err(PartialError::Error(Error(
ErrorOrigin::VirtualMemory,
ErrorKind::InvalidArchitecture,
))),
}
}
#[skip_func]
#[inline]
fn read_ptr_into<U: PrimitiveAddress, T: Pod + ?Sized>(
&mut self,
ptr: Pointer<U, T>,
out: &mut T,
) -> PartialResult<()>
where
Self: Sized,
{
self.read_into(ptr.into(), out)
}
#[skip_func]
#[inline]
fn read_ptr<U: PrimitiveAddress, T: Pod + Sized>(
&mut self,
ptr: Pointer<U, T>,
) -> PartialResult<T>
where
Self: Sized,
{
self.read(ptr.into())
}
#[int_result]
#[vtbl_only]
#[custom_impl(
// Types within the C interface other than self and additional wrappers.
{
inp: CIterator<WriteData<'a>>,
out: Option<&mut WriteCallback<'b, 'a>>,
out_fail: Option<&mut WriteCallback<'b, 'a>>,
},
// Unwrapped return type
Result<()>,
// Conversion in trait impl to C arguments (signature names are expected).
{},
// This is the body of C impl minus the automatic wrapping.
{
MemOps::with_raw(
inp.map(|CTup2(a, b)| CTup3(a, a, b)),
out,
out_fail,
|data| this.write_raw_iter(data),
)
},
// This part is processed in the trait impl after the call returns (impl_func_ret,
// nothing extra needs to happen here).
{},
)]
fn write_iter<'a, 'b>(
&mut self,
inp: impl Iterator<Item = WriteData<'a>>,
out: Option<&mut WriteCallback<'b, 'a>>,
out_fail: Option<&mut WriteCallback<'b, 'a>>,
) -> Result<()> {
MemOps::with_raw(
inp.map(|CTup2(a, b)| CTup3(a, a, b)),
out,
out_fail,
|data| self.write_raw_iter(data),
)
}
fn write_raw_list(&mut self, data: &[WriteData]) -> PartialResult<()> {
let mut out = Ok(());
let callback = &mut |_| {
out = Err(PartialError::PartialVirtualWrite(()));
true
};
let iter = data.iter().copied();
MemOps::with_raw(iter, None, Some(&mut callback.into()), |data| {
self.write_iter(data.inp, data.out, data.out_fail)
})?;
out
}
#[inline]
fn write_raw(&mut self, addr: Address, data: &[u8]) -> PartialResult<()> {
self.write_raw_list(&[CTup2(addr, data.into())])
}
#[skip_func]
#[inline]
fn write<T: Pod + ?Sized>(&mut self, addr: Address, data: &T) -> PartialResult<()>
where
Self: Sized,
{
self.write_raw(addr, data.as_bytes())
}
#[skip_func]
#[inline]
fn write_ptr<U: PrimitiveAddress, T: Pod + ?Sized>(
&mut self,
ptr: Pointer<U, T>,
data: &T,
) -> PartialResult<()>
where
Self: Sized,
{
self.write(ptr.into(), data)
}
#[deprecated = "please use read_utf8 or read_utf8_lossy instead"]
#[skip_func]
fn read_char_array(&mut self, addr: Address, len: usize) -> PartialResult<String> {
let mut buf = vec![0; len];
self.read_raw_into(addr, &mut buf).data_part()?;
if let Some((n, _)) = buf.iter().enumerate().find(|(_, c)| **c == 0_u8) {
buf.truncate(n);
}
Ok(String::from_utf8_lossy(&buf).to_string())
}
#[deprecated = "please use read_utf8 or read_utf8_lossy instead"]
#[skip_func]
#[inline]
fn read_char_string_n(&mut self, addr: Address, n: usize) -> PartialResult<String> {
self.read_utf8_lossy(addr, n)
}
#[deprecated = "please use read_utf8 or read_utf8_lossy instead"]
#[skip_func]
#[inline]
fn read_char_string(&mut self, addr: Address) -> PartialResult<String> {
self.read_utf8_lossy(addr, 4096)
}
#[skip_func]
fn read_utf8(&mut self, addr: Address, max_length: usize) -> PartialResult<String> {
let mut buf = vec![0; max_length];
self.read_raw_into(addr, &mut buf).data_part()?;
if let Some((n, _)) = buf.iter().enumerate().find(|(_, c)| **c == 0_u8) {
buf.truncate(n);
}
Ok(String::from_utf8(buf).map_err(|err| {
Error(ErrorOrigin::Memory, ErrorKind::Encoding).log_error(format!(
"unable to convert bytes to valid utf8 string: {}",
err
))
})?)
}
#[skip_func]
fn read_utf8_lossy(&mut self, addr: Address, max_length: usize) -> PartialResult<String> {
let mut buf = vec![0; max_length];
self.read_raw_into(addr, &mut buf).data_part()?;
if let Some((n, _)) = buf.iter().enumerate().find(|(_, c)| **c == 0_u8) {
buf.truncate(n);
}
Ok(String::from_utf8_lossy(&buf).to_string())
}
#[cfg(feature = "std")]
#[skip_func]
#[inline]
fn cursor(&mut self) -> MemoryCursor<Fwd<&mut Self>>
where
Self: Sized,
{
MemoryCursor::new(self.forward())
}
#[cfg(feature = "std")]
#[skip_func]
#[inline]
fn into_cursor(self) -> MemoryCursor<Self>
where
Self: Sized,
{
MemoryCursor::new(self)
}
#[cfg(feature = "std")]
#[skip_func]
fn cursor_at(&mut self, address: Address) -> MemoryCursor<Fwd<&mut Self>>
where
Self: Sized,
{
MemoryCursor::at(self.forward(), address)
}
#[cfg(feature = "std")]
#[skip_func]
#[inline]
fn into_cursor_at(self, address: Address) -> MemoryCursor<Self>
where
Self: Sized,
{
MemoryCursor::at(self, address)
}
#[skip_func]
#[inline]
fn batcher(&mut self) -> MemoryViewBatcher<'_, Self>
where
Self: Sized,
{
MemoryViewBatcher::new(self)
}
#[skip_func]
#[inline]
fn into_overlay_arch(self, arch: ArchitectureObj) -> ArchOverlayView<Self>
where
Self: Sized,
{
ArchOverlayView::new(self, arch)
}
#[skip_func]
#[inline]
fn overlay_arch(&mut self, arch: ArchitectureObj) -> ArchOverlayView<Fwd<&mut Self>>
where
Self: Sized,
{
ArchOverlayView::new(self.forward_mut(), arch)
}
#[skip_func]
#[inline]
fn into_overlay_arch_parts(self, arch_bits: u8, little_endian: bool) -> ArchOverlayView<Self>
where
Self: Sized,
{
ArchOverlayView::new_parts(self, arch_bits, little_endian)
}
#[skip_func]
#[inline]
fn overlay_arch_parts(
&mut self,
arch_bits: u8,
little_endian: bool,
) -> ArchOverlayView<Fwd<&mut Self>>
where
Self: Sized,
{
ArchOverlayView::new_parts(self.forward_mut(), arch_bits, little_endian)
}
#[skip_func]
#[inline]
fn into_remap_view(self, mem_map: MemoryMap<(Address, umem)>) -> RemapView<Self>
where
Self: Sized,
{
RemapView::new(self, mem_map)
}
#[skip_func]
#[inline]
fn remap_view(&mut self, mem_map: MemoryMap<(Address, umem)>) -> RemapView<Fwd<&mut Self>>
where
Self: Sized,
{
self.forward_mut().into_remap_view(mem_map)
}
#[skip_func]
#[inline]
fn into_phys_mem(self) -> PhysicalMemoryOnView<Self>
where
Self: Sized,
{
PhysicalMemoryOnView { mem: self }
}
#[skip_func]
#[inline]
fn phys_mem(&mut self) -> PhysicalMemoryOnView<Fwd<&mut Self>>
where
Self: Sized,
{
self.forward_mut().into_phys_mem()
}
}
#[repr(C)]
#[derive(Clone)]
#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))]
pub struct PhysicalMemoryOnView<T> {
mem: T,
}
impl<T: MemoryView> PhysicalMemory for PhysicalMemoryOnView<T>
where
T: MemoryView,
{
#[inline]
fn phys_read_raw_iter(
&mut self,
MemOps { inp, out, out_fail }: PhysicalReadMemOps,
) -> Result<()> {
let inp = inp.map(|CTup3(addr, meta_addr, data)| CTup3(addr.into(), meta_addr, data));
MemOps::with_raw(inp, out, out_fail, |data| self.mem.read_raw_iter(data))
}
#[inline]
fn phys_write_raw_iter(
&mut self,
MemOps { inp, out, out_fail }: PhysicalWriteMemOps,
) -> Result<()> {
let inp = inp.map(|CTup3(addr, meta_addr, data)| CTup3(addr.into(), meta_addr, data));
MemOps::with_raw(inp, out, out_fail, |data| self.mem.write_raw_iter(data))
}
#[inline]
fn metadata(&self) -> PhysicalMemoryMetadata {
let md = self.mem.metadata();
PhysicalMemoryMetadata {
max_address: md.max_address,
real_size: md.real_size,
readonly: md.readonly,
ideal_batch_size: 4096,
}
}
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(::serde::Serialize, ::serde::Deserialize))]
#[cfg_attr(feature = "abi_stable", derive(::abi_stable::StableAbi))]
pub struct MemoryViewMetadata {
pub max_address: Address,
pub real_size: umem,
pub readonly: bool,
pub little_endian: bool,
pub arch_bits: u8,
}