diff --git a/tests/unit/Makefile b/tests/unit/Makefile index b261da4d..cd0e46eb 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile @@ -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_tb_x86 test_multihook .PHONY: all all: ${ALL_TESTS} @@ -23,6 +23,7 @@ test: ${ALL_TESTS} ./test_mem_map_ptr ./test_mem_high ./test_tb_x86 + ./test_multihook test_sanity: test_sanity.c test_x86: test_x86.c @@ -30,6 +31,7 @@ test_mem_map: test_mem_map.c 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 ${ALL_TESTS}: ${CC} ${CFLAGS} -o $@ $^ diff --git a/tests/unit/test_multihook.c b/tests/unit/test_multihook.c new file mode 100644 index 00000000..eb831865 --- /dev/null +++ b/tests/unit/test_multihook.c @@ -0,0 +1,111 @@ +#include "unicorn_test.h" +#include + +#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; +} + +/******************************************************************************/ + +struct bb { + uint64_t addr; + size_t size; +}; + +struct bbtest { + const struct bb *blocks; + unsigned int blocknum; +}; + + +static void test_basic_blocks_hook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + struct bbtest *bbtest = user_data; + const struct bb *bb = &bbtest->blocks[bbtest->blocknum]; + + printf("block hook 1: %d == %zu\n", size, bb->size); + assert_int_equal(address, bb->addr); + assert_int_equal((size_t)size, bb->size); +} + +static void test_basic_blocks_hook2(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + struct bbtest *bbtest = user_data; + const struct bb *bb = &bbtest->blocks[bbtest->blocknum++]; + + printf("block hook 2: %d == %zu\n", size, bb->size); + assert_int_equal(address, bb->addr); + assert_int_equal((size_t)size, bb->size); +} + +static void test_basic_blocks(void **state) +{ + uc_engine *uc = *state; + uc_hook trace1, trace2; + +#define BASEADDR 0x1000000 + + uint64_t address = BASEADDR; + const uint8_t code[] = { + 0x33, 0xC0, // xor eax, eax + 0x90, // nop + 0x90, // nop + 0xEB, 0x00, // jmp $+2 + 0x90, // nop + 0x90, // nop + 0x90, // nop + }; + + static const struct bb blocks[] = { + {BASEADDR, 6}, + {BASEADDR+ 6, 3}, + }; + + struct bbtest bbtest = { + .blocks = blocks, + .blocknum = 0, + }; + + +#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))); + + // trace all basic blocks + OK(uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, test_basic_blocks_hook, &bbtest, (uint64_t)1, (uint64_t)0)); + OK(uc_hook_add(uc, &trace2, UC_HOOK_BLOCK, test_basic_blocks_hook2, &bbtest, (uint64_t)1, (uint64_t)0)); + + OK(uc_emu_start(uc, address, address+sizeof(code), 0, 0)); +} + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_basic_blocks, setup32, teardown), + }; + return cmocka_run_group_tests(tests, NULL, NULL); +}