use std::cell::Ref;
use std::fmt::{Debug, Display};
use crate::arch::{Arch, CpuState};
use crate::encoding::dataflows::Dest;
use crate::value::{MutValue, Value};
mod addr;
mod byteview;
pub mod jit;
mod locs;
mod memory;
pub mod random;
mod split_dests;
pub use addr::{Addr, Area, Page};
pub use byteview::*;
pub use locs::*;
pub use memory::*;
pub use split_dests::SplitDests;
pub const MAX_MEMORY_SIZE: usize = 128;
#[derive(Copy, Clone, Debug)]
pub struct SystemStateIoPair<'a, A: Arch> {
pub state_in: &'a SystemState<A>,
pub state_out: &'a SystemState<A>,
}
impl<'a, A: Arch> From<(&'a SystemState<A>, &'a SystemState<A>)> for SystemStateIoPair<'a, A> {
fn from((state_in, state_out): (&'a SystemState<A>, &'a SystemState<A>)) -> Self {
Self {
state_in,
state_out,
}
}
}
#[derive(Clone, PartialEq, Eq)]
pub struct SystemState<A: Arch> {
cpu: Box<A::CpuState>,
memory: MemoryState,
pub use_trap_flag: bool,
pub contains_valid_addrs: bool,
}
impl<A: Arch> AsRef<SystemState<A>> for SystemState<A> {
fn as_ref(&self) -> &SystemState<A> {
self
}
}
impl<A: Arch> AsSystemState<A> for SystemState<A> {
type Output<'a> = &'a SystemState<A>;
fn as_system_state(&self) -> Self::Output<'_> {
self
}
}
impl<A: Arch> AsSystemState<A> for &SystemState<A> {
type Output<'a>
= &'a SystemState<A>
where
Self: 'a;
fn as_system_state(&self) -> Self::Output<'_> {
self
}
}
impl<A: Arch> AsSystemState<A> for Box<SystemState<A>> {
type Output<'a> = &'a SystemState<A>;
fn as_system_state(&self) -> Self::Output<'_> {
self.as_ref()
}
}
impl<A: Arch> AsRef<SystemState<A>> for Ref<'_, SystemState<A>> {
fn as_ref(&self) -> &SystemState<A> {
SystemState::as_ref(self)
}
}
impl<A: Arch> Debug for SystemState<A> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
Display::fmt(self.cpu(), f)?;
Display::fmt(self.memory(), f)?;
Ok(())
}
}
impl<A: Arch> Default for SystemState<A> {
fn default() -> Self {
Self::new_without_memory(Default::default())
}
}
impl<A: Arch> SystemState<A> {
#[inline(always)]
pub fn cpu(&self) -> &A::CpuState {
&self.cpu
}
#[inline(always)]
pub fn memory(&self) -> &MemoryState {
&self.memory
}
#[inline(always)]
pub fn cpu_mut(&mut self) -> &mut A::CpuState {
&mut self.cpu
}
#[inline(always)]
pub fn memory_mut(&mut self) -> &mut MemoryState {
&mut self.memory
}
#[inline]
pub fn new(cpu: A::CpuState, memory: MemoryState) -> SystemState<A> {
SystemState {
cpu: Box::new(cpu),
memory,
use_trap_flag: true,
contains_valid_addrs: true,
}
}
#[inline]
pub fn new_without_memory(cpu: A::CpuState) -> SystemState<A> {
Self::new(cpu, MemoryState::default())
}
#[inline]
pub fn with_new_memory(self, _num_memory: usize, _num_bytes: usize, memory: MemoryState) -> SystemState<A> {
Self::new(self.cpu().clone(), memory)
}
#[inline]
pub fn with_location(&self, loc: &Location<A>, value: Value) -> Self {
let mut result = self.clone();
result.set_location(loc, value);
result
}
pub fn get_dest(&self, dest: &Dest<A>) -> Value<'_> {
let loc = Location::from(dest);
let value = self.location(&loc);
let size = dest.size();
let sliced = value.slice(size);
sliced
}
pub fn set_dest(&mut self, dest: &Dest<A>, new_value: &Value<'_>) {
let loc = Location::from(dest);
let new_bytes;
let size = dest.size();
let current_value = self.location(&loc);
let sliced = {
match (current_value, new_value) {
(Value::Num(current), Value::Num(new)) => {
let w = (size.end_byte - size.start_byte + 1) * 8;
let mask = if w == 64 { 0xffff_ffff_ffff_ffff } else { (1 << w) - 1 } << (size.start_byte * 8);
Value::Num((current & !mask) | ((new << (size.start_byte * 8)) & mask))
},
(Value::Bytes(current), Value::Bytes(new)) => {
new_bytes = current
.iter()
.copied()
.take(size.start_byte)
.chain(new.iter().copied().take(size.end_byte - size.start_byte + 1))
.chain(current.iter().copied().skip(size.end_byte + 1))
.collect::<Vec<_>>();
Value::Bytes(&new_bytes)
},
(_, new) => *new,
}
};
self.set_location(&loc, sliced)
}
pub fn modify_dest(&mut self, dest: &Dest<A>, modify: impl FnOnce(MutValue<'_>)) {
match dest {
Dest::Reg(reg, size) => self.cpu_mut().modify_reg(*reg, |value| match value {
MutValue::Num(current) => {
let w = (size.end_byte - size.start_byte + 1) * 8;
let unshifted_mask = if w == 64 { 0xffff_ffff_ffff_ffff } else { (1 << w) - 1 };
let mask = unshifted_mask << (size.start_byte * 8);
let mut val = (*current >> (size.start_byte * 8)) & unshifted_mask;
modify(MutValue::Num(&mut val));
*current = (*current & !mask) | ((val << (size.start_byte * 8)) & mask);
},
MutValue::Bytes(bytes) => modify(MutValue::Bytes(&mut bytes[size.start_byte..=size.end_byte])),
}),
Dest::Mem(index, size) => self
.memory_mut()
.get_mut(*index)
.modify_data(|bytes| modify(MutValue::Bytes(&mut bytes[size.start_byte..=size.end_byte]))),
}
}
#[inline]
pub fn set_reg(&mut self, reg: A::Reg, new_value: Value) {
self.cpu_mut().modify_reg(reg, |value| match (value, new_value) {
(MutValue::Num(dst), Value::Num(src)) => *dst = src,
(MutValue::Bytes(dst), Value::Bytes(src)) => dst.copy_from_slice(src),
v => panic!("Set register not matching: {v:?}"),
})
}
#[inline]
pub fn with_dest(&self, dest: &Dest<A>, v: &Value<'_>) -> Self {
let mut result = self.clone();
result.set_dest(dest, v);
result
}
#[inline]
pub fn set_flag(&mut self, flag: A::Flag, value: bool) {
self.cpu_mut().set_flag(flag, value)
}
pub fn set_location(&mut self, loc: &Location<A>, value: Value) {
match (loc, value) {
(Location::Reg(reg), value) => self.set_reg(*reg, value),
(Location::Memory(index), Value::Bytes(v)) => {
self.memory_mut().get_mut(*index).modify_data(|target| {
target.copy_from_slice(v);
});
},
(loc, value) => panic!("Unsupported (location, value) pair: {loc:?} and {value:?}"),
}
}
pub fn location(&self, loc: &Location<A>) -> Value<'_> {
match loc {
Location::Reg(reg) => self.cpu().reg(*reg),
Location::Memory(n) => Value::Bytes(&self.memory().get(*n).2),
}
}
pub fn get_location(&self, loc: &Location<A>) -> Option<Value<'_>> {
match loc {
Location::Reg(reg) => Some(self.cpu().reg(*reg)),
Location::Memory(n) => self.memory().get_checked(*n).as_ref().map(|v| Value::Bytes(&v.2)),
}
}
}
pub trait AsSystemState<A: Arch> {
type Output<'a>: AsRef<SystemState<A>>
where
Self: 'a;
fn as_system_state(&self) -> Self::Output<'_>;
fn num_memory_mappings(&self) -> usize {
self.as_system_state().as_ref().memory().len()
}
}
impl<A: Arch, T> AsSystemState<A> for (SystemState<A>, T) {
type Output<'a>
= &'a SystemState<A>
where
Self: 'a;
fn as_system_state(&self) -> Self::Output<'_> {
&self.0
}
}
#[cfg(test)]
mod tests {
use crate::arch::fake::{FakeArch, FakeReg, FakeState};
use crate::encoding::dataflows::{Dest, Size};
use crate::state::{CpuState, MutValue, SystemState, Value};
#[test]
pub fn set_dest_flag() {
let state = FakeState::create(|_, value| match value {
MutValue::Num(n) => *n = 0x0101,
MutValue::Bytes(_) => (),
});
let mut s = SystemState::<FakeArch>::new_without_memory(state);
assert!(match s.get_dest(&Dest::Reg(FakeReg::RF, Size::new(1, 1))) {
Value::Num(n) => n == 1,
_ => panic!(),
});
s.set_dest(&Dest::Reg(FakeReg::RF, Size::new(1, 1)), &Value::Num(0));
assert!(match s.get_dest(&Dest::Reg(FakeReg::RF, Size::new(0, 0))) {
Value::Num(n) => n == 1,
_ => panic!(),
});
assert!(match s.get_dest(&Dest::Reg(FakeReg::RF, Size::new(1, 1))) {
Value::Num(n) => n == 0,
_ => panic!(),
});
}
#[test]
pub fn set_dest_byte() {
let state = FakeState::create(|_, value| match value {
MutValue::Num(n) => *n = 0,
MutValue::Bytes(_) => (),
});
let mut s = SystemState::<FakeArch>::new_without_memory(state);
assert!(match s.get_dest(&Dest::Reg(FakeReg::R1, Size::new(1, 1))) {
Value::Num(n) => n == 0,
_ => panic!(),
});
s.set_dest(&Dest::Reg(FakeReg::R1, Size::new(1, 1)), &Value::Num(0x25));
assert!(match s.get_dest(&Dest::Reg(FakeReg::R0, Size::new(1, 1))) {
Value::Num(n) => n == 0,
_ => panic!(),
});
assert!(match s.get_dest(&Dest::Reg(FakeReg::R1, Size::new(1, 1))) {
Value::Num(n) => n == 0x25,
_ => panic!(),
});
}
}