UNICORN_EXPORT uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count) { // reset the counter uc->emu_counter = 0; uc->invalid_error = UC_ERR_OK; uc->block_full = false; uc->emulation_done = false; switch(uc->arch) { default: break; case UC_ARCH_M68K: uc_reg_write(uc, UC_M68K_REG_PC, &begin); break; case UC_ARCH_X86: switch(uc->mode) { default: break; case UC_MODE_16: uc_reg_write(uc, UC_X86_REG_IP, &begin); break; case UC_MODE_32: uc_reg_write(uc, UC_X86_REG_EIP, &begin); break; case UC_MODE_64: uc_reg_write(uc, UC_X86_REG_RIP, &begin); break; } break; case UC_ARCH_ARM: uc_reg_write(uc, UC_ARM_REG_R15, &begin); break; case UC_ARCH_ARM64: uc_reg_write(uc, UC_ARM64_REG_PC, &begin); break; case UC_ARCH_MIPS: // TODO: MIPS32/MIPS64/BIGENDIAN etc uc_reg_write(uc, UC_MIPS_REG_PC, &begin); break; case UC_ARCH_SPARC: // TODO: Sparc/Sparc64 uc_reg_write(uc, UC_SPARC_REG_PC, &begin); break; } uc->stop_request = false; uc->emu_count = count; // remove count hook if counting isn't necessary if (count <= 0 && uc->count_hook != 0) { uc_hook_del(uc, uc->count_hook); uc->count_hook = 0; } // set up count hook to count instructions. if (count > 0 && uc->count_hook == 0) { uc_err err = uc_hook_add(uc, &uc->count_hook, UC_HOOK_CODE, hook_count_cb, NULL, 1, 0); if (err != UC_ERR_OK) { return err; } } uc->addr_end = until; if (timeout) enable_emu_timer(uc, timeout * 1000); // microseconds -> nanoseconds if (uc->vm_start(uc)) { return UC_ERR_RESOURCE; } // emulation is done uc->emulation_done = true; if (timeout) { // wait for the timer to finish qemu_thread_join(&uc->timer); } return uc->invalid_error; }
UNICORN_EXPORT uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count) { // reset the counter uc->emu_counter = 0; uc->stop_request = false; uc->invalid_error = UC_ERR_OK; uc->block_full = false; uc->emulation_done = false; switch(uc->arch) { default: break; case UC_ARCH_M68K: uc_reg_write(uc, UC_M68K_REG_PC, &begin); break; case UC_ARCH_X86: switch(uc->mode) { default: break; case UC_MODE_16: uc_reg_write(uc, UC_X86_REG_IP, &begin); break; case UC_MODE_32: uc_reg_write(uc, UC_X86_REG_EIP, &begin); break; case UC_MODE_64: uc_reg_write(uc, UC_X86_REG_RIP, &begin); break; } break; case UC_ARCH_ARM: switch(uc->mode) { default: break; case UC_MODE_THUMB: case UC_MODE_ARM: uc_reg_write(uc, UC_ARM_REG_R15, &begin); break; } break; case UC_ARCH_ARM64: uc_reg_write(uc, UC_ARM64_REG_PC, &begin); break; case UC_ARCH_MIPS: // TODO: MIPS32/MIPS64/BIGENDIAN etc uc_reg_write(uc, UC_MIPS_REG_PC, &begin); break; case UC_ARCH_SPARC: // TODO: Sparc/Sparc64 uc_reg_write(uc, UC_SPARC_REG_PC, &begin); break; } uc->emu_count = count; if (count > 0) { uc->hook_insn = true; } uc->addr_end = until; uc->vm_start(uc); if (timeout) enable_emu_timer(uc, timeout * 1000); // microseconds -> nanoseconds uc->pause_all_vcpus(uc); // emulation is done uc->emulation_done = true; if (timeout) { // wait for the timer to finish qemu_thread_join(&uc->timer); } return uc->invalid_error; }