use std::borrow::Borrow;
use std::cmp::Ordering;
use std::fmt::{Debug, Display, Formatter};
use std::hash::{Hash, Hasher};
use std::sync::Arc;
use jingle_sleigh::PcodeOperation;
use crate::analysis::cfg::CfgState;
use crate::analysis::cpa::lattice::JoinSemiLattice;
use crate::analysis::cpa::state::{
AbstractState, LocationState, MergeOutcome, PcodeLocation, Successor,
};
use crate::analysis::linkage::PcodeReverseLinkage;
use crate::analysis::pcode_store::{PcodeOpRef, PcodeStore};
pub struct ReverseLocationState<N: CfgState, L: PcodeReverseLinkage<N>> {
pub(super) inner: N,
pub(super) linkage: Arc<L>,
}
impl<N: CfgState, L: PcodeReverseLinkage<N>> ReverseLocationState<N, L> {
pub fn node(&self) -> &N {
&self.inner
}
}
impl<N: CfgState, L: PcodeReverseLinkage<N>> PartialEq for ReverseLocationState<N, L> {
fn eq(&self, other: &Self) -> bool {
self.inner == other.inner
}
}
impl<N: CfgState, L: PcodeReverseLinkage<N>> Eq for ReverseLocationState<N, L> {}
impl<N: CfgState, L: PcodeReverseLinkage<N>> Hash for ReverseLocationState<N, L> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.inner.hash(state);
}
}
impl<N: CfgState, L: PcodeReverseLinkage<N>> Clone for ReverseLocationState<N, L> {
fn clone(&self) -> Self {
Self {
inner: self.inner.clone(),
linkage: Arc::clone(&self.linkage),
}
}
}
impl<N: CfgState + PartialOrd, L: PcodeReverseLinkage<N>> PartialOrd
for ReverseLocationState<N, L>
{
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.inner.partial_cmp(&other.inner)
}
}
impl<N: CfgState, L: PcodeReverseLinkage<N>> Debug for ReverseLocationState<N, L> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("ReverseLocationState")
.field("inner", &self.inner)
.finish()
}
}
impl<N: CfgState + Display, L: PcodeReverseLinkage<N>> Display for ReverseLocationState<N, L> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(f, "Rev({})", self.inner)
}
}
impl<N: CfgState + JoinSemiLattice, L: PcodeReverseLinkage<N>> JoinSemiLattice
for ReverseLocationState<N, L>
{
fn join(&mut self, other: &Self) {
self.inner.join(&other.inner);
}
}
impl<N, L> AbstractState for ReverseLocationState<N, L>
where
N: CfgState + JoinSemiLattice + Display + PartialOrd + 'static,
L: PcodeReverseLinkage<N> + 'static,
{
fn merge(&mut self, other: &Self) -> MergeOutcome {
self.merge_sep(other)
}
fn stop<'a, T: Iterator<Item = &'a Self>>(&'a self, states: T) -> bool {
self.stop_sep(states)
}
fn transfer<'a, B: Borrow<PcodeOperation>>(&'a self, _op: B) -> Successor<'a, Self> {
let preds: Arc<Vec<N>> = Arc::new(self.linkage.predecessors_of(&self.inner));
let n = preds.len();
let linkage = Arc::clone(&self.linkage);
(0..n)
.map(move |i| ReverseLocationState {
inner: preds[i].clone(),
linkage: Arc::clone(&linkage),
})
.into()
}
}
impl<N: CfgState, L: PcodeReverseLinkage<N>> PcodeLocation for ReverseLocationState<N, L> {
fn location(&self) -> crate::analysis::cpa::lattice::pcode::PcodeAddressLattice {
self.inner.location()
}
}
impl<N, L> LocationState for ReverseLocationState<N, L>
where
N: CfgState + JoinSemiLattice + Display + PartialOrd + 'static,
L: PcodeReverseLinkage<N> + 'static,
{
fn get_transitions<'op, T: PcodeStore<'op> + ?Sized>(
&self,
store: &'op T,
) -> Vec<(PcodeOpRef<'op>, Self)> {
self.linkage
.predecessors_of(&self.inner)
.into_iter()
.filter_map(|pred| {
let addr = pred.concrete_location()?;
let op = store.get_pcode_op_at(addr)?;
Some((
op,
ReverseLocationState {
inner: pred,
linkage: Arc::clone(&self.linkage),
},
))
})
.collect()
}
}