import logging
from .engine import SuccessorsMixin
from .procedure import ProcedureMixin
from archinfo.arch_soot import SootAddressDescriptor
l = logging.getLogger(name=__name__)
# pylint: disable=abstract-method,unused-argument,arguments-differ
[docs]class HooksMixin(SuccessorsMixin, ProcedureMixin):
"""
A SimEngine mixin which adds a SimSuccessors handler which will look into the project's hooks and run the hook at
the current address.
Will respond to the following parameters provided to the step stack:
- procedure: A SimProcedure instance to force-run instead of consulting the current hooks
- ret_to: An address to force-return-to at the end of the procedure
"""
def _lookup_hook(self, state, procedure):
# TODO this is moderately controversial. If the jumpkind was NoHook and the user provided the procedure
# argument, which takes precedence?
# tentative guess: passed argument takes priority
if procedure is not None:
return procedure
# we have at this point entered the next step - we should check the "previous" jumpkind
if state.history and state.history.parent and state.history.parent.jumpkind == "Ijk_NoHook":
return None
if type(state._ip) is not int and state._ip.symbolic:
# symbolic IP is not supported
return None
addr = state.addr
procedure = self.project._sim_procedures.get(addr, None)
if procedure is not None:
return procedure
if not state.arch.name.startswith("ARM") or addr & 1 != 1:
return None
procedure = self.project._sim_procedures.get(addr - 1, None)
if procedure is not None:
return procedure
return None
[docs] def process_successors(self, successors, procedure=None, **kwargs):
state = self.state
if procedure is None:
procedure = self._lookup_hook(state, procedure)
if procedure is None:
return super().process_successors(successors, procedure=procedure, **kwargs)
if isinstance(procedure.addr, SootAddressDescriptor):
l.debug("Running %s (originally at %r)", repr(procedure), procedure.addr)
else:
l.debug(
"Running %s (originally at %s)",
repr(procedure),
procedure.addr if procedure.addr is None else hex(procedure.addr),
)
return self.process_procedure(state, successors, procedure, **kwargs)