use std::{string::String, vec, vec::Vec};
use crate::abi::VirtAddr;
use super::ArchRef;
pub const MAX_INLINE_STR: usize = 256;
#[derive(Clone, Copy)]
pub struct GuestMem {
arch: ArchRef,
cr3: u64,
}
impl ArchRef {
pub fn mem(&self, cr3: u64) -> GuestMem {
GuestMem { arch: *self, cr3: cr3 }
}
}
impl GuestMem {
pub fn at(&self, cr3: u64) -> GuestMem {
GuestMem { arch: self.arch, cr3: cr3 }
}
pub fn cr3(&self) -> u64 {
self.cr3
}
pub fn read(&self, buf: &mut [u8], va: u64) -> bool {
unsafe { self.arch.read_virt_into_with_cr3(buf, va, self.cr3) }.is_ok()
}
pub fn u64(&self, va: u64) -> Option<u64> {
let mut b = [0u8; 8];
self.read(&mut b, va).then(|| u64::from_le_bytes(b))
}
pub fn u32(&self, va: u64) -> Option<u32> {
let mut b = [0u8; 4];
self.read(&mut b, va).then(|| u32::from_le_bytes(b))
}
pub fn blob(&self, va: u64, len: usize) -> Option<Vec<u8>> {
let mut buf = vec![0u8; len];
self.read(&mut buf, va).then_some(buf)
}
pub fn inline_str(&self, va: u64, width: usize) -> Option<String> {
let buf = self.blob(va, width.min(MAX_INLINE_STR))?;
let end = buf.iter().position(|&b| b == 0).unwrap_or(buf.len());
Some(String::from_utf8_lossy(&buf[..end]).into_owned())
}
pub fn executable(&self, va: u64) -> bool {
unsafe { self.arch.translate_attr_with_cr3(VirtAddr(va), self.cr3) }
.is_some_and(|(_, attr)| attr.executable())
}
pub fn translate(&self, va: u64) -> Option<u64> {
unsafe { self.arch.translate_with_cr3(VirtAddr(va), self.cr3) }.map(|pa| pa.0)
}
}