Source code for angr.state_plugins.sim_action_object

import logging

l = logging.getLogger(name=__name__)

import claripy
import functools

from .. import sim_options as o

# pylint:disable=unidiomatic-typecheck

_noneset = frozenset()


def _raw_ast(a):
    if type(a) is SimActionObject:
        return a.ast
    elif type(a) is dict:
        return {k: _raw_ast(a[k]) for k in a}
    elif type(a) in (tuple, list, set, frozenset):
        return type(a)(_raw_ast(b) for b in a)
    elif type(a) in (zip, filter, map):
        return (_raw_ast(i) for i in a)
    else:
        return a


def _all_objects(a):
    if type(a) is SimActionObject:
        yield a
    elif type(a) is dict:
        for b in a.values():
            yield from _all_objects(b)
    elif type(a) is (tuple, list, set, frozenset):
        for b in a:
            yield from _all_objects(b)


[docs]def ast_stripping_op(f, *args, **kwargs): new_args = _raw_ast(args) new_kwargs = _raw_ast(kwargs) return f(*new_args, **new_kwargs)
[docs]def ast_preserving_op(f, *args, **kwargs): tmp_deps = frozenset.union(_noneset, *(a.tmp_deps for a in _all_objects(args))) reg_deps = frozenset.union(_noneset, *(a.reg_deps for a in _all_objects(args))) a = ast_stripping_op(f, *args, **kwargs) if isinstance(a, claripy.ast.Base): return SimActionObject(a, reg_deps=reg_deps, tmp_deps=tmp_deps) else: return a
[docs]def ast_stripping_decorator(f): @functools.wraps(f) def ast_stripper(*args, **kwargs): new_args = _raw_ast(args) new_kwargs = _raw_ast(kwargs) return f(*new_args, **new_kwargs) return ast_stripper
[docs]class SimActionObject: """ A SimActionObject tracks an AST and its dependencies. """
[docs] def __init__(self, ast, reg_deps=None, tmp_deps=None, deps=None, state=None): if type(ast) is SimActionObject: raise SimActionError("SimActionObject inception!!!") self.ast = ast if deps is not None: if len(deps) == 0 or (state is not None and o.ACTION_DEPS not in state.options): self.reg_deps = _noneset self.tmp_deps = _noneset else: self.reg_deps = frozenset.union( *[r.reg_deps for r in deps if type(r) in (sim_action.SimActionData, sim_action.SimActionOperation)] ) self.tmp_deps = frozenset.union( *[r.tmp_deps for r in deps if type(r) in (sim_action.SimActionData, sim_action.SimActionOperation)] ) else: self.reg_deps = _noneset if reg_deps is None else reg_deps self.tmp_deps = _noneset if tmp_deps is None else tmp_deps
def __repr__(self): return f"<SAO {self.ast}>" def __getstate__(self): return self.ast, self.reg_deps, self.tmp_deps def __setstate__(self, data): self.ast, self.reg_deps, self.tmp_deps = data def _preserving_unbound(self, f, *args, **kwargs): return ast_preserving_op(f, *((self,) + tuple(args)), **kwargs) def _preserving_bound(self, f, *args, **kwargs): # pylint:disable=no-self-use return ast_preserving_op(f, *args, **kwargs) def __getattr__(self, attr): if attr == "__slots__": raise AttributeError("not forwarding __slots__ to AST") f = getattr(self.ast, attr) if hasattr(f, "__call__"): return functools.partial(self._preserving_bound, f) elif isinstance(f, claripy.ast.Base): return SimActionObject(f, reg_deps=self.reg_deps, tmp_deps=self.tmp_deps) else: return f def __len__(self): return len(self.ast)
[docs] def to_claripy(self): return self.ast
[docs] def copy(self): return SimActionObject(self.ast, self.reg_deps, self.tmp_deps)
# # Overload the operators # def _operator(cls, op_name): def wrapper(self, *args, **kwargs): return self._preserving_unbound(getattr(self.ast.__class__, op_name), *args, **kwargs) wrapper.__name__ = op_name setattr(cls, op_name, wrapper)
[docs]def make_methods(): for name in claripy.operations.expression_operations | {"__getitem__"}: _operator(SimActionObject, name)
make_methods() from ..errors import SimActionError from . import sim_action