allow to change PC during callback. this solves issue #210

This commit is contained in:
Nguyen Anh Quynh
2016-01-28 14:06:17 +08:00
parent e750a4e97c
commit 5a04bcb115
11 changed files with 143 additions and 2 deletions

View File

@@ -5,7 +5,7 @@ CFLAGS += -lcmocka -lunicorn
CFLAGS += -I ../../include
ALL_TESTS = test_sanity test_x86 test_mem_map test_mem_high test_mem_map_ptr \
test_tb_x86 test_multihook
test_tb_x86 test_multihook test_pc_change
.PHONY: all
all: ${ALL_TESTS}
@@ -24,6 +24,7 @@ test: ${ALL_TESTS}
./test_mem_high
./test_tb_x86
./test_multihook
./test_pc_change
test_sanity: test_sanity.c
test_x86: test_x86.c
@@ -32,6 +33,7 @@ test_mem_map_ptr: test_mem_map_ptr.c
test_mem_high: test_mem_high.c
test_tb_x86: test_tb_x86.c
test_multihook: test_multihook.c
test_pc_change: test_pc_change.c
${ALL_TESTS}:
${CC} ${CFLAGS} -o $@ $^

104
tests/unit/test_pc_change.c Normal file
View File

@@ -0,0 +1,104 @@
// Test PC change during the callback. by Nguyen Anh Quynh, 2016
#include "unicorn_test.h"
#include <inttypes.h>
#define OK(x) uc_assert_success(x)
/* Called before every test to set up a new instance */
static int setup32(void **state)
{
uc_engine *uc;
OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc));
*state = uc;
return 0;
}
/* Called after every test to clean up */
static int teardown(void **state)
{
uc_engine *uc = *state;
OK(uc_close(uc));
*state = NULL;
return 0;
}
/******************************************************************************/
static void test_code_hook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
{
uint8_t tmp[256];
int32_t r_eip = 0x1000006;
printf("instruction at 0x%"PRIx64": ", address);
if (!uc_mem_read(uc, address, tmp, size)) {
uint32_t i;
for (i = 0; i < size; i++) {
printf("0x%x ", tmp[i]);
}
printf("\n");
}
if (address == 0x1000003) {
// change the PC to "inc EDX"
uc_reg_write(uc, UC_X86_REG_EIP, &r_eip);
}
}
static void test_pc_change(void **state)
{
uc_engine *uc = *state;
uc_hook trace1;
int32_t r_ecx = 3, r_edx = 15;
#define BASEADDR 0x1000000
uint64_t address = BASEADDR;
const uint8_t code[] = {
0x41, // inc ECX @0x1000000
0x41, // inc ECX
0x41, // inc ECX
0x41, // inc ECX @0x1000003
0x41, // inc ECX
0x41, // inc ECX
0x42, // inc EDX @0x1000006
0x42, // inc EDX
};
#undef BASEADDR
// map 2MB memory for this emulation
OK(uc_mem_map(uc, address, 2 * 1024 * 1024, UC_PROT_ALL));
// write machine code to be emulated to memory
OK(uc_mem_write(uc, address, code, sizeof(code)));
uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx);
uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
printf("ECX = %u, EDX = %u\n", r_ecx, r_edx);
// trace all instructions
OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, test_code_hook, NULL, (uint64_t)1, (uint64_t)0));
OK(uc_emu_start(uc, address, address+sizeof(code), 0, 0));
uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx);
uc_reg_read(uc, UC_X86_REG_EDX, &r_edx);
printf("ECX = %u, EDX = %u\n", r_ecx, r_edx);
assert_int_equal(r_ecx, 6);
assert_int_equal(r_edx, 17);
}
int main(void)
{
const struct CMUnitTest tests[] = {
cmocka_unit_test_setup_teardown(test_pc_change, setup32, teardown),
};
return cmocka_run_group_tests(tests, NULL, NULL);
}