From c206e37963b4291b7eed62ed08cf7f547916c48d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= Date: Tue, 14 Jan 2020 09:42:50 -0500 Subject: [PATCH] Timeout error (#1173) * Implement timeout state and new error for such case * Adjust test_i386_loop sample * Adjust test_i386_loop test Backports commit 3a3bc0c22de5453335dfb597a95dbda07c9f47a2 from unicorn --- include/uc_priv.h | 1 + include/unicorn/unicorn.h | 3 ++- samples/sample_x86.c | 6 +++--- tests/unit/test_x86.c | 2 +- uc.c | 8 ++++++++ 5 files changed, 15 insertions(+), 5 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index c9772b25..f634d6cf 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -262,6 +262,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 91aa2638..544e4feb 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -170,7 +170,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..e5fe0134 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -382,9 +382,9 @@ 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", - err, uc_strerror(err)); + 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)); } // now print out some registers 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 3a743dff..45f18b02 100644 --- a/uc.c +++ b/uc.c @@ -103,6 +103,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)"; } } @@ -530,6 +532,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); } @@ -561,6 +564,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: @@ -663,6 +667,10 @@ 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; }