use std::fmt::{Debug, Display};
use std::hash::Hash;
use serde::de::DeserializeOwned;
use serde::Serialize;
use crate::state::{StateByte, SystemStateIoPair};
use crate::value::{MutValue, Value, ValueType};
pub mod fake;
mod scope;
pub mod undef;
pub mod x64;
pub use scope::*;
pub trait Arch: Copy + Clone + Debug + PartialEq + Eq + Hash + Default + PartialOrd + Ord + Send + Sync + 'static
where
Self: Sized,
{
type CpuState: CpuState<Self> + Clone + PartialEq + Eq + Send + Sync + Debug + Display;
type Reg: Register
+ Copy
+ Clone
+ Debug
+ Display
+ Eq
+ Hash
+ PartialOrd
+ Ord
+ Serialize
+ DeserializeOwned
+ Send
+ Sync;
type GpReg: Register
+ NumberedRegister
+ Clone
+ Debug
+ Display
+ Eq
+ Hash
+ PartialOrd
+ Ord
+ Serialize
+ DeserializeOwned
+ Send
+ Sync;
type Flag: Flag
+ Clone
+ Debug
+ Display
+ PartialEq
+ Eq
+ Hash
+ PartialOrd
+ Ord
+ Serialize
+ DeserializeOwned
+ Send
+ Sync;
const PAGE_BITS: usize;
const PC: Self::GpReg;
const ZERO: Self::GpReg;
const INSTRUCTION_ALIGNMENT: usize = 1;
fn reg(reg: Self::GpReg) -> Self::Reg;
fn try_reg_to_gpreg(reg: Self::Reg) -> Option<Self::GpReg>;
fn flagreg_to_flags(reg: Self::Reg, start_byte: usize, end_byte: usize) -> &'static [Self::Flag];
fn iter_gpregs() -> impl Iterator<Item = Self::GpReg>;
fn iter_regs() -> impl Iterator<Item = Self::Reg>;
}
pub trait CpuState<A: Arch>: Default {
type DiffMask: Clone + Default + Debug;
fn gpreg(&self, reg: A::GpReg) -> u64;
fn set_gpreg(&mut self, reg: A::GpReg, value: u64);
fn reg(&self, reg: A::Reg) -> Value<'_>;
fn modify_reg<F: FnOnce(MutValue)>(&mut self, reg: A::Reg, update: F);
fn flag(&self, flag: A::Flag) -> bool;
fn set_flag(&mut self, flag: A::Flag, value: bool);
#[inline(always)]
fn create<R: FnMut(A::Reg, MutValue)>(mut regval: R) -> Self {
let mut state = Self::default();
for reg in A::iter_regs() {
CpuState::modify_reg(&mut state, reg, |val| regval(reg, val));
}
state
}
fn default_with_pc(pc: u64) -> Self {
let mut state = Self::default();
state.set_gpreg(A::PC, pc);
state
}
fn size() -> usize;
#[inline]
fn get_state_byte(&self, byte: StateByte) -> u8 {
let (reg, index) = Self::state_byte_to_reg(byte);
self.reg(reg).select_byte(index)
}
fn set_state_byte(&mut self, byte: StateByte, value: u8) {
let (reg, index) = Self::state_byte_to_reg(byte);
self.modify_reg(reg, |v| match v {
MutValue::Num(n) => {
let shift = index * 8;
let mask = 0xff << shift;
#[cfg(debug_assertions)]
{
let (reg, index) = Self::state_byte_to_reg(byte);
let mask = if let Some(mask) = reg.mask() {
(mask >> (index * 8)) as u8
} else {
0xff
};
debug_assert_eq!(value & !mask, 0, "State byte {byte:?} ({reg:?} byte {index}) is masked (0b{mask:b}, tried to set value 0b{value:b}) and should not have bits set outside its mask");
}
*n = (*n & !mask) | ((value as u64) << shift);
},
MutValue::Bytes(b) => {
b[index] = value;
},
})
}
#[inline]
fn state_bytes_unequal(&self, dest: StateByte, other: &Self) -> bool {
self.get_state_byte(dest) != other.get_state_byte(dest)
}
#[inline]
fn state_bytes_equal(&self, dest: StateByte, other: &Self) -> bool {
!self.state_bytes_unequal(dest, other)
}
fn state_byte_to_reg(byte: StateByte) -> (A::Reg, usize);
fn reg_to_state_byte(reg: A::Reg, byte: usize) -> StateByte;
fn find_differences<F: FnMut(StateByte)>(&self, other: &Self, found: &mut F) {
for b in (0..Self::size()).map(StateByte::new) {
if self.get_state_byte(b) != other.get_state_byte(b) {
found(b);
}
}
}
fn create_diff_mask<I: Iterator<Item = StateByte>>(items: I) -> Self::DiffMask;
#[allow(unused)]
fn find_dataflows_masked<F: FnMut(StateByte)>(
b: SystemStateIoPair<A>, a: SystemStateIoPair<A>, dest_diff_mask: &Self::DiffMask, diff_mask: &Self::DiffMask,
found: &mut F,
) {
a.state_in.cpu().find_differences(a.state_out.cpu(), found);
b.state_in.cpu().find_differences(b.state_out.cpu(), found);
}
}
pub trait Register: Copy + Sized + PartialOrd + Ord + PartialEq {
fn is_pc(&self) -> bool;
fn is_zero(&self) -> bool;
fn is_flags(&self) -> bool;
fn mask(&self) -> Option<u64>;
fn is_addr_reg(&self) -> bool;
fn should_avoid(&self) -> bool {
false
}
fn byte_size(&self) -> usize;
fn reg_type(self) -> ValueType;
}
pub trait NumberedRegister {
fn as_num(&self) -> usize;
fn from_num(num: usize) -> Self;
}
pub trait Flag: Copy + Sized + PartialOrd + Ord {
fn iter() -> impl Iterator<Item = Self>;
}