diff --git a/include/uc_priv.h b/include/uc_priv.h index 56973157..c5f652e0 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -227,6 +227,7 @@ struct uc_struct { bool stop_request; // request to immediately stop emulation - for uc_emu_stop() bool quit_request; // request to quit the current TB, but continue to emulate - for uc_mem_protect() bool emulation_done; // emulation is done by uc_emu_start() + bool timed_out; // emulation timed out, uc_emu_start() will result in EC_ERR_TIMEOUT QemuThread timer; // timer for emulation timeout uint64_t timeout; // timeout for uc_emu_start() diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 9c08eea3..fb5a5657 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -163,7 +163,8 @@ typedef enum uc_err { UC_ERR_FETCH_UNALIGNED, // Unaligned fetch UC_ERR_HOOK_EXIST, // hook for this event already existed UC_ERR_RESOURCE, // Insufficient resource: uc_emu_start() - UC_ERR_EXCEPTION // Unhandled CPU exception + UC_ERR_EXCEPTION, // Unhandled CPU exception + UC_ERR_TIMEOUT // Emulation timed out } uc_err; diff --git a/samples/sample_x86.c b/samples/sample_x86.c index 9504106c..84928911 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -382,8 +382,8 @@ static void test_i386_loop(void) // emulate machine code in 2 seconds, so we can quit even // if the code loops err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_LOOP) - 1, 2 * UC_SECOND_SCALE, 0); - if (err) { - printf("Failed on uc_emu_start() with error returned %u: %s\n", + if (err != UC_ERR_TIMEOUT) { + printf("Failed on uc_emu_start() with error returned %u: %s, expected UC_ERR_TIMEOUT\n", err, uc_strerror(err)); } diff --git a/tests/unit/test_x86.c b/tests/unit/test_x86.c index f890a26f..280d4b07 100644 --- a/tests/unit/test_x86.c +++ b/tests/unit/test_x86.c @@ -379,7 +379,7 @@ static void test_i386_loop(void **state) // emulate machine code in 2 seconds, so we can quit even // if the code loops err = uc_emu_start(uc, address, address+sizeof(code), 2*UC_SECOND_SCALE, 0); - uc_assert_success(err); + uc_assert_err(err, UC_ERR_TIMEOUT); // verify register values uc_assert_success(uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx)); diff --git a/uc.c b/uc.c index ba6f49e6..adf6edd2 100644 --- a/uc.c +++ b/uc.c @@ -101,6 +101,8 @@ const char *uc_strerror(uc_err code) return "Insufficient resource (UC_ERR_RESOURCE)"; case UC_ERR_EXCEPTION: return "Unhandled CPU exception (UC_ERR_EXCEPTION)"; + case UC_ERR_TIMEOUT: + return "Emulation timed out (UC_ERR_TIMEOUT)"; } } @@ -504,6 +506,7 @@ static void *_timeout_fn(void *arg) // timeout before emulation is done? if (!uc->emulation_done) { + uc->timed_out = true; // force emulation to stop uc_emu_stop(uc); } @@ -535,6 +538,7 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time uc->invalid_error = UC_ERR_OK; uc->block_full = false; uc->emulation_done = false; + uc->timed_out = false; switch(uc->arch) { default: @@ -632,6 +636,9 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time qemu_thread_join(&uc->timer); } + if(uc->timed_out) + return UC_ERR_TIMEOUT; + return uc->invalid_error; }