use crate::JingleError;
use crate::analysis::cpa::lattice::flat::FlatLattice;
use crate::analysis::pcode_store::PcodeOpRef;
use crate::modeling::machine::MachineState;
use crate::modeling::machine::cpu::concrete::ConcretePcodeAddress;
use jingle_sleigh::{PcodeOperation, SleighArchInfo};
use std::fmt::Debug;
use std::hash::Hash;
use z3::ast::Bool;
pub trait CfgStateModel: Debug + Clone + Sized {
fn location_eq(&self, other: &Self) -> Bool;
fn state_eq(&self, other: &Self) -> Bool;
fn apply(&self, op: &PcodeOperation) -> Result<Self, JingleError>;
}
impl CfgStateModel for MachineState {
fn location_eq(&self, other: &Self) -> Bool {
self.pc().eq(other.pc())
}
fn state_eq(&self, other: &Self) -> Bool {
let machine_eq = self.pc().machine.eq(&other.pc().machine);
self.memory()._eq(other.memory(), &machine_eq)
}
fn apply(&self, op: &PcodeOperation) -> Result<Self, JingleError> {
self.apply(op)
}
}
pub trait CfgState: Clone + Debug + Hash + Eq {
type Model: CfgStateModel;
fn new_const(&self, i: &SleighArchInfo) -> Self::Model;
fn model_id(&self) -> String;
fn location(&self) -> Option<ConcretePcodeAddress>;
}
pub trait ModelTransition<S: CfgStateModel>: Clone + Debug {
fn transition(&self, init: &S) -> Result<S, JingleError>;
}
impl CfgState for ConcretePcodeAddress {
type Model = MachineState;
fn new_const(&self, i: &SleighArchInfo) -> Self::Model {
MachineState::fresh_for_address(i, *self)
}
fn model_id(&self) -> String {
format!("State_PC_{:x}_{:x}", self.machine, self.pcode)
}
fn location(&self) -> Option<ConcretePcodeAddress> {
Some(*self)
}
}
impl CfgState for FlatLattice<ConcretePcodeAddress> {
type Model = MachineState;
fn new_const(&self, i: &SleighArchInfo) -> Self::Model {
match self {
FlatLattice::Value(addr) => MachineState::fresh_for_address(i, addr),
FlatLattice::Top => MachineState::fresh(i),
}
}
fn model_id(&self) -> String {
match self {
FlatLattice::Value(a) => a.model_id(),
FlatLattice::Top => "State_Top_".to_string(),
}
}
fn location(&self) -> Option<ConcretePcodeAddress> {
Option::from(*self)
}
}
impl<N: CfgStateModel> ModelTransition<N> for PcodeOperation {
fn transition(&self, init: &N) -> Result<N, JingleError> {
init.apply(self)
}
}
impl<'a, N: CfgStateModel> ModelTransition<N> for PcodeOpRef<'a> {
fn transition(&self, init: &N) -> Result<N, JingleError> {
init.apply(self)
}
}
impl<N: CfgStateModel, T: ModelTransition<N>> ModelTransition<N> for Vec<T> {
fn transition(&self, init: &N) -> Result<N, JingleError> {
let mut state = init.clone();
for op in self {
state = op.transition(&state)?;
}
Ok(state)
}
}