use std::{
collections::{HashMap, HashSet},
marker::PhantomData,
};
use petgraph::{graph::NodeIndex, visit::IntoNodeReferences};
use crate::{
abstract_domain::{AbstractDomain, DomainInsertion, HasTop},
analysis::{
forward_interprocedural_fixpoint::Context as _, graph::Node,
interprocedural_fixpoint_generic::NodeValue,
pointer_inference::PointerInference as PointerInferenceComputation,
pointer_inference::State as PointerInferenceState,
},
intermediate_representation::{Def, ExternSymbol, Project, Term, Tid},
};
use super::{state::State, Config};
pub mod symbol_calls;
mod trait_impls;
pub struct Context<'a, T: AbstractDomain + DomainInsertion + HasTop + Eq + From<String>> {
pub project: &'a Project,
pub pointer_inference_results: &'a PointerInferenceComputation<'a>,
pub string_symbol_map: HashMap<Tid, &'a ExternSymbol>,
pub extern_symbol_map: HashMap<Tid, &'a ExternSymbol>,
pub format_string_index_map: HashMap<String, usize>,
pub block_start_node_map: HashMap<(Tid, Tid), NodeIndex>,
pub block_first_def_set: HashSet<(Tid, Tid)>,
pub jmp_to_blk_end_node_map: HashMap<(Tid, Tid), NodeIndex>,
_phantom_string_domain: PhantomData<T>,
}
impl<'a, T: AbstractDomain + HasTop + Eq + From<String> + DomainInsertion> Context<'a, T> {
pub fn new(
project: &'a Project,
pointer_inference_results: &'a PointerInferenceComputation<'a>,
config: Config,
) -> Context<'a, T> {
let string_symbol_map =
crate::utils::symbol_utils::get_symbol_map(project, &config.string_symbols[..]);
let mut extern_symbol_map = HashMap::new();
for (tid, symbol) in project.program.term.extern_symbols.iter() {
extern_symbol_map.insert(tid.clone(), symbol);
}
let mut block_start_node_map: HashMap<(Tid, Tid), NodeIndex> = HashMap::new();
let mut block_first_def_set = HashSet::new();
let mut jmp_to_blk_end_node_map = HashMap::new();
for (node_id, node) in pointer_inference_results.get_graph().node_references() {
match node {
Node::BlkStart(block, sub) => {
if let Some(def) = block.term.defs.first() {
block_start_node_map.insert((def.tid.clone(), sub.tid.clone()), node_id);
block_first_def_set.insert((def.tid.clone(), sub.tid.clone()));
}
}
Node::BlkEnd(block, sub) => {
for jmp in block.term.jmps.iter() {
jmp_to_blk_end_node_map.insert((jmp.tid.clone(), sub.tid.clone()), node_id);
}
}
_ => (),
}
}
Context {
project,
pointer_inference_results,
format_string_index_map: config.format_string_index.into_iter().collect(),
string_symbol_map,
extern_symbol_map,
block_start_node_map,
block_first_def_set,
jmp_to_blk_end_node_map,
_phantom_string_domain: PhantomData,
}
}
fn get_current_pointer_inference_state(
&self,
state: &State<T>,
tid: &Tid,
) -> Option<PointerInferenceState> {
if let Some(pi_state) = state.get_pointer_inference_state() {
Some(pi_state.clone())
} else if let Some(node_id) = self
.block_start_node_map
.get(&(tid.clone(), state.get_current_sub().unwrap().tid.clone()))
{
match self.pointer_inference_results.get_node_value(*node_id) {
Some(NodeValue::Value(val)) => Some(val.clone()),
_ => None,
}
} else {
None
}
}
fn update_pointer_inference_state(&self, state: &mut State<T>, def: &Term<Def>) {
if let Some(pi_state) = self.get_current_pointer_inference_state(state, &def.tid) {
let pi_context = self.pointer_inference_results.get_context();
let new_pi_state = pi_context.update_def(&pi_state, def);
state.set_pointer_inference_state(new_pi_state);
}
}
}
#[cfg(test)]
mod tests;