diff --git a/qemu/accel/tcg/cpu-exec.c b/qemu/accel/tcg/cpu-exec.c index e8d493edd6..09148f1dbc 100644 --- a/qemu/accel/tcg/cpu-exec.c +++ b/qemu/accel/tcg/cpu-exec.c @@ -359,6 +359,9 @@ static inline bool cpu_handle_exception(CPUState *cpu, int *ret) // we want to stop emulation *ret = EXCP_HLT; return true; + } else { + // Continue execution because user hints us it has been handled + cpu->exception_index = -1; } } diff --git a/tests/regress/invalid_insn.py b/tests/regress/invalid_insn.py new file mode 100644 index 0000000000..42d74360f8 --- /dev/null +++ b/tests/regress/invalid_insn.py @@ -0,0 +1,71 @@ + +import regress + +from unicorn import * +from unicorn.x86_const import * + +from capstone import * + + +CODE = bytes.fromhex( + '48 31 c0' # xor rax,rax + '48 0f c7 f0' # rdrand rax + 'f4' # hlt +) + +BASE = 0x100000 +PAGE_SIZE = 0x1000 + +# max possible length of a x86 instruction +MAX_INSN_LEN = 15 + + +def hook_invalid_insn(uc, ud): + regress.logger.debug('entered invalid instruction handler') + + pc = uc.reg_read(UC_X86_REG_RIP) + data = uc.mem_read(pc, MAX_INSN_LEN) + + md = Cs(CS_ARCH_X86, CS_MODE_64) + insn = next(md.disasm(data, pc, 1)) + + if insn.mnemonic == 'rdrand': + # chosen by fair dice roll, guaranteed to be random + rax = 4 + + # set result to rax + uc.reg_write(UC_X86_REG_RAX, rax) + + # resume emulation from next instruction + uc.reg_write(UC_X86_REG_RIP, pc + insn.size) + + # signal uc we are ok + return True + + # not handled, uc will crash + return False + + +class TestHooks(regress.RegressTest): + def test_invalid_insn_recover(self): + mu = Uc(UC_ARCH_X86, UC_MODE_64) + + mu.mem_map(BASE, PAGE_SIZE) + mu.mem_write(BASE, CODE) + + mu.hook_add(UC_HOOK_INSN_INVALID, hook_invalid_insn) + + try: + mu.emu_start(BASE, BASE + len(CODE)) + except UcError as ex: + if ex.errno == UC_ERR_INSN_INVALID: + self.fail('invalid instruction did not recover properly') + + # unexpected exception, re-raise + raise + + self.assertNotEqual(0, mu.reg_read(UC_X86_REG_RAX)) + + +if __name__ == '__main__': + regress.main()