Source code for angr.state_plugins.plugin

from typing import cast

import angr  # For type annotations; pylint: disable=unused-import
import logging

from ..misc.ux import once

l = logging.getLogger(name=__name__)


[docs]class SimStatePlugin: """ This is a base class for SimState plugins. A SimState plugin will be copied along with the state when the state is branched. They are intended to be used for things such as tracking open files, tracking heap details, and providing storage and persistence for SimProcedures. """ STRONGREF_STATE = False
[docs] def __init__(self): self.state: angr.SimState = cast(angr.SimState, None)
[docs] def set_state(self, state): """ Sets a new state (for example, if the state has been branched) """ self.state = state._get_weakref()
[docs] def set_strongref_state(self, state): pass
def __getstate__(self): d = dict(self.__dict__) d["state"] = None return d
[docs] def copy(self, _memo): """ Should return a copy of the plugin without any state attached. Should check the memo first, and add itself to memo if it ends up making a new copy. In order to simplify using the memo, you should annotate implementations of this function with ``SimStatePlugin.memo`` The base implementation of this function constructs a new instance of the plugin's class without calling its initializer. If you super-call down to it, make sure you instanciate all the fields in your copy method! :param memo: A dictionary mapping object identifiers (id(obj)) to their copied instance. Use this to avoid infinite recursion and diverged copies. """ o = type(self).__new__(type(self)) o.state = None return o
[docs] @staticmethod def memo(f): """ A decorator function you should apply to ``copy`` """ def inner(self, memo=None, **kwargs): if memo is None: memo = {} if id(self) in memo: return memo[id(self)] else: c = f(self, memo, **kwargs) memo[id(self)] = c return c return inner
[docs] def merge(self, others, merge_conditions, common_ancestor=None): # pylint:disable=unused-argument """ Should merge the state plugin with the provided others. This will be called by ``state.merge()`` after copying the target state, so this should mutate the current instance to merge with the others. Note that when multiple instances of a single plugin object (for example, a file) are referenced in the state, it is important that merge only ever be called once. This should be solved by designating one of the plugin's referees as the "real owner", who should be the one to actually merge it. This technique doesn't work to resolve the similar issue that arises during copying because merging doesn't produce a new reference to insert. There will be n ``others`` and n+1 merge conditions, since the first condition corresponds to self. To match elements up to conditions, say ``zip([self] + others, merge_conditions)`` When implementing this, make sure that you "deepen" both ``others`` and ``common_ancestor`` before calling sub-elements' merge methods, e.g. .. code-block:: python self.foo.merge( [o.foo for o in others], merge_conditions, common_ancestor=common_ancestor.foo if common_ancestor is not None else None ) During static analysis, merge_conditions can be None, in which case you should use ``state.solver.union(values)``. TODO: fish please make this less bullshit There is a utility ``state.solver.ite_cases`` which will help with constructing arbitrarily large merged ASTs. Use it like ``self.bar = self.state.solver.ite_cases(zip(conditions[1:], [o.bar for o in others]), self.bar)`` :param others: the other state plugins to merge with :param merge_conditions: a symbolic condition for each of the plugins :param common_ancestor: a common ancestor of this plugin and the others being merged :returns: True if the state plugins are actually merged. :rtype: bool """ raise NotImplementedError("merge() not implement for %s" % self.__class__.__name__)
[docs] def widen(self, others): # pylint:disable=unused-argument """ The widening operation for plugins. Widening is a special kind of merging that produces a more general state from several more specific states. It is used only during intensive static analysis. The same behavior regarding copying and mutation from ``merge`` should be followed. :param others: the other state plugin :returns: True if the state plugin is actually widened. :rtype: bool """ raise NotImplementedError("widen() not implemented for %s" % self.__class__.__name__)
[docs] @classmethod def register_default(cls, name, xtr=None): if cls is SimStatePlugin: if once("simstateplugin_register_default deprecation"): l.critical( "SimStatePlugin.register_default(name, cls) is deprecated, " "please use SimState.register_default(name)" ) from angr.sim_state import SimState SimState.register_default(name, xtr) else: if xtr is cls: if once("simstateplugin_register_default deprecation case 2"): l.critical( "SimStatePlugin.register_default(name, cls) is deprecated, " "please use cls.register_default(name)" ) xtr = None from angr.sim_state import SimState SimState.register_default(name, cls, xtr if xtr is not None else "default")
[docs] def init_state(self): """ Use this function to perform any initialization on the state at plugin-add time """ pass