From d341bc94ff1cd015aa3fffc96c155aeab166a910 Mon Sep 17 00:00:00 2001 From: Peter Goodman Date: Wed, 8 Nov 2017 14:48:23 -0500 Subject: [PATCH] Move inline function definitions out of the AbstractCPU's execute method (#538) * This change moves from inline function definitions out of the critical path of AbstractCpu's execute method. * Raise a mcore exception if we fail at emulation --- manticore/core/cpu/abstractcpu.py | 62 +++++++++++++++++-------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/manticore/core/cpu/abstractcpu.py b/manticore/core/cpu/abstractcpu.py index bfc89e2..b9a447b 100644 --- a/manticore/core/cpu/abstractcpu.py +++ b/manticore/core/cpu/abstractcpu.py @@ -42,6 +42,12 @@ class InstructionNotImplementedError(CpuException): ''' pass +class InstructionEmulationError(CpuException): + ''' + Exception raised when failing to emulate an instruction outside of Manticore. + ''' + pass + class DivideByZeroError(CpuException): ''' A division by zero ''' pass @@ -742,36 +748,36 @@ class Cpu(Eventful): return name = self.canonicalize_instruction_name(insn) - - def fallback_to_emulate(*operands): - text_bytes = ' '.join('%02x'%x for x in insn.bytes) - logger.info("Unimplemented instruction: 0x%016x:\t%s\t%s\t%s", - insn.address, text_bytes, insn.mnemonic, insn.op_str) - self.emulate(insn) - - implementation = getattr(self, name, fallback_to_emulate) - + if logger.level == logging.DEBUG : logger.debug(self.render_instruction(insn)) for l in self.render_registers(): register_logger.debug(l) - #FIXME(yan): In the case the instruction implementation invokes a system call, we would not be able to - # publish the did_execute_instruction event from here, so we capture and attach it to the syscall - # exception for the platform to emit it for us once the syscall has successfully been executed. - def did_exec(): - self._icount += 1 - self._publish('did_execute_instruction', self._last_pc, self.PC, insn) - try: - implementation(*insn.operands) + try: + getattr(self, name)(*insn.operands) + except AttributeError: + text_bytes = ' '.join('%02x'%x for x in insn.bytes) + logger.info("Unimplemented instruction: 0x%016x:\t%s\t%s\t%s", + insn.address, text_bytes, insn.mnemonic, insn.op_str) + self.emulate(insn) except (Interruption, Syscall) as e: - e.on_handled = did_exec + e.on_handled = lambda: self._publish_instruction_as_executed(insn) raise e else: - did_exec() - + self._publish_instruction_as_executed(insn) + #FIXME(yan): In the case the instruction implementation invokes a system call, we would not be able to + # publish the did_execute_instruction event from here, so we capture and attach it to the syscall + # exception for the platform to emit it for us once the syscall has successfully been executed. + def _publish_instruction_as_executed(self, insn): + ''' + Notify listeners that an instruction has been executed. + ''' + self._icount += 1 + self._publish('did_execute_instruction', self._last_pc, self.PC, insn) + def emulate(self, insn): ''' If we could not handle emulating an instruction, use Unicorn to emulate @@ -781,13 +787,15 @@ class Cpu(Eventful): ''' emu = UnicornEmulator(self) - emu.emulate(insn) - - - # We have been seeing occasional Unicorn issues with it not clearing - # the backing unicorn instance. Saw fewer issues with the following - # line present. - del emu + try: + emu.emulate(insn) + except e: + raise InstructionEmulationError(str(e)) + finally: + # We have been seeing occasional Unicorn issues with it not clearing + # the backing unicorn instance. Saw fewer issues with the following + # line present. + del emu def render_instruction(self, insn=None): try: