difference between stop_request and quit_request
quit_request is for internal use. This means the IP register was updated and qemu needs to rebuild the translation blocks. stop_request is set by the user (uc_emu_stop) to indecate that unicorn sould stop emulating.
This commit is contained in:
parent
ca7e0e7f42
commit
b7b1a4d6b4
@ -486,6 +486,28 @@ static inline void hooked_regions_check(uc_engine *uc, uint64_t start,
|
|||||||
length);
|
length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
break translation loop:
|
||||||
|
This is done in two cases:
|
||||||
|
1. the user wants to stop the emulation.
|
||||||
|
2. the user has set it IP. This requires to restart the internal
|
||||||
|
CPU emulation and rebuild some translation blocks
|
||||||
|
*/
|
||||||
|
static inline uc_err break_translation_loop(uc_engine *uc)
|
||||||
|
{
|
||||||
|
if (uc->emulation_done) {
|
||||||
|
return UC_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: make this atomic somehow?
|
||||||
|
if (uc->cpu) {
|
||||||
|
// exit the current TB
|
||||||
|
cpu_exit(uc->cpu);
|
||||||
|
}
|
||||||
|
|
||||||
|
return UC_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef UNICORN_TRACER
|
#ifdef UNICORN_TRACER
|
||||||
#define UC_TRACE_START(loc) trace_start(get_tracer(), loc)
|
#define UC_TRACE_START(loc) trace_start(get_tracer(), loc)
|
||||||
#define UC_TRACE_END(loc, fmt, ...) \
|
#define UC_TRACE_END(loc, fmt, ...) \
|
||||||
|
@ -96,7 +96,7 @@ static int tcg_cpu_exec(struct uc_struct *uc)
|
|||||||
r = cpu_exec(uc, cpu);
|
r = cpu_exec(uc, cpu);
|
||||||
|
|
||||||
// quit current TB but continue emulating?
|
// quit current TB but continue emulating?
|
||||||
if (uc->quit_request) {
|
if (uc->quit_request && !uc->stop_request) {
|
||||||
// reset stop_request
|
// reset stop_request
|
||||||
uc->stop_request = false;
|
uc->stop_request = false;
|
||||||
|
|
||||||
|
@ -372,7 +372,7 @@ int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
|||||||
if (regid == UC_ARM64_REG_PC) {
|
if (regid == UC_ARM64_REG_PC) {
|
||||||
// force to quit execution and flush TB
|
// force to quit execution and flush TB
|
||||||
uc->quit_request = true;
|
uc->quit_request = true;
|
||||||
uc_emu_stop(uc);
|
break_translation_loop(uc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -515,7 +515,7 @@ int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
|||||||
if (regid == UC_ARM_REG_R15) {
|
if (regid == UC_ARM_REG_R15) {
|
||||||
// force to quit execution and flush TB
|
// force to quit execution and flush TB
|
||||||
uc->quit_request = true;
|
uc->quit_request = true;
|
||||||
uc_emu_stop(uc);
|
break_translation_loop(uc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1521,7 +1521,7 @@ int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
|||||||
case UC_X86_REG_IP:
|
case UC_X86_REG_IP:
|
||||||
// force to quit execution and flush TB
|
// force to quit execution and flush TB
|
||||||
uc->quit_request = true;
|
uc->quit_request = true;
|
||||||
uc_emu_stop(uc);
|
break_translation_loop(uc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1535,7 +1535,7 @@ int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
|||||||
case UC_X86_REG_IP:
|
case UC_X86_REG_IP:
|
||||||
// force to quit execution and flush TB
|
// force to quit execution and flush TB
|
||||||
uc->quit_request = true;
|
uc->quit_request = true;
|
||||||
uc_emu_stop(uc);
|
break_translation_loop(uc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -117,7 +117,7 @@ int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
|||||||
if (regid == UC_M68K_REG_PC) {
|
if (regid == UC_M68K_REG_PC) {
|
||||||
// force to quit execution and flush TB
|
// force to quit execution and flush TB
|
||||||
uc->quit_request = true;
|
uc->quit_request = true;
|
||||||
uc_emu_stop(uc);
|
break_translation_loop(uc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +170,7 @@ int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
|||||||
if (regid == UC_MIPS_REG_PC) {
|
if (regid == UC_MIPS_REG_PC) {
|
||||||
// force to quit execution and flush TB
|
// force to quit execution and flush TB
|
||||||
uc->quit_request = true;
|
uc->quit_request = true;
|
||||||
uc_emu_stop(uc);
|
break_translation_loop(uc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -361,7 +361,7 @@ int ppc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
|||||||
if (regid == UC_PPC_REG_PC) {
|
if (regid == UC_PPC_REG_PC) {
|
||||||
// force to quit execution and flush TB
|
// force to quit execution and flush TB
|
||||||
uc->quit_request = true;
|
uc->quit_request = true;
|
||||||
uc_emu_stop(uc);
|
break_translation_loop(uc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -560,7 +560,7 @@ int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
|||||||
if (regid == UC_RISCV_REG_PC) {
|
if (regid == UC_RISCV_REG_PC) {
|
||||||
// force to quit execution and flush TB
|
// force to quit execution and flush TB
|
||||||
uc->quit_request = true;
|
uc->quit_request = true;
|
||||||
uc_emu_stop(uc);
|
break_translation_loop(uc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -130,7 +130,7 @@ static int s390_reg_write(struct uc_struct *uc, unsigned int *regs,
|
|||||||
if (regid == UC_S390X_REG_PC) {
|
if (regid == UC_S390X_REG_PC) {
|
||||||
// force to quit execution and flush TB
|
// force to quit execution and flush TB
|
||||||
uc->quit_request = true;
|
uc->quit_request = true;
|
||||||
uc_emu_stop(uc);
|
break_translation_loop(uc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,7 +229,7 @@ int tricore_reg_write(struct uc_struct *uc, unsigned int *regs,
|
|||||||
if (regid == UC_TRICORE_REG_PC) {
|
if (regid == UC_TRICORE_REG_PC) {
|
||||||
// force to quit execution and flush TB
|
// force to quit execution and flush TB
|
||||||
uc->quit_request = true;
|
uc->quit_request = true;
|
||||||
uc_emu_stop(uc);
|
break_translation_loop(uc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -304,6 +304,41 @@ static void test_uc_hook_cached_uaf(void)
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_uc_emu_stop_set_ip_callback(uc_engine *uc, uint64_t address, uint32_t size, void *userdata)
|
||||||
|
{
|
||||||
|
uint64_t rip = code_start + 0xb;
|
||||||
|
|
||||||
|
if (address == code_start + 0x7) {
|
||||||
|
printf("stoping\n");
|
||||||
|
uc_emu_stop(uc);
|
||||||
|
uc_reg_write(uc, UC_X86_REG_RIP, &rip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_uc_emu_stop_set_ip(void)
|
||||||
|
{
|
||||||
|
uc_engine *uc;
|
||||||
|
uc_hook h;
|
||||||
|
uint64_t rip;
|
||||||
|
|
||||||
|
char code[] = "\x48\x31\xc0" // 0x0 xor rax, rax : rax = 0
|
||||||
|
"\x90" // 0x3 nop :
|
||||||
|
"\x48\xff\xc0" // 0x4 inc rax : rax++
|
||||||
|
"\x90" // 0x7 nop : <-- going to stop here
|
||||||
|
"\x48\xff\xc0" // 0x8 inc rax : rax++
|
||||||
|
"\x90" // 0xb nop :
|
||||||
|
"\x0f\x0b" // 0xc ud2 : <-- will raise UC_ERR_INSN_INVALID, but should not never be reached
|
||||||
|
"\x90" // 0xe nop :
|
||||||
|
"\x90"; // 0xf nop :
|
||||||
|
|
||||||
|
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_64, code, sizeof(code) - 1);
|
||||||
|
OK(uc_hook_add(uc, &h, UC_HOOK_CODE, test_uc_emu_stop_set_ip_callback, NULL, 1, 0));
|
||||||
|
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||||
|
OK(uc_reg_read(uc, UC_X86_REG_RIP, &rip));
|
||||||
|
TEST_CHECK(rip == code_start + 0xb);
|
||||||
|
OK(uc_close(uc));
|
||||||
|
}
|
||||||
|
|
||||||
TEST_LIST = {{"test_uc_ctl_mode", test_uc_ctl_mode},
|
TEST_LIST = {{"test_uc_ctl_mode", test_uc_ctl_mode},
|
||||||
{"test_uc_ctl_page_size", test_uc_ctl_page_size},
|
{"test_uc_ctl_page_size", test_uc_ctl_page_size},
|
||||||
{"test_uc_ctl_arch", test_uc_ctl_arch},
|
{"test_uc_ctl_arch", test_uc_ctl_arch},
|
||||||
@ -315,4 +350,5 @@ TEST_LIST = {{"test_uc_ctl_mode", test_uc_ctl_mode},
|
|||||||
{"test_uc_ctl_arm_cpu", test_uc_ctl_arm_cpu},
|
{"test_uc_ctl_arm_cpu", test_uc_ctl_arm_cpu},
|
||||||
#endif
|
#endif
|
||||||
{"test_uc_hook_cached_uaf", test_uc_hook_cached_uaf},
|
{"test_uc_hook_cached_uaf", test_uc_hook_cached_uaf},
|
||||||
|
{"test_uc_emu_stop_set_ip", test_uc_emu_stop_set_ip},
|
||||||
{NULL, NULL}};
|
{NULL, NULL}};
|
||||||
|
13
uc.c
13
uc.c
@ -907,19 +907,8 @@ UNICORN_EXPORT
|
|||||||
uc_err uc_emu_stop(uc_engine *uc)
|
uc_err uc_emu_stop(uc_engine *uc)
|
||||||
{
|
{
|
||||||
UC_INIT(uc);
|
UC_INIT(uc);
|
||||||
|
|
||||||
if (uc->emulation_done) {
|
|
||||||
return UC_ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
uc->stop_request = true;
|
uc->stop_request = true;
|
||||||
// TODO: make this atomic somehow?
|
return break_translation_loop(uc);
|
||||||
if (uc->cpu) {
|
|
||||||
// exit the current TB
|
|
||||||
cpu_exit(uc->cpu);
|
|
||||||
}
|
|
||||||
|
|
||||||
return UC_ERR_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// return target index where a memory region at the address exists, or could be
|
// return target index where a memory region at the address exists, or could be
|
||||||
|
Loading…
Reference in New Issue
Block a user