from typing import Optional, Generator
import claripy
from ....sim_options import HYBRID_SOLVER, APPROXIMATE_FIRST
from .... import concretization_strategies
from ....errors import SimMergeError, SimMemoryAddressError
from .. import MemoryMixin
from .abstract_address_descriptor import AbstractAddressDescriptor
from .region_data import AddressWrapper
[docs]class RegionedAddressConcretizationMixin(MemoryMixin):
[docs] def __init__(self, read_strategies=None, write_strategies=None, **kwargs):
super().__init__(**kwargs)
self.read_strategies = read_strategies
self.write_strategies = write_strategies
[docs] def set_state(self, state):
super().set_state(state)
if self.state is not None:
if self.read_strategies is None:
self._create_default_read_strategies()
if self.write_strategies is None:
self._create_default_write_strategies()
@MemoryMixin.memo
def copy(self, memo):
o = super().copy(memo)
o.read_strategies = list(self.read_strategies)
o.write_strategies = list(self.write_strategies)
return o
[docs] def merge(self, others, merge_conditions, common_ancestor=None) -> bool:
r = super().merge(others, merge_conditions, common_ancestor=common_ancestor)
self.read_strategies = self._merge_strategies(self.read_strategies, *[o.read_strategies for o in others])
self.write_strategies = self._merge_strategies(self.write_strategies, *[o.write_strategies for o in others])
return r
def _create_default_read_strategies(self):
"""
This function is used to populate `self.read_strategies` if by set-state time none have been provided
It uses state options to pick defaults.
"""
self.read_strategies = [
concretization_strategies.SimConcretizationStrategyUnlimitedRange(self._read_targets_limit)
]
def _create_default_write_strategies(self):
"""
This function is used to populate `self.write_strategies` if by set-state time none have been provided.
It uses state options to pick defaults.
"""
self.write_strategies = [
concretization_strategies.SimConcretizationStrategyUnlimitedRange(self._write_targets_limit)
]
@staticmethod
def _merge_strategies(*strategy_lists):
"""
Utility function for merging. Does the merge operation on lists of strategies
"""
if len({len(sl) for sl in strategy_lists}) != 1:
raise SimMergeError("unable to merge memories with amounts of strategies")
merged_strategies = []
for strategies in zip(*strategy_lists):
if len({s.__class__ for s in strategies}) != 1:
raise SimMergeError("unable to merge memories with different types of strategies")
unique = list(set(strategies))
if len(unique) > 1:
unique[0].merge(unique[1:])
merged_strategies.append(unique[0])
return merged_strategies
def _apply_concretization_strategies(self, addr, strategies):
"""
Applies concretization strategies on the address until one of them succeeds.
"""
for s in strategies:
a = s.concretize(self, addr)
# return the result if not None!
if a is not None:
return a
# well, we tried
raise SimMemoryAddressError("Unable to concretize address with the provided strategies.")
def _concretize_address_descriptor(
self,
desc: AbstractAddressDescriptor,
original_addr: claripy.ast.Bits,
is_write: bool = False,
target_region: Optional[str] = None,
) -> Generator[AddressWrapper, None, None]:
strategies = self.write_strategies if is_write else self.read_strategies
targets_limit = self._write_targets_limit if is_write else self._read_targets_limit
for region, addr_si in desc:
concrete_addrs = self._apply_concretization_strategies(addr_si, strategies)
if len(concrete_addrs) == targets_limit and HYBRID_SOLVER in self.state.options:
exact = True if APPROXIMATE_FIRST not in self.state.options else None
solutions = self.state.solver.eval_upto(original_addr, targets_limit, exact=exact)
if len(solutions) < len(concrete_addrs):
concrete_addrs = [addr_si.intersection(s).eval(1)[0] for s in solutions]
for c in concrete_addrs:
yield self._normalize_address_core(region, c, target_region=target_region)
def _normalize_address_core(
self, region_id: str, relative_address: int, target_region: Optional[str] = None
) -> AddressWrapper:
return super()._normalize_address_core(region_id, relative_address, target_region)