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:
Takacs, Philipp 2023-03-06 15:35:01 +01:00
parent ca7e0e7f42
commit b7b1a4d6b4
13 changed files with 70 additions and 23 deletions

View File

@ -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, ...) \

View File

@ -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;

View File

@ -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);
} }
} }

View File

@ -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);
} }
} }

View File

@ -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

View File

@ -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);
} }
} }

View File

@ -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);
} }
} }

View File

@ -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);
} }
} }

View File

@ -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);
} }
} }

View File

@ -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);
} }
} }

View File

@ -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);
} }
} }

View File

@ -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
View File

@ -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