use super::*;
use crate::analysis::function_signature::AccessPattern;
impl<'a> Context<'a> {
pub fn create_callee_id_to_caller_data_map(
&self,
state_before_call: &State,
state_before_return: &State,
) -> BTreeMap<AbstractIdentifier, Data> {
let stack_register = &self.project.stack_pointer_register;
let mut id_map = BTreeMap::new();
let callee_tid = state_before_return.get_fn_tid();
if let Some(callee_fn_sig) = self.fn_signatures.get(callee_tid) {
for param in callee_fn_sig.parameters.keys() {
let param_id = AbstractIdentifier::new(callee_tid.clone(), param.clone());
let param_value = state_before_call
.eval_abstract_location(param, &self.project.runtime_memory_image);
id_map.insert(param_id, param_value);
}
for global_param in callee_fn_sig.global_parameters.keys() {
let global_param_id =
AbstractIdentifier::new(callee_tid.clone(), global_param.clone());
let global_param_value = state_before_call
.eval_abstract_location(global_param, &self.project.runtime_memory_image);
id_map.insert(global_param_id, global_param_value);
}
}
for object_id in state_before_return.memory.get_all_object_ids() {
if object_id.get_tid() != callee_tid || !object_id.get_path_hints().is_empty() {
id_map.insert(
object_id.clone(),
Data::from_target(
object_id,
Bitvector::zero(stack_register.size.into()).into(),
),
);
}
}
id_map.insert(
state_before_return.stack_id.clone(),
Data::new_top(stack_register.size),
);
id_map.insert(
state_before_return.get_global_mem_id(),
Data::from_target(
state_before_call.get_global_mem_id(),
Bitvector::zero(stack_register.size.into()).into(),
),
);
id_map
}
pub fn create_full_callee_id_to_caller_data_map(
&self,
state_before_call: &State,
state_before_return: &State,
call_tid: &Tid,
) -> BTreeMap<AbstractIdentifier, Data> {
let cconv = &self.project.program.term.subs[state_before_return.get_fn_tid()]
.term
.calling_convention;
let cconv = match self.project.get_specific_calling_convention(cconv) {
Some(cconv) => cconv,
None => {
return BTreeMap::new();
}
};
let callee_fn_sig = self
.fn_signatures
.get(state_before_return.get_fn_tid())
.unwrap();
let mut minimized_return_state = state_before_return.clone();
minimized_return_state.minimize_before_return_instruction(callee_fn_sig, cconv);
let mut location_to_data_map =
minimized_return_state.map_abstract_locations_to_pointer_data(call_tid);
minimized_return_state.filter_location_to_pointer_data_map(&mut location_to_data_map);
let mut replacement_map =
minimized_return_state.get_id_to_unified_ids_replacement_map(&location_to_data_map);
minimized_return_state.merge_mem_objects_with_unique_abstract_location(call_tid);
let unified_to_caller_replacement_map =
self.create_callee_id_to_caller_data_map(state_before_call, &minimized_return_state);
for value in replacement_map.values_mut() {
value.replace_all_ids(&unified_to_caller_replacement_map);
}
let callee_tid = state_before_return.get_fn_tid();
for (id, value) in unified_to_caller_replacement_map {
if id.get_tid() == callee_tid && id.get_path_hints().is_empty() {
replacement_map.insert(id, value);
}
}
replacement_map
}
pub fn create_id_to_access_pattern_map(
&self,
state: &State,
) -> BTreeMap<AbstractIdentifier, &AccessPattern> {
let mut id_to_access_pattern_map = BTreeMap::new();
let fn_tid = state.get_fn_tid();
let callee_fn_sig = self.fn_signatures.get(fn_tid).unwrap();
for (param, access_pattern) in &callee_fn_sig.parameters {
let param_id = AbstractIdentifier::new(fn_tid.clone(), param.clone());
id_to_access_pattern_map.insert(param_id.clone(), access_pattern);
}
for (param, access_pattern) in &callee_fn_sig.global_parameters {
let param_id = AbstractIdentifier::new(fn_tid.clone(), param.clone());
id_to_access_pattern_map.insert(param_id.clone(), access_pattern);
}
id_to_access_pattern_map
}
pub fn get_unsound_caller_ids(
&self,
callee_id_to_caller_data_map: &BTreeMap<AbstractIdentifier, Data>,
callee_id_to_access_pattern_map: &BTreeMap<AbstractIdentifier, &AccessPattern>,
) -> BTreeSet<AbstractIdentifier> {
let mut ids_touched = BTreeSet::new();
let mut ids_modified = BTreeSet::new();
let mut unsound_caller_ids = BTreeSet::new();
for (callee_id, access_pattern) in callee_id_to_access_pattern_map {
for id in callee_id_to_caller_data_map
.get(callee_id)
.unwrap()
.referenced_ids()
{
if ids_modified.contains(id)
|| (access_pattern.is_mutably_dereferenced() && ids_touched.contains(id))
{
unsound_caller_ids.insert(id.clone());
}
ids_touched.insert(id.clone());
if access_pattern.is_mutably_dereferenced() {
ids_modified.insert(id.clone());
}
}
}
unsound_caller_ids
}
}