From dbdc2b371571f46a8983960d1c1e6222f7f55223 Mon Sep 17 00:00:00 2001 From: Egbert Date: Sat, 3 Oct 2015 22:46:25 -0700 Subject: [PATCH 001/149] Issue #465 hook_count_cb doesn't stop at n instructions; unit test file --- tests/unit/Makefile | 5 +- tests/unit/test_hookcounts.c | 197 +++++++++++++++++++++++++++++++++++ 2 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test_hookcounts.c diff --git a/tests/unit/Makefile b/tests/unit/Makefile index d08671d1..b99570da 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile @@ -5,7 +5,8 @@ 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_pc_change test_x86_soft_paging + test_tb_x86 test_multihook test_pc_change test_x86_soft_paging \ + test_hookcounts .PHONY: all all: ${ALL_TESTS} @@ -26,6 +27,7 @@ test: ${ALL_TESTS} ./test_multihook ./test_pc_change ./test_x86_soft_paging + ./test_hookcounts test_sanity: test_sanity.c test_x86: test_x86.c @@ -36,6 +38,7 @@ test_tb_x86: test_tb_x86.c test_multihook: test_multihook.c test_pc_change: test_pc_change.c test_x86_soft_paging: test_x86_soft_paging.c +test_hookcounts: test_hookcounts.c ${ALL_TESTS}: ${CC} ${CFLAGS} -o $@ $^ diff --git a/tests/unit/test_hookcounts.c b/tests/unit/test_hookcounts.c new file mode 100644 index 00000000..c0a5ca4a --- /dev/null +++ b/tests/unit/test_hookcounts.c @@ -0,0 +1,197 @@ +// Test hook evocation count +// +// Objective is to demonstrate finer duration control of +// emulation by counts of instruction code +// +#include "unicorn_test.h" +#include + +#define OK(x) uc_assert_success(x) + +volatile int expected_instructions = 0; +volatile int total_instructions = 0; + + +// NOTE: It would appear that this UC_HOOK_CODE is being done before the +// uc_count_fb hook. +// So, termination by uc->emu_count has not been done yet here... +static void test_code_hook(uc_engine *uc, + uint64_t address, + uint32_t size, + void *user_data) +{ + + ++total_instructions; + if (total_instructions > expected_instructions) + { + uc_emu_stop(uc); + } + +#ifdef DEBUG + printf("instruction at 0x%"PRIx64": ", address); + if (!uc_mem_read(uc, address, tmp, size)) { + uint8_t tmp[256]; + uint32_t i; + + for (i = 0; i < size; i++) { + printf("0x%x ", tmp[i]); + } + printf("\n"); + } +#endif // DEBUG +} + + +/* Called before every test to set up a new instance */ +static int setup32(void **state) +{ + uc_hook trace1; + uc_engine *uc; + + OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); + + *state = uc; + + // trace all instructions + OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, test_code_hook, NULL, 1, 0)); + + 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_hook_count(uc_engine *uc, + const uint8_t *code, + int start_offset, + int expected_instructions) +{ + +#define BASEADDR 0x1000000 +#define MEMSIZE (2 * 1024 * 1024) + + uint64_t address = BASEADDR + (expected_instructions * MEMSIZE); + total_instructions = 0; + +#undef BASEADDR + + // map a new 2MB memory for this emulation + OK(uc_mem_map(uc, address, MEMSIZE, UC_PROT_ALL)); + + // write machine code to be emulated to memory + OK(uc_mem_write(uc, address, code, expected_instructions)); + + OK(uc_emu_start(uc, + address, + address+start_offset, + 0, + expected_instructions)); + + assert_int_equal(expected_instructions, total_instructions); + + // map 2MB memory for this emulation + OK(uc_mem_unmap(uc, address, MEMSIZE)); +} + + +/* Perform fine-grain emulation control of exactly 1 instruction */ +static void test_hook_count_1(void **state) +{ + uc_engine *uc = *state; + 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 + }; + test_hook_count(uc, code, 0, 1); +} + + +/* Perform fine-grain emulation control over a range of */ +/* varied instruction steps. */ +static void test_hook_count_range(void **state) +{ + int i; + uc_engine *uc = *state; + 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 + }; + for (i = 2; i < 7; i++) + { + test_hook_count(uc, code, 1, i); + } +} + + +static void test_hook_count_end(void **state) +{ + uc_engine *uc = *state; + 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 + }; + test_hook_count(uc, code, sizeof(code)-1, 1); +} + + +static void test_hook_count_midpoint(void **state) +{ + uc_engine *uc = *state; + 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 + }; + test_hook_count(uc, code, sizeof(code)/2, 2); + test_hook_count(uc, code, 2, sizeof(code)-2); +} + + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_hook_count_1, setup32, teardown), + cmocka_unit_test_setup_teardown(test_hook_count_range, setup32, teardown), + cmocka_unit_test_setup_teardown(test_hook_count_midpoint, setup32, teardown), + cmocka_unit_test_setup_teardown(test_hook_count_end, setup32, teardown), + }; + return cmocka_run_group_tests(tests, NULL, NULL); +} + From ff66a72d7b19b47c2e609be4bf06349652bc33cb Mon Sep 17 00:00:00 2001 From: feliam Date: Wed, 9 Mar 2016 18:07:38 -0300 Subject: [PATCH 002/149] GDT/LDT/IDT/FPU access from python bingings --- bindings/python/unicorn/unicorn.py | 50 ++++++++++++++++++++++++++++-- qemu/target-i386/unicorn.c | 39 +++++++++++++++++++++++ 2 files changed, 86 insertions(+), 3 deletions(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 989d985f..28ba7e77 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -156,6 +156,23 @@ def uc_arch_supported(query): return _uc.uc_arch_supported(query) + +class uc_x86_mmr(ctypes.Structure): + '''Memory-Management Register for instructions IDTR, GDTR, LDTR, TR.''' + _fields_ = [ + ("selector", ctypes.c_uint16), # not used by GDTR and IDTR + ("base", ctypes.c_uint64), # handle 32 or 64 bit CPUs + ("limit", ctypes.c_uint32), + ("flags", ctypes.c_uint32), # not used by GDTR and IDTR + ] + +class uc_x86_float80(ctypes.Structure): + '''Float80''' + _fields_ = [ + ("mantissa", ctypes.c_uint64), + ("exponent", ctypes.c_uint16), + ] + class Uc(object): def __init__(self, arch, mode): # verify version compatibility with the core before doing anything @@ -188,7 +205,6 @@ class Uc(object): except: # _uc might be pulled from under our feet pass - # emulate from @begin, and stop when reaching address @until def emu_start(self, begin, until, timeout=0, count=0): status = _uc.uc_emu_start(self._uch, begin, until, timeout, count) @@ -205,6 +221,20 @@ class Uc(object): # return the value of a register def reg_read(self, reg_id): + if self._arch == UC_ARCH_X86: + if reg_id in [ x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]: + reg = uc_x86_mmr() + status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg)) + if status != UC_ERR_OK: + raise UcError(status) + return (reg.selector,reg.base, reg.limits, reg.flags) + if reg_id in range(x86_const.UC_X86_REG_FP0,x86_const.UC_X86_REG_FP0+8): + reg = uc_x86_float80() + status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg)) + if status != UC_ERR_OK: + raise UcError(status) + return (reg.mantissa, reg.exponent) + # read to 64bit number to be safe reg = ctypes.c_int64(0) status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg)) @@ -215,8 +245,22 @@ class Uc(object): # write to a register def reg_write(self, reg_id, value): - # convert to 64bit number to be safe - reg = ctypes.c_int64(value) + if self._arch == UC_ARCH_X86: + if reg_id in [ x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]: + assert isinstance(value, tuple) and len(value)==4 + reg = uc_x86_mmr() + reg.selector=value[0] + reg.base=value[1] + reg.limits=value[2] + reg.flags=value[3] + if reg_id in range(x86_const.UC_X86_REG_FP0, x86_const.UC_X86_REG_FP0+8): + reg = uc_x86_float80() + reg.mantissa = value[0] + reg.exponent = value[1] + else: + # convert to 64bit number to be safe + reg = ctypes.c_int64(value) + status = _uc.uc_reg_write(self._uch, reg_id, ctypes.byref(reg)) if status != UC_ERR_OK: raise UcError(status) diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 7ec2d140..3ab525c3 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -140,6 +140,25 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) { CPUState *mycpu = first_cpu; + switch(regid) { + default: + break; + case UC_X86_REG_FP0 ... UC_X86_REG_FP7: + { + floatx80 reg = X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d; + cpu_get_fp80(value, value+sizeof(uint64_t), reg); + } + break; + case UC_X86_REG_FPSW: + { + uint16_t fpus = X86_CPU(uc, mycpu)->env.fpus; + fpus = fpus & ~(7<<11); + fpus |= (X86_CPU(uc, mycpu)->env.fpstt&7)<<11; + *(uint16_t*) value = fpus; + } + break; + } + switch(uc->mode) { default: break; @@ -573,6 +592,26 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; + switch(regid) { + default: + break; + case UC_X86_REG_FP0 ... UC_X86_REG_FP7: + { + //floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper); + uint64_t mant = *(uint64_t*) value; + uint16_t upper = *(uint16_t*) (value+sizeof(uint64_t)); + X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d = cpu_set_fp80(mant, upper); + } + break; + case UC_X86_REG_FPSW: + { + uint16_t fpus = *(uint16_t*) value; + X86_CPU(uc, mycpu)->env.fpus = fpus; + X86_CPU(uc, mycpu)->env.fpstt = (fpus>>11)&7; + } + break; + } + switch(uc->mode) { default: break; From a5f2a64de52dfa1772cd8de0886292964fe32236 Mon Sep 17 00:00:00 2001 From: feliam Date: Wed, 9 Mar 2016 18:27:59 -0300 Subject: [PATCH 003/149] -spaces- --- bindings/python/unicorn/unicorn.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 28ba7e77..01cbff13 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -156,7 +156,6 @@ def uc_arch_supported(query): return _uc.uc_arch_supported(query) - class uc_x86_mmr(ctypes.Structure): '''Memory-Management Register for instructions IDTR, GDTR, LDTR, TR.''' _fields_ = [ @@ -166,6 +165,7 @@ class uc_x86_mmr(ctypes.Structure): ("flags", ctypes.c_uint32), # not used by GDTR and IDTR ] + class uc_x86_float80(ctypes.Structure): '''Float80''' _fields_ = [ @@ -173,6 +173,7 @@ class uc_x86_float80(ctypes.Structure): ("exponent", ctypes.c_uint16), ] + class Uc(object): def __init__(self, arch, mode): # verify version compatibility with the core before doing anything From 0a3799eadac6ad335551d4fb30328a9e6c802e8e Mon Sep 17 00:00:00 2001 From: feliam Date: Wed, 9 Mar 2016 19:14:33 -0300 Subject: [PATCH 004/149] FPU control word and tags --- bindings/python/unicorn/x86_const.py | 4 ++- include/unicorn/x86.h | 3 +- qemu/target-i386/unicorn.c | 52 +++++++++++++++++++++++++--- 3 files changed, 53 insertions(+), 6 deletions(-) diff --git a/bindings/python/unicorn/x86_const.py b/bindings/python/unicorn/x86_const.py index a0cf0abc..8f93c0e0 100644 --- a/bindings/python/unicorn/x86_const.py +++ b/bindings/python/unicorn/x86_const.py @@ -248,7 +248,9 @@ UC_X86_REG_IDTR = 242 UC_X86_REG_GDTR = 243 UC_X86_REG_LDTR = 244 UC_X86_REG_TR = 245 -UC_X86_REG_ENDING = 246 +UC_X86_REG_FPTAGS = 246 +UC_X86_REG_FPCW = 247 +UC_X86_REG_ENDING = 248 # X86 instructions diff --git a/include/unicorn/x86.h b/include/unicorn/x86.h index 51401eba..88559730 100644 --- a/include/unicorn/x86.h +++ b/include/unicorn/x86.h @@ -73,7 +73,8 @@ typedef enum uc_x86_reg { UC_X86_REG_R9D, UC_X86_REG_R10D, UC_X86_REG_R11D, UC_X86_REG_R12D, UC_X86_REG_R13D, UC_X86_REG_R14D, UC_X86_REG_R15D, UC_X86_REG_R8W, UC_X86_REG_R9W, UC_X86_REG_R10W, UC_X86_REG_R11W, UC_X86_REG_R12W, UC_X86_REG_R13W, UC_X86_REG_R14W, UC_X86_REG_R15W, - UC_X86_REG_IDTR, UC_X86_REG_GDTR, UC_X86_REG_LDTR, UC_X86_REG_TR, + UC_X86_REG_IDTR, UC_X86_REG_GDTR, UC_X86_REG_LDTR, UC_X86_REG_TR, UC_X86_REG_FPCW, + UC_X86_REG_FPTAG, UC_X86_REG_ENDING // <-- mark the end of the list of registers } uc_x86_reg; diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 3ab525c3..4b285f93 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -152,10 +152,42 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) case UC_X86_REG_FPSW: { uint16_t fpus = X86_CPU(uc, mycpu)->env.fpus; - fpus = fpus & ~(7<<11); - fpus |= (X86_CPU(uc, mycpu)->env.fpstt&7)<<11; + fpus = fpus & ~0x3800; + fpus |= ( X86_CPU(uc, mycpu)->env.fpstt & 0x7 ) << 11; *(uint16_t*) value = fpus; } + case UC_X86_REG_FPCW: + *(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc; + break; + case UC_X86_REG_FPTAG: + { + #define EXPD(fp) (fp.l.upper & 0x7fff) + #define MANTD(fp) (fp.l.lower) + #define MAXEXPD 0x7fff + int fptag, exp, i; + uint64_t mant; + CPU_LDoubleU tmp; + fptag = 0; + for (i = 7; i >= 0; i--) { + fptag <<= 2; + if (X86_CPU(uc, mycpu)->env.fptags[i]) { + fptag |= 3; + } else { + tmp.d = X86_CPU(uc, mycpu)->env.fpregs[i].d; + exp = EXPD(tmp); + mant = MANTD(tmp); + if (exp == 0 && mant == 0) { + /* zero */ + fptag |= 1; + } else if (exp == 0 || exp == MAXEXPD + || (mant & (1LL << 63)) == 0) { + /* NaNs, infinity, denormal */ + fptag |= 2; + } + } + } + *(uint16_t*) value = fptag; + } break; } @@ -606,10 +638,22 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) case UC_X86_REG_FPSW: { uint16_t fpus = *(uint16_t*) value; - X86_CPU(uc, mycpu)->env.fpus = fpus; - X86_CPU(uc, mycpu)->env.fpstt = (fpus>>11)&7; + X86_CPU(uc, mycpu)->env.fpus = fpus & ~0x3800; + X86_CPU(uc, mycpu)->env.fpstt = (fpus >> 11) & 0x7; } break; + case UC_X86_REG_FPCW: + *(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc; + break; + case UC_X86_REG_FPTAG: + { + int i; + uint16_t fptag = *(uint16_t*) value; + for (i = 0; i < 8; i++) { + X86_CPU(uc, mycpu)->env.fptags[i] = ((fptag & 3) == 3); + fptag >>= 2; + } + } } switch(uc->mode) { From 3038726a5b9fef12bb78b6ea5dd593c1fbe853b7 Mon Sep 17 00:00:00 2001 From: feliam Date: Wed, 9 Mar 2016 22:14:51 -0300 Subject: [PATCH 005/149] Fix --- bindings/python/unicorn/unicorn.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 01cbff13..aef9d996 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -246,6 +246,8 @@ class Uc(object): # write to a register def reg_write(self, reg_id, value): + reg = None + if self._arch == UC_ARCH_X86: if reg_id in [ x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]: assert isinstance(value, tuple) and len(value)==4 @@ -258,7 +260,8 @@ class Uc(object): reg = uc_x86_float80() reg.mantissa = value[0] reg.exponent = value[1] - else: + + if reg is None: # convert to 64bit number to be safe reg = ctypes.c_int64(value) From c5b123d2d9d86c5d0ac8ddc936b5b53cd88139d4 Mon Sep 17 00:00:00 2001 From: xorstream Date: Thu, 10 Mar 2016 14:41:11 +1100 Subject: [PATCH 006/149] Updated MSVC bindings for new and changed functions. --- bindings/msvc/unicorn.def | 3 ++ bindings/msvc/unicorn_dynload.c | 56 +++++++++++++++++++++++---------- bindings/msvc/unicorn_dynload.h | 2 +- 3 files changed, 44 insertions(+), 17 deletions(-) diff --git a/bindings/msvc/unicorn.def b/bindings/msvc/unicorn.def index c8d88b3b..d53f96a3 100644 --- a/bindings/msvc/unicorn.def +++ b/bindings/msvc/unicorn.def @@ -3,6 +3,7 @@ uc_version uc_arch_supported uc_open uc_close +uc_query uc_errno uc_strerror uc_reg_write @@ -14,5 +15,7 @@ uc_emu_stop uc_hook_add uc_hook_del uc_mem_map +uc_mem_map_ptr uc_mem_unmap uc_mem_protect +uc_mem_regions diff --git a/bindings/msvc/unicorn_dynload.c b/bindings/msvc/unicorn_dynload.c index ca9b4e2a..5db754f8 100644 --- a/bindings/msvc/unicorn_dynload.c +++ b/bindings/msvc/unicorn_dynload.c @@ -1,6 +1,6 @@ // // Dynamic loader for unicorn shared library in windows and linux. -// This was made for v0.9 of unicorn. +// This was made for v1.0 of unicorn. // Newer versions of unicorn may require changes to these files. // // Windows Notes: @@ -62,6 +62,7 @@ typedef unsigned int (*uc_version_t)(unsigned int *major, unsigned int *minor); typedef bool (*uc_arch_supported_t)(uc_arch arch); typedef uc_err (*uc_open_t)(uc_arch arch, uc_mode mode, uc_engine **uc); typedef uc_err (*uc_close_t)(uc_engine *uc); +typedef uc_err (*uc_query_t)(uc_engine *uc, uc_query_type type, size_t *result); typedef uc_err (*uc_errno_t)(uc_engine *uc); typedef const char* (*uc_strerror_t)(uc_err code); typedef uc_err (*uc_reg_write_t)(uc_engine *uc, int regid, const void *value); @@ -70,17 +71,20 @@ typedef uc_err (*uc_mem_write_t)(uc_engine *uc, uint64_t address, const void *by typedef uc_err (*uc_mem_read_t)(uc_engine *uc, uint64_t address, void *bytes, size_t size); typedef uc_err (*uc_emu_start_t)(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count); typedef uc_err (*uc_emu_stop_t)(uc_engine *uc); -typedef uc_err (*uc_hook_add_t)(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...); +typedef uc_err (*uc_hook_add_t)(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, uint64_t begin, uint64_t end, ...); typedef uc_err (*uc_hook_del_t)(uc_engine *uc, uc_hook hh); typedef uc_err (*uc_mem_map_t)(uc_engine *uc, uint64_t address, size_t size, uint32_t perms); +typedef uc_err (*uc_mem_map_ptr_t)(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr); typedef uc_err (*uc_mem_unmap_t)(uc_engine *uc, uint64_t address, size_t size); typedef uc_err (*uc_mem_protect_t)(uc_engine *uc, uint64_t address, size_t size, uint32_t perms); +typedef uc_err (*uc_mem_regions_t)(uc_engine *uc, uc_mem_region **regions, uint32_t *count); static uc_version_t gp_uc_version = NULL; static uc_arch_supported_t gp_uc_arch_supported = NULL; static uc_open_t gp_uc_open = NULL; static uc_close_t gp_uc_close = NULL; +static uc_query_t gp_uc_query = NULL; static uc_errno_t gp_uc_errno = NULL; static uc_strerror_t gp_uc_strerror = NULL; static uc_reg_write_t gp_uc_reg_write = NULL; @@ -92,8 +96,10 @@ static uc_emu_stop_t gp_uc_emu_stop = NULL; static uc_hook_add_t gp_uc_hook_add = NULL; static uc_hook_del_t gp_uc_hook_del = NULL; static uc_mem_map_t gp_uc_mem_map = NULL; +static uc_mem_map_ptr_t gp_uc_mem_map_ptr = NULL; static uc_mem_unmap_t gp_uc_mem_unmap = NULL; static uc_mem_protect_t gp_uc_mem_protect = NULL; +static uc_mem_regions_t gp_uc_mem_regions = NULL; bool uc_dyn_load(const char* path, int flags) @@ -118,6 +124,7 @@ bool uc_dyn_load(const char* path, int flags) gp_uc_arch_supported = (uc_arch_supported_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_arch_supported"); gp_uc_open = (uc_open_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_open"); gp_uc_close = (uc_close_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_close"); + gp_uc_query = (uc_query_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_query"); gp_uc_errno = (uc_errno_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_errno"); gp_uc_strerror = (uc_strerror_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_strerror"); gp_uc_reg_write = (uc_reg_write_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_reg_write"); @@ -129,8 +136,10 @@ bool uc_dyn_load(const char* path, int flags) gp_uc_hook_add = (uc_hook_add_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_hook_add"); gp_uc_hook_del = (uc_hook_del_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_hook_del"); gp_uc_mem_map = (uc_mem_map_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_map"); + gp_uc_mem_map_ptr = (uc_mem_map_ptr_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_map_ptr"); gp_uc_mem_unmap = (uc_mem_unmap_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_unmap"); gp_uc_mem_protect = (uc_mem_protect_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_protect"); + gp_uc_mem_regions = (uc_mem_regions_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_regions"); return true; } @@ -146,6 +155,7 @@ bool uc_dyn_free(void) gp_uc_arch_supported = NULL; gp_uc_open = NULL; gp_uc_close = NULL; + gp_uc_query = NULL; gp_uc_errno = NULL; gp_uc_strerror = NULL; gp_uc_reg_write = NULL; @@ -157,8 +167,10 @@ bool uc_dyn_free(void) gp_uc_hook_add = NULL; gp_uc_hook_del = NULL; gp_uc_mem_map = NULL; + gp_uc_mem_map_ptr = NULL; gp_uc_mem_unmap = NULL; gp_uc_mem_protect = NULL; + gp_uc_mem_regions = NULL; return true; } @@ -183,6 +195,11 @@ uc_err uc_close(uc_engine *uc) return gp_uc_close(uc); } +uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result) +{ + return gp_uc_query(uc, type, result); +} + uc_err uc_errno(uc_engine *uc) { return gp_uc_errno(uc); @@ -223,43 +240,40 @@ uc_err uc_emu_stop(uc_engine *uc) return gp_uc_emu_stop(uc); } -uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...) +uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, uint64_t begin, uint64_t end, ...) { va_list valist; uc_err ret = UC_ERR_OK; int id; - uint64_t begin, end; va_start(valist, user_data); switch(type) { // note this default case will capture any combinations of // UC_HOOK_MEM_*_PROT and UC_HOOK_MEM_*_UNMAPPED + // as well as any combination of + // UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE and UC_HOOK_MEM_FETCH default: case UC_HOOK_INTR: + case UC_HOOK_CODE: + case UC_HOOK_BLOCK: + // all combinations of UC_HOOK_MEM_*_PROT and UC_HOOK_MEM_*_UNMAPPED are caught by 'default' case UC_HOOK_MEM_READ_UNMAPPED: case UC_HOOK_MEM_WRITE_UNMAPPED: case UC_HOOK_MEM_FETCH_UNMAPPED: case UC_HOOK_MEM_READ_PROT: case UC_HOOK_MEM_WRITE_PROT: case UC_HOOK_MEM_FETCH_PROT: + // all combinations of read/write/fetch are caught by 'default' + case UC_HOOK_MEM_READ: + case UC_HOOK_MEM_WRITE: case UC_HOOK_MEM_FETCH: // 0 extra args - ret = gp_uc_hook_add(uc, hh, type, callback, user_data); + ret = gp_uc_hook_add(uc, hh, type, callback, user_data, begin, end); break; case UC_HOOK_INSN: // 1 extra arg id = va_arg(valist, int); - ret = gp_uc_hook_add(uc, hh, type, callback, user_data, id); - break; - case UC_HOOK_CODE: - case UC_HOOK_BLOCK: - case UC_HOOK_MEM_READ: - case UC_HOOK_MEM_WRITE: - case UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE: - // 2 extra args - begin = va_arg(valist, uint64_t); - end = va_arg(valist, uint64_t); - ret = gp_uc_hook_add(uc, hh, type, callback, user_data, begin, end); + ret = gp_uc_hook_add(uc, hh, type, callback, user_data, begin, end, id); break; } @@ -277,6 +291,11 @@ uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms) return gp_uc_mem_map(uc, address, size, perms); } +uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr) +{ + return gp_uc_mem_map_ptr(uc, address, size, perms, ptr); +} + uc_err uc_mem_unmap(uc_engine *uc, uint64_t address, size_t size) { return gp_uc_mem_unmap(uc, address, size); @@ -287,4 +306,9 @@ uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size, uint32_t per return gp_uc_mem_protect(uc, address, size, perms); } +uc_err uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count) +{ + return gp_uc_mem_regions(uc, regions, count); +} + #endif // DYNLOAD diff --git a/bindings/msvc/unicorn_dynload.h b/bindings/msvc/unicorn_dynload.h index 638f5250..2618bde5 100644 --- a/bindings/msvc/unicorn_dynload.h +++ b/bindings/msvc/unicorn_dynload.h @@ -1,6 +1,6 @@ // // Dynamic loader for unicorn shared library in windows and linux. -// This was made for v0.9 of unicorn. +// This was made for v1.0 of unicorn. // Newer versions of unicorn may require changes to these files. // // Windows Notes: From 23b3f651f910afb28a68fb1c2810d21aba9082f2 Mon Sep 17 00:00:00 2001 From: feliam Date: Thu, 10 Mar 2016 07:45:36 -0300 Subject: [PATCH 007/149] Indentation --- bindings/python/unicorn/unicorn.py | 1 + include/unicorn/x86.h | 2 +- qemu/target-i386/unicorn.c | 8 ++++---- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index aef9d996..7b592a7c 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -206,6 +206,7 @@ class Uc(object): except: # _uc might be pulled from under our feet pass + # emulate from @begin, and stop when reaching address @until def emu_start(self, begin, until, timeout=0, count=0): status = _uc.uc_emu_start(self._uch, begin, until, timeout, count) diff --git a/include/unicorn/x86.h b/include/unicorn/x86.h index 88559730..fe33c723 100644 --- a/include/unicorn/x86.h +++ b/include/unicorn/x86.h @@ -74,7 +74,7 @@ typedef enum uc_x86_reg { UC_X86_REG_R14D, UC_X86_REG_R15D, UC_X86_REG_R8W, UC_X86_REG_R9W, UC_X86_REG_R10W, UC_X86_REG_R11W, UC_X86_REG_R12W, UC_X86_REG_R13W, UC_X86_REG_R14W, UC_X86_REG_R15W, UC_X86_REG_IDTR, UC_X86_REG_GDTR, UC_X86_REG_LDTR, UC_X86_REG_TR, UC_X86_REG_FPCW, - UC_X86_REG_FPTAG, + UC_X86_REG_FPTAG, UC_X86_REG_ENDING // <-- mark the end of the list of registers } uc_x86_reg; diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 4b285f93..106266f3 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -152,7 +152,7 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) case UC_X86_REG_FPSW: { uint16_t fpus = X86_CPU(uc, mycpu)->env.fpus; - fpus = fpus & ~0x3800; + fpus = fpus & ~0x3800; fpus |= ( X86_CPU(uc, mycpu)->env.fpstt & 0x7 ) << 11; *(uint16_t*) value = fpus; } @@ -629,9 +629,8 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) break; case UC_X86_REG_FP0 ... UC_X86_REG_FP7: { - //floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper); uint64_t mant = *(uint64_t*) value; - uint16_t upper = *(uint16_t*) (value+sizeof(uint64_t)); + uint16_t upper = *(uint16_t*) (value + sizeof(uint64_t)); X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d = cpu_set_fp80(mant, upper); } break; @@ -654,7 +653,8 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) fptag >>= 2; } } - } + break; + } switch(uc->mode) { default: From 28b94d10b8ff76a2193a4ae42f6949a7f58fd4a0 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 14 Mar 2016 09:14:48 +0800 Subject: [PATCH 008/149] bindings: add X86 FPTAGS & FPCW registers after recent change in the core --- bindings/dotnet/UnicornManaged/Const/X86.fs | 4 +++- bindings/go/unicorn/x86_const.go | 4 +++- bindings/java/unicorn/X86Const.java | 4 +++- bindings/python/unicorn/x86_const.py | 4 ++-- 4 files changed, 11 insertions(+), 5 deletions(-) diff --git a/bindings/dotnet/UnicornManaged/Const/X86.fs b/bindings/dotnet/UnicornManaged/Const/X86.fs index e293d5a1..d0526f87 100644 --- a/bindings/dotnet/UnicornManaged/Const/X86.fs +++ b/bindings/dotnet/UnicornManaged/Const/X86.fs @@ -255,7 +255,9 @@ module X86 = let UC_X86_REG_GDTR = 243 let UC_X86_REG_LDTR = 244 let UC_X86_REG_TR = 245 - let UC_X86_REG_ENDING = 246 + let UC_X86_REG_FPCW = 246 + let UC_X86_REG_FPTAG = 247 + let UC_X86_REG_ENDING = 248 // X86 instructions diff --git a/bindings/go/unicorn/x86_const.go b/bindings/go/unicorn/x86_const.go index 49e2310f..ef18c08e 100644 --- a/bindings/go/unicorn/x86_const.go +++ b/bindings/go/unicorn/x86_const.go @@ -250,7 +250,9 @@ const ( X86_REG_GDTR = 243 X86_REG_LDTR = 244 X86_REG_TR = 245 - X86_REG_ENDING = 246 + X86_REG_FPCW = 246 + X86_REG_FPTAG = 247 + X86_REG_ENDING = 248 // X86 instructions diff --git a/bindings/java/unicorn/X86Const.java b/bindings/java/unicorn/X86Const.java index 9c6d93ee..7afed1f9 100644 --- a/bindings/java/unicorn/X86Const.java +++ b/bindings/java/unicorn/X86Const.java @@ -252,7 +252,9 @@ public interface X86Const { public static final int UC_X86_REG_GDTR = 243; public static final int UC_X86_REG_LDTR = 244; public static final int UC_X86_REG_TR = 245; - public static final int UC_X86_REG_ENDING = 246; + public static final int UC_X86_REG_FPCW = 246; + public static final int UC_X86_REG_FPTAG = 247; + public static final int UC_X86_REG_ENDING = 248; // X86 instructions diff --git a/bindings/python/unicorn/x86_const.py b/bindings/python/unicorn/x86_const.py index 8f93c0e0..ee5ba38f 100644 --- a/bindings/python/unicorn/x86_const.py +++ b/bindings/python/unicorn/x86_const.py @@ -248,8 +248,8 @@ UC_X86_REG_IDTR = 242 UC_X86_REG_GDTR = 243 UC_X86_REG_LDTR = 244 UC_X86_REG_TR = 245 -UC_X86_REG_FPTAGS = 246 -UC_X86_REG_FPCW = 247 +UC_X86_REG_FPCW = 246 +UC_X86_REG_FPTAG = 247 UC_X86_REG_ENDING = 248 # X86 instructions From 75e5fb466c38a0cc83dbc3826af34ee4d34477f7 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 14 Mar 2016 09:27:46 +0800 Subject: [PATCH 009/149] x86: fix writing to UC_X86_REG_FPCW --- qemu/target-i386/unicorn.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 106266f3..a3ccfe8c 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -642,7 +642,7 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) } break; case UC_X86_REG_FPCW: - *(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc; + X86_CPU(uc, mycpu)->env.fpuc = *(uint16_t *)value; break; case UC_X86_REG_FPTAG: { From 0524f34b8201cf37bc2784fcde8db8af11c0e4e5 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 14 Mar 2016 23:50:58 +0800 Subject: [PATCH 010/149] rename appveyor.yml to .appveyor.yml --- appveyor.yml => .appveyor.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename appveyor.yml => .appveyor.yml (100%) diff --git a/appveyor.yml b/.appveyor.yml similarity index 100% rename from appveyor.yml rename to .appveyor.yml From 2a9a794bffa30402819cd9873577ecc2f424288d Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Mon, 14 Mar 2016 17:44:02 -0700 Subject: [PATCH 011/149] tweak Go bindings for 32-bit --- bindings/go/unicorn/unicorn.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index 2b0e456c..be8a7348 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -120,7 +120,7 @@ func (u *uc) MemRegions() ([]*MemRegion, error) { return nil, errReturn(ucerr) } ret := make([]*MemRegion, count) - tmp := (*[1 << 30]C.struct_uc_mem_region)(unsafe.Pointer(regions))[:count] + tmp := (*[1 << 24]C.struct_uc_mem_region)(unsafe.Pointer(regions))[:count] for i, v := range tmp { ret[i] = &MemRegion{ Begin: uint64(v.begin), From b43f89566f7ec3f209a2e2862089c3d7fa36befa Mon Sep 17 00:00:00 2001 From: feliam Date: Tue, 15 Mar 2016 12:17:40 -0300 Subject: [PATCH 012/149] Bugfix --- qemu/target-i386/unicorn.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index a3ccfe8c..6d149ece 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -156,6 +156,7 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) fpus |= ( X86_CPU(uc, mycpu)->env.fpstt & 0x7 ) << 11; *(uint16_t*) value = fpus; } + break; case UC_X86_REG_FPCW: *(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc; break; From 347d86336525dd3c5a4236d86965834ebbd46240 Mon Sep 17 00:00:00 2001 From: egberts Date: Sat, 3 Oct 2015 22:46:25 -0700 Subject: [PATCH 013/149] Issue #465 hook_count_cb doesn't stop at n instructions; unit test file --- tests/unit/Makefile | 5 +- tests/unit/test_hookcounts.c | 197 +++++++++++++++++++++++++++++++++++ 2 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 tests/unit/test_hookcounts.c diff --git a/tests/unit/Makefile b/tests/unit/Makefile index d08671d1..b99570da 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile @@ -5,7 +5,8 @@ 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_pc_change test_x86_soft_paging + test_tb_x86 test_multihook test_pc_change test_x86_soft_paging \ + test_hookcounts .PHONY: all all: ${ALL_TESTS} @@ -26,6 +27,7 @@ test: ${ALL_TESTS} ./test_multihook ./test_pc_change ./test_x86_soft_paging + ./test_hookcounts test_sanity: test_sanity.c test_x86: test_x86.c @@ -36,6 +38,7 @@ test_tb_x86: test_tb_x86.c test_multihook: test_multihook.c test_pc_change: test_pc_change.c test_x86_soft_paging: test_x86_soft_paging.c +test_hookcounts: test_hookcounts.c ${ALL_TESTS}: ${CC} ${CFLAGS} -o $@ $^ diff --git a/tests/unit/test_hookcounts.c b/tests/unit/test_hookcounts.c new file mode 100644 index 00000000..c0a5ca4a --- /dev/null +++ b/tests/unit/test_hookcounts.c @@ -0,0 +1,197 @@ +// Test hook evocation count +// +// Objective is to demonstrate finer duration control of +// emulation by counts of instruction code +// +#include "unicorn_test.h" +#include + +#define OK(x) uc_assert_success(x) + +volatile int expected_instructions = 0; +volatile int total_instructions = 0; + + +// NOTE: It would appear that this UC_HOOK_CODE is being done before the +// uc_count_fb hook. +// So, termination by uc->emu_count has not been done yet here... +static void test_code_hook(uc_engine *uc, + uint64_t address, + uint32_t size, + void *user_data) +{ + + ++total_instructions; + if (total_instructions > expected_instructions) + { + uc_emu_stop(uc); + } + +#ifdef DEBUG + printf("instruction at 0x%"PRIx64": ", address); + if (!uc_mem_read(uc, address, tmp, size)) { + uint8_t tmp[256]; + uint32_t i; + + for (i = 0; i < size; i++) { + printf("0x%x ", tmp[i]); + } + printf("\n"); + } +#endif // DEBUG +} + + +/* Called before every test to set up a new instance */ +static int setup32(void **state) +{ + uc_hook trace1; + uc_engine *uc; + + OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); + + *state = uc; + + // trace all instructions + OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, test_code_hook, NULL, 1, 0)); + + 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_hook_count(uc_engine *uc, + const uint8_t *code, + int start_offset, + int expected_instructions) +{ + +#define BASEADDR 0x1000000 +#define MEMSIZE (2 * 1024 * 1024) + + uint64_t address = BASEADDR + (expected_instructions * MEMSIZE); + total_instructions = 0; + +#undef BASEADDR + + // map a new 2MB memory for this emulation + OK(uc_mem_map(uc, address, MEMSIZE, UC_PROT_ALL)); + + // write machine code to be emulated to memory + OK(uc_mem_write(uc, address, code, expected_instructions)); + + OK(uc_emu_start(uc, + address, + address+start_offset, + 0, + expected_instructions)); + + assert_int_equal(expected_instructions, total_instructions); + + // map 2MB memory for this emulation + OK(uc_mem_unmap(uc, address, MEMSIZE)); +} + + +/* Perform fine-grain emulation control of exactly 1 instruction */ +static void test_hook_count_1(void **state) +{ + uc_engine *uc = *state; + 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 + }; + test_hook_count(uc, code, 0, 1); +} + + +/* Perform fine-grain emulation control over a range of */ +/* varied instruction steps. */ +static void test_hook_count_range(void **state) +{ + int i; + uc_engine *uc = *state; + 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 + }; + for (i = 2; i < 7; i++) + { + test_hook_count(uc, code, 1, i); + } +} + + +static void test_hook_count_end(void **state) +{ + uc_engine *uc = *state; + 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 + }; + test_hook_count(uc, code, sizeof(code)-1, 1); +} + + +static void test_hook_count_midpoint(void **state) +{ + uc_engine *uc = *state; + 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 + }; + test_hook_count(uc, code, sizeof(code)/2, 2); + test_hook_count(uc, code, 2, sizeof(code)-2); +} + + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_hook_count_1, setup32, teardown), + cmocka_unit_test_setup_teardown(test_hook_count_range, setup32, teardown), + cmocka_unit_test_setup_teardown(test_hook_count_midpoint, setup32, teardown), + cmocka_unit_test_setup_teardown(test_hook_count_end, setup32, teardown), + }; + return cmocka_run_group_tests(tests, NULL, NULL); +} + From 036763d6aec6a725930989090f47049471d173fa Mon Sep 17 00:00:00 2001 From: farmdve Date: Fri, 8 Jan 2016 01:41:45 +0200 Subject: [PATCH 014/149] Fix memory leaks as reported by DrMemory and Valgrind. ARM and probably the rest of the arches have significant memory leaks as they have no release interface. Additionally, DrMemory does not have 64-bit support and thus I can't test the 64-bit version under Windows. Under Linux valgrind supports both 32-bit and 64-bit but there are different macros and code for Linux and Windows. --- include/uc_priv.h | 2 ++ qemu/aarch64.h | 2 -- qemu/arm.h | 2 -- qemu/cpus.c | 12 ++++++++++- qemu/header_gen.py | 2 -- qemu/include/qemu/thread.h | 2 +- qemu/m68k.h | 2 -- qemu/main-loop.c | 3 +++ qemu/memory.c | 14 +++++++++--- qemu/mips.h | 2 -- qemu/mips64.h | 2 -- qemu/mips64el.h | 2 -- qemu/mipsel.h | 2 -- qemu/powerpc.h | 2 -- qemu/sparc.h | 2 -- qemu/sparc64.h | 2 -- qemu/unicorn_common.h | 40 +++++++++++++++++++++++++++++++++++ qemu/util/qemu-thread-posix.c | 2 +- qemu/util/qemu-thread-win32.c | 4 +++- qemu/vl.c | 19 ++++++++++------- qemu/x86_64.h | 2 -- uc.c | 8 ++----- 22 files changed, 85 insertions(+), 45 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index 5cdf6557..32616ae0 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -130,10 +130,12 @@ struct uc_struct { QemuMutex flat_view_mutex; QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners; QTAILQ_HEAD(, AddressSpace) address_spaces; + MachineState *machine_state; // qom/object.c GHashTable *type_table; Type type_interface; Object *root; + Object *owner; bool enumerating_types; // util/module.c ModuleTypeList init_type_list[MODULE_INIT_MAX]; diff --git a/qemu/aarch64.h b/qemu/aarch64.h index 2deac84f..e368bee4 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -2414,7 +2414,6 @@ #define qemu_clock_get_us qemu_clock_get_us_aarch64 #define qemu_clock_ptr qemu_clock_ptr_aarch64 #define qemu_clocks qemu_clocks_aarch64 -#define qemu_cond_destroy qemu_cond_destroy_aarch64 #define qemu_cpu_is_self qemu_cpu_is_self_aarch64 #define qemu_cpu_kick_thread qemu_cpu_kick_thread_aarch64 #define qemu_daemon qemu_daemon_aarch64 @@ -2442,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_aarch64 #define qemu_loglevel_mask qemu_loglevel_mask_aarch64 #define qemu_log_vprintf qemu_log_vprintf_aarch64 -#define qemu_mutex_destroy qemu_mutex_destroy_aarch64 #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_aarch64 #define qemu_mutex_trylock qemu_mutex_trylock_aarch64 #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_aarch64 diff --git a/qemu/arm.h b/qemu/arm.h index a5ae3a38..09b8a147 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -2414,7 +2414,6 @@ #define qemu_clock_get_us qemu_clock_get_us_arm #define qemu_clock_ptr qemu_clock_ptr_arm #define qemu_clocks qemu_clocks_arm -#define qemu_cond_destroy qemu_cond_destroy_arm #define qemu_cpu_is_self qemu_cpu_is_self_arm #define qemu_cpu_kick_thread qemu_cpu_kick_thread_arm #define qemu_daemon qemu_daemon_arm @@ -2442,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_arm #define qemu_loglevel_mask qemu_loglevel_mask_arm #define qemu_log_vprintf qemu_log_vprintf_arm -#define qemu_mutex_destroy qemu_mutex_destroy_arm #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_arm #define qemu_mutex_trylock qemu_mutex_trylock_arm #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_arm diff --git a/qemu/cpus.c b/qemu/cpus.c index 98ee07c1..a0e9435f 100644 --- a/qemu/cpus.c +++ b/qemu/cpus.c @@ -28,6 +28,7 @@ #include "config-host.h" #include "sysemu/sysemu.h" #include "sysemu/cpus.h" +#include "qemu/thread.h" #include "exec/address-spaces.h" // debug, can be removed later @@ -76,7 +77,9 @@ void pause_all_vcpus(struct uc_struct *uc) CPUState *cpu; CPU_FOREACH(cpu) { - qemu_thread_join(cpu->thread); // qq: fix qemu_thread_join() to work for instance + qemu_thread_join(uc, cpu->thread); // qq: fix qemu_thread_join() to work for instance + free(cpu->thread); + cpu->thread = NULL; } } @@ -164,6 +167,13 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) CPU_FOREACH(cpu) { cpu->thread_id = 0; cpu->created = false; + qemu_cond_destroy(cpu->halt_cond); + free(cpu->halt_cond); +#ifdef _WIN32 + if(cpu->hThread) + CloseHandle(cpu->hThread); +#endif + cpu->halt_cond = NULL; } qemu_mutex_unlock(&uc->qemu_global_mutex); diff --git a/qemu/header_gen.py b/qemu/header_gen.py index d889247d..0616d1de 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -2420,7 +2420,6 @@ symbols = ( 'qemu_clock_get_us', 'qemu_clock_ptr', 'qemu_clocks', - 'qemu_cond_destroy', 'qemu_cpu_is_self', 'qemu_cpu_kick_thread', 'qemu_daemon', @@ -2448,7 +2447,6 @@ symbols = ( 'qemu_log_flush', 'qemu_loglevel_mask', 'qemu_log_vprintf', - 'qemu_mutex_destroy', 'qemu_mutex_lock_ramlist', 'qemu_mutex_trylock', 'qemu_mutex_unlock_ramlist', diff --git a/qemu/include/qemu/thread.h b/qemu/include/qemu/thread.h index 2a402673..d8f477d7 100644 --- a/qemu/include/qemu/thread.h +++ b/qemu/include/qemu/thread.h @@ -57,7 +57,7 @@ struct uc_struct; int qemu_thread_create(struct uc_struct *uc, QemuThread *thread, const char *name, void *(*start_routine)(void *), void *arg, int mode); -void *qemu_thread_join(QemuThread *thread); +void *qemu_thread_join(struct uc_struct *uc, QemuThread *thread); void qemu_thread_get_self(struct uc_struct *uc, QemuThread *thread); bool qemu_thread_is_self(QemuThread *thread); void qemu_thread_exit(struct uc_struct *uc, void *retval); diff --git a/qemu/m68k.h b/qemu/m68k.h index f1a6712f..7591ff9a 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -2414,7 +2414,6 @@ #define qemu_clock_get_us qemu_clock_get_us_m68k #define qemu_clock_ptr qemu_clock_ptr_m68k #define qemu_clocks qemu_clocks_m68k -#define qemu_cond_destroy qemu_cond_destroy_m68k #define qemu_cpu_is_self qemu_cpu_is_self_m68k #define qemu_cpu_kick_thread qemu_cpu_kick_thread_m68k #define qemu_daemon qemu_daemon_m68k @@ -2442,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_m68k #define qemu_loglevel_mask qemu_loglevel_mask_m68k #define qemu_log_vprintf qemu_log_vprintf_m68k -#define qemu_mutex_destroy qemu_mutex_destroy_m68k #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_m68k #define qemu_mutex_trylock qemu_mutex_trylock_m68k #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_m68k diff --git a/qemu/main-loop.c b/qemu/main-loop.c index bb7c3d02..9d7d6290 100644 --- a/qemu/main-loop.c +++ b/qemu/main-loop.c @@ -90,6 +90,9 @@ static void qemu_cpu_kick_thread(CPUState *cpu) GetLastError()); exit(1); } + + CloseHandle(cpu->hThread); + cpu->hThread = 0; } #endif } diff --git a/qemu/memory.c b/qemu/memory.c index 26683230..c7b709ee 100644 --- a/qemu/memory.c +++ b/qemu/memory.c @@ -70,6 +70,7 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) { int i; target_ulong addr; + Object *obj; // Make sure all pages associated with the MemoryRegion are flushed // Only need to do this if we are in a running state @@ -87,8 +88,12 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) //shift remainder of array down over deleted pointer memcpy(&uc->mapped_blocks[i], &uc->mapped_blocks[i + 1], sizeof(MemoryRegion*) * (uc->mapped_block_count - i)); mr->destructor(mr); - g_free((char *)mr->name); + obj = OBJECT(mr); + obj->ref = 1; + obj->free = g_free; g_free(mr->ioeventfds); + g_free((char *)mr->name); + mr->name = NULL; break; } } @@ -97,6 +102,7 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) int memory_free(struct uc_struct *uc) { MemoryRegion *mr; + Object *obj; int i; get_system_memory(uc)->enabled = false; @@ -105,9 +111,10 @@ int memory_free(struct uc_struct *uc) mr->enabled = false; memory_region_del_subregion(get_system_memory(uc), mr); mr->destructor(mr); - g_free((char *)mr->name); + obj = OBJECT(mr); + obj->ref = 1; + obj->free = g_free; g_free(mr->ioeventfds); - g_free(mr); } return 0; @@ -948,6 +955,7 @@ void memory_region_init(struct uc_struct *uc, MemoryRegion *mr, { if (!owner) { owner = qdev_get_machine(uc); + uc->owner = owner; } object_initialize(uc, mr, sizeof(*mr), TYPE_MEMORY_REGION); diff --git a/qemu/mips.h b/qemu/mips.h index ed7e86d1..d50d7fe1 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -2414,7 +2414,6 @@ #define qemu_clock_get_us qemu_clock_get_us_mips #define qemu_clock_ptr qemu_clock_ptr_mips #define qemu_clocks qemu_clocks_mips -#define qemu_cond_destroy qemu_cond_destroy_mips #define qemu_cpu_is_self qemu_cpu_is_self_mips #define qemu_cpu_kick_thread qemu_cpu_kick_thread_mips #define qemu_daemon qemu_daemon_mips @@ -2442,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_mips #define qemu_loglevel_mask qemu_loglevel_mask_mips #define qemu_log_vprintf qemu_log_vprintf_mips -#define qemu_mutex_destroy qemu_mutex_destroy_mips #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_mips #define qemu_mutex_trylock qemu_mutex_trylock_mips #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index 96ff3baa..d62f4ee6 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -2414,7 +2414,6 @@ #define qemu_clock_get_us qemu_clock_get_us_mips64 #define qemu_clock_ptr qemu_clock_ptr_mips64 #define qemu_clocks qemu_clocks_mips64 -#define qemu_cond_destroy qemu_cond_destroy_mips64 #define qemu_cpu_is_self qemu_cpu_is_self_mips64 #define qemu_cpu_kick_thread qemu_cpu_kick_thread_mips64 #define qemu_daemon qemu_daemon_mips64 @@ -2442,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_mips64 #define qemu_loglevel_mask qemu_loglevel_mask_mips64 #define qemu_log_vprintf qemu_log_vprintf_mips64 -#define qemu_mutex_destroy qemu_mutex_destroy_mips64 #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_mips64 #define qemu_mutex_trylock qemu_mutex_trylock_mips64 #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index 60315919..8193f24b 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -2414,7 +2414,6 @@ #define qemu_clock_get_us qemu_clock_get_us_mips64el #define qemu_clock_ptr qemu_clock_ptr_mips64el #define qemu_clocks qemu_clocks_mips64el -#define qemu_cond_destroy qemu_cond_destroy_mips64el #define qemu_cpu_is_self qemu_cpu_is_self_mips64el #define qemu_cpu_kick_thread qemu_cpu_kick_thread_mips64el #define qemu_daemon qemu_daemon_mips64el @@ -2442,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_mips64el #define qemu_loglevel_mask qemu_loglevel_mask_mips64el #define qemu_log_vprintf qemu_log_vprintf_mips64el -#define qemu_mutex_destroy qemu_mutex_destroy_mips64el #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_mips64el #define qemu_mutex_trylock qemu_mutex_trylock_mips64el #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 54c454f8..02a39df5 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -2414,7 +2414,6 @@ #define qemu_clock_get_us qemu_clock_get_us_mipsel #define qemu_clock_ptr qemu_clock_ptr_mipsel #define qemu_clocks qemu_clocks_mipsel -#define qemu_cond_destroy qemu_cond_destroy_mipsel #define qemu_cpu_is_self qemu_cpu_is_self_mipsel #define qemu_cpu_kick_thread qemu_cpu_kick_thread_mipsel #define qemu_daemon qemu_daemon_mipsel @@ -2442,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_mipsel #define qemu_loglevel_mask qemu_loglevel_mask_mipsel #define qemu_log_vprintf qemu_log_vprintf_mipsel -#define qemu_mutex_destroy qemu_mutex_destroy_mipsel #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_mipsel #define qemu_mutex_trylock qemu_mutex_trylock_mipsel #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_mipsel diff --git a/qemu/powerpc.h b/qemu/powerpc.h index 7cd2c00d..cb7a046c 100644 --- a/qemu/powerpc.h +++ b/qemu/powerpc.h @@ -2414,7 +2414,6 @@ #define qemu_clock_get_us qemu_clock_get_us_powerpc #define qemu_clock_ptr qemu_clock_ptr_powerpc #define qemu_clocks qemu_clocks_powerpc -#define qemu_cond_destroy qemu_cond_destroy_powerpc #define qemu_cpu_is_self qemu_cpu_is_self_powerpc #define qemu_cpu_kick_thread qemu_cpu_kick_thread_powerpc #define qemu_daemon qemu_daemon_powerpc @@ -2442,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_powerpc #define qemu_loglevel_mask qemu_loglevel_mask_powerpc #define qemu_log_vprintf qemu_log_vprintf_powerpc -#define qemu_mutex_destroy qemu_mutex_destroy_powerpc #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_powerpc #define qemu_mutex_trylock qemu_mutex_trylock_powerpc #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_powerpc diff --git a/qemu/sparc.h b/qemu/sparc.h index c30dd375..85e042e8 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -2414,7 +2414,6 @@ #define qemu_clock_get_us qemu_clock_get_us_sparc #define qemu_clock_ptr qemu_clock_ptr_sparc #define qemu_clocks qemu_clocks_sparc -#define qemu_cond_destroy qemu_cond_destroy_sparc #define qemu_cpu_is_self qemu_cpu_is_self_sparc #define qemu_cpu_kick_thread qemu_cpu_kick_thread_sparc #define qemu_daemon qemu_daemon_sparc @@ -2442,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_sparc #define qemu_loglevel_mask qemu_loglevel_mask_sparc #define qemu_log_vprintf qemu_log_vprintf_sparc -#define qemu_mutex_destroy qemu_mutex_destroy_sparc #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_sparc #define qemu_mutex_trylock qemu_mutex_trylock_sparc #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index c7824ebf..a08c42e1 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -2414,7 +2414,6 @@ #define qemu_clock_get_us qemu_clock_get_us_sparc64 #define qemu_clock_ptr qemu_clock_ptr_sparc64 #define qemu_clocks qemu_clocks_sparc64 -#define qemu_cond_destroy qemu_cond_destroy_sparc64 #define qemu_cpu_is_self qemu_cpu_is_self_sparc64 #define qemu_cpu_kick_thread qemu_cpu_kick_thread_sparc64 #define qemu_daemon qemu_daemon_sparc64 @@ -2442,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_sparc64 #define qemu_loglevel_mask qemu_loglevel_mask_sparc64 #define qemu_log_vprintf qemu_log_vprintf_sparc64 -#define qemu_mutex_destroy qemu_mutex_destroy_sparc64 #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_sparc64 #define qemu_mutex_trylock qemu_mutex_trylock_sparc64 #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_sparc64 diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h index 2df9ccef..a09253d3 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -35,6 +35,7 @@ static void release_common(void *t) { TCGContext *s = (TCGContext *)t; struct uc_struct* uc = s->uc; + CPUState *cpu; // Clean TCG. TCGOpDef* def = &s->tcg_op_defs[0]; @@ -55,9 +56,48 @@ static void release_common(void *t) memory_free(uc); // Clean CPU. + CPU_FOREACH(cpu) { + g_free(cpu->tcg_as_listener); + g_free(cpu->thread); + g_free(cpu->halt_cond); + } + + OBJECT(uc->machine_state->accelerator)->ref = 1; + OBJECT(uc->machine_state)->ref = 1; + OBJECT(uc->owner)->ref = 1; + OBJECT(uc->root)->ref = 1; + + object_unref(uc, OBJECT(uc->machine_state->accelerator)); + object_unref(uc, OBJECT(uc->machine_state)); object_unref(uc, uc->cpu); + object_unref(uc, OBJECT(&uc->io_mem_notdirty)); + object_unref(uc, OBJECT(&uc->io_mem_unassigned)); + object_unref(uc, OBJECT(&uc->io_mem_rom)); + object_unref(uc, OBJECT(uc->root)); g_hash_table_foreach(uc->type_table, free_table, uc); + g_free(uc->system_memory); + + if(uc->qemu_thread_data) + free(uc->qemu_thread_data); + +#if TCG_TARGET_REG_BITS == 32 + for(int i = 0; i < s->nb_globals; i++) + { + TCGTemp *ts = &s->temps[i]; + if(ts->base_type == TCG_TYPE_I64) + { + if(ts->name && ((strcmp(ts->name+(strlen(ts->name)-2), "_0") == 0) || (strcmp(ts->name+(strlen(ts->name)-2), "_1") == 0))) + { + free((void *)ts->name); + } + } + } +#endif + + qemu_mutex_destroy(&uc->qemu_global_mutex); + qemu_cond_destroy(&uc->qemu_cpu_cond); + // Clean cache. tb_cleanup(uc); } diff --git a/qemu/util/qemu-thread-posix.c b/qemu/util/qemu-thread-posix.c index 26cba2da..a250044f 100644 --- a/qemu/util/qemu-thread-posix.c +++ b/qemu/util/qemu-thread-posix.c @@ -441,7 +441,7 @@ void qemu_thread_exit(struct uc_struct *uc, void *retval) pthread_exit(retval); } -void *qemu_thread_join(QemuThread *thread) +void *qemu_thread_join(struct uc_struct *uc, QemuThread *thread) { int err; void *ret; diff --git a/qemu/util/qemu-thread-win32.c b/qemu/util/qemu-thread-win32.c index 2c2cf4ad..4732731d 100644 --- a/qemu/util/qemu-thread-win32.c +++ b/qemu/util/qemu-thread-win32.c @@ -276,6 +276,7 @@ static unsigned __stdcall win32_start_routine(void *arg) void *thread_arg = data->arg; if (data->mode == QEMU_THREAD_DETACHED) { + data->uc->qemu_thread_data = NULL; g_free(data); data = NULL; } @@ -297,7 +298,7 @@ void qemu_thread_exit(struct uc_struct *uc, void *arg) _endthreadex(0); } -void *qemu_thread_join(QemuThread *thread) +void *qemu_thread_join(struct uc_struct *uc, QemuThread *thread) { QemuThreadData *data; void *ret; @@ -322,6 +323,7 @@ void *qemu_thread_join(QemuThread *thread) ret = data->ret; assert(data->mode != QEMU_THREAD_DETACHED); DeleteCriticalSection(&data->cs); + uc->qemu_thread_data = NULL; g_free(data); return ret; } diff --git a/qemu/vl.c b/qemu/vl.c index caf6686f..34b0f40a 100644 --- a/qemu/vl.c +++ b/qemu/vl.c @@ -107,15 +107,18 @@ int machine_initialize(struct uc_struct *uc) module_call_init(uc, MODULE_INIT_MACHINE); // this will auto initialize all register objects above. machine_class = find_default_machine(uc, uc->arch); - if (machine_class == NULL) { - //fprintf(stderr, "No machine specified, and there is no default.\n" - // "Use -machine help to list supported machines!\n"); - return -2; + if(!uc->machine_state) + { + if (machine_class == NULL) { + //fprintf(stderr, "No machine specified, and there is no default.\n" + // "Use -machine help to list supported machines!\n"); + return -2; + } + + current_machine = MACHINE(uc, object_new(uc, object_class_get_name( + OBJECT_CLASS(machine_class)))); + uc->machine_state = current_machine; } - - current_machine = MACHINE(uc, object_new(uc, object_class_get_name( - OBJECT_CLASS(machine_class)))); - current_machine->uc = uc; uc->cpu_exec_init_all(uc); diff --git a/qemu/x86_64.h b/qemu/x86_64.h index 340e4e08..882a7b0d 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -2414,7 +2414,6 @@ #define qemu_clock_get_us qemu_clock_get_us_x86_64 #define qemu_clock_ptr qemu_clock_ptr_x86_64 #define qemu_clocks qemu_clocks_x86_64 -#define qemu_cond_destroy qemu_cond_destroy_x86_64 #define qemu_cpu_is_self qemu_cpu_is_self_x86_64 #define qemu_cpu_kick_thread qemu_cpu_kick_thread_x86_64 #define qemu_daemon qemu_daemon_x86_64 @@ -2442,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_x86_64 #define qemu_loglevel_mask qemu_loglevel_mask_x86_64 #define qemu_log_vprintf qemu_log_vprintf_x86_64 -#define qemu_mutex_destroy qemu_mutex_destroy_x86_64 #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_x86_64 #define qemu_mutex_trylock qemu_mutex_trylock_x86_64 #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_x86_64 diff --git a/uc.c b/uc.c index 5d6f5f2c..14290e8e 100644 --- a/uc.c +++ b/uc.c @@ -263,9 +263,7 @@ uc_err uc_close(uc_engine *uc) if (uc->release) uc->release(uc->tcg_ctx); -#ifndef _WIN32 free(uc->l1_map); -#endif if (uc->bounce.buffer) { free(uc->bounce.buffer); @@ -273,8 +271,6 @@ uc_err uc_close(uc_engine *uc) g_free(uc->tcg_ctx); - free((void*) uc->system_memory->name); - g_free(uc->system_memory); g_hash_table_destroy(uc->type_table); for (i = 0; i < DIRTY_MEMORY_NUM; i++) { @@ -282,7 +278,7 @@ uc_err uc_close(uc_engine *uc) } // TODO: remove uc->root (created with object_new()) - uc->root->free(uc->root); + //uc->root->free(uc->root); free(uc->hook_callbacks); @@ -524,7 +520,7 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time if (timeout) { // wait for the timer to finish - qemu_thread_join(&uc->timer); + qemu_thread_join(uc, &uc->timer); } return uc->invalid_error; From 580bc7b56afce3318120a391c155481246cfc729 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 10 Jan 2016 23:10:00 +0800 Subject: [PATCH 015/149] cleanup --- qemu/cpus.c | 15 ++------------- qemu/unicorn_common.h | 12 +++++------- qemu/vl.c | 3 +-- uc.c | 3 --- 4 files changed, 8 insertions(+), 25 deletions(-) diff --git a/qemu/cpus.c b/qemu/cpus.c index a0e9435f..68090a9b 100644 --- a/qemu/cpus.c +++ b/qemu/cpus.c @@ -77,7 +77,7 @@ void pause_all_vcpus(struct uc_struct *uc) CPUState *cpu; CPU_FOREACH(cpu) { - qemu_thread_join(uc, cpu->thread); // qq: fix qemu_thread_join() to work for instance + qemu_thread_join(uc, cpu->thread); free(cpu->thread); cpu->thread = NULL; } @@ -149,17 +149,6 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) } while (1) { -#if 0 - int count = 0; - if (count < 10) { - count++; - unsigned int eip = X86_CPU(mycpu)->env.eip; - printf(">>> current EIP = %x\n", eip); - printf(">>> ECX = %x\n", (unsigned int)X86_CPU(mycpu)->env.regs[R_ECX]); - printf(">>> EDX = %x\n", (unsigned int)X86_CPU(mycpu)->env.regs[R_EDX]); - } -#endif - if (tcg_exec_all(uc)) break; } @@ -170,7 +159,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) qemu_cond_destroy(cpu->halt_cond); free(cpu->halt_cond); #ifdef _WIN32 - if(cpu->hThread) + if (cpu->hThread) CloseHandle(cpu->hThread); #endif cpu->halt_cond = NULL; diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h index a09253d3..adccbe01 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -78,17 +78,15 @@ static void release_common(void *t) g_free(uc->system_memory); - if(uc->qemu_thread_data) + if (uc->qemu_thread_data) free(uc->qemu_thread_data); #if TCG_TARGET_REG_BITS == 32 - for(int i = 0; i < s->nb_globals; i++) - { + for(int i = 0; i < s->nb_globals; i++) { TCGTemp *ts = &s->temps[i]; - if(ts->base_type == TCG_TYPE_I64) - { - if(ts->name && ((strcmp(ts->name+(strlen(ts->name)-2), "_0") == 0) || (strcmp(ts->name+(strlen(ts->name)-2), "_1") == 0))) - { + if (ts->base_type == TCG_TYPE_I64) { + if (ts->name && ((strcmp(ts->name+(strlen(ts->name)-2), "_0") == 0) || + (strcmp(ts->name+(strlen(ts->name)-2), "_1") == 0))) { free((void *)ts->name); } } diff --git a/qemu/vl.c b/qemu/vl.c index 34b0f40a..7cbfb065 100644 --- a/qemu/vl.c +++ b/qemu/vl.c @@ -107,8 +107,7 @@ int machine_initialize(struct uc_struct *uc) module_call_init(uc, MODULE_INIT_MACHINE); // this will auto initialize all register objects above. machine_class = find_default_machine(uc, uc->arch); - if(!uc->machine_state) - { + if (!uc->machine_state) { if (machine_class == NULL) { //fprintf(stderr, "No machine specified, and there is no default.\n" // "Use -machine help to list supported machines!\n"); diff --git a/uc.c b/uc.c index 14290e8e..04ae8dea 100644 --- a/uc.c +++ b/uc.c @@ -277,9 +277,6 @@ uc_err uc_close(uc_engine *uc) free(uc->ram_list.dirty_memory[i]); } - // TODO: remove uc->root (created with object_new()) - //uc->root->free(uc->root); - free(uc->hook_callbacks); free(uc->mapped_blocks); From cd6c98f5dfc0e336b7951803f08b73f5c454454d Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 10 Jan 2016 23:25:05 +0800 Subject: [PATCH 016/149] sample: make hook_out() of sample_x86.c more deterministic --- samples/sample_x86.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/samples/sample_x86.c b/samples/sample_x86.c index c57043d2..b6d55401 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -148,7 +148,7 @@ static uint32_t hook_in(uc_engine *uc, uint32_t port, int size, void *user_data) // callback for OUT instruction (X86). static void hook_out(uc_engine *uc, uint32_t port, int size, uint32_t value, void *user_data) { - uint32_t tmp; + uint32_t tmp = 0; uint32_t eip; uc_reg_read(uc, UC_X86_REG_EIP, &eip); @@ -605,6 +605,7 @@ static void test_i386_inout(void) uc_err err; uc_hook trace1, trace2, trace3, trace4; + int r_eax = 0x1234; // EAX register int r_ecx = 0x6789; // ECX register From a0aa26d6ee21beeec472b957fc881688ac3819f1 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 10 Jan 2016 23:34:36 +0800 Subject: [PATCH 017/149] c89 --- qemu/target-i386/unicorn.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 2280d564..3ac5d22f 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -26,9 +26,11 @@ void x86_release(void *ctx); void x86_release(void *ctx) { - release_common(ctx); + int i; TCGContext *s = (TCGContext *) ctx; + release_common(ctx); + // arch specific g_free(s->cpu_A0); g_free(s->cpu_T[0]); @@ -40,7 +42,6 @@ void x86_release(void *ctx) g_free(s->cpu_cc_src); g_free(s->cpu_cc_src2); - int i; for (i = 0; i < CPU_NB_REGS; ++i) { g_free(s->cpu_regs[i]); } From 32bca0bd02dd3904e7c96c8918cce69dcdc67371 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 10 Jan 2016 23:45:02 +0800 Subject: [PATCH 018/149] regress: fix some compilation warnings on printf format --- tests/regress/mips_branch_likely_issue.c | 2 +- tests/regress/mips_delay_slot_code_hook.c | 2 +- tests/regress/threaded_emu_start.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/regress/mips_branch_likely_issue.c b/tests/regress/mips_branch_likely_issue.c index 84f49cdc..3e94851b 100644 --- a/tests/regress/mips_branch_likely_issue.c +++ b/tests/regress/mips_branch_likely_issue.c @@ -61,7 +61,7 @@ bool test2_delayslot_hooked = false; // This hook is used to show that code is executing in the emulator. static void mips_codehook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { - printf("Test %d Executing: %llX\n", test_num, address); + printf("Test %d Executing: %"PRIx64"\n", test_num, address); if( test_num == 1 && address == 0x100010 ) { printf("Delay slot hook called!\n"); diff --git a/tests/regress/mips_delay_slot_code_hook.c b/tests/regress/mips_delay_slot_code_hook.c index 905cad8d..e1fbc734 100644 --- a/tests/regress/mips_delay_slot_code_hook.c +++ b/tests/regress/mips_delay_slot_code_hook.c @@ -59,7 +59,7 @@ static void mips_codehook(uc_engine *uc, uint64_t address, uint32_t size, void * printf("\nloop %d:\n", loop_count); loop_count++; } - printf("Code: %llX\n", address); + printf("Code: %"PRIx64"\n", address); } diff --git a/tests/regress/threaded_emu_start.c b/tests/regress/threaded_emu_start.c index 9a5a2fa9..8c6dfe5f 100644 --- a/tests/regress/threaded_emu_start.c +++ b/tests/regress/threaded_emu_start.c @@ -65,7 +65,7 @@ int loop_count = 0; // This hook is used to show that code is executing in the emulator. static void mips_codehook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { - printf("Code: %llX\n", address); + printf("Code: %"PRIx64"\n", address); } From ec4a47fc199b7c10c22de94f201bb3985ce8ba66 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 10 Jan 2016 23:55:19 +0800 Subject: [PATCH 019/149] regress: fix 1 more compilation warning on printf format --- tests/regress/emu_stop_in_hook_overrun.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/regress/emu_stop_in_hook_overrun.c b/tests/regress/emu_stop_in_hook_overrun.c index 6c18c74d..9bd67b6a 100644 --- a/tests/regress/emu_stop_in_hook_overrun.c +++ b/tests/regress/emu_stop_in_hook_overrun.c @@ -47,10 +47,10 @@ bool test_passed_ok = false; // This hook is used to show that code is executing in the emulator. static void mips_codehook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { - printf("Executing: %llX\n", address); + printf("Executing: %"PRIx64"\n", address); if( address == 0x100008 ) { - printf("Stopping at: %llX\n", address); + printf("Stopping at: %"PRIx64"\n", address); uc_emu_stop(uc); } } From 2a269acac1158794f8515f1d7e92fd9efb96f068 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 10 Jan 2016 23:56:14 +0800 Subject: [PATCH 020/149] regress: add memleak_xxx.c to test memleak issue --- .gitignore | 7 + tests/regress/Makefile | 7 + tests/regress/memleak_arm.c | 178 ++++++++++++++++++++ tests/regress/memleak_arm64.c | 122 ++++++++++++++ tests/regress/memleak_m68k.c | 185 ++++++++++++++++++++ tests/regress/memleak_mips.c | 171 +++++++++++++++++++ tests/regress/memleak_sparc.c | 125 ++++++++++++++ tests/regress/memleak_x86.c | 306 ++++++++++++++++++++++++++++++++++ 8 files changed, 1101 insertions(+) create mode 100644 tests/regress/memleak_arm.c create mode 100644 tests/regress/memleak_arm64.c create mode 100644 tests/regress/memleak_m68k.c create mode 100644 tests/regress/memleak_mips.c create mode 100644 tests/regress/memleak_sparc.c create mode 100644 tests/regress/memleak_x86.c diff --git a/.gitignore b/.gitignore index 4578b7dc..b184113c 100644 --- a/.gitignore +++ b/.gitignore @@ -132,6 +132,13 @@ rw_hookstack hook_extrainvoke sysenter_hook_x86 +memleak_x86 +memleak_arm +memleak_arm64 +memleak_mips +memleak_m68k +memleak_sparc + ################# ## Visual Studio diff --git a/tests/regress/Makefile b/tests/regress/Makefile index 3f1d59a5..388b0b12 100644 --- a/tests/regress/Makefile +++ b/tests/regress/Makefile @@ -37,6 +37,13 @@ TESTS += mips_branch_likely_issue TESTS += hook_extrainvoke TESTS += sysenter_hook_x86 +TESTS += memleak_x86 +TESTS += memleak_arm +TESTS += memleak_arm64 +TESTS += memleak_mips +TESTS += memleak_m68k +TESTS += memleak_sparc + all: $(TESTS) clean: diff --git a/tests/regress/memleak_arm.c b/tests/regress/memleak_arm.c new file mode 100644 index 00000000..21430795 --- /dev/null +++ b/tests/regress/memleak_arm.c @@ -0,0 +1,178 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh, 2015 */ + +/* Sample code to demonstrate how to emulate ARM code */ + +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include "unicorn_dynload.h" +#else // DYNLOAD +#include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER + + +// code to be emulated +#define ARM_CODE "\x37\x00\xa0\xe3\x03\x10\x42\xe0" // mov r0, #0x37; sub r1, r2, r3 +#define THUMB_CODE "\x83\xb0" // sub sp, #0xc + +// memory address where emulation starts +#define ADDRESS 0x10000 + +static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); +} + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); +} + +static void test_arm(void) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1, trace2; + + int r0 = 0x1234; // R0 register + int r2 = 0x6789; // R1 register + int r3 = 0x3333; // R2 register + int r1; // R1 register + + printf("Emulate ARM code\n"); + + // Initialize emulator in ARM mode + err = uc_open(UC_ARCH_ARM, UC_MODE_ARM, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u (%s)\n", + err, uc_strerror(err)); + return; + } + + // map 2MB memory for this emulation + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc_mem_write(uc, ADDRESS, ARM_CODE, sizeof(ARM_CODE) - 1); + + // initialize machine registers + uc_reg_write(uc, UC_ARM_REG_R0, &r0); + uc_reg_write(uc, UC_ARM_REG_R2, &r2); + uc_reg_write(uc, UC_ARM_REG_R3, &r3); + + // tracing all basic blocks with customized callback + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + + // tracing one instruction at ADDRESS with customized callback + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned: %u\n", err); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_ARM_REG_R0, &r0); + uc_reg_read(uc, UC_ARM_REG_R1, &r1); + printf(">>> R0 = 0x%x\n", r0); + printf(">>> R1 = 0x%x\n", r1); + + uc_close(uc); +} + +static void test_thumb(void) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1, trace2; + + int sp = 0x1234; // R0 register + + printf("Emulate THUMB code\n"); + + // Initialize emulator in ARM mode + err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u (%s)\n", + err, uc_strerror(err)); + return; + } + + // map 2MB memory for this emulation + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc_mem_write(uc, ADDRESS, THUMB_CODE, sizeof(THUMB_CODE) - 1); + + // initialize machine registers + uc_reg_write(uc, UC_ARM_REG_SP, &sp); + + // tracing all basic blocks with customized callback + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + + // tracing one instruction at ADDRESS with customized callback + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(THUMB_CODE) -1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned: %u\n", err); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_ARM_REG_SP, &sp); + printf(">>> SP = 0x%x\n", sp); + + uc_close(uc); +} + +int main(int argc, char **argv, char **envp) +{ + // dynamically load shared library +#ifdef DYNLOAD + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + // test memleak + while(1) { + test_arm(); + printf("==========================\n"); + test_thumb(); + } + + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + + return 0; +} diff --git a/tests/regress/memleak_arm64.c b/tests/regress/memleak_arm64.c new file mode 100644 index 00000000..e9b43c0e --- /dev/null +++ b/tests/regress/memleak_arm64.c @@ -0,0 +1,122 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh, 2015 */ + +/* Sample code to demonstrate how to emulate ARM64 code */ + +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include "unicorn_dynload.h" +#else // DYNLOAD +#include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER + + +// code to be emulated +#define ARM_CODE "\xab\x01\x0f\x8b" // add x11, x13, x15 + +// memory address where emulation starts +#define ADDRESS 0x10000 + +static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); +} + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); +} + +static void test_arm64(void) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1, trace2; + + int64_t x11 = 0x1234; // X11 register + int64_t x13 = 0x6789; // X13 register + int64_t x15 = 0x3333; // X15 register + + printf("Emulate ARM64 code\n"); + + // Initialize emulator in ARM mode + err = uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u (%s)\n", + err, uc_strerror(err)); + return; + } + + // map 2MB memory for this emulation + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc_mem_write(uc, ADDRESS, ARM_CODE, sizeof(ARM_CODE) - 1); + + // initialize machine registers + uc_reg_write(uc, UC_ARM64_REG_X11, &x11); + uc_reg_write(uc, UC_ARM64_REG_X13, &x13); + uc_reg_write(uc, UC_ARM64_REG_X15, &x15); + + // tracing all basic blocks with customized callback + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + + // tracing one instruction at ADDRESS with customized callback + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned: %u\n", err); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_ARM64_REG_X11, &x11); + printf(">>> X11 = 0x%" PRIx64 "\n", x11); + + uc_close(uc); +} + +int main(int argc, char **argv, char **envp) +{ + // dynamically load shared library +#ifdef DYNLOAD + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + while(1) { + test_arm64(); + } + + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + + return 0; +} diff --git a/tests/regress/memleak_m68k.c b/tests/regress/memleak_m68k.c new file mode 100644 index 00000000..8504daf1 --- /dev/null +++ b/tests/regress/memleak_m68k.c @@ -0,0 +1,185 @@ +/* Unicorn Emulator Engine */ +/* By Loi Anh Tuan, 2015 */ + +/* Sample code to demonstrate how to emulate m68k code */ + +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include "unicorn_dynload.h" +#else // DYNLOAD +#include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER + +// code to be emulated +#define M68K_CODE "\x76\xed" // movq #-19, %d3 + +// memory address where emulation starts +#define ADDRESS 0x10000 + +static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); +} + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); +} + +static void test_m68k(void) +{ + uc_engine *uc; + uc_hook trace1, trace2; + uc_err err; + + int d0 = 0x0000; // d0 data register + int d1 = 0x0000; // d1 data register + int d2 = 0x0000; // d2 data register + int d3 = 0x0000; // d3 data register + int d4 = 0x0000; // d4 data register + int d5 = 0x0000; // d5 data register + int d6 = 0x0000; // d6 data register + int d7 = 0x0000; // d7 data register + + int a0 = 0x0000; // a0 address register + int a1 = 0x0000; // a1 address register + int a2 = 0x0000; // a2 address register + int a3 = 0x0000; // a3 address register + int a4 = 0x0000; // a4 address register + int a5 = 0x0000; // a5 address register + int a6 = 0x0000; // a6 address register + int a7 = 0x0000; // a6 address register + + int pc = 0x0000; // program counter + int sr = 0x0000; // status register + + printf("Emulate M68K code\n"); + + // Initialize emulator in M68K mode + err = uc_open(UC_ARCH_M68K, UC_MODE_BIG_ENDIAN, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u (%s)\n", + err, uc_strerror(err)); + return; + } + + // map 2MB memory for this emulation + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc_mem_write(uc, ADDRESS, M68K_CODE, sizeof(M68K_CODE) - 1); + + // initialize machine registers + uc_reg_write(uc, UC_M68K_REG_D0, &d0); + uc_reg_write(uc, UC_M68K_REG_D1, &d1); + uc_reg_write(uc, UC_M68K_REG_D2, &d2); + uc_reg_write(uc, UC_M68K_REG_D3, &d3); + uc_reg_write(uc, UC_M68K_REG_D4, &d4); + uc_reg_write(uc, UC_M68K_REG_D5, &d5); + uc_reg_write(uc, UC_M68K_REG_D6, &d6); + uc_reg_write(uc, UC_M68K_REG_D7, &d7); + + uc_reg_write(uc, UC_M68K_REG_A0, &a0); + uc_reg_write(uc, UC_M68K_REG_A1, &a1); + uc_reg_write(uc, UC_M68K_REG_A2, &a2); + uc_reg_write(uc, UC_M68K_REG_A3, &a3); + uc_reg_write(uc, UC_M68K_REG_A4, &a4); + uc_reg_write(uc, UC_M68K_REG_A5, &a5); + uc_reg_write(uc, UC_M68K_REG_A6, &a6); + uc_reg_write(uc, UC_M68K_REG_A7, &a7); + + uc_reg_write(uc, UC_M68K_REG_PC, &pc); + uc_reg_write(uc, UC_M68K_REG_SR, &sr); + + // tracing all basic blocks with customized callback + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + + // tracing all instruction + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(M68K_CODE)-1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned: %u\n", err); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_M68K_REG_D0, &d0); + uc_reg_read(uc, UC_M68K_REG_D1, &d1); + uc_reg_read(uc, UC_M68K_REG_D2, &d2); + uc_reg_read(uc, UC_M68K_REG_D3, &d3); + uc_reg_read(uc, UC_M68K_REG_D4, &d4); + uc_reg_read(uc, UC_M68K_REG_D5, &d5); + uc_reg_read(uc, UC_M68K_REG_D6, &d6); + uc_reg_read(uc, UC_M68K_REG_D7, &d7); + + uc_reg_read(uc, UC_M68K_REG_A0, &a0); + uc_reg_read(uc, UC_M68K_REG_A1, &a1); + uc_reg_read(uc, UC_M68K_REG_A2, &a2); + uc_reg_read(uc, UC_M68K_REG_A3, &a3); + uc_reg_read(uc, UC_M68K_REG_A4, &a4); + uc_reg_read(uc, UC_M68K_REG_A5, &a5); + uc_reg_read(uc, UC_M68K_REG_A6, &a6); + uc_reg_read(uc, UC_M68K_REG_A7, &a7); + + uc_reg_read(uc, UC_M68K_REG_PC, &pc); + uc_reg_read(uc, UC_M68K_REG_SR, &sr); + + printf(">>> A0 = 0x%x\t\t>>> D0 = 0x%x\n", a0, d0); + printf(">>> A1 = 0x%x\t\t>>> D1 = 0x%x\n", a1, d1); + printf(">>> A2 = 0x%x\t\t>>> D2 = 0x%x\n", a2, d2); + printf(">>> A3 = 0x%x\t\t>>> D3 = 0x%x\n", a3, d3); + printf(">>> A4 = 0x%x\t\t>>> D4 = 0x%x\n", a4, d4); + printf(">>> A5 = 0x%x\t\t>>> D5 = 0x%x\n", a5, d5); + printf(">>> A6 = 0x%x\t\t>>> D6 = 0x%x\n", a6, d6); + printf(">>> A7 = 0x%x\t\t>>> D7 = 0x%x\n", a7, d7); + printf(">>> PC = 0x%x\n", pc); + printf(">>> SR = 0x%x\n", sr); + + uc_close(uc); +} + +int main(int argc, char **argv, char **envp) +{ + // dynamically load shared library +#ifdef DYNLOAD + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + // test memleak + while(1) { + test_m68k(); + } + + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + + return 0; +} diff --git a/tests/regress/memleak_mips.c b/tests/regress/memleak_mips.c new file mode 100644 index 00000000..e82a301b --- /dev/null +++ b/tests/regress/memleak_mips.c @@ -0,0 +1,171 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh, 2015 */ + +/* Sample code to demonstrate how to emulate Mips code (big endian) */ + +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include "unicorn_dynload.h" +#else // DYNLOAD +#include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER + + +// code to be emulated +#define MIPS_CODE_EB "\x34\x21\x34\x56" // ori $at, $at, 0x3456; +#define MIPS_CODE_EL "\x56\x34\x21\x34" // ori $at, $at, 0x3456; + +// memory address where emulation starts +#define ADDRESS 0x10000 + +static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); +} + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); +} + +static void test_mips_eb(void) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1, trace2; + + int r1 = 0x6789; // R1 register + + printf("Emulate MIPS code (big-endian)\n"); + + // Initialize emulator in MIPS mode + err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u (%s)\n", + err, uc_strerror(err)); + return; + } + + // map 2MB memory for this emulation + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc_mem_write(uc, ADDRESS, MIPS_CODE_EB, sizeof(MIPS_CODE_EB) - 1); + + // initialize machine registers + uc_reg_write(uc, UC_MIPS_REG_1, &r1); + + // tracing all basic blocks with customized callback + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + + // tracing one instruction at ADDRESS with customized callback + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(MIPS_CODE_EB) - 1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err, uc_strerror(err)); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_MIPS_REG_1, &r1); + printf(">>> R1 = 0x%x\n", r1); + + uc_close(uc); +} + +static void test_mips_el(void) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1, trace2; + + int r1 = 0x6789; // R1 register + + printf("===========================\n"); + printf("Emulate MIPS code (little-endian)\n"); + + // Initialize emulator in MIPS mode + err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u (%s)\n", + err, uc_strerror(err)); + return; + } + + // map 2MB memory for this emulation + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc_mem_write(uc, ADDRESS, MIPS_CODE_EL, sizeof(MIPS_CODE_EL) - 1); + + // initialize machine registers + uc_reg_write(uc, UC_MIPS_REG_1, &r1); + + // tracing all basic blocks with customized callback + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + + // tracing one instruction at ADDRESS with customized callback + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(MIPS_CODE_EL) - 1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err, uc_strerror(err)); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_MIPS_REG_1, &r1); + printf(">>> R1 = 0x%x\n", r1); + + uc_close(uc); +} + +int main(int argc, char **argv, char **envp) +{ + // dynamically load shared library +#ifdef DYNLOAD + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + // test memleak + while(1) { + test_mips_eb(); + test_mips_el(); + } + + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + + return 0; +} diff --git a/tests/regress/memleak_sparc.c b/tests/regress/memleak_sparc.c new file mode 100644 index 00000000..1493d24e --- /dev/null +++ b/tests/regress/memleak_sparc.c @@ -0,0 +1,125 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh, 2015 */ + +/* Sample code to demonstrate how to emulate Sparc code */ + +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include "unicorn_dynload.h" +#else // DYNLOAD +#include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER + + +// code to be emulated +#define SPARC_CODE "\x86\x00\x40\x02" // add %g1, %g2, %g3; +//#define SPARC_CODE "\xbb\x70\x00\x00" // illegal code + +// memory address where emulation starts +#define ADDRESS 0x10000 + +static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); +} + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); +} + +static void test_sparc(void) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1, trace2; + + int g1 = 0x1230; // G1 register + int g2 = 0x6789; // G2 register + int g3 = 0x5555; // G3 register + + printf("Emulate SPARC code\n"); + + // Initialize emulator in Sparc mode + err = uc_open(UC_ARCH_SPARC, UC_MODE_32, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u (%s)\n", + err, uc_strerror(err)); + return; + } + + // map 2MB memory for this emulation + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc_mem_write(uc, ADDRESS, SPARC_CODE, sizeof(SPARC_CODE) - 1); + + // initialize machine registers + uc_reg_write(uc, UC_SPARC_REG_G1, &g1); + uc_reg_write(uc, UC_SPARC_REG_G2, &g2); + uc_reg_write(uc, UC_SPARC_REG_G3, &g3); + + // tracing all basic blocks with customized callback + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + + // tracing all instructions with customized callback + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(SPARC_CODE) - 1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned: %u (%s)\n", + err, uc_strerror(err)); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_SPARC_REG_G3, &g3); + printf(">>> G3 = 0x%x\n", g3); + + uc_close(uc); +} + +int main(int argc, char **argv, char **envp) +{ + // dynamically load shared library +#ifdef DYNLOAD + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + // test memleak + while(1) { + test_sparc(); + } + + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + + return 0; +} diff --git a/tests/regress/memleak_x86.c b/tests/regress/memleak_x86.c new file mode 100644 index 00000000..737f7305 --- /dev/null +++ b/tests/regress/memleak_x86.c @@ -0,0 +1,306 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh & Dang Hoang Vu, 2015 */ + +/* Sample code to demonstrate how to emulate X86 code */ + +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include "unicorn_dynload.h" +#else // DYNLOAD +#include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER + +// common includes +#include + + +// code to be emulated +#define X86_CODE32 "\x41\x4a" // INC ecx; DEC edx +#define X86_CODE32_JUMP "\xeb\x02\x90\x90\x90\x90\x90\x90" // jmp 4; nop; nop; nop; nop; nop; nop +// #define X86_CODE32_SELF "\xeb\x1c\x5a\x89\xd6\x8b\x02\x66\x3d\xca\x7d\x75\x06\x66\x05\x03\x03\x89\x02\xfe\xc2\x3d\x41\x41\x41\x41\x75\xe9\xff\xe6\xe8\xdf\xff\xff\xff\x31\xd2\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xca\x7d\x41\x41\x41\x41" +//#define X86_CODE32 "\x51\x51\x51\x51" // PUSH ecx; +#define X86_CODE32_LOOP "\x41\x4a\xeb\xfe" // INC ecx; DEC edx; JMP self-loop +#define X86_CODE32_MEM_WRITE "\x89\x0D\xAA\xAA\xAA\xAA\x41\x4a" // mov [0xaaaaaaaa], ecx; INC ecx; DEC edx +#define X86_CODE32_MEM_READ "\x8B\x0D\xAA\xAA\xAA\xAA\x41\x4a" // mov ecx,[0xaaaaaaaa]; INC ecx; DEC edx + +#define X86_CODE32_JMP_INVALID "\xe9\xe9\xee\xee\xee\x41\x4a" // JMP outside; INC ecx; DEC edx +#define X86_CODE32_INOUT "\x41\xE4\x3F\x4a\xE6\x46\x43" // INC ecx; IN AL, 0x3f; DEC edx; OUT 0x46, AL; INC ebx + +//#define X86_CODE64 "\x41\xBC\x3B\xB0\x28\x2A \x49\x0F\xC9 \x90 \x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9" // <== still crash +//#define X86_CODE64 "\x41\xBC\x3B\xB0\x28\x2A\x49\x0F\xC9\x90\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9" +#define X86_CODE64 "\x41\xBC\x3B\xB0\x28\x2A\x49\x0F\xC9\x90\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9\x4D\x29\xF4\x49\x81\xC9\xF6\x8A\xC6\x53\x4D\x87\xED\x48\x0F\xAD\xD2\x49\xF7\xD4\x48\xF7\xE1\x4D\x19\xC5\x4D\x89\xC5\x48\xF7\xD6\x41\xB8\x4F\x8D\x6B\x59\x4D\x87\xD0\x68\x6A\x1E\x09\x3C\x59" +#define X86_CODE16 "\x00\x00" // add byte ptr [bx + si], al +#define X86_CODE64_SYSCALL "\x0f\x05" // SYSCALL + +// memory address where emulation starts +#define ADDRESS 0x1000000 + +// callback for tracing basic blocks +static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); +} + +// callback for tracing instruction +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + int eflags; + printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); + + uc_reg_read(uc, UC_X86_REG_EFLAGS, &eflags); + printf(">>> --- EFLAGS is 0x%x\n", eflags); + + // Uncomment below code to stop the emulation using uc_emu_stop() + // if (address == 0x1000009) + // uc_emu_stop(uc); +} + +// callback for tracing instruction +static void hook_code64(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + uint64_t rip; + + uc_reg_read(uc, UC_X86_REG_RIP, &rip); + printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); + printf(">>> RIP is 0x%"PRIx64 "\n", rip); + + // Uncomment below code to stop the emulation using uc_emu_stop() + // if (address == 0x1000009) + // uc_emu_stop(uc); +} + +static void hook_mem64(uc_engine *uc, uc_mem_type type, + uint64_t address, int size, int64_t value, void *user_data) +{ + switch(type) { + default: break; + case UC_MEM_READ: + printf(">>> Memory is being READ at 0x%"PRIx64 ", data size = %u\n", + address, size); + break; + case UC_MEM_WRITE: + printf(">>> Memory is being WRITE at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", + address, size, value); + break; + } +} + +static void test_i386(void) +{ + uc_engine *uc; + uc_err err; + uint32_t tmp; + uc_hook trace1, trace2; + + int r_ecx = 0x1234; // ECX register + int r_edx = 0x7890; // EDX register + + printf("Emulate i386 code\n"); + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u\n", err); + return; + } + + // map 2MB memory for this emulation + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + if (uc_mem_write(uc, ADDRESS, X86_CODE32, sizeof(X86_CODE32) - 1)) { + printf("Failed to write emulation code to memory, quit!\n"); + return; + } + + // initialize machine registers + uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); + uc_reg_write(uc, UC_X86_REG_EDX, &r_edx); + + // tracing all basic blocks with customized callback + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + + // tracing all instruction by having @begin > @end + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + + // emulate machine code in infinite time + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned %u: %s\n", + err, uc_strerror(err)); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); + uc_reg_read(uc, UC_X86_REG_EDX, &r_edx); + printf(">>> ECX = 0x%x\n", r_ecx); + printf(">>> EDX = 0x%x\n", r_edx); + + // read from memory + if (!uc_mem_read(uc, ADDRESS, &tmp, sizeof(tmp))) + printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", ADDRESS, tmp); + else + printf(">>> Failed to read 4 bytes from [0x%x]\n", ADDRESS); + + uc_close(uc); +} + +static void test_x86_64(void) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1, trace2, trace3, trace4; + + int64_t rax = 0x71f3029efd49d41d; + int64_t rbx = 0xd87b45277f133ddb; + int64_t rcx = 0xab40d1ffd8afc461; + int64_t rdx = 0x919317b4a733f01; + int64_t rsi = 0x4c24e753a17ea358; + int64_t rdi = 0xe509a57d2571ce96; + int64_t r8 = 0xea5b108cc2b9ab1f; + int64_t r9 = 0x19ec097c8eb618c1; + int64_t r10 = 0xec45774f00c5f682; + int64_t r11 = 0xe17e9dbec8c074aa; + int64_t r12 = 0x80f86a8dc0f6d457; + int64_t r13 = 0x48288ca5671c5492; + int64_t r14 = 0x595f72f6e4017f6e; + int64_t r15 = 0x1efd97aea331cccc; + + int64_t rsp = ADDRESS + 0x200000; + + + printf("Emulate x86_64 code\n"); + + // Initialize emulator in X86-64bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u\n", err); + return; + } + + // map 2MB memory for this emulation + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + if (uc_mem_write(uc, ADDRESS, X86_CODE64, sizeof(X86_CODE64) - 1)) { + printf("Failed to write emulation code to memory, quit!\n"); + return; + } + + // initialize machine registers + uc_reg_write(uc, UC_X86_REG_RSP, &rsp); + + uc_reg_write(uc, UC_X86_REG_RAX, &rax); + uc_reg_write(uc, UC_X86_REG_RBX, &rbx); + uc_reg_write(uc, UC_X86_REG_RCX, &rcx); + uc_reg_write(uc, UC_X86_REG_RDX, &rdx); + uc_reg_write(uc, UC_X86_REG_RSI, &rsi); + uc_reg_write(uc, UC_X86_REG_RDI, &rdi); + uc_reg_write(uc, UC_X86_REG_R8, &r8); + uc_reg_write(uc, UC_X86_REG_R9, &r9); + uc_reg_write(uc, UC_X86_REG_R10, &r10); + uc_reg_write(uc, UC_X86_REG_R11, &r11); + uc_reg_write(uc, UC_X86_REG_R12, &r12); + uc_reg_write(uc, UC_X86_REG_R13, &r13); + uc_reg_write(uc, UC_X86_REG_R14, &r14); + uc_reg_write(uc, UC_X86_REG_R15, &r15); + + // tracing all basic blocks with customized callback + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + + // tracing all instructions in the range [ADDRESS, ADDRESS+20] + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code64, NULL, (uint64_t)ADDRESS, (uint64_t)(ADDRESS+20)); + + // tracing all memory WRITE access (with @begin > @end) + uc_hook_add(uc, &trace3, UC_HOOK_MEM_WRITE, hook_mem64, NULL, (uint64_t)1, (uint64_t)0); + + // tracing all memory READ access (with @begin > @end) + uc_hook_add(uc, &trace4, UC_HOOK_MEM_READ, hook_mem64, NULL, (uint64_t)1, (uint64_t)0); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE64) - 1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned %u: %s\n", + err, uc_strerror(err)); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_X86_REG_RAX, &rax); + uc_reg_read(uc, UC_X86_REG_RBX, &rbx); + uc_reg_read(uc, UC_X86_REG_RCX, &rcx); + uc_reg_read(uc, UC_X86_REG_RDX, &rdx); + uc_reg_read(uc, UC_X86_REG_RSI, &rsi); + uc_reg_read(uc, UC_X86_REG_RDI, &rdi); + uc_reg_read(uc, UC_X86_REG_R8, &r8); + uc_reg_read(uc, UC_X86_REG_R9, &r9); + uc_reg_read(uc, UC_X86_REG_R10, &r10); + uc_reg_read(uc, UC_X86_REG_R11, &r11); + uc_reg_read(uc, UC_X86_REG_R12, &r12); + uc_reg_read(uc, UC_X86_REG_R13, &r13); + uc_reg_read(uc, UC_X86_REG_R14, &r14); + uc_reg_read(uc, UC_X86_REG_R15, &r15); + + printf(">>> RAX = 0x%" PRIx64 "\n", rax); + printf(">>> RBX = 0x%" PRIx64 "\n", rbx); + printf(">>> RCX = 0x%" PRIx64 "\n", rcx); + printf(">>> RDX = 0x%" PRIx64 "\n", rdx); + printf(">>> RSI = 0x%" PRIx64 "\n", rsi); + printf(">>> RDI = 0x%" PRIx64 "\n", rdi); + printf(">>> R8 = 0x%" PRIx64 "\n", r8); + printf(">>> R9 = 0x%" PRIx64 "\n", r9); + printf(">>> R10 = 0x%" PRIx64 "\n", r10); + printf(">>> R11 = 0x%" PRIx64 "\n", r11); + printf(">>> R12 = 0x%" PRIx64 "\n", r12); + printf(">>> R13 = 0x%" PRIx64 "\n", r13); + printf(">>> R14 = 0x%" PRIx64 "\n", r14); + printf(">>> R15 = 0x%" PRIx64 "\n", r15); + + uc_close(uc); +} + +int main(int argc, char **argv, char **envp) +{ + // dynamically load shared library +#ifdef DYNLOAD + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + while(1) { + test_i386(); + test_x86_64(); + } + + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + + return 0; +} From 7c9f851e72b8b666f3f2e6388150a8da46bee99f Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 11 Jan 2016 00:08:04 +0800 Subject: [PATCH 021/149] sample: remove memleak test code in sample_x86.c --- samples/sample_x86.c | 8 -------- 1 file changed, 8 deletions(-) diff --git a/samples/sample_x86.c b/samples/sample_x86.c index b6d55401..87a6d60f 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -914,14 +914,6 @@ int main(int argc, char **argv, char **envp) if (!strcmp(argv[1], "-16")) { test_x86_16(); } - - // test memleak - if (!strcmp(argv[1], "-0")) { - while(1) { - test_i386(); - // test_x86_64(); - } - } } else { printf("Syntax: %s <-16|-32|-64>\n", argv[0]); } From 36e53ad8a14f2c726e5a3c85c6fd5e2d2dd358d4 Mon Sep 17 00:00:00 2001 From: danghvu Date: Sun, 31 Jan 2016 16:22:20 -0600 Subject: [PATCH 022/149] Fix arm & arm64 memleaks --- qemu/hw/arm/tosa.c | 2 +- qemu/hw/arm/virt.c | 2 +- qemu/target-arm/unicorn_aarch64.c | 18 ++++++++++++++++++ qemu/target-arm/unicorn_arm.c | 18 ++++++++++++++++++ qemu/unicorn_common.h | 1 + 5 files changed, 39 insertions(+), 2 deletions(-) diff --git a/qemu/hw/arm/tosa.c b/qemu/hw/arm/tosa.c index fe9eaf6e..8630e46e 100644 --- a/qemu/hw/arm/tosa.c +++ b/qemu/hw/arm/tosa.c @@ -20,7 +20,7 @@ static int tosa_init(struct uc_struct *uc, MachineState *machine) { //cpu_arm_init(uc, "pxa255"); - cpu_arm_init(uc, "cortex-a15"); // FIXME + uc->cpu = cpu_arm_init(uc, "cortex-a15"); // FIXME return 0; } diff --git a/qemu/hw/arm/virt.c b/qemu/hw/arm/virt.c index 554e89d7..e2a68412 100644 --- a/qemu/hw/arm/virt.c +++ b/qemu/hw/arm/virt.c @@ -54,7 +54,7 @@ static int machvirt_init(struct uc_struct *uc, MachineState *machine) return -1; } - cpuobj = object_new(uc, object_class_get_name(oc)); + uc->cpu = cpuobj = object_new(uc, object_class_get_name(oc)); object_property_set_bool(uc, cpuobj, true, "realized", NULL); } diff --git a/qemu/target-arm/unicorn_aarch64.c b/qemu/target-arm/unicorn_aarch64.c index 0123b5cb..00f71c6a 100644 --- a/qemu/target-arm/unicorn_aarch64.c +++ b/qemu/target-arm/unicorn_aarch64.c @@ -25,6 +25,23 @@ static void arm64_set_pc(struct uc_struct *uc, uint64_t address) ((CPUARMState *)uc->current_cpu->env_ptr)->pc = address; } +void arm64_release(void* ctx); + +void arm64_release(void* ctx) +{ + TCGContext *s = (TCGContext *) ctx; + + g_free(s->tb_ctx.tbs); + struct uc_struct* uc = s->uc; + ARMCPU* cpu = (ARMCPU*) uc->cpu; + g_free(cpu->cpreg_indexes); + g_free(cpu->cpreg_values); + g_free(cpu->cpreg_vmstate_indexes); + g_free(cpu->cpreg_vmstate_values); + + release_common(ctx); +} + void arm64_reg_reset(struct uc_struct *uc) { CPUArchState *env = first_cpu->env_ptr; @@ -103,5 +120,6 @@ void arm64_uc_init(struct uc_struct* uc) uc->reg_write = arm64_reg_write; uc->reg_reset = arm64_reg_reset; uc->set_pc = arm64_set_pc; + uc->release = arm64_release; uc_common_init(uc); } diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index 1c4004af..22c35cf9 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -25,6 +25,23 @@ static void arm_set_pc(struct uc_struct *uc, uint64_t address) ((CPUARMState *)uc->current_cpu->env_ptr)->regs[15] = address; } +void arm_release(void* ctx); + +void arm_release(void* ctx) +{ + TCGContext *s = (TCGContext *) ctx; + + g_free(s->tb_ctx.tbs); + struct uc_struct* uc = s->uc; + ARMCPU* cpu = (ARMCPU*) uc->cpu; + g_free(cpu->cpreg_indexes); + g_free(cpu->cpreg_values); + g_free(cpu->cpreg_vmstate_indexes); + g_free(cpu->cpreg_vmstate_values); + + release_common(ctx); +} + void arm_reg_reset(struct uc_struct *uc) { (void)uc; @@ -134,5 +151,6 @@ void arm_uc_init(struct uc_struct* uc) uc->reg_reset = arm_reg_reset; uc->set_pc = arm_set_pc; uc->stop_interrupt = arm_stop_interrupt; + uc->release = arm_release; uc_common_init(uc); } diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h index adccbe01..a9fb5176 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -42,6 +42,7 @@ static void release_common(void *t) g_free(def->args_ct); g_free(def->sorted_args); g_free(s->tcg_op_defs); + TCGPool *po, *to; for (po = s->pool_first; po; po = to) { to = po->next; From cfaac6921bb0e334e8448d3d739eef4154710889 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 1 Feb 2016 12:05:46 +0800 Subject: [PATCH 023/149] c89 --- qemu/unicorn_common.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h index a9fb5176..ca095b8b 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -36,6 +36,9 @@ static void release_common(void *t) TCGContext *s = (TCGContext *)t; struct uc_struct* uc = s->uc; CPUState *cpu; +#if TCG_TARGET_REG_BITS == 32 + int i; +#endif // Clean TCG. TCGOpDef* def = &s->tcg_op_defs[0]; @@ -83,7 +86,7 @@ static void release_common(void *t) free(uc->qemu_thread_data); #if TCG_TARGET_REG_BITS == 32 - for(int i = 0; i < s->nb_globals; i++) { + for(i = 0; i < s->nb_globals; i++) { TCGTemp *ts = &s->temps[i]; if (ts->base_type == TCG_TYPE_I64) { if (ts->name && ((strcmp(ts->name+(strlen(ts->name)-2), "_0") == 0) || From b6897e201585660714fce8ea46a66b1f46b2c88a Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 11 Feb 2016 09:19:08 +0800 Subject: [PATCH 024/149] fix a compilation warning --- qemu/vl.c | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/qemu/vl.c b/qemu/vl.c index 7cbfb065..f1599c6d 100644 --- a/qemu/vl.c +++ b/qemu/vl.c @@ -107,17 +107,15 @@ int machine_initialize(struct uc_struct *uc) module_call_init(uc, MODULE_INIT_MACHINE); // this will auto initialize all register objects above. machine_class = find_default_machine(uc, uc->arch); - if (!uc->machine_state) { - if (machine_class == NULL) { - //fprintf(stderr, "No machine specified, and there is no default.\n" - // "Use -machine help to list supported machines!\n"); - return -2; - } - - current_machine = MACHINE(uc, object_new(uc, object_class_get_name( - OBJECT_CLASS(machine_class)))); - uc->machine_state = current_machine; + if (machine_class == NULL) { + //fprintf(stderr, "No machine specified, and there is no default.\n" + // "Use -machine help to list supported machines!\n"); + return -2; } + + current_machine = MACHINE(uc, object_new(uc, object_class_get_name( + OBJECT_CLASS(machine_class)))); + uc->machine_state = current_machine; current_machine->uc = uc; uc->cpu_exec_init_all(uc); From 5fa6705d7af599275193d5eeaad5abf20fcc1fee Mon Sep 17 00:00:00 2001 From: Jonas Zaddach Date: Mon, 29 Feb 2016 22:57:41 +0100 Subject: [PATCH 025/149] Fixed restoring of eflags after helper call --- qemu/target-i386/translate.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/qemu/target-i386/translate.c b/qemu/target-i386/translate.c index d68cb516..76bab2d6 100644 --- a/qemu/target-i386/translate.c +++ b/qemu/target-i386/translate.c @@ -4721,6 +4721,17 @@ static void sync_eflags(DisasContext *s, TCGContext *tcg_ctx) tcg_gen_st_tl(tcg_ctx, *cpu_T[0], cpu_env, offsetof(CPUX86State, eflags)); } +static void restore_eflags(DisasContext *s, TCGContext *tcg_ctx) +{ + TCGv **cpu_T = (TCGv **)tcg_ctx->cpu_T; + TCGv_ptr cpu_env = tcg_ctx->cpu_env; + + tcg_gen_ld_tl(tcg_ctx, *cpu_T[0], cpu_env, offsetof(CPUX86State, eflags)); + gen_helper_write_eflags(tcg_ctx, cpu_env, *cpu_T[0], + tcg_const_i32(tcg_ctx, (TF_MASK | AC_MASK | ID_MASK | NT_MASK) & 0xffff)); + set_cc_op(s, CC_OP_EFLAGS); +} + /* convert one instruction. s->is_jmp is set if the translation must be stopped. Return the next pc value */ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, @@ -4773,6 +4784,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, changed_cc_op = true; } gen_uc_tracecode(tcg_ctx, 0xf1f1f1f1, UC_HOOK_CODE_IDX, env->uc, pc_start); + restore_eflags(s, tcg_ctx); // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); } From 9eb1c57c34cf8ba5c3f59a77087ebf170f46ae25 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 1 Mar 2016 13:49:27 +0800 Subject: [PATCH 026/149] add Travis support for automated tests --- .travis.yml | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 .travis.yml diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..b80f07f3 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,9 @@ +language: c +sudo: false +before_install: + - export LD_LIBRARY_PATH=`pwd`/samples/:$LD_LIBRARY_PATH +script: + - ./make.sh +compiler: + - clang + - gcc From d6fee1fd6a3427d50f8a28ca66df104c9c3783bd Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 1 Mar 2016 13:54:32 +0800 Subject: [PATCH 027/149] add Travis build status to README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 942e1b8e..0d8e7558 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ Unicorn Engine ============== +[![Build Status](https://travis-ci.org/unicorn-engine/unicorn.svg?branch=master)](https://travis-ci.org/unicorn-engine/unicorn) + Unicorn is a lightweight, multi-platform, multi-architecture CPU emulator framework based on [QEMU](http://qemu.org). From 1cd3c3093b0fc152daed76bfd0068a34c922e09c Mon Sep 17 00:00:00 2001 From: Hiroyuki UEKAWA Date: Wed, 2 Mar 2016 09:23:48 +0900 Subject: [PATCH 028/149] fix WRITE_BYTE_H --- qemu/target-arm/unicorn_aarch64.c | 2 +- qemu/target-arm/unicorn_arm.c | 2 +- qemu/target-i386/unicorn.c | 2 +- qemu/target-m68k/unicorn.c | 2 +- qemu/target-mips/unicorn.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/qemu/target-arm/unicorn_aarch64.c b/qemu/target-arm/unicorn_aarch64.c index 1ce9d6eb..fbdfaff7 100644 --- a/qemu/target-arm/unicorn_aarch64.c +++ b/qemu/target-arm/unicorn_aarch64.c @@ -62,7 +62,7 @@ int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value) #define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) #define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) +#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index 95ea812d..da51cac4 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -69,7 +69,7 @@ int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value) #define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) #define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) +#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index c8436b9b..92b79d32 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -578,7 +578,7 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) #define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) #define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) +#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) diff --git a/qemu/target-m68k/unicorn.c b/qemu/target-m68k/unicorn.c index 0055d4a1..bbf5898f 100644 --- a/qemu/target-m68k/unicorn.c +++ b/qemu/target-m68k/unicorn.c @@ -54,7 +54,7 @@ int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value) #define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) #define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) +#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) diff --git a/qemu/target-mips/unicorn.c b/qemu/target-mips/unicorn.c index 6af98dce..6085a259 100644 --- a/qemu/target-mips/unicorn.c +++ b/qemu/target-mips/unicorn.c @@ -67,7 +67,7 @@ int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value) #define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) #define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff)) +#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) #define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) From c5888e5670e7608b9e49436962b294fb81fddbe2 Mon Sep 17 00:00:00 2001 From: Hiroyuki UEKAWA Date: Wed, 2 Mar 2016 12:43:02 +0900 Subject: [PATCH 029/149] move macros in `qemu/target-*/unicorn*.c` to `uc_priv.h` --- include/uc_priv.h | 11 +++++++++++ qemu/target-arm/unicorn_aarch64.c | 17 +---------------- qemu/target-arm/unicorn_arm.c | 16 +--------------- qemu/target-i386/unicorn.c | 16 ++-------------- qemu/target-m68k/unicorn.c | 14 +------------- qemu/target-mips/unicorn.c | 15 +-------------- qemu/target-sparc/unicorn.c | 8 +------- qemu/target-sparc/unicorn64.c | 8 +------- 8 files changed, 19 insertions(+), 86 deletions(-) diff --git a/include/uc_priv.h b/include/uc_priv.h index 0ef5a3dd..e36a8c84 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -22,6 +22,17 @@ #define ARR_SIZE(a) (sizeof(a)/sizeof(a[0])) +#define READ_QWORD(x) ((uint64)x) +#define READ_DWORD(x) (x & 0xffffffff) +#define READ_WORD(x) (x & 0xffff) +#define READ_BYTE_H(x) ((x & 0xffff) >> 8) +#define READ_BYTE_L(x) (x & 0xff) +#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) +#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) +#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) +#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) + + QTAILQ_HEAD(CPUTailQ, CPUState); typedef struct ModuleEntry { diff --git a/qemu/target-arm/unicorn_aarch64.c b/qemu/target-arm/unicorn_aarch64.c index fbdfaff7..c1d53a68 100644 --- a/qemu/target-arm/unicorn_aarch64.c +++ b/qemu/target-arm/unicorn_aarch64.c @@ -3,21 +3,11 @@ #include "hw/boards.h" #include "hw/arm/arm.h" - #include "sysemu/cpus.h" - #include "unicorn.h" - #include "cpu.h" - #include "unicorn_common.h" - - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static void arm64_set_pc(struct uc_struct *uc, uint64_t address) @@ -60,11 +50,6 @@ int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value) return 0; } -#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) -#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) -#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) - int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index da51cac4..9fc2a44c 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -3,20 +3,11 @@ #include "hw/boards.h" #include "hw/arm/arm.h" - #include "sysemu/cpus.h" - #include "unicorn.h" - #include "cpu.h" #include "unicorn_common.h" - - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static void arm_set_pc(struct uc_struct *uc, uint64_t address) @@ -67,11 +58,6 @@ int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value) return 0; } -#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) -#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) -#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) - int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 92b79d32..7ec2d140 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -2,20 +2,14 @@ /* By Nguyen Anh Quynh , 2015 */ #include "hw/boards.h" -#include "sysemu/cpus.h" #include "hw/i386/pc.h" +#include "sysemu/cpus.h" #include "unicorn.h" #include "cpu.h" #include "tcg.h" - #include "unicorn_common.h" #include /* needed for uc_x86_mmr */ - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static void x86_set_pc(struct uc_struct *uc, uint64_t address) @@ -575,12 +569,6 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) return 0; } - -#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) -#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) -#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) - int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; diff --git a/qemu/target-m68k/unicorn.c b/qemu/target-m68k/unicorn.c index bbf5898f..0edf04c2 100644 --- a/qemu/target-m68k/unicorn.c +++ b/qemu/target-m68k/unicorn.c @@ -6,14 +6,8 @@ #include "sysemu/cpus.h" #include "unicorn.h" #include "cpu.h" - #include "unicorn_common.h" - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static void m68k_set_pc(struct uc_struct *uc, uint64_t address) @@ -51,12 +45,6 @@ int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value) return 0; } - -#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) -#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) -#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) - int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; diff --git a/qemu/target-mips/unicorn.c b/qemu/target-mips/unicorn.c index 6085a259..7740d0d9 100644 --- a/qemu/target-mips/unicorn.c +++ b/qemu/target-mips/unicorn.c @@ -6,15 +6,8 @@ #include "sysemu/cpus.h" #include "unicorn.h" #include "cpu.h" - #include "unicorn_common.h" - - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static uint64_t mips_mem_redirect(uint64_t address) @@ -64,12 +57,6 @@ int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value) return 0; } - -#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff)) -#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff)) -#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8)) -#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff)) - int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) { CPUState *mycpu = first_cpu; diff --git a/qemu/target-sparc/unicorn.c b/qemu/target-sparc/unicorn.c index e612457b..3775776a 100644 --- a/qemu/target-sparc/unicorn.c +++ b/qemu/target-sparc/unicorn.c @@ -7,13 +7,7 @@ #include "unicorn.h" #include "cpu.h" #include "unicorn_common.h" - - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static bool sparc_stop_interrupt(int intno) diff --git a/qemu/target-sparc/unicorn64.c b/qemu/target-sparc/unicorn64.c index e9257b75..ef99b5ab 100644 --- a/qemu/target-sparc/unicorn64.c +++ b/qemu/target-sparc/unicorn64.c @@ -7,13 +7,7 @@ #include "unicorn.h" #include "cpu.h" #include "unicorn_common.h" - - -#define READ_QWORD(x) ((uint64)x) -#define READ_DWORD(x) (x & 0xffffffff) -#define READ_WORD(x) (x & 0xffff) -#define READ_BYTE_H(x) ((x & 0xffff) >> 8) -#define READ_BYTE_L(x) (x & 0xff) +#include "uc_priv.h" static bool sparc_stop_interrupt(int intno) From feb7b8e1ae56f4290da6c5372c2d6b3d93c8ea3f Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 3 Mar 2016 23:14:25 +0800 Subject: [PATCH 030/149] travis: support OSX & Linux --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index b80f07f3..4d077ff9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,3 +7,6 @@ script: compiler: - clang - gcc +os: + - linux + - osx From cf08670a1c1d16b53637c6bcf0c805a5e29cf180 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 3 Mar 2016 23:25:29 +0800 Subject: [PATCH 031/149] Travis: install dependencies for OSX --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 4d077ff9..9a3ebd3f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,9 @@ language: c sudo: false before_install: - export LD_LIBRARY_PATH=`pwd`/samples/:$LD_LIBRARY_PATH + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew pkg-config glib; fi + script: - ./make.sh compiler: From 3ebb5d3a2e145aa9355e4c1e0349f8a181236281 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 3 Mar 2016 23:33:07 +0800 Subject: [PATCH 032/149] travis: fix brew install --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9a3ebd3f..ffc13784 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ sudo: false before_install: - export LD_LIBRARY_PATH=`pwd`/samples/:$LD_LIBRARY_PATH - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew pkg-config glib; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install pkg-config glib; fi script: - ./make.sh From 1ddebc7304dd4d0a91ad410eedc7e41bae8d46fa Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 3 Mar 2016 23:41:03 +0800 Subject: [PATCH 033/149] travis: do not need to install pkg-config --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index ffc13784..39c18b8e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,7 @@ sudo: false before_install: - export LD_LIBRARY_PATH=`pwd`/samples/:$LD_LIBRARY_PATH - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install pkg-config glib; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install glib; fi script: - ./make.sh From 1087ba9dea62ef0e6c2b2e7e147b1dab9b46c2d2 Mon Sep 17 00:00:00 2001 From: Nicolas PLANEL Date: Fri, 4 Mar 2016 15:26:06 +1100 Subject: [PATCH 034/149] [query] add UC_QUERY_PAGE_SIZE uc_query helper Return the current page size used by the current arch. Useful to call uc_mem_map() with memory/size aligned. Signed-off-by: Nicolas PLANEL --- include/unicorn/unicorn.h | 1 + tests/unit/test_mem_map.c | 10 ++++++++++ uc.c | 5 +++++ 3 files changed, 16 insertions(+) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 35e745ca..23a17a4f 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -262,6 +262,7 @@ typedef struct uc_mem_region { typedef enum uc_query_type { // Dynamically query current hardware mode. UC_QUERY_MODE = 1, + UC_QUERY_PAGE_SIZE, } uc_query_type; /* diff --git a/tests/unit/test_mem_map.c b/tests/unit/test_mem_map.c index 303a370b..9c2b9892 100644 --- a/tests/unit/test_mem_map.c +++ b/tests/unit/test_mem_map.c @@ -158,6 +158,15 @@ static void test_strange_map(void **state) uc_mem_unmap(uc, 0x0,0x1000); } +static void test_query_page_size(void **state) +{ + uc_engine *uc = *state; + + size_t page_size; + uc_assert_success(uc_query(uc, UC_QUERY_PAGE_SIZE, &page_size)); + assert_int_equal(4096, page_size); +} + void write(uc_engine* uc, uint64_t addr, uint64_t len){ uint8_t* buff = alloca(len); memset(buff,0,len); @@ -220,6 +229,7 @@ int main(void) { test(test_unmap_double_map), test(test_overlap_unmap_double_map), test(test_strange_map), + test(test_query_page_size), }; #undef test return cmocka_run_group_tests(tests, NULL, NULL); diff --git a/uc.c b/uc.c index 298d21e0..ce9f121d 100644 --- a/uc.c +++ b/uc.c @@ -1094,6 +1094,11 @@ uint32_t uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count) UNICORN_EXPORT uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result) { + if (type == UC_QUERY_PAGE_SIZE) { + *result = uc->target_page_size; + return UC_ERR_OK; + } + switch(uc->arch) { case UC_ARCH_ARM: return uc->query(uc, type, result); From 2031f7cbdd64cb5a2bc5e980574710ed1ff2d5b9 Mon Sep 17 00:00:00 2001 From: Nicolas PLANEL Date: Fri, 4 Mar 2016 15:29:32 +1100 Subject: [PATCH 035/149] [query] update bindings UC_QUERY_PAGE_SIZE Signed-off-by: Nicolas PLANEL --- bindings/dotnet/UnicornManaged/Const/Common.fs | 1 + bindings/go/unicorn/unicorn_const.go | 1 + bindings/java/unicorn/UnicornConst.java | 1 + bindings/python/unicorn/unicorn_const.py | 1 + 4 files changed, 4 insertions(+) diff --git a/bindings/dotnet/UnicornManaged/Const/Common.fs b/bindings/dotnet/UnicornManaged/Const/Common.fs index 0f42d3d7..ef9004e6 100644 --- a/bindings/dotnet/UnicornManaged/Const/Common.fs +++ b/bindings/dotnet/UnicornManaged/Const/Common.fs @@ -93,6 +93,7 @@ module Common = let UC_HOOK_MEM_INVALID = 1008 let UC_HOOK_MEM_VALID = 7168 let UC_QUERY_MODE = 1 + let UC_QUERY_PAGE_SIZE = 2 let UC_PROT_NONE = 0 let UC_PROT_READ = 1 diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index 1faff075..01b62fca 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -88,6 +88,7 @@ const ( HOOK_MEM_INVALID = 1008 HOOK_MEM_VALID = 7168 QUERY_MODE = 1 + QUERY_PAGE_SIZE = 2 PROT_NONE = 0 PROT_READ = 1 diff --git a/bindings/java/unicorn/UnicornConst.java b/bindings/java/unicorn/UnicornConst.java index 64b52236..033267ae 100644 --- a/bindings/java/unicorn/UnicornConst.java +++ b/bindings/java/unicorn/UnicornConst.java @@ -90,6 +90,7 @@ public interface UnicornConst { public static final int UC_HOOK_MEM_INVALID = 1008; public static final int UC_HOOK_MEM_VALID = 7168; public static final int UC_QUERY_MODE = 1; + public static final int UC_QUERY_PAGE_SIZE = 2; public static final int UC_PROT_NONE = 0; public static final int UC_PROT_READ = 1; diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index bdb8ed01..89ccd919 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -86,6 +86,7 @@ UC_HOOK_MEM_FETCH_INVALID = 576 UC_HOOK_MEM_INVALID = 1008 UC_HOOK_MEM_VALID = 7168 UC_QUERY_MODE = 1 +UC_QUERY_PAGE_SIZE = 2 UC_PROT_NONE = 0 UC_PROT_READ = 1 From bf7dc4293b7711a89938996c325439255bc89061 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 6 Mar 2016 17:27:50 +0800 Subject: [PATCH 036/149] python: README -> README.md in setup.py --- bindings/python/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/setup.py b/bindings/python/setup.py index 66ea8ab0..8c44f470 100755 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -63,7 +63,7 @@ def copy_sources(): src.extend(glob.glob("../../Makefile")) src.extend(glob.glob("../../LICENSE*")) - src.extend(glob.glob("../../README")) + src.extend(glob.glob("../../README.md")) src.extend(glob.glob("../../*.TXT")) src.extend(glob.glob("../../RELEASE_NOTES")) src.extend(glob.glob("../../make.sh")) From 0950f2e18b54acc20062bbd69e21a0f7e31204ce Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 6 Mar 2016 17:28:32 +0800 Subject: [PATCH 037/149] python: 0.9 -> 1.0 in setup.py --- bindings/python/setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/setup.py b/bindings/python/setup.py index 8c44f470..6b98bae5 100755 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -24,7 +24,7 @@ PKG_NAME = 'unicorn' if os.path.exists(PATH_LIB64) and os.path.exists(PATH_LIB32): PKG_NAME = 'unicorn-windows' -VERSION = '0.9' +VERSION = '1.0' SYSTEM = sys.platform # virtualenv breaks import, but get_python_lib() will work. From eb5a7624526cece15e43353e73b67e5f334abefe Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 6 Mar 2016 21:21:39 +0800 Subject: [PATCH 038/149] python: add __version__ --- bindings/python/unicorn/__init__.py | 2 +- bindings/python/unicorn/unicorn.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/bindings/python/unicorn/__init__.py b/bindings/python/unicorn/__init__.py index 3f63904c..9d2b717c 100644 --- a/bindings/python/unicorn/__init__.py +++ b/bindings/python/unicorn/__init__.py @@ -1,4 +1,4 @@ # Unicorn Python bindings, by Nguyen Anh Quynnh from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const from .unicorn_const import * -from .unicorn import Uc, uc_version, uc_arch_supported, version_bind, debug, UcError +from .unicorn import Uc, uc_version, uc_arch_supported, version_bind, debug, UcError, __version__ diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 3d784368..989d985f 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -81,6 +81,8 @@ if _found == False: raise ImportError("ERROR: fail to load the dynamic library.") +__version__ = "%s.%s" %(UC_API_MAJOR, UC_API_MINOR) + # setup all the function prototype def _setup_prototype(lib, fname, restype, *argtypes): getattr(lib, fname).restype = restype From 338fb0e81b18b4909d969207ca4131ddb3ebc9ba Mon Sep 17 00:00:00 2001 From: Spl3en Date: Mon, 7 Mar 2016 17:52:08 +0100 Subject: [PATCH 039/149] Fix a typo in uc_hook_add documentation. --- include/unicorn/unicorn.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 23a17a4f..65d6aa53 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -459,7 +459,7 @@ uc_err uc_emu_stop(uc_engine *uc); @user_data: user-defined data. This will be passed to callback function in its last argument @user_data @begin: start address of the area where the callback is effect (inclusive) - @begin: end address of the area where the callback is effect (inclusive) + @end: end address of the area where the callback is effect (inclusive) NOTE 1: the callback is called only if related address is in range [@begin, @end] NOTE 2: if @begin > @end, callback is called whenever this hook type is triggered @...: variable arguments (depending on @type) From 9d9056c4747c404f6c460e8c779cda407aff1df7 Mon Sep 17 00:00:00 2001 From: Hoang-Vu Dang Date: Mon, 7 Mar 2016 12:22:20 -0600 Subject: [PATCH 040/149] Add a license for regression tests --- tests/regress/LICENSE | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 tests/regress/LICENSE diff --git a/tests/regress/LICENSE b/tests/regress/LICENSE new file mode 100644 index 00000000..dceeb48a --- /dev/null +++ b/tests/regress/LICENSE @@ -0,0 +1,30 @@ +This is the software license for Unicorn regression tests. The regression tests +are written by several Unicorn contributors (See CREDITS.TXT) and maintained by +Hoang-Vu Dang + +Copyright (c) 2015, Unicorn contributers +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. +* Neither the name of the developer(s) nor the names of its + contributors may be used to endorse or promote products derived from this + software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. From 9c91a6ec28744d5140fd44d6de6af9ab7d190b93 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 8 Mar 2016 08:55:55 +0800 Subject: [PATCH 041/149] fix a typo in tests/regress/LICENSE --- tests/regress/LICENSE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/regress/LICENSE b/tests/regress/LICENSE index dceeb48a..dd85900f 100644 --- a/tests/regress/LICENSE +++ b/tests/regress/LICENSE @@ -2,7 +2,7 @@ This is the software license for Unicorn regression tests. The regression tests are written by several Unicorn contributors (See CREDITS.TXT) and maintained by Hoang-Vu Dang -Copyright (c) 2015, Unicorn contributers +Copyright (c) 2015, Unicorn contributors All rights reserved. Redistribution and use in source and binary forms, with or without From 86e2127af16dd332221d17bf73401ca4800485d5 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 8 Mar 2016 12:52:13 +0800 Subject: [PATCH 042/149] add Appveyor CI --- appveyor.yml | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml new file mode 100644 index 00000000..c854f49e --- /dev/null +++ b/appveyor.yml @@ -0,0 +1,27 @@ +version: 1.0-{build} + +platform: + - x64 + +environment: + global: + MSYS2_BASEVER: 20150512 + MSYS2_ARCH: x86_64 + matrix: + - HOST_ARCH_ARG: --host=x86_64-w64-mingw32 + ADD_PATH: /mingw64/bin + - HOST_ARCH_ARG: --host=i686-w64-mingw32 + ADD_PATH: /mingw32/bin + - HOST_ARCH_ARG: --enable-msvc + ADD_PATH: /mingw64/bin + +install: + - C:\"Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" + - appveyor DownloadFile "http://kent.dl.sourceforge.net/project/msys2/Base/%MSYS2_ARCH%/msys2-base-%MSYS2_ARCH%-%MSYS2_BASEVER%.tar.xz" -FileName "msys2.tar.xz" + - 7z x msys2.tar.xz + - 7z x msys2.tar > NUL + - msys64\usr\bin\bash -lc "" + - msys64\usr\bin\bash -lc "for i in {1..3}; do pacman --noconfirm -Suy python2 make pkg-config mingw-w64-x86_64-glib2 mingw-w64-x86_64-toolchain && break || sleep 15; done" + +build_script: + - ./make.sh cross-win64 From 861d5e1ad83501b83d4c61bc42041a34fb0bf76c Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 8 Mar 2016 13:06:16 +0800 Subject: [PATCH 043/149] fix appveyor.yml --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index c854f49e..db1e0861 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -24,4 +24,4 @@ install: - msys64\usr\bin\bash -lc "for i in {1..3}; do pacman --noconfirm -Suy python2 make pkg-config mingw-w64-x86_64-glib2 mingw-w64-x86_64-toolchain && break || sleep 15; done" build_script: - - ./make.sh cross-win64 + - make.sh cross-win64 From 276775f5cca809f54c90849a6356a350e6431d81 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 8 Mar 2016 13:41:24 +0800 Subject: [PATCH 044/149] more fix for Appveyor CI --- README.md | 1 + appveyor.yml | 2 -- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 0d8e7558..f57b1df6 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,7 @@ Unicorn Engine ============== [![Build Status](https://travis-ci.org/unicorn-engine/unicorn.svg?branch=master)](https://travis-ci.org/unicorn-engine/unicorn) +[![Build status](https://ci.appveyor.com/api/projects/status/kojr7bald748ba2x/branch/master?svg=true)](https://ci.appveyor.com/project/aquynh/unicorn/branch/master) Unicorn is a lightweight, multi-platform, multi-architecture CPU emulator framework based on [QEMU](http://qemu.org). diff --git a/appveyor.yml b/appveyor.yml index db1e0861..8d1c61e7 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,8 +12,6 @@ environment: ADD_PATH: /mingw64/bin - HOST_ARCH_ARG: --host=i686-w64-mingw32 ADD_PATH: /mingw32/bin - - HOST_ARCH_ARG: --enable-msvc - ADD_PATH: /mingw64/bin install: - C:\"Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" From 26261be2445c7c91917b981736913b76487d5084 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 9 Mar 2016 09:35:00 +0800 Subject: [PATCH 045/149] improve Appveyor config --- appveyor.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 8d1c61e7..790d37c8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -5,7 +5,6 @@ platform: environment: global: - MSYS2_BASEVER: 20150512 MSYS2_ARCH: x86_64 matrix: - HOST_ARCH_ARG: --host=x86_64-w64-mingw32 @@ -15,11 +14,7 @@ environment: install: - C:\"Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" - - appveyor DownloadFile "http://kent.dl.sourceforge.net/project/msys2/Base/%MSYS2_ARCH%/msys2-base-%MSYS2_ARCH%-%MSYS2_BASEVER%.tar.xz" -FileName "msys2.tar.xz" - - 7z x msys2.tar.xz - - 7z x msys2.tar > NUL - - msys64\usr\bin\bash -lc "" - - msys64\usr\bin\bash -lc "for i in {1..3}; do pacman --noconfirm -Suy python2 make pkg-config mingw-w64-x86_64-glib2 mingw-w64-x86_64-toolchain && break || sleep 15; done" + - C:\msys64\usr\bin\bash -lc "pacman --noconfirm -Suy python2 make pkg-config mingw-w64-x86_64-glib2 mingw-w64-x86_64-toolchain" build_script: - make.sh cross-win64 From dca32a875e14e35403c62c82c7c15f46c5ef450c Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 9 Mar 2016 09:54:09 +0800 Subject: [PATCH 046/149] appveyor: try without pacman installs --- appveyor.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 790d37c8..ffa5aa42 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -14,7 +14,6 @@ environment: install: - C:\"Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" - - C:\msys64\usr\bin\bash -lc "pacman --noconfirm -Suy python2 make pkg-config mingw-w64-x86_64-glib2 mingw-w64-x86_64-toolchain" build_script: - make.sh cross-win64 From 2cfe6fb9c0b74fa5e129b20819afbe7e05f4ce8f Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 9 Mar 2016 11:53:59 +0800 Subject: [PATCH 047/149] appveyor: no need to initialize MSVC env for Msys2 --- appveyor.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index ffa5aa42..cbc1c215 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -12,8 +12,5 @@ environment: - HOST_ARCH_ARG: --host=i686-w64-mingw32 ADD_PATH: /mingw32/bin -install: - - C:\"Program Files (x86)\Microsoft Visual Studio 12.0\VC\vcvarsall.bat" - build_script: - make.sh cross-win64 From ab5ed1504405448e3805c72ae42d4ded4cb88ba1 Mon Sep 17 00:00:00 2001 From: egberts Date: Wed, 16 Mar 2016 10:54:20 -0700 Subject: [PATCH 048/149] Issue #465 - Enhanced test for more scenarios; fixed some semantic bugs. --- tests/unit/test_hookcounts.c | 89 ++++++++++++++++++++++++++++++------ 1 file changed, 75 insertions(+), 14 deletions(-) diff --git a/tests/unit/test_hookcounts.c b/tests/unit/test_hookcounts.c index c0a5ca4a..113e1aac 100644 --- a/tests/unit/test_hookcounts.c +++ b/tests/unit/test_hookcounts.c @@ -6,6 +6,8 @@ #include "unicorn_test.h" #include +#define DEBUG 1 + #define OK(x) uc_assert_success(x) volatile int expected_instructions = 0; @@ -29,8 +31,8 @@ static void test_code_hook(uc_engine *uc, #ifdef DEBUG printf("instruction at 0x%"PRIx64": ", address); + uint8_t tmp[256]; if (!uc_mem_read(uc, address, tmp, size)) { - uint8_t tmp[256]; uint32_t i; for (i = 0; i < size; i++) { @@ -75,6 +77,7 @@ static void test_hook_count(uc_engine *uc, const uint8_t *code, int start_offset, + int code_length, int expected_instructions) { @@ -92,9 +95,15 @@ test_hook_count(uc_engine *uc, // write machine code to be emulated to memory OK(uc_mem_write(uc, address, code, expected_instructions)); +#ifdef DEBUG + printf("Address: %8.8lx\n", address); + printf("Start : %8.8lx\n", address + start_offset); + printf("End : %8.8lx\n", address + code_length); + printf("Count : %d\n", expected_instructions); +#endif OK(uc_emu_start(uc, - address, address+start_offset, + address+code_length, 0, expected_instructions)); @@ -106,7 +115,23 @@ test_hook_count(uc_engine *uc, /* Perform fine-grain emulation control of exactly 1 instruction */ -static void test_hook_count_1(void **state) +/* of 1-opcode code space*/ +static void test_hook_count_1_begin(void **state) +{ + uc_engine *uc = *state; + const uint8_t code[] = { + 0x41, // inc ECX @0x1000000 + }; + int code_length = sizeof(code)-1; + int start_offset = 0; + int ins_count = 1; + + test_hook_count(uc, code, start_offset, code_length, ins_count); +} + + +/* Perform fine-grain emulation control of exactly 1 instruction */ +static void test_hook_count_1_midpoint(void **state) { uc_engine *uc = *state; const uint8_t code[] = { @@ -116,11 +141,36 @@ static void test_hook_count_1(void **state) 0x41, // inc ECX @0x1000003 0x41, // inc ECX 0x41, // inc ECX - 0x42, // inc EDX @0x1000006 0x42, // inc EDX }; - test_hook_count(uc, code, 0, 1); + int code_length = sizeof(code); + int start_offset = code_length/2; + int ins_count = 1; + + test_hook_count(uc, code, start_offset, code_length, ins_count); +} + + +/* Perform fine-grain emulation control of exactly 1 instruction */ +static void test_hook_count_1_end(void **state) +{ + uc_engine *uc = *state; + 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 + }; + int code_length = sizeof(code); + int start_offset = code_length; + int ins_count = 1; + + test_hook_count(uc, code, start_offset, code_length, ins_count); } @@ -128,7 +178,6 @@ static void test_hook_count_1(void **state) /* varied instruction steps. */ static void test_hook_count_range(void **state) { - int i; uc_engine *uc = *state; const uint8_t code[] = { 0x41, // inc ECX @0x1000000 @@ -140,9 +189,14 @@ static void test_hook_count_range(void **state) 0x42, // inc EDX @0x1000006 0x42, // inc EDX }; - for (i = 2; i < 7; i++) + int code_length = sizeof(code); + int start_offset; + int ins_count = 2; + + for (start_offset = 2; start_offset < (code_length - ins_count); start_offset++) { - test_hook_count(uc, code, 1, i); + printf("Iteration %d\n", start_offset); + test_hook_count(uc, code, start_offset, code_length, ins_count); } } @@ -157,11 +211,14 @@ static void test_hook_count_end(void **state) 0x41, // inc ECX @0x1000003 0x41, // inc ECX 0x41, // inc ECX - 0x42, // inc EDX @0x1000006 0x42, // inc EDX }; - test_hook_count(uc, code, sizeof(code)-1, 1); + int code_length = sizeof(code); + int ins_count = 3; + int start_offset = sizeof(code) - ins_count; + + test_hook_count(uc, code, start_offset, code_length, ins_count); } @@ -175,19 +232,23 @@ static void test_hook_count_midpoint(void **state) 0x41, // inc ECX @0x1000003 0x41, // inc ECX 0x41, // inc ECX - 0x42, // inc EDX @0x1000006 0x42, // inc EDX }; - test_hook_count(uc, code, sizeof(code)/2, 2); - test_hook_count(uc, code, 2, sizeof(code)-2); + int code_length = sizeof(code); + int ins_count = 3; + int start_offset = 2; + + test_hook_count(uc, code, start_offset, code_length, ins_count); } int main(void) { const struct CMUnitTest tests[] = { - cmocka_unit_test_setup_teardown(test_hook_count_1, setup32, teardown), + cmocka_unit_test_setup_teardown(test_hook_count_1_begin, setup32, teardown), + cmocka_unit_test_setup_teardown(test_hook_count_1_midpoint, setup32, teardown), + cmocka_unit_test_setup_teardown(test_hook_count_1_end, setup32, teardown), cmocka_unit_test_setup_teardown(test_hook_count_range, setup32, teardown), cmocka_unit_test_setup_teardown(test_hook_count_midpoint, setup32, teardown), cmocka_unit_test_setup_teardown(test_hook_count_end, setup32, teardown), From 881360d60f1f4bcfe47b4402e0eed711ca474472 Mon Sep 17 00:00:00 2001 From: egberts Date: Wed, 16 Mar 2016 11:01:59 -0700 Subject: [PATCH 049/149] Issue #465 - Added test_hookcounts to .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index ae776b30..92832daa 100644 --- a/.gitignore +++ b/.gitignore @@ -139,6 +139,7 @@ test_multihook test_pc_change mem_fuzz test_x86_soft_paging +test_hookcounts ################# From ac21e74641188dce0d2f3edcb8ae13dc6eacb6a6 Mon Sep 17 00:00:00 2001 From: egberts Date: Wed, 16 Mar 2016 11:49:25 -0700 Subject: [PATCH 050/149] Issues #465 Pull Request #466 Added one more test case Fixed two test case into passing (for a total of 3 passing out of 7) --- tests/unit/test_hookcounts.c | 30 ++++++++++++++++++++++++++---- 1 file changed, 26 insertions(+), 4 deletions(-) diff --git a/tests/unit/test_hookcounts.c b/tests/unit/test_hookcounts.c index 113e1aac..61ef263a 100644 --- a/tests/unit/test_hookcounts.c +++ b/tests/unit/test_hookcounts.c @@ -93,12 +93,12 @@ test_hook_count(uc_engine *uc, OK(uc_mem_map(uc, address, MEMSIZE, UC_PROT_ALL)); // write machine code to be emulated to memory - OK(uc_mem_write(uc, address, code, expected_instructions)); + OK(uc_mem_write(uc, address, code, code_length)); #ifdef DEBUG printf("Address: %8.8lx\n", address); printf("Start : %8.8lx\n", address + start_offset); - printf("End : %8.8lx\n", address + code_length); + printf("End : %8.8lx\n", address + code_length - 1); printf("Count : %d\n", expected_instructions); #endif OK(uc_emu_start(uc, @@ -122,7 +122,7 @@ static void test_hook_count_1_begin(void **state) const uint8_t code[] = { 0x41, // inc ECX @0x1000000 }; - int code_length = sizeof(code)-1; + int code_length = sizeof(code); int start_offset = 0; int ins_count = 1; @@ -167,7 +167,7 @@ static void test_hook_count_1_end(void **state) 0x42, // inc EDX }; int code_length = sizeof(code); - int start_offset = code_length; + int start_offset = code_length - 1; int ins_count = 1; test_hook_count(uc, code, start_offset, code_length, ins_count); @@ -222,6 +222,27 @@ static void test_hook_count_end(void **state) } +static void test_hook_count_begins(void **state) +{ + uc_engine *uc = *state; + 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 + }; + int code_length = sizeof(code); + int ins_count = 3; + int start_offset = 0; + + test_hook_count(uc, code, start_offset, code_length, ins_count); +} + + static void test_hook_count_midpoint(void **state) { uc_engine *uc = *state; @@ -249,6 +270,7 @@ int main(void) cmocka_unit_test_setup_teardown(test_hook_count_1_begin, setup32, teardown), cmocka_unit_test_setup_teardown(test_hook_count_1_midpoint, setup32, teardown), cmocka_unit_test_setup_teardown(test_hook_count_1_end, setup32, teardown), + cmocka_unit_test_setup_teardown(test_hook_count_begins, setup32, teardown), cmocka_unit_test_setup_teardown(test_hook_count_range, setup32, teardown), cmocka_unit_test_setup_teardown(test_hook_count_midpoint, setup32, teardown), cmocka_unit_test_setup_teardown(test_hook_count_end, setup32, teardown), From 0af4baac31ea6babc1a07a9ec928df2082cca970 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 17 Mar 2016 17:49:22 +0800 Subject: [PATCH 051/149] unit: fix warnings in printing uint64_t in test_hookcounts.c --- tests/unit/test_hookcounts.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/unit/test_hookcounts.c b/tests/unit/test_hookcounts.c index 61ef263a..d5d807f9 100644 --- a/tests/unit/test_hookcounts.c +++ b/tests/unit/test_hookcounts.c @@ -96,9 +96,9 @@ test_hook_count(uc_engine *uc, OK(uc_mem_write(uc, address, code, code_length)); #ifdef DEBUG - printf("Address: %8.8lx\n", address); - printf("Start : %8.8lx\n", address + start_offset); - printf("End : %8.8lx\n", address + code_length - 1); + printf("Address: %"PRIx64"\n", address); + printf("Start : %"PRIx64"\n", address + start_offset); + printf("End : %"PRIx64"\n", address + code_length - 1); printf("Count : %d\n", expected_instructions); #endif OK(uc_emu_start(uc, From 25864b589de23e929de9488fae4296d378b4a505 Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Fri, 18 Mar 2016 07:44:05 +0100 Subject: [PATCH 052/149] Bugfix: uc_x86_mmr has no attribute limits --- bindings/python/unicorn/unicorn.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 7b592a7c..dc1a2ac9 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -229,7 +229,7 @@ class Uc(object): status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg)) if status != UC_ERR_OK: raise UcError(status) - return (reg.selector,reg.base, reg.limits, reg.flags) + return (reg.selector,reg.base, reg.limit, reg.flags) if reg_id in range(x86_const.UC_X86_REG_FP0,x86_const.UC_X86_REG_FP0+8): reg = uc_x86_float80() status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg)) @@ -255,7 +255,7 @@ class Uc(object): reg = uc_x86_mmr() reg.selector=value[0] reg.base=value[1] - reg.limits=value[2] + reg.limit=value[2] reg.flags=value[3] if reg_id in range(x86_const.UC_X86_REG_FP0, x86_const.UC_X86_REG_FP0+8): reg = uc_x86_float80() From ad6bb8c9f8f710fefe35c0d7bc9556e68b184714 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 20 Mar 2016 01:54:37 +0800 Subject: [PATCH 053/149] unit: fix test_hookcounts.c --- tests/unit/test_hookcounts.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/tests/unit/test_hookcounts.c b/tests/unit/test_hookcounts.c index d5d807f9..e744f142 100644 --- a/tests/unit/test_hookcounts.c +++ b/tests/unit/test_hookcounts.c @@ -24,7 +24,7 @@ static void test_code_hook(uc_engine *uc, { ++total_instructions; - if (total_instructions > expected_instructions) + if (total_instructions == expected_instructions) { uc_emu_stop(uc); } @@ -78,13 +78,13 @@ test_hook_count(uc_engine *uc, const uint8_t *code, int start_offset, int code_length, - int expected_instructions) + int count) { #define BASEADDR 0x1000000 #define MEMSIZE (2 * 1024 * 1024) - uint64_t address = BASEADDR + (expected_instructions * MEMSIZE); + uint64_t address = BASEADDR + (count * MEMSIZE); total_instructions = 0; #undef BASEADDR @@ -99,13 +99,14 @@ test_hook_count(uc_engine *uc, printf("Address: %"PRIx64"\n", address); printf("Start : %"PRIx64"\n", address + start_offset); printf("End : %"PRIx64"\n", address + code_length - 1); - printf("Count : %d\n", expected_instructions); + printf("Count : %d\n", count); #endif + expected_instructions = count; OK(uc_emu_start(uc, address+start_offset, address+code_length, 0, - expected_instructions)); + count)); assert_int_equal(expected_instructions, total_instructions); From 859111f8f58e9f87eda3b97ba67c6423e5263f69 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 20 Mar 2016 18:15:41 +0800 Subject: [PATCH 054/149] x86: return immediately after handling FPSW/FPCW/FPTAG registers --- qemu/target-i386/unicorn.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 6d149ece..302f04c9 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -148,7 +148,7 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) floatx80 reg = X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d; cpu_get_fp80(value, value+sizeof(uint64_t), reg); } - break; + return 0; case UC_X86_REG_FPSW: { uint16_t fpus = X86_CPU(uc, mycpu)->env.fpus; @@ -156,10 +156,10 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) fpus |= ( X86_CPU(uc, mycpu)->env.fpstt & 0x7 ) << 11; *(uint16_t*) value = fpus; } - break; + return 0; case UC_X86_REG_FPCW: *(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc; - break; + return 0; case UC_X86_REG_FPTAG: { #define EXPD(fp) (fp.l.upper & 0x7fff) @@ -189,7 +189,7 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) } *(uint16_t*) value = fptag; } - break; + return 0; } switch(uc->mode) { @@ -634,17 +634,17 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) uint16_t upper = *(uint16_t*) (value + sizeof(uint64_t)); X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d = cpu_set_fp80(mant, upper); } - break; + return 0; case UC_X86_REG_FPSW: { uint16_t fpus = *(uint16_t*) value; X86_CPU(uc, mycpu)->env.fpus = fpus & ~0x3800; X86_CPU(uc, mycpu)->env.fpstt = (fpus >> 11) & 0x7; } - break; + return 0; case UC_X86_REG_FPCW: X86_CPU(uc, mycpu)->env.fpuc = *(uint16_t *)value; - break; + return 0; case UC_X86_REG_FPTAG: { int i; @@ -653,6 +653,8 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) X86_CPU(uc, mycpu)->env.fptags[i] = ((fptag & 3) == 3); fptag >>= 2; } + + return 0; } break; } From d2ffea0e88c82fb97322689fb320f176f588948a Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 21 Mar 2016 13:02:17 +0800 Subject: [PATCH 055/149] Makefile: do not recompile samples/ for install target --- Makefile | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 5bd94a93..ad237953 100644 --- a/Makefile +++ b/Makefile @@ -224,7 +224,6 @@ endif compile_lib: config qemu/config-host.h-timestamp rm -rf lib$(LIBNAME)* $(LIBNAME)*.lib $(LIBNAME)*.dll cyg$(LIBNAME)*.dll && cd qemu && $(MAKE) -j 4 $(MAKE) unicorn - cd samples && $(MAKE) clean unicorn: $(LIBRARY) $(ARCHIVE) @@ -266,7 +265,7 @@ test: all $(MAKE) -C tests/unit test -install: all $(PKGCFGF) +install: compile_lib $(PKGCFGF) mkdir -p $(DESTDIR)$(LIBDIR) ifeq ($(UNICORN_SHARED),yes) ifeq ($(IS_CYGWIN),1) From 5e72ce39f0b6a325ab315b7aa8d56de72c3c9bf5 Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Tue, 22 Mar 2016 12:17:23 +0100 Subject: [PATCH 056/149] ruby binding added --- bindings/README | 1 + bindings/const_generator.py | 16 + bindings/ruby/Makefile | 11 + bindings/ruby/README.md | 20 + bindings/ruby/sample_x86.rb | 511 ++++++ bindings/ruby/unicorn_gem/Gemfile | 3 + bindings/ruby/unicorn_gem/Rakefile | 2 + bindings/ruby/unicorn_gem/ext/extconf.rb | 8 + bindings/ruby/unicorn_gem/ext/unicorn.c | 454 +++++ bindings/ruby/unicorn_gem/ext/unicorn.h | 34 + .../unicorn_gem/lib/unicorn/arm64_const.rb | 277 +++ .../ruby/unicorn_gem/lib/unicorn/arm_const.rb | 128 ++ .../unicorn_gem/lib/unicorn/m68k_const.rb | 27 + .../unicorn_gem/lib/unicorn/mips_const.rb | 198 ++ .../unicorn_gem/lib/unicorn/sparc_const.rb | 99 + .../unicorn_gem/lib/unicorn/unicorn_const.rb | 98 + .../ruby/unicorn_gem/lib/unicorn/version.rb | 3 + .../ruby/unicorn_gem/lib/unicorn/x86_const.rb | 1598 +++++++++++++++++ bindings/ruby/unicorn_gem/pkg/.gitignore | 10 + .../ruby/unicorn_gem/pkg/unicorn-0.9.0.gem | Bin 0 -> 20992 bytes bindings/ruby/unicorn_gem/unicorn.gemspec | 21 + 21 files changed, 3519 insertions(+) create mode 100644 bindings/ruby/Makefile create mode 100644 bindings/ruby/README.md create mode 100644 bindings/ruby/sample_x86.rb create mode 100644 bindings/ruby/unicorn_gem/Gemfile create mode 100644 bindings/ruby/unicorn_gem/Rakefile create mode 100644 bindings/ruby/unicorn_gem/ext/extconf.rb create mode 100644 bindings/ruby/unicorn_gem/ext/unicorn.c create mode 100644 bindings/ruby/unicorn_gem/ext/unicorn.h create mode 100644 bindings/ruby/unicorn_gem/lib/unicorn/arm64_const.rb create mode 100644 bindings/ruby/unicorn_gem/lib/unicorn/arm_const.rb create mode 100644 bindings/ruby/unicorn_gem/lib/unicorn/m68k_const.rb create mode 100644 bindings/ruby/unicorn_gem/lib/unicorn/mips_const.rb create mode 100644 bindings/ruby/unicorn_gem/lib/unicorn/sparc_const.rb create mode 100644 bindings/ruby/unicorn_gem/lib/unicorn/unicorn_const.rb create mode 100644 bindings/ruby/unicorn_gem/lib/unicorn/version.rb create mode 100644 bindings/ruby/unicorn_gem/lib/unicorn/x86_const.rb create mode 100644 bindings/ruby/unicorn_gem/pkg/.gitignore create mode 100644 bindings/ruby/unicorn_gem/pkg/unicorn-0.9.0.gem create mode 100644 bindings/ruby/unicorn_gem/unicorn.gemspec diff --git a/bindings/README b/bindings/README index c3abec91..4c4a2430 100644 --- a/bindings/README +++ b/bindings/README @@ -7,6 +7,7 @@ The following bindings are contributed by community. - Go binding: by Ryan Hileman. - .NET binding: by Antonio Parata. - MSVC binding: by Zak Escano +- Ruby binding: by Sascha Schirra More bindings created & maintained externally by community are available as follows. diff --git a/bindings/const_generator.py b/bindings/const_generator.py index 826340b2..c224d082 100644 --- a/bindings/const_generator.py +++ b/bindings/const_generator.py @@ -24,6 +24,22 @@ template = { 'comment_open': '#', 'comment_close': '', }, + 'ruby': { + 'header': "# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [%s_const.rb]\n\nmodule Unicorn\n", + 'footer': "end", + 'line_format': '\tUC_%s = %s\n', + 'out_file': './ruby/unicorn_gem/lib/unicorn/%s_const.rb', + # prefixes for constant filenames of all archs - case sensitive + 'arm.h': 'arm', + 'arm64.h': 'arm64', + 'mips.h': 'mips', + 'x86.h': 'x86', + 'sparc.h': 'sparc', + 'm68k.h': 'm68k', + 'unicorn.h': 'unicorn', + 'comment_open': '#', + 'comment_close': '', + }, 'go': { 'header': "package unicorn\n// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [%s_const.go]\nconst (\n", 'footer': ")", diff --git a/bindings/ruby/Makefile b/bindings/ruby/Makefile new file mode 100644 index 00000000..6e801fc6 --- /dev/null +++ b/bindings/ruby/Makefile @@ -0,0 +1,11 @@ +# Ruby binding for Unicorn engine. Sascha Schirra + +.PHONY: gen_const + +install: + $(MAKE) gen_const + cd unicorn_gem && rake build + cd unicorn_gem && gem install --local pkg/unicorn-0.9.0.gem + +gen_const: + cd .. && python const_generator.py ruby diff --git a/bindings/ruby/README.md b/bindings/ruby/README.md new file mode 100644 index 00000000..c8bf4566 --- /dev/null +++ b/bindings/ruby/README.md @@ -0,0 +1,20 @@ +Installation +============ + +1. Softwarerequirements + +Linux +- ruby >= 1.9.3 +- rubygems +- make +- gcc + +Mac OS +- ruby >= 1.9.3 +- rubygems +- make +- XCode + +2. Install unicorn + + diff --git a/bindings/ruby/sample_x86.rb b/bindings/ruby/sample_x86.rb new file mode 100644 index 00000000..e951927b --- /dev/null +++ b/bindings/ruby/sample_x86.rb @@ -0,0 +1,511 @@ +#!/usr/bin/env ruby +require 'unicorn' +require 'unicorn/x86_const' + +include Unicorn + +X86_CODE32 = "\x41\x4a" # INC ecx; DEC edx +X86_CODE32_LOOP = "\x41\x4a\xeb\xfe" # INC ecx; DEC edx; JMP self-loop +X86_CODE32_MEM_READ = "\x8B\x0D\xAA\xAA\xAA\xAA\x41\x4a" # mov ecx,[0xaaaaaaaa]; INC ecx; DEC edx +X86_CODE32_MEM_WRITE = "\x89\x0D\xAA\xAA\xAA\xAA\x41\x4a" # mov [0xaaaaaaaa], ecx; INC ecx; DEC edx +X86_CODE64 = "\x41\xBC\x3B\xB0\x28\x2A\x49\x0F\xC9\x90\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9\x4D\x29\xF4\x49\x81\xC9\xF6\x8A\xC6\x53\x4D\x87\xED\x48\x0F\xAD\xD2\x49\xF7\xD4\x48\xF7\xE1\x4D\x19\xC5\x4D\x89\xC5\x48\xF7\xD6\x41\xB8\x4F\x8D\x6B\x59\x4D\x87\xD0\x68\x6A\x1E\x09\x3C\x59" +X86_CODE32_INOUT = "\x41\xE4\x3F\x4a\xE6\x46\x43" # INC ecx; IN AL, 0x3f; DEC edx; OUT 0x46, AL; INC ebx +X86_CODE64_SYSCALL = "\x0f\x05" # SYSCALL +X86_CODE16 = "\x00\x00" # add byte ptr [bx + si], al + +# memory address where emulation starts +ADDRESS = 0x1000000 + + +# callback for tracing basic blocks +HOOK_BLOCK = Proc.new do |uc, address, size, user_data | + puts(">>> Tracing basic block at 0x%x, block size = 0x%x" % [address, size]) +end + +# callback for tracing instructions +HOOK_CODE = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing instruction at 0x%x, instruction size = %u" % [address, size]) +end + + +# callback for tracing invalid memory access (READ or WRITE) +HOOK_MEM_INVALID = lambda do |uc, access, address, size, value, user_data| + if access == UC_MEM_WRITE_UNMAPPED + puts(">>> Missing memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" % [address, size, value]) + # map this memory in with 2MB in size + uc.mem_map(0xaaaa0000, 2 * 1024*1024) + # return True to indicate we want to continue emulation + return true + else + puts(">>> Missing memory is being READ at 0x%x" % address) + # return False to indicate we want to stop emulation + return false + end +end + + +# callback for tracing memory access (READ or WRITE) +HOOK_MEM_ACCESS = Proc.new do |uc, access, address, size, value, user_data| + if access == UC_MEM_WRITE + puts(">>> Memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" % [address, size, value]) + else # READ + puts(">>> Memory is being READ at 0x%x, data size = %u" % [address, size]) + end +end + +# callback for IN instruction +HOOK_IN = lambda do |uc, port, size, user_data| + eip = uc.reg_read(UC_X86_REG_EIP) + puts("--- reading from port 0x%x, size: %u, address: 0x%x" % [port, size, eip]) + if size == 1 + # read 1 byte to AL + return 0xf1 + end + if size == 2 + # read 2 byte to AX + return 0xf2 + end + if size == 4 + # read 4 byte to EAX + return 0xf4 + end + # we should never reach here + return 0 +end + + +# callback for OUT instruction +HOOK_OUT = Proc.new do |uc, port, size, value, user_data| + + eip = uc.reg_read(UC_X86_REG_EIP) + puts("--- writing to port 0x%x, size: %u, value: 0x%x, address: 0x%x" % [port, size, value, eip]) + + # confirm that value is indeed the value of AL/AX/EAX + v = 0 + if size == 1 + # read 1 byte in AL + v = uc.reg_read(UC_X86_REG_AL) + end + if size == 2 + # read 2 bytes in AX + v = uc.reg_read(UC_X86_REG_AX) + end + if size == 4 + # read 4 bytes in EAX + v = uc.reg_read(UC_X86_REG_EAX) + end + + puts("--- register value = 0x%x" %v) +end + + +# Test X86 32 bit +def test_i386() + puts("Emulate i386 code") + begin + # Initialize emulator in X86-32bit mode + mu = Uc.new UC_ARCH_X86, UC_MODE_32 + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, X86_CODE32) + + # initialize machine registers + mu.reg_write(UC_X86_REG_ECX, 0x1234) + mu.reg_write(UC_X86_REG_EDX, 0x7890) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, HOOK_BLOCK) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, HOOK_CODE) + mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED, HOOK_MEM_INVALID) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + X86_CODE32.bytesize) + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + r_ecx = mu.reg_read(UC_X86_REG_ECX) + r_edx = mu.reg_read(UC_X86_REG_EDX) + puts(">>> ECX = 0x%x" % r_ecx) + puts(">>> EDX = 0x%x" % r_edx) + + # read from memory + tmp = mu.mem_read(ADDRESS, 2) + print(">>> Read 2 bytes from [0x%x] =" % (ADDRESS)) + tmp.each_byte { |i| print(" 0x%x" % i) } + + + puts + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +def test_i386_loop() + puts("Emulate i386 code with infinite loop - wait for 2 seconds then stop emulation") + begin + # Initialize emulator in X86-32bit mode + mu = Uc.new UC_ARCH_X86, UC_MODE_32 + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, X86_CODE32_LOOP) + + # initialize machine registers + mu.reg_write(UC_X86_REG_ECX, 0x1234) + mu.reg_write(UC_X86_REG_EDX, 0x7890) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + X86_CODE32_LOOP.bytesize, 2 * UC_SECOND_SCALE) + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + r_ecx = mu.reg_read(UC_X86_REG_ECX) + r_edx = mu.reg_read(UC_X86_REG_EDX) + puts(">>> ECX = 0x%x" % r_ecx) + puts(">>> EDX = 0x%x" % r_edx) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +def test_i386_invalid_mem_read() + puts("Emulate i386 code that read from invalid memory") + begin + # Initialize emulator in X86-32bit mode + mu = Uc.new UC_ARCH_X86, UC_MODE_32 + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, X86_CODE32_MEM_READ) + + # initialize machine registers + mu.reg_write(UC_X86_REG_ECX, 0x1234) + mu.reg_write(UC_X86_REG_EDX, 0x7890) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, HOOK_BLOCK) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, HOOK_CODE) + + begin + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + X86_CODE32_MEM_READ.bytesize) + rescue UcError => e + puts("ERROR: %s" % e) + end + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + r_ecx = mu.reg_read(UC_X86_REG_ECX) + r_edx = mu.reg_read(UC_X86_REG_EDX) + puts(">>> ECX = 0x%x" % r_ecx) + puts(">>> EDX = 0x%x" % r_edx) + + rescue UcError => e + print("ERROR: %s" % e) + end +end + + +def test_i386_invalid_mem_write() + puts("Emulate i386 code that write to invalid memory") + begin + # Initialize emulator in X86-32bit mode + mu = Uc.new UC_ARCH_X86, UC_MODE_32 + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, X86_CODE32_MEM_WRITE) + + # initialize machine registers + mu.reg_write(UC_X86_REG_ECX, 0x1234) + mu.reg_write(UC_X86_REG_EDX, 0x7890) + + # tracing all basic blocks with customized callback + #mu.hook_add(UC_HOOK_BLOCK, HOOK_BLOCK) + + # tracing all instructions with customized callback + #mu.hook_add(UC_HOOK_CODE, HOOK_CODE) + + # intercept invalid memory events + mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, HOOK_MEM_INVALID) + + begin + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + X86_CODE32_MEM_WRITE.bytesize) + rescue UcError => e + puts "ERROR: %s" % e + end + + # now print out some registers + puts ">>> Emulation done. Below is the CPU context" + + r_ecx = mu.reg_read(UC_X86_REG_ECX) + r_edx = mu.reg_read(UC_X86_REG_EDX) + puts ">>> ECX = 0x%x" % r_ecx + puts ">>> EDX = 0x%x" % r_edx + + begin + # read from memory + print ">>> Read 4 bytes from [0x%x] = " % (0xaaaaaaaa) + tmp = mu.mem_read(0xaaaaaaaa, 4) + tmp.each_byte { |i| print(" 0x%x" % i) } + puts + + print ">>> Read 4 bytes from [0x%x] = " % 0xffffffaa + tmp = mu.mem_read(0xffffffaa, 4) + tmp.each_byte { |i| puts(" 0x%x" % i) } + puts + + rescue UcError => e + puts "ERROR: %s" % e + end + + rescue UcError => e + puts "ERROR: %s" % e + end +end + +# Test X86 32 bit with IN/OUT instruction +def test_i386_inout() + puts("Emulate i386 code with IN/OUT instructions") + begin + # Initialize emulator in X86-32bit mode + mu = Uc.new UC_ARCH_X86, UC_MODE_32 + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, X86_CODE32_INOUT) + + # initialize machine registers + mu.reg_write(UC_X86_REG_EAX, 0x1234) + mu.reg_write(UC_X86_REG_ECX, 0x6789) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, HOOK_BLOCK) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, HOOK_CODE) + + # handle IN & OUT instruction + mu.hook_add(UC_HOOK_INSN, HOOK_IN, nil, 1, 0, UC_X86_INS_IN) + mu.hook_add(UC_HOOK_INSN, HOOK_OUT, nil, 1, 0, UC_X86_INS_OUT) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + X86_CODE32_INOUT.bytesize) + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + r_ecx = mu.reg_read(UC_X86_REG_ECX) + r_eax = mu.reg_read(UC_X86_REG_EAX) + puts ">>> EAX = 0x%x" % r_eax + puts ">>> ECX = 0x%x" % r_ecx + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +def test_x86_64() + puts("Emulate x86_64 code") + begin + # Initialize emulator in X86-64bit mode + mu = Uc.new UC_ARCH_X86, UC_MODE_64 + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, X86_CODE64) + + # initialize machine registers + mu.reg_write(UC_X86_REG_RAX, 0x71f3029efd49d41d) + mu.reg_write(UC_X86_REG_RBX, 0xd87b45277f133ddb) + mu.reg_write(UC_X86_REG_RCX, 0xab40d1ffd8afc461) + mu.reg_write(UC_X86_REG_RDX, 0x919317b4a733f01) + mu.reg_write(UC_X86_REG_RSI, 0x4c24e753a17ea358) + mu.reg_write(UC_X86_REG_RDI, 0xe509a57d2571ce96) + mu.reg_write(UC_X86_REG_R8, 0xea5b108cc2b9ab1f) + mu.reg_write(UC_X86_REG_R9, 0x19ec097c8eb618c1) + mu.reg_write(UC_X86_REG_R10, 0xec45774f00c5f682) + mu.reg_write(UC_X86_REG_R11, 0xe17e9dbec8c074aa) + mu.reg_write(UC_X86_REG_R12, 0x80f86a8dc0f6d457) + mu.reg_write(UC_X86_REG_R13, 0x48288ca5671c5492) + mu.reg_write(UC_X86_REG_R14, 0x595f72f6e4017f6e) + mu.reg_write(UC_X86_REG_R15, 0x1efd97aea331cccc) + + # setup stack + mu.reg_write(UC_X86_REG_RSP, ADDRESS + 0x200000) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, HOOK_BLOCK) + + # tracing all instructions in range [ADDRESS, ADDRESS+20] + mu.hook_add(UC_HOOK_CODE, HOOK_CODE, 0, ADDRESS, ADDRESS+20) + + # tracing all memory READ & WRITE access + mu.hook_add(UC_HOOK_MEM_WRITE, HOOK_MEM_ACCESS) + mu.hook_add(UC_HOOK_MEM_READ, HOOK_MEM_ACCESS) + # actually you can also use READ_WRITE to trace all memory access + #mu.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, hook_mem_access) + + begin + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + X86_CODE64.bytesize) + rescue UcError => e + puts("ERROR: %s" % e) + end + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + rax = mu.reg_read(UC_X86_REG_RAX) + rbx = mu.reg_read(UC_X86_REG_RBX) + rcx = mu.reg_read(UC_X86_REG_RCX) + rdx = mu.reg_read(UC_X86_REG_RDX) + rsi = mu.reg_read(UC_X86_REG_RSI) + rdi = mu.reg_read(UC_X86_REG_RDI) + r8 = mu.reg_read(UC_X86_REG_R8) + r9 = mu.reg_read(UC_X86_REG_R9) + r10 = mu.reg_read(UC_X86_REG_R10) + r11 = mu.reg_read(UC_X86_REG_R11) + r12 = mu.reg_read(UC_X86_REG_R12) + r13 = mu.reg_read(UC_X86_REG_R13) + r14 = mu.reg_read(UC_X86_REG_R14) + r15 = mu.reg_read(UC_X86_REG_R15) + + puts(">>> RAX = %d" % rax) + puts(">>> RBX = %d" % rbx) + puts(">>> RCX = %d" % rcx) + puts(">>> RDX = %d" % rdx) + puts(">>> RSI = %d" % rsi) + puts(">>> RDI = %d" % rdi) + puts(">>> R8 = %d" % r8) + puts(">>> R9 = %d" % r9) + puts(">>> R10 = %d" % r10) + puts(">>> R11 = %d" % r11) + puts(">>> R12 = %d" % r12) + puts(">>> R13 = %d" % r13) + puts(">>> R14 = %d" % r14) + puts(">>> R15 = %d" % r15) + #BUG + mu.emu_start(ADDRESS, ADDRESS + X86_CODE64.bytesize) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +def test_x86_64_syscall() + puts("Emulate x86_64 code with 'syscall' instruction") + begin + # Initialize emulator in X86-64bit mode + mu = Uc.new UC_ARCH_X86, UC_MODE_64 + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, X86_CODE64_SYSCALL) + + hook_syscall = Proc.new do |mu, user_data| + rax = mu.reg_read(UC_X86_REG_RAX) + if rax == 0x100 + mu.reg_write(UC_X86_REG_RAX, 0x200) + else + puts('ERROR: was not expecting rax=%d in syscall' % rax) + end + end + + # hook interrupts for syscall + mu.hook_add(UC_HOOK_INSN, hook_syscall, nil, 1, 0, UC_X86_INS_SYSCALL) + + # syscall handler is expecting rax=0x100 + mu.reg_write(UC_X86_REG_RAX, 0x100) + + begin + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + X86_CODE64_SYSCALL.bytesize) + rescue UcError => e + puts("ERROR: %s" % e) + end + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + rax = mu.reg_read(UC_X86_REG_RAX) + puts(">>> RAX = 0x%x" % rax) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +def test_x86_16() + puts("Emulate x86 16-bit code") + begin + # Initialize emulator in X86-16bit mode + mu = Uc.new UC_ARCH_X86, UC_MODE_16 + + # map 8KB memory for this emulation + mu.mem_map(0, 8 * 1024) + + # set CPU registers + mu.reg_write(UC_X86_REG_EAX, 7) + mu.reg_write(UC_X86_REG_EBX, 5) + mu.reg_write(UC_X86_REG_ESI, 6) + + # write machine code to be emulated to memory + mu.mem_write(0, X86_CODE16) + + # emulate machine code in infinite time + mu.emu_start(0, X86_CODE16.bytesize) + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + tmp = mu.mem_read(11, 1) + puts("[0x%x] = 0x%x" % [11, tmp[0].ord]) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + + test_i386() + puts("=" * 20) + test_i386_loop() + puts("=" * 20) + test_i386_invalid_mem_read() + puts("=" * 20) + test_i386_invalid_mem_write() + puts("=" * 20) + test_i386_inout() + puts("=" * 20) + test_x86_64() + puts("=" * 20) + test_x86_64_syscall() + puts("=" * 20) + test_x86_16() diff --git a/bindings/ruby/unicorn_gem/Gemfile b/bindings/ruby/unicorn_gem/Gemfile new file mode 100644 index 00000000..fa75df15 --- /dev/null +++ b/bindings/ruby/unicorn_gem/Gemfile @@ -0,0 +1,3 @@ +source 'https://rubygems.org' + +gemspec diff --git a/bindings/ruby/unicorn_gem/Rakefile b/bindings/ruby/unicorn_gem/Rakefile new file mode 100644 index 00000000..43022f71 --- /dev/null +++ b/bindings/ruby/unicorn_gem/Rakefile @@ -0,0 +1,2 @@ +require "bundler/gem_tasks" +task :default => :spec diff --git a/bindings/ruby/unicorn_gem/ext/extconf.rb b/bindings/ruby/unicorn_gem/ext/extconf.rb new file mode 100644 index 00000000..cdbfc837 --- /dev/null +++ b/bindings/ruby/unicorn_gem/ext/extconf.rb @@ -0,0 +1,8 @@ +require 'mkmf' + +extension_name = 'unicorn' + +dir_config(extension_name) +have_library('unicorn') + +create_makefile(extension_name) \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/ext/unicorn.c b/bindings/ruby/unicorn_gem/ext/unicorn.c new file mode 100644 index 00000000..09d1d580 --- /dev/null +++ b/bindings/ruby/unicorn_gem/ext/unicorn.c @@ -0,0 +1,454 @@ +/* + +Ruby bindings for the Unicorn Emulator Engine + +Copyright(c) 2016 Sascha Schirra + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ +#include "ruby.h" +#include +#include +#include "unicorn.h" + +VALUE UnicornModule = Qnil; +VALUE UcClass = Qnil; +VALUE UcError = Qnil; + + + +void Init_unicorn() { + rb_require("unicorn/unicorn_const"); + UnicornModule = rb_define_module("Unicorn"); + UcError = rb_define_class_under(UnicornModule, "UcError", rb_eStandardError); + + UcClass = rb_define_class_under(UnicornModule, "Uc", rb_cObject); + rb_define_method(UcClass, "initialize", m_uc_initialize, 2); + rb_define_method(UcClass, "emu_start", m_uc_emu_start, -1); + rb_define_method(UcClass, "emu_stop", m_uc_emu_stop, 0); + rb_define_method(UcClass, "reg_read", m_uc_reg_read, 1); + rb_define_method(UcClass, "reg_write", m_uc_reg_write, 2); + rb_define_method(UcClass, "mem_read", m_uc_mem_read, 2); + rb_define_method(UcClass, "mem_write", m_uc_mem_write, 2); + rb_define_method(UcClass, "mem_map", m_uc_mem_map, -1); + //rb_define_method(UcClass, "mem_map_ptr", m_uc_mem_map_pzt, 4); + rb_define_method(UcClass, "mem_unmap", m_uc_mem_unmap, 2); + rb_define_method(UcClass, "mem_protect", m_uc_mem_protect, 3); + rb_define_method(UcClass, "hook_add", m_uc_hook_add, -1); + rb_define_method(UcClass, "hook_del", m_uc_hook_del, 1); + rb_define_method(UcClass, "query", m_uc_hook_del, 1); + + +} + +VALUE m_uc_initialize(VALUE self, VALUE arch, VALUE mode) { + uc_engine *_uc; + uc_err err; + err = uc_open(NUM2INT(arch), NUM2INT(mode), &_uc); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + + VALUE uc = Data_Wrap_Struct(UcClass, 0, uc_close, _uc); + rb_iv_set(self, "@uch", uc); + + return self; +} + +VALUE m_uc_emu_start(int argc, VALUE* argv, VALUE self){ + VALUE begin; + VALUE until; + VALUE timeout; + VALUE count; + uc_err err; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + + rb_scan_args(argc, argv, "22",&begin, &until, &timeout, &count); + if (NIL_P(timeout)) + timeout = INT2NUM(0); + + if (NIL_P(count)) + count = INT2NUM(0); + + err = uc_emu_start(_uc, NUM2ULL(begin), NUM2ULL(until), NUM2INT(timeout), NUM2INT(count)); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return Qnil; +} + +VALUE m_uc_emu_stop(VALUE self){ + uc_err err; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + + err = uc_emu_stop(_uc); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return Qnil; +} + +VALUE m_uc_reg_read(VALUE self, VALUE reg_id){ + + uc_err err; + int32_t tmp_reg = NUM2INT(reg_id); + int64_t reg_value = 0; + VALUE to_ret; + uc_x86_mmr mmr; + + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + switch(tmp_reg){ + case UC_X86_REG_GDTR: + case UC_X86_REG_IDTR: + case UC_X86_REG_LDTR: + case UC_X86_REG_TR: + mmr.selector = 0; + mmr.base = 0; + mmr.limit = 0; + mmr.flags = 0; + err = uc_reg_read(_uc, tmp_reg, &mmr); + + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + VALUE mmr_ary = rb_ary_new(); + reg_value = mmr.selector; + rb_ary_store(mmr_ary, 0, UINT2NUM(reg_value)); + rb_ary_store(mmr_ary, 1, ULL2NUM(mmr.base)); + rb_ary_store(mmr_ary, 2, UINT2NUM(mmr.limit)); + rb_ary_store(mmr_ary, 3, UINT2NUM(mmr.flags)); + return mmr_ary; + default: + + err = uc_reg_read(_uc, tmp_reg, ®_value); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return LL2NUM(reg_value); + } + +} + +VALUE m_uc_reg_write(VALUE self, VALUE reg_id, VALUE reg_value){ + uc_err err; + int32_t tmp_reg = NUM2INT(reg_id); + uc_x86_mmr mmr; + int64_t tmp; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + + switch(tmp_reg){ + case UC_X86_REG_GDTR: + case UC_X86_REG_IDTR: + case UC_X86_REG_LDTR: + case UC_X86_REG_TR: + Check_Type(reg_value, T_ARRAY); + + mmr.selector = NUM2USHORT(rb_ary_entry(reg_value,0)); + mmr.base = NUM2ULL(rb_ary_entry(reg_value,1)); + mmr.limit = NUM2UINT(rb_ary_entry(reg_value,2)); + mmr.flags = NUM2UINT(rb_ary_entry(reg_value,3)); + err = uc_reg_write(_uc, tmp_reg, &mmr); + break; + default: + tmp = NUM2ULL(reg_value); + + err = uc_reg_write(_uc, NUM2INT(reg_id), &tmp); + break; + } + + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return Qnil; +} + +VALUE m_uc_mem_read(VALUE self, VALUE address, VALUE size){ + size_t isize = NUM2UINT(size); + uint8_t bytes[isize]; + uc_err err; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + + err = uc_mem_read(_uc, NUM2ULL(address), &bytes, isize); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return rb_str_new(bytes, isize); +} + +VALUE m_uc_mem_write(VALUE self, VALUE address, VALUE bytes){ + uc_err err; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + err = uc_mem_write(_uc, NUM2ULL(address), StringValuePtr(bytes), RSTRING_LEN(bytes)); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return Qnil; +} + +VALUE m_uc_mem_map(int argc, VALUE* argv, VALUE self){ + uc_err err; + VALUE address; + VALUE size; + VALUE perms; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + rb_scan_args(argc, argv, "21",&address, &size, &perms); + if (NIL_P(perms)) + perms = INT2NUM(UC_PROT_ALL); + + err = uc_mem_map(_uc, NUM2ULL(address), NUM2UINT(size), NUM2UINT(perms)); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return Qnil; +} + +// VALUE m_uc_mem_map_ptr(VALUE self, VALUE address, VALUE size, VALUE perms, VALUE ptr){ +// uc_err err; + +// err = uc_mem_map_ptr(_uc, NUM2INT(address), NUM2INT(size), NUM2INT(perms), NUM2INT(ptr)); +// if (err != UC_ERR_OK) { +// rb_raise(UcError, "%s", uc_strerror(err)); +// } +// return Qnil; +// } + +VALUE m_uc_mem_unmap(VALUE self, VALUE address, VALUE size){ + uc_err err; + uc_engine *_uc; + _uc = (uc_engine*) NUM2ULL(rb_iv_get(self, "@uch")); + err = uc_mem_unmap(_uc, NUM2ULL(address), NUM2UINT(size)); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return Qnil; +} + +VALUE m_uc_mem_protect(VALUE self, VALUE address, VALUE size, VALUE perms){ + uc_err err; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + err = uc_mem_protect(_uc, NUM2ULL(address), NUM2UINT(size), NUM2UINT(perms)); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return Qnil; +} + +static void cb_hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data){ + VALUE passthrough = (VALUE)user_data; + VALUE cb; + VALUE ud; + VALUE rUc; + + cb = rb_ary_entry(passthrough, 0); + ud = rb_ary_entry(passthrough, 1); + rUc = rb_ary_entry(passthrough, 2); + rb_funcall(cb, rb_intern("call"), 4, rUc, ULL2NUM(address), UINT2NUM(size), ud); + +} + +static void cb_hook_mem_access(uc_engine *uc, uint32_t access, uint64_t address, uint32_t size, int64_t value, void *user_data){ + VALUE passthrough = (VALUE)user_data; + VALUE cb; + VALUE ud; + VALUE rUc; + + cb = rb_ary_entry(passthrough, 0); + ud = rb_ary_entry(passthrough, 1); + rUc = rb_ary_entry(passthrough, 2); + + rb_funcall(cb, rb_intern("call"), 6, rUc, UINT2NUM(access), ULL2NUM(address), UINT2NUM(size), LL2NUM(value), ud); + +} + +static bool cb_hook_mem_invalid(uc_engine *uc, uint32_t access, uint64_t address, uint32_t size, int64_t value, void *user_data){ + VALUE passthrough = (VALUE)user_data; + VALUE cb; + VALUE ud; + VALUE rUc; + + cb = rb_ary_entry(passthrough, 0); + ud = rb_ary_entry(passthrough, 1); + rUc = rb_ary_entry(passthrough, 2); + return RTEST(rb_funcall(cb, rb_intern("call"), 6, rUc, UINT2NUM(access), ULL2NUM(address), UINT2NUM(size), LL2NUM(value), ud)); +} + +static uint32_t cb_hook_insn_in(uc_engine *uc, uint32_t port, int size, void *user_data){ + VALUE passthrough = (VALUE)user_data; + VALUE cb; + VALUE ud; + VALUE rUc; + + cb = rb_ary_entry(passthrough, 0); + ud = rb_ary_entry(passthrough, 1); + rUc = rb_ary_entry(passthrough, 2); + return NUM2UINT(rb_funcall(cb, rb_intern("call"), 4, rUc, UINT2NUM(port), INT2NUM(size), ud)); + +} + +static void cb_hook_insn_out(uc_engine *uc, uint32_t port, int size, uint32_t value, void *user_data){ + VALUE passthrough = (VALUE)user_data; + VALUE cb; + VALUE ud; + VALUE rUc; + + cb = rb_ary_entry(passthrough, 0); + ud = rb_ary_entry(passthrough, 1); + rUc = rb_ary_entry(passthrough, 2); + rb_funcall(cb, rb_intern("call"), 5, rUc, UINT2NUM(port), INT2NUM(size), UINT2NUM(value), ud); + +} + +static void cb_hook_insn_syscall(uc_engine *uc, void *user_data){ + VALUE passthrough = (VALUE)user_data; + VALUE cb; + VALUE ud; + VALUE rUc; + + cb = rb_ary_entry(passthrough, 0); + ud = rb_ary_entry(passthrough, 1); + rUc = rb_ary_entry(passthrough, 2); + rb_funcall(cb, rb_intern("call"), 2, rUc, ud); + +} + +static void cb_hook_intr(uc_engine *uc, uint64_t address, uint32_t size, int64_t value, void *user_data){ + VALUE passthrough = (VALUE)user_data; + VALUE cb; + VALUE ud; + VALUE rUc; + + cb = rb_ary_entry(passthrough, 0); + ud = rb_ary_entry(passthrough, 1); + rUc = rb_ary_entry(passthrough, 2); + rb_funcall(cb, rb_intern("call"), 5, rUc, ULL2NUM(address), UINT2NUM(size), LL2NUM(value), ud); + +} + + +VALUE m_uc_hook_add(int argc, VALUE* argv, VALUE self){ + VALUE hook_type; + VALUE callback; + VALUE user_data; + VALUE begin; + VALUE end; + VALUE arg1; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + rb_scan_args(argc, argv, "24",&hook_type, &callback, &user_data, &begin, &end, &arg1); + if (NIL_P(begin)) + begin = ULL2NUM(1); + + if (NIL_P(end)) + end = ULL2NUM(0); + + if (NIL_P(arg1)) + arg1 = INT2NUM(0); + + + VALUE passthrough; + uc_hook trace; + uc_err err; + + + if (rb_class_of(callback) != rb_cProc) + rb_raise(UcError, "Expected Proc callback"); + + passthrough = rb_ary_new(); + rb_ary_store(passthrough, 0, callback); + rb_ary_store(passthrough, 1, user_data); + rb_ary_store(passthrough, 2, self); + + uint32_t htype = NUM2UINT(hook_type); + if(htype == UC_HOOK_INSN){ + + switch(NUM2INT(arg1)){ + case UC_X86_INS_IN: + err = uc_hook_add(_uc, &trace, htype, cb_hook_insn_in,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end), NUM2INT(arg1)); + break; + case UC_X86_INS_OUT: + err = uc_hook_add(_uc, &trace, htype, cb_hook_insn_out,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end), NUM2INT(arg1)); + break; + case UC_X86_INS_SYSCALL: + case UC_X86_INS_SYSENTER: + err = uc_hook_add(_uc, &trace, htype, cb_hook_insn_syscall,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end), NUM2INT(arg1)); + break; + } + err = uc_hook_add(_uc, &trace, htype, cb_hook_intr,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end)); + } + else if(htype == UC_HOOK_INTR){ + err = uc_hook_add(_uc, &trace, htype, cb_hook_intr,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end)); + } + else if(htype == UC_HOOK_CODE || htype == UC_HOOK_BLOCK){ + + err = uc_hook_add(_uc, &trace, htype, cb_hook_code,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end)); + } + else if (htype & UC_HOOK_MEM_READ_UNMAPPED + || htype & UC_HOOK_MEM_WRITE_UNMAPPED + || htype & UC_HOOK_MEM_FETCH_UNMAPPED + || htype & UC_HOOK_MEM_READ_PROT + || htype & UC_HOOK_MEM_WRITE_PROT + || htype & UC_HOOK_MEM_FETCH_PROT + || htype & UC_HOOK_MEM_READ_INVALID + || htype & UC_HOOK_MEM_WRITE_INVALID + || htype & UC_HOOK_MEM_FETCH_INVALID + || htype & UC_HOOK_MEM_UNMAPPED + || htype & UC_HOOK_MEM_PROT + || htype & UC_HOOK_MEM_INVALID) { + err = uc_hook_add(_uc, &trace, htype, cb_hook_mem_invalid,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end)); + } + else{ + err = uc_hook_add(_uc, &trace, htype, cb_hook_mem_access,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end)); + } + + + + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return INT2NUM(trace); +} + +VALUE m_uc_hook_del(VALUE self, VALUE hook){ + int h = NUM2INT(hook); + uc_err err; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + err = uc_hook_del(_uc, h); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return Qnil; +} + +VALUE m_uc_query(VALUE self, VALUE query_mode){ + int qm = NUM2INT(query_mode); + size_t result; + uc_err err; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + err = uc_query(_uc, qm, &result); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return INT2NUM(result); +} diff --git a/bindings/ruby/unicorn_gem/ext/unicorn.h b/bindings/ruby/unicorn_gem/ext/unicorn.h new file mode 100644 index 00000000..30b417d9 --- /dev/null +++ b/bindings/ruby/unicorn_gem/ext/unicorn.h @@ -0,0 +1,34 @@ +/* + +Ruby bindings for the Unicorn Emulator Engine + +Copyright(c) 2016 Sascha Schirra + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ +VALUE m_uc_initialize(VALUE self, VALUE arch, VALUE mode); +VALUE m_uc_emu_start(int argc, VALUE* argv, VALUE self); +VALUE m_uc_emu_stop(VALUE self); +VALUE m_uc_reg_read(VALUE self, VALUE reg_id); +VALUE m_uc_reg_write(VALUE self, VALUE reg_id, VALUE reg_value); +VALUE m_uc_mem_read(VALUE self, VALUE address, VALUE size); +VALUE m_uc_mem_write(VALUE self, VALUE address, VALUE bytes); +VALUE m_uc_mem_map(int argc, VALUE* argv, VALUE self); +//VALUE m_uc_mem_map_ptr(VALUE self, VALUE address, VALUE size, VALUE perms, VALUE ptr); +VALUE m_uc_mem_unmap(VALUE self, VALUE address, VALUE size); +VALUE m_uc_mem_protect(VALUE self, VALUE address, VALUE size, VALUE perms); +VALUE m_uc_hook_add(int argc, VALUE* argv, VALUE self); +VALUE m_uc_hook_del(VALUE self, VALUE hook); +VALUE m_uc_query(VALUE self, VALUE query_mode); \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/lib/unicorn/arm64_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn/arm64_const.rb new file mode 100644 index 00000000..7767d96b --- /dev/null +++ b/bindings/ruby/unicorn_gem/lib/unicorn/arm64_const.rb @@ -0,0 +1,277 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [arm64_const.rb] + +module Unicorn + +# ARM64 registers + + UC_ARM64_REG_INVALID = 0 + UC_ARM64_REG_X29 = 1 + UC_ARM64_REG_X30 = 2 + UC_ARM64_REG_NZCV = 3 + UC_ARM64_REG_SP = 4 + UC_ARM64_REG_WSP = 5 + UC_ARM64_REG_WZR = 6 + UC_ARM64_REG_XZR = 7 + UC_ARM64_REG_B0 = 8 + UC_ARM64_REG_B1 = 9 + UC_ARM64_REG_B2 = 10 + UC_ARM64_REG_B3 = 11 + UC_ARM64_REG_B4 = 12 + UC_ARM64_REG_B5 = 13 + UC_ARM64_REG_B6 = 14 + UC_ARM64_REG_B7 = 15 + UC_ARM64_REG_B8 = 16 + UC_ARM64_REG_B9 = 17 + UC_ARM64_REG_B10 = 18 + UC_ARM64_REG_B11 = 19 + UC_ARM64_REG_B12 = 20 + UC_ARM64_REG_B13 = 21 + UC_ARM64_REG_B14 = 22 + UC_ARM64_REG_B15 = 23 + UC_ARM64_REG_B16 = 24 + UC_ARM64_REG_B17 = 25 + UC_ARM64_REG_B18 = 26 + UC_ARM64_REG_B19 = 27 + UC_ARM64_REG_B20 = 28 + UC_ARM64_REG_B21 = 29 + UC_ARM64_REG_B22 = 30 + UC_ARM64_REG_B23 = 31 + UC_ARM64_REG_B24 = 32 + UC_ARM64_REG_B25 = 33 + UC_ARM64_REG_B26 = 34 + UC_ARM64_REG_B27 = 35 + UC_ARM64_REG_B28 = 36 + UC_ARM64_REG_B29 = 37 + UC_ARM64_REG_B30 = 38 + UC_ARM64_REG_B31 = 39 + UC_ARM64_REG_D0 = 40 + UC_ARM64_REG_D1 = 41 + UC_ARM64_REG_D2 = 42 + UC_ARM64_REG_D3 = 43 + UC_ARM64_REG_D4 = 44 + UC_ARM64_REG_D5 = 45 + UC_ARM64_REG_D6 = 46 + UC_ARM64_REG_D7 = 47 + UC_ARM64_REG_D8 = 48 + UC_ARM64_REG_D9 = 49 + UC_ARM64_REG_D10 = 50 + UC_ARM64_REG_D11 = 51 + UC_ARM64_REG_D12 = 52 + UC_ARM64_REG_D13 = 53 + UC_ARM64_REG_D14 = 54 + UC_ARM64_REG_D15 = 55 + UC_ARM64_REG_D16 = 56 + UC_ARM64_REG_D17 = 57 + UC_ARM64_REG_D18 = 58 + UC_ARM64_REG_D19 = 59 + UC_ARM64_REG_D20 = 60 + UC_ARM64_REG_D21 = 61 + UC_ARM64_REG_D22 = 62 + UC_ARM64_REG_D23 = 63 + UC_ARM64_REG_D24 = 64 + UC_ARM64_REG_D25 = 65 + UC_ARM64_REG_D26 = 66 + UC_ARM64_REG_D27 = 67 + UC_ARM64_REG_D28 = 68 + UC_ARM64_REG_D29 = 69 + UC_ARM64_REG_D30 = 70 + UC_ARM64_REG_D31 = 71 + UC_ARM64_REG_H0 = 72 + UC_ARM64_REG_H1 = 73 + UC_ARM64_REG_H2 = 74 + UC_ARM64_REG_H3 = 75 + UC_ARM64_REG_H4 = 76 + UC_ARM64_REG_H5 = 77 + UC_ARM64_REG_H6 = 78 + UC_ARM64_REG_H7 = 79 + UC_ARM64_REG_H8 = 80 + UC_ARM64_REG_H9 = 81 + UC_ARM64_REG_H10 = 82 + UC_ARM64_REG_H11 = 83 + UC_ARM64_REG_H12 = 84 + UC_ARM64_REG_H13 = 85 + UC_ARM64_REG_H14 = 86 + UC_ARM64_REG_H15 = 87 + UC_ARM64_REG_H16 = 88 + UC_ARM64_REG_H17 = 89 + UC_ARM64_REG_H18 = 90 + UC_ARM64_REG_H19 = 91 + UC_ARM64_REG_H20 = 92 + UC_ARM64_REG_H21 = 93 + UC_ARM64_REG_H22 = 94 + UC_ARM64_REG_H23 = 95 + UC_ARM64_REG_H24 = 96 + UC_ARM64_REG_H25 = 97 + UC_ARM64_REG_H26 = 98 + UC_ARM64_REG_H27 = 99 + UC_ARM64_REG_H28 = 100 + UC_ARM64_REG_H29 = 101 + UC_ARM64_REG_H30 = 102 + UC_ARM64_REG_H31 = 103 + UC_ARM64_REG_Q0 = 104 + UC_ARM64_REG_Q1 = 105 + UC_ARM64_REG_Q2 = 106 + UC_ARM64_REG_Q3 = 107 + UC_ARM64_REG_Q4 = 108 + UC_ARM64_REG_Q5 = 109 + UC_ARM64_REG_Q6 = 110 + UC_ARM64_REG_Q7 = 111 + UC_ARM64_REG_Q8 = 112 + UC_ARM64_REG_Q9 = 113 + UC_ARM64_REG_Q10 = 114 + UC_ARM64_REG_Q11 = 115 + UC_ARM64_REG_Q12 = 116 + UC_ARM64_REG_Q13 = 117 + UC_ARM64_REG_Q14 = 118 + UC_ARM64_REG_Q15 = 119 + UC_ARM64_REG_Q16 = 120 + UC_ARM64_REG_Q17 = 121 + UC_ARM64_REG_Q18 = 122 + UC_ARM64_REG_Q19 = 123 + UC_ARM64_REG_Q20 = 124 + UC_ARM64_REG_Q21 = 125 + UC_ARM64_REG_Q22 = 126 + UC_ARM64_REG_Q23 = 127 + UC_ARM64_REG_Q24 = 128 + UC_ARM64_REG_Q25 = 129 + UC_ARM64_REG_Q26 = 130 + UC_ARM64_REG_Q27 = 131 + UC_ARM64_REG_Q28 = 132 + UC_ARM64_REG_Q29 = 133 + UC_ARM64_REG_Q30 = 134 + UC_ARM64_REG_Q31 = 135 + UC_ARM64_REG_S0 = 136 + UC_ARM64_REG_S1 = 137 + UC_ARM64_REG_S2 = 138 + UC_ARM64_REG_S3 = 139 + UC_ARM64_REG_S4 = 140 + UC_ARM64_REG_S5 = 141 + UC_ARM64_REG_S6 = 142 + UC_ARM64_REG_S7 = 143 + UC_ARM64_REG_S8 = 144 + UC_ARM64_REG_S9 = 145 + UC_ARM64_REG_S10 = 146 + UC_ARM64_REG_S11 = 147 + UC_ARM64_REG_S12 = 148 + UC_ARM64_REG_S13 = 149 + UC_ARM64_REG_S14 = 150 + UC_ARM64_REG_S15 = 151 + UC_ARM64_REG_S16 = 152 + UC_ARM64_REG_S17 = 153 + UC_ARM64_REG_S18 = 154 + UC_ARM64_REG_S19 = 155 + UC_ARM64_REG_S20 = 156 + UC_ARM64_REG_S21 = 157 + UC_ARM64_REG_S22 = 158 + UC_ARM64_REG_S23 = 159 + UC_ARM64_REG_S24 = 160 + UC_ARM64_REG_S25 = 161 + UC_ARM64_REG_S26 = 162 + UC_ARM64_REG_S27 = 163 + UC_ARM64_REG_S28 = 164 + UC_ARM64_REG_S29 = 165 + UC_ARM64_REG_S30 = 166 + UC_ARM64_REG_S31 = 167 + UC_ARM64_REG_W0 = 168 + UC_ARM64_REG_W1 = 169 + UC_ARM64_REG_W2 = 170 + UC_ARM64_REG_W3 = 171 + UC_ARM64_REG_W4 = 172 + UC_ARM64_REG_W5 = 173 + UC_ARM64_REG_W6 = 174 + UC_ARM64_REG_W7 = 175 + UC_ARM64_REG_W8 = 176 + UC_ARM64_REG_W9 = 177 + UC_ARM64_REG_W10 = 178 + UC_ARM64_REG_W11 = 179 + UC_ARM64_REG_W12 = 180 + UC_ARM64_REG_W13 = 181 + UC_ARM64_REG_W14 = 182 + UC_ARM64_REG_W15 = 183 + UC_ARM64_REG_W16 = 184 + UC_ARM64_REG_W17 = 185 + UC_ARM64_REG_W18 = 186 + UC_ARM64_REG_W19 = 187 + UC_ARM64_REG_W20 = 188 + UC_ARM64_REG_W21 = 189 + UC_ARM64_REG_W22 = 190 + UC_ARM64_REG_W23 = 191 + UC_ARM64_REG_W24 = 192 + UC_ARM64_REG_W25 = 193 + UC_ARM64_REG_W26 = 194 + UC_ARM64_REG_W27 = 195 + UC_ARM64_REG_W28 = 196 + UC_ARM64_REG_W29 = 197 + UC_ARM64_REG_W30 = 198 + UC_ARM64_REG_X0 = 199 + UC_ARM64_REG_X1 = 200 + UC_ARM64_REG_X2 = 201 + UC_ARM64_REG_X3 = 202 + UC_ARM64_REG_X4 = 203 + UC_ARM64_REG_X5 = 204 + UC_ARM64_REG_X6 = 205 + UC_ARM64_REG_X7 = 206 + UC_ARM64_REG_X8 = 207 + UC_ARM64_REG_X9 = 208 + UC_ARM64_REG_X10 = 209 + UC_ARM64_REG_X11 = 210 + UC_ARM64_REG_X12 = 211 + UC_ARM64_REG_X13 = 212 + UC_ARM64_REG_X14 = 213 + UC_ARM64_REG_X15 = 214 + UC_ARM64_REG_X16 = 215 + UC_ARM64_REG_X17 = 216 + UC_ARM64_REG_X18 = 217 + UC_ARM64_REG_X19 = 218 + UC_ARM64_REG_X20 = 219 + UC_ARM64_REG_X21 = 220 + UC_ARM64_REG_X22 = 221 + UC_ARM64_REG_X23 = 222 + UC_ARM64_REG_X24 = 223 + UC_ARM64_REG_X25 = 224 + UC_ARM64_REG_X26 = 225 + UC_ARM64_REG_X27 = 226 + UC_ARM64_REG_X28 = 227 + UC_ARM64_REG_V0 = 228 + UC_ARM64_REG_V1 = 229 + UC_ARM64_REG_V2 = 230 + UC_ARM64_REG_V3 = 231 + UC_ARM64_REG_V4 = 232 + UC_ARM64_REG_V5 = 233 + UC_ARM64_REG_V6 = 234 + UC_ARM64_REG_V7 = 235 + UC_ARM64_REG_V8 = 236 + UC_ARM64_REG_V9 = 237 + UC_ARM64_REG_V10 = 238 + UC_ARM64_REG_V11 = 239 + UC_ARM64_REG_V12 = 240 + UC_ARM64_REG_V13 = 241 + UC_ARM64_REG_V14 = 242 + UC_ARM64_REG_V15 = 243 + UC_ARM64_REG_V16 = 244 + UC_ARM64_REG_V17 = 245 + UC_ARM64_REG_V18 = 246 + UC_ARM64_REG_V19 = 247 + UC_ARM64_REG_V20 = 248 + UC_ARM64_REG_V21 = 249 + UC_ARM64_REG_V22 = 250 + UC_ARM64_REG_V23 = 251 + UC_ARM64_REG_V24 = 252 + UC_ARM64_REG_V25 = 253 + UC_ARM64_REG_V26 = 254 + UC_ARM64_REG_V27 = 255 + UC_ARM64_REG_V28 = 256 + UC_ARM64_REG_V29 = 257 + UC_ARM64_REG_V30 = 258 + UC_ARM64_REG_V31 = 259 + +# pseudo registers + UC_ARM64_REG_PC = 260 + UC_ARM64_REG_ENDING = 261 + +# alias registers + UC_ARM64_REG_IP1 = 215 + UC_ARM64_REG_IP0 = 216 + UC_ARM64_REG_FP = 1 + UC_ARM64_REG_LR = 2 +end \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/lib/unicorn/arm_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn/arm_const.rb new file mode 100644 index 00000000..2a80d44c --- /dev/null +++ b/bindings/ruby/unicorn_gem/lib/unicorn/arm_const.rb @@ -0,0 +1,128 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [arm_const.rb] + +module Unicorn + +# ARM registers + + UC_ARM_REG_INVALID = 0 + UC_ARM_REG_APSR = 1 + UC_ARM_REG_APSR_NZCV = 2 + UC_ARM_REG_CPSR = 3 + UC_ARM_REG_FPEXC = 4 + UC_ARM_REG_FPINST = 5 + UC_ARM_REG_FPSCR = 6 + UC_ARM_REG_FPSCR_NZCV = 7 + UC_ARM_REG_FPSID = 8 + UC_ARM_REG_ITSTATE = 9 + UC_ARM_REG_LR = 10 + UC_ARM_REG_PC = 11 + UC_ARM_REG_SP = 12 + UC_ARM_REG_SPSR = 13 + UC_ARM_REG_D0 = 14 + UC_ARM_REG_D1 = 15 + UC_ARM_REG_D2 = 16 + UC_ARM_REG_D3 = 17 + UC_ARM_REG_D4 = 18 + UC_ARM_REG_D5 = 19 + UC_ARM_REG_D6 = 20 + UC_ARM_REG_D7 = 21 + UC_ARM_REG_D8 = 22 + UC_ARM_REG_D9 = 23 + UC_ARM_REG_D10 = 24 + UC_ARM_REG_D11 = 25 + UC_ARM_REG_D12 = 26 + UC_ARM_REG_D13 = 27 + UC_ARM_REG_D14 = 28 + UC_ARM_REG_D15 = 29 + UC_ARM_REG_D16 = 30 + UC_ARM_REG_D17 = 31 + UC_ARM_REG_D18 = 32 + UC_ARM_REG_D19 = 33 + UC_ARM_REG_D20 = 34 + UC_ARM_REG_D21 = 35 + UC_ARM_REG_D22 = 36 + UC_ARM_REG_D23 = 37 + UC_ARM_REG_D24 = 38 + UC_ARM_REG_D25 = 39 + UC_ARM_REG_D26 = 40 + UC_ARM_REG_D27 = 41 + UC_ARM_REG_D28 = 42 + UC_ARM_REG_D29 = 43 + UC_ARM_REG_D30 = 44 + UC_ARM_REG_D31 = 45 + UC_ARM_REG_FPINST2 = 46 + UC_ARM_REG_MVFR0 = 47 + UC_ARM_REG_MVFR1 = 48 + UC_ARM_REG_MVFR2 = 49 + UC_ARM_REG_Q0 = 50 + UC_ARM_REG_Q1 = 51 + UC_ARM_REG_Q2 = 52 + UC_ARM_REG_Q3 = 53 + UC_ARM_REG_Q4 = 54 + UC_ARM_REG_Q5 = 55 + UC_ARM_REG_Q6 = 56 + UC_ARM_REG_Q7 = 57 + UC_ARM_REG_Q8 = 58 + UC_ARM_REG_Q9 = 59 + UC_ARM_REG_Q10 = 60 + UC_ARM_REG_Q11 = 61 + UC_ARM_REG_Q12 = 62 + UC_ARM_REG_Q13 = 63 + UC_ARM_REG_Q14 = 64 + UC_ARM_REG_Q15 = 65 + UC_ARM_REG_R0 = 66 + UC_ARM_REG_R1 = 67 + UC_ARM_REG_R2 = 68 + UC_ARM_REG_R3 = 69 + UC_ARM_REG_R4 = 70 + UC_ARM_REG_R5 = 71 + UC_ARM_REG_R6 = 72 + UC_ARM_REG_R7 = 73 + UC_ARM_REG_R8 = 74 + UC_ARM_REG_R9 = 75 + UC_ARM_REG_R10 = 76 + UC_ARM_REG_R11 = 77 + UC_ARM_REG_R12 = 78 + UC_ARM_REG_S0 = 79 + UC_ARM_REG_S1 = 80 + UC_ARM_REG_S2 = 81 + UC_ARM_REG_S3 = 82 + UC_ARM_REG_S4 = 83 + UC_ARM_REG_S5 = 84 + UC_ARM_REG_S6 = 85 + UC_ARM_REG_S7 = 86 + UC_ARM_REG_S8 = 87 + UC_ARM_REG_S9 = 88 + UC_ARM_REG_S10 = 89 + UC_ARM_REG_S11 = 90 + UC_ARM_REG_S12 = 91 + UC_ARM_REG_S13 = 92 + UC_ARM_REG_S14 = 93 + UC_ARM_REG_S15 = 94 + UC_ARM_REG_S16 = 95 + UC_ARM_REG_S17 = 96 + UC_ARM_REG_S18 = 97 + UC_ARM_REG_S19 = 98 + UC_ARM_REG_S20 = 99 + UC_ARM_REG_S21 = 100 + UC_ARM_REG_S22 = 101 + UC_ARM_REG_S23 = 102 + UC_ARM_REG_S24 = 103 + UC_ARM_REG_S25 = 104 + UC_ARM_REG_S26 = 105 + UC_ARM_REG_S27 = 106 + UC_ARM_REG_S28 = 107 + UC_ARM_REG_S29 = 108 + UC_ARM_REG_S30 = 109 + UC_ARM_REG_S31 = 110 + UC_ARM_REG_ENDING = 111 + +# alias registers + UC_ARM_REG_R13 = 12 + UC_ARM_REG_R14 = 10 + UC_ARM_REG_R15 = 11 + UC_ARM_REG_SB = 75 + UC_ARM_REG_SL = 76 + UC_ARM_REG_FP = 77 + UC_ARM_REG_IP = 78 +end \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/lib/unicorn/m68k_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn/m68k_const.rb new file mode 100644 index 00000000..2c53636d --- /dev/null +++ b/bindings/ruby/unicorn_gem/lib/unicorn/m68k_const.rb @@ -0,0 +1,27 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [m68k_const.rb] + +module Unicorn + +# M68K registers + + UC_M68K_REG_INVALID = 0 + UC_M68K_REG_A0 = 1 + UC_M68K_REG_A1 = 2 + UC_M68K_REG_A2 = 3 + UC_M68K_REG_A3 = 4 + UC_M68K_REG_A4 = 5 + UC_M68K_REG_A5 = 6 + UC_M68K_REG_A6 = 7 + UC_M68K_REG_A7 = 8 + UC_M68K_REG_D0 = 9 + UC_M68K_REG_D1 = 10 + UC_M68K_REG_D2 = 11 + UC_M68K_REG_D3 = 12 + UC_M68K_REG_D4 = 13 + UC_M68K_REG_D5 = 14 + UC_M68K_REG_D6 = 15 + UC_M68K_REG_D7 = 16 + UC_M68K_REG_SR = 17 + UC_M68K_REG_PC = 18 + UC_M68K_REG_ENDING = 19 +end \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/lib/unicorn/mips_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn/mips_const.rb new file mode 100644 index 00000000..d92e94e5 --- /dev/null +++ b/bindings/ruby/unicorn_gem/lib/unicorn/mips_const.rb @@ -0,0 +1,198 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [mips_const.rb] + +module Unicorn + +# MIPS registers + + UC_MIPS_REG_INVALID = 0 + +# General purpose registers + UC_MIPS_REG_PC = 1 + UC_MIPS_REG_0 = 2 + UC_MIPS_REG_1 = 3 + UC_MIPS_REG_2 = 4 + UC_MIPS_REG_3 = 5 + UC_MIPS_REG_4 = 6 + UC_MIPS_REG_5 = 7 + UC_MIPS_REG_6 = 8 + UC_MIPS_REG_7 = 9 + UC_MIPS_REG_8 = 10 + UC_MIPS_REG_9 = 11 + UC_MIPS_REG_10 = 12 + UC_MIPS_REG_11 = 13 + UC_MIPS_REG_12 = 14 + UC_MIPS_REG_13 = 15 + UC_MIPS_REG_14 = 16 + UC_MIPS_REG_15 = 17 + UC_MIPS_REG_16 = 18 + UC_MIPS_REG_17 = 19 + UC_MIPS_REG_18 = 20 + UC_MIPS_REG_19 = 21 + UC_MIPS_REG_20 = 22 + UC_MIPS_REG_21 = 23 + UC_MIPS_REG_22 = 24 + UC_MIPS_REG_23 = 25 + UC_MIPS_REG_24 = 26 + UC_MIPS_REG_25 = 27 + UC_MIPS_REG_26 = 28 + UC_MIPS_REG_27 = 29 + UC_MIPS_REG_28 = 30 + UC_MIPS_REG_29 = 31 + UC_MIPS_REG_30 = 32 + UC_MIPS_REG_31 = 33 + +# DSP registers + UC_MIPS_REG_DSPCCOND = 34 + UC_MIPS_REG_DSPCARRY = 35 + UC_MIPS_REG_DSPEFI = 36 + UC_MIPS_REG_DSPOUTFLAG = 37 + UC_MIPS_REG_DSPOUTFLAG16_19 = 38 + UC_MIPS_REG_DSPOUTFLAG20 = 39 + UC_MIPS_REG_DSPOUTFLAG21 = 40 + UC_MIPS_REG_DSPOUTFLAG22 = 41 + UC_MIPS_REG_DSPOUTFLAG23 = 42 + UC_MIPS_REG_DSPPOS = 43 + UC_MIPS_REG_DSPSCOUNT = 44 + +# ACC registers + UC_MIPS_REG_AC0 = 45 + UC_MIPS_REG_AC1 = 46 + UC_MIPS_REG_AC2 = 47 + UC_MIPS_REG_AC3 = 48 + +# COP registers + UC_MIPS_REG_CC0 = 49 + UC_MIPS_REG_CC1 = 50 + UC_MIPS_REG_CC2 = 51 + UC_MIPS_REG_CC3 = 52 + UC_MIPS_REG_CC4 = 53 + UC_MIPS_REG_CC5 = 54 + UC_MIPS_REG_CC6 = 55 + UC_MIPS_REG_CC7 = 56 + +# FPU registers + UC_MIPS_REG_F0 = 57 + UC_MIPS_REG_F1 = 58 + UC_MIPS_REG_F2 = 59 + UC_MIPS_REG_F3 = 60 + UC_MIPS_REG_F4 = 61 + UC_MIPS_REG_F5 = 62 + UC_MIPS_REG_F6 = 63 + UC_MIPS_REG_F7 = 64 + UC_MIPS_REG_F8 = 65 + UC_MIPS_REG_F9 = 66 + UC_MIPS_REG_F10 = 67 + UC_MIPS_REG_F11 = 68 + UC_MIPS_REG_F12 = 69 + UC_MIPS_REG_F13 = 70 + UC_MIPS_REG_F14 = 71 + UC_MIPS_REG_F15 = 72 + UC_MIPS_REG_F16 = 73 + UC_MIPS_REG_F17 = 74 + UC_MIPS_REG_F18 = 75 + UC_MIPS_REG_F19 = 76 + UC_MIPS_REG_F20 = 77 + UC_MIPS_REG_F21 = 78 + UC_MIPS_REG_F22 = 79 + UC_MIPS_REG_F23 = 80 + UC_MIPS_REG_F24 = 81 + UC_MIPS_REG_F25 = 82 + UC_MIPS_REG_F26 = 83 + UC_MIPS_REG_F27 = 84 + UC_MIPS_REG_F28 = 85 + UC_MIPS_REG_F29 = 86 + UC_MIPS_REG_F30 = 87 + UC_MIPS_REG_F31 = 88 + UC_MIPS_REG_FCC0 = 89 + UC_MIPS_REG_FCC1 = 90 + UC_MIPS_REG_FCC2 = 91 + UC_MIPS_REG_FCC3 = 92 + UC_MIPS_REG_FCC4 = 93 + UC_MIPS_REG_FCC5 = 94 + UC_MIPS_REG_FCC6 = 95 + UC_MIPS_REG_FCC7 = 96 + +# AFPR128 + UC_MIPS_REG_W0 = 97 + UC_MIPS_REG_W1 = 98 + UC_MIPS_REG_W2 = 99 + UC_MIPS_REG_W3 = 100 + UC_MIPS_REG_W4 = 101 + UC_MIPS_REG_W5 = 102 + UC_MIPS_REG_W6 = 103 + UC_MIPS_REG_W7 = 104 + UC_MIPS_REG_W8 = 105 + UC_MIPS_REG_W9 = 106 + UC_MIPS_REG_W10 = 107 + UC_MIPS_REG_W11 = 108 + UC_MIPS_REG_W12 = 109 + UC_MIPS_REG_W13 = 110 + UC_MIPS_REG_W14 = 111 + UC_MIPS_REG_W15 = 112 + UC_MIPS_REG_W16 = 113 + UC_MIPS_REG_W17 = 114 + UC_MIPS_REG_W18 = 115 + UC_MIPS_REG_W19 = 116 + UC_MIPS_REG_W20 = 117 + UC_MIPS_REG_W21 = 118 + UC_MIPS_REG_W22 = 119 + UC_MIPS_REG_W23 = 120 + UC_MIPS_REG_W24 = 121 + UC_MIPS_REG_W25 = 122 + UC_MIPS_REG_W26 = 123 + UC_MIPS_REG_W27 = 124 + UC_MIPS_REG_W28 = 125 + UC_MIPS_REG_W29 = 126 + UC_MIPS_REG_W30 = 127 + UC_MIPS_REG_W31 = 128 + UC_MIPS_REG_HI = 129 + UC_MIPS_REG_LO = 130 + UC_MIPS_REG_P0 = 131 + UC_MIPS_REG_P1 = 132 + UC_MIPS_REG_P2 = 133 + UC_MIPS_REG_MPL0 = 134 + UC_MIPS_REG_MPL1 = 135 + UC_MIPS_REG_MPL2 = 136 + UC_MIPS_REG_ENDING = 137 + UC_MIPS_REG_ZERO = 2 + UC_MIPS_REG_AT = 3 + UC_MIPS_REG_V0 = 4 + UC_MIPS_REG_V1 = 5 + UC_MIPS_REG_A0 = 6 + UC_MIPS_REG_A1 = 7 + UC_MIPS_REG_A2 = 8 + UC_MIPS_REG_A3 = 9 + UC_MIPS_REG_T0 = 10 + UC_MIPS_REG_T1 = 11 + UC_MIPS_REG_T2 = 12 + UC_MIPS_REG_T3 = 13 + UC_MIPS_REG_T4 = 14 + UC_MIPS_REG_T5 = 15 + UC_MIPS_REG_T6 = 16 + UC_MIPS_REG_T7 = 17 + UC_MIPS_REG_S0 = 18 + UC_MIPS_REG_S1 = 19 + UC_MIPS_REG_S2 = 20 + UC_MIPS_REG_S3 = 21 + UC_MIPS_REG_S4 = 22 + UC_MIPS_REG_S5 = 23 + UC_MIPS_REG_S6 = 24 + UC_MIPS_REG_S7 = 25 + UC_MIPS_REG_T8 = 26 + UC_MIPS_REG_T9 = 27 + UC_MIPS_REG_K0 = 28 + UC_MIPS_REG_K1 = 29 + UC_MIPS_REG_GP = 30 + UC_MIPS_REG_SP = 31 + UC_MIPS_REG_FP = 32 + UC_MIPS_REG_S8 = 32 + UC_MIPS_REG_RA = 33 + UC_MIPS_REG_HI0 = 45 + UC_MIPS_REG_HI1 = 46 + UC_MIPS_REG_HI2 = 47 + UC_MIPS_REG_HI3 = 48 + UC_MIPS_REG_LO0 = 45 + UC_MIPS_REG_LO1 = 46 + UC_MIPS_REG_LO2 = 47 + UC_MIPS_REG_LO3 = 48 +end \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/lib/unicorn/sparc_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn/sparc_const.rb new file mode 100644 index 00000000..85d9eef1 --- /dev/null +++ b/bindings/ruby/unicorn_gem/lib/unicorn/sparc_const.rb @@ -0,0 +1,99 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [sparc_const.rb] + +module Unicorn + +# SPARC registers + + UC_SPARC_REG_INVALID = 0 + UC_SPARC_REG_F0 = 1 + UC_SPARC_REG_F1 = 2 + UC_SPARC_REG_F2 = 3 + UC_SPARC_REG_F3 = 4 + UC_SPARC_REG_F4 = 5 + UC_SPARC_REG_F5 = 6 + UC_SPARC_REG_F6 = 7 + UC_SPARC_REG_F7 = 8 + UC_SPARC_REG_F8 = 9 + UC_SPARC_REG_F9 = 10 + UC_SPARC_REG_F10 = 11 + UC_SPARC_REG_F11 = 12 + UC_SPARC_REG_F12 = 13 + UC_SPARC_REG_F13 = 14 + UC_SPARC_REG_F14 = 15 + UC_SPARC_REG_F15 = 16 + UC_SPARC_REG_F16 = 17 + UC_SPARC_REG_F17 = 18 + UC_SPARC_REG_F18 = 19 + UC_SPARC_REG_F19 = 20 + UC_SPARC_REG_F20 = 21 + UC_SPARC_REG_F21 = 22 + UC_SPARC_REG_F22 = 23 + UC_SPARC_REG_F23 = 24 + UC_SPARC_REG_F24 = 25 + UC_SPARC_REG_F25 = 26 + UC_SPARC_REG_F26 = 27 + UC_SPARC_REG_F27 = 28 + UC_SPARC_REG_F28 = 29 + UC_SPARC_REG_F29 = 30 + UC_SPARC_REG_F30 = 31 + UC_SPARC_REG_F31 = 32 + UC_SPARC_REG_F32 = 33 + UC_SPARC_REG_F34 = 34 + UC_SPARC_REG_F36 = 35 + UC_SPARC_REG_F38 = 36 + UC_SPARC_REG_F40 = 37 + UC_SPARC_REG_F42 = 38 + UC_SPARC_REG_F44 = 39 + UC_SPARC_REG_F46 = 40 + UC_SPARC_REG_F48 = 41 + UC_SPARC_REG_F50 = 42 + UC_SPARC_REG_F52 = 43 + UC_SPARC_REG_F54 = 44 + UC_SPARC_REG_F56 = 45 + UC_SPARC_REG_F58 = 46 + UC_SPARC_REG_F60 = 47 + UC_SPARC_REG_F62 = 48 + UC_SPARC_REG_FCC0 = 49 + UC_SPARC_REG_FCC1 = 50 + UC_SPARC_REG_FCC2 = 51 + UC_SPARC_REG_FCC3 = 52 + UC_SPARC_REG_G0 = 53 + UC_SPARC_REG_G1 = 54 + UC_SPARC_REG_G2 = 55 + UC_SPARC_REG_G3 = 56 + UC_SPARC_REG_G4 = 57 + UC_SPARC_REG_G5 = 58 + UC_SPARC_REG_G6 = 59 + UC_SPARC_REG_G7 = 60 + UC_SPARC_REG_I0 = 61 + UC_SPARC_REG_I1 = 62 + UC_SPARC_REG_I2 = 63 + UC_SPARC_REG_I3 = 64 + UC_SPARC_REG_I4 = 65 + UC_SPARC_REG_I5 = 66 + UC_SPARC_REG_FP = 67 + UC_SPARC_REG_I7 = 68 + UC_SPARC_REG_ICC = 69 + UC_SPARC_REG_L0 = 70 + UC_SPARC_REG_L1 = 71 + UC_SPARC_REG_L2 = 72 + UC_SPARC_REG_L3 = 73 + UC_SPARC_REG_L4 = 74 + UC_SPARC_REG_L5 = 75 + UC_SPARC_REG_L6 = 76 + UC_SPARC_REG_L7 = 77 + UC_SPARC_REG_O0 = 78 + UC_SPARC_REG_O1 = 79 + UC_SPARC_REG_O2 = 80 + UC_SPARC_REG_O3 = 81 + UC_SPARC_REG_O4 = 82 + UC_SPARC_REG_O5 = 83 + UC_SPARC_REG_SP = 84 + UC_SPARC_REG_O7 = 85 + UC_SPARC_REG_Y = 86 + UC_SPARC_REG_XCC = 87 + UC_SPARC_REG_PC = 88 + UC_SPARC_REG_ENDING = 89 + UC_SPARC_REG_O6 = 84 + UC_SPARC_REG_I6 = 67 +end \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/lib/unicorn/unicorn_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn/unicorn_const.rb new file mode 100644 index 00000000..7fe8a994 --- /dev/null +++ b/bindings/ruby/unicorn_gem/lib/unicorn/unicorn_const.rb @@ -0,0 +1,98 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [unicorn_const.rb] + +module Unicorn + UC_API_MAJOR = 1 + + UC_API_MINOR = 0 + UC_SECOND_SCALE = 1000000 + UC_MILISECOND_SCALE = 1000 + UC_ARCH_ARM = 1 + UC_ARCH_ARM64 = 2 + UC_ARCH_MIPS = 3 + UC_ARCH_X86 = 4 + UC_ARCH_PPC = 5 + UC_ARCH_SPARC = 6 + UC_ARCH_M68K = 7 + UC_ARCH_MAX = 8 + + UC_MODE_LITTLE_ENDIAN = 0 + UC_MODE_BIG_ENDIAN = 1073741824 + + UC_MODE_ARM = 0 + UC_MODE_THUMB = 16 + UC_MODE_MCLASS = 32 + UC_MODE_V8 = 64 + UC_MODE_MICRO = 16 + UC_MODE_MIPS3 = 32 + UC_MODE_MIPS32R6 = 64 + UC_MODE_MIPS32 = 4 + UC_MODE_MIPS64 = 8 + UC_MODE_16 = 2 + UC_MODE_32 = 4 + UC_MODE_64 = 8 + UC_MODE_PPC32 = 4 + UC_MODE_PPC64 = 8 + UC_MODE_QPX = 16 + UC_MODE_SPARC32 = 4 + UC_MODE_SPARC64 = 8 + UC_MODE_V9 = 16 + + UC_ERR_OK = 0 + UC_ERR_NOMEM = 1 + UC_ERR_ARCH = 2 + UC_ERR_HANDLE = 3 + UC_ERR_MODE = 4 + UC_ERR_VERSION = 5 + UC_ERR_READ_UNMAPPED = 6 + UC_ERR_WRITE_UNMAPPED = 7 + UC_ERR_FETCH_UNMAPPED = 8 + UC_ERR_HOOK = 9 + UC_ERR_INSN_INVALID = 10 + UC_ERR_MAP = 11 + UC_ERR_WRITE_PROT = 12 + UC_ERR_READ_PROT = 13 + UC_ERR_FETCH_PROT = 14 + UC_ERR_ARG = 15 + UC_ERR_READ_UNALIGNED = 16 + UC_ERR_WRITE_UNALIGNED = 17 + UC_ERR_FETCH_UNALIGNED = 18 + UC_ERR_HOOK_EXIST = 19 + UC_ERR_RESOURCE = 20 + UC_MEM_READ = 16 + UC_MEM_WRITE = 17 + UC_MEM_FETCH = 18 + UC_MEM_READ_UNMAPPED = 19 + UC_MEM_WRITE_UNMAPPED = 20 + UC_MEM_FETCH_UNMAPPED = 21 + UC_MEM_WRITE_PROT = 22 + UC_MEM_READ_PROT = 23 + UC_MEM_FETCH_PROT = 24 + UC_HOOK_INTR = 1 + UC_HOOK_INSN = 2 + UC_HOOK_CODE = 4 + UC_HOOK_BLOCK = 8 + UC_HOOK_MEM_READ_UNMAPPED = 16 + UC_HOOK_MEM_WRITE_UNMAPPED = 32 + UC_HOOK_MEM_FETCH_UNMAPPED = 64 + UC_HOOK_MEM_READ_PROT = 128 + UC_HOOK_MEM_WRITE_PROT = 256 + UC_HOOK_MEM_FETCH_PROT = 512 + UC_HOOK_MEM_READ = 1024 + UC_HOOK_MEM_WRITE = 2048 + UC_HOOK_MEM_FETCH = 4096 + UC_HOOK_MEM_UNMAPPED = 112 + UC_HOOK_MEM_PROT = 896 + UC_HOOK_MEM_READ_INVALID = 144 + UC_HOOK_MEM_WRITE_INVALID = 288 + UC_HOOK_MEM_FETCH_INVALID = 576 + UC_HOOK_MEM_INVALID = 1008 + UC_HOOK_MEM_VALID = 7168 + UC_QUERY_MODE = 1 + UC_QUERY_PAGE_SIZE = 2 + + UC_PROT_NONE = 0 + UC_PROT_READ = 1 + UC_PROT_WRITE = 2 + UC_PROT_EXEC = 4 + UC_PROT_ALL = 7 +end \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/lib/unicorn/version.rb b/bindings/ruby/unicorn_gem/lib/unicorn/version.rb new file mode 100644 index 00000000..1ebff38c --- /dev/null +++ b/bindings/ruby/unicorn_gem/lib/unicorn/version.rb @@ -0,0 +1,3 @@ +module Unicorn + VERSION = "0.9.0" +end diff --git a/bindings/ruby/unicorn_gem/lib/unicorn/x86_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn/x86_const.rb new file mode 100644 index 00000000..2226de17 --- /dev/null +++ b/bindings/ruby/unicorn_gem/lib/unicorn/x86_const.rb @@ -0,0 +1,1598 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [x86_const.rb] + +module Unicorn + +# X86 registers + + UC_X86_REG_INVALID = 0 + UC_X86_REG_AH = 1 + UC_X86_REG_AL = 2 + UC_X86_REG_AX = 3 + UC_X86_REG_BH = 4 + UC_X86_REG_BL = 5 + UC_X86_REG_BP = 6 + UC_X86_REG_BPL = 7 + UC_X86_REG_BX = 8 + UC_X86_REG_CH = 9 + UC_X86_REG_CL = 10 + UC_X86_REG_CS = 11 + UC_X86_REG_CX = 12 + UC_X86_REG_DH = 13 + UC_X86_REG_DI = 14 + UC_X86_REG_DIL = 15 + UC_X86_REG_DL = 16 + UC_X86_REG_DS = 17 + UC_X86_REG_DX = 18 + UC_X86_REG_EAX = 19 + UC_X86_REG_EBP = 20 + UC_X86_REG_EBX = 21 + UC_X86_REG_ECX = 22 + UC_X86_REG_EDI = 23 + UC_X86_REG_EDX = 24 + UC_X86_REG_EFLAGS = 25 + UC_X86_REG_EIP = 26 + UC_X86_REG_EIZ = 27 + UC_X86_REG_ES = 28 + UC_X86_REG_ESI = 29 + UC_X86_REG_ESP = 30 + UC_X86_REG_FPSW = 31 + UC_X86_REG_FS = 32 + UC_X86_REG_GS = 33 + UC_X86_REG_IP = 34 + UC_X86_REG_RAX = 35 + UC_X86_REG_RBP = 36 + UC_X86_REG_RBX = 37 + UC_X86_REG_RCX = 38 + UC_X86_REG_RDI = 39 + UC_X86_REG_RDX = 40 + UC_X86_REG_RIP = 41 + UC_X86_REG_RIZ = 42 + UC_X86_REG_RSI = 43 + UC_X86_REG_RSP = 44 + UC_X86_REG_SI = 45 + UC_X86_REG_SIL = 46 + UC_X86_REG_SP = 47 + UC_X86_REG_SPL = 48 + UC_X86_REG_SS = 49 + UC_X86_REG_CR0 = 50 + UC_X86_REG_CR1 = 51 + UC_X86_REG_CR2 = 52 + UC_X86_REG_CR3 = 53 + UC_X86_REG_CR4 = 54 + UC_X86_REG_CR5 = 55 + UC_X86_REG_CR6 = 56 + UC_X86_REG_CR7 = 57 + UC_X86_REG_CR8 = 58 + UC_X86_REG_CR9 = 59 + UC_X86_REG_CR10 = 60 + UC_X86_REG_CR11 = 61 + UC_X86_REG_CR12 = 62 + UC_X86_REG_CR13 = 63 + UC_X86_REG_CR14 = 64 + UC_X86_REG_CR15 = 65 + UC_X86_REG_DR0 = 66 + UC_X86_REG_DR1 = 67 + UC_X86_REG_DR2 = 68 + UC_X86_REG_DR3 = 69 + UC_X86_REG_DR4 = 70 + UC_X86_REG_DR5 = 71 + UC_X86_REG_DR6 = 72 + UC_X86_REG_DR7 = 73 + UC_X86_REG_DR8 = 74 + UC_X86_REG_DR9 = 75 + UC_X86_REG_DR10 = 76 + UC_X86_REG_DR11 = 77 + UC_X86_REG_DR12 = 78 + UC_X86_REG_DR13 = 79 + UC_X86_REG_DR14 = 80 + UC_X86_REG_DR15 = 81 + UC_X86_REG_FP0 = 82 + UC_X86_REG_FP1 = 83 + UC_X86_REG_FP2 = 84 + UC_X86_REG_FP3 = 85 + UC_X86_REG_FP4 = 86 + UC_X86_REG_FP5 = 87 + UC_X86_REG_FP6 = 88 + UC_X86_REG_FP7 = 89 + UC_X86_REG_K0 = 90 + UC_X86_REG_K1 = 91 + UC_X86_REG_K2 = 92 + UC_X86_REG_K3 = 93 + UC_X86_REG_K4 = 94 + UC_X86_REG_K5 = 95 + UC_X86_REG_K6 = 96 + UC_X86_REG_K7 = 97 + UC_X86_REG_MM0 = 98 + UC_X86_REG_MM1 = 99 + UC_X86_REG_MM2 = 100 + UC_X86_REG_MM3 = 101 + UC_X86_REG_MM4 = 102 + UC_X86_REG_MM5 = 103 + UC_X86_REG_MM6 = 104 + UC_X86_REG_MM7 = 105 + UC_X86_REG_R8 = 106 + UC_X86_REG_R9 = 107 + UC_X86_REG_R10 = 108 + UC_X86_REG_R11 = 109 + UC_X86_REG_R12 = 110 + UC_X86_REG_R13 = 111 + UC_X86_REG_R14 = 112 + UC_X86_REG_R15 = 113 + UC_X86_REG_ST0 = 114 + UC_X86_REG_ST1 = 115 + UC_X86_REG_ST2 = 116 + UC_X86_REG_ST3 = 117 + UC_X86_REG_ST4 = 118 + UC_X86_REG_ST5 = 119 + UC_X86_REG_ST6 = 120 + UC_X86_REG_ST7 = 121 + UC_X86_REG_XMM0 = 122 + UC_X86_REG_XMM1 = 123 + UC_X86_REG_XMM2 = 124 + UC_X86_REG_XMM3 = 125 + UC_X86_REG_XMM4 = 126 + UC_X86_REG_XMM5 = 127 + UC_X86_REG_XMM6 = 128 + UC_X86_REG_XMM7 = 129 + UC_X86_REG_XMM8 = 130 + UC_X86_REG_XMM9 = 131 + UC_X86_REG_XMM10 = 132 + UC_X86_REG_XMM11 = 133 + UC_X86_REG_XMM12 = 134 + UC_X86_REG_XMM13 = 135 + UC_X86_REG_XMM14 = 136 + UC_X86_REG_XMM15 = 137 + UC_X86_REG_XMM16 = 138 + UC_X86_REG_XMM17 = 139 + UC_X86_REG_XMM18 = 140 + UC_X86_REG_XMM19 = 141 + UC_X86_REG_XMM20 = 142 + UC_X86_REG_XMM21 = 143 + UC_X86_REG_XMM22 = 144 + UC_X86_REG_XMM23 = 145 + UC_X86_REG_XMM24 = 146 + UC_X86_REG_XMM25 = 147 + UC_X86_REG_XMM26 = 148 + UC_X86_REG_XMM27 = 149 + UC_X86_REG_XMM28 = 150 + UC_X86_REG_XMM29 = 151 + UC_X86_REG_XMM30 = 152 + UC_X86_REG_XMM31 = 153 + UC_X86_REG_YMM0 = 154 + UC_X86_REG_YMM1 = 155 + UC_X86_REG_YMM2 = 156 + UC_X86_REG_YMM3 = 157 + UC_X86_REG_YMM4 = 158 + UC_X86_REG_YMM5 = 159 + UC_X86_REG_YMM6 = 160 + UC_X86_REG_YMM7 = 161 + UC_X86_REG_YMM8 = 162 + UC_X86_REG_YMM9 = 163 + UC_X86_REG_YMM10 = 164 + UC_X86_REG_YMM11 = 165 + UC_X86_REG_YMM12 = 166 + UC_X86_REG_YMM13 = 167 + UC_X86_REG_YMM14 = 168 + UC_X86_REG_YMM15 = 169 + UC_X86_REG_YMM16 = 170 + UC_X86_REG_YMM17 = 171 + UC_X86_REG_YMM18 = 172 + UC_X86_REG_YMM19 = 173 + UC_X86_REG_YMM20 = 174 + UC_X86_REG_YMM21 = 175 + UC_X86_REG_YMM22 = 176 + UC_X86_REG_YMM23 = 177 + UC_X86_REG_YMM24 = 178 + UC_X86_REG_YMM25 = 179 + UC_X86_REG_YMM26 = 180 + UC_X86_REG_YMM27 = 181 + UC_X86_REG_YMM28 = 182 + UC_X86_REG_YMM29 = 183 + UC_X86_REG_YMM30 = 184 + UC_X86_REG_YMM31 = 185 + UC_X86_REG_ZMM0 = 186 + UC_X86_REG_ZMM1 = 187 + UC_X86_REG_ZMM2 = 188 + UC_X86_REG_ZMM3 = 189 + UC_X86_REG_ZMM4 = 190 + UC_X86_REG_ZMM5 = 191 + UC_X86_REG_ZMM6 = 192 + UC_X86_REG_ZMM7 = 193 + UC_X86_REG_ZMM8 = 194 + UC_X86_REG_ZMM9 = 195 + UC_X86_REG_ZMM10 = 196 + UC_X86_REG_ZMM11 = 197 + UC_X86_REG_ZMM12 = 198 + UC_X86_REG_ZMM13 = 199 + UC_X86_REG_ZMM14 = 200 + UC_X86_REG_ZMM15 = 201 + UC_X86_REG_ZMM16 = 202 + UC_X86_REG_ZMM17 = 203 + UC_X86_REG_ZMM18 = 204 + UC_X86_REG_ZMM19 = 205 + UC_X86_REG_ZMM20 = 206 + UC_X86_REG_ZMM21 = 207 + UC_X86_REG_ZMM22 = 208 + UC_X86_REG_ZMM23 = 209 + UC_X86_REG_ZMM24 = 210 + UC_X86_REG_ZMM25 = 211 + UC_X86_REG_ZMM26 = 212 + UC_X86_REG_ZMM27 = 213 + UC_X86_REG_ZMM28 = 214 + UC_X86_REG_ZMM29 = 215 + UC_X86_REG_ZMM30 = 216 + UC_X86_REG_ZMM31 = 217 + UC_X86_REG_R8B = 218 + UC_X86_REG_R9B = 219 + UC_X86_REG_R10B = 220 + UC_X86_REG_R11B = 221 + UC_X86_REG_R12B = 222 + UC_X86_REG_R13B = 223 + UC_X86_REG_R14B = 224 + UC_X86_REG_R15B = 225 + UC_X86_REG_R8D = 226 + UC_X86_REG_R9D = 227 + UC_X86_REG_R10D = 228 + UC_X86_REG_R11D = 229 + UC_X86_REG_R12D = 230 + UC_X86_REG_R13D = 231 + UC_X86_REG_R14D = 232 + UC_X86_REG_R15D = 233 + UC_X86_REG_R8W = 234 + UC_X86_REG_R9W = 235 + UC_X86_REG_R10W = 236 + UC_X86_REG_R11W = 237 + UC_X86_REG_R12W = 238 + UC_X86_REG_R13W = 239 + UC_X86_REG_R14W = 240 + UC_X86_REG_R15W = 241 + UC_X86_REG_IDTR = 242 + UC_X86_REG_GDTR = 243 + UC_X86_REG_LDTR = 244 + UC_X86_REG_TR = 245 + UC_X86_REG_FPCW = 246 + UC_X86_REG_FPTAG = 247 + UC_X86_REG_ENDING = 248 + +# X86 instructions + + UC_X86_INS_INVALID = 0 + UC_X86_INS_AAA = 1 + UC_X86_INS_AAD = 2 + UC_X86_INS_AAM = 3 + UC_X86_INS_AAS = 4 + UC_X86_INS_FABS = 5 + UC_X86_INS_ADC = 6 + UC_X86_INS_ADCX = 7 + UC_X86_INS_ADD = 8 + UC_X86_INS_ADDPD = 9 + UC_X86_INS_ADDPS = 10 + UC_X86_INS_ADDSD = 11 + UC_X86_INS_ADDSS = 12 + UC_X86_INS_ADDSUBPD = 13 + UC_X86_INS_ADDSUBPS = 14 + UC_X86_INS_FADD = 15 + UC_X86_INS_FIADD = 16 + UC_X86_INS_FADDP = 17 + UC_X86_INS_ADOX = 18 + UC_X86_INS_AESDECLAST = 19 + UC_X86_INS_AESDEC = 20 + UC_X86_INS_AESENCLAST = 21 + UC_X86_INS_AESENC = 22 + UC_X86_INS_AESIMC = 23 + UC_X86_INS_AESKEYGENASSIST = 24 + UC_X86_INS_AND = 25 + UC_X86_INS_ANDN = 26 + UC_X86_INS_ANDNPD = 27 + UC_X86_INS_ANDNPS = 28 + UC_X86_INS_ANDPD = 29 + UC_X86_INS_ANDPS = 30 + UC_X86_INS_ARPL = 31 + UC_X86_INS_BEXTR = 32 + UC_X86_INS_BLCFILL = 33 + UC_X86_INS_BLCI = 34 + UC_X86_INS_BLCIC = 35 + UC_X86_INS_BLCMSK = 36 + UC_X86_INS_BLCS = 37 + UC_X86_INS_BLENDPD = 38 + UC_X86_INS_BLENDPS = 39 + UC_X86_INS_BLENDVPD = 40 + UC_X86_INS_BLENDVPS = 41 + UC_X86_INS_BLSFILL = 42 + UC_X86_INS_BLSI = 43 + UC_X86_INS_BLSIC = 44 + UC_X86_INS_BLSMSK = 45 + UC_X86_INS_BLSR = 46 + UC_X86_INS_BOUND = 47 + UC_X86_INS_BSF = 48 + UC_X86_INS_BSR = 49 + UC_X86_INS_BSWAP = 50 + UC_X86_INS_BT = 51 + UC_X86_INS_BTC = 52 + UC_X86_INS_BTR = 53 + UC_X86_INS_BTS = 54 + UC_X86_INS_BZHI = 55 + UC_X86_INS_CALL = 56 + UC_X86_INS_CBW = 57 + UC_X86_INS_CDQ = 58 + UC_X86_INS_CDQE = 59 + UC_X86_INS_FCHS = 60 + UC_X86_INS_CLAC = 61 + UC_X86_INS_CLC = 62 + UC_X86_INS_CLD = 63 + UC_X86_INS_CLFLUSH = 64 + UC_X86_INS_CLFLUSHOPT = 65 + UC_X86_INS_CLGI = 66 + UC_X86_INS_CLI = 67 + UC_X86_INS_CLTS = 68 + UC_X86_INS_CLWB = 69 + UC_X86_INS_CMC = 70 + UC_X86_INS_CMOVA = 71 + UC_X86_INS_CMOVAE = 72 + UC_X86_INS_CMOVB = 73 + UC_X86_INS_CMOVBE = 74 + UC_X86_INS_FCMOVBE = 75 + UC_X86_INS_FCMOVB = 76 + UC_X86_INS_CMOVE = 77 + UC_X86_INS_FCMOVE = 78 + UC_X86_INS_CMOVG = 79 + UC_X86_INS_CMOVGE = 80 + UC_X86_INS_CMOVL = 81 + UC_X86_INS_CMOVLE = 82 + UC_X86_INS_FCMOVNBE = 83 + UC_X86_INS_FCMOVNB = 84 + UC_X86_INS_CMOVNE = 85 + UC_X86_INS_FCMOVNE = 86 + UC_X86_INS_CMOVNO = 87 + UC_X86_INS_CMOVNP = 88 + UC_X86_INS_FCMOVNU = 89 + UC_X86_INS_CMOVNS = 90 + UC_X86_INS_CMOVO = 91 + UC_X86_INS_CMOVP = 92 + UC_X86_INS_FCMOVU = 93 + UC_X86_INS_CMOVS = 94 + UC_X86_INS_CMP = 95 + UC_X86_INS_CMPPD = 96 + UC_X86_INS_CMPPS = 97 + UC_X86_INS_CMPSB = 98 + UC_X86_INS_CMPSD = 99 + UC_X86_INS_CMPSQ = 100 + UC_X86_INS_CMPSS = 101 + UC_X86_INS_CMPSW = 102 + UC_X86_INS_CMPXCHG16B = 103 + UC_X86_INS_CMPXCHG = 104 + UC_X86_INS_CMPXCHG8B = 105 + UC_X86_INS_COMISD = 106 + UC_X86_INS_COMISS = 107 + UC_X86_INS_FCOMP = 108 + UC_X86_INS_FCOMPI = 109 + UC_X86_INS_FCOMI = 110 + UC_X86_INS_FCOM = 111 + UC_X86_INS_FCOS = 112 + UC_X86_INS_CPUID = 113 + UC_X86_INS_CQO = 114 + UC_X86_INS_CRC32 = 115 + UC_X86_INS_CVTDQ2PD = 116 + UC_X86_INS_CVTDQ2PS = 117 + UC_X86_INS_CVTPD2DQ = 118 + UC_X86_INS_CVTPD2PS = 119 + UC_X86_INS_CVTPS2DQ = 120 + UC_X86_INS_CVTPS2PD = 121 + UC_X86_INS_CVTSD2SI = 122 + UC_X86_INS_CVTSD2SS = 123 + UC_X86_INS_CVTSI2SD = 124 + UC_X86_INS_CVTSI2SS = 125 + UC_X86_INS_CVTSS2SD = 126 + UC_X86_INS_CVTSS2SI = 127 + UC_X86_INS_CVTTPD2DQ = 128 + UC_X86_INS_CVTTPS2DQ = 129 + UC_X86_INS_CVTTSD2SI = 130 + UC_X86_INS_CVTTSS2SI = 131 + UC_X86_INS_CWD = 132 + UC_X86_INS_CWDE = 133 + UC_X86_INS_DAA = 134 + UC_X86_INS_DAS = 135 + UC_X86_INS_DATA16 = 136 + UC_X86_INS_DEC = 137 + UC_X86_INS_DIV = 138 + UC_X86_INS_DIVPD = 139 + UC_X86_INS_DIVPS = 140 + UC_X86_INS_FDIVR = 141 + UC_X86_INS_FIDIVR = 142 + UC_X86_INS_FDIVRP = 143 + UC_X86_INS_DIVSD = 144 + UC_X86_INS_DIVSS = 145 + UC_X86_INS_FDIV = 146 + UC_X86_INS_FIDIV = 147 + UC_X86_INS_FDIVP = 148 + UC_X86_INS_DPPD = 149 + UC_X86_INS_DPPS = 150 + UC_X86_INS_RET = 151 + UC_X86_INS_ENCLS = 152 + UC_X86_INS_ENCLU = 153 + UC_X86_INS_ENTER = 154 + UC_X86_INS_EXTRACTPS = 155 + UC_X86_INS_EXTRQ = 156 + UC_X86_INS_F2XM1 = 157 + UC_X86_INS_LCALL = 158 + UC_X86_INS_LJMP = 159 + UC_X86_INS_FBLD = 160 + UC_X86_INS_FBSTP = 161 + UC_X86_INS_FCOMPP = 162 + UC_X86_INS_FDECSTP = 163 + UC_X86_INS_FEMMS = 164 + UC_X86_INS_FFREE = 165 + UC_X86_INS_FICOM = 166 + UC_X86_INS_FICOMP = 167 + UC_X86_INS_FINCSTP = 168 + UC_X86_INS_FLDCW = 169 + UC_X86_INS_FLDENV = 170 + UC_X86_INS_FLDL2E = 171 + UC_X86_INS_FLDL2T = 172 + UC_X86_INS_FLDLG2 = 173 + UC_X86_INS_FLDLN2 = 174 + UC_X86_INS_FLDPI = 175 + UC_X86_INS_FNCLEX = 176 + UC_X86_INS_FNINIT = 177 + UC_X86_INS_FNOP = 178 + UC_X86_INS_FNSTCW = 179 + UC_X86_INS_FNSTSW = 180 + UC_X86_INS_FPATAN = 181 + UC_X86_INS_FPREM = 182 + UC_X86_INS_FPREM1 = 183 + UC_X86_INS_FPTAN = 184 + UC_X86_INS_FFREEP = 185 + UC_X86_INS_FRNDINT = 186 + UC_X86_INS_FRSTOR = 187 + UC_X86_INS_FNSAVE = 188 + UC_X86_INS_FSCALE = 189 + UC_X86_INS_FSETPM = 190 + UC_X86_INS_FSINCOS = 191 + UC_X86_INS_FNSTENV = 192 + UC_X86_INS_FXAM = 193 + UC_X86_INS_FXRSTOR = 194 + UC_X86_INS_FXRSTOR64 = 195 + UC_X86_INS_FXSAVE = 196 + UC_X86_INS_FXSAVE64 = 197 + UC_X86_INS_FXTRACT = 198 + UC_X86_INS_FYL2X = 199 + UC_X86_INS_FYL2XP1 = 200 + UC_X86_INS_MOVAPD = 201 + UC_X86_INS_MOVAPS = 202 + UC_X86_INS_ORPD = 203 + UC_X86_INS_ORPS = 204 + UC_X86_INS_VMOVAPD = 205 + UC_X86_INS_VMOVAPS = 206 + UC_X86_INS_XORPD = 207 + UC_X86_INS_XORPS = 208 + UC_X86_INS_GETSEC = 209 + UC_X86_INS_HADDPD = 210 + UC_X86_INS_HADDPS = 211 + UC_X86_INS_HLT = 212 + UC_X86_INS_HSUBPD = 213 + UC_X86_INS_HSUBPS = 214 + UC_X86_INS_IDIV = 215 + UC_X86_INS_FILD = 216 + UC_X86_INS_IMUL = 217 + UC_X86_INS_IN = 218 + UC_X86_INS_INC = 219 + UC_X86_INS_INSB = 220 + UC_X86_INS_INSERTPS = 221 + UC_X86_INS_INSERTQ = 222 + UC_X86_INS_INSD = 223 + UC_X86_INS_INSW = 224 + UC_X86_INS_INT = 225 + UC_X86_INS_INT1 = 226 + UC_X86_INS_INT3 = 227 + UC_X86_INS_INTO = 228 + UC_X86_INS_INVD = 229 + UC_X86_INS_INVEPT = 230 + UC_X86_INS_INVLPG = 231 + UC_X86_INS_INVLPGA = 232 + UC_X86_INS_INVPCID = 233 + UC_X86_INS_INVVPID = 234 + UC_X86_INS_IRET = 235 + UC_X86_INS_IRETD = 236 + UC_X86_INS_IRETQ = 237 + UC_X86_INS_FISTTP = 238 + UC_X86_INS_FIST = 239 + UC_X86_INS_FISTP = 240 + UC_X86_INS_UCOMISD = 241 + UC_X86_INS_UCOMISS = 242 + UC_X86_INS_VCOMISD = 243 + UC_X86_INS_VCOMISS = 244 + UC_X86_INS_VCVTSD2SS = 245 + UC_X86_INS_VCVTSI2SD = 246 + UC_X86_INS_VCVTSI2SS = 247 + UC_X86_INS_VCVTSS2SD = 248 + UC_X86_INS_VCVTTSD2SI = 249 + UC_X86_INS_VCVTTSD2USI = 250 + UC_X86_INS_VCVTTSS2SI = 251 + UC_X86_INS_VCVTTSS2USI = 252 + UC_X86_INS_VCVTUSI2SD = 253 + UC_X86_INS_VCVTUSI2SS = 254 + UC_X86_INS_VUCOMISD = 255 + UC_X86_INS_VUCOMISS = 256 + UC_X86_INS_JAE = 257 + UC_X86_INS_JA = 258 + UC_X86_INS_JBE = 259 + UC_X86_INS_JB = 260 + UC_X86_INS_JCXZ = 261 + UC_X86_INS_JECXZ = 262 + UC_X86_INS_JE = 263 + UC_X86_INS_JGE = 264 + UC_X86_INS_JG = 265 + UC_X86_INS_JLE = 266 + UC_X86_INS_JL = 267 + UC_X86_INS_JMP = 268 + UC_X86_INS_JNE = 269 + UC_X86_INS_JNO = 270 + UC_X86_INS_JNP = 271 + UC_X86_INS_JNS = 272 + UC_X86_INS_JO = 273 + UC_X86_INS_JP = 274 + UC_X86_INS_JRCXZ = 275 + UC_X86_INS_JS = 276 + UC_X86_INS_KANDB = 277 + UC_X86_INS_KANDD = 278 + UC_X86_INS_KANDNB = 279 + UC_X86_INS_KANDND = 280 + UC_X86_INS_KANDNQ = 281 + UC_X86_INS_KANDNW = 282 + UC_X86_INS_KANDQ = 283 + UC_X86_INS_KANDW = 284 + UC_X86_INS_KMOVB = 285 + UC_X86_INS_KMOVD = 286 + UC_X86_INS_KMOVQ = 287 + UC_X86_INS_KMOVW = 288 + UC_X86_INS_KNOTB = 289 + UC_X86_INS_KNOTD = 290 + UC_X86_INS_KNOTQ = 291 + UC_X86_INS_KNOTW = 292 + UC_X86_INS_KORB = 293 + UC_X86_INS_KORD = 294 + UC_X86_INS_KORQ = 295 + UC_X86_INS_KORTESTB = 296 + UC_X86_INS_KORTESTD = 297 + UC_X86_INS_KORTESTQ = 298 + UC_X86_INS_KORTESTW = 299 + UC_X86_INS_KORW = 300 + UC_X86_INS_KSHIFTLB = 301 + UC_X86_INS_KSHIFTLD = 302 + UC_X86_INS_KSHIFTLQ = 303 + UC_X86_INS_KSHIFTLW = 304 + UC_X86_INS_KSHIFTRB = 305 + UC_X86_INS_KSHIFTRD = 306 + UC_X86_INS_KSHIFTRQ = 307 + UC_X86_INS_KSHIFTRW = 308 + UC_X86_INS_KUNPCKBW = 309 + UC_X86_INS_KXNORB = 310 + UC_X86_INS_KXNORD = 311 + UC_X86_INS_KXNORQ = 312 + UC_X86_INS_KXNORW = 313 + UC_X86_INS_KXORB = 314 + UC_X86_INS_KXORD = 315 + UC_X86_INS_KXORQ = 316 + UC_X86_INS_KXORW = 317 + UC_X86_INS_LAHF = 318 + UC_X86_INS_LAR = 319 + UC_X86_INS_LDDQU = 320 + UC_X86_INS_LDMXCSR = 321 + UC_X86_INS_LDS = 322 + UC_X86_INS_FLDZ = 323 + UC_X86_INS_FLD1 = 324 + UC_X86_INS_FLD = 325 + UC_X86_INS_LEA = 326 + UC_X86_INS_LEAVE = 327 + UC_X86_INS_LES = 328 + UC_X86_INS_LFENCE = 329 + UC_X86_INS_LFS = 330 + UC_X86_INS_LGDT = 331 + UC_X86_INS_LGS = 332 + UC_X86_INS_LIDT = 333 + UC_X86_INS_LLDT = 334 + UC_X86_INS_LMSW = 335 + UC_X86_INS_OR = 336 + UC_X86_INS_SUB = 337 + UC_X86_INS_XOR = 338 + UC_X86_INS_LODSB = 339 + UC_X86_INS_LODSD = 340 + UC_X86_INS_LODSQ = 341 + UC_X86_INS_LODSW = 342 + UC_X86_INS_LOOP = 343 + UC_X86_INS_LOOPE = 344 + UC_X86_INS_LOOPNE = 345 + UC_X86_INS_RETF = 346 + UC_X86_INS_RETFQ = 347 + UC_X86_INS_LSL = 348 + UC_X86_INS_LSS = 349 + UC_X86_INS_LTR = 350 + UC_X86_INS_XADD = 351 + UC_X86_INS_LZCNT = 352 + UC_X86_INS_MASKMOVDQU = 353 + UC_X86_INS_MAXPD = 354 + UC_X86_INS_MAXPS = 355 + UC_X86_INS_MAXSD = 356 + UC_X86_INS_MAXSS = 357 + UC_X86_INS_MFENCE = 358 + UC_X86_INS_MINPD = 359 + UC_X86_INS_MINPS = 360 + UC_X86_INS_MINSD = 361 + UC_X86_INS_MINSS = 362 + UC_X86_INS_CVTPD2PI = 363 + UC_X86_INS_CVTPI2PD = 364 + UC_X86_INS_CVTPI2PS = 365 + UC_X86_INS_CVTPS2PI = 366 + UC_X86_INS_CVTTPD2PI = 367 + UC_X86_INS_CVTTPS2PI = 368 + UC_X86_INS_EMMS = 369 + UC_X86_INS_MASKMOVQ = 370 + UC_X86_INS_MOVD = 371 + UC_X86_INS_MOVDQ2Q = 372 + UC_X86_INS_MOVNTQ = 373 + UC_X86_INS_MOVQ2DQ = 374 + UC_X86_INS_MOVQ = 375 + UC_X86_INS_PABSB = 376 + UC_X86_INS_PABSD = 377 + UC_X86_INS_PABSW = 378 + UC_X86_INS_PACKSSDW = 379 + UC_X86_INS_PACKSSWB = 380 + UC_X86_INS_PACKUSWB = 381 + UC_X86_INS_PADDB = 382 + UC_X86_INS_PADDD = 383 + UC_X86_INS_PADDQ = 384 + UC_X86_INS_PADDSB = 385 + UC_X86_INS_PADDSW = 386 + UC_X86_INS_PADDUSB = 387 + UC_X86_INS_PADDUSW = 388 + UC_X86_INS_PADDW = 389 + UC_X86_INS_PALIGNR = 390 + UC_X86_INS_PANDN = 391 + UC_X86_INS_PAND = 392 + UC_X86_INS_PAVGB = 393 + UC_X86_INS_PAVGW = 394 + UC_X86_INS_PCMPEQB = 395 + UC_X86_INS_PCMPEQD = 396 + UC_X86_INS_PCMPEQW = 397 + UC_X86_INS_PCMPGTB = 398 + UC_X86_INS_PCMPGTD = 399 + UC_X86_INS_PCMPGTW = 400 + UC_X86_INS_PEXTRW = 401 + UC_X86_INS_PHADDSW = 402 + UC_X86_INS_PHADDW = 403 + UC_X86_INS_PHADDD = 404 + UC_X86_INS_PHSUBD = 405 + UC_X86_INS_PHSUBSW = 406 + UC_X86_INS_PHSUBW = 407 + UC_X86_INS_PINSRW = 408 + UC_X86_INS_PMADDUBSW = 409 + UC_X86_INS_PMADDWD = 410 + UC_X86_INS_PMAXSW = 411 + UC_X86_INS_PMAXUB = 412 + UC_X86_INS_PMINSW = 413 + UC_X86_INS_PMINUB = 414 + UC_X86_INS_PMOVMSKB = 415 + UC_X86_INS_PMULHRSW = 416 + UC_X86_INS_PMULHUW = 417 + UC_X86_INS_PMULHW = 418 + UC_X86_INS_PMULLW = 419 + UC_X86_INS_PMULUDQ = 420 + UC_X86_INS_POR = 421 + UC_X86_INS_PSADBW = 422 + UC_X86_INS_PSHUFB = 423 + UC_X86_INS_PSHUFW = 424 + UC_X86_INS_PSIGNB = 425 + UC_X86_INS_PSIGND = 426 + UC_X86_INS_PSIGNW = 427 + UC_X86_INS_PSLLD = 428 + UC_X86_INS_PSLLQ = 429 + UC_X86_INS_PSLLW = 430 + UC_X86_INS_PSRAD = 431 + UC_X86_INS_PSRAW = 432 + UC_X86_INS_PSRLD = 433 + UC_X86_INS_PSRLQ = 434 + UC_X86_INS_PSRLW = 435 + UC_X86_INS_PSUBB = 436 + UC_X86_INS_PSUBD = 437 + UC_X86_INS_PSUBQ = 438 + UC_X86_INS_PSUBSB = 439 + UC_X86_INS_PSUBSW = 440 + UC_X86_INS_PSUBUSB = 441 + UC_X86_INS_PSUBUSW = 442 + UC_X86_INS_PSUBW = 443 + UC_X86_INS_PUNPCKHBW = 444 + UC_X86_INS_PUNPCKHDQ = 445 + UC_X86_INS_PUNPCKHWD = 446 + UC_X86_INS_PUNPCKLBW = 447 + UC_X86_INS_PUNPCKLDQ = 448 + UC_X86_INS_PUNPCKLWD = 449 + UC_X86_INS_PXOR = 450 + UC_X86_INS_MONITOR = 451 + UC_X86_INS_MONTMUL = 452 + UC_X86_INS_MOV = 453 + UC_X86_INS_MOVABS = 454 + UC_X86_INS_MOVBE = 455 + UC_X86_INS_MOVDDUP = 456 + UC_X86_INS_MOVDQA = 457 + UC_X86_INS_MOVDQU = 458 + UC_X86_INS_MOVHLPS = 459 + UC_X86_INS_MOVHPD = 460 + UC_X86_INS_MOVHPS = 461 + UC_X86_INS_MOVLHPS = 462 + UC_X86_INS_MOVLPD = 463 + UC_X86_INS_MOVLPS = 464 + UC_X86_INS_MOVMSKPD = 465 + UC_X86_INS_MOVMSKPS = 466 + UC_X86_INS_MOVNTDQA = 467 + UC_X86_INS_MOVNTDQ = 468 + UC_X86_INS_MOVNTI = 469 + UC_X86_INS_MOVNTPD = 470 + UC_X86_INS_MOVNTPS = 471 + UC_X86_INS_MOVNTSD = 472 + UC_X86_INS_MOVNTSS = 473 + UC_X86_INS_MOVSB = 474 + UC_X86_INS_MOVSD = 475 + UC_X86_INS_MOVSHDUP = 476 + UC_X86_INS_MOVSLDUP = 477 + UC_X86_INS_MOVSQ = 478 + UC_X86_INS_MOVSS = 479 + UC_X86_INS_MOVSW = 480 + UC_X86_INS_MOVSX = 481 + UC_X86_INS_MOVSXD = 482 + UC_X86_INS_MOVUPD = 483 + UC_X86_INS_MOVUPS = 484 + UC_X86_INS_MOVZX = 485 + UC_X86_INS_MPSADBW = 486 + UC_X86_INS_MUL = 487 + UC_X86_INS_MULPD = 488 + UC_X86_INS_MULPS = 489 + UC_X86_INS_MULSD = 490 + UC_X86_INS_MULSS = 491 + UC_X86_INS_MULX = 492 + UC_X86_INS_FMUL = 493 + UC_X86_INS_FIMUL = 494 + UC_X86_INS_FMULP = 495 + UC_X86_INS_MWAIT = 496 + UC_X86_INS_NEG = 497 + UC_X86_INS_NOP = 498 + UC_X86_INS_NOT = 499 + UC_X86_INS_OUT = 500 + UC_X86_INS_OUTSB = 501 + UC_X86_INS_OUTSD = 502 + UC_X86_INS_OUTSW = 503 + UC_X86_INS_PACKUSDW = 504 + UC_X86_INS_PAUSE = 505 + UC_X86_INS_PAVGUSB = 506 + UC_X86_INS_PBLENDVB = 507 + UC_X86_INS_PBLENDW = 508 + UC_X86_INS_PCLMULQDQ = 509 + UC_X86_INS_PCMPEQQ = 510 + UC_X86_INS_PCMPESTRI = 511 + UC_X86_INS_PCMPESTRM = 512 + UC_X86_INS_PCMPGTQ = 513 + UC_X86_INS_PCMPISTRI = 514 + UC_X86_INS_PCMPISTRM = 515 + UC_X86_INS_PCOMMIT = 516 + UC_X86_INS_PDEP = 517 + UC_X86_INS_PEXT = 518 + UC_X86_INS_PEXTRB = 519 + UC_X86_INS_PEXTRD = 520 + UC_X86_INS_PEXTRQ = 521 + UC_X86_INS_PF2ID = 522 + UC_X86_INS_PF2IW = 523 + UC_X86_INS_PFACC = 524 + UC_X86_INS_PFADD = 525 + UC_X86_INS_PFCMPEQ = 526 + UC_X86_INS_PFCMPGE = 527 + UC_X86_INS_PFCMPGT = 528 + UC_X86_INS_PFMAX = 529 + UC_X86_INS_PFMIN = 530 + UC_X86_INS_PFMUL = 531 + UC_X86_INS_PFNACC = 532 + UC_X86_INS_PFPNACC = 533 + UC_X86_INS_PFRCPIT1 = 534 + UC_X86_INS_PFRCPIT2 = 535 + UC_X86_INS_PFRCP = 536 + UC_X86_INS_PFRSQIT1 = 537 + UC_X86_INS_PFRSQRT = 538 + UC_X86_INS_PFSUBR = 539 + UC_X86_INS_PFSUB = 540 + UC_X86_INS_PHMINPOSUW = 541 + UC_X86_INS_PI2FD = 542 + UC_X86_INS_PI2FW = 543 + UC_X86_INS_PINSRB = 544 + UC_X86_INS_PINSRD = 545 + UC_X86_INS_PINSRQ = 546 + UC_X86_INS_PMAXSB = 547 + UC_X86_INS_PMAXSD = 548 + UC_X86_INS_PMAXUD = 549 + UC_X86_INS_PMAXUW = 550 + UC_X86_INS_PMINSB = 551 + UC_X86_INS_PMINSD = 552 + UC_X86_INS_PMINUD = 553 + UC_X86_INS_PMINUW = 554 + UC_X86_INS_PMOVSXBD = 555 + UC_X86_INS_PMOVSXBQ = 556 + UC_X86_INS_PMOVSXBW = 557 + UC_X86_INS_PMOVSXDQ = 558 + UC_X86_INS_PMOVSXWD = 559 + UC_X86_INS_PMOVSXWQ = 560 + UC_X86_INS_PMOVZXBD = 561 + UC_X86_INS_PMOVZXBQ = 562 + UC_X86_INS_PMOVZXBW = 563 + UC_X86_INS_PMOVZXDQ = 564 + UC_X86_INS_PMOVZXWD = 565 + UC_X86_INS_PMOVZXWQ = 566 + UC_X86_INS_PMULDQ = 567 + UC_X86_INS_PMULHRW = 568 + UC_X86_INS_PMULLD = 569 + UC_X86_INS_POP = 570 + UC_X86_INS_POPAW = 571 + UC_X86_INS_POPAL = 572 + UC_X86_INS_POPCNT = 573 + UC_X86_INS_POPF = 574 + UC_X86_INS_POPFD = 575 + UC_X86_INS_POPFQ = 576 + UC_X86_INS_PREFETCH = 577 + UC_X86_INS_PREFETCHNTA = 578 + UC_X86_INS_PREFETCHT0 = 579 + UC_X86_INS_PREFETCHT1 = 580 + UC_X86_INS_PREFETCHT2 = 581 + UC_X86_INS_PREFETCHW = 582 + UC_X86_INS_PSHUFD = 583 + UC_X86_INS_PSHUFHW = 584 + UC_X86_INS_PSHUFLW = 585 + UC_X86_INS_PSLLDQ = 586 + UC_X86_INS_PSRLDQ = 587 + UC_X86_INS_PSWAPD = 588 + UC_X86_INS_PTEST = 589 + UC_X86_INS_PUNPCKHQDQ = 590 + UC_X86_INS_PUNPCKLQDQ = 591 + UC_X86_INS_PUSH = 592 + UC_X86_INS_PUSHAW = 593 + UC_X86_INS_PUSHAL = 594 + UC_X86_INS_PUSHF = 595 + UC_X86_INS_PUSHFD = 596 + UC_X86_INS_PUSHFQ = 597 + UC_X86_INS_RCL = 598 + UC_X86_INS_RCPPS = 599 + UC_X86_INS_RCPSS = 600 + UC_X86_INS_RCR = 601 + UC_X86_INS_RDFSBASE = 602 + UC_X86_INS_RDGSBASE = 603 + UC_X86_INS_RDMSR = 604 + UC_X86_INS_RDPMC = 605 + UC_X86_INS_RDRAND = 606 + UC_X86_INS_RDSEED = 607 + UC_X86_INS_RDTSC = 608 + UC_X86_INS_RDTSCP = 609 + UC_X86_INS_ROL = 610 + UC_X86_INS_ROR = 611 + UC_X86_INS_RORX = 612 + UC_X86_INS_ROUNDPD = 613 + UC_X86_INS_ROUNDPS = 614 + UC_X86_INS_ROUNDSD = 615 + UC_X86_INS_ROUNDSS = 616 + UC_X86_INS_RSM = 617 + UC_X86_INS_RSQRTPS = 618 + UC_X86_INS_RSQRTSS = 619 + UC_X86_INS_SAHF = 620 + UC_X86_INS_SAL = 621 + UC_X86_INS_SALC = 622 + UC_X86_INS_SAR = 623 + UC_X86_INS_SARX = 624 + UC_X86_INS_SBB = 625 + UC_X86_INS_SCASB = 626 + UC_X86_INS_SCASD = 627 + UC_X86_INS_SCASQ = 628 + UC_X86_INS_SCASW = 629 + UC_X86_INS_SETAE = 630 + UC_X86_INS_SETA = 631 + UC_X86_INS_SETBE = 632 + UC_X86_INS_SETB = 633 + UC_X86_INS_SETE = 634 + UC_X86_INS_SETGE = 635 + UC_X86_INS_SETG = 636 + UC_X86_INS_SETLE = 637 + UC_X86_INS_SETL = 638 + UC_X86_INS_SETNE = 639 + UC_X86_INS_SETNO = 640 + UC_X86_INS_SETNP = 641 + UC_X86_INS_SETNS = 642 + UC_X86_INS_SETO = 643 + UC_X86_INS_SETP = 644 + UC_X86_INS_SETS = 645 + UC_X86_INS_SFENCE = 646 + UC_X86_INS_SGDT = 647 + UC_X86_INS_SHA1MSG1 = 648 + UC_X86_INS_SHA1MSG2 = 649 + UC_X86_INS_SHA1NEXTE = 650 + UC_X86_INS_SHA1RNDS4 = 651 + UC_X86_INS_SHA256MSG1 = 652 + UC_X86_INS_SHA256MSG2 = 653 + UC_X86_INS_SHA256RNDS2 = 654 + UC_X86_INS_SHL = 655 + UC_X86_INS_SHLD = 656 + UC_X86_INS_SHLX = 657 + UC_X86_INS_SHR = 658 + UC_X86_INS_SHRD = 659 + UC_X86_INS_SHRX = 660 + UC_X86_INS_SHUFPD = 661 + UC_X86_INS_SHUFPS = 662 + UC_X86_INS_SIDT = 663 + UC_X86_INS_FSIN = 664 + UC_X86_INS_SKINIT = 665 + UC_X86_INS_SLDT = 666 + UC_X86_INS_SMSW = 667 + UC_X86_INS_SQRTPD = 668 + UC_X86_INS_SQRTPS = 669 + UC_X86_INS_SQRTSD = 670 + UC_X86_INS_SQRTSS = 671 + UC_X86_INS_FSQRT = 672 + UC_X86_INS_STAC = 673 + UC_X86_INS_STC = 674 + UC_X86_INS_STD = 675 + UC_X86_INS_STGI = 676 + UC_X86_INS_STI = 677 + UC_X86_INS_STMXCSR = 678 + UC_X86_INS_STOSB = 679 + UC_X86_INS_STOSD = 680 + UC_X86_INS_STOSQ = 681 + UC_X86_INS_STOSW = 682 + UC_X86_INS_STR = 683 + UC_X86_INS_FST = 684 + UC_X86_INS_FSTP = 685 + UC_X86_INS_FSTPNCE = 686 + UC_X86_INS_FXCH = 687 + UC_X86_INS_SUBPD = 688 + UC_X86_INS_SUBPS = 689 + UC_X86_INS_FSUBR = 690 + UC_X86_INS_FISUBR = 691 + UC_X86_INS_FSUBRP = 692 + UC_X86_INS_SUBSD = 693 + UC_X86_INS_SUBSS = 694 + UC_X86_INS_FSUB = 695 + UC_X86_INS_FISUB = 696 + UC_X86_INS_FSUBP = 697 + UC_X86_INS_SWAPGS = 698 + UC_X86_INS_SYSCALL = 699 + UC_X86_INS_SYSENTER = 700 + UC_X86_INS_SYSEXIT = 701 + UC_X86_INS_SYSRET = 702 + UC_X86_INS_T1MSKC = 703 + UC_X86_INS_TEST = 704 + UC_X86_INS_UD2 = 705 + UC_X86_INS_FTST = 706 + UC_X86_INS_TZCNT = 707 + UC_X86_INS_TZMSK = 708 + UC_X86_INS_FUCOMPI = 709 + UC_X86_INS_FUCOMI = 710 + UC_X86_INS_FUCOMPP = 711 + UC_X86_INS_FUCOMP = 712 + UC_X86_INS_FUCOM = 713 + UC_X86_INS_UD2B = 714 + UC_X86_INS_UNPCKHPD = 715 + UC_X86_INS_UNPCKHPS = 716 + UC_X86_INS_UNPCKLPD = 717 + UC_X86_INS_UNPCKLPS = 718 + UC_X86_INS_VADDPD = 719 + UC_X86_INS_VADDPS = 720 + UC_X86_INS_VADDSD = 721 + UC_X86_INS_VADDSS = 722 + UC_X86_INS_VADDSUBPD = 723 + UC_X86_INS_VADDSUBPS = 724 + UC_X86_INS_VAESDECLAST = 725 + UC_X86_INS_VAESDEC = 726 + UC_X86_INS_VAESENCLAST = 727 + UC_X86_INS_VAESENC = 728 + UC_X86_INS_VAESIMC = 729 + UC_X86_INS_VAESKEYGENASSIST = 730 + UC_X86_INS_VALIGND = 731 + UC_X86_INS_VALIGNQ = 732 + UC_X86_INS_VANDNPD = 733 + UC_X86_INS_VANDNPS = 734 + UC_X86_INS_VANDPD = 735 + UC_X86_INS_VANDPS = 736 + UC_X86_INS_VBLENDMPD = 737 + UC_X86_INS_VBLENDMPS = 738 + UC_X86_INS_VBLENDPD = 739 + UC_X86_INS_VBLENDPS = 740 + UC_X86_INS_VBLENDVPD = 741 + UC_X86_INS_VBLENDVPS = 742 + UC_X86_INS_VBROADCASTF128 = 743 + UC_X86_INS_VBROADCASTI32X4 = 744 + UC_X86_INS_VBROADCASTI64X4 = 745 + UC_X86_INS_VBROADCASTSD = 746 + UC_X86_INS_VBROADCASTSS = 747 + UC_X86_INS_VCMPPD = 748 + UC_X86_INS_VCMPPS = 749 + UC_X86_INS_VCMPSD = 750 + UC_X86_INS_VCMPSS = 751 + UC_X86_INS_VCOMPRESSPD = 752 + UC_X86_INS_VCOMPRESSPS = 753 + UC_X86_INS_VCVTDQ2PD = 754 + UC_X86_INS_VCVTDQ2PS = 755 + UC_X86_INS_VCVTPD2DQX = 756 + UC_X86_INS_VCVTPD2DQ = 757 + UC_X86_INS_VCVTPD2PSX = 758 + UC_X86_INS_VCVTPD2PS = 759 + UC_X86_INS_VCVTPD2UDQ = 760 + UC_X86_INS_VCVTPH2PS = 761 + UC_X86_INS_VCVTPS2DQ = 762 + UC_X86_INS_VCVTPS2PD = 763 + UC_X86_INS_VCVTPS2PH = 764 + UC_X86_INS_VCVTPS2UDQ = 765 + UC_X86_INS_VCVTSD2SI = 766 + UC_X86_INS_VCVTSD2USI = 767 + UC_X86_INS_VCVTSS2SI = 768 + UC_X86_INS_VCVTSS2USI = 769 + UC_X86_INS_VCVTTPD2DQX = 770 + UC_X86_INS_VCVTTPD2DQ = 771 + UC_X86_INS_VCVTTPD2UDQ = 772 + UC_X86_INS_VCVTTPS2DQ = 773 + UC_X86_INS_VCVTTPS2UDQ = 774 + UC_X86_INS_VCVTUDQ2PD = 775 + UC_X86_INS_VCVTUDQ2PS = 776 + UC_X86_INS_VDIVPD = 777 + UC_X86_INS_VDIVPS = 778 + UC_X86_INS_VDIVSD = 779 + UC_X86_INS_VDIVSS = 780 + UC_X86_INS_VDPPD = 781 + UC_X86_INS_VDPPS = 782 + UC_X86_INS_VERR = 783 + UC_X86_INS_VERW = 784 + UC_X86_INS_VEXP2PD = 785 + UC_X86_INS_VEXP2PS = 786 + UC_X86_INS_VEXPANDPD = 787 + UC_X86_INS_VEXPANDPS = 788 + UC_X86_INS_VEXTRACTF128 = 789 + UC_X86_INS_VEXTRACTF32X4 = 790 + UC_X86_INS_VEXTRACTF64X4 = 791 + UC_X86_INS_VEXTRACTI128 = 792 + UC_X86_INS_VEXTRACTI32X4 = 793 + UC_X86_INS_VEXTRACTI64X4 = 794 + UC_X86_INS_VEXTRACTPS = 795 + UC_X86_INS_VFMADD132PD = 796 + UC_X86_INS_VFMADD132PS = 797 + UC_X86_INS_VFMADDPD = 798 + UC_X86_INS_VFMADD213PD = 799 + UC_X86_INS_VFMADD231PD = 800 + UC_X86_INS_VFMADDPS = 801 + UC_X86_INS_VFMADD213PS = 802 + UC_X86_INS_VFMADD231PS = 803 + UC_X86_INS_VFMADDSD = 804 + UC_X86_INS_VFMADD213SD = 805 + UC_X86_INS_VFMADD132SD = 806 + UC_X86_INS_VFMADD231SD = 807 + UC_X86_INS_VFMADDSS = 808 + UC_X86_INS_VFMADD213SS = 809 + UC_X86_INS_VFMADD132SS = 810 + UC_X86_INS_VFMADD231SS = 811 + UC_X86_INS_VFMADDSUB132PD = 812 + UC_X86_INS_VFMADDSUB132PS = 813 + UC_X86_INS_VFMADDSUBPD = 814 + UC_X86_INS_VFMADDSUB213PD = 815 + UC_X86_INS_VFMADDSUB231PD = 816 + UC_X86_INS_VFMADDSUBPS = 817 + UC_X86_INS_VFMADDSUB213PS = 818 + UC_X86_INS_VFMADDSUB231PS = 819 + UC_X86_INS_VFMSUB132PD = 820 + UC_X86_INS_VFMSUB132PS = 821 + UC_X86_INS_VFMSUBADD132PD = 822 + UC_X86_INS_VFMSUBADD132PS = 823 + UC_X86_INS_VFMSUBADDPD = 824 + UC_X86_INS_VFMSUBADD213PD = 825 + UC_X86_INS_VFMSUBADD231PD = 826 + UC_X86_INS_VFMSUBADDPS = 827 + UC_X86_INS_VFMSUBADD213PS = 828 + UC_X86_INS_VFMSUBADD231PS = 829 + UC_X86_INS_VFMSUBPD = 830 + UC_X86_INS_VFMSUB213PD = 831 + UC_X86_INS_VFMSUB231PD = 832 + UC_X86_INS_VFMSUBPS = 833 + UC_X86_INS_VFMSUB213PS = 834 + UC_X86_INS_VFMSUB231PS = 835 + UC_X86_INS_VFMSUBSD = 836 + UC_X86_INS_VFMSUB213SD = 837 + UC_X86_INS_VFMSUB132SD = 838 + UC_X86_INS_VFMSUB231SD = 839 + UC_X86_INS_VFMSUBSS = 840 + UC_X86_INS_VFMSUB213SS = 841 + UC_X86_INS_VFMSUB132SS = 842 + UC_X86_INS_VFMSUB231SS = 843 + UC_X86_INS_VFNMADD132PD = 844 + UC_X86_INS_VFNMADD132PS = 845 + UC_X86_INS_VFNMADDPD = 846 + UC_X86_INS_VFNMADD213PD = 847 + UC_X86_INS_VFNMADD231PD = 848 + UC_X86_INS_VFNMADDPS = 849 + UC_X86_INS_VFNMADD213PS = 850 + UC_X86_INS_VFNMADD231PS = 851 + UC_X86_INS_VFNMADDSD = 852 + UC_X86_INS_VFNMADD213SD = 853 + UC_X86_INS_VFNMADD132SD = 854 + UC_X86_INS_VFNMADD231SD = 855 + UC_X86_INS_VFNMADDSS = 856 + UC_X86_INS_VFNMADD213SS = 857 + UC_X86_INS_VFNMADD132SS = 858 + UC_X86_INS_VFNMADD231SS = 859 + UC_X86_INS_VFNMSUB132PD = 860 + UC_X86_INS_VFNMSUB132PS = 861 + UC_X86_INS_VFNMSUBPD = 862 + UC_X86_INS_VFNMSUB213PD = 863 + UC_X86_INS_VFNMSUB231PD = 864 + UC_X86_INS_VFNMSUBPS = 865 + UC_X86_INS_VFNMSUB213PS = 866 + UC_X86_INS_VFNMSUB231PS = 867 + UC_X86_INS_VFNMSUBSD = 868 + UC_X86_INS_VFNMSUB213SD = 869 + UC_X86_INS_VFNMSUB132SD = 870 + UC_X86_INS_VFNMSUB231SD = 871 + UC_X86_INS_VFNMSUBSS = 872 + UC_X86_INS_VFNMSUB213SS = 873 + UC_X86_INS_VFNMSUB132SS = 874 + UC_X86_INS_VFNMSUB231SS = 875 + UC_X86_INS_VFRCZPD = 876 + UC_X86_INS_VFRCZPS = 877 + UC_X86_INS_VFRCZSD = 878 + UC_X86_INS_VFRCZSS = 879 + UC_X86_INS_VORPD = 880 + UC_X86_INS_VORPS = 881 + UC_X86_INS_VXORPD = 882 + UC_X86_INS_VXORPS = 883 + UC_X86_INS_VGATHERDPD = 884 + UC_X86_INS_VGATHERDPS = 885 + UC_X86_INS_VGATHERPF0DPD = 886 + UC_X86_INS_VGATHERPF0DPS = 887 + UC_X86_INS_VGATHERPF0QPD = 888 + UC_X86_INS_VGATHERPF0QPS = 889 + UC_X86_INS_VGATHERPF1DPD = 890 + UC_X86_INS_VGATHERPF1DPS = 891 + UC_X86_INS_VGATHERPF1QPD = 892 + UC_X86_INS_VGATHERPF1QPS = 893 + UC_X86_INS_VGATHERQPD = 894 + UC_X86_INS_VGATHERQPS = 895 + UC_X86_INS_VHADDPD = 896 + UC_X86_INS_VHADDPS = 897 + UC_X86_INS_VHSUBPD = 898 + UC_X86_INS_VHSUBPS = 899 + UC_X86_INS_VINSERTF128 = 900 + UC_X86_INS_VINSERTF32X4 = 901 + UC_X86_INS_VINSERTF32X8 = 902 + UC_X86_INS_VINSERTF64X2 = 903 + UC_X86_INS_VINSERTF64X4 = 904 + UC_X86_INS_VINSERTI128 = 905 + UC_X86_INS_VINSERTI32X4 = 906 + UC_X86_INS_VINSERTI32X8 = 907 + UC_X86_INS_VINSERTI64X2 = 908 + UC_X86_INS_VINSERTI64X4 = 909 + UC_X86_INS_VINSERTPS = 910 + UC_X86_INS_VLDDQU = 911 + UC_X86_INS_VLDMXCSR = 912 + UC_X86_INS_VMASKMOVDQU = 913 + UC_X86_INS_VMASKMOVPD = 914 + UC_X86_INS_VMASKMOVPS = 915 + UC_X86_INS_VMAXPD = 916 + UC_X86_INS_VMAXPS = 917 + UC_X86_INS_VMAXSD = 918 + UC_X86_INS_VMAXSS = 919 + UC_X86_INS_VMCALL = 920 + UC_X86_INS_VMCLEAR = 921 + UC_X86_INS_VMFUNC = 922 + UC_X86_INS_VMINPD = 923 + UC_X86_INS_VMINPS = 924 + UC_X86_INS_VMINSD = 925 + UC_X86_INS_VMINSS = 926 + UC_X86_INS_VMLAUNCH = 927 + UC_X86_INS_VMLOAD = 928 + UC_X86_INS_VMMCALL = 929 + UC_X86_INS_VMOVQ = 930 + UC_X86_INS_VMOVDDUP = 931 + UC_X86_INS_VMOVD = 932 + UC_X86_INS_VMOVDQA32 = 933 + UC_X86_INS_VMOVDQA64 = 934 + UC_X86_INS_VMOVDQA = 935 + UC_X86_INS_VMOVDQU16 = 936 + UC_X86_INS_VMOVDQU32 = 937 + UC_X86_INS_VMOVDQU64 = 938 + UC_X86_INS_VMOVDQU8 = 939 + UC_X86_INS_VMOVDQU = 940 + UC_X86_INS_VMOVHLPS = 941 + UC_X86_INS_VMOVHPD = 942 + UC_X86_INS_VMOVHPS = 943 + UC_X86_INS_VMOVLHPS = 944 + UC_X86_INS_VMOVLPD = 945 + UC_X86_INS_VMOVLPS = 946 + UC_X86_INS_VMOVMSKPD = 947 + UC_X86_INS_VMOVMSKPS = 948 + UC_X86_INS_VMOVNTDQA = 949 + UC_X86_INS_VMOVNTDQ = 950 + UC_X86_INS_VMOVNTPD = 951 + UC_X86_INS_VMOVNTPS = 952 + UC_X86_INS_VMOVSD = 953 + UC_X86_INS_VMOVSHDUP = 954 + UC_X86_INS_VMOVSLDUP = 955 + UC_X86_INS_VMOVSS = 956 + UC_X86_INS_VMOVUPD = 957 + UC_X86_INS_VMOVUPS = 958 + UC_X86_INS_VMPSADBW = 959 + UC_X86_INS_VMPTRLD = 960 + UC_X86_INS_VMPTRST = 961 + UC_X86_INS_VMREAD = 962 + UC_X86_INS_VMRESUME = 963 + UC_X86_INS_VMRUN = 964 + UC_X86_INS_VMSAVE = 965 + UC_X86_INS_VMULPD = 966 + UC_X86_INS_VMULPS = 967 + UC_X86_INS_VMULSD = 968 + UC_X86_INS_VMULSS = 969 + UC_X86_INS_VMWRITE = 970 + UC_X86_INS_VMXOFF = 971 + UC_X86_INS_VMXON = 972 + UC_X86_INS_VPABSB = 973 + UC_X86_INS_VPABSD = 974 + UC_X86_INS_VPABSQ = 975 + UC_X86_INS_VPABSW = 976 + UC_X86_INS_VPACKSSDW = 977 + UC_X86_INS_VPACKSSWB = 978 + UC_X86_INS_VPACKUSDW = 979 + UC_X86_INS_VPACKUSWB = 980 + UC_X86_INS_VPADDB = 981 + UC_X86_INS_VPADDD = 982 + UC_X86_INS_VPADDQ = 983 + UC_X86_INS_VPADDSB = 984 + UC_X86_INS_VPADDSW = 985 + UC_X86_INS_VPADDUSB = 986 + UC_X86_INS_VPADDUSW = 987 + UC_X86_INS_VPADDW = 988 + UC_X86_INS_VPALIGNR = 989 + UC_X86_INS_VPANDD = 990 + UC_X86_INS_VPANDND = 991 + UC_X86_INS_VPANDNQ = 992 + UC_X86_INS_VPANDN = 993 + UC_X86_INS_VPANDQ = 994 + UC_X86_INS_VPAND = 995 + UC_X86_INS_VPAVGB = 996 + UC_X86_INS_VPAVGW = 997 + UC_X86_INS_VPBLENDD = 998 + UC_X86_INS_VPBLENDMB = 999 + UC_X86_INS_VPBLENDMD = 1000 + UC_X86_INS_VPBLENDMQ = 1001 + UC_X86_INS_VPBLENDMW = 1002 + UC_X86_INS_VPBLENDVB = 1003 + UC_X86_INS_VPBLENDW = 1004 + UC_X86_INS_VPBROADCASTB = 1005 + UC_X86_INS_VPBROADCASTD = 1006 + UC_X86_INS_VPBROADCASTMB2Q = 1007 + UC_X86_INS_VPBROADCASTMW2D = 1008 + UC_X86_INS_VPBROADCASTQ = 1009 + UC_X86_INS_VPBROADCASTW = 1010 + UC_X86_INS_VPCLMULQDQ = 1011 + UC_X86_INS_VPCMOV = 1012 + UC_X86_INS_VPCMPB = 1013 + UC_X86_INS_VPCMPD = 1014 + UC_X86_INS_VPCMPEQB = 1015 + UC_X86_INS_VPCMPEQD = 1016 + UC_X86_INS_VPCMPEQQ = 1017 + UC_X86_INS_VPCMPEQW = 1018 + UC_X86_INS_VPCMPESTRI = 1019 + UC_X86_INS_VPCMPESTRM = 1020 + UC_X86_INS_VPCMPGTB = 1021 + UC_X86_INS_VPCMPGTD = 1022 + UC_X86_INS_VPCMPGTQ = 1023 + UC_X86_INS_VPCMPGTW = 1024 + UC_X86_INS_VPCMPISTRI = 1025 + UC_X86_INS_VPCMPISTRM = 1026 + UC_X86_INS_VPCMPQ = 1027 + UC_X86_INS_VPCMPUB = 1028 + UC_X86_INS_VPCMPUD = 1029 + UC_X86_INS_VPCMPUQ = 1030 + UC_X86_INS_VPCMPUW = 1031 + UC_X86_INS_VPCMPW = 1032 + UC_X86_INS_VPCOMB = 1033 + UC_X86_INS_VPCOMD = 1034 + UC_X86_INS_VPCOMPRESSD = 1035 + UC_X86_INS_VPCOMPRESSQ = 1036 + UC_X86_INS_VPCOMQ = 1037 + UC_X86_INS_VPCOMUB = 1038 + UC_X86_INS_VPCOMUD = 1039 + UC_X86_INS_VPCOMUQ = 1040 + UC_X86_INS_VPCOMUW = 1041 + UC_X86_INS_VPCOMW = 1042 + UC_X86_INS_VPCONFLICTD = 1043 + UC_X86_INS_VPCONFLICTQ = 1044 + UC_X86_INS_VPERM2F128 = 1045 + UC_X86_INS_VPERM2I128 = 1046 + UC_X86_INS_VPERMD = 1047 + UC_X86_INS_VPERMI2D = 1048 + UC_X86_INS_VPERMI2PD = 1049 + UC_X86_INS_VPERMI2PS = 1050 + UC_X86_INS_VPERMI2Q = 1051 + UC_X86_INS_VPERMIL2PD = 1052 + UC_X86_INS_VPERMIL2PS = 1053 + UC_X86_INS_VPERMILPD = 1054 + UC_X86_INS_VPERMILPS = 1055 + UC_X86_INS_VPERMPD = 1056 + UC_X86_INS_VPERMPS = 1057 + UC_X86_INS_VPERMQ = 1058 + UC_X86_INS_VPERMT2D = 1059 + UC_X86_INS_VPERMT2PD = 1060 + UC_X86_INS_VPERMT2PS = 1061 + UC_X86_INS_VPERMT2Q = 1062 + UC_X86_INS_VPEXPANDD = 1063 + UC_X86_INS_VPEXPANDQ = 1064 + UC_X86_INS_VPEXTRB = 1065 + UC_X86_INS_VPEXTRD = 1066 + UC_X86_INS_VPEXTRQ = 1067 + UC_X86_INS_VPEXTRW = 1068 + UC_X86_INS_VPGATHERDD = 1069 + UC_X86_INS_VPGATHERDQ = 1070 + UC_X86_INS_VPGATHERQD = 1071 + UC_X86_INS_VPGATHERQQ = 1072 + UC_X86_INS_VPHADDBD = 1073 + UC_X86_INS_VPHADDBQ = 1074 + UC_X86_INS_VPHADDBW = 1075 + UC_X86_INS_VPHADDDQ = 1076 + UC_X86_INS_VPHADDD = 1077 + UC_X86_INS_VPHADDSW = 1078 + UC_X86_INS_VPHADDUBD = 1079 + UC_X86_INS_VPHADDUBQ = 1080 + UC_X86_INS_VPHADDUBW = 1081 + UC_X86_INS_VPHADDUDQ = 1082 + UC_X86_INS_VPHADDUWD = 1083 + UC_X86_INS_VPHADDUWQ = 1084 + UC_X86_INS_VPHADDWD = 1085 + UC_X86_INS_VPHADDWQ = 1086 + UC_X86_INS_VPHADDW = 1087 + UC_X86_INS_VPHMINPOSUW = 1088 + UC_X86_INS_VPHSUBBW = 1089 + UC_X86_INS_VPHSUBDQ = 1090 + UC_X86_INS_VPHSUBD = 1091 + UC_X86_INS_VPHSUBSW = 1092 + UC_X86_INS_VPHSUBWD = 1093 + UC_X86_INS_VPHSUBW = 1094 + UC_X86_INS_VPINSRB = 1095 + UC_X86_INS_VPINSRD = 1096 + UC_X86_INS_VPINSRQ = 1097 + UC_X86_INS_VPINSRW = 1098 + UC_X86_INS_VPLZCNTD = 1099 + UC_X86_INS_VPLZCNTQ = 1100 + UC_X86_INS_VPMACSDD = 1101 + UC_X86_INS_VPMACSDQH = 1102 + UC_X86_INS_VPMACSDQL = 1103 + UC_X86_INS_VPMACSSDD = 1104 + UC_X86_INS_VPMACSSDQH = 1105 + UC_X86_INS_VPMACSSDQL = 1106 + UC_X86_INS_VPMACSSWD = 1107 + UC_X86_INS_VPMACSSWW = 1108 + UC_X86_INS_VPMACSWD = 1109 + UC_X86_INS_VPMACSWW = 1110 + UC_X86_INS_VPMADCSSWD = 1111 + UC_X86_INS_VPMADCSWD = 1112 + UC_X86_INS_VPMADDUBSW = 1113 + UC_X86_INS_VPMADDWD = 1114 + UC_X86_INS_VPMASKMOVD = 1115 + UC_X86_INS_VPMASKMOVQ = 1116 + UC_X86_INS_VPMAXSB = 1117 + UC_X86_INS_VPMAXSD = 1118 + UC_X86_INS_VPMAXSQ = 1119 + UC_X86_INS_VPMAXSW = 1120 + UC_X86_INS_VPMAXUB = 1121 + UC_X86_INS_VPMAXUD = 1122 + UC_X86_INS_VPMAXUQ = 1123 + UC_X86_INS_VPMAXUW = 1124 + UC_X86_INS_VPMINSB = 1125 + UC_X86_INS_VPMINSD = 1126 + UC_X86_INS_VPMINSQ = 1127 + UC_X86_INS_VPMINSW = 1128 + UC_X86_INS_VPMINUB = 1129 + UC_X86_INS_VPMINUD = 1130 + UC_X86_INS_VPMINUQ = 1131 + UC_X86_INS_VPMINUW = 1132 + UC_X86_INS_VPMOVDB = 1133 + UC_X86_INS_VPMOVDW = 1134 + UC_X86_INS_VPMOVM2B = 1135 + UC_X86_INS_VPMOVM2D = 1136 + UC_X86_INS_VPMOVM2Q = 1137 + UC_X86_INS_VPMOVM2W = 1138 + UC_X86_INS_VPMOVMSKB = 1139 + UC_X86_INS_VPMOVQB = 1140 + UC_X86_INS_VPMOVQD = 1141 + UC_X86_INS_VPMOVQW = 1142 + UC_X86_INS_VPMOVSDB = 1143 + UC_X86_INS_VPMOVSDW = 1144 + UC_X86_INS_VPMOVSQB = 1145 + UC_X86_INS_VPMOVSQD = 1146 + UC_X86_INS_VPMOVSQW = 1147 + UC_X86_INS_VPMOVSXBD = 1148 + UC_X86_INS_VPMOVSXBQ = 1149 + UC_X86_INS_VPMOVSXBW = 1150 + UC_X86_INS_VPMOVSXDQ = 1151 + UC_X86_INS_VPMOVSXWD = 1152 + UC_X86_INS_VPMOVSXWQ = 1153 + UC_X86_INS_VPMOVUSDB = 1154 + UC_X86_INS_VPMOVUSDW = 1155 + UC_X86_INS_VPMOVUSQB = 1156 + UC_X86_INS_VPMOVUSQD = 1157 + UC_X86_INS_VPMOVUSQW = 1158 + UC_X86_INS_VPMOVZXBD = 1159 + UC_X86_INS_VPMOVZXBQ = 1160 + UC_X86_INS_VPMOVZXBW = 1161 + UC_X86_INS_VPMOVZXDQ = 1162 + UC_X86_INS_VPMOVZXWD = 1163 + UC_X86_INS_VPMOVZXWQ = 1164 + UC_X86_INS_VPMULDQ = 1165 + UC_X86_INS_VPMULHRSW = 1166 + UC_X86_INS_VPMULHUW = 1167 + UC_X86_INS_VPMULHW = 1168 + UC_X86_INS_VPMULLD = 1169 + UC_X86_INS_VPMULLQ = 1170 + UC_X86_INS_VPMULLW = 1171 + UC_X86_INS_VPMULUDQ = 1172 + UC_X86_INS_VPORD = 1173 + UC_X86_INS_VPORQ = 1174 + UC_X86_INS_VPOR = 1175 + UC_X86_INS_VPPERM = 1176 + UC_X86_INS_VPROTB = 1177 + UC_X86_INS_VPROTD = 1178 + UC_X86_INS_VPROTQ = 1179 + UC_X86_INS_VPROTW = 1180 + UC_X86_INS_VPSADBW = 1181 + UC_X86_INS_VPSCATTERDD = 1182 + UC_X86_INS_VPSCATTERDQ = 1183 + UC_X86_INS_VPSCATTERQD = 1184 + UC_X86_INS_VPSCATTERQQ = 1185 + UC_X86_INS_VPSHAB = 1186 + UC_X86_INS_VPSHAD = 1187 + UC_X86_INS_VPSHAQ = 1188 + UC_X86_INS_VPSHAW = 1189 + UC_X86_INS_VPSHLB = 1190 + UC_X86_INS_VPSHLD = 1191 + UC_X86_INS_VPSHLQ = 1192 + UC_X86_INS_VPSHLW = 1193 + UC_X86_INS_VPSHUFB = 1194 + UC_X86_INS_VPSHUFD = 1195 + UC_X86_INS_VPSHUFHW = 1196 + UC_X86_INS_VPSHUFLW = 1197 + UC_X86_INS_VPSIGNB = 1198 + UC_X86_INS_VPSIGND = 1199 + UC_X86_INS_VPSIGNW = 1200 + UC_X86_INS_VPSLLDQ = 1201 + UC_X86_INS_VPSLLD = 1202 + UC_X86_INS_VPSLLQ = 1203 + UC_X86_INS_VPSLLVD = 1204 + UC_X86_INS_VPSLLVQ = 1205 + UC_X86_INS_VPSLLW = 1206 + UC_X86_INS_VPSRAD = 1207 + UC_X86_INS_VPSRAQ = 1208 + UC_X86_INS_VPSRAVD = 1209 + UC_X86_INS_VPSRAVQ = 1210 + UC_X86_INS_VPSRAW = 1211 + UC_X86_INS_VPSRLDQ = 1212 + UC_X86_INS_VPSRLD = 1213 + UC_X86_INS_VPSRLQ = 1214 + UC_X86_INS_VPSRLVD = 1215 + UC_X86_INS_VPSRLVQ = 1216 + UC_X86_INS_VPSRLW = 1217 + UC_X86_INS_VPSUBB = 1218 + UC_X86_INS_VPSUBD = 1219 + UC_X86_INS_VPSUBQ = 1220 + UC_X86_INS_VPSUBSB = 1221 + UC_X86_INS_VPSUBSW = 1222 + UC_X86_INS_VPSUBUSB = 1223 + UC_X86_INS_VPSUBUSW = 1224 + UC_X86_INS_VPSUBW = 1225 + UC_X86_INS_VPTESTMD = 1226 + UC_X86_INS_VPTESTMQ = 1227 + UC_X86_INS_VPTESTNMD = 1228 + UC_X86_INS_VPTESTNMQ = 1229 + UC_X86_INS_VPTEST = 1230 + UC_X86_INS_VPUNPCKHBW = 1231 + UC_X86_INS_VPUNPCKHDQ = 1232 + UC_X86_INS_VPUNPCKHQDQ = 1233 + UC_X86_INS_VPUNPCKHWD = 1234 + UC_X86_INS_VPUNPCKLBW = 1235 + UC_X86_INS_VPUNPCKLDQ = 1236 + UC_X86_INS_VPUNPCKLQDQ = 1237 + UC_X86_INS_VPUNPCKLWD = 1238 + UC_X86_INS_VPXORD = 1239 + UC_X86_INS_VPXORQ = 1240 + UC_X86_INS_VPXOR = 1241 + UC_X86_INS_VRCP14PD = 1242 + UC_X86_INS_VRCP14PS = 1243 + UC_X86_INS_VRCP14SD = 1244 + UC_X86_INS_VRCP14SS = 1245 + UC_X86_INS_VRCP28PD = 1246 + UC_X86_INS_VRCP28PS = 1247 + UC_X86_INS_VRCP28SD = 1248 + UC_X86_INS_VRCP28SS = 1249 + UC_X86_INS_VRCPPS = 1250 + UC_X86_INS_VRCPSS = 1251 + UC_X86_INS_VRNDSCALEPD = 1252 + UC_X86_INS_VRNDSCALEPS = 1253 + UC_X86_INS_VRNDSCALESD = 1254 + UC_X86_INS_VRNDSCALESS = 1255 + UC_X86_INS_VROUNDPD = 1256 + UC_X86_INS_VROUNDPS = 1257 + UC_X86_INS_VROUNDSD = 1258 + UC_X86_INS_VROUNDSS = 1259 + UC_X86_INS_VRSQRT14PD = 1260 + UC_X86_INS_VRSQRT14PS = 1261 + UC_X86_INS_VRSQRT14SD = 1262 + UC_X86_INS_VRSQRT14SS = 1263 + UC_X86_INS_VRSQRT28PD = 1264 + UC_X86_INS_VRSQRT28PS = 1265 + UC_X86_INS_VRSQRT28SD = 1266 + UC_X86_INS_VRSQRT28SS = 1267 + UC_X86_INS_VRSQRTPS = 1268 + UC_X86_INS_VRSQRTSS = 1269 + UC_X86_INS_VSCATTERDPD = 1270 + UC_X86_INS_VSCATTERDPS = 1271 + UC_X86_INS_VSCATTERPF0DPD = 1272 + UC_X86_INS_VSCATTERPF0DPS = 1273 + UC_X86_INS_VSCATTERPF0QPD = 1274 + UC_X86_INS_VSCATTERPF0QPS = 1275 + UC_X86_INS_VSCATTERPF1DPD = 1276 + UC_X86_INS_VSCATTERPF1DPS = 1277 + UC_X86_INS_VSCATTERPF1QPD = 1278 + UC_X86_INS_VSCATTERPF1QPS = 1279 + UC_X86_INS_VSCATTERQPD = 1280 + UC_X86_INS_VSCATTERQPS = 1281 + UC_X86_INS_VSHUFPD = 1282 + UC_X86_INS_VSHUFPS = 1283 + UC_X86_INS_VSQRTPD = 1284 + UC_X86_INS_VSQRTPS = 1285 + UC_X86_INS_VSQRTSD = 1286 + UC_X86_INS_VSQRTSS = 1287 + UC_X86_INS_VSTMXCSR = 1288 + UC_X86_INS_VSUBPD = 1289 + UC_X86_INS_VSUBPS = 1290 + UC_X86_INS_VSUBSD = 1291 + UC_X86_INS_VSUBSS = 1292 + UC_X86_INS_VTESTPD = 1293 + UC_X86_INS_VTESTPS = 1294 + UC_X86_INS_VUNPCKHPD = 1295 + UC_X86_INS_VUNPCKHPS = 1296 + UC_X86_INS_VUNPCKLPD = 1297 + UC_X86_INS_VUNPCKLPS = 1298 + UC_X86_INS_VZEROALL = 1299 + UC_X86_INS_VZEROUPPER = 1300 + UC_X86_INS_WAIT = 1301 + UC_X86_INS_WBINVD = 1302 + UC_X86_INS_WRFSBASE = 1303 + UC_X86_INS_WRGSBASE = 1304 + UC_X86_INS_WRMSR = 1305 + UC_X86_INS_XABORT = 1306 + UC_X86_INS_XACQUIRE = 1307 + UC_X86_INS_XBEGIN = 1308 + UC_X86_INS_XCHG = 1309 + UC_X86_INS_XCRYPTCBC = 1310 + UC_X86_INS_XCRYPTCFB = 1311 + UC_X86_INS_XCRYPTCTR = 1312 + UC_X86_INS_XCRYPTECB = 1313 + UC_X86_INS_XCRYPTOFB = 1314 + UC_X86_INS_XEND = 1315 + UC_X86_INS_XGETBV = 1316 + UC_X86_INS_XLATB = 1317 + UC_X86_INS_XRELEASE = 1318 + UC_X86_INS_XRSTOR = 1319 + UC_X86_INS_XRSTOR64 = 1320 + UC_X86_INS_XRSTORS = 1321 + UC_X86_INS_XRSTORS64 = 1322 + UC_X86_INS_XSAVE = 1323 + UC_X86_INS_XSAVE64 = 1324 + UC_X86_INS_XSAVEC = 1325 + UC_X86_INS_XSAVEC64 = 1326 + UC_X86_INS_XSAVEOPT = 1327 + UC_X86_INS_XSAVEOPT64 = 1328 + UC_X86_INS_XSAVES = 1329 + UC_X86_INS_XSAVES64 = 1330 + UC_X86_INS_XSETBV = 1331 + UC_X86_INS_XSHA1 = 1332 + UC_X86_INS_XSHA256 = 1333 + UC_X86_INS_XSTORE = 1334 + UC_X86_INS_XTEST = 1335 + UC_X86_INS_FDISI8087_NOP = 1336 + UC_X86_INS_FENI8087_NOP = 1337 + UC_X86_INS_ENDING = 1338 +end \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/pkg/.gitignore b/bindings/ruby/unicorn_gem/pkg/.gitignore new file mode 100644 index 00000000..e394af59 --- /dev/null +++ b/bindings/ruby/unicorn_gem/pkg/.gitignore @@ -0,0 +1,10 @@ +/.bundle/ +/.yardoc +/Gemfile.lock +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ +.gem diff --git a/bindings/ruby/unicorn_gem/pkg/unicorn-0.9.0.gem b/bindings/ruby/unicorn_gem/pkg/unicorn-0.9.0.gem new file mode 100644 index 0000000000000000000000000000000000000000..57b7a6b32541290b63026617f81080101054d520 GIT binary patch literal 20992 zcmeFXWl&r}*De}@ySoKcXtUv2f4$0tL}I1SGVf? zI(5&Fv#a{qPd~lZ?$x`y*Yr${otcY~sga8jvxV2E|5X<&_~PW`{Pb}LU;q8i#>T<* ziH)6`hm)P1lZ%_}6Du1BCnwLRFRcHo0{S1H>+0-cK3$#Dw-T?On3;3vDVxd%TA#B=vmkL& zEFLdhg#W}+N<&^x?x%AbM<6p+3cb~A^_CWNAp7BpZK5el@>8~jHpvv{8tDsS`E)^* z3Sy*Vqx0z11HOQ

1EpNtu+)&4^?^3To%&1w_eyq09G5Qn_QEr_StwJXF#-Ti(mm z_RQk?73|pX94ZaZQ1@j5fhu!iep_@wF&j%E5=oXg4?)~3ny3rI;Hhd(*9rgMF8g}< zxJs*N!}h;3WwwqplMfzCdz=2i>M6v&OjzzgnPd}avf$Gv*j=HbcHLZcu=;v_C+la5 zVisLV^7mTX;m*6%jCU)rl>f=>;UZ6GRJ9zDqD~J?h`_&PH2dlYmeOS%G z+EGuX5>?^`-UI$?bk>9v;JZKkElzd|RNRBYb&JSR&%L?hFRK`FL@usxm_c_>E?!+6 z6{$h{B&q6n0m9x1x4`anE@7;s!=NT6EHBbhV^tqaZzEdp5NpsfTaYC!r@c_WNo_d} zQULGvn1wHPmV3vVG4C7Rgj`q}FVRB@QvEdu3S+$&ex;AACEHI9(D4eC@+un?a~zsg z{$Uz~aZfpTe>)N^(&yNsgSLNA4zCMnsE2*$+%7D(ycCg`>G!OF{oi%T|DU-2hd1z_ z+z-xx|NrHGPF8jv&i|hOIl$8Y$^ZYuJpHet|CRsGeL>EIGD#)=LT}i-irGIir&oXZ zJ)GX}ihiOr+S%}sBP2wM3SrEp`wE$qdo%g$-(5CdR&_oeB=wYkQxzJ4AHB8oO)n#7 z(m=_UOMxKh>?Gnnt6VQj{?}Oha$) zKV$8G1Mi3G{%|C)k<#6@VPEaP+k$$t-ttb~y>ZWis@ZOL2Hf<0xSS9nCOXzy-dxw) z*v#I@?p|wpYrIoN<_xaubO^TRW)~P;{yHPmw{a*25Vz?3xl}t5g-wzRk?x7cV6Y>sfYK{N8i_@ z;NYkJGt%$X)%MKQ_FbJeovj;8Mn%i&PnO>)O+Ao@1-9d+M)kp0Y zw~MIFsFl&TS&R1Gp04iQ?Ov}A-FA8#&67Wv!LNk4qrJ1k>oypI#Gbi%IURIyxuJJ< zkNo1uuHU58#Iv^X>Yd+0sz3*lHiRbGd2HqO&TjcD>wC zSa)Gbymk6Kb#=F6@P`_drq@(upZ9NV?V*kA$JCYL+?$uH?}k^WozS}7mY}YPz_d)$ zV({RJX{)8{5R1;)q|YWki@xxZ%w~7z!udUjY0>%a^7SsYN`uGP-Ou?wnET9d9_X%o zcau}t>rmsdGJ7dZ!Z`F=W=*VoSgB;Qn!y6IaZtnYL-FVBNztkQg7r6@xx9;Bzwn*~ zANTUg&h<^8f!>ytnt}Dh)(N$qLDRU2jzL)T#ll0I*ij{-uNCRe!R^^v){kCR-=c@L z+r@>f#fgj8`b7hG&F7@eE%|Cvk7^McWP9c=uSNM(;r*AxcAJZ%Q+?732Hq~OLI#np zuFef18{&=4jjVo|9F1~fx`j6jCe-=*#kx~V=eL);USO3ya}_Cbb0v)c@u)$k?{4C| z9jX1D#O1|1e1bni9n4LU@bjPE-ZBo|`;80MwoacG?yJF-iG@4oVLg}XsjEw<)vb#L z5OJCR)|S4Wb$RvW)Hyr~u<6ZjdbWGxi~~e3?9-QNyV>ggpqwil4(Tc2(yQ=l-8plm z6@UUxrOyF0J^M*;^xA#RJ=VFsn^dpG z@shy9<;MN!%F5`K#_@5|2ZSOtN~Qvv@;u*e`Nom)2uG^4{2Zo_lw6TmJ{q{kxA~uEB;K>cyPg8mRlSq4t^c zS*VjMf$nu)Gf&Ft29`y+n9v;vU6`$Wo+>7A}7vii^O-R{A%j5 z=^^|$o#y>vXO}5^MhMz{4Fp>mkMx?&*X*}Sq`zUQR}Z@H^SYfnjK9jUQJg9Dr&09n zT$uD#TJv-Mp-)WG((To}U>zim`yA^<+J%#U2A#{hvMC^wm%qg?F*8{@<)eLyeUvFs zxi#59=N@iJ^!<)9DpwGM5i`Anvs(3TlU4B!%|x~2Er^$^h|2W-&uZ)yWnF}^xEhF( zDGNK5@As0aWxp732Qv!UD^JQ0ru5khDk zsnW91C4yyimjxp^lGujcy(07q!P2s1yX|TIt6bqMInU&uFM*83LnX-lN>OT+(p}GP z<++A&CLI47bbAI{*s~f7y4Apaa4*D3v$)!{f`7BOc)cs%N^<`mZqOmrfb9S5PWp26 z{oSVfhYR81YjS<^rtuq#_e!sFT|dy2&cbhXwc2IuP65-U)D_LlAd4Vq{BEJW9K?Ee z`24aaAh&?71^a3J&m!4#ZQ)p(rE51Z4)6dPfphI9CG=l`^KG7+8Y5L1U^bO8^7Jh~=?bdE*)&#oNGU(tK}N*o68gP^Cf}xT+Y*G%XW@H7qRDA4wKE%4 z;8DFMo;!zd{Ic`hh3`y?i?Jy+^{(n@R9T;Ug#3K-<=O?3uIu4O`n|90?M;Ei_2op0 z)W7Zc$DQyKvG8Quk7nGh940@H?z^8S+BS~nUjcJ2lR zs;?fBN#v#~MV`}@iA!ztV~zGfMON5%}w>Ul+jl%#(8pdsWfBHQH>gfI~ z_50#JUZ^xxuuePYe)Yh!C&PjxTp8!6cdycY{@1CQD+fp6WHYN%VqD}d*3;}wp&Fma z`0AVQ1I}~$lF0gxt2gAhmxm+ZcdEr9uKA|MFW_eVt`kk@s_0^zdy?!94U^cS zv4;w|InH&k6ebA3aoIsaw%l?c(Zz8j%ZWZk~vi#>Y$c=J;BTUy-$P58O{`}w=h1gX|UFQpfCwREnN zU_9VqlIV&Qy4?q#HRN^Yhlz-++qql(T#b$;ItAUfw}YD7*TR2nWg0?XTlrd2I6k)} zT6Y%tU!>t`wCQ%-=eVVG?IZaK9`F36K`qC89E%1D#v!S7c(%0ic6SMPcpwK`tU|7B zOzdC=XVl2%W{mo5Z5Uj&S=d!S1fR@a+;&F-Z=(_Q*j=!Dj$}o4>v%Ws6W+WHie>am z#`UP(Rj0F*Nu77jA(qDymu~JZE?oEc^*4?ss+mO$M&i3SuI0E4{xKXM`OQW@rw9|B zG3+p(FHCI2zIAuv-n~}h&vTDHq2AgKL`&Ub#QSQr*%)P)I6mdQMAA^{My!Q{WDFuR zANSU!Njor3_NpWmue|U7FgQQ-6KALEU%_Wy z7Fgd$iFWZ1a>M-fz2rCfa8NKPkO&ctA7#B!Eq?{3ZC6DbIXTI%B#;Hp4nBpmCA|o( z%h|e`P^RJ1{RmelqwnsB%lXn!fAb$B-|q6hAqs|AD^wCzG=& zv5<21z1`-tlU6<3-=z*7;6kJCwbtGE@G&gvA}W6i_PSQPw^k{l`e8xlHR&}}f0!(9ZVhdgwZ?@_sK*AYEn+ji{EO!*_0o0~=-=rUJnVV% zm;t_f4e6Zxg(tq=>t(UNeZAaUTOC2Nt8P^8=h-lxv@hCHJ!?zW@4f@RuV4(!IL!L? zuD&Y7uxi&D3`e9j?vAxp7QP+ZZeIPHOxshn;Jr0K@f+P6&Zp@)4@{Yp)h*kKmbQ4HsJiRipgMuWEH!5rg=-y_^=!cxYRTg~F<-uki zUsL8P_%yc~Ic$jF)1wyv?9Fz*YUu8u(5H|QEWM?3nY!3{ep745y!d4Bc0fF?!BP1* z(Rq4=x;hsaEK;5LT3GS!3qsX?UyJ(-h`j4wIlAixF1`Edzk@tquS^!--_FhKru;7p zDvwCN``y0mX_N@Q7prvw--Garru=8rhmS;lkOMQC|7DH8c)cl7iCXR)5bqF#bD5^Xllosr}FU`5WiCh|L{!<&Ejg=>tskVmFt`!4@it!vlooTyHP% zd(IQB!Z?L|xBQ*W)AqLi@f$)wi#Q}Es<{xZ3AgHR)xnvT%9)7#J}bgCX{$aoB8&GsCN;5! zJqQm&LwaabR$s!zjIkmnCbhPPon2$7Z*)WpACZCL|1HY5s2UqltM|1gj zcckyfYvG$~Er^mFFujLJ;hSqL))O5dy@v?lo2xCd6CG~7hH&AVt1NUA9rnD2Fe7V_ z3;0uq@Xx*)5lgz#j|cx!3iU->_|1w|z>ke1u3p+F8F8w<45yldKtWcfW<(|FN?j51 zYjU59Q^UMZKH?Oh1+SU|&p=kj@&B}iq@pck)L<0wV`_-2AAJ~Q>v$r-I#Vd`XxZ=m zc9fk|6y$mvX$>tMBIe_{p7)?Qy3Zl7*kA8Z+l$WDakti0b=Xsir9m(vlyoJFv?q=;$jr8of~)%L>L&a1h1d zAlk6NLHt)60yxsfeQe$ikF`Ff2%80*Fmc0j?q-*;aAySz4^A-Q57FU=B%3`8dr&@wW408YnVhT(1ma0P@`=PDMmYz zhs(u>YQu=KfJv+h+0PLB#gOl5j&>#=0hZe_$}C`JszS~)#9GQ_^)+iW;ehy19T=k) zIQb)3_u?ZA`M&08xAGBSwG-piB21NKe+sEk{}_lb-H9g35#yB~Krfh`rL!}$zKW1d zfu#c7g^uv+^Aa4qdZ0xJOqoicvjoF+w2ByZi_}OSLI=5vN~kJOmZMiGKa?Kq9rgj? zU?7Y5U>`sh`N2MbEb4=O09iDB%(MD`;wwZb)TjLb*$=S%fQS$H^#LOvaQp#qMPQ&U z;v$)x(AxtC$HglHu02YFp+#D@h|5FTvWSaUIs&Xo{Q_%JBSlVhE9L?Z6<`C7Bz+O@PMp1x?KITa2|u7oA*bL_s4 zY6`fjFIx)sn^pq*k>!5)34QqaeE7Y7_RWCk>yyL!7<`@`>|RZlA&*H1t`<7H1fiPAf6Q zXprS<;8lW0%laKWTB8Pp*M__RL`tux{Jljx1{o(rt>syFan zZz;IStngyyewAowiCF!iWzLjMsiK zs(R?4-=;&Ntf}J!9sz0NL?1vx^w$JtCxEmbE*z9Dm5y$68;!{&Gi!;`G7;0KtCgi4 zno+~efp}|ZXO3&$yE@J)FgnawZ{jn~DbP1;+n>!c2kS~Rij;S8CAk6@U+j=>QkT4u z;ig``5}57obXj#poi-`E1bH%+wfm7opTz-(liHS!Y8x(ZJsHadyh+B+ zs`O*UP%BK+|0?UEO20*(iT&-lH{2EQA_4d+PX%XOoqDo9_;wNuOj6Xtf^x^dy!X+G zh)le1Pra8vxC7sws$H|A24CJepI=_y!6!DWiV)y?uoYGAI|1gDzi)+(#r>Pn!`r?6 z*gtzc1X4rAaTbJMWCsSwC{Zt2y<)ZgY`nBLSJ1GEKXh2(Oxde4d^z!NPuV6Dcisos*yxeKnHuGNu$TIETlJxVJsp)-8G* z*N*6ge)-hR1}9Ewc(LBE$fHsV>zwq?TQCTvKiL+;Is+^J8Sd1lk}&$VC2@9LV5Wh4 zG?N4O$OKOSYM>Is1h!CGo~r$Xn(+CXl-H_kfYES`j}w$8JS<)%wq~IXSLTC~oR>Id zjKO*D2?(MVPL`XVKVpZ^e6pn$a|TXPTJCUULNWO&C5L=nv*3a+^UCk4bu!!WFX22c_0C?(g+3w%j}wIV1Nv^ zHp%u(1S86?nHd*ZTv(NCW|TY+Ne$Tf7G*n!;(ui#z!5(Q3o-!|*0cCV$dVUF=-D)1 z*byDaJM=%Bko%SCKX5NZ-;MG=6Gup49g8yViozNvLh++Tb4~|pnFgW^kfXYMDRaw% zRQ)XqTMz{{qelS?l+%H~X2HVfhXA&~k;;RtrG+Gp06z_OHx$9;i&9A-3KZaQdj?g4 zR`9W${L`d>pFKqDt9ZeK3mQgeX>h`^5b=OtPtJNzzE^m%N@u^^ug#r-MG&9sqk+h~ z`@@@$`^}$+cS{;ofrF=R$phf6fA`Ug0f$Bqe2?{NhPx*WTF*9Gf<@db9vZ~!7jU5k z7gliL1s73pkp&kOG>GWuPQ{+t?iQ=FwYLRDqXUCYthkr6tiD?RKsDZ*Y6pbUH!7u_ z@$MnIY!EJADB?SPsl$oE;XkK_*R$-t(e7zFq9;xMP?Ptsr4G9WXIM(F(K&q?{*7w9 z4=nBoxNmn#JG0%}Rz8id47p(QDX=*Ye<&spqsZZKE)a_v$0=Oaa9S&V#LlId7kCEjL(Z2HjO$zIY9ngcM`P~kq zl;n<_U34YrH+z2~5JV5`qOjbbbBBt39S{evemxoR>OX_adDr5Jt`RTXv>Uzk z!~D1m6+;->2u7W{tOP51Z#CxZNXf_u2HCA5oJUbHNl#a_0lsM&+wICr(3fBr?rDae z5+$$K`W?esy!##1Wqi;dyD)x&Y!BVWTV7@L{BKnvpY6z`a7xE!(B%g3ZRd&I%AzRa zkl+-2Hd+XXxQ@kx>Q%qClbJ(9L>tEW)wcxt?#>x)uk@L;a4)@2j9u?FW<8M+?8;1( z5H7m35Oh!mbetnRY=~CxZay|DPXPD+{JNqT`f@10sDZcLz;P*7G{|LIR;6qo@XcQz znR<`k9BJ{TC<>9dzec&V1&#E#HNwLN2#3zm8-$~h(nT$sp!hZ;HoM}cwbEf?cTSk)Q=NNcy=#5N_=bo=4@61xXtEUC94qw znJJg|b-lF^P95%bDJdtaEdV&eowsdvOyfV&rMRQ~B1%m*Pvj(;Sz|7M+=God#0ioS*@%VX zo6PL{{T_Vx-_v*0Q~wRfk&HLxx%1n%E#UsJq<8s2@kH{y=7Ht~%_08v6NRXM28!0bTdqXXJ)O~Z(X<=CWKp%&RSRV?%me5 z+wJ-!gwL0n$S9p9)wQD!e%7{o?II{=!B^^YNy3j*)*KFd?fhJDLz0Rn&(nWt&9{f# z9j&JU$ki`j^ke&tcWF(w8AJj!gHuU6Z{zHo1huc#vrrSgDGYelh=~R(?4u+4c(R@+{kg}g^ z`CxYg>H5R`w5niA{Q#3D5+dXu{lu34h~itB>kl?nLq$!}6B3kdy1V|evIG`Pz(UT4 za1R#Nz=AXCtVdlttk|D>5-2K=H(HAAH8_Lxg9RMYJ7VRBN3h*K*zPCT(N0)U_WlVh z9D{{Yuu%CSJcEVvV9wn0d$8jM*wK#^oXipk#V|$orKjgnTc1i{R&2L|P0M{zlVb0M zWSdqVzO0yng=nyV{2?s4e*x$)X5sW!4AxmqMUPCyRM##mM_1PlOhs1L&MQY$*N$I3 ztD3X|A+Bm>eqC7fc&j|&Uz5a)AbG?OnZk6)V6sDQ7Sd%vT+PIc2Rv9RnfENA4hI1O zs(X_F{?%dvbh$!<7ug>7c+FY!^+zo^=u;&7ZsLO8No!BnieqKa8;o0pF6BP)v$21L zgxAHxKTvC-A`I;a2uwzi_Ie6_Xcz4HS@VNi3JgoKy?Ra;vX zR@K^C)n3!kFhur)oF1x-TcruBWbG>~P18+*K??S(oL#nz2c?^kaqm(OdGk&+K?=~W znjj6~o?6Ej0WeVN?9H9cQ+w~J=_XFx(2*oEG7Os32?-Bket_BsaD0IC2Oxfc0vM2c zxK~JkyHU3BSJywePcx)FtqOC0r+iSQ4@#H%K{fuP{)g&*(3AgALogM_)G(g6m<332 z50-jJegNPD#NEIk-vkEfdoU<*50!d|xq(5hX{dDRx8nU!X$yJQo|+(eI~b_fz(Do^ zR3AX`0W@If`0@diYkPB_Y?Ci;=&DBUA5r|xzyaoHf}`5>1XH@)4|@1P|NMvk{h*P+ z5B2SX%H@Hnf)SOpFWrQ?shUre%m)mcYWhUcnCkdMm6{s(L|K@c_(UCg*H6P$wWfNb&Ky{%0?fg$r4!mHW}^#n*T0uHG3)E_ditXCtqC4l`okJfUUV!P=F0yif;WhV0q#{GRuEtgzib2 zJHv4iW8;&7UPZ!i6ng?IvCa1Lsy`%;B>Fv7=;+CEers;)n7x$t)%KT{?x?tj3>%d0 z0(hFe>y^C%IZ70s(OT7sol>^*vRmXDTz{Kk1TKlb#Ue2iEuV3JZNXXNbZUXSCy>*P zR`iY)tdb}aYMf=J)V~YAoj+P@mXmCV;b3S4515#hD!FoimTawE@;J zvgEy%E%D3^;7piSA7wu2M?VZ#0g68Ba@^Y7^!{1{ynTO>dOwi!U;j;?J%`Dqc-7-Z zt2)~2$bo#Wa&42MkZl&s6c_&Ub5$n3QNU3`ZA{iZ$sLb_!JwjZeAvbw1Ry%XLZ1@GbS?)=1e)$fwl=s_MlsH4E)}* z3`v-4Y({_OEOS@KD8MRbxp#woNg~AgM5dJ~;(eBM+HoWedO{@bW7|t7^xOqd7*YGLlo2lViN9z>i~4mvr+7b;iaH%><(}@w*9A+wUtqT{K_Gl*SAi9DsBo98aN^1j$oH}D*>|}1hyCp*V5G-T#MFhl{ zi9j}09g}V?fV;t>ZNMr4z~*X!nKlM9Kl!c!U~$!q-eeR%801VYrcYaHns31ERnum> z2}xo4hEP^lobDrzkkvb%TvDd5j;z&{rGh=?DPWDZ6KZ<;=PUM@uRxhoaUB|$A)kYS zr@Lh6zI9=!NQaf9j?<+Nz`%7$C=I*W5=b?Oyx#8zjj1Vg%tl*M>6IfjY~GSJRJi{Q zpnC_ykcQm+3;S%0P~@AyZp{G-@C{b*cIfTq@M{P7`dqy;lwUTW{0A)xHSU@|3YOQ)38MU*w&-hLh)hu!cIgKnNU@++4UdXY7V$$`Ql2EPjH>r z+VT?#eMiw|Cw7iw{26EX^I#Ue(t~-U@0G7hgS=!aA+t86&CH9j*nWpg;WtHxA--!g zecIP%hjFJczHoB$?kTCk3F~e7C6jto9 zR*F3{?*Yn{sN?&HlR9klOY}K&hJtm9k|_;!3mHH$pHn0wrVRsqKSjw3(MgnakltcR zkz;zrNVBy~k}e$ej>f(`EA|8Oz9)IfPS;67{KDe4>Xu(wQ)E*7?4qIj?WkWu6T|~C z2^&#QN$pnlmrPcyo)X_Jq#G4;0>Qa-4GDAtww(J3JO;xOF>7jLj0-~9aY+Es7jori zL}dMsn$PBVX%=o1l{V?LAeeHy@Am~9mw{^;Bpkfd7l?uJwW4(Jx+*JaP=Z|PUm!o{ z_5%{}KO+u&9^T7>>8_#ci8x^kHi>2rG1^@}f;0a?|ficxZ>^)FiJk#Vk8T0So9mf|3SIFDGp&W8_-dr+l-rO&kyo*y_D>-u}0opX}kQA1H9Axj#6%6Uc zRU}fownsLDlF2Y3-CVNg%<4}#LW=7_ivKtu>!Ng%1^n|Mi)ZmX~NNubPs={KexXwZOFccK4e zhNI+#O`?ZD)NM6`!yAH{YzPw$!w$in4RFv?WHh{HnA3+LrAYkSfE7YErwcQ5SThE{ z#TSz?ORzgc4=_e{WKEYVM~<5t2B;$&xaO0haqw}Ss$YxuURyX>&#!Fbv8a883CCf> zFLrbho>PGV&(C7qDXW>hH7DL0=FiXJQR&$PE6l3n|5AEy9%)km!>Ab%P!BEv__w?Y z;#eB#VSmrHjBrMcb(m4jYMGY)1uBjX0-RS6VS1CJ)gd?qa3g~@8T&q?TMQvm8Y_*n zHj{ARYXIA<-W!}lnkg`iVTQR6K8LTx!Pi=qf(pvKWK$s!r0q?phmaawQjFEB!#yY+ zvb)d_iI7aK$G0tw66HUy>X-&;t&)2N^s3Q;kq_COq(S1aYo znK3%>vL&0%U0SXJjUqXFw)yHl1vef9@o5{{Nd@$-j((~Sv!WPxN%oKlTJbxrlIv5) zXO$gD>S?7LhoBA)k)((BP6DvYvfkdkufTAe$xxH)+7<5`8qymX+gg*9tAs?dN%WL+ zf@}PBd<7r1WsGqj-)`^`LzWFTCar(2wURk`9wS4ST^1_{k6abO7{1xGZ(s#0M654l zrQ!77GzgHTSUz{ahSxWbkERubZ*Y=@qEM6+pwOpIfTo3A-%fy1D@x|jP>IDm-=DJD zklDXJNT~tdL#;E;f6polQZ<-Qj+&t||D6;c!^Q1m_b& z9f`oIMU8>9J8pgaH~Tv?yd$0!U_cw?O1xx0fpC@o7R};}Q9QdcnGcfdN7CO1kVj1o zlK)^lZhC>z*PAF<^^Pq^0-L0$B>~D>jH>g7uwy18E3PFsX+4*K5vp3Kg6)A5v{I0x zXDNO*S$ZQC1QmO}U057?7^(nO)4|&Y zVY!;HK?NS+3j-G&y{-KWOd{|X8@5%BJ2vny5g-WA{W*i70xb|^VR ziX+6Ljg#PbN+`8MCjCpqD~KN64{cIl-*DN(>()oP(c=Hva!!M2T`4_oo4;xg31W#8VZ?(ql%aJGu9<#cTxrh%z9mlJ(#28OweN;x zu^%8DcJ>)SjgO}%*BS>2gLEW+iRZqd*qS6j(#z^Nnws5drdG8dH@t|%d=OX4)sGBx zFNMULQf$qYK)9#hNt#p%aNavw7+*+Jutr&Q)^o3*!kyG%p@L9b%6KZJ{>kw>?`MLO z8BavqPL!iwsiUB98Zm>Q0y%sIT`H8W7xNLI6rp^SD)1Y2U2~`;9lWLeYT5=XuS^*w z#JA$Qy|5!$NMatr@bi{$Srm-PVYD^E6Cb$(me!}MSSsNAUh60tba7o%p8g7sIX!r7 z&`OFS*7J%QA=XoV0C>63t;9AiKzr3X+e+jSMwc4J1-P4K-ZGyz1fQ{|^z7{PK;;av z#b&V!l}4HbU_$KKSO4y@FvVRa06uJVHPTHjYg>05f6{?kf%aQ#MoNB+-EvD0vA~+z z)W+~phkCv>)I~p@S|g7%4I3${^N))*VqXcA4tj7{;nK@C;lUcbRPe?Gs0uGKecVZ4I1b*rOpU8ISx1fY!a^~VxyOw{iN_JKj`%UQ$ zf+lJ$U;74Mo}%+n=iccr$O0yl=O3E_H|pcRR6`r7kbr%CxiKf*oy3K&lxn4@LJj>bb`Hhxwr+$N{KqL&4j z0oK25D1~}ZJ2)U?y1@V;^x=Gvc{%F410u!nlU-q8wHzPeP~)Lc9L9|V`FF12cYpUl zO!5j2^g9Pa>N4!lfi#xUVBUoeee zU|De2zw$B|7<}5L*(*nMu(lmq!m(W5ob<8lg;BR0QvaECl*2Z2P~vG}tOwzyz|mD< zsDdev6Hvn5Xf{N%Jr1zNCz>2rvt7QLcytO1?B{Ug%}v9v_;v`tIK}9vz2Yi~ucnjf zIF{~2-GbB@NXTeWpuoXv!*7vflMhT}aWHe4b6{|GE@@5^TE0m7UAY%3)M9nlH!1%o zWBz+bA2x{3;JMYsM#Q=6-q{M*|Ip{=XqG8r^yzu3Sg$IDV+I;(n~eu~(UhYzw9PMy zbVOD{J#=d_VSYMoR01o_*tu#WC^Gv`RjLkaBF9dnlR(%$z`JrimyA!%fT7Mtc9L^B z>YOl%gRIH={3?+{tf|cXaU_FMhwC1EW7Sz`_t{q^!&^V1h?noJ$r1jW-fm_&>~O0E zosQ4C&SpOsFBk`j#7m_FWfEPK)PpfjoM1w-BJP>c?<5saKlqUq(j#;defgZI_ccr{ z;<8y(cr%sxg_z=Shw1z5ocDxak#;SEN$Uak#EDe*5iV2cc)dP5L8Y~kJ{LiHR>0^` zM7K&`W*nwvv%6NUYD3)VBjd^-zmRdzw@@1SLLtVq)M)H=f*V1_AfmKn8$LsAPFt1~ zb0drv!2v}EMy(LJ?NPMwIo7{`s)O|0)u0UB(H#w|BWt>ax5na$1q&%c9;xTxYkS2*jFz{+W=w^?e3YvhK>wHN|S zs@Camv;T~z>X_$pq_#Sh_d8Q_Xxe*vOu8J7GM`UoOzN(rZt%@zl)n)*AYo<_=tGX% zUi~OpbfD%=?By^G`VE`|IP#;6VP^-2=3b(Y3|J_(!+ycc=ei>C2SoGx8J4pYvg&D) zhCj7EQ;rl`0ZOalCOSB-BJ1HO8fNpY{L zG1WN+R9?r(wR|7DbWAj>zm{VnbW#nySlJ^VOY>GjsIb1`qpKrhv3fdWw#hGeg*8NW zeEg&%2w#8sj6=WS9MC>MzosUVE3{=GLZWhBO^S-PS$HUOA;g#xs~$kbBZV#nLhT{g zy@qJ=z%aMDk~+zS%zh}aRetrj_wj%A5UuU@6a2C-BxcfYM|#c||^#}Mx( zIJQ5z)``fih*w>_h?+JlfPjtv+2SWh*kAM zvBh&}cG2c!Rb5rOMmno{T2=LS6CR6B1{0#ry%#pp-$N}spmbf9xOBXL^^7^^e6_{F zlYL_em(FR$x4tyeZOiV)MaA96g$y=Vh50Te;tfm$p)Jn@7LEySOS}p}TzlGczFZVJ z7v=aTf|7e?BT+*Cc~rvWnzxeeNnZUm`#vb!?8IX$GEwP12hZxV+VcV1D`U*bum-@4 zZzGLvScBvoztL5=-M4PPrRreR^&3(0V^5&cbS;mWJh6{6c>7hYz@r|tnpb;z`!TP=#~%deI)^5+Mp9)QoldADR4txufN}mT zRtO%c9aeNgK4IZk2VXYzqDHWTNSl zrkmbQ1*BTqxBssDr?ExnpSBaSaNQmb)z7WM%NkUQcdDP8g?m&*0Se5m8{#ub3U)43`$dq9F}2C%)g;&)meNA9X$eY#U)gS?kn|20-D9PuawP55kt9;wu7Y=)F~6k z%4SU6>=9Ki=2-t8$DX?B5Y0EL{tWpeLA}kyD(fdK9%H|rYIQkn>nyP%Zi{8*KKT+W zYo?l$uRt9znWeR5L9&tPE^yZ`on<({nRFR>OP<+cV>K=bQMvRKo>i8_qs5n;I zC{<|4b&$@Y9!?*8i<+u-6BV1ZG&CM-W6WnHH1Jtnk{rG#6w=|bdcSJAG=F&JVX?X?S_9l^iRp$likoHyOnn${pYlH=piHoLTiH%*LF+JV1} zEmAn5=bfL7ehS5=zW5aCMkD_tsqM@xsoA8@VPpbAr-F zIa9&h5Xi1uLT>THrb>+|lJMTSIEr$$x0v2RLX%0eJg)I>h-?vCF{p?M|2m!l*CCDp z`#P?Xd^;=jPUm|VuXj@gG3AX<212685WvHHZyiVp zs8Niwm_VbPkd6hudF}TqTPB+=Slvzj#k7M>w$@4t9d;DQCS8o(X`FmFBMv+rW<*EX z1Bg*SC5ht=wdI{b9L8YEToqb<%G&SwUV#mYOyX7AyFAFNQbd$?e-fN^d%>kO!P!4H_JJKu@epnj*EVeFUl_A^Eh}_MstH8o_^=~wtCX^BUURHA43pyL zs~Xv`f4GvQ0$iZS(83Q=TvVojUw@;W$(|H=0jZ1Ci467RP6|ft*2_}l`x*6Bsq{h= zl2X5V2GqIYfVtt=yR4*{Q$>+x+4tX+OfP;41{Gft5l4?ODgxe zV4ov;%7b%y$duP@WdYHh){r+>#OhRx&&#?NfDdb#*U zo=Pe~(x2KaVZeIMEuvw|UjAD|18O)YLQ<1ykAT8a8z+2HlbBUR!=ys}7c0UPSUDZL z9*OE~&@8)b0iCvhtZ^fFB`o@CW06;a>Ud>Wllmmwkh{N%LxPacQ!waTHv5$5$bvVh z-Q?l%&llers5oo#YpBFOwNG57V4OB@zA4e=`#P4I7KdC9Rwkull;Mi_7liC`5u=&5 zkRG-uw0sr6oOA>_6o)M5C|B^J%e%*UhcZx^RuQ78$VaS~t!XprZi&NZoLPbv8h8O~ zD!5;lW|}zN0j{fJx1oy*F_r8;V=5~XVj63)#?huIu&VS9ey5|d6we~#-lac zV@ei>w77!kXup*}j7s}tK=ZnD@4&YQ7JL=oY-7So#W-EGEBHlDX1~FWOpmd;cv%Ck z*j|uC(_@rra4_i5!mBi?)6=a9?jWw`s7i_du^w8~kR58wM^e#}kI-u0DvSyVa3$3E zB|D zBMWU0xbUstf6)CV&(}Otr20k)RepviEnb~Dn2>H29byPQ*(8GMV4_(A2c9EXPERz1`8>7=>phA^#p!3!sKs=l2CjvA5`coa6 z#n=JFWKK04csJAW>QLa;*#E?#5*{&WqGBbrubCt1oqs)vdihX-gkYwP2{&w>Ny>flPVX#}e z!HJ_8`<-NFw1e#;vV{?5G;Nm@`L-N{{mwrVRdJ>H0+M8?>od4v!Kxe~@E`0}ZSYzE zDxdQhKgmP|=w!YT_^r2`;I{jg?~>AgCtXp#qkGFKxa-)oRk%ULt~{a%QNRmdv-=Pg zk1W}nV+{>r&s{9Wde=3Eh5tIuiv$uIVZ8$qLG!%t(laFj{(O2a@z;=}08$+cZ~hk@ zsWe@~+YDLhx~)d4z5i{*(r-aCuV$i92L{Lf^!CqQzuo5RD@L@P#C+z9ef&tLUxlR@tuLu(sFK~AS^fh9YvxA4DBKQz;PPQdf|4p#4Y zS2Ct>=t9Sj9^Ec;*erHSGW4=Y{-o2Q*k3YXd;Qfc+|1&Z${Qu9);OF{T zn!yjq83h!FKypTEa&~cPZn0ivVr~v?P5}WOjfCg?Cj%2h^z)xg%z#3p=YLQfyMzru zod1zJ!McdqfWxJF{vq)Kw+05y*j-;N8SR&PO)i{znSFOD=jQ&qPs?`4?z6Lh@V991 zzbkhyz5Dj<@Ao?2PZ~ECs2thkU-hkKOVR5D(WeubKbw3{dH3!2lT!~`WBFj+op-GEu3?m@-n7DAi*@DxFP?Ku`#(Jj`Y=V%Evi~R z`ABiiqpas#k0dh{=Q%H5YW3xDR-?Xsa+pGn+srrC&1TC|jxxPjQ!A;yc}=C8?#rMH hy(_=6RQ_cDaEIf?qS5k%aB3M} + spec.homepage = "https://unicorn-engine.org" + + spec.files = Dir["lib/unicorn/*.rb"] + Dir["ext/unicorn.c"] + Dir["ext/unicorn.h"] + Dir["ext/extconf.rb"] + spec.require_paths = ["lib","ext"] + spec.extensions = ["ext/extconf.rb"] + spec.add_development_dependency "bundler", "~> 1.11" + spec.add_development_dependency "rake", "~> 10.0" +end From 937b3bc22c1f394ab00ebcc2d8168c233a5b1d8e Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Tue, 22 Mar 2016 12:19:26 +0100 Subject: [PATCH 057/149] README changed --- bindings/ruby/README.md | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/bindings/ruby/README.md b/bindings/ruby/README.md index c8bf4566..d18df8bc 100644 --- a/bindings/ruby/README.md +++ b/bindings/ruby/README.md @@ -2,19 +2,28 @@ Installation ============ 1. Softwarerequirements +----------------------- -Linux -- ruby >= 1.9.3 -- rubygems -- make -- gcc + Linux + - ruby >= 1.9.3 + - rubygems + - make + - gcc -Mac OS -- ruby >= 1.9.3 -- rubygems -- make -- XCode + Mac OS + - ruby >= 1.9.3 + - rubygems + - make + - XCode 2. Install unicorn +------------------ + cd + ./make.sh install + +3. Install ruby binding +----------------------- + cd bindings/ruby + make install From 80b2f45178b061f99dd81250ff0f31d58c897fe4 Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Tue, 22 Mar 2016 12:22:02 +0100 Subject: [PATCH 058/149] README format changed --- bindings/ruby/README.md | 40 ++++++++++++++++++---------------------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/bindings/ruby/README.md b/bindings/ruby/README.md index d18df8bc..47f225ba 100644 --- a/bindings/ruby/README.md +++ b/bindings/ruby/README.md @@ -1,29 +1,25 @@ -Installation -============ +#Installation -1. Softwarerequirements ------------------------ +##Softwarerequirements - Linux - - ruby >= 1.9.3 - - rubygems - - make - - gcc +### Linux +- ruby >= 1.9.3 +- rubygems +- make +- gcc - Mac OS - - ruby >= 1.9.3 - - rubygems - - make - - XCode +### Mac OS +- ruby >= 1.9.3 +- rubygems +- make +- XCode -2. Install unicorn ------------------- - cd - ./make.sh install +## Install unicorn +cd +./make.sh install -3. Install ruby binding ------------------------ - cd bindings/ruby - make install +## Install ruby binding +cd bindings/ruby +make install From 04cad5cd8cf6dd9412d38be9134820ce993fa56d Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Tue, 22 Mar 2016 12:23:08 +0100 Subject: [PATCH 059/149] README format changed --- bindings/ruby/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/bindings/ruby/README.md b/bindings/ruby/README.md index 47f225ba..a00b5639 100644 --- a/bindings/ruby/README.md +++ b/bindings/ruby/README.md @@ -15,11 +15,11 @@ - XCode ## Install unicorn -cd -./make.sh install + cd path_to_unicorn + ./make.sh install ## Install ruby binding -cd bindings/ruby -make install + cd bindings/ruby + make install From a9de03edfbd9f8466698f23117f3654fae25acf0 Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Tue, 22 Mar 2016 12:26:12 +0100 Subject: [PATCH 060/149] README format changed --- bindings/ruby/README.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/bindings/ruby/README.md b/bindings/ruby/README.md index a00b5639..67a2109f 100644 --- a/bindings/ruby/README.md +++ b/bindings/ruby/README.md @@ -1,6 +1,6 @@ -#Installation +# Installation -##Softwarerequirements +## Software requirements ### Linux - ruby >= 1.9.3 @@ -15,11 +15,10 @@ - XCode ## Install unicorn - cd path_to_unicorn - ./make.sh install + * cd path_to_unicorn + * ./make.sh install ## Install ruby binding - cd bindings/ruby - make install - - + * cd bindings/ruby + * make install + \ No newline at end of file From b5ea277900d3f9aeae0ab15aa65c525955540a36 Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Tue, 22 Mar 2016 22:32:59 +1100 Subject: [PATCH 061/149] Fixed minor typos --- samples/sample_x86.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/samples/sample_x86.c b/samples/sample_x86.c index 264015f2..bc290de4 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -470,7 +470,7 @@ static void test_i386_invalid_mem_read(void) uc_close(uc); } -// emulate code that read invalid memory +// emulate code that write invalid memory static void test_i386_invalid_mem_write(void) { uc_engine *uc; @@ -532,7 +532,7 @@ static void test_i386_invalid_mem_write(void) if (!uc_mem_read(uc, 0xaaaaaaaa, &tmp, sizeof(tmp))) printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", 0xaaaaaaaa, tmp); else - printf(">>> Failed to read 4 bytes from [0x%x]\n", 0xffffffaa); + printf(">>> Failed to read 4 bytes from [0x%x]\n", 0xaaaaaaaa); if (!uc_mem_read(uc, 0xffffffaa, &tmp, sizeof(tmp))) printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", 0xffffffaa, tmp); From 903fb04f298884c057cb8aa21872d9f76dcfbe92 Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Tue, 22 Mar 2016 23:09:38 +1100 Subject: [PATCH 062/149] Another typo --- samples/sample_x86.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/sample_x86.c b/samples/sample_x86.c index bc290de4..7b4fc120 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -850,7 +850,7 @@ static void test_x86_16(void) uc_mem_map(uc, 0, 8 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - if (uc_mem_write(uc, 0, X86_CODE16, sizeof(X86_CODE64) - 1)) { + if (uc_mem_write(uc, 0, X86_CODE16, sizeof(X86_CODE16) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } From 9379d41764258efdbca453978baad982a354ab4a Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Tue, 22 Mar 2016 13:30:29 +0100 Subject: [PATCH 063/149] blank lines removed --- bindings/ruby/unicorn_gem/ext/unicorn.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/bindings/ruby/unicorn_gem/ext/unicorn.c b/bindings/ruby/unicorn_gem/ext/unicorn.c index 09d1d580..4529448a 100644 --- a/bindings/ruby/unicorn_gem/ext/unicorn.c +++ b/bindings/ruby/unicorn_gem/ext/unicorn.c @@ -43,14 +43,11 @@ void Init_unicorn() { rb_define_method(UcClass, "mem_read", m_uc_mem_read, 2); rb_define_method(UcClass, "mem_write", m_uc_mem_write, 2); rb_define_method(UcClass, "mem_map", m_uc_mem_map, -1); - //rb_define_method(UcClass, "mem_map_ptr", m_uc_mem_map_pzt, 4); rb_define_method(UcClass, "mem_unmap", m_uc_mem_unmap, 2); rb_define_method(UcClass, "mem_protect", m_uc_mem_protect, 3); rb_define_method(UcClass, "hook_add", m_uc_hook_add, -1); rb_define_method(UcClass, "hook_del", m_uc_hook_del, 1); rb_define_method(UcClass, "query", m_uc_hook_del, 1); - - } VALUE m_uc_initialize(VALUE self, VALUE arch, VALUE mode) { @@ -221,16 +218,6 @@ VALUE m_uc_mem_map(int argc, VALUE* argv, VALUE self){ return Qnil; } -// VALUE m_uc_mem_map_ptr(VALUE self, VALUE address, VALUE size, VALUE perms, VALUE ptr){ -// uc_err err; - -// err = uc_mem_map_ptr(_uc, NUM2INT(address), NUM2INT(size), NUM2INT(perms), NUM2INT(ptr)); -// if (err != UC_ERR_OK) { -// rb_raise(UcError, "%s", uc_strerror(err)); -// } -// return Qnil; -// } - VALUE m_uc_mem_unmap(VALUE self, VALUE address, VALUE size){ uc_err err; uc_engine *_uc; From a6b570d033309899de38c6865c338cc556e4a24a Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Tue, 22 Mar 2016 13:30:52 +0100 Subject: [PATCH 064/149] Version changed --- bindings/ruby/unicorn_gem/lib/unicorn/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/ruby/unicorn_gem/lib/unicorn/version.rb b/bindings/ruby/unicorn_gem/lib/unicorn/version.rb index 1ebff38c..ad18d0e7 100644 --- a/bindings/ruby/unicorn_gem/lib/unicorn/version.rb +++ b/bindings/ruby/unicorn_gem/lib/unicorn/version.rb @@ -1,3 +1,3 @@ module Unicorn - VERSION = "0.9.0" + VERSION = "1.0.0" end From 16f77061d97a9e20edcd76985c01df8678940392 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 22 Mar 2016 20:54:51 +0800 Subject: [PATCH 065/149] ruby: spaces & indentation --- bindings/ruby/sample_x86.rb | 36 ++++++++++++------------- bindings/ruby/unicorn_gem/ext/unicorn.c | 28 +++++-------------- 2 files changed, 23 insertions(+), 41 deletions(-) diff --git a/bindings/ruby/sample_x86.rb b/bindings/ruby/sample_x86.rb index e951927b..86496d9b 100644 --- a/bindings/ruby/sample_x86.rb +++ b/bindings/ruby/sample_x86.rb @@ -76,7 +76,6 @@ end # callback for OUT instruction HOOK_OUT = Proc.new do |uc, port, size, value, user_data| - eip = uc.reg_read(UC_X86_REG_EIP) puts("--- writing to port 0x%x, size: %u, value: 0x%x, address: 0x%x" % [port, size, value, eip]) @@ -137,9 +136,8 @@ def test_i386() tmp = mu.mem_read(ADDRESS, 2) print(">>> Read 2 bytes from [0x%x] =" % (ADDRESS)) tmp.each_byte { |i| print(" 0x%x" % i) } - - - puts + + puts rescue UcError => e puts("ERROR: %s" % e) @@ -494,18 +492,18 @@ def test_x86_16() end - test_i386() - puts("=" * 20) - test_i386_loop() - puts("=" * 20) - test_i386_invalid_mem_read() - puts("=" * 20) - test_i386_invalid_mem_write() - puts("=" * 20) - test_i386_inout() - puts("=" * 20) - test_x86_64() - puts("=" * 20) - test_x86_64_syscall() - puts("=" * 20) - test_x86_16() +test_i386() +puts("=" * 20) +test_i386_loop() +puts("=" * 20) +test_i386_invalid_mem_read() +puts("=" * 20) +test_i386_invalid_mem_write() +puts("=" * 20) +test_i386_inout() +puts("=" * 20) +test_x86_64() +puts("=" * 20) +test_x86_64_syscall() +puts("=" * 20) +test_x86_16() diff --git a/bindings/ruby/unicorn_gem/ext/unicorn.c b/bindings/ruby/unicorn_gem/ext/unicorn.c index 4529448a..8681d4ae 100644 --- a/bindings/ruby/unicorn_gem/ext/unicorn.c +++ b/bindings/ruby/unicorn_gem/ext/unicorn.c @@ -28,7 +28,6 @@ VALUE UcClass = Qnil; VALUE UcError = Qnil; - void Init_unicorn() { rb_require("unicorn/unicorn_const"); UnicornModule = rb_define_module("Unicorn"); @@ -72,7 +71,7 @@ VALUE m_uc_emu_start(int argc, VALUE* argv, VALUE self){ uc_err err; uc_engine *_uc; Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); - + rb_scan_args(argc, argv, "22",&begin, &until, &timeout, &count); if (NIL_P(timeout)) timeout = INT2NUM(0); @@ -100,7 +99,6 @@ VALUE m_uc_emu_stop(VALUE self){ } VALUE m_uc_reg_read(VALUE self, VALUE reg_id){ - uc_err err; int32_t tmp_reg = NUM2INT(reg_id); int64_t reg_value = 0; @@ -131,7 +129,6 @@ VALUE m_uc_reg_read(VALUE self, VALUE reg_id){ rb_ary_store(mmr_ary, 3, UINT2NUM(mmr.flags)); return mmr_ary; default: - err = uc_reg_read(_uc, tmp_reg, ®_value); if (err != UC_ERR_OK) { rb_raise(UcError, "%s", uc_strerror(err)); @@ -155,7 +152,7 @@ VALUE m_uc_reg_write(VALUE self, VALUE reg_id, VALUE reg_value){ case UC_X86_REG_LDTR: case UC_X86_REG_TR: Check_Type(reg_value, T_ARRAY); - + mmr.selector = NUM2USHORT(rb_ary_entry(reg_value,0)); mmr.base = NUM2ULL(rb_ary_entry(reg_value,1)); mmr.limit = NUM2UINT(rb_ary_entry(reg_value,2)); @@ -220,7 +217,7 @@ VALUE m_uc_mem_map(int argc, VALUE* argv, VALUE self){ VALUE m_uc_mem_unmap(VALUE self, VALUE address, VALUE size){ uc_err err; - uc_engine *_uc; + uc_engine *_uc; _uc = (uc_engine*) NUM2ULL(rb_iv_get(self, "@uch")); err = uc_mem_unmap(_uc, NUM2ULL(address), NUM2UINT(size)); if (err != UC_ERR_OK) { @@ -231,7 +228,7 @@ VALUE m_uc_mem_unmap(VALUE self, VALUE address, VALUE size){ VALUE m_uc_mem_protect(VALUE self, VALUE address, VALUE size, VALUE perms){ uc_err err; - uc_engine *_uc; + uc_engine *_uc; Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); err = uc_mem_protect(_uc, NUM2ULL(address), NUM2UINT(size), NUM2UINT(perms)); if (err != UC_ERR_OK) { @@ -250,7 +247,6 @@ static void cb_hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *u ud = rb_ary_entry(passthrough, 1); rUc = rb_ary_entry(passthrough, 2); rb_funcall(cb, rb_intern("call"), 4, rUc, ULL2NUM(address), UINT2NUM(size), ud); - } static void cb_hook_mem_access(uc_engine *uc, uint32_t access, uint64_t address, uint32_t size, int64_t value, void *user_data){ @@ -264,7 +260,6 @@ static void cb_hook_mem_access(uc_engine *uc, uint32_t access, uint64_t address, rUc = rb_ary_entry(passthrough, 2); rb_funcall(cb, rb_intern("call"), 6, rUc, UINT2NUM(access), ULL2NUM(address), UINT2NUM(size), LL2NUM(value), ud); - } static bool cb_hook_mem_invalid(uc_engine *uc, uint32_t access, uint64_t address, uint32_t size, int64_t value, void *user_data){ @@ -289,7 +284,6 @@ static uint32_t cb_hook_insn_in(uc_engine *uc, uint32_t port, int size, void *us ud = rb_ary_entry(passthrough, 1); rUc = rb_ary_entry(passthrough, 2); return NUM2UINT(rb_funcall(cb, rb_intern("call"), 4, rUc, UINT2NUM(port), INT2NUM(size), ud)); - } static void cb_hook_insn_out(uc_engine *uc, uint32_t port, int size, uint32_t value, void *user_data){ @@ -302,7 +296,6 @@ static void cb_hook_insn_out(uc_engine *uc, uint32_t port, int size, uint32_t va ud = rb_ary_entry(passthrough, 1); rUc = rb_ary_entry(passthrough, 2); rb_funcall(cb, rb_intern("call"), 5, rUc, UINT2NUM(port), INT2NUM(size), UINT2NUM(value), ud); - } static void cb_hook_insn_syscall(uc_engine *uc, void *user_data){ @@ -315,7 +308,6 @@ static void cb_hook_insn_syscall(uc_engine *uc, void *user_data){ ud = rb_ary_entry(passthrough, 1); rUc = rb_ary_entry(passthrough, 2); rb_funcall(cb, rb_intern("call"), 2, rUc, ud); - } static void cb_hook_intr(uc_engine *uc, uint64_t address, uint32_t size, int64_t value, void *user_data){ @@ -328,10 +320,8 @@ static void cb_hook_intr(uc_engine *uc, uint64_t address, uint32_t size, int64_t ud = rb_ary_entry(passthrough, 1); rUc = rb_ary_entry(passthrough, 2); rb_funcall(cb, rb_intern("call"), 5, rUc, ULL2NUM(address), UINT2NUM(size), LL2NUM(value), ud); - } - VALUE m_uc_hook_add(int argc, VALUE* argv, VALUE self){ VALUE hook_type; VALUE callback; @@ -351,12 +341,10 @@ VALUE m_uc_hook_add(int argc, VALUE* argv, VALUE self){ if (NIL_P(arg1)) arg1 = INT2NUM(0); - VALUE passthrough; uc_hook trace; uc_err err; - if (rb_class_of(callback) != rb_cProc) rb_raise(UcError, "Expected Proc callback"); @@ -367,7 +355,6 @@ VALUE m_uc_hook_add(int argc, VALUE* argv, VALUE self){ uint32_t htype = NUM2UINT(hook_type); if(htype == UC_HOOK_INSN){ - switch(NUM2INT(arg1)){ case UC_X86_INS_IN: err = uc_hook_add(_uc, &trace, htype, cb_hook_insn_in,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end), NUM2INT(arg1)); @@ -386,7 +373,6 @@ VALUE m_uc_hook_add(int argc, VALUE* argv, VALUE self){ err = uc_hook_add(_uc, &trace, htype, cb_hook_intr,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end)); } else if(htype == UC_HOOK_CODE || htype == UC_HOOK_BLOCK){ - err = uc_hook_add(_uc, &trace, htype, cb_hook_code,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end)); } else if (htype & UC_HOOK_MEM_READ_UNMAPPED @@ -407,8 +393,6 @@ VALUE m_uc_hook_add(int argc, VALUE* argv, VALUE self){ err = uc_hook_add(_uc, &trace, htype, cb_hook_mem_access,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end)); } - - if (err != UC_ERR_OK) { rb_raise(UcError, "%s", uc_strerror(err)); } @@ -425,7 +409,7 @@ VALUE m_uc_hook_del(VALUE self, VALUE hook){ rb_raise(UcError, "%s", uc_strerror(err)); } return Qnil; -} +} VALUE m_uc_query(VALUE self, VALUE query_mode){ int qm = NUM2INT(query_mode); @@ -438,4 +422,4 @@ VALUE m_uc_query(VALUE self, VALUE query_mode){ rb_raise(UcError, "%s", uc_strerror(err)); } return INT2NUM(result); -} +} From c49c7f7c075dec3003c7a0782754a3d8cf04b611 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 22 Mar 2016 20:55:41 +0800 Subject: [PATCH 066/149] update CREDITS.TXT --- CREDITS.TXT | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.TXT b/CREDITS.TXT index e4319580..8156f74c 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -59,3 +59,4 @@ Chris Eagle: Java binding Ryan Hileman: Go binding Antonio Parata: .NET binding Jonathon Reinhart: C unit test +Sascha Schirra: Ruby binding From 56c670509fc4210ad3a0f762ddda4ade02445165 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 22 Mar 2016 20:58:06 +0800 Subject: [PATCH 067/149] update list of bindings in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f57b1df6..e970c408 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ Unicorn offers some unparalleled features: - Multi-architecture: ARM, ARM64 (ARMv8), M68K, MIPS, SPARC, and X86 (16, 32, 64-bit) - Clean/simple/lightweight/intuitive architecture-neutral API -- Implemented in pure C language, with bindings for Python, Java, and Go +- Implemented in pure C language, with bindings for Ruby, Python, Java, MSVC, .NET, Go and Delphi/Free Pascal. - Native support for Windows & *nix (with Mac OSX, Linux, *BSD & Solaris confirmed) - High performance via Just-In-Time compilation - Support for fine-grained instrumentation at various levels From 3642c685873f2a1b29ddf123c4d761891b35e510 Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Tue, 22 Mar 2016 18:36:26 +0100 Subject: [PATCH 068/149] Remove blank line --- bindings/ruby/unicorn_gem/ext/unicorn.h | 1 - 1 file changed, 1 deletion(-) diff --git a/bindings/ruby/unicorn_gem/ext/unicorn.h b/bindings/ruby/unicorn_gem/ext/unicorn.h index 30b417d9..05fb2608 100644 --- a/bindings/ruby/unicorn_gem/ext/unicorn.h +++ b/bindings/ruby/unicorn_gem/ext/unicorn.h @@ -26,7 +26,6 @@ VALUE m_uc_reg_write(VALUE self, VALUE reg_id, VALUE reg_value); VALUE m_uc_mem_read(VALUE self, VALUE address, VALUE size); VALUE m_uc_mem_write(VALUE self, VALUE address, VALUE bytes); VALUE m_uc_mem_map(int argc, VALUE* argv, VALUE self); -//VALUE m_uc_mem_map_ptr(VALUE self, VALUE address, VALUE size, VALUE perms, VALUE ptr); VALUE m_uc_mem_unmap(VALUE self, VALUE address, VALUE size); VALUE m_uc_mem_protect(VALUE self, VALUE address, VALUE size, VALUE perms); VALUE m_uc_hook_add(int argc, VALUE* argv, VALUE self); From 0c49f83cb5621cf3839b84fe480811f2de57d949 Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Tue, 22 Mar 2016 20:08:15 +0100 Subject: [PATCH 069/149] GDT test added --- tests/regress/x86_gdt.py | 94 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 tests/regress/x86_gdt.py diff --git a/tests/regress/x86_gdt.py b/tests/regress/x86_gdt.py new file mode 100644 index 00000000..3565a74c --- /dev/null +++ b/tests/regress/x86_gdt.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +from unicorn import * +from unicorn.x86_const import * +from struct import pack + +import regress + +F_GRANULARITY = 0x8 +F_PROT_32 = 0x4 +F_LONG = 0x2 +F_AVAILABLE = 0x1 + +A_PRESENT = 0x80 + +A_PRIV_3 = 0x60 +A_PRIV_2 = 0x40 +A_PRIV_1 = 0x20 +A_PRIV_0 = 0x0 + +A_CODE = 0x10 +A_DATA = 0x10 +A_TSS = 0x0 +A_GATE = 0x0 + +A_DATA_WRITABLE = 0x2 +A_CODE_READABLE = 0x2 + +A_DIR_CON_BIT = 0x4 + +S_GDT = 0x0 +S_LDT = 0x4 +S_PRIV_3 = 0x3 +S_PRIV_2 = 0x2 +S_PRIV_1 = 0x1 +S_PRIV_0 = 0x0 + +CODE = '65330d18000000'.decode('hex') # xor ecx, dword ptr gs:[0x18] + +def create_selector(idx, flags): + to_ret = flags + to_ret |= idx << 3 + return to_ret + +def create_gdt_entry(base, limit, access, flags): + + to_ret = limit & 0xffff; + to_ret |= (base & 0xffffff) << 16; + to_ret |= (access & 0xff) << 40; + to_ret |= ((limit >> 16) & 0xf) << 48; + to_ret |= (flags & 0xff) << 52; + to_ret |= ((base >> 24) & 0xff) << 56; + return pack(' Date: Tue, 22 Mar 2016 23:54:30 -0700 Subject: [PATCH 070/149] fix x86 segment setup by updating cached segment registers on reg_write --- qemu/target-i386/seg_helper.c | 2 - qemu/target-i386/unicorn.c | 12 +- samples/sample_x86_32_gdt_and_seg_regs.c | 290 +++++++++++++++++++++++ 3 files changed, 296 insertions(+), 8 deletions(-) create mode 100755 samples/sample_x86_32_gdt_and_seg_regs.c diff --git a/qemu/target-i386/seg_helper.c b/qemu/target-i386/seg_helper.c index 4702dfcc..326fb870 100644 --- a/qemu/target-i386/seg_helper.c +++ b/qemu/target-i386/seg_helper.c @@ -2556,7 +2556,6 @@ void helper_verw(CPUX86State *env, target_ulong selector1) CC_SRC = eflags | CC_Z; } -#if defined(CONFIG_USER_ONLY) void cpu_x86_load_seg(CPUX86State *env, int seg_reg, int selector) { if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { @@ -2570,7 +2569,6 @@ void cpu_x86_load_seg(CPUX86State *env, int seg_reg, int selector) helper_load_seg(env, seg_reg, selector); } } -#endif /* check if Port I/O is allowed in TSS */ static inline void check_io(CPUX86State *env, int addr, int size) diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 302f04c9..961e8d98 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -782,22 +782,22 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) uc_emu_stop(uc); break; case UC_X86_REG_CS: - X86_CPU(uc, mycpu)->env.segs[R_CS].selector = *(uint16_t *)value; + cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_CS, *(uint16_t *)value); break; case UC_X86_REG_DS: - X86_CPU(uc, mycpu)->env.segs[R_DS].selector = *(uint16_t *)value; + cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_DS, *(uint16_t *)value); break; case UC_X86_REG_SS: - X86_CPU(uc, mycpu)->env.segs[R_SS].selector = *(uint16_t *)value; + cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_SS, *(uint16_t *)value); break; case UC_X86_REG_ES: - X86_CPU(uc, mycpu)->env.segs[R_ES].selector = *(uint16_t *)value; + cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_ES, *(uint16_t *)value); break; case UC_X86_REG_FS: - X86_CPU(uc, mycpu)->env.segs[R_FS].selector = *(uint16_t *)value; + cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_FS, *(uint16_t *)value); break; case UC_X86_REG_GS: - X86_CPU(uc, mycpu)->env.segs[R_GS].selector = *(uint16_t *)value; + cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_GS, *(uint16_t *)value); break; case UC_X86_REG_IDTR: X86_CPU(uc, mycpu)->env.idt.limit = (uint16_t)((uc_x86_mmr *)value)->limit; diff --git a/samples/sample_x86_32_gdt_and_seg_regs.c b/samples/sample_x86_32_gdt_and_seg_regs.c new file mode 100755 index 00000000..6d40cbef --- /dev/null +++ b/samples/sample_x86_32_gdt_and_seg_regs.c @@ -0,0 +1,290 @@ +/* + +Sample code to setup a GDT, and use segments. + +Copyright(c) 2016 Chris Eagle + +This program is free software; you can redistribute it and/or +modify it under the terms of the GNU General Public License +version 2 as published by the Free Software Foundation. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program; if not, write to the Free Software +Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ + +#include +#include +#include +#include +#include +#include + +struct SegmentDescriptor { + union { + struct { +# if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned short limit0; + unsigned short base0; + unsigned char base1; + unsigned int type:4; + unsigned int system:1; /* S flag */ + unsigned int dpl:2; + unsigned int present:1; /* P flag */ + unsigned int limit1:4; + unsigned int avail:1; + unsigned int is_64_code:1; /* L flag */ + unsigned int db:1; /* DB flag */ + unsigned int granularity:1; /* G flag */ + unsigned char base2; +# else + unsigned char base2; + unsigned int granularity:1; /* G flag */ + unsigned int db:1; /* DB flag */ + unsigned int is_64_code:1; /* L flag */ + unsigned int avail:1; + unsigned int limit1:4; + unsigned int present:1; /* P flag */ + unsigned int dpl:2; + unsigned int system:1; /* S flag */ + unsigned int type:4; + unsigned char base1; + unsigned short base0; + unsigned short limit0; +# endif + }; + uint64_t desc; + }; +}; + +#define SEGBASE(d) ((uint32_t)((((d).desc >> 16) & 0xffffff) | (((d).desc >> 32) & 0xff000000))) +#define SEGLIMIT(d) ((d).limit0 | (((unsigned int)(d).limit1) << 16)) + +/** + * Assert that err matches expect + */ +#define uc_assert_err(expect, err) \ +do { \ + uc_err __err = err; \ + if (__err != expect) { \ + fprintf(stderr, "%s", uc_strerror(__err)); \ + exit(1); \ + } \ +} while (0) + +/** + * Assert that err is UC_ERR_OK + */ +#define uc_assert_success(err) uc_assert_err(UC_ERR_OK, err) + +/** + * Assert that err is anything but UC_ERR_OK + * + * Note: Better to use uc_assert_err(, err), + * as this serves to document which errors a function will return + * in various scenarios. + */ +#define uc_assert_fail(err) \ +do { \ + uc_err __err = err; \ + if (__err == UC_ERR_OK) { \ + fprintf(stderr, "%s", uc_strerror(__err)); \ + exit(1); \ + } \ +} while (0) + +#define OK(x) uc_assert_success(x) + +/******************************************************************************/ + +void hook_mem(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) { + switch(type) { + case UC_MEM_WRITE: + printf("mem write at 0x%"PRIx64 ", size = %u, value = 0x%"PRIx64 "\n", address, size, value); + break; + default: break; + } +} + +void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { + printf("Executing at 0x%"PRIx64 ", ilen = 0x%x\n", address, size); +} + +//VERY basic descriptor init function, sets many fields to user space sane defaults +void init_descriptor(struct SegmentDescriptor *desc, uint32_t base, uint32_t limit, uint8_t is_code) { + desc->desc = 0; //clear the descriptor + desc->base0 = base & 0xffff; + desc->base1 = (base >> 16) & 0xff; + desc->base2 = base >> 24; + if (limit > 0xfffff) { + //need Giant granularity + limit >>= 12; + desc->granularity = 1; + } + desc->limit0 = limit & 0xffff; + desc->limit1 = limit >> 16; + + //some sane defaults + desc->dpl = 3; + desc->present = 1; + desc->db = 1; //32 bit + desc->type = is_code ? 0xb : 3; + desc->system = 1; //code or data +} + +void hex_dump(unsigned char *ptr, unsigned int len) { + int i; + for (i = 0; i < len; i++) { + if (i != 0 && (i & 0xf) == 0) { + fprintf(stderr, "\n"); + } + fprintf(stderr, "%02hhx", ptr[i]); + } + fprintf(stderr, "\n"); +} + +static void gdt_demo() { + uc_engine *uc; + uc_hook hook1, hook2; + uc_err err; + uint8_t buf[128]; + uc_x86_mmr idtr; + uc_x86_mmr gdtr; + uc_x86_mmr ldtr; + uc_x86_mmr tr; + +/* +bits 32 + +push dword 0x01234567 +push dword 0x89abcdef + +mov dword [fs:0], 0x01234567 +mov dword [fs:4], 0x89abcdef +*/ + + const uint8_t code[] = "\x68\x67\x45\x23\x01\x68\xef\xcd\xab\x89\x64\xc7\x05\x00\x00\x00\x00\x67\x45\x23\x01\x64\xc7\x05\x04\x00\x00\x00\xef\xcd\xab\x89"; + const uint64_t code_address = 0x1000000; + const uint64_t stack_address = 0x120000; + const uint64_t gdt_address = 0xc0000000; + const uint64_t fs_address = 0x7efdd000; + + struct SegmentDescriptor *gdt = (struct SegmentDescriptor*)calloc(31, sizeof(struct SegmentDescriptor)); + + int r_esp = stack_address + 0x1000; // initial esp + int r_cs = 0x73; + int r_ss = 0x88; //ring 0 + int r_ds = 0x7b; + int r_es = 0x7b; + int r_fs = 0x83; + + gdtr.base = gdt_address; + gdtr.limit = 31 * sizeof(struct SegmentDescriptor) - 1; + + init_descriptor(&gdt[14], 0, 0xfffff000, 1); //code segment + init_descriptor(&gdt[15], 0, 0xfffff000, 0); //data segment + init_descriptor(&gdt[16], 0x7efdd000, 0xfff, 0); //one page data segment simulate fs + init_descriptor(&gdt[17], 0, 0xfffff000, 0); //ring 0 data + gdt[17].dpl = 0; //set descriptor privilege level + +/* + fprintf(stderr, "GDT: \n"); + hex_dump((unsigned char*)gdt, 31 * sizeof(struct SegmentDescriptor)); +*/ + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + uc_assert_success(err); + + uc_hook_add(uc, &hook1, UC_HOOK_CODE, hook_code, NULL, code_address, code_address + sizeof(code) - 1); + + err = uc_hook_add(uc, &hook2, UC_HOOK_MEM_WRITE, hook_mem, NULL, (uint64_t)1, (uint64_t)0); + uc_assert_success(err); + + // map 1 page of code for this emulation + err = uc_mem_map(uc, code_address, 0x1000, UC_PROT_ALL); + uc_assert_success(err); + + // map 1 page of stack for this emulation + err = uc_mem_map(uc, stack_address, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_assert_success(err); + + // map 64k for a GDT + err = uc_mem_map(uc, gdt_address, 0x10000, UC_PROT_WRITE | UC_PROT_READ); + uc_assert_success(err); + + //set up a GDT BEFORE you manipulate any segment registers + err = uc_reg_write(uc, UC_X86_REG_GDTR, &gdtr); + uc_assert_success(err); + + // write gdt to be emulated to memory + err = uc_mem_write(uc, gdt_address, gdt, 31 * sizeof(struct SegmentDescriptor)); + uc_assert_success(err); + + // map 1 page for FS + err = uc_mem_map(uc, fs_address, 0x1000, UC_PROT_WRITE | UC_PROT_READ); + uc_assert_success(err); + + // write machine code to be emulated to memory + err = uc_mem_write(uc, code_address, code, sizeof(code)-1); + uc_assert_success(err); + + // initialize machine registers + err = uc_reg_write(uc, UC_X86_REG_ESP, &r_esp); + uc_assert_success(err); + + // when setting SS, need rpl == cpl && dpl == cpl + // emulator starts with cpl == 0, so we need a dpl 0 descriptor and rpl 0 selector + err = uc_reg_write(uc, UC_X86_REG_SS, &r_ss); + uc_assert_success(err); + + err = uc_reg_write(uc, UC_X86_REG_CS, &r_cs); + uc_assert_success(err); + err = uc_reg_write(uc, UC_X86_REG_DS, &r_ds); + uc_assert_success(err); + err = uc_reg_write(uc, UC_X86_REG_ES, &r_es); + uc_assert_success(err); + err = uc_reg_write(uc, UC_X86_REG_FS, &r_fs); + uc_assert_success(err); + + // emulate machine code in infinite time + err = uc_emu_start(uc, code_address, code_address+sizeof(code)-1, 0, 0); + uc_assert_success(err); + + // read from memory + err = uc_mem_read(uc, r_esp - 8, buf, 8); + uc_assert_success(err); + + int i; + for (i = 0; i < 8; i++) { + fprintf(stderr, "%02hhx", buf[i]); + } + fprintf(stderr, "\n"); + + assert(memcmp(buf, "\xef\xcd\xab\x89\x67\x45\x23\x01", 8) == 0); + + // read from memory + err = uc_mem_read(uc, fs_address, buf, 8); + uc_assert_success(err); + + assert(memcmp(buf, "\x67\x45\x23\x01\xef\xcd\xab\x89", 8) == 0); + + uc_close(uc); + +} + +/******************************************************************************/ + +int main(int argc, char **argv) { + gdt_demo(); + + fprintf(stderr, "success\n"); + + return 0; +} From f0af8f828226285ce095bc9a736fffba50e54cb5 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Wed, 23 Mar 2016 22:31:23 -0700 Subject: [PATCH 071/149] execute cpus in same thread as uc_emu_start() note: I'm sure this makes some dead code --- qemu/cpus.c | 37 +++++-------------------------------- qemu/vl.c | 1 - uc.c | 7 +++---- 3 files changed, 8 insertions(+), 37 deletions(-) diff --git a/qemu/cpus.c b/qemu/cpus.c index 64c73b0b..05220405 100644 --- a/qemu/cpus.c +++ b/qemu/cpus.c @@ -38,17 +38,13 @@ static void cpu_handle_guest_debug(CPUState *cpu); static int tcg_cpu_exec(struct uc_struct *uc, CPUArchState *env); static bool tcg_exec_all(struct uc_struct* uc); static int qemu_tcg_init_vcpu(CPUState *cpu); -static void *qemu_tcg_cpu_thread_fn(void *arg); +static void *qemu_tcg_cpu_loop(struct uc_struct *uc); int vm_start(struct uc_struct* uc) { if (resume_all_vcpus(uc)) { return -1; } - - // kick off TCG thread - qemu_mutex_unlock_iothread(uc); - return 0; } @@ -99,7 +95,6 @@ int resume_all_vcpus(struct uc_struct *uc) if (qemu_init_vcpu(cpu)) return -1; } - qemu_mutex_lock_iothread(uc); } } @@ -107,6 +102,7 @@ int resume_all_vcpus(struct uc_struct *uc) CPU_FOREACH(cpu) { cpu_resume(cpu); } + qemu_tcg_cpu_loop(uc); return 0; } @@ -125,13 +121,11 @@ int qemu_init_vcpu(CPUState *cpu) } -static void *qemu_tcg_cpu_thread_fn(void *arg) +static void *qemu_tcg_cpu_loop(struct uc_struct *uc) { - CPUState *cpu = arg; - struct uc_struct *uc = cpu->uc; + CPUState *cpu; //qemu_tcg_init_cpu_signals(); - qemu_thread_get_self(uc, cpu->thread); qemu_mutex_lock(&uc->qemu_global_mutex); CPU_FOREACH(cpu) { @@ -140,23 +134,7 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) } qemu_cond_signal(&uc->qemu_cpu_cond); - /* wait for initial kick-off after machine start */ - while (QTAILQ_FIRST(&uc->cpus)->stopped) { - qemu_cond_wait(uc->tcg_halt_cond, &uc->qemu_global_mutex); - } - while (1) { -#if 0 - int count = 0; - if (count < 10) { - count++; - unsigned int eip = X86_CPU(mycpu)->env.eip; - printf(">>> current EIP = %x\n", eip); - printf(">>> ECX = %x\n", (unsigned int)X86_CPU(mycpu)->env.regs[R_ECX]); - printf(">>> EDX = %x\n", (unsigned int)X86_CPU(mycpu)->env.regs[R_EDX]); - } -#endif - if (tcg_exec_all(uc)) break; } @@ -191,15 +169,10 @@ static int qemu_tcg_init_vcpu(CPUState *cpu) uc->tcg_halt_cond = cpu->halt_cond; snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/TCG", cpu->cpu_index); - if (qemu_thread_create(uc, cpu->thread, thread_name, qemu_tcg_cpu_thread_fn, - cpu, QEMU_THREAD_JOINABLE)) - return -1; + qemu_thread_get_self(uc, cpu->thread); #ifdef _WIN32 cpu->hThread = qemu_thread_get_handle(cpu->thread); #endif - while (!cpu->created) { - qemu_cond_wait(&uc->qemu_cpu_cond, &uc->qemu_global_mutex); - } uc->tcg_cpu_thread = cpu->thread; } else { cpu->thread = uc->tcg_cpu_thread; diff --git a/qemu/vl.c b/qemu/vl.c index caf6686f..a9d2c829 100644 --- a/qemu/vl.c +++ b/qemu/vl.c @@ -123,7 +123,6 @@ int machine_initialize(struct uc_struct *uc) configure_accelerator(current_machine); qemu_init_cpu_loop(uc); - qemu_mutex_lock_iothread(uc); current_machine->cpu_model = NULL; diff --git a/uc.c b/uc.c index ce9f121d..549a9ee6 100644 --- a/uc.c +++ b/uc.c @@ -559,14 +559,13 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time uc->addr_end = until; + if (timeout) + enable_emu_timer(uc, timeout * 1000); // microseconds -> nanoseconds + if (uc->vm_start(uc)) { return UC_ERR_RESOURCE; } - if (timeout) - enable_emu_timer(uc, timeout * 1000); // microseconds -> nanoseconds - - uc->pause_all_vcpus(uc); // emulation is done uc->emulation_done = true; From 2825cfd07a7dac3ec2325ad7ce2d853c396cbae6 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 24 Mar 2016 08:56:13 -0700 Subject: [PATCH 072/149] add sample to Makefile --- samples/Makefile | 3 ++- samples/sample_x86_32_gdt_and_seg_regs.c | 0 2 files changed, 2 insertions(+), 1 deletion(-) mode change 100644 => 100755 samples/Makefile mode change 100755 => 100644 samples/sample_x86_32_gdt_and_seg_regs.c diff --git a/samples/Makefile b/samples/Makefile old mode 100644 new mode 100755 index 02a1f66d..e63ce4fb --- a/samples/Makefile +++ b/samples/Makefile @@ -100,6 +100,7 @@ ifneq (,$(findstring x86,$(UNICORN_ARCHS))) SOURCES += sample_x86.c SOURCES += shellcode.c SOURCES += mem_apis.c +SOURCES += sample_x86_32_gdt_and_seg_regs.c endif ifneq (,$(findstring m68k,$(UNICORN_ARCHS))) SOURCES += sample_m68k.c @@ -114,7 +115,7 @@ all: $(BINARY) clean: rm -rf *.o $(OBJS_ELF) $(BINARY) $(SAMPLEDIR)/*.exe $(SAMPLEDIR)/*.static $(OBJDIR)/lib$(LIBNAME)* $(OBJDIR)/$(LIBNAME)* rm -rf libunicorn*.so libunicorn*.lib libunicorn*.dylib unicorn*.dll unicorn*.lib - rm -rf sample_x86 sample_arm sample_arm64 sample_mips sample_sparc sample_ppc sample_m68k shellcode mem_apis + rm -rf sample_x86 sample_arm sample_arm64 sample_mips sample_sparc sample_ppc sample_m68k shellcode mem_apis sample_x86_32_gdt_and_seg_regs $(BINARY): $(OBJS) diff --git a/samples/sample_x86_32_gdt_and_seg_regs.c b/samples/sample_x86_32_gdt_and_seg_regs.c old mode 100755 new mode 100644 From 79ec6145dbd9968e4b15b3d9d6bf3165fca8b826 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Thu, 24 Mar 2016 08:56:44 -0700 Subject: [PATCH 073/149] expose version from Go bindings --- bindings/go/unicorn/unicorn.go | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index be8a7348..fcebddda 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -62,9 +62,14 @@ type UcOptions struct { Timeout, Count uint64 } -func NewUnicorn(arch, mode int) (Unicorn, error) { +func Version() (int, int) { var major, minor C.uint C.uc_version(&major, &minor) + return int(major), int(minor) +} + +func NewUnicorn(arch, mode int) (Unicorn, error) { + major, minor := Version() if major != C.UC_API_MAJOR || minor != C.UC_API_MINOR { return nil, UcError(ERR_VERSION) } From dc7ec51c6d4ef3445a4471aa8d03b8139dda2b3f Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Thu, 24 Mar 2016 08:57:00 -0700 Subject: [PATCH 074/149] file permissions --- samples/Makefile | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100755 => 100644 samples/Makefile diff --git a/samples/Makefile b/samples/Makefile old mode 100755 new mode 100644 From 08bd4b3f616e172d11d2d36b34e9e3f9f906f44e Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Fri, 25 Mar 2016 11:11:32 +0800 Subject: [PATCH 075/149] regress chmod +x x86_gdt.py tcg_liveness_analysis_bug_issue-287.py --- tests/regress/tcg_liveness_analysis_bug_issue-287.py | 0 tests/regress/x86_gdt.py | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tests/regress/tcg_liveness_analysis_bug_issue-287.py mode change 100644 => 100755 tests/regress/x86_gdt.py diff --git a/tests/regress/tcg_liveness_analysis_bug_issue-287.py b/tests/regress/tcg_liveness_analysis_bug_issue-287.py old mode 100644 new mode 100755 diff --git a/tests/regress/x86_gdt.py b/tests/regress/x86_gdt.py old mode 100644 new mode 100755 From b63866e30aaa1c4d7176291a6be2c9f653f62d77 Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Fri, 25 Mar 2016 02:27:56 -0700 Subject: [PATCH 076/149] update java bindings to reflect changes in uc_hook_add --- bindings/java/samples/Sample_x86_mmr.java | 2 +- bindings/java/unicorn_Unicorn.c | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/bindings/java/samples/Sample_x86_mmr.java b/bindings/java/samples/Sample_x86_mmr.java index 87bd8a0a..e2b1a6dd 100644 --- a/bindings/java/samples/Sample_x86_mmr.java +++ b/bindings/java/samples/Sample_x86_mmr.java @@ -36,7 +36,7 @@ public class Sample_x86_mmr { } // map 4k - uc.mem_map(ADDRESS, 0x1000, Unicorn.UC_PROT_ALL); + uc.mem_map(0x400000, 0x1000, Unicorn.UC_PROT_ALL); X86_MMR ldtr1 = new X86_MMR(0x1111111122222222L, 0x33333333, 0x44444444, (short)0x5555); X86_MMR ldtr2; diff --git a/bindings/java/unicorn_Unicorn.c b/bindings/java/unicorn_Unicorn.c index 8b3bcfe2..a1e6fbc7 100644 --- a/bindings/java/unicorn_Unicorn.c +++ b/bindings/java/unicorn_Unicorn.c @@ -519,7 +519,7 @@ JNIEXPORT jlong JNICALL Java_unicorn_Unicorn_registerHook__JI if (invokeInterruptCallbacks == 0) { invokeInterruptCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeInterruptCallbacks", "(JI)V"); } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookintr, env); + err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookintr, env, 1, 0); break; case UC_HOOK_MEM_FETCH_UNMAPPED: // Hook for all invalid memory access events case UC_HOOK_MEM_READ_UNMAPPED: // Hook for all invalid memory access events @@ -530,7 +530,7 @@ JNIEXPORT jlong JNICALL Java_unicorn_Unicorn_registerHook__JI if (invokeEventMemCallbacks == 0) { invokeEventMemCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeEventMemCallbacks", "(JIJIJ)Z"); } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_eventmem, env); + err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_eventmem, env, 1, 0); break; } return (jlong)hh; @@ -552,18 +552,18 @@ JNIEXPORT jlong JNICALL Java_unicorn_Unicorn_registerHook__JII if (invokeOutCallbacks == 0) { invokeOutCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeOutCallbacks", "(JIII)V"); } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_insn_out, env, arg1); + err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_insn_out, env, 1, 0, arg1); case UC_X86_INS_IN: if (invokeInCallbacks == 0) { invokeInCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeInCallbacks", "(JII)I"); } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_insn_in, env, arg1); + err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_insn_in, env, 1, 0, arg1); case UC_X86_INS_SYSENTER: case UC_X86_INS_SYSCALL: if (invokeSyscallCallbacks == 0) { invokeSyscallCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeSyscallCallbacks", "(J)V"); } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_insn_syscall, env, arg1); + err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_insn_syscall, env, 1, 0, arg1); } break; } @@ -584,25 +584,25 @@ JNIEXPORT jlong JNICALL Java_unicorn_Unicorn_registerHook__JIJJ if (invokeCodeCallbacks == 0) { invokeCodeCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeCodeCallbacks", "(JJI)V"); } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookcode, env, arg1, arg2); + err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookcode, env, 1, 0, arg1, arg2); break; case UC_HOOK_BLOCK: // Hook basic blocks if (invokeBlockCallbacks == 0) { invokeBlockCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeBlockCallbacks", "(JJI)V"); } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookblock, env, arg1, arg2); + err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookblock, env, 1, 0, arg1, arg2); break; case UC_HOOK_MEM_READ: // Hook all memory read events. if (invokeReadCallbacks == 0) { invokeReadCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeReadCallbacks", "(JJI)V"); } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookmem, env, arg1, arg2); + err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookmem, env, 1, 0, arg1, arg2); break; case UC_HOOK_MEM_WRITE: // Hook all memory write events. if (invokeWriteCallbacks == 0) { invokeWriteCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeWriteCallbacks", "(JJIJ)V"); } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookmem, env, arg1, arg2); + err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookmem, env, 1, 0, arg1, arg2); break; } return (jlong)hh; From 3bb05fa8e9e9bd7272dfe9ddc0874da3e39014b1 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Fri, 25 Mar 2016 22:29:50 +0800 Subject: [PATCH 077/149] samples: clean executable binaries before building --- samples/Makefile | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/samples/Makefile b/samples/Makefile index 02a1f66d..ee376de4 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -75,7 +75,7 @@ ARCHIVE = $(LIBDIR)/lib$(LIBNAME).$(AR_EXT) endif endif -.PHONY: all clean +.PHONY: all clean clean_bins clean_libs UNICORN_ARCHS := $(shell if [ -e ../config.log ]; then cat ../config.log;\ else printf "$(UNICORN_ARCHS)"; fi) @@ -109,13 +109,17 @@ OBJS = $(addprefix $(OBJDIR)/,$(SOURCES:.c=.o)) OBJS_ELF = $(addprefix $(OBJDIR)/,$(SOURCES:.c=)) BINARY = $(addprefix $(SAMPLEDIR)/,$(SOURCES:.c=$(BIN_EXT))) -all: $(BINARY) +all: clean_bins $(BINARY) -clean: +clean_bins: rm -rf *.o $(OBJS_ELF) $(BINARY) $(SAMPLEDIR)/*.exe $(SAMPLEDIR)/*.static $(OBJDIR)/lib$(LIBNAME)* $(OBJDIR)/$(LIBNAME)* - rm -rf libunicorn*.so libunicorn*.lib libunicorn*.dylib unicorn*.dll unicorn*.lib rm -rf sample_x86 sample_arm sample_arm64 sample_mips sample_sparc sample_ppc sample_m68k shellcode mem_apis +clean_libs: + rm -rf libunicorn*.so libunicorn*.lib libunicorn*.dylib unicorn*.dll unicorn*.lib + +clean: clean_bins clean_libs + $(BINARY): $(OBJS) $(SAMPLEDIR)/%$(BIN_EXT): $(OBJDIR)/%.o From 90cefeb1676e1c35546b3cb78879c2adbd4d3388 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 26 Mar 2016 00:32:32 +0800 Subject: [PATCH 078/149] regress: adapt all C code to latest change in uc_hook_add() API --- tests/regress/block_test.c | 2 +- tests/regress/eflags_nosync.c | 4 ++-- tests/regress/emu_clear_errors.c | 2 +- tests/regress/emu_stop_in_hook_overrun.c | 2 +- tests/regress/hook_extrainvoke.c | 2 +- tests/regress/invalid_read_in_cpu_tb_exec.c | 2 +- tests/regress/mem_exec.c | 6 +++--- tests/regress/mem_protect.c | 6 +++--- tests/regress/mem_unmap.c | 6 +++--- tests/regress/mips_branch_likely_issue.c | 2 +- tests/regress/mips_delay_slot_code_hook.c | 2 +- tests/regress/mips_invalid_read_of_size_4_when_tracing.c | 2 +- tests/regress/nr_mem_test.c | 4 ++-- tests/regress/rep_movsb.c | 4 ++-- tests/regress/ro_mem_test.c | 4 ++-- tests/regress/threaded_emu_start.c | 2 +- tests/regress/timeout_segfault.c | 8 ++++---- 17 files changed, 30 insertions(+), 30 deletions(-) diff --git a/tests/regress/block_test.c b/tests/regress/block_test.c index 9a648f07..71d1021f 100644 --- a/tests/regress/block_test.c +++ b/tests/regress/block_test.c @@ -65,7 +65,7 @@ int main() { uc_hook h1, h2; - err = uc_hook_add(uc, &h1, UC_HOOK_BLOCK, cb_hookblock, NULL, (uint64_t)1, (uint64_t)0); + err = uc_hook_add(uc, &h1, UC_HOOK_BLOCK, cb_hookblock, NULL, 1, 0); if (err != UC_ERR_OK) { fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err)); exit(0); diff --git a/tests/regress/eflags_nosync.c b/tests/regress/eflags_nosync.c index 3e141414..f026ce01 100644 --- a/tests/regress/eflags_nosync.c +++ b/tests/regress/eflags_nosync.c @@ -120,10 +120,10 @@ static void VM_exec() uc_reg_write(uc, UC_X86_REG_EDI, &r_edi); uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags); - uc_hook_add(uc, &trace1, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, (void *)hook_invalid_mem, NULL); + uc_hook_add(uc, &trace1, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, (void *)hook_invalid_mem, NULL, 1, 0); // tracing all instruction by having @begin > @end - uc_hook_add(uc, &trace2, UC_HOOK_CODE, (void *)hook_ins, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, (void *)hook_ins, NULL, 1, 0); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + (sizeof(X86_CODE32) - 1), 0, 0); diff --git a/tests/regress/emu_clear_errors.c b/tests/regress/emu_clear_errors.c index 36c4e745..bed3965d 100644 --- a/tests/regress/emu_clear_errors.c +++ b/tests/regress/emu_clear_errors.c @@ -112,7 +112,7 @@ int main() { uc_hook h1; - err = uc_hook_add(uc, &h1, UC_HOOK_MEM_UNMAPPED, cb_hookunmapped, NULL); + err = uc_hook_add(uc, &h1, UC_HOOK_MEM_UNMAPPED, cb_hookunmapped, NULL, 1, 0); if (err != UC_ERR_OK) { fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err)); exit(0); diff --git a/tests/regress/emu_stop_in_hook_overrun.c b/tests/regress/emu_stop_in_hook_overrun.c index 6c18c74d..c9e24647 100644 --- a/tests/regress/emu_stop_in_hook_overrun.c +++ b/tests/regress/emu_stop_in_hook_overrun.c @@ -98,7 +98,7 @@ int main(int argc, char **argv, char **envp) // hook all instructions by having @begin > @end printf("uc_hook_add()\n"); - uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, 1, 0); if( err ) { printf("Failed on uc_hook_add(code) with error returned: %u\n", err); diff --git a/tests/regress/hook_extrainvoke.c b/tests/regress/hook_extrainvoke.c index 5f74e4d7..174257c9 100644 --- a/tests/regress/hook_extrainvoke.c +++ b/tests/regress/hook_extrainvoke.c @@ -58,7 +58,7 @@ static void VM_exec() uc_reg_write(uc, UC_X86_REG_ESP, &r_esp); //make stack pointer point to already mapped memory so we don't need to hook. uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags); - uc_hook_add(uc, &trace, UC_HOOK_CODE, (void *)hook_ins, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace, UC_HOOK_CODE, (void *)hook_ins, NULL, 1, 0); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + (sizeof(X86_CODE32) - 1), 0, 0); diff --git a/tests/regress/invalid_read_in_cpu_tb_exec.c b/tests/regress/invalid_read_in_cpu_tb_exec.c index f9fe162c..d618c31a 100644 --- a/tests/regress/invalid_read_in_cpu_tb_exec.c +++ b/tests/regress/invalid_read_in_cpu_tb_exec.c @@ -25,7 +25,7 @@ int main(int argc, char **argv, char **envp) { return 1; } uc_hook hook; - uc_hook_add(uc, &hook, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &hook, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); printf("uc_emu_start(…)\n"); uc_emu_start(uc, STARTING_ADDRESS, STARTING_ADDRESS + sizeof(BINARY) - 1, 0, 20); printf("done\n"); diff --git a/tests/regress/mem_exec.c b/tests/regress/mem_exec.c index db9a2bc1..8be1dab3 100644 --- a/tests/regress/mem_exec.c +++ b/tests/regress/mem_exec.c @@ -205,7 +205,7 @@ int main(int argc, char **argv, char **envp) printf("ok %d - Program written to memory\n", log_num++); } - if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_CODE ucr\n", log_num++); return 6; } else { @@ -213,7 +213,7 @@ int main(int argc, char **argv, char **envp) } // intercept memory write events - if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE ucr\n", log_num++); return 7; } else { @@ -221,7 +221,7 @@ int main(int argc, char **argv, char **envp) } // intercept invalid memory events - if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_PROT | UC_HOOK_MEM_FETCH_PROT, hook_mem_invalid, NULL) != UC_ERR_OK) { + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_PROT | UC_HOOK_MEM_FETCH_PROT, hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install memory invalid handler\n", log_num++); return 8; } else { diff --git a/tests/regress/mem_protect.c b/tests/regress/mem_protect.c index d29dc490..3f1ec820 100644 --- a/tests/regress/mem_protect.c +++ b/tests/regress/mem_protect.c @@ -213,7 +213,7 @@ int main(int argc, char **argv, char **envp) printf("ok %d - Program written to memory\n", log_num++); } - if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_CODE ucr\n", log_num++); return 5; } else { @@ -221,7 +221,7 @@ int main(int argc, char **argv, char **envp) } // intercept memory write events - if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE ucr\n", log_num++); return 6; } else { @@ -229,7 +229,7 @@ int main(int argc, char **argv, char **envp) } // intercept invalid memory events - if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_PROT, hook_mem_invalid, NULL) != UC_ERR_OK) { + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_PROT, hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install memory invalid handler\n", log_num++); return 7; } else { diff --git a/tests/regress/mem_unmap.c b/tests/regress/mem_unmap.c index 16a9f88a..17997870 100644 --- a/tests/regress/mem_unmap.c +++ b/tests/regress/mem_unmap.c @@ -208,7 +208,7 @@ int main(int argc, char **argv, char **envp) printf("ok %d - Program written to memory\n", log_num++); } - if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_CODE ucr\n", log_num++); return 5; } else { @@ -216,7 +216,7 @@ int main(int argc, char **argv, char **envp) } // intercept memory write events - if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE ucr\n", log_num++); return 6; } else { @@ -224,7 +224,7 @@ int main(int argc, char **argv, char **envp) } // intercept invalid memory events - if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_invalid, NULL) != UC_ERR_OK) { + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install memory invalid handler\n", log_num++); return 7; } else { diff --git a/tests/regress/mips_branch_likely_issue.c b/tests/regress/mips_branch_likely_issue.c index 84f49cdc..b02cf864 100644 --- a/tests/regress/mips_branch_likely_issue.c +++ b/tests/regress/mips_branch_likely_issue.c @@ -107,7 +107,7 @@ int main(int argc, char **argv, char **envp) // hook all instructions by having @begin > @end printf("uc_hook_add()\n"); - uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, 1, 0); if( err ) { printf("Failed on uc_hook_add(code) with error returned: %u\n", err); diff --git a/tests/regress/mips_delay_slot_code_hook.c b/tests/regress/mips_delay_slot_code_hook.c index 905cad8d..663ae979 100644 --- a/tests/regress/mips_delay_slot_code_hook.c +++ b/tests/regress/mips_delay_slot_code_hook.c @@ -100,7 +100,7 @@ int main(int argc, char **argv, char **envp) } // hook all instructions by having @begin > @end - uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, 1, 0); if( err ) { printf("Failed on uc_hook_add(code) with error returned: %u\n", err); diff --git a/tests/regress/mips_invalid_read_of_size_4_when_tracing.c b/tests/regress/mips_invalid_read_of_size_4_when_tracing.c index d912a604..013016e4 100644 --- a/tests/regress/mips_invalid_read_of_size_4_when_tracing.c +++ b/tests/regress/mips_invalid_read_of_size_4_when_tracing.c @@ -25,7 +25,7 @@ int main(int argc, char **argv, char **envp) { return 1; } uc_hook trace; - uc_hook_add(uc, &trace, UC_HOOK_CODE, hook_code, NULL, (uint64_t)MEMORY_STARTING_ADDRESS, (uint64_t)(MEMORY_STARTING_ADDRESS + 1)); + uc_hook_add(uc, &trace, UC_HOOK_CODE, hook_code, NULL, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + 1); printf("uc_emu_start(…)\n"); uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 0); printf("done\n"); diff --git a/tests/regress/nr_mem_test.c b/tests/regress/nr_mem_test.c index 60e97db7..b6ab8d8e 100644 --- a/tests/regress/nr_mem_test.c +++ b/tests/regress/nr_mem_test.c @@ -83,10 +83,10 @@ int main(int argc, char **argv, char **envp) uc_mem_write(uc, 0x300000, (const uint8_t*)"\x41\x41\x41\x41", 4); uc_mem_write(uc, 0x400000, (const uint8_t*)"\x42\x42\x42\x42", 4); - //uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff); + //uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 0x400000, 0x400fff); // intercept invalid memory events - uc_hook_add(uc, &trace1, UC_MEM_READ_PROT, hook_mem_invalid, NULL); + uc_hook_add(uc, &trace1, UC_MEM_READ_PROT, hook_mem_invalid, NULL, 1, 0); // emulate machine code in infinite time printf("BEGIN execution\n"); diff --git a/tests/regress/rep_movsb.c b/tests/regress/rep_movsb.c index 17b22641..86594978 100644 --- a/tests/regress/rep_movsb.c +++ b/tests/regress/rep_movsb.c @@ -129,7 +129,7 @@ int main(int argc, char **argv, char **envp) printf("ok %d - Program written to memory\n", log_num++); } - if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); return 5; } @@ -138,7 +138,7 @@ int main(int argc, char **argv, char **envp) } // intercept memory write events only, NOT read events - if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); return 6; } diff --git a/tests/regress/ro_mem_test.c b/tests/regress/ro_mem_test.c index 7b430497..845859b1 100644 --- a/tests/regress/ro_mem_test.c +++ b/tests/regress/ro_mem_test.c @@ -139,10 +139,10 @@ int main(int argc, char **argv, char **envp) printf("Allowed to write to read only memory via uc_mem_write\n"); } - //uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff); + //uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 0x400000, 0x400fff); // intercept invalid memory events - uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_WRITE_PROT, hook_mem_invalid, NULL); + uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_WRITE_PROT, hook_mem_invalid, NULL, 1, 0); // emulate machine code in infinite time printf("BEGIN execution - 1\n"); diff --git a/tests/regress/threaded_emu_start.c b/tests/regress/threaded_emu_start.c index 9a5a2fa9..de6907e3 100644 --- a/tests/regress/threaded_emu_start.c +++ b/tests/regress/threaded_emu_start.c @@ -164,7 +164,7 @@ int main(int argc, char **argv, char **envp) // hook all instructions by having @begin > @end printf("uc_hook_add()\n"); - uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, 1, 0); if( err ) { printf("Failed on uc_hook_add(code) with error returned: %u\n", err); diff --git a/tests/regress/timeout_segfault.c b/tests/regress/timeout_segfault.c index 49d9a370..54b04db0 100644 --- a/tests/regress/timeout_segfault.c +++ b/tests/regress/timeout_segfault.c @@ -67,10 +67,10 @@ static void test_arm(void) uc_reg_write(uc, UC_ARM_REG_R3, &r3); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. @@ -118,10 +118,10 @@ static void test_thumb(void) uc_reg_write(uc, UC_ARM_REG_SP, &sp); // tracing all basic blocks with customized callback - uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); // tracing one instruction at ADDRESS with customized callback - uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS); // emulate machine code in infinite time (last param = 0), or when // finishing all the code. From 9467254fc0cffe2e8070d0ec57eed7096bd1791e Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Fri, 25 Mar 2016 17:24:28 -0700 Subject: [PATCH 079/149] strip out per cpu thread code --- include/uc_priv.h | 3 +- qemu/Makefile.objs | 2 +- qemu/aarch64.h | 5 -- qemu/arm.h | 5 -- qemu/cpus.c | 48 ++---------- qemu/exec.c | 5 +- qemu/header_gen.py | 5 -- qemu/hw/intc/apic.c | 1 - qemu/include/qemu/main-loop.h | 77 ------------------ qemu/include/qemu/osdep.h | 1 - qemu/include/qemu/thread.h | 2 - qemu/include/qom/cpu.h | 10 --- qemu/include/sysemu/cpus.h | 1 - qemu/include/sysemu/iothread.h | 40 ---------- qemu/include/sysemu/sysemu.h | 2 - qemu/m68k.h | 5 -- qemu/main-loop.c | 139 --------------------------------- qemu/mips.h | 5 -- qemu/mips64.h | 5 -- qemu/mips64el.h | 5 -- qemu/mipsel.h | 5 -- qemu/powerpc.h | 2 - qemu/sparc.h | 5 -- qemu/sparc64.h | 5 -- qemu/translate-all.c | 9 --- qemu/unicorn_common.h | 1 - qemu/util/oslib-posix.c | 9 --- qemu/util/oslib-win32.c | 6 -- qemu/util/qemu-thread-posix.c | 10 --- qemu/util/qemu-thread-win32.c | 11 --- qemu/x86_64.h | 5 -- 31 files changed, 8 insertions(+), 426 deletions(-) delete mode 100644 qemu/include/qemu/main-loop.h delete mode 100644 qemu/include/sysemu/iothread.h delete mode 100644 qemu/main-loop.c diff --git a/include/uc_priv.h b/include/uc_priv.h index e36a8c84..b3401525 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -147,7 +147,6 @@ struct uc_struct { uc_mode mode; QemuMutex qemu_global_mutex; // qemu/cpus.c QemuCond qemu_cpu_cond; // qemu/cpus.c - QemuThread *tcg_cpu_thread; // qemu/cpus.c QemuCond *tcg_halt_cond; // qemu/cpus.c struct CPUTailQ cpus; // qemu/cpu-exec.c uc_err errnum; // qemu/cpu-exec.c @@ -163,7 +162,7 @@ struct uc_struct { uc_args_uc_u64_t set_pc; // set PC for tracecode uc_args_int_t stop_interrupt; // check if the interrupt should stop emulation - uc_args_uc_t init_arch, pause_all_vcpus, cpu_exec_init_all; + uc_args_uc_t init_arch, cpu_exec_init_all; uc_args_int_uc_t vm_start; uc_args_tcg_enable_t tcg_enabled; uc_args_uc_long_t tcg_exec_init; diff --git a/qemu/Makefile.objs b/qemu/Makefile.objs index d309d2a4..e3bc755c 100644 --- a/qemu/Makefile.objs +++ b/qemu/Makefile.objs @@ -19,7 +19,7 @@ ifeq ($(CONFIG_SOFTMMU),y) common-obj-y += hw/ common-obj-y += accel.o -common-obj-y += vl.o main-loop.o qemu-timer.o +common-obj-y += vl.o qemu-timer.o endif diff --git a/qemu/aarch64.h b/qemu/aarch64.h index d75c06e1..dd02222b 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_aarch64 #define par_write par_write_aarch64 #define patch_reloc patch_reloc_aarch64 -#define pause_all_vcpus pause_all_vcpus_aarch64 #define phys_map_node_alloc phys_map_node_alloc_aarch64 #define phys_map_node_reserve phys_map_node_reserve_aarch64 #define phys_mem_alloc phys_mem_alloc_aarch64 @@ -2418,8 +2417,6 @@ #define qemu_clock_ptr qemu_clock_ptr_aarch64 #define qemu_clocks qemu_clocks_aarch64 #define qemu_cond_destroy qemu_cond_destroy_aarch64 -#define qemu_cpu_is_self qemu_cpu_is_self_aarch64 -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_aarch64 #define qemu_daemon qemu_daemon_aarch64 #define qemu_event_destroy qemu_event_destroy_aarch64 #define qemu_event_init qemu_event_init_aarch64 @@ -2516,9 +2513,7 @@ #define qemu_st_helpers qemu_st_helpers_aarch64 #define qemu_strnlen qemu_strnlen_aarch64 #define qemu_strsep qemu_strsep_aarch64 -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_aarch64 #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_aarch64 -#define qemu_thread_exit qemu_thread_exit_aarch64 #define qemu_try_memalign qemu_try_memalign_aarch64 #define qentry_destroy qentry_destroy_aarch64 #define qerror_human qerror_human_aarch64 diff --git a/qemu/arm.h b/qemu/arm.h index ef850c24..d4fcf42c 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_arm #define par_write par_write_arm #define patch_reloc patch_reloc_arm -#define pause_all_vcpus pause_all_vcpus_arm #define phys_map_node_alloc phys_map_node_alloc_arm #define phys_map_node_reserve phys_map_node_reserve_arm #define phys_mem_alloc phys_mem_alloc_arm @@ -2418,8 +2417,6 @@ #define qemu_clock_ptr qemu_clock_ptr_arm #define qemu_clocks qemu_clocks_arm #define qemu_cond_destroy qemu_cond_destroy_arm -#define qemu_cpu_is_self qemu_cpu_is_self_arm -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_arm #define qemu_daemon qemu_daemon_arm #define qemu_event_destroy qemu_event_destroy_arm #define qemu_event_init qemu_event_init_arm @@ -2516,9 +2513,7 @@ #define qemu_st_helpers qemu_st_helpers_arm #define qemu_strnlen qemu_strnlen_arm #define qemu_strsep qemu_strsep_arm -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_arm #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_arm -#define qemu_thread_exit qemu_thread_exit_arm #define qemu_try_memalign qemu_try_memalign_arm #define qentry_destroy qentry_destroy_arm #define qerror_human qerror_human_arm diff --git a/qemu/cpus.c b/qemu/cpus.c index 05220405..6961ed2f 100644 --- a/qemu/cpus.c +++ b/qemu/cpus.c @@ -55,28 +55,10 @@ bool cpu_is_stopped(CPUState *cpu) void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data) { - if (qemu_cpu_is_self(cpu)) { - func(data); - return; - } + func(data); + return; } -// send halt_cond/tcg_halt_cond to @cpu -bool qemu_cpu_is_self(CPUState *cpu) -{ - return qemu_thread_is_self(cpu->thread); -} - -void pause_all_vcpus(struct uc_struct *uc) -{ - CPUState *cpu; - - CPU_FOREACH(cpu) { - qemu_thread_join(cpu->thread); // qq: fix qemu_thread_join() to work for instance - } -} - - int resume_all_vcpus(struct uc_struct *uc) { CPUState *cpu; @@ -112,7 +94,6 @@ int qemu_init_vcpu(CPUState *cpu) cpu->nr_cores = smp_cores; cpu->nr_threads = smp_threads; cpu->stopped = true; - cpu->uc->tcg_cpu_thread = NULL; if (tcg_enabled(cpu->uc)) return qemu_tcg_init_vcpu(cpu); @@ -129,7 +110,6 @@ static void *qemu_tcg_cpu_loop(struct uc_struct *uc) qemu_mutex_lock(&uc->qemu_global_mutex); CPU_FOREACH(cpu) { - cpu->thread_id = qemu_get_thread_id(); cpu->created = true; } qemu_cond_signal(&uc->qemu_cpu_cond); @@ -140,7 +120,6 @@ static void *qemu_tcg_cpu_loop(struct uc_struct *uc) } CPU_FOREACH(cpu) { - cpu->thread_id = 0; cpu->created = false; } @@ -151,33 +130,16 @@ static void *qemu_tcg_cpu_loop(struct uc_struct *uc) -/* For temporary buffers for forming a name */ -#define VCPU_THREAD_NAME_SIZE 16 - static int qemu_tcg_init_vcpu(CPUState *cpu) { struct uc_struct *uc = cpu->uc; - char thread_name[VCPU_THREAD_NAME_SIZE]; tcg_cpu_address_space_init(cpu, cpu->as); /* share a single thread for all cpus with TCG */ - if (!uc->tcg_cpu_thread) { - cpu->thread = g_malloc0(sizeof(QemuThread)); - cpu->halt_cond = g_malloc0(sizeof(QemuCond)); - qemu_cond_init(cpu->halt_cond); - uc->tcg_halt_cond = cpu->halt_cond; - snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/TCG", - cpu->cpu_index); - qemu_thread_get_self(uc, cpu->thread); -#ifdef _WIN32 - cpu->hThread = qemu_thread_get_handle(cpu->thread); -#endif - uc->tcg_cpu_thread = cpu->thread; - } else { - cpu->thread = uc->tcg_cpu_thread; - cpu->halt_cond = uc->tcg_halt_cond; - } + cpu->halt_cond = g_malloc0(sizeof(QemuCond)); + qemu_cond_init(cpu->halt_cond); + uc->tcg_halt_cond = cpu->halt_cond; return 0; } diff --git a/qemu/exec.c b/qemu/exec.c index fcb2b7f4..15c4809f 100644 --- a/qemu/exec.c +++ b/qemu/exec.c @@ -432,10 +432,7 @@ void cpu_exec_init(CPUArchState *env, void *opaque) QTAILQ_INIT(&cpu->watchpoints); cpu->as = &uc->as; -#ifndef CONFIG_USER_ONLY - //cpu->as = &address_space_memory; - cpu->thread_id = qemu_get_thread_id(); -#endif + QTAILQ_INSERT_TAIL(&uc->cpus, cpu, node); //QTAILQ_INSERT_TAIL(&uc->cpus, cpu, node); #if defined(CONFIG_USER_ONLY) diff --git a/qemu/header_gen.py b/qemu/header_gen.py index 46bab7c9..5fcd7f01 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -2264,7 +2264,6 @@ symbols = ( 'parse_value', 'par_write', 'patch_reloc', - 'pause_all_vcpus', 'phys_map_node_alloc', 'phys_map_node_reserve', 'phys_mem_alloc', @@ -2424,8 +2423,6 @@ symbols = ( 'qemu_clock_ptr', 'qemu_clocks', 'qemu_cond_destroy', - 'qemu_cpu_is_self', - 'qemu_cpu_kick_thread', 'qemu_daemon', 'qemu_event_destroy', 'qemu_event_init', @@ -2522,9 +2519,7 @@ symbols = ( 'qemu_st_helpers', 'qemu_strnlen', 'qemu_strsep', - 'qemu_tcg_cpu_thread_fn', 'qemu_tcg_init_vcpu', - 'qemu_thread_exit', 'qemu_try_memalign', 'qentry_destroy', 'qerror_human', diff --git a/qemu/hw/intc/apic.c b/qemu/hw/intc/apic.c index e58d742b..1f89770e 100644 --- a/qemu/hw/intc/apic.c +++ b/qemu/hw/intc/apic.c @@ -70,7 +70,6 @@ static void apic_sync_vapic(APICCommonState *s, int sync_type) //length = offsetof(VAPICState, enabled) - offsetof(VAPICState, isr); if (sync_type & SYNC_TO_VAPIC) { - assert(qemu_cpu_is_self(CPU(s->cpu))); vapic_state.tpr = s->tpr; vapic_state.enabled = 1; diff --git a/qemu/include/qemu/main-loop.h b/qemu/include/qemu/main-loop.h deleted file mode 100644 index 2f196e1b..00000000 --- a/qemu/include/qemu/main-loop.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef QEMU_MAIN_LOOP_H -#define QEMU_MAIN_LOOP_H 1 - -#define SIG_IPI SIGUSR1 - -struct uc_struct; - -/** - * qemu_init_main_loop: Set up the process so that it can run the main loop. - * - * This includes setting up signal handlers. It should be called before - * any other threads are created. In addition, threads other than the - * main one should block signals that are trapped by the main loop. - * For simplicity, you can consider these signals to be safe: SIGUSR1, - * SIGUSR2, thread signals (SIGFPE, SIGILL, SIGSEGV, SIGBUS) and real-time - * signals if available. Remember that Windows in practice does not have - * signals, though. - * - * In the case of QEMU tools, this will also start/initialize timers. - */ -int qemu_init_main_loop(void); - -/** - * qemu_mutex_lock_iothread: Lock the main loop mutex. - * - * This function locks the main loop mutex. The mutex is taken by - * qemu_init_main_loop and always taken except while waiting on - * external events (such as with select). The mutex should be taken - * by threads other than the main loop thread when calling - * qemu_bh_new(), qemu_set_fd_handler() and basically all other - * functions documented in this file. - * - * NOTE: tools currently are single-threaded and qemu_mutex_lock_iothread - * is a no-op there. - */ -void qemu_mutex_lock_iothread(struct uc_struct* uc); - -/** - * qemu_mutex_unlock_iothread: Unlock the main loop mutex. - * - * This function unlocks the main loop mutex. The mutex is taken by - * qemu_init_main_loop and always taken except while waiting on - * external events (such as with select). The mutex should be unlocked - * as soon as possible by threads other than the main loop thread, - * because it prevents the main loop from processing callbacks, - * including timers and bottom halves. - * - * NOTE: tools currently are single-threaded and qemu_mutex_unlock_iothread - * is a no-op there. - */ -void qemu_mutex_unlock_iothread(struct uc_struct* uc); - -#endif diff --git a/qemu/include/qemu/osdep.h b/qemu/include/qemu/osdep.h index 256bb011..9e4c7403 100644 --- a/qemu/include/qemu/osdep.h +++ b/qemu/include/qemu/osdep.h @@ -183,7 +183,6 @@ int qemu_close(int fd); #endif int qemu_create_pidfile(const char *filename); -int qemu_get_thread_id(void); #ifdef _WIN32 static inline void qemu_timersub(const struct timeval *val1, diff --git a/qemu/include/qemu/thread.h b/qemu/include/qemu/thread.h index 2a402673..67e893e1 100644 --- a/qemu/include/qemu/thread.h +++ b/qemu/include/qemu/thread.h @@ -58,8 +58,6 @@ int qemu_thread_create(struct uc_struct *uc, QemuThread *thread, const char *nam void *(*start_routine)(void *), void *arg, int mode); void *qemu_thread_join(QemuThread *thread); -void qemu_thread_get_self(struct uc_struct *uc, QemuThread *thread); -bool qemu_thread_is_self(QemuThread *thread); void qemu_thread_exit(struct uc_struct *uc, void *retval); #endif diff --git a/qemu/include/qom/cpu.h b/qemu/include/qom/cpu.h index fb666d1e..08cb6ba7 100644 --- a/qemu/include/qom/cpu.h +++ b/qemu/include/qom/cpu.h @@ -436,16 +436,6 @@ static inline bool cpu_has_work(CPUState *cpu) return cc->has_work(cpu); } -/** - * qemu_cpu_is_self: - * @cpu: The vCPU to check against. - * - * Checks whether the caller is executing on the vCPU thread. - * - * Returns: %true if called from @cpu's thread, %false otherwise. - */ -bool qemu_cpu_is_self(CPUState *cpu); - /** * qemu_cpu_kick: * @cpu: The vCPU to kick. diff --git a/qemu/include/sysemu/cpus.h b/qemu/include/sysemu/cpus.h index f22ad69d..72e1deec 100644 --- a/qemu/include/sysemu/cpus.h +++ b/qemu/include/sysemu/cpus.h @@ -6,7 +6,6 @@ struct uc_struct; /* cpus.c */ void qemu_init_cpu_loop(struct uc_struct*); int resume_all_vcpus(struct uc_struct*); -void pause_all_vcpus(struct uc_struct*); void cpu_stop_current(struct uc_struct*); void cpu_synchronize_all_states(void); diff --git a/qemu/include/sysemu/iothread.h b/qemu/include/sysemu/iothread.h deleted file mode 100644 index 7c01a61d..00000000 --- a/qemu/include/sysemu/iothread.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Event loop thread - * - * Copyright Red Hat Inc., 2013 - * - * Authors: - * Stefan Hajnoczi - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - */ - -#ifndef IOTHREAD_H -#define IOTHREAD_H - -#include "block/aio.h" -#include "qemu/thread.h" - -#define TYPE_IOTHREAD "iothread" - -typedef struct { - Object parent_obj; - - QemuThread thread; - AioContext *ctx; - QemuMutex init_done_lock; - QemuCond init_done_cond; /* is thread initialization done? */ - bool stopping; - int thread_id; -} IOThread; - -#define IOTHREAD(obj) \ - OBJECT_CHECK(IOThread, obj, TYPE_IOTHREAD) - -IOThread *iothread_find(const char *id); -char *iothread_get_id(IOThread *iothread); -AioContext *iothread_get_aio_context(IOThread *iothread); - -#endif /* IOTHREAD_H */ diff --git a/qemu/include/sysemu/sysemu.h b/qemu/include/sysemu/sysemu.h index f2ab6e95..e5c93292 100644 --- a/qemu/include/sysemu/sysemu.h +++ b/qemu/include/sysemu/sysemu.h @@ -2,8 +2,6 @@ #define SYSEMU_H /* Misc. things related to the system emulator. */ -#include "qemu/main-loop.h" - #include "qemu/timer.h" #include "qapi/error.h" diff --git a/qemu/m68k.h b/qemu/m68k.h index 8e41d569..a26f88a6 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_m68k #define par_write par_write_m68k #define patch_reloc patch_reloc_m68k -#define pause_all_vcpus pause_all_vcpus_m68k #define phys_map_node_alloc phys_map_node_alloc_m68k #define phys_map_node_reserve phys_map_node_reserve_m68k #define phys_mem_alloc phys_mem_alloc_m68k @@ -2418,8 +2417,6 @@ #define qemu_clock_ptr qemu_clock_ptr_m68k #define qemu_clocks qemu_clocks_m68k #define qemu_cond_destroy qemu_cond_destroy_m68k -#define qemu_cpu_is_self qemu_cpu_is_self_m68k -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_m68k #define qemu_daemon qemu_daemon_m68k #define qemu_event_destroy qemu_event_destroy_m68k #define qemu_event_init qemu_event_init_m68k @@ -2516,9 +2513,7 @@ #define qemu_st_helpers qemu_st_helpers_m68k #define qemu_strnlen qemu_strnlen_m68k #define qemu_strsep qemu_strsep_m68k -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_m68k #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_m68k -#define qemu_thread_exit qemu_thread_exit_m68k #define qemu_try_memalign qemu_try_memalign_m68k #define qentry_destroy qentry_destroy_m68k #define qerror_human qerror_human_m68k diff --git a/qemu/main-loop.c b/qemu/main-loop.c deleted file mode 100644 index bb7c3d02..00000000 --- a/qemu/main-loop.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -/* Modified for Unicorn Engine by Nguyen Anh Quynh, 2015 */ - -#include "qemu-common.h" -#include "qemu/timer.h" -#include "qemu/main-loop.h" -#include "qemu/thread.h" -#include "qom/cpu.h" - -#include "uc_priv.h" - -#ifndef _WIN32 -#endif - -static void qemu_cpu_kick_thread(CPUState *cpu); - -void qemu_mutex_lock_iothread(struct uc_struct* uc) -{ - if (!uc->tcg_enabled(uc)) { // arch-dependent - qemu_mutex_lock(&uc->qemu_global_mutex); - } else { - if (qemu_mutex_trylock(&uc->qemu_global_mutex)) { - qemu_cpu_kick_thread(first_cpu); - qemu_mutex_lock(&uc->qemu_global_mutex); - } - } -} - -void qemu_mutex_unlock_iothread(struct uc_struct* uc) -{ - qemu_mutex_unlock(&uc->qemu_global_mutex); -} - -static void qemu_cpu_kick_thread(CPUState *cpu) -{ -#ifndef _WIN32 - int err; - - err = pthread_kill(cpu->thread->thread, SIG_IPI); - if (err) { - fprintf(stderr, "qemu:%s: %s", __func__, strerror(err)); - exit(1); - } -#else /* _WIN32 */ - if (!qemu_thread_is_self(cpu->thread)) { - CONTEXT tcgContext; - - if (SuspendThread(cpu->hThread) == (DWORD)-1) { - fprintf(stderr, "qemu:%s: GetLastError:%lu\n", __func__, - GetLastError()); - exit(1); - } - - /* On multi-core systems, we are not sure that the thread is actually - * suspended until we can get the context. - */ - tcgContext.ContextFlags = CONTEXT_CONTROL; - while (GetThreadContext(cpu->hThread, &tcgContext) != 0) { - continue; - } - - // FIXME(danghvu): anysignal ? - // cpu_signal(0); - - if (ResumeThread(cpu->hThread) == (DWORD)-1) { - fprintf(stderr, "qemu:%s: GetLastError:%lu\n", __func__, - GetLastError()); - exit(1); - } - } -#endif -} - - -#if 0 -static int qemu_signal_init(void) -{ - sigset_t set; - - /* - * SIG_IPI must be blocked in the main thread and must not be caught - * by sigwait() in the signal thread. Otherwise, the cpu thread will - * not catch it reliably. - */ - sigemptyset(&set); - sigaddset(&set, SIG_IPI); - sigaddset(&set, SIGIO); - sigaddset(&set, SIGALRM); - sigaddset(&set, SIGBUS); - /* SIGINT cannot be handled via signalfd, so that ^C can be used - * to interrupt QEMU when it is being run under gdb. SIGHUP and - * SIGTERM are also handled asynchronously, even though it is not - * strictly necessary, because they use the same handler as SIGINT. - */ - pthread_sigmask(SIG_BLOCK, &set, NULL); - - sigdelset(&set, SIG_IPI); - return 0; -} -#endif - -/* -static int qemu_signal_init(void) -{ - return 0; -}*/ - -/* -static int qemu_init_main_loop(void) -{ - init_clocks(); - - return qemu_signal_init(); -}*/ - - diff --git a/qemu/mips.h b/qemu/mips.h index 0861ed05..32ef4c00 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_mips #define par_write par_write_mips #define patch_reloc patch_reloc_mips -#define pause_all_vcpus pause_all_vcpus_mips #define phys_map_node_alloc phys_map_node_alloc_mips #define phys_map_node_reserve phys_map_node_reserve_mips #define phys_mem_alloc phys_mem_alloc_mips @@ -2418,8 +2417,6 @@ #define qemu_clock_ptr qemu_clock_ptr_mips #define qemu_clocks qemu_clocks_mips #define qemu_cond_destroy qemu_cond_destroy_mips -#define qemu_cpu_is_self qemu_cpu_is_self_mips -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_mips #define qemu_daemon qemu_daemon_mips #define qemu_event_destroy qemu_event_destroy_mips #define qemu_event_init qemu_event_init_mips @@ -2516,9 +2513,7 @@ #define qemu_st_helpers qemu_st_helpers_mips #define qemu_strnlen qemu_strnlen_mips #define qemu_strsep qemu_strsep_mips -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_mips #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_mips -#define qemu_thread_exit qemu_thread_exit_mips #define qemu_try_memalign qemu_try_memalign_mips #define qentry_destroy qentry_destroy_mips #define qerror_human qerror_human_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index be1a4b4c..67fbd77f 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_mips64 #define par_write par_write_mips64 #define patch_reloc patch_reloc_mips64 -#define pause_all_vcpus pause_all_vcpus_mips64 #define phys_map_node_alloc phys_map_node_alloc_mips64 #define phys_map_node_reserve phys_map_node_reserve_mips64 #define phys_mem_alloc phys_mem_alloc_mips64 @@ -2418,8 +2417,6 @@ #define qemu_clock_ptr qemu_clock_ptr_mips64 #define qemu_clocks qemu_clocks_mips64 #define qemu_cond_destroy qemu_cond_destroy_mips64 -#define qemu_cpu_is_self qemu_cpu_is_self_mips64 -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_mips64 #define qemu_daemon qemu_daemon_mips64 #define qemu_event_destroy qemu_event_destroy_mips64 #define qemu_event_init qemu_event_init_mips64 @@ -2516,9 +2513,7 @@ #define qemu_st_helpers qemu_st_helpers_mips64 #define qemu_strnlen qemu_strnlen_mips64 #define qemu_strsep qemu_strsep_mips64 -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_mips64 #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_mips64 -#define qemu_thread_exit qemu_thread_exit_mips64 #define qemu_try_memalign qemu_try_memalign_mips64 #define qentry_destroy qentry_destroy_mips64 #define qerror_human qerror_human_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index 9e144d9b..a97749fe 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_mips64el #define par_write par_write_mips64el #define patch_reloc patch_reloc_mips64el -#define pause_all_vcpus pause_all_vcpus_mips64el #define phys_map_node_alloc phys_map_node_alloc_mips64el #define phys_map_node_reserve phys_map_node_reserve_mips64el #define phys_mem_alloc phys_mem_alloc_mips64el @@ -2418,8 +2417,6 @@ #define qemu_clock_ptr qemu_clock_ptr_mips64el #define qemu_clocks qemu_clocks_mips64el #define qemu_cond_destroy qemu_cond_destroy_mips64el -#define qemu_cpu_is_self qemu_cpu_is_self_mips64el -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_mips64el #define qemu_daemon qemu_daemon_mips64el #define qemu_event_destroy qemu_event_destroy_mips64el #define qemu_event_init qemu_event_init_mips64el @@ -2516,9 +2513,7 @@ #define qemu_st_helpers qemu_st_helpers_mips64el #define qemu_strnlen qemu_strnlen_mips64el #define qemu_strsep qemu_strsep_mips64el -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_mips64el #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_mips64el -#define qemu_thread_exit qemu_thread_exit_mips64el #define qemu_try_memalign qemu_try_memalign_mips64el #define qentry_destroy qentry_destroy_mips64el #define qerror_human qerror_human_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 8fb00f62..dced0f85 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_mipsel #define par_write par_write_mipsel #define patch_reloc patch_reloc_mipsel -#define pause_all_vcpus pause_all_vcpus_mipsel #define phys_map_node_alloc phys_map_node_alloc_mipsel #define phys_map_node_reserve phys_map_node_reserve_mipsel #define phys_mem_alloc phys_mem_alloc_mipsel @@ -2418,8 +2417,6 @@ #define qemu_clock_ptr qemu_clock_ptr_mipsel #define qemu_clocks qemu_clocks_mipsel #define qemu_cond_destroy qemu_cond_destroy_mipsel -#define qemu_cpu_is_self qemu_cpu_is_self_mipsel -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_mipsel #define qemu_daemon qemu_daemon_mipsel #define qemu_event_destroy qemu_event_destroy_mipsel #define qemu_event_init qemu_event_init_mipsel @@ -2516,9 +2513,7 @@ #define qemu_st_helpers qemu_st_helpers_mipsel #define qemu_strnlen qemu_strnlen_mipsel #define qemu_strsep qemu_strsep_mipsel -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_mipsel #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_mipsel -#define qemu_thread_exit qemu_thread_exit_mipsel #define qemu_try_memalign qemu_try_memalign_mipsel #define qentry_destroy qentry_destroy_mipsel #define qerror_human qerror_human_mipsel diff --git a/qemu/powerpc.h b/qemu/powerpc.h index 5d2f53f2..1e46c3b4 100644 --- a/qemu/powerpc.h +++ b/qemu/powerpc.h @@ -2418,7 +2418,6 @@ #define qemu_clock_ptr qemu_clock_ptr_powerpc #define qemu_clocks qemu_clocks_powerpc #define qemu_cond_destroy qemu_cond_destroy_powerpc -#define qemu_cpu_is_self qemu_cpu_is_self_powerpc #define qemu_cpu_kick_thread qemu_cpu_kick_thread_powerpc #define qemu_daemon qemu_daemon_powerpc #define qemu_event_destroy qemu_event_destroy_powerpc @@ -2516,7 +2515,6 @@ #define qemu_st_helpers qemu_st_helpers_powerpc #define qemu_strnlen qemu_strnlen_powerpc #define qemu_strsep qemu_strsep_powerpc -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_powerpc #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_powerpc #define qemu_thread_exit qemu_thread_exit_powerpc #define qemu_try_memalign qemu_try_memalign_powerpc diff --git a/qemu/sparc.h b/qemu/sparc.h index cf04547f..637911c2 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_sparc #define par_write par_write_sparc #define patch_reloc patch_reloc_sparc -#define pause_all_vcpus pause_all_vcpus_sparc #define phys_map_node_alloc phys_map_node_alloc_sparc #define phys_map_node_reserve phys_map_node_reserve_sparc #define phys_mem_alloc phys_mem_alloc_sparc @@ -2418,8 +2417,6 @@ #define qemu_clock_ptr qemu_clock_ptr_sparc #define qemu_clocks qemu_clocks_sparc #define qemu_cond_destroy qemu_cond_destroy_sparc -#define qemu_cpu_is_self qemu_cpu_is_self_sparc -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_sparc #define qemu_daemon qemu_daemon_sparc #define qemu_event_destroy qemu_event_destroy_sparc #define qemu_event_init qemu_event_init_sparc @@ -2516,9 +2513,7 @@ #define qemu_st_helpers qemu_st_helpers_sparc #define qemu_strnlen qemu_strnlen_sparc #define qemu_strsep qemu_strsep_sparc -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_sparc #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_sparc -#define qemu_thread_exit qemu_thread_exit_sparc #define qemu_try_memalign qemu_try_memalign_sparc #define qentry_destroy qentry_destroy_sparc #define qerror_human qerror_human_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index 2195b1d6..57b3b4fe 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_sparc64 #define par_write par_write_sparc64 #define patch_reloc patch_reloc_sparc64 -#define pause_all_vcpus pause_all_vcpus_sparc64 #define phys_map_node_alloc phys_map_node_alloc_sparc64 #define phys_map_node_reserve phys_map_node_reserve_sparc64 #define phys_mem_alloc phys_mem_alloc_sparc64 @@ -2418,8 +2417,6 @@ #define qemu_clock_ptr qemu_clock_ptr_sparc64 #define qemu_clocks qemu_clocks_sparc64 #define qemu_cond_destroy qemu_cond_destroy_sparc64 -#define qemu_cpu_is_self qemu_cpu_is_self_sparc64 -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_sparc64 #define qemu_daemon qemu_daemon_sparc64 #define qemu_event_destroy qemu_event_destroy_sparc64 #define qemu_event_init qemu_event_init_sparc64 @@ -2516,9 +2513,7 @@ #define qemu_st_helpers qemu_st_helpers_sparc64 #define qemu_strnlen qemu_strnlen_sparc64 #define qemu_strsep qemu_strsep_sparc64 -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_sparc64 #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_sparc64 -#define qemu_thread_exit qemu_thread_exit_sparc64 #define qemu_try_memalign qemu_try_memalign_sparc64 #define qentry_destroy qentry_destroy_sparc64 #define qerror_human qerror_human_sparc64 diff --git a/qemu/translate-all.c b/qemu/translate-all.c index aec38c7c..12ef2ca7 100644 --- a/qemu/translate-all.c +++ b/qemu/translate-all.c @@ -1531,15 +1531,6 @@ static void tcg_handle_interrupt(CPUState *cpu, int mask) { cpu->interrupt_request |= mask; - /* - * If called from iothread context, wake the target cpu in - * case its halted. - */ - if (!qemu_cpu_is_self(cpu)) { - qemu_cpu_kick(cpu); - return; - } - cpu->tcg_exit_req = 1; } diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h index 2df9ccef..d1e00c14 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -70,7 +70,6 @@ static inline void uc_common_init(struct uc_struct* uc) uc->tcg_enabled = tcg_enabled; uc->tcg_exec_init = tcg_exec_init; uc->cpu_exec_init_all = cpu_exec_init_all; - uc->pause_all_vcpus = pause_all_vcpus; uc->vm_start = vm_start; uc->memory_map = memory_map; uc->memory_map_ptr = memory_map_ptr; diff --git a/qemu/util/oslib-posix.c b/qemu/util/oslib-posix.c index c936b6e9..49e902f7 100644 --- a/qemu/util/oslib-posix.c +++ b/qemu/util/oslib-posix.c @@ -71,15 +71,6 @@ extern int daemon(int, int); #include #endif -int qemu_get_thread_id(void) -{ -#if defined(__linux__) - return syscall(SYS_gettid); -#else - return getpid(); -#endif -} - int qemu_daemon(int nochdir, int noclose) { return daemon(nochdir, noclose); diff --git a/qemu/util/oslib-win32.c b/qemu/util/oslib-win32.c index eb8409ac..63b60798 100644 --- a/qemu/util/oslib-win32.c +++ b/qemu/util/oslib-win32.c @@ -37,7 +37,6 @@ #include #include "config-host.h" #include "sysemu/sysemu.h" -#include "qemu/main-loop.h" // #include "trace.h" //#include "qemu/sockets.h" @@ -167,11 +166,6 @@ int qemu_gettimeofday(qemu_timeval *tp) return 0; } -int qemu_get_thread_id(void) -{ - return GetCurrentThreadId(); -} - char * qemu_get_local_state_pathname(const char *relative_pathname) { diff --git a/qemu/util/qemu-thread-posix.c b/qemu/util/qemu-thread-posix.c index 6430f929..78bbb75c 100644 --- a/qemu/util/qemu-thread-posix.c +++ b/qemu/util/qemu-thread-posix.c @@ -426,16 +426,6 @@ int qemu_thread_create(struct uc_struct *uc, QemuThread *thread, const char *nam return 0; } -void qemu_thread_get_self(struct uc_struct *uc, QemuThread *thread) -{ - thread->thread = pthread_self(); -} - -bool qemu_thread_is_self(QemuThread *thread) -{ - return pthread_equal(pthread_self(), thread->thread); -} - void qemu_thread_exit(struct uc_struct *uc, void *retval) { pthread_exit(retval); diff --git a/qemu/util/qemu-thread-win32.c b/qemu/util/qemu-thread-win32.c index 2c2cf4ad..1715c037 100644 --- a/qemu/util/qemu-thread-win32.c +++ b/qemu/util/qemu-thread-win32.c @@ -359,12 +359,6 @@ int qemu_thread_create(struct uc_struct *uc, QemuThread *thread, const char *nam return 0; } -void qemu_thread_get_self(struct uc_struct *uc, QemuThread *thread) -{ - thread->data = uc->qemu_thread_data; - thread->tid = GetCurrentThreadId(); -} - HANDLE qemu_thread_get_handle(QemuThread *thread) { QemuThreadData *data; @@ -386,8 +380,3 @@ HANDLE qemu_thread_get_handle(QemuThread *thread) LeaveCriticalSection(&data->cs); return handle; } - -bool qemu_thread_is_self(QemuThread *thread) -{ - return GetCurrentThreadId() == thread->tid; -} diff --git a/qemu/x86_64.h b/qemu/x86_64.h index bbb695e5..e465a0c0 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_x86_64 #define par_write par_write_x86_64 #define patch_reloc patch_reloc_x86_64 -#define pause_all_vcpus pause_all_vcpus_x86_64 #define phys_map_node_alloc phys_map_node_alloc_x86_64 #define phys_map_node_reserve phys_map_node_reserve_x86_64 #define phys_mem_alloc phys_mem_alloc_x86_64 @@ -2418,8 +2417,6 @@ #define qemu_clock_ptr qemu_clock_ptr_x86_64 #define qemu_clocks qemu_clocks_x86_64 #define qemu_cond_destroy qemu_cond_destroy_x86_64 -#define qemu_cpu_is_self qemu_cpu_is_self_x86_64 -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_x86_64 #define qemu_daemon qemu_daemon_x86_64 #define qemu_event_destroy qemu_event_destroy_x86_64 #define qemu_event_init qemu_event_init_x86_64 @@ -2516,9 +2513,7 @@ #define qemu_st_helpers qemu_st_helpers_x86_64 #define qemu_strnlen qemu_strnlen_x86_64 #define qemu_strsep qemu_strsep_x86_64 -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_x86_64 #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_x86_64 -#define qemu_thread_exit qemu_thread_exit_x86_64 #define qemu_try_memalign qemu_try_memalign_x86_64 #define qentry_destroy qentry_destroy_x86_64 #define qerror_human qerror_human_x86_64 From 977863401e82d7d9c5fdefa181ddd02b6a1af1f7 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Fri, 25 Mar 2016 18:28:03 -0700 Subject: [PATCH 080/149] static -> dynamic code buffer, and shrink 32M->8M --- qemu/translate-all.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/qemu/translate-all.c b/qemu/translate-all.c index aec38c7c..1fd4100c 100644 --- a/qemu/translate-all.c +++ b/qemu/translate-all.c @@ -63,8 +63,6 @@ #include "uc_priv.h" -#define USE_STATIC_CODE_GEN_BUFFER - //#define DEBUG_TB_INVALIDATE //#define DEBUG_FLUSH /* make various TB consistency checks */ @@ -501,7 +499,7 @@ static inline PageDesc *page_find(struct uc_struct *uc, tb_page_addr_t index) # define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1) #endif -#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (32u * 1024 * 1024) +#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (8 * 1024 * 1024) #define DEFAULT_CODE_GEN_BUFFER_SIZE \ (DEFAULT_CODE_GEN_BUFFER_SIZE_1 < MAX_CODE_GEN_BUFFER_SIZE \ @@ -520,7 +518,7 @@ static inline size_t size_code_gen_buffer(struct uc_struct *uc, size_t tb_size) /* ??? If we relax the requirement that CONFIG_USER_ONLY use the static buffer, we could size this on RESERVED_VA, on the text segment size of the executable, or continue to use the default. */ - tb_size = (unsigned long)(uc->ram_size / 4); + tb_size = (unsigned long)DEFAULT_CODE_GEN_BUFFER_SIZE; #endif } if (tb_size < MIN_CODE_GEN_BUFFER_SIZE) { From d5e85cf3f9b9637e369872c9a003b7cedd5931fe Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Fri, 25 Mar 2016 20:25:18 -0700 Subject: [PATCH 081/149] more efficient hook removal --- uc.c | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/uc.c b/uc.c index ce9f121d..af504fe1 100644 --- a/uc.c +++ b/uc.c @@ -1029,15 +1029,19 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, UNICORN_EXPORT uc_err uc_hook_del(uc_engine *uc, uc_hook hh) { - int i; - struct hook *hook; - for (i = 0; i < UC_HOOK_MAX; i++) { - if (list_remove(&uc->hook[i], (void *)hh)) { - hook = (struct hook *)hh; - if (--hook->refs == 0) { - free(hook); + int i = 0; + struct hook *hook = (struct hook *)hh; + int type = hook->type; + + while ((type >> i) > 0 && i < UC_HOOK_MAX) { + if ((type >> i) & 1) { + if (list_remove(&uc->hook[i], (void *)hh)) { + if (--hook->refs == 0) { + free(hook); + } } } + i++; } return UC_ERR_OK; } From 784efc8be021e99c6ebebc84d8098df4b7f2f879 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Fri, 25 Mar 2016 20:28:23 -0700 Subject: [PATCH 082/149] fix memory corruption in list_remove --- list.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/list.c b/list.c index 6dbe4782..b1627f59 100644 --- a/list.c +++ b/list.c @@ -54,6 +54,8 @@ bool list_remove(struct list *list, void *data) if (cur->data == data) { if (cur == list->head) { list->head = next; + } else { + prev->next = next; } if (cur == list->tail) { list->tail = prev; From e44f8f298176357e4c967b0dc777f5dc333d1d17 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 27 Mar 2016 10:25:46 +0800 Subject: [PATCH 083/149] samples: code style for sample_x86_32_gdt_and_seg_regs.c --- samples/sample_x86_32_gdt_and_seg_regs.c | 169 ++++++++++++----------- 1 file changed, 88 insertions(+), 81 deletions(-) diff --git a/samples/sample_x86_32_gdt_and_seg_regs.c b/samples/sample_x86_32_gdt_and_seg_regs.c index 5ec55b71..be226cf5 100644 --- a/samples/sample_x86_32_gdt_and_seg_regs.c +++ b/samples/sample_x86_32_gdt_and_seg_regs.c @@ -27,40 +27,40 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include struct SegmentDescriptor { - union { - struct { + union { + struct { # if __BYTE_ORDER == __LITTLE_ENDIAN - unsigned short limit0; - unsigned short base0; - unsigned char base1; - unsigned int type:4; - unsigned int system:1; /* S flag */ - unsigned int dpl:2; - unsigned int present:1; /* P flag */ - unsigned int limit1:4; - unsigned int avail:1; - unsigned int is_64_code:1; /* L flag */ - unsigned int db:1; /* DB flag */ - unsigned int granularity:1; /* G flag */ - unsigned char base2; + unsigned short limit0; + unsigned short base0; + unsigned char base1; + unsigned int type:4; + unsigned int system:1; /* S flag */ + unsigned int dpl:2; + unsigned int present:1; /* P flag */ + unsigned int limit1:4; + unsigned int avail:1; + unsigned int is_64_code:1; /* L flag */ + unsigned int db:1; /* DB flag */ + unsigned int granularity:1; /* G flag */ + unsigned char base2; # else - unsigned char base2; - unsigned int granularity:1; /* G flag */ - unsigned int db:1; /* DB flag */ - unsigned int is_64_code:1; /* L flag */ - unsigned int avail:1; - unsigned int limit1:4; - unsigned int present:1; /* P flag */ - unsigned int dpl:2; - unsigned int system:1; /* S flag */ - unsigned int type:4; - unsigned char base1; - unsigned short base0; - unsigned short limit0; + unsigned char base2; + unsigned int granularity:1; /* G flag */ + unsigned int db:1; /* DB flag */ + unsigned int is_64_code:1; /* L flag */ + unsigned int avail:1; + unsigned int limit1:4; + unsigned int present:1; /* P flag */ + unsigned int dpl:2; + unsigned int system:1; /* S flag */ + unsigned int type:4; + unsigned char base1; + unsigned short base0; + unsigned short limit0; # endif - }; - uint64_t desc; - }; + }; + uint64_t desc; + }; }; #define SEGBASE(d) ((uint32_t)((((d).desc >> 16) & 0xffffff) | (((d).desc >> 32) & 0xff000000))) @@ -103,42 +103,47 @@ do { \ /******************************************************************************/ -void hook_mem(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) { - switch(type) { - case UC_MEM_WRITE: - printf("mem write at 0x%"PRIx64 ", size = %u, value = 0x%"PRIx64 "\n", address, size, value); - break; - default: break; - } +static void hook_mem(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) +{ + switch(type) { + case UC_MEM_WRITE: + printf("mem write at 0x%"PRIx64 ", size = %u, value = 0x%"PRIx64 "\n", address, size, value); + break; + default: break; + } } -void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ printf("Executing at 0x%"PRIx64 ", ilen = 0x%x\n", address, size); } //VERY basic descriptor init function, sets many fields to user space sane defaults -void init_descriptor(struct SegmentDescriptor *desc, uint32_t base, uint32_t limit, uint8_t is_code) { - desc->desc = 0; //clear the descriptor - desc->base0 = base & 0xffff; - desc->base1 = (base >> 16) & 0xff; - desc->base2 = base >> 24; - if (limit > 0xfffff) { - //need Giant granularity - limit >>= 12; - desc->granularity = 1; - } - desc->limit0 = limit & 0xffff; - desc->limit1 = limit >> 16; - - //some sane defaults - desc->dpl = 3; - desc->present = 1; - desc->db = 1; //32 bit - desc->type = is_code ? 0xb : 3; - desc->system = 1; //code or data +static void init_descriptor(struct SegmentDescriptor *desc, uint32_t base, uint32_t limit, uint8_t is_code) +{ + desc->desc = 0; //clear the descriptor + desc->base0 = base & 0xffff; + desc->base1 = (base >> 16) & 0xff; + desc->base2 = base >> 24; + if (limit > 0xfffff) { + //need Giant granularity + limit >>= 12; + desc->granularity = 1; + } + desc->limit0 = limit & 0xffff; + desc->limit1 = limit >> 16; + + //some sane defaults + desc->dpl = 3; + desc->present = 1; + desc->db = 1; //32 bit + desc->type = is_code ? 0xb : 3; + desc->system = 1; //code or data } -void hex_dump(unsigned char *ptr, unsigned int len) { +/* +static void hex_dump(unsigned char *ptr, unsigned int len) +{ int i; for (i = 0; i < len; i++) { if (i != 0 && (i & 0xf) == 0) { @@ -148,23 +153,25 @@ void hex_dump(unsigned char *ptr, unsigned int len) { } fprintf(stderr, "\n"); } +*/ -static void gdt_demo() { +static void gdt_demo() +{ uc_engine *uc; uc_hook hook1, hook2; uc_err err; uint8_t buf[128]; uc_x86_mmr gdtr; -/* -bits 32 + /* + bits 32 -push dword 0x01234567 -push dword 0x89abcdef + push dword 0x01234567 + push dword 0x89abcdef -mov dword [fs:0], 0x01234567 -mov dword [fs:4], 0x89abcdef -*/ + mov dword [fs:0], 0x01234567 + mov dword [fs:4], 0x89abcdef + */ const uint8_t code[] = "\x68\x67\x45\x23\x01\x68\xef\xcd\xab\x89\x64\xc7\x05\x00\x00\x00\x00\x67\x45\x23\x01\x64\xc7\x05\x04\x00\x00\x00\xef\xcd\xab\x89"; const uint64_t code_address = 0x1000000; @@ -183,17 +190,17 @@ mov dword [fs:4], 0x89abcdef gdtr.base = gdt_address; gdtr.limit = 31 * sizeof(struct SegmentDescriptor) - 1; - + init_descriptor(&gdt[14], 0, 0xfffff000, 1); //code segment init_descriptor(&gdt[15], 0, 0xfffff000, 0); //data segment init_descriptor(&gdt[16], 0x7efdd000, 0xfff, 0); //one page data segment simulate fs init_descriptor(&gdt[17], 0, 0xfffff000, 0); //ring 0 data gdt[17].dpl = 0; //set descriptor privilege level -/* - fprintf(stderr, "GDT: \n"); - hex_dump((unsigned char*)gdt, 31 * sizeof(struct SegmentDescriptor)); -*/ + /* + fprintf(stderr, "GDT: \n"); + hex_dump((unsigned char*)gdt, 31 * sizeof(struct SegmentDescriptor)); + */ // Initialize emulator in X86-32bit mode err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); @@ -257,10 +264,10 @@ mov dword [fs:4], 0x89abcdef // read from memory err = uc_mem_read(uc, r_esp - 8, buf, 8); uc_assert_success(err); - + int i; for (i = 0; i < 8; i++) { - fprintf(stderr, "%02hhx", buf[i]); + fprintf(stderr, "%02hhx", buf[i]); } fprintf(stderr, "\n"); @@ -273,15 +280,15 @@ mov dword [fs:4], 0x89abcdef assert(memcmp(buf, "\x67\x45\x23\x01\xef\xcd\xab\x89", 8) == 0); uc_close(uc); - } /******************************************************************************/ -int main(int argc, char **argv) { - gdt_demo(); - - fprintf(stderr, "success\n"); - - return 0; +int main(int argc, char **argv) +{ + gdt_demo(); + + fprintf(stderr, "success\n"); + + return 0; } From 09784d85c18965787ec2d2316bd4be5caead4ce0 Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Sun, 27 Mar 2016 11:26:57 +0200 Subject: [PATCH 084/149] bugfix read_reg -> reg_read --- tests/regress/x86_gdt.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/regress/x86_gdt.py b/tests/regress/x86_gdt.py index 3565a74c..5f4234a4 100755 --- a/tests/regress/x86_gdt.py +++ b/tests/regress/x86_gdt.py @@ -88,7 +88,7 @@ class GdtRead(regress.RegressTest): uc.emu_start(CODE_ADDR, CODE_ADDR+len(CODE)) - self.assertEqual(uc.read_reg(UC_X86_REG_ECX), 0x41414141) + self.assertEqual(uc.reg_read(UC_X86_REG_ECX), 0x41414141) if __name__ == '__main__': - regress.main() \ No newline at end of file + regress.main() From ae9e21f9b88533efedea07c74a199c2e8a55a245 Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Sun, 27 Mar 2016 18:26:43 +0200 Subject: [PATCH 085/149] license parameter changed --- bindings/ruby/unicorn_gem/unicorn.gemspec | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/ruby/unicorn_gem/unicorn.gemspec b/bindings/ruby/unicorn_gem/unicorn.gemspec index 18f38bb8..67640837 100644 --- a/bindings/ruby/unicorn_gem/unicorn.gemspec +++ b/bindings/ruby/unicorn_gem/unicorn.gemspec @@ -8,7 +8,7 @@ Gem::Specification.new do |spec| spec.version = Unicorn::VERSION spec.authors = ["Sascha Schirra"] spec.email = ["sashs@scoding.de"] - spec.license = GPLv2 + spec.license = 'GPL-2.0' spec.summary = %q{Ruby binding for Unicorn-Engine} spec.description = %q{Ruby binding for Unicorn-Engine } spec.homepage = "https://unicorn-engine.org" From 97c39a3a83466481a4a141a470637dc34507b32f Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Sun, 27 Mar 2016 20:58:05 +0200 Subject: [PATCH 086/149] Bugfix: remove hook_add call if no insn type is given --- bindings/ruby/unicorn_gem/ext/unicorn.c | 1 - 1 file changed, 1 deletion(-) diff --git a/bindings/ruby/unicorn_gem/ext/unicorn.c b/bindings/ruby/unicorn_gem/ext/unicorn.c index 8681d4ae..c7979343 100644 --- a/bindings/ruby/unicorn_gem/ext/unicorn.c +++ b/bindings/ruby/unicorn_gem/ext/unicorn.c @@ -367,7 +367,6 @@ VALUE m_uc_hook_add(int argc, VALUE* argv, VALUE self){ err = uc_hook_add(_uc, &trace, htype, cb_hook_insn_syscall,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end), NUM2INT(arg1)); break; } - err = uc_hook_add(_uc, &trace, htype, cb_hook_intr,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end)); } else if(htype == UC_HOOK_INTR){ err = uc_hook_add(_uc, &trace, htype, cb_hook_intr,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end)); From ae979259bd507b85d360a0b6606fb311ce452fce Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Sun, 27 Mar 2016 20:58:38 +0200 Subject: [PATCH 087/149] gem removed --- bindings/ruby/unicorn_gem/pkg/unicorn-0.9.0.gem | Bin 20992 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 bindings/ruby/unicorn_gem/pkg/unicorn-0.9.0.gem diff --git a/bindings/ruby/unicorn_gem/pkg/unicorn-0.9.0.gem b/bindings/ruby/unicorn_gem/pkg/unicorn-0.9.0.gem deleted file mode 100644 index 57b7a6b32541290b63026617f81080101054d520..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20992 zcmeFXWl&r}*De}@ySoKcXtUv2f4$0tL}I1SGVf? zI(5&Fv#a{qPd~lZ?$x`y*Yr${otcY~sga8jvxV2E|5X<&_~PW`{Pb}LU;q8i#>T<* ziH)6`hm)P1lZ%_}6Du1BCnwLRFRcHo0{S1H>+0-cK3$#Dw-T?On3;3vDVxd%TA#B=vmkL& zEFLdhg#W}+N<&^x?x%AbM<6p+3cb~A^_CWNAp7BpZK5el@>8~jHpvv{8tDsS`E)^* z3Sy*Vqx0z11HOQ

1EpNtu+)&4^?^3To%&1w_eyq09G5Qn_QEr_StwJXF#-Ti(mm z_RQk?73|pX94ZaZQ1@j5fhu!iep_@wF&j%E5=oXg4?)~3ny3rI;Hhd(*9rgMF8g}< zxJs*N!}h;3WwwqplMfzCdz=2i>M6v&OjzzgnPd}avf$Gv*j=HbcHLZcu=;v_C+la5 zVisLV^7mTX;m*6%jCU)rl>f=>;UZ6GRJ9zDqD~J?h`_&PH2dlYmeOS%G z+EGuX5>?^`-UI$?bk>9v;JZKkElzd|RNRBYb&JSR&%L?hFRK`FL@usxm_c_>E?!+6 z6{$h{B&q6n0m9x1x4`anE@7;s!=NT6EHBbhV^tqaZzEdp5NpsfTaYC!r@c_WNo_d} zQULGvn1wHPmV3vVG4C7Rgj`q}FVRB@QvEdu3S+$&ex;AACEHI9(D4eC@+un?a~zsg z{$Uz~aZfpTe>)N^(&yNsgSLNA4zCMnsE2*$+%7D(ycCg`>G!OF{oi%T|DU-2hd1z_ z+z-xx|NrHGPF8jv&i|hOIl$8Y$^ZYuJpHet|CRsGeL>EIGD#)=LT}i-irGIir&oXZ zJ)GX}ihiOr+S%}sBP2wM3SrEp`wE$qdo%g$-(5CdR&_oeB=wYkQxzJ4AHB8oO)n#7 z(m=_UOMxKh>?Gnnt6VQj{?}Oha$) zKV$8G1Mi3G{%|C)k<#6@VPEaP+k$$t-ttb~y>ZWis@ZOL2Hf<0xSS9nCOXzy-dxw) z*v#I@?p|wpYrIoN<_xaubO^TRW)~P;{yHPmw{a*25Vz?3xl}t5g-wzRk?x7cV6Y>sfYK{N8i_@ z;NYkJGt%$X)%MKQ_FbJeovj;8Mn%i&PnO>)O+Ao@1-9d+M)kp0Y zw~MIFsFl&TS&R1Gp04iQ?Ov}A-FA8#&67Wv!LNk4qrJ1k>oypI#Gbi%IURIyxuJJ< zkNo1uuHU58#Iv^X>Yd+0sz3*lHiRbGd2HqO&TjcD>wC zSa)Gbymk6Kb#=F6@P`_drq@(upZ9NV?V*kA$JCYL+?$uH?}k^WozS}7mY}YPz_d)$ zV({RJX{)8{5R1;)q|YWki@xxZ%w~7z!udUjY0>%a^7SsYN`uGP-Ou?wnET9d9_X%o zcau}t>rmsdGJ7dZ!Z`F=W=*VoSgB;Qn!y6IaZtnYL-FVBNztkQg7r6@xx9;Bzwn*~ zANTUg&h<^8f!>ytnt}Dh)(N$qLDRU2jzL)T#ll0I*ij{-uNCRe!R^^v){kCR-=c@L z+r@>f#fgj8`b7hG&F7@eE%|Cvk7^McWP9c=uSNM(;r*AxcAJZ%Q+?732Hq~OLI#np zuFef18{&=4jjVo|9F1~fx`j6jCe-=*#kx~V=eL);USO3ya}_Cbb0v)c@u)$k?{4C| z9jX1D#O1|1e1bni9n4LU@bjPE-ZBo|`;80MwoacG?yJF-iG@4oVLg}XsjEw<)vb#L z5OJCR)|S4Wb$RvW)Hyr~u<6ZjdbWGxi~~e3?9-QNyV>ggpqwil4(Tc2(yQ=l-8plm z6@UUxrOyF0J^M*;^xA#RJ=VFsn^dpG z@shy9<;MN!%F5`K#_@5|2ZSOtN~Qvv@;u*e`Nom)2uG^4{2Zo_lw6TmJ{q{kxA~uEB;K>cyPg8mRlSq4t^c zS*VjMf$nu)Gf&Ft29`y+n9v;vU6`$Wo+>7A}7vii^O-R{A%j5 z=^^|$o#y>vXO}5^MhMz{4Fp>mkMx?&*X*}Sq`zUQR}Z@H^SYfnjK9jUQJg9Dr&09n zT$uD#TJv-Mp-)WG((To}U>zim`yA^<+J%#U2A#{hvMC^wm%qg?F*8{@<)eLyeUvFs zxi#59=N@iJ^!<)9DpwGM5i`Anvs(3TlU4B!%|x~2Er^$^h|2W-&uZ)yWnF}^xEhF( zDGNK5@As0aWxp732Qv!UD^JQ0ru5khDk zsnW91C4yyimjxp^lGujcy(07q!P2s1yX|TIt6bqMInU&uFM*83LnX-lN>OT+(p}GP z<++A&CLI47bbAI{*s~f7y4Apaa4*D3v$)!{f`7BOc)cs%N^<`mZqOmrfb9S5PWp26 z{oSVfhYR81YjS<^rtuq#_e!sFT|dy2&cbhXwc2IuP65-U)D_LlAd4Vq{BEJW9K?Ee z`24aaAh&?71^a3J&m!4#ZQ)p(rE51Z4)6dPfphI9CG=l`^KG7+8Y5L1U^bO8^7Jh~=?bdE*)&#oNGU(tK}N*o68gP^Cf}xT+Y*G%XW@H7qRDA4wKE%4 z;8DFMo;!zd{Ic`hh3`y?i?Jy+^{(n@R9T;Ug#3K-<=O?3uIu4O`n|90?M;Ei_2op0 z)W7Zc$DQyKvG8Quk7nGh940@H?z^8S+BS~nUjcJ2lR zs;?fBN#v#~MV`}@iA!ztV~zGfMON5%}w>Ul+jl%#(8pdsWfBHQH>gfI~ z_50#JUZ^xxuuePYe)Yh!C&PjxTp8!6cdycY{@1CQD+fp6WHYN%VqD}d*3;}wp&Fma z`0AVQ1I}~$lF0gxt2gAhmxm+ZcdEr9uKA|MFW_eVt`kk@s_0^zdy?!94U^cS zv4;w|InH&k6ebA3aoIsaw%l?c(Zz8j%ZWZk~vi#>Y$c=J;BTUy-$P58O{`}w=h1gX|UFQpfCwREnN zU_9VqlIV&Qy4?q#HRN^Yhlz-++qql(T#b$;ItAUfw}YD7*TR2nWg0?XTlrd2I6k)} zT6Y%tU!>t`wCQ%-=eVVG?IZaK9`F36K`qC89E%1D#v!S7c(%0ic6SMPcpwK`tU|7B zOzdC=XVl2%W{mo5Z5Uj&S=d!S1fR@a+;&F-Z=(_Q*j=!Dj$}o4>v%Ws6W+WHie>am z#`UP(Rj0F*Nu77jA(qDymu~JZE?oEc^*4?ss+mO$M&i3SuI0E4{xKXM`OQW@rw9|B zG3+p(FHCI2zIAuv-n~}h&vTDHq2AgKL`&Ub#QSQr*%)P)I6mdQMAA^{My!Q{WDFuR zANSU!Njor3_NpWmue|U7FgQQ-6KALEU%_Wy z7Fgd$iFWZ1a>M-fz2rCfa8NKPkO&ctA7#B!Eq?{3ZC6DbIXTI%B#;Hp4nBpmCA|o( z%h|e`P^RJ1{RmelqwnsB%lXn!fAb$B-|q6hAqs|AD^wCzG=& zv5<21z1`-tlU6<3-=z*7;6kJCwbtGE@G&gvA}W6i_PSQPw^k{l`e8xlHR&}}f0!(9ZVhdgwZ?@_sK*AYEn+ji{EO!*_0o0~=-=rUJnVV% zm;t_f4e6Zxg(tq=>t(UNeZAaUTOC2Nt8P^8=h-lxv@hCHJ!?zW@4f@RuV4(!IL!L? zuD&Y7uxi&D3`e9j?vAxp7QP+ZZeIPHOxshn;Jr0K@f+P6&Zp@)4@{Yp)h*kKmbQ4HsJiRipgMuWEH!5rg=-y_^=!cxYRTg~F<-uki zUsL8P_%yc~Ic$jF)1wyv?9Fz*YUu8u(5H|QEWM?3nY!3{ep745y!d4Bc0fF?!BP1* z(Rq4=x;hsaEK;5LT3GS!3qsX?UyJ(-h`j4wIlAixF1`Edzk@tquS^!--_FhKru;7p zDvwCN``y0mX_N@Q7prvw--Garru=8rhmS;lkOMQC|7DH8c)cl7iCXR)5bqF#bD5^Xllosr}FU`5WiCh|L{!<&Ejg=>tskVmFt`!4@it!vlooTyHP% zd(IQB!Z?L|xBQ*W)AqLi@f$)wi#Q}Es<{xZ3AgHR)xnvT%9)7#J}bgCX{$aoB8&GsCN;5! zJqQm&LwaabR$s!zjIkmnCbhPPon2$7Z*)WpACZCL|1HY5s2UqltM|1gj zcckyfYvG$~Er^mFFujLJ;hSqL))O5dy@v?lo2xCd6CG~7hH&AVt1NUA9rnD2Fe7V_ z3;0uq@Xx*)5lgz#j|cx!3iU->_|1w|z>ke1u3p+F8F8w<45yldKtWcfW<(|FN?j51 zYjU59Q^UMZKH?Oh1+SU|&p=kj@&B}iq@pck)L<0wV`_-2AAJ~Q>v$r-I#Vd`XxZ=m zc9fk|6y$mvX$>tMBIe_{p7)?Qy3Zl7*kA8Z+l$WDakti0b=Xsir9m(vlyoJFv?q=;$jr8of~)%L>L&a1h1d zAlk6NLHt)60yxsfeQe$ikF`Ff2%80*Fmc0j?q-*;aAySz4^A-Q57FU=B%3`8dr&@wW408YnVhT(1ma0P@`=PDMmYz zhs(u>YQu=KfJv+h+0PLB#gOl5j&>#=0hZe_$}C`JszS~)#9GQ_^)+iW;ehy19T=k) zIQb)3_u?ZA`M&08xAGBSwG-piB21NKe+sEk{}_lb-H9g35#yB~Krfh`rL!}$zKW1d zfu#c7g^uv+^Aa4qdZ0xJOqoicvjoF+w2ByZi_}OSLI=5vN~kJOmZMiGKa?Kq9rgj? zU?7Y5U>`sh`N2MbEb4=O09iDB%(MD`;wwZb)TjLb*$=S%fQS$H^#LOvaQp#qMPQ&U z;v$)x(AxtC$HglHu02YFp+#D@h|5FTvWSaUIs&Xo{Q_%JBSlVhE9L?Z6<`C7Bz+O@PMp1x?KITa2|u7oA*bL_s4 zY6`fjFIx)sn^pq*k>!5)34QqaeE7Y7_RWCk>yyL!7<`@`>|RZlA&*H1t`<7H1fiPAf6Q zXprS<;8lW0%laKWTB8Pp*M__RL`tux{Jljx1{o(rt>syFan zZz;IStngyyewAowiCF!iWzLjMsiK zs(R?4-=;&Ntf}J!9sz0NL?1vx^w$JtCxEmbE*z9Dm5y$68;!{&Gi!;`G7;0KtCgi4 zno+~efp}|ZXO3&$yE@J)FgnawZ{jn~DbP1;+n>!c2kS~Rij;S8CAk6@U+j=>QkT4u z;ig``5}57obXj#poi-`E1bH%+wfm7opTz-(liHS!Y8x(ZJsHadyh+B+ zs`O*UP%BK+|0?UEO20*(iT&-lH{2EQA_4d+PX%XOoqDo9_;wNuOj6Xtf^x^dy!X+G zh)le1Pra8vxC7sws$H|A24CJepI=_y!6!DWiV)y?uoYGAI|1gDzi)+(#r>Pn!`r?6 z*gtzc1X4rAaTbJMWCsSwC{Zt2y<)ZgY`nBLSJ1GEKXh2(Oxde4d^z!NPuV6Dcisos*yxeKnHuGNu$TIETlJxVJsp)-8G* z*N*6ge)-hR1}9Ewc(LBE$fHsV>zwq?TQCTvKiL+;Is+^J8Sd1lk}&$VC2@9LV5Wh4 zG?N4O$OKOSYM>Is1h!CGo~r$Xn(+CXl-H_kfYES`j}w$8JS<)%wq~IXSLTC~oR>Id zjKO*D2?(MVPL`XVKVpZ^e6pn$a|TXPTJCUULNWO&C5L=nv*3a+^UCk4bu!!WFX22c_0C?(g+3w%j}wIV1Nv^ zHp%u(1S86?nHd*ZTv(NCW|TY+Ne$Tf7G*n!;(ui#z!5(Q3o-!|*0cCV$dVUF=-D)1 z*byDaJM=%Bko%SCKX5NZ-;MG=6Gup49g8yViozNvLh++Tb4~|pnFgW^kfXYMDRaw% zRQ)XqTMz{{qelS?l+%H~X2HVfhXA&~k;;RtrG+Gp06z_OHx$9;i&9A-3KZaQdj?g4 zR`9W${L`d>pFKqDt9ZeK3mQgeX>h`^5b=OtPtJNzzE^m%N@u^^ug#r-MG&9sqk+h~ z`@@@$`^}$+cS{;ofrF=R$phf6fA`Ug0f$Bqe2?{NhPx*WTF*9Gf<@db9vZ~!7jU5k z7gliL1s73pkp&kOG>GWuPQ{+t?iQ=FwYLRDqXUCYthkr6tiD?RKsDZ*Y6pbUH!7u_ z@$MnIY!EJADB?SPsl$oE;XkK_*R$-t(e7zFq9;xMP?Ptsr4G9WXIM(F(K&q?{*7w9 z4=nBoxNmn#JG0%}Rz8id47p(QDX=*Ye<&spqsZZKE)a_v$0=Oaa9S&V#LlId7kCEjL(Z2HjO$zIY9ngcM`P~kq zl;n<_U34YrH+z2~5JV5`qOjbbbBBt39S{evemxoR>OX_adDr5Jt`RTXv>Uzk z!~D1m6+;->2u7W{tOP51Z#CxZNXf_u2HCA5oJUbHNl#a_0lsM&+wICr(3fBr?rDae z5+$$K`W?esy!##1Wqi;dyD)x&Y!BVWTV7@L{BKnvpY6z`a7xE!(B%g3ZRd&I%AzRa zkl+-2Hd+XXxQ@kx>Q%qClbJ(9L>tEW)wcxt?#>x)uk@L;a4)@2j9u?FW<8M+?8;1( z5H7m35Oh!mbetnRY=~CxZay|DPXPD+{JNqT`f@10sDZcLz;P*7G{|LIR;6qo@XcQz znR<`k9BJ{TC<>9dzec&V1&#E#HNwLN2#3zm8-$~h(nT$sp!hZ;HoM}cwbEf?cTSk)Q=NNcy=#5N_=bo=4@61xXtEUC94qw znJJg|b-lF^P95%bDJdtaEdV&eowsdvOyfV&rMRQ~B1%m*Pvj(;Sz|7M+=God#0ioS*@%VX zo6PL{{T_Vx-_v*0Q~wRfk&HLxx%1n%E#UsJq<8s2@kH{y=7Ht~%_08v6NRXM28!0bTdqXXJ)O~Z(X<=CWKp%&RSRV?%me5 z+wJ-!gwL0n$S9p9)wQD!e%7{o?II{=!B^^YNy3j*)*KFd?fhJDLz0Rn&(nWt&9{f# z9j&JU$ki`j^ke&tcWF(w8AJj!gHuU6Z{zHo1huc#vrrSgDGYelh=~R(?4u+4c(R@+{kg}g^ z`CxYg>H5R`w5niA{Q#3D5+dXu{lu34h~itB>kl?nLq$!}6B3kdy1V|evIG`Pz(UT4 za1R#Nz=AXCtVdlttk|D>5-2K=H(HAAH8_Lxg9RMYJ7VRBN3h*K*zPCT(N0)U_WlVh z9D{{Yuu%CSJcEVvV9wn0d$8jM*wK#^oXipk#V|$orKjgnTc1i{R&2L|P0M{zlVb0M zWSdqVzO0yng=nyV{2?s4e*x$)X5sW!4AxmqMUPCyRM##mM_1PlOhs1L&MQY$*N$I3 ztD3X|A+Bm>eqC7fc&j|&Uz5a)AbG?OnZk6)V6sDQ7Sd%vT+PIc2Rv9RnfENA4hI1O zs(X_F{?%dvbh$!<7ug>7c+FY!^+zo^=u;&7ZsLO8No!BnieqKa8;o0pF6BP)v$21L zgxAHxKTvC-A`I;a2uwzi_Ie6_Xcz4HS@VNi3JgoKy?Ra;vX zR@K^C)n3!kFhur)oF1x-TcruBWbG>~P18+*K??S(oL#nz2c?^kaqm(OdGk&+K?=~W znjj6~o?6Ej0WeVN?9H9cQ+w~J=_XFx(2*oEG7Os32?-Bket_BsaD0IC2Oxfc0vM2c zxK~JkyHU3BSJywePcx)FtqOC0r+iSQ4@#H%K{fuP{)g&*(3AgALogM_)G(g6m<332 z50-jJegNPD#NEIk-vkEfdoU<*50!d|xq(5hX{dDRx8nU!X$yJQo|+(eI~b_fz(Do^ zR3AX`0W@If`0@diYkPB_Y?Ci;=&DBUA5r|xzyaoHf}`5>1XH@)4|@1P|NMvk{h*P+ z5B2SX%H@Hnf)SOpFWrQ?shUre%m)mcYWhUcnCkdMm6{s(L|K@c_(UCg*H6P$wWfNb&Ky{%0?fg$r4!mHW}^#n*T0uHG3)E_ditXCtqC4l`okJfUUV!P=F0yif;WhV0q#{GRuEtgzib2 zJHv4iW8;&7UPZ!i6ng?IvCa1Lsy`%;B>Fv7=;+CEers;)n7x$t)%KT{?x?tj3>%d0 z0(hFe>y^C%IZ70s(OT7sol>^*vRmXDTz{Kk1TKlb#Ue2iEuV3JZNXXNbZUXSCy>*P zR`iY)tdb}aYMf=J)V~YAoj+P@mXmCV;b3S4515#hD!FoimTawE@;J zvgEy%E%D3^;7piSA7wu2M?VZ#0g68Ba@^Y7^!{1{ynTO>dOwi!U;j;?J%`Dqc-7-Z zt2)~2$bo#Wa&42MkZl&s6c_&Ub5$n3QNU3`ZA{iZ$sLb_!JwjZeAvbw1Ry%XLZ1@GbS?)=1e)$fwl=s_MlsH4E)}* z3`v-4Y({_OEOS@KD8MRbxp#woNg~AgM5dJ~;(eBM+HoWedO{@bW7|t7^xOqd7*YGLlo2lViN9z>i~4mvr+7b;iaH%><(}@w*9A+wUtqT{K_Gl*SAi9DsBo98aN^1j$oH}D*>|}1hyCp*V5G-T#MFhl{ zi9j}09g}V?fV;t>ZNMr4z~*X!nKlM9Kl!c!U~$!q-eeR%801VYrcYaHns31ERnum> z2}xo4hEP^lobDrzkkvb%TvDd5j;z&{rGh=?DPWDZ6KZ<;=PUM@uRxhoaUB|$A)kYS zr@Lh6zI9=!NQaf9j?<+Nz`%7$C=I*W5=b?Oyx#8zjj1Vg%tl*M>6IfjY~GSJRJi{Q zpnC_ykcQm+3;S%0P~@AyZp{G-@C{b*cIfTq@M{P7`dqy;lwUTW{0A)xHSU@|3YOQ)38MU*w&-hLh)hu!cIgKnNU@++4UdXY7V$$`Ql2EPjH>r z+VT?#eMiw|Cw7iw{26EX^I#Ue(t~-U@0G7hgS=!aA+t86&CH9j*nWpg;WtHxA--!g zecIP%hjFJczHoB$?kTCk3F~e7C6jto9 zR*F3{?*Yn{sN?&HlR9klOY}K&hJtm9k|_;!3mHH$pHn0wrVRsqKSjw3(MgnakltcR zkz;zrNVBy~k}e$ej>f(`EA|8Oz9)IfPS;67{KDe4>Xu(wQ)E*7?4qIj?WkWu6T|~C z2^&#QN$pnlmrPcyo)X_Jq#G4;0>Qa-4GDAtww(J3JO;xOF>7jLj0-~9aY+Es7jori zL}dMsn$PBVX%=o1l{V?LAeeHy@Am~9mw{^;Bpkfd7l?uJwW4(Jx+*JaP=Z|PUm!o{ z_5%{}KO+u&9^T7>>8_#ci8x^kHi>2rG1^@}f;0a?|ficxZ>^)FiJk#Vk8T0So9mf|3SIFDGp&W8_-dr+l-rO&kyo*y_D>-u}0opX}kQA1H9Axj#6%6Uc zRU}fownsLDlF2Y3-CVNg%<4}#LW=7_ivKtu>!Ng%1^n|Mi)ZmX~NNubPs={KexXwZOFccK4e zhNI+#O`?ZD)NM6`!yAH{YzPw$!w$in4RFv?WHh{HnA3+LrAYkSfE7YErwcQ5SThE{ z#TSz?ORzgc4=_e{WKEYVM~<5t2B;$&xaO0haqw}Ss$YxuURyX>&#!Fbv8a883CCf> zFLrbho>PGV&(C7qDXW>hH7DL0=FiXJQR&$PE6l3n|5AEy9%)km!>Ab%P!BEv__w?Y z;#eB#VSmrHjBrMcb(m4jYMGY)1uBjX0-RS6VS1CJ)gd?qa3g~@8T&q?TMQvm8Y_*n zHj{ARYXIA<-W!}lnkg`iVTQR6K8LTx!Pi=qf(pvKWK$s!r0q?phmaawQjFEB!#yY+ zvb)d_iI7aK$G0tw66HUy>X-&;t&)2N^s3Q;kq_COq(S1aYo znK3%>vL&0%U0SXJjUqXFw)yHl1vef9@o5{{Nd@$-j((~Sv!WPxN%oKlTJbxrlIv5) zXO$gD>S?7LhoBA)k)((BP6DvYvfkdkufTAe$xxH)+7<5`8qymX+gg*9tAs?dN%WL+ zf@}PBd<7r1WsGqj-)`^`LzWFTCar(2wURk`9wS4ST^1_{k6abO7{1xGZ(s#0M654l zrQ!77GzgHTSUz{ahSxWbkERubZ*Y=@qEM6+pwOpIfTo3A-%fy1D@x|jP>IDm-=DJD zklDXJNT~tdL#;E;f6polQZ<-Qj+&t||D6;c!^Q1m_b& z9f`oIMU8>9J8pgaH~Tv?yd$0!U_cw?O1xx0fpC@o7R};}Q9QdcnGcfdN7CO1kVj1o zlK)^lZhC>z*PAF<^^Pq^0-L0$B>~D>jH>g7uwy18E3PFsX+4*K5vp3Kg6)A5v{I0x zXDNO*S$ZQC1QmO}U057?7^(nO)4|&Y zVY!;HK?NS+3j-G&y{-KWOd{|X8@5%BJ2vny5g-WA{W*i70xb|^VR ziX+6Ljg#PbN+`8MCjCpqD~KN64{cIl-*DN(>()oP(c=Hva!!M2T`4_oo4;xg31W#8VZ?(ql%aJGu9<#cTxrh%z9mlJ(#28OweN;x zu^%8DcJ>)SjgO}%*BS>2gLEW+iRZqd*qS6j(#z^Nnws5drdG8dH@t|%d=OX4)sGBx zFNMULQf$qYK)9#hNt#p%aNavw7+*+Jutr&Q)^o3*!kyG%p@L9b%6KZJ{>kw>?`MLO z8BavqPL!iwsiUB98Zm>Q0y%sIT`H8W7xNLI6rp^SD)1Y2U2~`;9lWLeYT5=XuS^*w z#JA$Qy|5!$NMatr@bi{$Srm-PVYD^E6Cb$(me!}MSSsNAUh60tba7o%p8g7sIX!r7 z&`OFS*7J%QA=XoV0C>63t;9AiKzr3X+e+jSMwc4J1-P4K-ZGyz1fQ{|^z7{PK;;av z#b&V!l}4HbU_$KKSO4y@FvVRa06uJVHPTHjYg>05f6{?kf%aQ#MoNB+-EvD0vA~+z z)W+~phkCv>)I~p@S|g7%4I3${^N))*VqXcA4tj7{;nK@C;lUcbRPe?Gs0uGKecVZ4I1b*rOpU8ISx1fY!a^~VxyOw{iN_JKj`%UQ$ zf+lJ$U;74Mo}%+n=iccr$O0yl=O3E_H|pcRR6`r7kbr%CxiKf*oy3K&lxn4@LJj>bb`Hhxwr+$N{KqL&4j z0oK25D1~}ZJ2)U?y1@V;^x=Gvc{%F410u!nlU-q8wHzPeP~)Lc9L9|V`FF12cYpUl zO!5j2^g9Pa>N4!lfi#xUVBUoeee zU|De2zw$B|7<}5L*(*nMu(lmq!m(W5ob<8lg;BR0QvaECl*2Z2P~vG}tOwzyz|mD< zsDdev6Hvn5Xf{N%Jr1zNCz>2rvt7QLcytO1?B{Ug%}v9v_;v`tIK}9vz2Yi~ucnjf zIF{~2-GbB@NXTeWpuoXv!*7vflMhT}aWHe4b6{|GE@@5^TE0m7UAY%3)M9nlH!1%o zWBz+bA2x{3;JMYsM#Q=6-q{M*|Ip{=XqG8r^yzu3Sg$IDV+I;(n~eu~(UhYzw9PMy zbVOD{J#=d_VSYMoR01o_*tu#WC^Gv`RjLkaBF9dnlR(%$z`JrimyA!%fT7Mtc9L^B z>YOl%gRIH={3?+{tf|cXaU_FMhwC1EW7Sz`_t{q^!&^V1h?noJ$r1jW-fm_&>~O0E zosQ4C&SpOsFBk`j#7m_FWfEPK)PpfjoM1w-BJP>c?<5saKlqUq(j#;defgZI_ccr{ z;<8y(cr%sxg_z=Shw1z5ocDxak#;SEN$Uak#EDe*5iV2cc)dP5L8Y~kJ{LiHR>0^` zM7K&`W*nwvv%6NUYD3)VBjd^-zmRdzw@@1SLLtVq)M)H=f*V1_AfmKn8$LsAPFt1~ zb0drv!2v}EMy(LJ?NPMwIo7{`s)O|0)u0UB(H#w|BWt>ax5na$1q&%c9;xTxYkS2*jFz{+W=w^?e3YvhK>wHN|S zs@Camv;T~z>X_$pq_#Sh_d8Q_Xxe*vOu8J7GM`UoOzN(rZt%@zl)n)*AYo<_=tGX% zUi~OpbfD%=?By^G`VE`|IP#;6VP^-2=3b(Y3|J_(!+ycc=ei>C2SoGx8J4pYvg&D) zhCj7EQ;rl`0ZOalCOSB-BJ1HO8fNpY{L zG1WN+R9?r(wR|7DbWAj>zm{VnbW#nySlJ^VOY>GjsIb1`qpKrhv3fdWw#hGeg*8NW zeEg&%2w#8sj6=WS9MC>MzosUVE3{=GLZWhBO^S-PS$HUOA;g#xs~$kbBZV#nLhT{g zy@qJ=z%aMDk~+zS%zh}aRetrj_wj%A5UuU@6a2C-BxcfYM|#c||^#}Mx( zIJQ5z)``fih*w>_h?+JlfPjtv+2SWh*kAM zvBh&}cG2c!Rb5rOMmno{T2=LS6CR6B1{0#ry%#pp-$N}spmbf9xOBXL^^7^^e6_{F zlYL_em(FR$x4tyeZOiV)MaA96g$y=Vh50Te;tfm$p)Jn@7LEySOS}p}TzlGczFZVJ z7v=aTf|7e?BT+*Cc~rvWnzxeeNnZUm`#vb!?8IX$GEwP12hZxV+VcV1D`U*bum-@4 zZzGLvScBvoztL5=-M4PPrRreR^&3(0V^5&cbS;mWJh6{6c>7hYz@r|tnpb;z`!TP=#~%deI)^5+Mp9)QoldADR4txufN}mT zRtO%c9aeNgK4IZk2VXYzqDHWTNSl zrkmbQ1*BTqxBssDr?ExnpSBaSaNQmb)z7WM%NkUQcdDP8g?m&*0Se5m8{#ub3U)43`$dq9F}2C%)g;&)meNA9X$eY#U)gS?kn|20-D9PuawP55kt9;wu7Y=)F~6k z%4SU6>=9Ki=2-t8$DX?B5Y0EL{tWpeLA}kyD(fdK9%H|rYIQkn>nyP%Zi{8*KKT+W zYo?l$uRt9znWeR5L9&tPE^yZ`on<({nRFR>OP<+cV>K=bQMvRKo>i8_qs5n;I zC{<|4b&$@Y9!?*8i<+u-6BV1ZG&CM-W6WnHH1Jtnk{rG#6w=|bdcSJAG=F&JVX?X?S_9l^iRp$likoHyOnn${pYlH=piHoLTiH%*LF+JV1} zEmAn5=bfL7ehS5=zW5aCMkD_tsqM@xsoA8@VPpbAr-F zIa9&h5Xi1uLT>THrb>+|lJMTSIEr$$x0v2RLX%0eJg)I>h-?vCF{p?M|2m!l*CCDp z`#P?Xd^;=jPUm|VuXj@gG3AX<212685WvHHZyiVp zs8Niwm_VbPkd6hudF}TqTPB+=Slvzj#k7M>w$@4t9d;DQCS8o(X`FmFBMv+rW<*EX z1Bg*SC5ht=wdI{b9L8YEToqb<%G&SwUV#mYOyX7AyFAFNQbd$?e-fN^d%>kO!P!4H_JJKu@epnj*EVeFUl_A^Eh}_MstH8o_^=~wtCX^BUURHA43pyL zs~Xv`f4GvQ0$iZS(83Q=TvVojUw@;W$(|H=0jZ1Ci467RP6|ft*2_}l`x*6Bsq{h= zl2X5V2GqIYfVtt=yR4*{Q$>+x+4tX+OfP;41{Gft5l4?ODgxe zV4ov;%7b%y$duP@WdYHh){r+>#OhRx&&#?NfDdb#*U zo=Pe~(x2KaVZeIMEuvw|UjAD|18O)YLQ<1ykAT8a8z+2HlbBUR!=ys}7c0UPSUDZL z9*OE~&@8)b0iCvhtZ^fFB`o@CW06;a>Ud>Wllmmwkh{N%LxPacQ!waTHv5$5$bvVh z-Q?l%&llers5oo#YpBFOwNG57V4OB@zA4e=`#P4I7KdC9Rwkull;Mi_7liC`5u=&5 zkRG-uw0sr6oOA>_6o)M5C|B^J%e%*UhcZx^RuQ78$VaS~t!XprZi&NZoLPbv8h8O~ zD!5;lW|}zN0j{fJx1oy*F_r8;V=5~XVj63)#?huIu&VS9ey5|d6we~#-lac zV@ei>w77!kXup*}j7s}tK=ZnD@4&YQ7JL=oY-7So#W-EGEBHlDX1~FWOpmd;cv%Ck z*j|uC(_@rra4_i5!mBi?)6=a9?jWw`s7i_du^w8~kR58wM^e#}kI-u0DvSyVa3$3E zB|D zBMWU0xbUstf6)CV&(}Otr20k)RepviEnb~Dn2>H29byPQ*(8GMV4_(A2c9EXPERz1`8>7=>phA^#p!3!sKs=l2CjvA5`coa6 z#n=JFWKK04csJAW>QLa;*#E?#5*{&WqGBbrubCt1oqs)vdihX-gkYwP2{&w>Ny>flPVX#}e z!HJ_8`<-NFw1e#;vV{?5G;Nm@`L-N{{mwrVRdJ>H0+M8?>od4v!Kxe~@E`0}ZSYzE zDxdQhKgmP|=w!YT_^r2`;I{jg?~>AgCtXp#qkGFKxa-)oRk%ULt~{a%QNRmdv-=Pg zk1W}nV+{>r&s{9Wde=3Eh5tIuiv$uIVZ8$qLG!%t(laFj{(O2a@z;=}08$+cZ~hk@ zsWe@~+YDLhx~)d4z5i{*(r-aCuV$i92L{Lf^!CqQzuo5RD@L@P#C+z9ef&tLUxlR@tuLu(sFK~AS^fh9YvxA4DBKQz;PPQdf|4p#4Y zS2Ct>=t9Sj9^Ec;*erHSGW4=Y{-o2Q*k3YXd;Qfc+|1&Z${Qu9);OF{T zn!yjq83h!FKypTEa&~cPZn0ivVr~v?P5}WOjfCg?Cj%2h^z)xg%z#3p=YLQfyMzru zod1zJ!McdqfWxJF{vq)Kw+05y*j-;N8SR&PO)i{znSFOD=jQ&qPs?`4?z6Lh@V991 zzbkhyz5Dj<@Ao?2PZ~ECs2thkU-hkKOVR5D(WeubKbw3{dH3!2lT!~`WBFj+op-GEu3?m@-n7DAi*@DxFP?Ku`#(Jj`Y=V%Evi~R z`ABiiqpas#k0dh{=Q%H5YW3xDR-?Xsa+pGn+srrC&1TC|jxxPjQ!A;yc}=C8?#rMH hy(_=6RQ_cDaEIf?qS5k%aB3M Date: Sun, 27 Mar 2016 20:59:56 +0200 Subject: [PATCH 088/149] *.gem added --- bindings/ruby/unicorn_gem/pkg/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/ruby/unicorn_gem/pkg/.gitignore b/bindings/ruby/unicorn_gem/pkg/.gitignore index e394af59..b7e77251 100644 --- a/bindings/ruby/unicorn_gem/pkg/.gitignore +++ b/bindings/ruby/unicorn_gem/pkg/.gitignore @@ -7,4 +7,4 @@ /pkg/ /spec/reports/ /tmp/ -.gem +*.gem From 4a10a9f9e4fca8a732e34b602e3b96871a968296 Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Sun, 27 Mar 2016 21:00:33 +0200 Subject: [PATCH 089/149] sample for arm added --- bindings/ruby/sample_arm.rb | 106 ++++++++++++++++++++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 bindings/ruby/sample_arm.rb diff --git a/bindings/ruby/sample_arm.rb b/bindings/ruby/sample_arm.rb new file mode 100644 index 00000000..dd0e4a06 --- /dev/null +++ b/bindings/ruby/sample_arm.rb @@ -0,0 +1,106 @@ +#!/usr/bin/env ruby + +require 'unicorn' +require 'unicorn/arm_const' + +include Unicorn + +# code to be emulated +ARM_CODE = "\x37\x00\xa0\xe3\x03\x10\x42\xe0" # mov r0, #0x37; sub r1, r2, r3 +THUMB_CODE = "\x83\xb0" # sub sp, #0xc +# memory address where emulation starts +ADDRESS = 0x10000 + + +# callback for tracing basic blocks +$hook_block = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing basic block at 0x%x, block size = 0x%x" % [address, size]) +end + + +# callback for tracing instructions +$hook_code = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing instruction at 0x%x, instruction size = %u" % [address, size]) +end + + +# Test ARM +def test_arm() + puts("Emulate ARM code") + begin + # Initialize emulator in ARM mode + mu = Uc.new UC_ARCH_ARM, UC_MODE_ARM + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, ARM_CODE) + + # initialize machine registers + mu.reg_write(UC_ARM_REG_R0, 0x1234) + mu.reg_write(UC_ARM_REG_R2, 0x6789) + mu.reg_write(UC_ARM_REG_R3, 0x3333) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, $hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, $hook_code) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + ARM_CODE.bytesize) + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + r0 = mu.reg_read(UC_ARM_REG_R0) + r1 = mu.reg_read(UC_ARM_REG_R1) + puts(">>> R0 = 0x%x" % r0) + puts(">>> R1 = 0x%x" % r1) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +def test_thumb() + puts("Emulate THUMB code") + begin + # Initialize emulator in thumb mode + mu = Uc.new UC_ARCH_ARM, UC_MODE_THUMB + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, THUMB_CODE) + + # initialize machine registers + mu.reg_write(UC_ARM_REG_SP, 0x1234) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, $hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, $hook_code) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + THUMB_CODE.bytesize) + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + sp = mu.reg_read(UC_ARM_REG_SP) + puts(">>> SP = 0x%x" % sp) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +test_arm() +puts("=" * 20) +test_thumb() From 40c8f0540cb62033b4f140e38707ece962eb232d Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Sun, 27 Mar 2016 21:15:45 +0200 Subject: [PATCH 090/149] sample for arm64 added --- bindings/ruby/sample_arm64.rb | 69 +++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) create mode 100644 bindings/ruby/sample_arm64.rb diff --git a/bindings/ruby/sample_arm64.rb b/bindings/ruby/sample_arm64.rb new file mode 100644 index 00000000..45b0c9c6 --- /dev/null +++ b/bindings/ruby/sample_arm64.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby +# Sample code for ARM64 of Unicorn. Nguyen Anh Quynh +# Ruby sample ported by Sascha Schirra +require 'unicorn' +require 'unicorn/arm64_const' + +include Unicorn + +# code to be emulated +ARM64_CODE = "\xab\x01\x0f\x8b" #add x11, x13, x15 + +# memory address where emulation starts +ADDRESS = 0x10000 + + +# callback for tracing basic blocks +$hook_block = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing basic block at 0x%x, block size = 0x%x" % [address, size]) +end + + +# callback for tracing instructions +$hook_code = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing instruction at 0x%x, instruction size = %u" % [address, size]) +end + + +# Test ARM64 +def test_arm64() + puts("Emulate ARM64 code") + begin + # Initialize emulator in ARM mode + mu = Uc.new UC_ARCH_ARM64, UC_MODE_ARM + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, ARM64_CODE) + + # initialize machine registers + mu.reg_write(UC_ARM64_REG_X11, 0x1234) + mu.reg_write(UC_ARM64_REG_X13, 0x6789) + mu.reg_write(UC_ARM64_REG_X15, 0x3333) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, $hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, $hook_code) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + ARM64_CODE.bytesize) + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + x11 = mu.reg_read(UC_ARM64_REG_X11) + x13 = mu.reg_read(UC_ARM64_REG_X13) + x15 = mu.reg_read(UC_ARM64_REG_X15) + puts(">>> X11 = 0x%x" % x11) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +test_arm64() From 6c54b8e2834f99fbdb95125f1983ab5c3a065182 Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Sun, 27 Mar 2016 21:31:34 +0200 Subject: [PATCH 091/149] sample for m68k added --- bindings/ruby/sample_m68k.rb | 65 ++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 bindings/ruby/sample_m68k.rb diff --git a/bindings/ruby/sample_m68k.rb b/bindings/ruby/sample_m68k.rb new file mode 100644 index 00000000..1acff39f --- /dev/null +++ b/bindings/ruby/sample_m68k.rb @@ -0,0 +1,65 @@ +#!/usr/bin/env ruby +# Sample code for ARM of Unicorn. Nguyen Anh Quynh +# Ruby sample ported by Sascha Schirra + +require 'unicorn' +require 'unicorn/m68k_const' + +include Unicorn + +# code to be emulated +M68K_CODE = "\x76\xed" # movq #-19, %d3 +# memory address where emulation starts +ADDRESS = 0x10000 + + +# callback for tracing basic blocks +$hook_block = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing basic block at 0x%x, block size = 0x%x" % [address, size]) +end + + +# callback for tracing instructions +$hook_code = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing instruction at 0x%x, instruction size = %u" % [address, size]) +end + + +# Test m68k +def test_m68k() + puts("Emulate M68K code") + begin + # Initialize emulator in m68k mode + mu = Uc.new UC_ARCH_M68K, UC_MODE_BIG_ENDIAN + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, M68K_CODE) + + # initialize machine registers + mu.reg_write(UC_M68K_REG_D3, 0x1234) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, $hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, $hook_code) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + M68K_CODE.bytesize) + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + d3 = mu.reg_read(UC_M68K_REG_D3) + puts(">>> D3 = 0x%x" % d3) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +test_m68k() From 30d26366f6576ffff6cd2629845d57a647394a3a Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Sun, 27 Mar 2016 21:38:46 +0200 Subject: [PATCH 092/149] sample for mips added --- bindings/ruby/sample_mips.rb | 104 +++++++++++++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 bindings/ruby/sample_mips.rb diff --git a/bindings/ruby/sample_mips.rb b/bindings/ruby/sample_mips.rb new file mode 100644 index 00000000..ec30e87d --- /dev/null +++ b/bindings/ruby/sample_mips.rb @@ -0,0 +1,104 @@ +#!/usr/bin/env ruby +# Sample code for MIPS of Unicorn. Nguyen Anh Quynh +# Ruby sample ported by Sascha Schirra +require 'unicorn' +require 'unicorn/mips_const' + +include Unicorn + +# code to be emulated +MIPS_CODE_EB = "\x34\x21\x34\x56" # ori $at, $at, 0x3456; +MIPS_CODE_EL = "\x56\x34\x21\x34" # ori $at, $at, 0x3456; + +# memory address where emulation starts +ADDRESS = 0x10000 + + +# callback for tracing basic blocks +$hook_block = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing basic block at 0x%x, block size = 0x%x" % [address, size]) +end + + +# callback for tracing instructions +$hook_code = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing instruction at 0x%x, instruction size = %u" % [address, size]) +end + +# Test MIPS EB +def test_mips_eb() + puts("Emulate MIPS code (big-endian)") + begin + # Initialize emulator in MIPS32 + EB mode + mu = Uc.new UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, MIPS_CODE_EB) + + # initialize machine registers + mu.reg_write(UC_MIPS_REG_1, 0x6789) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, $hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, $hook_code) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + MIPS_CODE_EB.bytesize) + + # now puts out some registers + puts(">>> Emulation done. Below is the CPU context") + + r1 = mu.reg_read(UC_MIPS_REG_1) + puts(">>> r1 = 0x%x" % r1) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +# Test MIPS EL +def test_mips_el() + puts("Emulate MIPS code (little-endian)") + begin + # Initialize emulator in MIPS32 + EL mode + mu = Uc.new UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, MIPS_CODE_EL) + + # initialize machine registers + mu.reg_write(UC_MIPS_REG_1, 0x6789) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, $hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, $hook_code) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + MIPS_CODE_EL.bytesize) + + # now puts out some registers + puts(">>> Emulation done. Below is the CPU context") + + r1 = mu.reg_read(UC_MIPS_REG_1) + puts(">>> r1 = 0x%x" % r1) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +test_mips_eb() +puts("=" * 20) +test_mips_el() From cf1c7ee7cabd6bb90d730ed4591f27cd99e259a2 Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Sun, 27 Mar 2016 21:44:09 +0200 Subject: [PATCH 093/149] sample for sparc added --- bindings/ruby/sample_sparc.rb | 65 +++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 bindings/ruby/sample_sparc.rb diff --git a/bindings/ruby/sample_sparc.rb b/bindings/ruby/sample_sparc.rb new file mode 100644 index 00000000..052be189 --- /dev/null +++ b/bindings/ruby/sample_sparc.rb @@ -0,0 +1,65 @@ +#!/usr/bin/env ruby +# Sample code for SPARC of Unicorn. Nguyen Anh Quynh +# Ruby sample ported by Sascha Schirra +require 'unicorn' +require 'unicorn/sparc_const' + +include Unicorn + +# code to be emulated +SPARC_CODE = "\x86\x00\x40\x02" # add %g1, %g2, %g3; +# memory address where emulation starts +ADDRESS = 0x10000 + + +# callback for tracing basic blocks +$hook_block = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing basic block at 0x%x, block size = 0x%x" % [address, size]) +end + + +# callback for tracing instructions +$hook_code = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing instruction at 0x%x, instruction size = %u" % [address, size]) +end + +# Test SPARC +def test_sparc() + puts("Emulate SPARC code") + begin + # Initialize emulator in SPARC EB mode + mu = Uc.new UC_ARCH_SPARC, UC_MODE_SPARC32|UC_MODE_BIG_ENDIAN + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, SPARC_CODE) + + # initialize machine registers + mu.reg_write(UC_SPARC_REG_G1, 0x1230) + mu.reg_write(UC_SPARC_REG_G2, 0x6789) + mu.reg_write(UC_SPARC_REG_G3, 0x5555) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, $hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, $hook_code) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + SPARC_CODE.bytesize) + + # now puts out some registers + puts(">>> Emulation done. Below is the CPU context") + + g3 = mu.reg_read(UC_SPARC_REG_G3) + puts(">>> G3 = 0x%x" %g3) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +test_sparc() From 5d4fb062d413abc1d43d82542f50ed2ed8602e6b Mon Sep 17 00:00:00 2001 From: Sascha Schirra Date: Sun, 27 Mar 2016 22:04:33 +0200 Subject: [PATCH 094/149] set gdt example added --- bindings/ruby/sample_x86_gdt.rb | 97 +++++++++++++++++++++++++++++++++ 1 file changed, 97 insertions(+) create mode 100644 bindings/ruby/sample_x86_gdt.rb diff --git a/bindings/ruby/sample_x86_gdt.rb b/bindings/ruby/sample_x86_gdt.rb new file mode 100644 index 00000000..ea6c9431 --- /dev/null +++ b/bindings/ruby/sample_x86_gdt.rb @@ -0,0 +1,97 @@ +#!/usr/bin/env ruby +require 'unicorn' +require 'unicorn/x86_const' + +include Unicorn + +F_GRANULARITY = 0x8 +F_PROT_32 = 0x4 +F_LONG = 0x2 +F_AVAILABLE = 0x1 + +A_PRESENT = 0x80 + +A_PRIV_3 = 0x60 +A_PRIV_2 = 0x40 +A_PRIV_1 = 0x20 +A_PRIV_0 = 0x0 + +A_CODE = 0x10 +A_DATA = 0x10 +A_TSS = 0x0 +A_GATE = 0x0 + +A_DATA_WRITABLE = 0x2 +A_CODE_READABLE = 0x2 + +A_DIR_CON_BIT = 0x4 + +S_GDT = 0x0 +S_LDT = 0x4 +S_PRIV_3 = 0x3 +S_PRIV_2 = 0x2 +S_PRIV_1 = 0x1 +S_PRIV_0 = 0x0 + +def create_selector(idx, flags) + to_ret = flags + to_ret |= idx << 3 + return to_ret +end + +def create_gdt_entry(base, limit, access, flags) + + to_ret = limit & 0xffff; + to_ret |= (base & 0xffffff) << 16; + to_ret |= (access & 0xff) << 40; + to_ret |= ((limit >> 16) & 0xf) << 48; + to_ret |= (flags & 0xff) << 52; + to_ret |= ((base >> 24) & 0xff) << 56; + return [to_ret].pack('Q') +end + +def write_gdt(uc, gdt, mem) + gdt.each_index do |idx| + offset = idx * GDT_ENTRY_SIZE + uc.mem_write(mem + offset, gdt[idx]) + end +end + +CODE_ADDR = 0x40000 +CODE_SIZE = 0x1000 + +GDT_ADDR = 0x3000 +GDT_LIMIT = 0x1000 +GDT_ENTRY_SIZE = 0x8 + +GS_SEGMENT_ADDR = 0x5000 +GS_SEGMENT_SIZE = 0x1000 + +uc = Uc.new UC_ARCH_X86, UC_MODE_32 + +uc.mem_map(GDT_ADDR, GDT_LIMIT) +uc.mem_map(GS_SEGMENT_ADDR, GS_SEGMENT_SIZE) +uc.mem_map(CODE_ADDR, CODE_SIZE) + +gdt = Array.new (31) {|i| create_gdt_entry(0,0,0,0)} +gdt[15] = create_gdt_entry(GS_SEGMENT_ADDR, GS_SEGMENT_SIZE, A_PRESENT | A_DATA | A_DATA_WRITABLE | A_PRIV_3 | A_DIR_CON_BIT, F_PROT_32) +gdt[16] = create_gdt_entry(0, 0xfffff000 , A_PRESENT | A_DATA | A_DATA_WRITABLE | A_PRIV_3 | A_DIR_CON_BIT, F_PROT_32) # Data Segment +gdt[17] = create_gdt_entry(0, 0xfffff000 , A_PRESENT | A_CODE | A_CODE_READABLE | A_PRIV_3 | A_DIR_CON_BIT, F_PROT_32) # Code Segment +gdt[18] = create_gdt_entry(0, 0xfffff000 , A_PRESENT | A_DATA | A_DATA_WRITABLE | A_PRIV_0 | A_DIR_CON_BIT, F_PROT_32) # Stack Segment + +write_gdt(uc, gdt, GDT_ADDR) +uc.reg_write(UC_X86_REG_GDTR, [0, GDT_ADDR, gdt.length * GDT_ENTRY_SIZE-1, 0x0]) + +selector = create_selector(15, S_GDT | S_PRIV_3) +uc.reg_write(UC_X86_REG_GS, selector) + +selector = create_selector(16, S_GDT | S_PRIV_3) +uc.reg_write(UC_X86_REG_DS, selector) + +selector = create_selector(17, S_GDT | S_PRIV_3) +uc.reg_write(UC_X86_REG_CS, selector) + +selector = create_selector(18, S_GDT | S_PRIV_0) +uc.reg_write(UC_X86_REG_SS, selector) + + From 3ca072e0de57063cf303297939bb74f71472813e Mon Sep 17 00:00:00 2001 From: Chris Eagle Date: Mon, 28 Mar 2016 09:29:55 -0700 Subject: [PATCH 095/149] pack SegmentDescriptor to eliminate any alignment ambiguity --- samples/sample_x86_32_gdt_and_seg_regs.c | 70 ++++++++++++------------ 1 file changed, 36 insertions(+), 34 deletions(-) diff --git a/samples/sample_x86_32_gdt_and_seg_regs.c b/samples/sample_x86_32_gdt_and_seg_regs.c index be226cf5..c3531619 100644 --- a/samples/sample_x86_32_gdt_and_seg_regs.c +++ b/samples/sample_x86_32_gdt_and_seg_regs.c @@ -26,42 +26,44 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include #include +#pragma pack(push, 1) struct SegmentDescriptor { - union { - struct { -# if __BYTE_ORDER == __LITTLE_ENDIAN - unsigned short limit0; - unsigned short base0; - unsigned char base1; - unsigned int type:4; - unsigned int system:1; /* S flag */ - unsigned int dpl:2; - unsigned int present:1; /* P flag */ - unsigned int limit1:4; - unsigned int avail:1; - unsigned int is_64_code:1; /* L flag */ - unsigned int db:1; /* DB flag */ - unsigned int granularity:1; /* G flag */ - unsigned char base2; -# else - unsigned char base2; - unsigned int granularity:1; /* G flag */ - unsigned int db:1; /* DB flag */ - unsigned int is_64_code:1; /* L flag */ - unsigned int avail:1; - unsigned int limit1:4; - unsigned int present:1; /* P flag */ - unsigned int dpl:2; - unsigned int system:1; /* S flag */ - unsigned int type:4; - unsigned char base1; - unsigned short base0; - unsigned short limit0; -# endif - }; - uint64_t desc; - }; + union { + struct { +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned short limit0; + unsigned short base0; + unsigned char base1; + unsigned char type:4; + unsigned char system:1; /* S flag */ + unsigned char dpl:2; + unsigned char present:1; /* P flag */ + unsigned char limit1:4; + unsigned char avail:1; + unsigned char is_64_code:1; /* L flag */ + unsigned char db:1; /* DB flag */ + unsigned char granularity:1; /* G flag */ + unsigned char base2; +#else + unsigned char base2; + unsigned char granularity:1; /* G flag */ + unsigned char db:1; /* DB flag */ + unsigned char is_64_code:1; /* L flag */ + unsigned char avail:1; + unsigned char limit1:4; + unsigned char present:1; /* P flag */ + unsigned char dpl:2; + unsigned char system:1; /* S flag */ + unsigned char type:4; + unsigned char base1; + unsigned short base0; + unsigned short limit0; +#endif + }; + uint64_t desc; + }; }; +#pragma pack(pop) #define SEGBASE(d) ((uint32_t)((((d).desc >> 16) & 0xffffff) | (((d).desc >> 32) & 0xff000000))) #define SEGLIMIT(d) ((d).limit0 | (((unsigned int)(d).limit1) << 16)) From 76786850c4918f6bbc25ab7bc9cd1a489831d924 Mon Sep 17 00:00:00 2001 From: Jurriaan Bremer Date: Sat, 26 Mar 2016 16:24:19 +0100 Subject: [PATCH 096/149] code cleanup of python bindings Addresses a couple of pep8 related changes improving the code quality. --- bindings/python/unicorn/unicorn.py | 276 ++++++++++++++++------------- 1 file changed, 152 insertions(+), 124 deletions(-) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index dc1a2ac9..e1c94491 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -1,42 +1,55 @@ # Unicorn Python bindings, by Nguyen Anh Quynnh + +import ctypes +import ctypes.util +import distutils.sysconfig +import inspect +import os.path +import platform import sys + +from . import x86_const, unicorn_const as uc + +if not hasattr(sys.modules[__name__], "__file__"): + __file__ = inspect.getfile(inspect.currentframe()) + _python2 = sys.version_info[0] < 3 if _python2: range = xrange -from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const -from .unicorn_const import * -import ctypes, ctypes.util, sys -from platform import system -from os.path import split, join, dirname, exists -import distutils.sysconfig +_lib_path = os.path.split(__file__)[0] +_all_libs = ( + "unicorn.dll", + "libunicorn.so", + "libunicorn.dylib", +) - -import inspect -if not hasattr(sys.modules[__name__], '__file__'): - __file__ = inspect.getfile(inspect.currentframe()) - -_lib_path = split(__file__)[0] -_all_libs = ('unicorn.dll', 'libunicorn.so', 'libunicorn.dylib') # Windows DLL in dependency order -_all_windows_dlls = ("libwinpthread-1.dll", "libgcc_s_seh-1.dll", "libgcc_s_dw2-1.dll", "libiconv-2.dll", "libintl-8.dll", "libglib-2.0-0.dll") +_all_windows_dlls = ( + "libwinpthread-1.dll", + "libgcc_s_seh-1.dll", + "libgcc_s_dw2-1.dll", + "libiconv-2.dll", + "libintl-8.dll", + "libglib-2.0-0.dll", +) _found = False for _lib in _all_libs: try: - if _lib == 'unicorn.dll': + if _lib == "unicorn.dll": for dll in _all_windows_dlls: # load all the rest DLLs first - _lib_file = join(_lib_path, dll) - if exists(_lib_file): + _lib_file = os.path.join(_lib_path, dll) + if os.path.exists(_lib_file): ctypes.cdll.LoadLibrary(_lib_file) - _lib_file = join(_lib_path, _lib) + _lib_file = os.path.join(_lib_path, _lib) _uc = ctypes.cdll.LoadLibrary(_lib_file) _found = True break except OSError: pass -if _found == False: +if not _found: # try loading from default paths for _lib in _all_libs: try: @@ -46,17 +59,17 @@ if _found == False: except OSError: pass -if _found == False: +if not _found: # last try: loading from python lib directory _lib_path = distutils.sysconfig.get_python_lib() for _lib in _all_libs: try: - if _lib == 'unicorn.dll': + if _lib == "unicorn.dll": for dll in _all_windows_dlls: # load all the rest DLLs first - _lib_file = join(_lib_path, 'unicorn', dll) - if exists(_lib_file): + _lib_file = os.path.join(_lib_path, "unicorn", dll) + if os.path.exists(_lib_file): ctypes.cdll.LoadLibrary(_lib_file) - _lib_file = join(_lib_path, 'unicorn', _lib) + _lib_file = os.path.join(_lib_path, "unicorn", _lib) _uc = ctypes.cdll.LoadLibrary(_lib_file) _found = True break @@ -65,11 +78,11 @@ if _found == False: # Attempt Darwin specific load (10.11 specific), # since LD_LIBRARY_PATH is not guaranteed to exist -if (_found == False) and (system() == 'Darwin'): - _lib_path = '/usr/local/lib/' +if not _found and platform.system() == "Darwin": + _lib_path = "/usr/local/lib/" for _lib in _all_libs: try: - _lib_file = join(_lib_path, _lib) + _lib_file = os.path.join(_lib_path, _lib) # print "Trying to load:", _lib_file _uc = ctypes.cdll.LoadLibrary(_lib_file) _found = True @@ -77,11 +90,11 @@ if (_found == False) and (system() == 'Darwin'): except OSError: pass -if _found == False: +if not _found: raise ImportError("ERROR: fail to load the dynamic library.") -__version__ = "%s.%s" %(UC_API_MAJOR, UC_API_MINOR) +__version__ = "%s.%s" % (uc.UC_API_MAJOR, uc.UC_API_MINOR) # setup all the function prototype def _setup_prototype(lib, fname, restype, *argtypes): @@ -112,20 +125,28 @@ _setup_prototype(_uc, "uc_mem_protect", ucerr, uc_engine, ctypes.c_uint64, ctype _setup_prototype(_uc, "uc_query", ucerr, uc_engine, ctypes.c_uint32, ctypes.POINTER(ctypes.c_size_t)) # uc_hook_add is special due to variable number of arguments -_uc.uc_hook_add = getattr(_uc, "uc_hook_add") +_uc.uc_hook_add = _uc.uc_hook_add _uc.uc_hook_add.restype = ucerr UC_HOOK_CODE_CB = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_void_p) -UC_HOOK_MEM_INVALID_CB = ctypes.CFUNCTYPE(ctypes.c_bool, uc_engine, ctypes.c_int, \ - ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p) -UC_HOOK_MEM_ACCESS_CB = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_int, \ - ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p) -UC_HOOK_INTR_CB = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_uint32, \ - ctypes.c_void_p) -UC_HOOK_INSN_IN_CB = ctypes.CFUNCTYPE(ctypes.c_uint32, uc_engine, ctypes.c_uint32, \ - ctypes.c_int, ctypes.c_void_p) -UC_HOOK_INSN_OUT_CB = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_uint32, \ - ctypes.c_int, ctypes.c_uint32, ctypes.c_void_p) +UC_HOOK_MEM_INVALID_CB = ctypes.CFUNCTYPE( + ctypes.c_bool, uc_engine, ctypes.c_int, + ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p +) +UC_HOOK_MEM_ACCESS_CB = ctypes.CFUNCTYPE( + None, uc_engine, ctypes.c_int, + ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p +) +UC_HOOK_INTR_CB = ctypes.CFUNCTYPE( + None, uc_engine, ctypes.c_uint32, ctypes.c_void_p +) +UC_HOOK_INSN_IN_CB = ctypes.CFUNCTYPE( + ctypes.c_uint32, uc_engine, ctypes.c_uint32, ctypes.c_int, ctypes.c_void_p +) +UC_HOOK_INSN_OUT_CB = ctypes.CFUNCTYPE( + None, uc_engine, ctypes.c_uint32, + ctypes.c_int, ctypes.c_uint32, ctypes.c_void_p +) UC_HOOK_INSN_SYSCALL_CB = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_void_p) @@ -148,7 +169,10 @@ def uc_version(): # return the binding's version def version_bind(): - return (UC_API_MAJOR, UC_API_MINOR, (UC_API_MAJOR << 8) + UC_API_MINOR) + return ( + uc.UC_API_MAJOR, uc.UC_API_MINOR, + (uc.UC_API_MAJOR << 8) + uc.UC_API_MINOR, + ) # check to see if this engine supports a particular arch @@ -157,36 +181,36 @@ def uc_arch_supported(query): class uc_x86_mmr(ctypes.Structure): - '''Memory-Management Register for instructions IDTR, GDTR, LDTR, TR.''' + """Memory-Management Register for instructions IDTR, GDTR, LDTR, TR.""" _fields_ = [ ("selector", ctypes.c_uint16), # not used by GDTR and IDTR ("base", ctypes.c_uint64), # handle 32 or 64 bit CPUs ("limit", ctypes.c_uint32), ("flags", ctypes.c_uint32), # not used by GDTR and IDTR - ] + ] class uc_x86_float80(ctypes.Structure): - '''Float80''' + """Float80""" _fields_ = [ ("mantissa", ctypes.c_uint64), ("exponent", ctypes.c_uint16), - ] + ] class Uc(object): def __init__(self, arch, mode): # verify version compatibility with the core before doing anything (major, minor, _combined) = uc_version() - if major != UC_API_MAJOR or minor != UC_API_MINOR: + if major != uc.UC_API_MAJOR or minor != uc.UC_API_MINOR: self._uch = None # our binding version is different from the core's API version - raise UcError(UC_ERR_VERSION) + raise UcError(uc.UC_ERR_VERSION) self._arch, self._mode = arch, mode self._uch = ctypes.c_void_p() status = _uc.uc_open(arch, mode, ctypes.byref(self._uch)) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: self._uch = None raise UcError(status) # internal mapping table to save callback & userdata @@ -194,177 +218,158 @@ class Uc(object): self._ctype_cbs = {} self._callback_count = 0 - # destructor to be called automatically when object is destroyed. def __del__(self): if self._uch: try: status = _uc.uc_close(self._uch) self._uch = None - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) - except: # _uc might be pulled from under our feet + except: # _uc might be pulled from under our feet pass - # emulate from @begin, and stop when reaching address @until def emu_start(self, begin, until, timeout=0, count=0): status = _uc.uc_emu_start(self._uch, begin, until, timeout, count) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) - # stop emulation def emu_stop(self): status = _uc.uc_emu_stop(self._uch) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) - # return the value of a register def reg_read(self, reg_id): - if self._arch == UC_ARCH_X86: - if reg_id in [ x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]: + if self._arch == uc.UC_ARCH_X86: + if reg_id in [x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]: reg = uc_x86_mmr() status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg)) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) - return (reg.selector,reg.base, reg.limit, reg.flags) - if reg_id in range(x86_const.UC_X86_REG_FP0,x86_const.UC_X86_REG_FP0+8): + return reg.selector, reg.base, reg.limit, reg.flags + if reg_id in range(x86_const.UC_X86_REG_FP0, x86_const.UC_X86_REG_FP0+8): reg = uc_x86_float80() status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg)) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) - return (reg.mantissa, reg.exponent) + return reg.mantissa, reg.exponent # read to 64bit number to be safe reg = ctypes.c_int64(0) status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg)) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) return reg.value - # write to a register def reg_write(self, reg_id, value): reg = None - if self._arch == UC_ARCH_X86: - if reg_id in [ x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]: - assert isinstance(value, tuple) and len(value)==4 + if self._arch == uc.UC_ARCH_X86: + if reg_id in [x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]: + assert isinstance(value, tuple) and len(value) == 4 reg = uc_x86_mmr() - reg.selector=value[0] - reg.base=value[1] - reg.limit=value[2] - reg.flags=value[3] + reg.selector = value[0] + reg.base = value[1] + reg.limit = value[2] + reg.flags = value[3] if reg_id in range(x86_const.UC_X86_REG_FP0, x86_const.UC_X86_REG_FP0+8): reg = uc_x86_float80() reg.mantissa = value[0] reg.exponent = value[1] - + if reg is None: # convert to 64bit number to be safe reg = ctypes.c_int64(value) status = _uc.uc_reg_write(self._uch, reg_id, ctypes.byref(reg)) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) - # read data from memory def mem_read(self, address, size): data = ctypes.create_string_buffer(size) status = _uc.uc_mem_read(self._uch, address, data, size) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) return bytearray(data) - # write to memory def mem_write(self, address, data): status = _uc.uc_mem_write(self._uch, address, data, len(data)) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) - # map a range of memory - def mem_map(self, address, size, perms=UC_PROT_ALL): + def mem_map(self, address, size, perms=uc.UC_PROT_ALL): status = _uc.uc_mem_map(self._uch, address, size, perms) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) - # map a range of memory from a raw host memory address def mem_map_ptr(self, address, size, perms, ptr): status = _uc.uc_mem_map_ptr(self._uch, address, size, perms, ptr) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) - # unmap a range of memory def mem_unmap(self, address, size): status = _uc.uc_mem_unmap(self._uch, address, size) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) - # protect a range of memory - def mem_protect(self, address, size, perms=UC_PROT_ALL): + def mem_protect(self, address, size, perms=uc.UC_PROT_ALL): status = _uc.uc_mem_protect(self._uch, address, size, perms) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) # return CPU mode at runtime def query(self, query_mode): result = ctypes.c_size_t(0) status = _uc.uc_query(self._uch, query_mode, ctypes.byref(result)) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) return result.value - def _hookcode_cb(self, handle, address, size, user_data): # call user's callback with self object (cb, data) = self._callbacks[user_data] cb(self, address, size, data) - def _hook_mem_invalid_cb(self, handle, access, address, size, value, user_data): # call user's callback with self object (cb, data) = self._callbacks[user_data] return cb(self, access, address, size, value, data) - def _hook_mem_access_cb(self, handle, access, address, size, value, user_data): # call user's callback with self object (cb, data) = self._callbacks[user_data] cb(self, access, address, size, value, data) - def _hook_intr_cb(self, handle, intno, user_data): # call user's callback with self object (cb, data) = self._callbacks[user_data] cb(self, intno, data) - def _hook_insn_in_cb(self, handle, port, size, user_data): # call user's callback with self object (cb, data) = self._callbacks[user_data] return cb(self, port, size, data) - def _hook_insn_out_cb(self, handle, port, size, value, user_data): # call user's callback with self object (cb, data) = self._callbacks[user_data] cb(self, port, size, value, data) - def _hook_insn_syscall_cb(self, handle, user_data): # call user's callback with self object (cb, data) = self._callbacks[user_data] cb(self, data) - # add a hook def hook_add(self, htype, callback, user_data=None, begin=1, end=0, arg1=0): _h2 = uc_hook_h() @@ -374,61 +379,83 @@ class Uc(object): self._callbacks[self._callback_count] = (callback, user_data) cb = None - if htype == UC_HOOK_INSN: + if htype == uc.UC_HOOK_INSN: insn = ctypes.c_int(arg1) if arg1 == x86_const.UC_X86_INS_IN: # IN instruction cb = ctypes.cast(UC_HOOK_INSN_IN_CB(self._hook_insn_in_cb), UC_HOOK_INSN_IN_CB) - if arg1 == x86_const.UC_X86_INS_OUT: # OUT instruction + if arg1 == x86_const.UC_X86_INS_OUT: # OUT instruction cb = ctypes.cast(UC_HOOK_INSN_OUT_CB(self._hook_insn_out_cb), UC_HOOK_INSN_OUT_CB) - if arg1 in (x86_const.UC_X86_INS_SYSCALL, x86_const.UC_X86_INS_SYSENTER): # SYSCALL/SYSENTER instruction + if arg1 in (x86_const.UC_X86_INS_SYSCALL, x86_const.UC_X86_INS_SYSENTER): # SYSCALL/SYSENTER instruction cb = ctypes.cast(UC_HOOK_INSN_SYSCALL_CB(self._hook_insn_syscall_cb), UC_HOOK_INSN_SYSCALL_CB) - status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \ - cb, ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end), insn) - elif htype == UC_HOOK_INTR: + status = _uc.uc_hook_add( + self._uch, ctypes.byref(_h2), htype, cb, + ctypes.cast(self._callback_count, ctypes.c_void_p), + ctypes.c_uint64(begin), ctypes.c_uint64(end), insn + ) + elif htype == uc.UC_HOOK_INTR: cb = ctypes.cast(UC_HOOK_INTR_CB(self._hook_intr_cb), UC_HOOK_INTR_CB) - status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \ - cb, ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end)) + status = _uc.uc_hook_add( + self._uch, ctypes.byref(_h2), htype, cb, + ctypes.cast(self._callback_count, ctypes.c_void_p), + ctypes.c_uint64(begin), ctypes.c_uint64(end) + ) else: - if htype in (UC_HOOK_BLOCK, UC_HOOK_CODE): + if htype in (uc.UC_HOOK_BLOCK, uc.UC_HOOK_CODE): # set callback with wrapper, so it can be called # with this object as param cb = ctypes.cast(UC_HOOK_CODE_CB(self._hookcode_cb), UC_HOOK_CODE_CB) - status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, cb, \ - ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end)) - elif htype & UC_HOOK_MEM_READ_UNMAPPED or htype & UC_HOOK_MEM_WRITE_UNMAPPED or \ - htype & UC_HOOK_MEM_FETCH_UNMAPPED or htype & UC_HOOK_MEM_READ_PROT or \ - htype & UC_HOOK_MEM_WRITE_PROT or htype & UC_HOOK_MEM_FETCH_PROT: + status = _uc.uc_hook_add( + self._uch, ctypes.byref(_h2), htype, cb, + ctypes.cast(self._callback_count, ctypes.c_void_p), + ctypes.c_uint64(begin), ctypes.c_uint64(end) + ) + elif htype & (uc.UC_HOOK_MEM_READ_UNMAPPED | + uc.UC_HOOK_MEM_WRITE_UNMAPPED | + uc.UC_HOOK_MEM_FETCH_UNMAPPED | + uc.UC_HOOK_MEM_READ_PROT | + uc.UC_HOOK_MEM_WRITE_PROT | + uc.UC_HOOK_MEM_FETCH_PROT): cb = ctypes.cast(UC_HOOK_MEM_INVALID_CB(self._hook_mem_invalid_cb), UC_HOOK_MEM_INVALID_CB) - status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \ - cb, ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end)) + status = _uc.uc_hook_add( + self._uch, ctypes.byref(_h2), htype, cb, + ctypes.cast(self._callback_count, ctypes.c_void_p), + ctypes.c_uint64(begin), ctypes.c_uint64(end) + ) else: cb = ctypes.cast(UC_HOOK_MEM_ACCESS_CB(self._hook_mem_access_cb), UC_HOOK_MEM_ACCESS_CB) - status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \ - cb, ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end)) + status = _uc.uc_hook_add( + self._uch, ctypes.byref(_h2), htype, cb, + ctypes.cast(self._callback_count, ctypes.c_void_p), + ctypes.c_uint64(begin), ctypes.c_uint64(end) + ) # save the ctype function so gc will leave it alone. self._ctype_cbs[self._callback_count] = cb - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) return _h2.value - # delete a hook def hook_del(self, h): _h = uc_hook_h(h) status = _uc.uc_hook_del(self._uch, _h) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) h = 0 # print out debugging info def debug(): - archs = { "arm": UC_ARCH_ARM, "arm64": UC_ARCH_ARM64, \ - "mips": UC_ARCH_MIPS, "sparc": UC_ARCH_SPARC, \ - "m68k": UC_ARCH_M68K, "x86": UC_ARCH_X86 } + archs = { + "arm": uc.UC_ARCH_ARM, + "arm64": uc.UC_ARCH_ARM64, + "mips": uc.UC_ARCH_MIPS, + "sparc": uc.UC_ARCH_SPARC, + "m68k": uc.UC_ARCH_M68K, + "x86": uc.UC_ARCH_X86, + } all_archs = "" keys = archs.keys() @@ -436,7 +463,8 @@ def debug(): if uc_arch_supported(archs[k]): all_archs += "-%s" % k - (major, minor, _combined) = uc_version() + major, minor, _combined = uc_version() - return "python-%s-c%u.%u-b%u.%u" % (all_archs, major, minor, UC_API_MAJOR, UC_API_MINOR) - + return "python-%s-c%u.%u-b%u.%u" % ( + all_archs, major, minor, uc.UC_API_MAJOR, uc.UC_API_MINOR + ) From 8cd23bceadb6eb08b55cd302e374fcb50be6791a Mon Sep 17 00:00:00 2001 From: Zach Riggle Date: Wed, 30 Mar 2016 20:57:48 -0400 Subject: [PATCH 097/149] Add test case for unicorn-engine/unicorn#499 --- tests/regress/x86_64_eflags.py | 38 ++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 tests/regress/x86_64_eflags.py diff --git a/tests/regress/x86_64_eflags.py b/tests/regress/x86_64_eflags.py new file mode 100644 index 00000000..ca7c48d1 --- /dev/null +++ b/tests/regress/x86_64_eflags.py @@ -0,0 +1,38 @@ +#!/usr/bin/python +import regress +import unicorn as U + +class WrongEFLAGS(regress.RegressTest): + def test_eflags(self): + # xor r14,r14 + CODE = 'M1\xf6' + + uc = U.Uc(U.UC_ARCH_X86, U.UC_MODE_64) + uc.reg_write(U.x86_const.UC_X86_REG_RIP, 0x6000b0) + uc.reg_write(U.x86_const.UC_X86_REG_EFLAGS, 0x200) + + uc.mem_map(0x600000, 0x1000) + uc.mem_write(0x6000b0, CODE) + uc.emu_start(0x6000b0, 0, count=1) + + + # Here's the original execution trace for this on actual hardware. + # + # (gdb) x/i $pc + # => 0x6000b0: xor %r14,%r14 + # (gdb) p/x $eflags + # $1 = 0x200 + # (gdb) p $eflags + # $2 = [ IF ] + # (gdb) si + # 0x00000000006000b3 in ?? () + # (gdb) p/x $eflags + # $3 = 0x246 + # (gdb) p $eflags + # $4 = [ PF ZF IF ] + + self.assertEqual(0x6000b3, uc.reg_read(U.x86_const.UC_X86_REG_RIP)) + self.assertEqual(0x246, uc.reg_read(U.x86_const.UC_X86_REG_EFLAGS)) + +if __name__ == '__main__': + regress.main() From 4e07e71e047bbfabeb2d4148068aad91f2b3e2fb Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Thu, 31 Mar 2016 10:06:33 +0800 Subject: [PATCH 098/149] regress: chmod +x x86_64_eflags.py --- tests/regress/x86_64_eflags.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tests/regress/x86_64_eflags.py diff --git a/tests/regress/x86_64_eflags.py b/tests/regress/x86_64_eflags.py old mode 100644 new mode 100755 From 99e136befc8113e1ba683bd3a437094b013190e1 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Wed, 30 Mar 2016 20:04:49 -0700 Subject: [PATCH 099/149] allow setting PREFIX in make.sh --- make.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/make.sh b/make.sh index 98cac449..db258df5 100755 --- a/make.sh +++ b/make.sh @@ -51,7 +51,7 @@ install() { rm -rf /usr/lib/libunicorn* rm -rf /usr/include/unicorn # install into /usr/local - PREFIX=/usr/local + PREFIX="${PREFIX-/usr/local}" ${MAKE} install else # not OSX test -d /usr/lib64 && LIBDIRARCH=lib64 @@ -64,7 +64,7 @@ uninstall() { if [ "$UNAME" = "Darwin" ]; then # find the directory automatically, so we can support both Macport & Brew PKGCFGDIR="$(pkg-config --variable pc_path pkg-config | cut -d ':' -f 1)" - PREFIX=/usr/local + PREFIX="${PREFIX-/usr/local}" ${MAKE} uninstall else # not OSX test -d /usr/lib64 && LIBDIRARCH=lib64 @@ -80,7 +80,7 @@ fi if [ -n "`echo "$UNAME" | grep BSD`" ]; then MAKE=gmake - PREFIX=/usr/local + PREFIX="${PREFIX-/usr/local}" fi [ -z "${UNAME}" ] && UNAME=$(uname) From fd825fb800e681dc0ffd8a70cde358efa01a2c01 Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Fri, 1 Apr 2016 23:38:32 +1100 Subject: [PATCH 100/149] Added stdint include to x86.h x86.h referenced types defined in stdint.h (e.g. uint16_t, etc.), but didn't actually include stdint.h --- include/unicorn/x86.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/include/unicorn/x86.h b/include/unicorn/x86.h index fe33c723..b0e02d8d 100644 --- a/include/unicorn/x86.h +++ b/include/unicorn/x86.h @@ -8,6 +8,8 @@ extern "C" { #endif +#include + // Memory-Management Register for instructions IDTR, GDTR, LDTR, TR. // Borrow from SegmentCache in qemu/target-i386/cpu.h typedef struct uc_x86_mmr { From 1486ccce7042394035182f9628cc496db187fc22 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 3 Apr 2016 23:32:14 +0800 Subject: [PATCH 101/149] regress: fix all the calls to uc_hook_add() following recent change on this API --- tests/regress/rw_hookstack.c | 2 +- tests/regress/sigill.c | 2 +- tests/regress/sysenter_hook_x86.c | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/regress/rw_hookstack.c b/tests/regress/rw_hookstack.c index e04dd64c..3d7eacaa 100644 --- a/tests/regress/rw_hookstack.c +++ b/tests/regress/rw_hookstack.c @@ -78,7 +78,7 @@ loop: } - uc_hook_add(uc, &trace, UC_HOOK_MEM_WRITE | UC_HOOK_MEM_READ, (void *)hook_mem_rw, NULL); + uc_hook_add(uc, &trace, UC_HOOK_MEM_WRITE | UC_HOOK_MEM_READ, (void *)hook_mem_rw, NULL, 1, 0); uc_reg_write(uc, UC_X86_REG_EAX, &EAX); uc_reg_write(uc, UC_X86_REG_ESP, &ESP); diff --git a/tests/regress/sigill.c b/tests/regress/sigill.c index 8ce230cd..ea8f987f 100644 --- a/tests/regress/sigill.c +++ b/tests/regress/sigill.c @@ -38,7 +38,7 @@ int main() uc_mem_write(uc, UC_BUG_WRITE_ADDR, (const uint8_t*)"\xff\xff\xff\xff\xff\xff\xff\xff", 8); } - uc_hook_add(uc, &uh_trap, UC_HOOK_INTR, _interrupt, NULL); + uc_hook_add(uc, &uh_trap, UC_HOOK_INTR, _interrupt, NULL, 1, 0); uc_emu_start(uc, UC_BUG_WRITE_ADDR, UC_BUG_WRITE_ADDR+8, 0, 1); uc_close(uc); printf ("Correct: %s\n", got_sigill? "YES": "NO"); diff --git a/tests/regress/sysenter_hook_x86.c b/tests/regress/sysenter_hook_x86.c index 4b28557b..af92c1c5 100644 --- a/tests/regress/sysenter_hook_x86.c +++ b/tests/regress/sysenter_hook_x86.c @@ -36,7 +36,7 @@ int main(int argc, char **argv, char **envp) } // Hook the SYSENTER instructions - if (uc_hook_add (uc, &sysenterHook, UC_HOOK_INSN, sysenter, NULL, UC_X86_INS_SYSENTER) != UC_ERR_OK) { + if (uc_hook_add (uc, &sysenterHook, UC_HOOK_INSN, sysenter, NULL, UC_X86_INS_SYSENTER, 1, 0) != UC_ERR_OK) { printf ("Cannot hook SYSENTER instruction\n."); return -1; } @@ -57,4 +57,4 @@ int main(int argc, char **argv, char **envp) } return 0; -} \ No newline at end of file +} From 66619fc6cd9255ab91fe19dd33196dc9bade2cad Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Sun, 3 Apr 2016 23:08:17 -0700 Subject: [PATCH 102/149] remove call to restore_eflags (#496) --- qemu/target-i386/translate.c | 1 - 1 file changed, 1 deletion(-) diff --git a/qemu/target-i386/translate.c b/qemu/target-i386/translate.c index 76bab2d6..e78ff694 100644 --- a/qemu/target-i386/translate.c +++ b/qemu/target-i386/translate.c @@ -4784,7 +4784,6 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s, changed_cc_op = true; } gen_uc_tracecode(tcg_ctx, 0xf1f1f1f1, UC_HOOK_CODE_IDX, env->uc, pc_start); - restore_eflags(s, tcg_ctx); // the callback might want to stop emulation immediately check_exit_request(tcg_ctx); } From 6e6ef66b76378e1d1fca42807572258ec911c96e Mon Sep 17 00:00:00 2001 From: The Gitter Badger Date: Mon, 4 Apr 2016 16:50:11 +0000 Subject: [PATCH 103/149] Add Gitter badge --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index e970c408..02916205 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,8 @@ Unicorn Engine ============== +[![Join the chat at https://gitter.im/unicorn-engine/unicorn](https://badges.gitter.im/unicorn-engine/unicorn.svg)](https://gitter.im/unicorn-engine/unicorn?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + [![Build Status](https://travis-ci.org/unicorn-engine/unicorn.svg?branch=master)](https://travis-ci.org/unicorn-engine/unicorn) [![Build status](https://ci.appveyor.com/api/projects/status/kojr7bald748ba2x/branch/master?svg=true)](https://ci.appveyor.com/project/aquynh/unicorn/branch/master) From 8ee696f81dd5bbbca56c906dd0c86e17702e61bd Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 5 Apr 2016 10:09:31 +0800 Subject: [PATCH 104/149] Update README.md Change Gitter link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 02916205..0f909c7d 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Unicorn Engine ============== -[![Join the chat at https://gitter.im/unicorn-engine/unicorn](https://badges.gitter.im/unicorn-engine/unicorn.svg)](https://gitter.im/unicorn-engine/unicorn?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) +[![Join the chat at https://gitter.im/unicorn-engine/chat](https://badges.gitter.im/unicorn-engine/unicorn.svg)](https://gitter.im/unicorn-engine/chat?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) [![Build Status](https://travis-ci.org/unicorn-engine/unicorn.svg?branch=master)](https://travis-ci.org/unicorn-engine/unicorn) [![Build status](https://ci.appveyor.com/api/projects/status/kojr7bald748ba2x/branch/master?svg=true)](https://ci.appveyor.com/project/aquynh/unicorn/branch/master) From acd88856e19cacb18b8fdf9998b1ccf4273204db Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Mon, 4 Apr 2016 08:25:30 -0700 Subject: [PATCH 105/149] add batched reg access --- bindings/go/unicorn/uc.c | 23 + bindings/go/unicorn/uc.h | 2 + bindings/go/unicorn/unicorn.go | 36 + include/uc_priv.h | 4 +- include/unicorn/unicorn.h | 28 + qemu/target-arm/unicorn.h | 8 +- qemu/target-arm/unicorn_aarch64.c | 88 +- qemu/target-arm/unicorn_arm.c | 92 +- qemu/target-i386/unicorn.c | 1887 +++++++++++++++-------------- qemu/target-i386/unicorn.h | 4 +- qemu/target-m68k/unicorn.c | 61 +- qemu/target-m68k/unicorn.h | 4 +- qemu/target-mips/unicorn.c | 53 +- qemu/target-mips/unicorn.h | 4 +- qemu/target-sparc/unicorn.c | 78 +- qemu/target-sparc/unicorn.h | 4 +- qemu/target-sparc/unicorn64.c | 73 +- uc.c | 22 +- 18 files changed, 1320 insertions(+), 1151 deletions(-) create mode 100644 bindings/go/unicorn/uc.c create mode 100644 bindings/go/unicorn/uc.h diff --git a/bindings/go/unicorn/uc.c b/bindings/go/unicorn/uc.c new file mode 100644 index 00000000..7d67c798 --- /dev/null +++ b/bindings/go/unicorn/uc.c @@ -0,0 +1,23 @@ +#include +#include +#include "_cgo_export.h" + +uc_err uc_reg_read_batch_helper(uc_engine *handle, int *regs, uint64_t *val_out, int count) { + void **val_ref = malloc(sizeof(void *) * count); + for (int i = 0; i < count; i++) { + val_ref[i] = (void *)&val_out[i]; + } + uc_err ret = uc_reg_read_batch(handle, regs, val_ref, count); + free(val_ref); + return ret; +} + +uc_err uc_reg_write_batch_helper(uc_engine *handle, int *regs, uint64_t *val_in, int count) { + const void **val_ref = malloc(sizeof(void *) * count); + for (int i = 0; i < count; i++) { + val_ref[i] = (void *)&val_in[i]; + } + uc_err ret = uc_reg_write_batch(handle, regs, val_ref, count); + free(val_ref); + return ret; +} diff --git a/bindings/go/unicorn/uc.h b/bindings/go/unicorn/uc.h new file mode 100644 index 00000000..06022346 --- /dev/null +++ b/bindings/go/unicorn/uc.h @@ -0,0 +1,2 @@ +uc_err uc_reg_read_batch_helper(uc_engine *handle, int *regs, uint64_t *val_out, int count); +uc_err uc_reg_write_batch_helper(uc_engine *handle, int *regs, uint64_t *val_in, int count); diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index fcebddda..42f619f9 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -7,8 +7,10 @@ import ( ) /* +#cgo CFLAGS: -O3 #cgo LDFLAGS: -lunicorn #include +#include "uc.h" */ import "C" @@ -41,7 +43,9 @@ type Unicorn interface { MemReadInto(dst []byte, addr uint64) error MemWrite(addr uint64, data []byte) error RegRead(reg int) (uint64, error) + RegReadBatch(regs []int) ([]uint64, error) RegWrite(reg int, value uint64) error + RegWriteBatch(regs []int, vals []uint64) error RegReadMmr(reg int) (*X86Mmr, error) RegWriteMmr(reg int, value *X86Mmr) error Start(begin, until uint64) error @@ -117,6 +121,38 @@ func (u *uc) RegRead(reg int) (uint64, error) { return uint64(val), errReturn(ucerr) } +func (u *uc) RegWriteBatch(regs []int, vals []uint64) error { + if len(regs) == 0 { + return nil + } + if len(vals) < len(regs) { + regs = regs[:len(vals)] + } + cregs := make([]C.int, len(regs)) + for i, v := range regs { + cregs[i] = C.int(v) + } + cregs2 := (*C.int)(unsafe.Pointer(&cregs[0])) + cvals := (*C.uint64_t)(unsafe.Pointer(&vals[0])) + ucerr := C.uc_reg_write_batch_helper(u.handle, cregs2, cvals, C.int(len(regs))) + return errReturn(ucerr) +} + +func (u *uc) RegReadBatch(regs []int) ([]uint64, error) { + if len(regs) == 0 { + return nil, nil + } + cregs := make([]C.int, len(regs)) + for i, v := range regs { + cregs[i] = C.int(v) + } + cregs2 := (*C.int)(unsafe.Pointer(&cregs[0])) + vals := make([]uint64, len(regs)) + cvals := (*C.uint64_t)(unsafe.Pointer(&vals[0])) + ucerr := C.uc_reg_read_batch_helper(u.handle, cregs2, cvals, C.int(len(regs))) + return vals, errReturn(ucerr) +} + func (u *uc) MemRegions() ([]*MemRegion, error) { var regions *C.struct_uc_mem_region var count C.uint32_t diff --git a/include/uc_priv.h b/include/uc_priv.h index e36a8c84..916f0c56 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -46,8 +46,8 @@ typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList; typedef uc_err (*query_t)(struct uc_struct *uc, uc_query_type type, size_t *result); // return 0 on success, -1 on failure -typedef int (*reg_read_t)(struct uc_struct *uc, unsigned int regid, void *value); -typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int regid, const void *value); +typedef int (*reg_read_t)(struct uc_struct *uc, unsigned int *regs, void **vals, int count); +typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count); typedef void (*reg_reset_t)(struct uc_struct *uc); diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 65d6aa53..0eb5390e 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -386,6 +386,34 @@ uc_err uc_reg_write(uc_engine *uc, int regid, const void *value); UNICORN_EXPORT uc_err uc_reg_read(uc_engine *uc, int regid, void *value); +/* + Write multiple register values. + + @uc: handle returned by uc_open() + @rges: array of register IDs to store + @value: pointer to array of register values + @count: length of both *regs and *vals + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_reg_write_batch(uc_engine *uc, int *regs, void *const *vals, int count); + +/* + Read multiple register values. + + @uc: handle returned by uc_open() + @rges: array of register IDs to retrieve + @value: pointer to array of values to hold registers + @count: length of both *regs and *vals + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_reg_read_batch(uc_engine *uc, int *regs, void **vals, int count); + /* Write to a range of bytes in memory. diff --git a/qemu/target-arm/unicorn.h b/qemu/target-arm/unicorn.h index 797ef979..0b3fb93d 100644 --- a/qemu/target-arm/unicorn.h +++ b/qemu/target-arm/unicorn.h @@ -5,10 +5,10 @@ #define UC_QEMU_TARGET_ARM_H // functions to read & write registers -int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value); -int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); -int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value); -int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); +int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count); +int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count); +int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count); +int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count); void arm_reg_reset(struct uc_struct *uc); void arm64_reg_reset(struct uc_struct *uc); diff --git a/qemu/target-arm/unicorn_aarch64.c b/qemu/target-arm/unicorn_aarch64.c index c1d53a68..8e4bccfe 100644 --- a/qemu/target-arm/unicorn_aarch64.c +++ b/qemu/target-arm/unicorn_aarch64.c @@ -23,57 +23,67 @@ void arm64_reg_reset(struct uc_struct *uc) env->pc = 0; } -int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value) +int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) - *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0]; - else { - switch(regid) { - default: break; - case UC_ARM64_REG_X29: - *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[29]; - break; - case UC_ARM64_REG_X30: - *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[30]; - break; - case UC_ARM64_REG_PC: - *(uint64_t *)value = ARM_CPU(uc, mycpu)->env.pc; - break; - case UC_ARM64_REG_SP: - *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[31]; - break; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) + *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0]; + else { + switch(regid) { + default: break; + case UC_ARM64_REG_X29: + *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[29]; + break; + case UC_ARM64_REG_X30: + *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[30]; + break; + case UC_ARM64_REG_PC: + *(uint64_t *)value = ARM_CPU(uc, mycpu)->env.pc; + break; + case UC_ARM64_REG_SP: + *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[31]; + break; + } } } return 0; } -int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) +int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void* const* vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) - ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0] = *(uint64_t *)value; - else { - switch(regid) { - default: break; - case UC_ARM64_REG_X29: - ARM_CPU(uc, mycpu)->env.xregs[29] = *(uint64_t *)value; - break; - case UC_ARM64_REG_X30: - ARM_CPU(uc, mycpu)->env.xregs[30] = *(uint64_t *)value; - break; - case UC_ARM64_REG_PC: - ARM_CPU(uc, mycpu)->env.pc = *(uint64_t *)value; - // force to quit execution and flush TB - uc->quit_request = true; - uc_emu_stop(uc); - break; - case UC_ARM64_REG_SP: - ARM_CPU(uc, mycpu)->env.xregs[31] = *(uint64_t *)value; - break; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) + ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0] = *(uint64_t *)value; + else { + switch(regid) { + default: break; + case UC_ARM64_REG_X29: + ARM_CPU(uc, mycpu)->env.xregs[29] = *(uint64_t *)value; + break; + case UC_ARM64_REG_X30: + ARM_CPU(uc, mycpu)->env.xregs[30] = *(uint64_t *)value; + break; + case UC_ARM64_REG_PC: + ARM_CPU(uc, mycpu)->env.pc = *(uint64_t *)value; + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); + break; + case UC_ARM64_REG_SP: + ARM_CPU(uc, mycpu)->env.xregs[31] = *(uint64_t *)value; + break; + } } } diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index 9fc2a44c..a6d9355f 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -27,62 +27,72 @@ void arm_reg_reset(struct uc_struct *uc) env->pc = 0; } -int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value) +int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count) { CPUState *mycpu; + int i; mycpu = first_cpu; - if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) - *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0]; - else { - switch(regid) { - case UC_ARM_REG_CPSR: - *(int32_t *)value = cpsr_read(&ARM_CPU(uc, mycpu)->env); - break; - //case UC_ARM_REG_SP: - case UC_ARM_REG_R13: - *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[13]; - break; - //case UC_ARM_REG_LR: - case UC_ARM_REG_R14: - *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[14]; - break; - //case UC_ARM_REG_PC: - case UC_ARM_REG_R15: - *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[15]; - break; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) + *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0]; + else { + switch(regid) { + case UC_ARM_REG_CPSR: + *(int32_t *)value = cpsr_read(&ARM_CPU(uc, mycpu)->env); + break; + //case UC_ARM_REG_SP: + case UC_ARM_REG_R13: + *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[13]; + break; + //case UC_ARM_REG_LR: + case UC_ARM_REG_R14: + *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[14]; + break; + //case UC_ARM_REG_PC: + case UC_ARM_REG_R15: + *(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[15]; + break; + } } } return 0; } -int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) +int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void* const* vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) - ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0] = *(uint32_t *)value; - else { - switch(regid) { - //case UC_ARM_REG_SP: - case UC_ARM_REG_R13: - ARM_CPU(uc, mycpu)->env.regs[13] = *(uint32_t *)value; - break; - //case UC_ARM_REG_LR: - case UC_ARM_REG_R14: - ARM_CPU(uc, mycpu)->env.regs[14] = *(uint32_t *)value; - break; - //case UC_ARM_REG_PC: - case UC_ARM_REG_R15: - ARM_CPU(uc, mycpu)->env.pc = *(uint32_t *)value; - ARM_CPU(uc, mycpu)->env.regs[15] = *(uint32_t *)value; - // force to quit execution and flush TB - uc->quit_request = true; - uc_emu_stop(uc); + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12) + ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0] = *(uint32_t *)value; + else { + switch(regid) { + //case UC_ARM_REG_SP: + case UC_ARM_REG_R13: + ARM_CPU(uc, mycpu)->env.regs[13] = *(uint32_t *)value; + break; + //case UC_ARM_REG_LR: + case UC_ARM_REG_R14: + ARM_CPU(uc, mycpu)->env.regs[14] = *(uint32_t *)value; + break; + //case UC_ARM_REG_PC: + case UC_ARM_REG_R15: + ARM_CPU(uc, mycpu)->env.pc = *(uint32_t *)value; + ARM_CPU(uc, mycpu)->env.regs[15] = *(uint32_t *)value; + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); - break; + break; + } } } diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index 961e8d98..f4d134bd 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -136,970 +136,979 @@ void x86_reg_reset(struct uc_struct *uc) } } -int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) +int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count) { CPUState *mycpu = first_cpu; + int i; - switch(regid) { - default: - break; - case UC_X86_REG_FP0 ... UC_X86_REG_FP7: - { - floatx80 reg = X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d; - cpu_get_fp80(value, value+sizeof(uint64_t), reg); - } - return 0; - case UC_X86_REG_FPSW: - { - uint16_t fpus = X86_CPU(uc, mycpu)->env.fpus; - fpus = fpus & ~0x3800; - fpus |= ( X86_CPU(uc, mycpu)->env.fpstt & 0x7 ) << 11; - *(uint16_t*) value = fpus; - } - return 0; - case UC_X86_REG_FPCW: - *(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc; - return 0; - case UC_X86_REG_FPTAG: - { - #define EXPD(fp) (fp.l.upper & 0x7fff) - #define MANTD(fp) (fp.l.lower) - #define MAXEXPD 0x7fff - int fptag, exp, i; - uint64_t mant; - CPU_LDoubleU tmp; - fptag = 0; - for (i = 7; i >= 0; i--) { - fptag <<= 2; - if (X86_CPU(uc, mycpu)->env.fptags[i]) { - fptag |= 3; - } else { - tmp.d = X86_CPU(uc, mycpu)->env.fpregs[i].d; - exp = EXPD(tmp); - mant = MANTD(tmp); - if (exp == 0 && mant == 0) { - /* zero */ - fptag |= 1; - } else if (exp == 0 || exp == MAXEXPD - || (mant & (1LL << 63)) == 0) { - /* NaNs, infinity, denormal */ - fptag |= 2; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + switch(regid) { + default: + break; + case UC_X86_REG_FP0 ... UC_X86_REG_FP7: + { + floatx80 reg = X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d; + cpu_get_fp80(value, value+sizeof(uint64_t), reg); + } + continue; + case UC_X86_REG_FPSW: + { + uint16_t fpus = X86_CPU(uc, mycpu)->env.fpus; + fpus = fpus & ~0x3800; + fpus |= ( X86_CPU(uc, mycpu)->env.fpstt & 0x7 ) << 11; + *(uint16_t*) value = fpus; + } + continue; + case UC_X86_REG_FPCW: + *(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc; + continue; + case UC_X86_REG_FPTAG: + { + #define EXPD(fp) (fp.l.upper & 0x7fff) + #define MANTD(fp) (fp.l.lower) + #define MAXEXPD 0x7fff + int fptag, exp, i; + uint64_t mant; + CPU_LDoubleU tmp; + fptag = 0; + for (i = 7; i >= 0; i--) { + fptag <<= 2; + if (X86_CPU(uc, mycpu)->env.fptags[i]) { + fptag |= 3; + } else { + tmp.d = X86_CPU(uc, mycpu)->env.fpregs[i].d; + exp = EXPD(tmp); + mant = MANTD(tmp); + if (exp == 0 && mant == 0) { + /* zero */ + fptag |= 1; + } else if (exp == 0 || exp == MAXEXPD + || (mant & (1LL << 63)) == 0) { + /* NaNs, infinity, denormal */ + fptag |= 2; + } } } + *(uint16_t*) value = fptag; } - *(uint16_t*) value = fptag; - } - return 0; - } + continue; + } - switch(uc->mode) { - default: - break; - case UC_MODE_16: - switch(regid) { - default: break; - case UC_X86_REG_ES: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_ES].selector; - return 0; - case UC_X86_REG_SS: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_SS].selector; - return 0; - case UC_X86_REG_DS: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_DS].selector; - return 0; - case UC_X86_REG_FS: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_FS].selector; - return 0; - case UC_X86_REG_GS: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].selector; - return 0; - } - // fall-thru - case UC_MODE_32: - switch(regid) { - default: - break; - case UC_X86_REG_CR0 ... UC_X86_REG_CR4: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.cr[regid - UC_X86_REG_CR0]; - break; - case UC_X86_REG_DR0 ... UC_X86_REG_DR7: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.dr[regid - UC_X86_REG_DR0]; - break; - case UC_X86_REG_EFLAGS: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.eflags; - break; - case UC_X86_REG_EAX: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EAX]; - break; - case UC_X86_REG_AX: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EAX]); - break; - case UC_X86_REG_AH: - *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EAX]); - break; - case UC_X86_REG_AL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EAX]); - break; - case UC_X86_REG_EBX: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EBX]; - break; - case UC_X86_REG_BX: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBX]); - break; - case UC_X86_REG_BH: - *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EBX]); - break; - case UC_X86_REG_BL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBX]); - break; - case UC_X86_REG_ECX: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ECX]; - break; - case UC_X86_REG_CX: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ECX]); - break; - case UC_X86_REG_CH: - *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_ECX]); - break; - case UC_X86_REG_CL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ECX]); - break; - case UC_X86_REG_EDX: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EDX]; - break; - case UC_X86_REG_DX: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDX]); - break; - case UC_X86_REG_DH: - *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EDX]); - break; - case UC_X86_REG_DL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDX]); - break; - case UC_X86_REG_ESP: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ESP]; - break; - case UC_X86_REG_SP: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESP]); - break; - case UC_X86_REG_EBP: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EBP]; - break; - case UC_X86_REG_BP: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBP]); - break; - case UC_X86_REG_ESI: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ESI]; - break; - case UC_X86_REG_SI: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESI]); - break; - case UC_X86_REG_EDI: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EDI]; - break; - case UC_X86_REG_DI: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDI]); - break; - case UC_X86_REG_EIP: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.eip; - break; - case UC_X86_REG_IP: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.eip); - break; - case UC_X86_REG_CS: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_CS].selector; - break; - case UC_X86_REG_DS: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_DS].selector; - break; - case UC_X86_REG_SS: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_SS].selector; - break; - case UC_X86_REG_ES: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_ES].selector; - break; - case UC_X86_REG_FS: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_FS].selector; - break; - case UC_X86_REG_GS: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_GS].selector; - break; - case UC_X86_REG_IDTR: - ((uc_x86_mmr *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.idt.limit; - ((uc_x86_mmr *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.idt.base; - break; - case UC_X86_REG_GDTR: - ((uc_x86_mmr *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.gdt.limit; - ((uc_x86_mmr *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.gdt.base; - break; - case UC_X86_REG_LDTR: - ((uc_x86_mmr *)value)->limit = X86_CPU(uc, mycpu)->env.ldt.limit; - ((uc_x86_mmr *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.ldt.base; - ((uc_x86_mmr *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.ldt.selector; - ((uc_x86_mmr *)value)->flags = X86_CPU(uc, mycpu)->env.ldt.flags; - break; - case UC_X86_REG_TR: - ((uc_x86_mmr *)value)->limit = X86_CPU(uc, mycpu)->env.tr.limit; - ((uc_x86_mmr *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.tr.base; - ((uc_x86_mmr *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.tr.selector; - ((uc_x86_mmr *)value)->flags = X86_CPU(uc, mycpu)->env.tr.flags; - break; - } - break; + switch(uc->mode) { + default: + break; + case UC_MODE_16: + switch(regid) { + default: break; + case UC_X86_REG_ES: + *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_ES].selector; + continue; + case UC_X86_REG_SS: + *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_SS].selector; + continue; + case UC_X86_REG_DS: + *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_DS].selector; + continue; + case UC_X86_REG_FS: + *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_FS].selector; + continue; + case UC_X86_REG_GS: + *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].selector; + continue; + } + // fall-thru + case UC_MODE_32: + switch(regid) { + default: + break; + case UC_X86_REG_CR0 ... UC_X86_REG_CR4: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.cr[regid - UC_X86_REG_CR0]; + break; + case UC_X86_REG_DR0 ... UC_X86_REG_DR7: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.dr[regid - UC_X86_REG_DR0]; + break; + case UC_X86_REG_EFLAGS: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.eflags; + break; + case UC_X86_REG_EAX: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EAX]; + break; + case UC_X86_REG_AX: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EAX]); + break; + case UC_X86_REG_AH: + *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EAX]); + break; + case UC_X86_REG_AL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EAX]); + break; + case UC_X86_REG_EBX: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EBX]; + break; + case UC_X86_REG_BX: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBX]); + break; + case UC_X86_REG_BH: + *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EBX]); + break; + case UC_X86_REG_BL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBX]); + break; + case UC_X86_REG_ECX: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ECX]; + break; + case UC_X86_REG_CX: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ECX]); + break; + case UC_X86_REG_CH: + *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_ECX]); + break; + case UC_X86_REG_CL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ECX]); + break; + case UC_X86_REG_EDX: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EDX]; + break; + case UC_X86_REG_DX: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDX]); + break; + case UC_X86_REG_DH: + *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EDX]); + break; + case UC_X86_REG_DL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDX]); + break; + case UC_X86_REG_ESP: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ESP]; + break; + case UC_X86_REG_SP: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESP]); + break; + case UC_X86_REG_EBP: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EBP]; + break; + case UC_X86_REG_BP: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBP]); + break; + case UC_X86_REG_ESI: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ESI]; + break; + case UC_X86_REG_SI: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESI]); + break; + case UC_X86_REG_EDI: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EDI]; + break; + case UC_X86_REG_DI: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDI]); + break; + case UC_X86_REG_EIP: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.eip; + break; + case UC_X86_REG_IP: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.eip); + break; + case UC_X86_REG_CS: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_CS].selector; + break; + case UC_X86_REG_DS: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_DS].selector; + break; + case UC_X86_REG_SS: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_SS].selector; + break; + case UC_X86_REG_ES: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_ES].selector; + break; + case UC_X86_REG_FS: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_FS].selector; + break; + case UC_X86_REG_GS: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_GS].selector; + break; + case UC_X86_REG_IDTR: + ((uc_x86_mmr *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.idt.limit; + ((uc_x86_mmr *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.idt.base; + break; + case UC_X86_REG_GDTR: + ((uc_x86_mmr *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.gdt.limit; + ((uc_x86_mmr *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.gdt.base; + break; + case UC_X86_REG_LDTR: + ((uc_x86_mmr *)value)->limit = X86_CPU(uc, mycpu)->env.ldt.limit; + ((uc_x86_mmr *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.ldt.base; + ((uc_x86_mmr *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.ldt.selector; + ((uc_x86_mmr *)value)->flags = X86_CPU(uc, mycpu)->env.ldt.flags; + break; + case UC_X86_REG_TR: + ((uc_x86_mmr *)value)->limit = X86_CPU(uc, mycpu)->env.tr.limit; + ((uc_x86_mmr *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.tr.base; + ((uc_x86_mmr *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.tr.selector; + ((uc_x86_mmr *)value)->flags = X86_CPU(uc, mycpu)->env.tr.flags; + break; + } + break; #ifdef TARGET_X86_64 - case UC_MODE_64: - switch(regid) { - default: - break; - case UC_X86_REG_CR0 ... UC_X86_REG_CR4: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.cr[regid - UC_X86_REG_CR0]; - break; - case UC_X86_REG_DR0 ... UC_X86_REG_DR7: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.dr[regid - UC_X86_REG_DR0]; - break; - case UC_X86_REG_EFLAGS: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.eflags; - break; - case UC_X86_REG_RAX: - *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EAX]; - break; - case UC_X86_REG_EAX: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EAX]); - break; - case UC_X86_REG_AX: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EAX]); - break; - case UC_X86_REG_AH: - *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EAX]); - break; - case UC_X86_REG_AL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EAX]); - break; - case UC_X86_REG_RBX: - *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EBX]; - break; - case UC_X86_REG_EBX: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EBX]); - break; - case UC_X86_REG_BX: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBX]); - break; - case UC_X86_REG_BH: - *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EBX]); - break; - case UC_X86_REG_BL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBX]); - break; - case UC_X86_REG_RCX: - *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ECX]; - break; - case UC_X86_REG_ECX: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ECX]); - break; - case UC_X86_REG_CX: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ECX]); - break; - case UC_X86_REG_CH: - *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_ECX]); - break; - case UC_X86_REG_CL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ECX]); - break; - case UC_X86_REG_RDX: - *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EDX]; - break; - case UC_X86_REG_EDX: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EDX]); - break; - case UC_X86_REG_DX: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDX]); - break; - case UC_X86_REG_DH: - *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EDX]); - break; - case UC_X86_REG_DL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDX]); - break; - case UC_X86_REG_RSP: - *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ESP]; - break; - case UC_X86_REG_ESP: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ESP]); - break; - case UC_X86_REG_SP: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESP]); - break; - case UC_X86_REG_SPL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ESP]); - break; - case UC_X86_REG_RBP: - *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EBP]; - break; - case UC_X86_REG_EBP: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EBP]); - break; - case UC_X86_REG_BP: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBP]); - break; - case UC_X86_REG_BPL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBP]); - break; - case UC_X86_REG_RSI: - *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ESI]; - break; - case UC_X86_REG_ESI: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ESI]); - break; - case UC_X86_REG_SI: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESI]); - break; - case UC_X86_REG_SIL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ESI]); - break; - case UC_X86_REG_RDI: - *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EDI]; - break; - case UC_X86_REG_EDI: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EDI]); - break; - case UC_X86_REG_DI: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDI]); - break; - case UC_X86_REG_DIL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDI]); - break; - case UC_X86_REG_RIP: - *(uint64_t *)value = X86_CPU(uc, mycpu)->env.eip; - break; - case UC_X86_REG_EIP: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.eip); - break; - case UC_X86_REG_IP: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.eip); - break; - case UC_X86_REG_CS: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_CS].selector; - break; - case UC_X86_REG_DS: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_DS].selector; - break; - case UC_X86_REG_SS: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_SS].selector; - break; - case UC_X86_REG_ES: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_ES].selector; - break; - case UC_X86_REG_FS: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_FS].selector; - break; - case UC_X86_REG_GS: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_GS].selector; - break; - case UC_X86_REG_R8: - *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[8]); - break; - case UC_X86_REG_R8D: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[8]); - break; - case UC_X86_REG_R8W: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[8]); - break; - case UC_X86_REG_R8B: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[8]); - break; - case UC_X86_REG_R9: - *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[9]); - break; - case UC_X86_REG_R9D: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[9]); - break; - case UC_X86_REG_R9W: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[9]); - break; - case UC_X86_REG_R9B: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[9]); - break; - case UC_X86_REG_R10: - *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[10]); - break; - case UC_X86_REG_R10D: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[10]); - break; - case UC_X86_REG_R10W: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[10]); - break; - case UC_X86_REG_R10B: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[10]); - break; - case UC_X86_REG_R11: - *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[11]); - break; - case UC_X86_REG_R11D: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[11]); - break; - case UC_X86_REG_R11W: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[11]); - break; - case UC_X86_REG_R11B: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[11]); - break; - case UC_X86_REG_R12: - *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[12]); - break; - case UC_X86_REG_R12D: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[12]); - break; - case UC_X86_REG_R12W: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[12]); - break; - case UC_X86_REG_R12B: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[12]); - break; - case UC_X86_REG_R13: - *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[13]); - break; - case UC_X86_REG_R13D: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[13]); - break; - case UC_X86_REG_R13W: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[13]); - break; - case UC_X86_REG_R13B: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[13]); - break; - case UC_X86_REG_R14: - *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[14]); - break; - case UC_X86_REG_R14D: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[14]); - break; - case UC_X86_REG_R14W: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[14]); - break; - case UC_X86_REG_R14B: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[14]); - break; - case UC_X86_REG_R15: - *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[15]); - break; - case UC_X86_REG_R15D: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[15]); - break; - case UC_X86_REG_R15W: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[15]); - break; - case UC_X86_REG_R15B: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[15]); - break; - case UC_X86_REG_IDTR: - ((uc_x86_mmr *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.idt.limit; - ((uc_x86_mmr *)value)->base = X86_CPU(uc, mycpu)->env.idt.base; - break; - case UC_X86_REG_GDTR: - ((uc_x86_mmr *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.gdt.limit; - ((uc_x86_mmr *)value)->base = X86_CPU(uc, mycpu)->env.gdt.base; - break; - case UC_X86_REG_LDTR: - ((uc_x86_mmr *)value)->limit = X86_CPU(uc, mycpu)->env.ldt.limit; - ((uc_x86_mmr *)value)->base = X86_CPU(uc, mycpu)->env.ldt.base; - ((uc_x86_mmr *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.ldt.selector; - ((uc_x86_mmr *)value)->flags = X86_CPU(uc, mycpu)->env.ldt.flags; - break; - case UC_X86_REG_TR: - ((uc_x86_mmr *)value)->limit = X86_CPU(uc, mycpu)->env.tr.limit; - ((uc_x86_mmr *)value)->base = X86_CPU(uc, mycpu)->env.tr.base; - ((uc_x86_mmr *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.tr.selector; - ((uc_x86_mmr *)value)->flags = X86_CPU(uc, mycpu)->env.tr.flags; - break; - } - break; + case UC_MODE_64: + switch(regid) { + default: + break; + case UC_X86_REG_CR0 ... UC_X86_REG_CR4: + *(int64_t *)value = X86_CPU(uc, mycpu)->env.cr[regid - UC_X86_REG_CR0]; + break; + case UC_X86_REG_DR0 ... UC_X86_REG_DR7: + *(int64_t *)value = X86_CPU(uc, mycpu)->env.dr[regid - UC_X86_REG_DR0]; + break; + case UC_X86_REG_EFLAGS: + *(int64_t *)value = X86_CPU(uc, mycpu)->env.eflags; + break; + case UC_X86_REG_RAX: + *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EAX]; + break; + case UC_X86_REG_EAX: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EAX]); + break; + case UC_X86_REG_AX: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EAX]); + break; + case UC_X86_REG_AH: + *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EAX]); + break; + case UC_X86_REG_AL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EAX]); + break; + case UC_X86_REG_RBX: + *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EBX]; + break; + case UC_X86_REG_EBX: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EBX]); + break; + case UC_X86_REG_BX: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBX]); + break; + case UC_X86_REG_BH: + *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EBX]); + break; + case UC_X86_REG_BL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBX]); + break; + case UC_X86_REG_RCX: + *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ECX]; + break; + case UC_X86_REG_ECX: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ECX]); + break; + case UC_X86_REG_CX: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ECX]); + break; + case UC_X86_REG_CH: + *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_ECX]); + break; + case UC_X86_REG_CL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ECX]); + break; + case UC_X86_REG_RDX: + *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EDX]; + break; + case UC_X86_REG_EDX: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EDX]); + break; + case UC_X86_REG_DX: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDX]); + break; + case UC_X86_REG_DH: + *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EDX]); + break; + case UC_X86_REG_DL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDX]); + break; + case UC_X86_REG_RSP: + *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ESP]; + break; + case UC_X86_REG_ESP: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ESP]); + break; + case UC_X86_REG_SP: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESP]); + break; + case UC_X86_REG_SPL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ESP]); + break; + case UC_X86_REG_RBP: + *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EBP]; + break; + case UC_X86_REG_EBP: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EBP]); + break; + case UC_X86_REG_BP: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBP]); + break; + case UC_X86_REG_BPL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBP]); + break; + case UC_X86_REG_RSI: + *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ESI]; + break; + case UC_X86_REG_ESI: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ESI]); + break; + case UC_X86_REG_SI: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESI]); + break; + case UC_X86_REG_SIL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ESI]); + break; + case UC_X86_REG_RDI: + *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EDI]; + break; + case UC_X86_REG_EDI: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EDI]); + break; + case UC_X86_REG_DI: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDI]); + break; + case UC_X86_REG_DIL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDI]); + break; + case UC_X86_REG_RIP: + *(uint64_t *)value = X86_CPU(uc, mycpu)->env.eip; + break; + case UC_X86_REG_EIP: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.eip); + break; + case UC_X86_REG_IP: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.eip); + break; + case UC_X86_REG_CS: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_CS].selector; + break; + case UC_X86_REG_DS: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_DS].selector; + break; + case UC_X86_REG_SS: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_SS].selector; + break; + case UC_X86_REG_ES: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_ES].selector; + break; + case UC_X86_REG_FS: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_FS].selector; + break; + case UC_X86_REG_GS: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_GS].selector; + break; + case UC_X86_REG_R8: + *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[8]); + break; + case UC_X86_REG_R8D: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[8]); + break; + case UC_X86_REG_R8W: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[8]); + break; + case UC_X86_REG_R8B: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[8]); + break; + case UC_X86_REG_R9: + *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[9]); + break; + case UC_X86_REG_R9D: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[9]); + break; + case UC_X86_REG_R9W: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[9]); + break; + case UC_X86_REG_R9B: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[9]); + break; + case UC_X86_REG_R10: + *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[10]); + break; + case UC_X86_REG_R10D: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[10]); + break; + case UC_X86_REG_R10W: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[10]); + break; + case UC_X86_REG_R10B: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[10]); + break; + case UC_X86_REG_R11: + *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[11]); + break; + case UC_X86_REG_R11D: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[11]); + break; + case UC_X86_REG_R11W: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[11]); + break; + case UC_X86_REG_R11B: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[11]); + break; + case UC_X86_REG_R12: + *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[12]); + break; + case UC_X86_REG_R12D: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[12]); + break; + case UC_X86_REG_R12W: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[12]); + break; + case UC_X86_REG_R12B: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[12]); + break; + case UC_X86_REG_R13: + *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[13]); + break; + case UC_X86_REG_R13D: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[13]); + break; + case UC_X86_REG_R13W: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[13]); + break; + case UC_X86_REG_R13B: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[13]); + break; + case UC_X86_REG_R14: + *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[14]); + break; + case UC_X86_REG_R14D: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[14]); + break; + case UC_X86_REG_R14W: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[14]); + break; + case UC_X86_REG_R14B: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[14]); + break; + case UC_X86_REG_R15: + *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[15]); + break; + case UC_X86_REG_R15D: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[15]); + break; + case UC_X86_REG_R15W: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[15]); + break; + case UC_X86_REG_R15B: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[15]); + break; + case UC_X86_REG_IDTR: + ((uc_x86_mmr *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.idt.limit; + ((uc_x86_mmr *)value)->base = X86_CPU(uc, mycpu)->env.idt.base; + break; + case UC_X86_REG_GDTR: + ((uc_x86_mmr *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.gdt.limit; + ((uc_x86_mmr *)value)->base = X86_CPU(uc, mycpu)->env.gdt.base; + break; + case UC_X86_REG_LDTR: + ((uc_x86_mmr *)value)->limit = X86_CPU(uc, mycpu)->env.ldt.limit; + ((uc_x86_mmr *)value)->base = X86_CPU(uc, mycpu)->env.ldt.base; + ((uc_x86_mmr *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.ldt.selector; + ((uc_x86_mmr *)value)->flags = X86_CPU(uc, mycpu)->env.ldt.flags; + break; + case UC_X86_REG_TR: + ((uc_x86_mmr *)value)->limit = X86_CPU(uc, mycpu)->env.tr.limit; + ((uc_x86_mmr *)value)->base = X86_CPU(uc, mycpu)->env.tr.base; + ((uc_x86_mmr *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.tr.selector; + ((uc_x86_mmr *)value)->flags = X86_CPU(uc, mycpu)->env.tr.flags; + break; + } + break; #endif + } } - return 0; } -int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) +int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count) { CPUState *mycpu = first_cpu; + int i; - switch(regid) { - default: - break; - case UC_X86_REG_FP0 ... UC_X86_REG_FP7: - { - uint64_t mant = *(uint64_t*) value; - uint16_t upper = *(uint16_t*) (value + sizeof(uint64_t)); - X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d = cpu_set_fp80(mant, upper); - } - return 0; - case UC_X86_REG_FPSW: - { - uint16_t fpus = *(uint16_t*) value; - X86_CPU(uc, mycpu)->env.fpus = fpus & ~0x3800; - X86_CPU(uc, mycpu)->env.fpstt = (fpus >> 11) & 0x7; - } - return 0; - case UC_X86_REG_FPCW: - X86_CPU(uc, mycpu)->env.fpuc = *(uint16_t *)value; - return 0; - case UC_X86_REG_FPTAG: - { - int i; - uint16_t fptag = *(uint16_t*) value; - for (i = 0; i < 8; i++) { - X86_CPU(uc, mycpu)->env.fptags[i] = ((fptag & 3) == 3); - fptag >>= 2; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + switch(regid) { + default: + break; + case UC_X86_REG_FP0 ... UC_X86_REG_FP7: + { + uint64_t mant = *(uint64_t*) value; + uint16_t upper = *(uint16_t*) (value + sizeof(uint64_t)); + X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d = cpu_set_fp80(mant, upper); } + continue; + case UC_X86_REG_FPSW: + { + uint16_t fpus = *(uint16_t*) value; + X86_CPU(uc, mycpu)->env.fpus = fpus & ~0x3800; + X86_CPU(uc, mycpu)->env.fpstt = (fpus >> 11) & 0x7; + } + continue; + case UC_X86_REG_FPCW: + X86_CPU(uc, mycpu)->env.fpuc = *(uint16_t *)value; + continue; + case UC_X86_REG_FPTAG: + { + int i; + uint16_t fptag = *(uint16_t*) value; + for (i = 0; i < 8; i++) { + X86_CPU(uc, mycpu)->env.fptags[i] = ((fptag & 3) == 3); + fptag >>= 2; + } - return 0; - } - break; - } + continue; + } + break; + } - switch(uc->mode) { - default: - break; + switch(uc->mode) { + default: + break; - case UC_MODE_16: - switch(regid) { - default: break; - case UC_X86_REG_ES: - X86_CPU(uc, mycpu)->env.segs[R_ES].selector = *(uint16_t *)value; - return 0; - case UC_X86_REG_SS: - X86_CPU(uc, mycpu)->env.segs[R_SS].selector = *(uint16_t *)value; - return 0; - case UC_X86_REG_DS: - X86_CPU(uc, mycpu)->env.segs[R_DS].selector = *(uint16_t *)value; - return 0; - case UC_X86_REG_FS: - X86_CPU(uc, mycpu)->env.segs[R_FS].selector = *(uint16_t *)value; - return 0; - case UC_X86_REG_GS: - X86_CPU(uc, mycpu)->env.segs[R_GS].selector = *(uint16_t *)value; - return 0; - } - // fall-thru - case UC_MODE_32: - switch(regid) { - default: - break; - case UC_X86_REG_CR0 ... UC_X86_REG_CR4: - X86_CPU(uc, mycpu)->env.cr[regid - UC_X86_REG_CR0] = *(uint32_t *)value; - break; - case UC_X86_REG_DR0 ... UC_X86_REG_DR7: - X86_CPU(uc, mycpu)->env.dr[regid - UC_X86_REG_DR0] = *(uint32_t *)value; - break; - case UC_X86_REG_EFLAGS: - X86_CPU(uc, mycpu)->env.eflags = *(uint32_t *)value; - X86_CPU(uc, mycpu)->env.eflags0 = *(uint32_t *)value; - break; - case UC_X86_REG_EAX: - X86_CPU(uc, mycpu)->env.regs[R_EAX] = *(uint32_t *)value; - break; - case UC_X86_REG_AX: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint16_t *)value); - break; - case UC_X86_REG_AH: - WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint8_t *)value); - break; - case UC_X86_REG_AL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint8_t *)value); - break; - case UC_X86_REG_EBX: - X86_CPU(uc, mycpu)->env.regs[R_EBX] = *(uint32_t *)value; - break; - case UC_X86_REG_BX: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint16_t *)value); - break; - case UC_X86_REG_BH: - WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint8_t *)value); - break; - case UC_X86_REG_BL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint8_t *)value); - break; - case UC_X86_REG_ECX: - X86_CPU(uc, mycpu)->env.regs[R_ECX] = *(uint32_t *)value; - break; - case UC_X86_REG_CX: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint16_t *)value); - break; - case UC_X86_REG_CH: - WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint8_t *)value); - break; - case UC_X86_REG_CL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint8_t *)value); - break; - case UC_X86_REG_EDX: - X86_CPU(uc, mycpu)->env.regs[R_EDX] = *(uint32_t *)value; - break; - case UC_X86_REG_DX: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint16_t *)value); - break; - case UC_X86_REG_DH: - WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint8_t *)value); - break; - case UC_X86_REG_DL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint8_t *)value); - break; - case UC_X86_REG_ESP: - X86_CPU(uc, mycpu)->env.regs[R_ESP] = *(uint32_t *)value; - break; - case UC_X86_REG_SP: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESP], *(uint16_t *)value); - break; - case UC_X86_REG_EBP: - X86_CPU(uc, mycpu)->env.regs[R_EBP] = *(uint32_t *)value; - break; - case UC_X86_REG_BP: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBP], *(uint16_t *)value); - break; - case UC_X86_REG_ESI: - X86_CPU(uc, mycpu)->env.regs[R_ESI] = *(uint32_t *)value; - break; - case UC_X86_REG_SI: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESI], *(uint16_t *)value); - break; - case UC_X86_REG_EDI: - X86_CPU(uc, mycpu)->env.regs[R_EDI] = *(uint32_t *)value; - break; - case UC_X86_REG_DI: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDI], *(uint16_t *)value); - break; - case UC_X86_REG_EIP: - X86_CPU(uc, mycpu)->env.eip = *(uint32_t *)value; - // force to quit execution and flush TB - uc->quit_request = true; - uc_emu_stop(uc); - break; - case UC_X86_REG_IP: - WRITE_WORD(X86_CPU(uc, mycpu)->env.eip, *(uint16_t *)value); - // force to quit execution and flush TB - uc->quit_request = true; - uc_emu_stop(uc); - break; - case UC_X86_REG_CS: - cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_CS, *(uint16_t *)value); - break; - case UC_X86_REG_DS: - cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_DS, *(uint16_t *)value); - break; - case UC_X86_REG_SS: - cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_SS, *(uint16_t *)value); - break; - case UC_X86_REG_ES: - cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_ES, *(uint16_t *)value); - break; - case UC_X86_REG_FS: - cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_FS, *(uint16_t *)value); - break; - case UC_X86_REG_GS: - cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_GS, *(uint16_t *)value); - break; - case UC_X86_REG_IDTR: - X86_CPU(uc, mycpu)->env.idt.limit = (uint16_t)((uc_x86_mmr *)value)->limit; - X86_CPU(uc, mycpu)->env.idt.base = (uint32_t)((uc_x86_mmr *)value)->base; - break; - case UC_X86_REG_GDTR: - X86_CPU(uc, mycpu)->env.gdt.limit = (uint16_t)((uc_x86_mmr *)value)->limit; - X86_CPU(uc, mycpu)->env.gdt.base = (uint32_t)((uc_x86_mmr *)value)->base; - break; - case UC_X86_REG_LDTR: - X86_CPU(uc, mycpu)->env.ldt.limit = ((uc_x86_mmr *)value)->limit; - X86_CPU(uc, mycpu)->env.ldt.base = (uint32_t)((uc_x86_mmr *)value)->base; - X86_CPU(uc, mycpu)->env.ldt.selector = (uint16_t)((uc_x86_mmr *)value)->selector; - X86_CPU(uc, mycpu)->env.ldt.flags = ((uc_x86_mmr *)value)->flags; - break; - case UC_X86_REG_TR: - X86_CPU(uc, mycpu)->env.tr.limit = ((uc_x86_mmr *)value)->limit; - X86_CPU(uc, mycpu)->env.tr.base = (uint32_t)((uc_x86_mmr *)value)->base; - X86_CPU(uc, mycpu)->env.tr.selector = (uint16_t)((uc_x86_mmr *)value)->selector; - X86_CPU(uc, mycpu)->env.tr.flags = ((uc_x86_mmr *)value)->flags; - break; - } - break; + case UC_MODE_16: + switch(regid) { + default: break; + case UC_X86_REG_ES: + X86_CPU(uc, mycpu)->env.segs[R_ES].selector = *(uint16_t *)value; + continue; + case UC_X86_REG_SS: + X86_CPU(uc, mycpu)->env.segs[R_SS].selector = *(uint16_t *)value; + continue; + case UC_X86_REG_DS: + X86_CPU(uc, mycpu)->env.segs[R_DS].selector = *(uint16_t *)value; + continue; + case UC_X86_REG_FS: + X86_CPU(uc, mycpu)->env.segs[R_FS].selector = *(uint16_t *)value; + continue; + case UC_X86_REG_GS: + X86_CPU(uc, mycpu)->env.segs[R_GS].selector = *(uint16_t *)value; + continue; + } + // fall-thru + case UC_MODE_32: + switch(regid) { + default: + break; + case UC_X86_REG_CR0 ... UC_X86_REG_CR4: + X86_CPU(uc, mycpu)->env.cr[regid - UC_X86_REG_CR0] = *(uint32_t *)value; + break; + case UC_X86_REG_DR0 ... UC_X86_REG_DR7: + X86_CPU(uc, mycpu)->env.dr[regid - UC_X86_REG_DR0] = *(uint32_t *)value; + break; + case UC_X86_REG_EFLAGS: + X86_CPU(uc, mycpu)->env.eflags = *(uint32_t *)value; + X86_CPU(uc, mycpu)->env.eflags0 = *(uint32_t *)value; + break; + case UC_X86_REG_EAX: + X86_CPU(uc, mycpu)->env.regs[R_EAX] = *(uint32_t *)value; + break; + case UC_X86_REG_AX: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint16_t *)value); + break; + case UC_X86_REG_AH: + WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint8_t *)value); + break; + case UC_X86_REG_AL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint8_t *)value); + break; + case UC_X86_REG_EBX: + X86_CPU(uc, mycpu)->env.regs[R_EBX] = *(uint32_t *)value; + break; + case UC_X86_REG_BX: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint16_t *)value); + break; + case UC_X86_REG_BH: + WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint8_t *)value); + break; + case UC_X86_REG_BL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint8_t *)value); + break; + case UC_X86_REG_ECX: + X86_CPU(uc, mycpu)->env.regs[R_ECX] = *(uint32_t *)value; + break; + case UC_X86_REG_CX: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint16_t *)value); + break; + case UC_X86_REG_CH: + WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint8_t *)value); + break; + case UC_X86_REG_CL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint8_t *)value); + break; + case UC_X86_REG_EDX: + X86_CPU(uc, mycpu)->env.regs[R_EDX] = *(uint32_t *)value; + break; + case UC_X86_REG_DX: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint16_t *)value); + break; + case UC_X86_REG_DH: + WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint8_t *)value); + break; + case UC_X86_REG_DL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint8_t *)value); + break; + case UC_X86_REG_ESP: + X86_CPU(uc, mycpu)->env.regs[R_ESP] = *(uint32_t *)value; + break; + case UC_X86_REG_SP: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESP], *(uint16_t *)value); + break; + case UC_X86_REG_EBP: + X86_CPU(uc, mycpu)->env.regs[R_EBP] = *(uint32_t *)value; + break; + case UC_X86_REG_BP: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBP], *(uint16_t *)value); + break; + case UC_X86_REG_ESI: + X86_CPU(uc, mycpu)->env.regs[R_ESI] = *(uint32_t *)value; + break; + case UC_X86_REG_SI: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESI], *(uint16_t *)value); + break; + case UC_X86_REG_EDI: + X86_CPU(uc, mycpu)->env.regs[R_EDI] = *(uint32_t *)value; + break; + case UC_X86_REG_DI: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDI], *(uint16_t *)value); + break; + case UC_X86_REG_EIP: + X86_CPU(uc, mycpu)->env.eip = *(uint32_t *)value; + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); + break; + case UC_X86_REG_IP: + WRITE_WORD(X86_CPU(uc, mycpu)->env.eip, *(uint16_t *)value); + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); + break; + case UC_X86_REG_CS: + cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_CS, *(uint16_t *)value); + break; + case UC_X86_REG_DS: + cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_DS, *(uint16_t *)value); + break; + case UC_X86_REG_SS: + cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_SS, *(uint16_t *)value); + break; + case UC_X86_REG_ES: + cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_ES, *(uint16_t *)value); + break; + case UC_X86_REG_FS: + cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_FS, *(uint16_t *)value); + break; + case UC_X86_REG_GS: + cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_GS, *(uint16_t *)value); + break; + case UC_X86_REG_IDTR: + X86_CPU(uc, mycpu)->env.idt.limit = (uint16_t)((uc_x86_mmr *)value)->limit; + X86_CPU(uc, mycpu)->env.idt.base = (uint32_t)((uc_x86_mmr *)value)->base; + break; + case UC_X86_REG_GDTR: + X86_CPU(uc, mycpu)->env.gdt.limit = (uint16_t)((uc_x86_mmr *)value)->limit; + X86_CPU(uc, mycpu)->env.gdt.base = (uint32_t)((uc_x86_mmr *)value)->base; + break; + case UC_X86_REG_LDTR: + X86_CPU(uc, mycpu)->env.ldt.limit = ((uc_x86_mmr *)value)->limit; + X86_CPU(uc, mycpu)->env.ldt.base = (uint32_t)((uc_x86_mmr *)value)->base; + X86_CPU(uc, mycpu)->env.ldt.selector = (uint16_t)((uc_x86_mmr *)value)->selector; + X86_CPU(uc, mycpu)->env.ldt.flags = ((uc_x86_mmr *)value)->flags; + break; + case UC_X86_REG_TR: + X86_CPU(uc, mycpu)->env.tr.limit = ((uc_x86_mmr *)value)->limit; + X86_CPU(uc, mycpu)->env.tr.base = (uint32_t)((uc_x86_mmr *)value)->base; + X86_CPU(uc, mycpu)->env.tr.selector = (uint16_t)((uc_x86_mmr *)value)->selector; + X86_CPU(uc, mycpu)->env.tr.flags = ((uc_x86_mmr *)value)->flags; + break; + } + break; #ifdef TARGET_X86_64 - case UC_MODE_64: - switch(regid) { - default: - break; - case UC_X86_REG_CR0 ... UC_X86_REG_CR4: - X86_CPU(uc, mycpu)->env.cr[regid - UC_X86_REG_CR0] = *(uint64_t *)value; - break; - case UC_X86_REG_DR0 ... UC_X86_REG_DR7: - X86_CPU(uc, mycpu)->env.dr[regid - UC_X86_REG_DR0] = *(uint64_t *)value; - break; - case UC_X86_REG_EFLAGS: - X86_CPU(uc, mycpu)->env.eflags = *(uint64_t *)value; - X86_CPU(uc, mycpu)->env.eflags0 = *(uint64_t *)value; - break; - case UC_X86_REG_RAX: - X86_CPU(uc, mycpu)->env.regs[R_EAX] = *(uint64_t *)value; - break; - case UC_X86_REG_EAX: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint32_t *)value); - break; - case UC_X86_REG_AX: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint16_t *)value); - break; - case UC_X86_REG_AH: - WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint8_t *)value); - break; - case UC_X86_REG_AL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint8_t *)value); - break; - case UC_X86_REG_RBX: - X86_CPU(uc, mycpu)->env.regs[R_EBX] = *(uint64_t *)value; - break; - case UC_X86_REG_EBX: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint32_t *)value); - break; - case UC_X86_REG_BX: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint16_t *)value); - break; - case UC_X86_REG_BH: - WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint8_t *)value); - break; - case UC_X86_REG_BL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint8_t *)value); - break; - case UC_X86_REG_RCX: - X86_CPU(uc, mycpu)->env.regs[R_ECX] = *(uint64_t *)value; - break; - case UC_X86_REG_ECX: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint32_t *)value); - break; - case UC_X86_REG_CX: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint16_t *)value); - break; - case UC_X86_REG_CH: - WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint8_t *)value); - break; - case UC_X86_REG_CL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint8_t *)value); - break; - case UC_X86_REG_RDX: - X86_CPU(uc, mycpu)->env.regs[R_EDX] = *(uint64_t *)value; - break; - case UC_X86_REG_EDX: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint32_t *)value); - break; - case UC_X86_REG_DX: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint16_t *)value); - break; - case UC_X86_REG_DH: - WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint8_t *)value); - break; - case UC_X86_REG_DL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint8_t *)value); - break; - case UC_X86_REG_RSP: - X86_CPU(uc, mycpu)->env.regs[R_ESP] = *(uint64_t *)value; - break; - case UC_X86_REG_ESP: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ESP], *(uint32_t *)value); - break; - case UC_X86_REG_SP: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESP], *(uint16_t *)value); - break; - case UC_X86_REG_SPL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ESP], *(uint8_t *)value); - break; - case UC_X86_REG_RBP: - X86_CPU(uc, mycpu)->env.regs[R_EBP] = *(uint64_t *)value; - break; - case UC_X86_REG_EBP: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EBP], *(uint32_t *)value); - break; - case UC_X86_REG_BP: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBP], *(uint16_t *)value); - break; - case UC_X86_REG_BPL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBP], *(uint8_t *)value); - break; - case UC_X86_REG_RSI: - X86_CPU(uc, mycpu)->env.regs[R_ESI] = *(uint64_t *)value; - break; - case UC_X86_REG_ESI: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ESI], *(uint32_t *)value); - break; - case UC_X86_REG_SI: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESI], *(uint16_t *)value); - break; - case UC_X86_REG_SIL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ESI], *(uint8_t *)value); - break; - case UC_X86_REG_RDI: - X86_CPU(uc, mycpu)->env.regs[R_EDI] = *(uint64_t *)value; - break; - case UC_X86_REG_EDI: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EDI], *(uint32_t *)value); - break; - case UC_X86_REG_DI: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDI], *(uint16_t *)value); - break; - case UC_X86_REG_DIL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDI], *(uint8_t *)value); - break; - case UC_X86_REG_RIP: - X86_CPU(uc, mycpu)->env.eip = *(uint64_t *)value; - // force to quit execution and flush TB - uc->quit_request = true; - uc_emu_stop(uc); - break; - case UC_X86_REG_EIP: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.eip, *(uint32_t *)value); - // force to quit execution and flush TB - uc->quit_request = true; - uc_emu_stop(uc); - break; - case UC_X86_REG_IP: - WRITE_WORD(X86_CPU(uc, mycpu)->env.eip, *(uint16_t *)value); - // force to quit execution and flush TB - uc->quit_request = true; - uc_emu_stop(uc); - break; - case UC_X86_REG_CS: - X86_CPU(uc, mycpu)->env.segs[R_CS].selector = *(uint16_t *)value; - break; - case UC_X86_REG_DS: - X86_CPU(uc, mycpu)->env.segs[R_DS].selector = *(uint16_t *)value; - break; - case UC_X86_REG_SS: - X86_CPU(uc, mycpu)->env.segs[R_SS].selector = *(uint16_t *)value; - break; - case UC_X86_REG_ES: - X86_CPU(uc, mycpu)->env.segs[R_ES].selector = *(uint16_t *)value; - break; - case UC_X86_REG_FS: - X86_CPU(uc, mycpu)->env.segs[R_FS].selector = *(uint16_t *)value; - break; - case UC_X86_REG_GS: - X86_CPU(uc, mycpu)->env.segs[R_GS].selector = *(uint16_t *)value; - break; - case UC_X86_REG_R8: - X86_CPU(uc, mycpu)->env.regs[8] = *(uint64_t *)value; - break; - case UC_X86_REG_R8D: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[8], *(uint32_t *)value); - break; - case UC_X86_REG_R8W: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[8], *(uint16_t *)value); - break; - case UC_X86_REG_R8B: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[8], *(uint8_t *)value); - break; - case UC_X86_REG_R9: - X86_CPU(uc, mycpu)->env.regs[9] = *(uint64_t *)value; - break; - case UC_X86_REG_R9D: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[9], *(uint32_t *)value); - break; - case UC_X86_REG_R9W: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[9], *(uint16_t *)value); - break; - case UC_X86_REG_R9B: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[9], *(uint8_t *)value); - break; - case UC_X86_REG_R10: - X86_CPU(uc, mycpu)->env.regs[10] = *(uint64_t *)value; - break; - case UC_X86_REG_R10D: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[10], *(uint32_t *)value); - break; - case UC_X86_REG_R10W: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[10], *(uint16_t *)value); - break; - case UC_X86_REG_R10B: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[10], *(uint8_t *)value); - break; - case UC_X86_REG_R11: - X86_CPU(uc, mycpu)->env.regs[11] = *(uint64_t *)value; - break; - case UC_X86_REG_R11D: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[11], *(uint32_t *)value); - break; - case UC_X86_REG_R11W: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[11], *(uint16_t *)value); - break; - case UC_X86_REG_R11B: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[11], *(uint8_t *)value); - break; - case UC_X86_REG_R12: - X86_CPU(uc, mycpu)->env.regs[12] = *(uint64_t *)value; - break; - case UC_X86_REG_R12D: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[12], *(uint32_t *)value); - break; - case UC_X86_REG_R12W: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[12], *(uint16_t *)value); - break; - case UC_X86_REG_R12B: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[12], *(uint8_t *)value); - break; - case UC_X86_REG_R13: - X86_CPU(uc, mycpu)->env.regs[13] = *(uint64_t *)value; - break; - case UC_X86_REG_R13D: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[13], *(uint32_t *)value); - break; - case UC_X86_REG_R13W: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[13], *(uint16_t *)value); - break; - case UC_X86_REG_R13B: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[13], *(uint8_t *)value); - break; - case UC_X86_REG_R14: - X86_CPU(uc, mycpu)->env.regs[14] = *(uint64_t *)value; - break; - case UC_X86_REG_R14D: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[14], *(uint32_t *)value); - break; - case UC_X86_REG_R14W: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[14], *(uint16_t *)value); - break; - case UC_X86_REG_R14B: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[14], *(uint8_t *)value); - break; - case UC_X86_REG_R15: - X86_CPU(uc, mycpu)->env.regs[15] = *(uint64_t *)value; - break; - case UC_X86_REG_R15D: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[15], *(uint32_t *)value); - break; - case UC_X86_REG_R15W: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[15], *(uint16_t *)value); - break; - case UC_X86_REG_R15B: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[15], *(uint8_t *)value); - break; - case UC_X86_REG_IDTR: - X86_CPU(uc, mycpu)->env.idt.limit = (uint16_t)((uc_x86_mmr *)value)->limit; - X86_CPU(uc, mycpu)->env.idt.base = ((uc_x86_mmr *)value)->base; - break; - case UC_X86_REG_GDTR: - X86_CPU(uc, mycpu)->env.gdt.limit = (uint16_t)((uc_x86_mmr *)value)->limit; - X86_CPU(uc, mycpu)->env.gdt.base = ((uc_x86_mmr *)value)->base; - break; - case UC_X86_REG_LDTR: - X86_CPU(uc, mycpu)->env.ldt.limit = ((uc_x86_mmr *)value)->limit; - X86_CPU(uc, mycpu)->env.ldt.base = ((uc_x86_mmr *)value)->base; - X86_CPU(uc, mycpu)->env.ldt.selector = (uint16_t)((uc_x86_mmr *)value)->selector; - X86_CPU(uc, mycpu)->env.ldt.flags = ((uc_x86_mmr *)value)->flags; - break; - case UC_X86_REG_TR: - X86_CPU(uc, mycpu)->env.tr.limit = ((uc_x86_mmr *)value)->limit; - X86_CPU(uc, mycpu)->env.tr.base = ((uc_x86_mmr *)value)->base; - X86_CPU(uc, mycpu)->env.tr.selector = (uint16_t)((uc_x86_mmr *)value)->selector; - X86_CPU(uc, mycpu)->env.tr.flags = ((uc_x86_mmr *)value)->flags; - break; - } - break; + case UC_MODE_64: + switch(regid) { + default: + break; + case UC_X86_REG_CR0 ... UC_X86_REG_CR4: + X86_CPU(uc, mycpu)->env.cr[regid - UC_X86_REG_CR0] = *(uint64_t *)value; + break; + case UC_X86_REG_DR0 ... UC_X86_REG_DR7: + X86_CPU(uc, mycpu)->env.dr[regid - UC_X86_REG_DR0] = *(uint64_t *)value; + break; + case UC_X86_REG_EFLAGS: + X86_CPU(uc, mycpu)->env.eflags = *(uint64_t *)value; + X86_CPU(uc, mycpu)->env.eflags0 = *(uint64_t *)value; + break; + case UC_X86_REG_RAX: + X86_CPU(uc, mycpu)->env.regs[R_EAX] = *(uint64_t *)value; + break; + case UC_X86_REG_EAX: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint32_t *)value); + break; + case UC_X86_REG_AX: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint16_t *)value); + break; + case UC_X86_REG_AH: + WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint8_t *)value); + break; + case UC_X86_REG_AL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint8_t *)value); + break; + case UC_X86_REG_RBX: + X86_CPU(uc, mycpu)->env.regs[R_EBX] = *(uint64_t *)value; + break; + case UC_X86_REG_EBX: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint32_t *)value); + break; + case UC_X86_REG_BX: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint16_t *)value); + break; + case UC_X86_REG_BH: + WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint8_t *)value); + break; + case UC_X86_REG_BL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint8_t *)value); + break; + case UC_X86_REG_RCX: + X86_CPU(uc, mycpu)->env.regs[R_ECX] = *(uint64_t *)value; + break; + case UC_X86_REG_ECX: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint32_t *)value); + break; + case UC_X86_REG_CX: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint16_t *)value); + break; + case UC_X86_REG_CH: + WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint8_t *)value); + break; + case UC_X86_REG_CL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint8_t *)value); + break; + case UC_X86_REG_RDX: + X86_CPU(uc, mycpu)->env.regs[R_EDX] = *(uint64_t *)value; + break; + case UC_X86_REG_EDX: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint32_t *)value); + break; + case UC_X86_REG_DX: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint16_t *)value); + break; + case UC_X86_REG_DH: + WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint8_t *)value); + break; + case UC_X86_REG_DL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint8_t *)value); + break; + case UC_X86_REG_RSP: + X86_CPU(uc, mycpu)->env.regs[R_ESP] = *(uint64_t *)value; + break; + case UC_X86_REG_ESP: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ESP], *(uint32_t *)value); + break; + case UC_X86_REG_SP: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESP], *(uint16_t *)value); + break; + case UC_X86_REG_SPL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ESP], *(uint8_t *)value); + break; + case UC_X86_REG_RBP: + X86_CPU(uc, mycpu)->env.regs[R_EBP] = *(uint64_t *)value; + break; + case UC_X86_REG_EBP: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EBP], *(uint32_t *)value); + break; + case UC_X86_REG_BP: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBP], *(uint16_t *)value); + break; + case UC_X86_REG_BPL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBP], *(uint8_t *)value); + break; + case UC_X86_REG_RSI: + X86_CPU(uc, mycpu)->env.regs[R_ESI] = *(uint64_t *)value; + break; + case UC_X86_REG_ESI: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ESI], *(uint32_t *)value); + break; + case UC_X86_REG_SI: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESI], *(uint16_t *)value); + break; + case UC_X86_REG_SIL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ESI], *(uint8_t *)value); + break; + case UC_X86_REG_RDI: + X86_CPU(uc, mycpu)->env.regs[R_EDI] = *(uint64_t *)value; + break; + case UC_X86_REG_EDI: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EDI], *(uint32_t *)value); + break; + case UC_X86_REG_DI: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDI], *(uint16_t *)value); + break; + case UC_X86_REG_DIL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDI], *(uint8_t *)value); + break; + case UC_X86_REG_RIP: + X86_CPU(uc, mycpu)->env.eip = *(uint64_t *)value; + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); + break; + case UC_X86_REG_EIP: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.eip, *(uint32_t *)value); + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); + break; + case UC_X86_REG_IP: + WRITE_WORD(X86_CPU(uc, mycpu)->env.eip, *(uint16_t *)value); + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); + break; + case UC_X86_REG_CS: + X86_CPU(uc, mycpu)->env.segs[R_CS].selector = *(uint16_t *)value; + break; + case UC_X86_REG_DS: + X86_CPU(uc, mycpu)->env.segs[R_DS].selector = *(uint16_t *)value; + break; + case UC_X86_REG_SS: + X86_CPU(uc, mycpu)->env.segs[R_SS].selector = *(uint16_t *)value; + break; + case UC_X86_REG_ES: + X86_CPU(uc, mycpu)->env.segs[R_ES].selector = *(uint16_t *)value; + break; + case UC_X86_REG_FS: + X86_CPU(uc, mycpu)->env.segs[R_FS].selector = *(uint16_t *)value; + break; + case UC_X86_REG_GS: + X86_CPU(uc, mycpu)->env.segs[R_GS].selector = *(uint16_t *)value; + break; + case UC_X86_REG_R8: + X86_CPU(uc, mycpu)->env.regs[8] = *(uint64_t *)value; + break; + case UC_X86_REG_R8D: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[8], *(uint32_t *)value); + break; + case UC_X86_REG_R8W: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[8], *(uint16_t *)value); + break; + case UC_X86_REG_R8B: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[8], *(uint8_t *)value); + break; + case UC_X86_REG_R9: + X86_CPU(uc, mycpu)->env.regs[9] = *(uint64_t *)value; + break; + case UC_X86_REG_R9D: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[9], *(uint32_t *)value); + break; + case UC_X86_REG_R9W: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[9], *(uint16_t *)value); + break; + case UC_X86_REG_R9B: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[9], *(uint8_t *)value); + break; + case UC_X86_REG_R10: + X86_CPU(uc, mycpu)->env.regs[10] = *(uint64_t *)value; + break; + case UC_X86_REG_R10D: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[10], *(uint32_t *)value); + break; + case UC_X86_REG_R10W: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[10], *(uint16_t *)value); + break; + case UC_X86_REG_R10B: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[10], *(uint8_t *)value); + break; + case UC_X86_REG_R11: + X86_CPU(uc, mycpu)->env.regs[11] = *(uint64_t *)value; + break; + case UC_X86_REG_R11D: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[11], *(uint32_t *)value); + break; + case UC_X86_REG_R11W: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[11], *(uint16_t *)value); + break; + case UC_X86_REG_R11B: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[11], *(uint8_t *)value); + break; + case UC_X86_REG_R12: + X86_CPU(uc, mycpu)->env.regs[12] = *(uint64_t *)value; + break; + case UC_X86_REG_R12D: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[12], *(uint32_t *)value); + break; + case UC_X86_REG_R12W: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[12], *(uint16_t *)value); + break; + case UC_X86_REG_R12B: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[12], *(uint8_t *)value); + break; + case UC_X86_REG_R13: + X86_CPU(uc, mycpu)->env.regs[13] = *(uint64_t *)value; + break; + case UC_X86_REG_R13D: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[13], *(uint32_t *)value); + break; + case UC_X86_REG_R13W: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[13], *(uint16_t *)value); + break; + case UC_X86_REG_R13B: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[13], *(uint8_t *)value); + break; + case UC_X86_REG_R14: + X86_CPU(uc, mycpu)->env.regs[14] = *(uint64_t *)value; + break; + case UC_X86_REG_R14D: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[14], *(uint32_t *)value); + break; + case UC_X86_REG_R14W: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[14], *(uint16_t *)value); + break; + case UC_X86_REG_R14B: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[14], *(uint8_t *)value); + break; + case UC_X86_REG_R15: + X86_CPU(uc, mycpu)->env.regs[15] = *(uint64_t *)value; + break; + case UC_X86_REG_R15D: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[15], *(uint32_t *)value); + break; + case UC_X86_REG_R15W: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[15], *(uint16_t *)value); + break; + case UC_X86_REG_R15B: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[15], *(uint8_t *)value); + break; + case UC_X86_REG_IDTR: + X86_CPU(uc, mycpu)->env.idt.limit = (uint16_t)((uc_x86_mmr *)value)->limit; + X86_CPU(uc, mycpu)->env.idt.base = ((uc_x86_mmr *)value)->base; + break; + case UC_X86_REG_GDTR: + X86_CPU(uc, mycpu)->env.gdt.limit = (uint16_t)((uc_x86_mmr *)value)->limit; + X86_CPU(uc, mycpu)->env.gdt.base = ((uc_x86_mmr *)value)->base; + break; + case UC_X86_REG_LDTR: + X86_CPU(uc, mycpu)->env.ldt.limit = ((uc_x86_mmr *)value)->limit; + X86_CPU(uc, mycpu)->env.ldt.base = ((uc_x86_mmr *)value)->base; + X86_CPU(uc, mycpu)->env.ldt.selector = (uint16_t)((uc_x86_mmr *)value)->selector; + X86_CPU(uc, mycpu)->env.ldt.flags = ((uc_x86_mmr *)value)->flags; + break; + case UC_X86_REG_TR: + X86_CPU(uc, mycpu)->env.tr.limit = ((uc_x86_mmr *)value)->limit; + X86_CPU(uc, mycpu)->env.tr.base = ((uc_x86_mmr *)value)->base; + X86_CPU(uc, mycpu)->env.tr.selector = (uint16_t)((uc_x86_mmr *)value)->selector; + X86_CPU(uc, mycpu)->env.tr.flags = ((uc_x86_mmr *)value)->flags; + break; + } + break; #endif + } } return 0; diff --git a/qemu/target-i386/unicorn.h b/qemu/target-i386/unicorn.h index a4dda81e..37e38b4f 100644 --- a/qemu/target-i386/unicorn.h +++ b/qemu/target-i386/unicorn.h @@ -5,8 +5,8 @@ #define UC_QEMU_TARGET_I386_H // functions to read & write registers -int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value); -int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); +int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count); +int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count); void x86_reg_reset(struct uc_struct *uc); diff --git a/qemu/target-m68k/unicorn.c b/qemu/target-m68k/unicorn.c index 0edf04c2..d2818cfe 100644 --- a/qemu/target-m68k/unicorn.c +++ b/qemu/target-m68k/unicorn.c @@ -25,47 +25,56 @@ void m68k_reg_reset(struct uc_struct *uc) env->pc = 0; } -int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value) +int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) - *(int32_t *)value = M68K_CPU(uc, mycpu)->env.aregs[regid - UC_M68K_REG_A0]; - else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7) - *(int32_t *)value = M68K_CPU(uc, mycpu)->env.dregs[regid - UC_M68K_REG_D0]; - else { - switch(regid) { - default: break; - case UC_M68K_REG_PC: - *(int32_t *)value = M68K_CPU(uc, mycpu)->env.pc; - break; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) + *(int32_t *)value = M68K_CPU(uc, mycpu)->env.aregs[regid - UC_M68K_REG_A0]; + else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7) + *(int32_t *)value = M68K_CPU(uc, mycpu)->env.dregs[regid - UC_M68K_REG_D0]; + else { + switch(regid) { + default: break; + case UC_M68K_REG_PC: + *(int32_t *)value = M68K_CPU(uc, mycpu)->env.pc; + break; + } } } return 0; } -int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) +int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) - M68K_CPU(uc, mycpu)->env.aregs[regid - UC_M68K_REG_A0] = *(uint32_t *)value; - else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7) - M68K_CPU(uc, mycpu)->env.dregs[regid - UC_M68K_REG_D0] = *(uint32_t *)value; - else { - switch(regid) { - default: break; - case UC_M68K_REG_PC: - M68K_CPU(uc, mycpu)->env.pc = *(uint32_t *)value; - // force to quit execution and flush TB - uc->quit_request = true; - uc_emu_stop(uc); - break; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) + M68K_CPU(uc, mycpu)->env.aregs[regid - UC_M68K_REG_A0] = *(uint32_t *)value; + else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7) + M68K_CPU(uc, mycpu)->env.dregs[regid - UC_M68K_REG_D0] = *(uint32_t *)value; + else { + switch(regid) { + default: break; + case UC_M68K_REG_PC: + M68K_CPU(uc, mycpu)->env.pc = *(uint32_t *)value; + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); + break; + } } } - return 0; } diff --git a/qemu/target-m68k/unicorn.h b/qemu/target-m68k/unicorn.h index 37ea828f..7cf8e21a 100644 --- a/qemu/target-m68k/unicorn.h +++ b/qemu/target-m68k/unicorn.h @@ -5,8 +5,8 @@ #define UC_QEMU_TARGET_M68K_H // functions to read & write registers -int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value); -int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); +int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count); +int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count); void m68k_reg_reset(struct uc_struct *uc); diff --git a/qemu/target-mips/unicorn.c b/qemu/target-mips/unicorn.c index 7740d0d9..ec8779bf 100644 --- a/qemu/target-mips/unicorn.c +++ b/qemu/target-mips/unicorn.c @@ -39,43 +39,52 @@ void mips_reg_reset(struct uc_struct *uc) env->active_tc.PC = 0; } -int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value) +int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) - *(int32_t *)value = MIPS_CPU(uc, mycpu)->env.active_tc.gpr[regid - UC_MIPS_REG_0]; - else { - switch(regid) { - default: break; - case UC_MIPS_REG_PC: - *(int32_t *)value = MIPS_CPU(uc, mycpu)->env.active_tc.PC; - break; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) + *(int32_t *)value = MIPS_CPU(uc, mycpu)->env.active_tc.gpr[regid - UC_MIPS_REG_0]; + else { + switch(regid) { + default: break; + case UC_MIPS_REG_PC: + *(int32_t *)value = MIPS_CPU(uc, mycpu)->env.active_tc.PC; + break; + } } } return 0; } -int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) +int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) - MIPS_CPU(uc, mycpu)->env.active_tc.gpr[regid - UC_MIPS_REG_0] = *(uint32_t *)value; - else { - switch(regid) { - default: break; - case UC_MIPS_REG_PC: - MIPS_CPU(uc, mycpu)->env.active_tc.PC = *(uint32_t *)value; - // force to quit execution and flush TB - uc->quit_request = true; - uc_emu_stop(uc); - break; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) + MIPS_CPU(uc, mycpu)->env.active_tc.gpr[regid - UC_MIPS_REG_0] = *(uint32_t *)value; + else { + switch(regid) { + default: break; + case UC_MIPS_REG_PC: + MIPS_CPU(uc, mycpu)->env.active_tc.PC = *(uint32_t *)value; + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); + break; + } } } - return 0; } diff --git a/qemu/target-mips/unicorn.h b/qemu/target-mips/unicorn.h index 874b82f1..c9639eb8 100644 --- a/qemu/target-mips/unicorn.h +++ b/qemu/target-mips/unicorn.h @@ -5,8 +5,8 @@ #define UC_QEMU_TARGET_MIPS_H // functions to read & write registers -int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value); -int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); +int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count); +int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count); void mips_reg_reset(struct uc_struct *uc); diff --git a/qemu/target-sparc/unicorn.c b/qemu/target-sparc/unicorn.c index 3775776a..a2a3dcaa 100644 --- a/qemu/target-sparc/unicorn.c +++ b/qemu/target-sparc/unicorn.c @@ -39,52 +39,62 @@ void sparc_reg_reset(struct uc_struct *uc) env->regwptr = env->regbase; } -int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) +int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) - *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0]; - else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) - *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0]; - else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) - *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0]; - else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) - *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0]; - else { - switch(regid) { - default: break; - case UC_SPARC_REG_PC: - *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.pc; - break; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) + *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0]; + else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) + *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0]; + else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) + *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0]; + else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) + *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0]; + else { + switch(regid) { + default: break; + case UC_SPARC_REG_PC: + *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.pc; + break; + } } } return 0; } -int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) +int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) - SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint32_t *)value; - else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) - SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0] = *(uint32_t *)value; - else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) - SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint32_t *)value; - else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) - SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint32_t *)value; - else { - switch(regid) { - default: break; - case UC_SPARC_REG_PC: - SPARC_CPU(uc, mycpu)->env.pc = *(uint32_t *)value; - SPARC_CPU(uc, mycpu)->env.npc = *(uint32_t *)value + 4; - // force to quit execution and flush TB - uc->quit_request = true; - uc_emu_stop(uc); - break; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) + SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint32_t *)value; + else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) + SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0] = *(uint32_t *)value; + else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) + SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint32_t *)value; + else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) + SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint32_t *)value; + else { + switch(regid) { + default: break; + case UC_SPARC_REG_PC: + SPARC_CPU(uc, mycpu)->env.pc = *(uint32_t *)value; + SPARC_CPU(uc, mycpu)->env.npc = *(uint32_t *)value + 4; + // force to quit execution and flush TB + uc->quit_request = true; + uc_emu_stop(uc); + break; + } } } diff --git a/qemu/target-sparc/unicorn.h b/qemu/target-sparc/unicorn.h index 89771827..53bf1303 100644 --- a/qemu/target-sparc/unicorn.h +++ b/qemu/target-sparc/unicorn.h @@ -5,8 +5,8 @@ #define UC_QEMU_TARGET_SPARC_H // functions to read & write registers -int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value); -int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); +int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count); +int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count); void sparc_reg_reset(struct uc_struct *uc); diff --git a/qemu/target-sparc/unicorn64.c b/qemu/target-sparc/unicorn64.c index ef99b5ab..9a748936 100644 --- a/qemu/target-sparc/unicorn64.c +++ b/qemu/target-sparc/unicorn64.c @@ -39,53 +39,62 @@ void sparc_reg_reset(struct uc_struct *uc) env->regwptr = env->regbase; } -int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) +int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) - *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0]; - else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) - *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0]; - else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) - *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0]; - else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) - *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0]; - else { - switch(regid) { - default: break; - case UC_SPARC_REG_PC: - *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.pc; - break; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) + *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0]; + else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) + *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0]; + else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) + *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0]; + else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) + *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0]; + else { + switch(regid) { + default: break; + case UC_SPARC_REG_PC: + *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.pc; + break; + } } } return 0; } -int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) +int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void* const* vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) - SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint64_t *)value; - else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) - SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0] = *(uint64_t *)value; - else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) - SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint64_t *)value; - else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) - SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint64_t *)value; - else { - switch(regid) { - default: break; - case UC_SPARC_REG_PC: - SPARC_CPU(uc, mycpu)->env.pc = *(uint64_t *)value; - SPARC_CPU(uc, mycpu)->env.npc = *(uint64_t *)value + 4; - break; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) + SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint64_t *)value; + else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) + SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0] = *(uint64_t *)value; + else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) + SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint64_t *)value; + else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) + SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint64_t *)value; + else { + switch(regid) { + default: break; + case UC_SPARC_REG_PC: + SPARC_CPU(uc, mycpu)->env.pc = *(uint64_t *)value; + SPARC_CPU(uc, mycpu)->env.npc = *(uint64_t *)value + 4; + break; + } } } - return 0; } diff --git a/uc.c b/uc.c index af504fe1..90ea8da3 100644 --- a/uc.c +++ b/uc.c @@ -332,10 +332,10 @@ uc_err uc_close(uc_engine *uc) UNICORN_EXPORT -uc_err uc_reg_read(uc_engine *uc, int regid, void *value) +uc_err uc_reg_read_batch(uc_engine *uc, int *ids, void **vals, int count) { if (uc->reg_read) - uc->reg_read(uc, regid, value); + uc->reg_read(uc, (unsigned int *)ids, vals, count); else return -1; // FIXME: need a proper uc_err @@ -344,10 +344,10 @@ uc_err uc_reg_read(uc_engine *uc, int regid, void *value) UNICORN_EXPORT -uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) +uc_err uc_reg_write_batch(uc_engine *uc, int *ids, void *const *vals, int count) { if (uc->reg_write) - uc->reg_write(uc, regid, value); + uc->reg_write(uc, (unsigned int *)ids, vals, count); else return -1; // FIXME: need a proper uc_err @@ -355,6 +355,20 @@ uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) } +UNICORN_EXPORT +uc_err uc_reg_read(uc_engine *uc, int regid, void *value) +{ + return uc_reg_read_batch(uc, ®id, &value, 1); +} + + +UNICORN_EXPORT +uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) +{ + return uc_reg_write_batch(uc, ®id, (void *const *)&value, 1); +} + + // check if a memory area is mapped // this is complicated because an area can overlap adjacent blocks static bool check_mem_area(uc_engine *uc, uint64_t address, size_t size) From 159f9310aa388dd4f6ecaff3795cbdd94b8b1f6a Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Mon, 4 Apr 2016 20:52:26 -0700 Subject: [PATCH 106/149] add sample_batch_reg --- samples/Makefile | 3 +- samples/sample_batch_reg.c | 90 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 samples/sample_batch_reg.c diff --git a/samples/Makefile b/samples/Makefile index 1850dceb..3cbaf69b 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -101,6 +101,7 @@ SOURCES += sample_x86.c SOURCES += shellcode.c SOURCES += mem_apis.c SOURCES += sample_x86_32_gdt_and_seg_regs.c +SOURCES += sample_batch_reg.c endif ifneq (,$(findstring m68k,$(UNICORN_ARCHS))) SOURCES += sample_m68k.c @@ -114,7 +115,7 @@ all: clean_bins $(BINARY) clean_bins: rm -rf *.o $(OBJS_ELF) $(BINARY) $(SAMPLEDIR)/*.exe $(SAMPLEDIR)/*.static $(OBJDIR)/lib$(LIBNAME)* $(OBJDIR)/$(LIBNAME)* - rm -rf sample_x86 sample_arm sample_arm64 sample_mips sample_sparc sample_ppc sample_m68k shellcode mem_apis sample_x86_32_gdt_and_seg_regs + rm -rf sample_x86 sample_arm sample_arm64 sample_mips sample_sparc sample_ppc sample_m68k shellcode mem_apis sample_x86_32_gdt_and_seg_regs sample_batch_reg clean_libs: rm -rf libunicorn*.so libunicorn*.lib libunicorn*.dylib unicorn*.dll unicorn*.lib diff --git a/samples/sample_batch_reg.c b/samples/sample_batch_reg.c new file mode 100644 index 00000000..2e5e0468 --- /dev/null +++ b/samples/sample_batch_reg.c @@ -0,0 +1,90 @@ +#include +#include +#include +#include + +int syscall_abi[] = {UC_X86_REG_RAX, UC_X86_REG_RDI, UC_X86_REG_RSI, UC_X86_REG_RDX, UC_X86_REG_R10, UC_X86_REG_R8, UC_X86_REG_R9}; +uint64_t vals[7] = {200, 10, 11, 12, 13, 14, 15}; +// This part of the API is less... clean... because Unicorn supports arbitrary register types. +// So the least intrusive solution is passing individual pointers. +// On the plus side, you only need to make this pointer array once. +void *ptrs[7]; + +void uc_perror(const char *func, uc_err err) { + fprintf(stderr, "Error in %s(): %s\n", func, uc_strerror(err)); +} + +#define BASE 0x10000 + +// mov rax, 100; mov rdi, 1; mov rsi, 2; mov rdx, 3; mov r10, 4; mov r8, 5; mov r9, 6; syscall +#define CODE "\x48\xc7\xc0\x64\x00\x00\x00\x48\xc7\xc7\x01\x00\x00\x00\x48\xc7\xc6\x02\x00\x00\x00\x48\xc7\xc2\x03\x00\x00\x00\x49\xc7\xc2\x04\x00\x00\x00\x49\xc7\xc0\x05\x00\x00\x00\x49\xc7\xc1\x06\x00\x00\x00\x0f\x05" + +void hook_syscall(uc_engine *uc, void *user_data) { + int i; + uc_reg_read_batch(uc, syscall_abi, ptrs, 7); + printf("syscall: {"); + for (i = 0; i < 7; i++) { + if (i != 0) printf(", "); + printf("%llu", vals[i]); + } + printf("}\n"); +} + +void hook_code(uc_engine *uc, uint64_t addr, uint32_t size, void *user_data) { + printf("HOOK_CODE: 0x%llx, 0x%x\n", addr, size); +} + +int main() { + int i; + // set up register pointers + for (i = 0; i < 7; i++) { + ptrs[i] = &vals[i]; + } + + uc_err err; + uc_engine *uc; + if ((err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc))) { + uc_perror("uc_open", err); + return 1; + } + + // reg_write_batch + printf("reg_write_batch({200, 10, 11, 12, 13, 14, 15})\n"); + if ((err = uc_reg_write_batch(uc, syscall_abi, ptrs, 7))) { + uc_perror("uc_reg_write_batch", err); + return 1; + } + // reg_read_batch + memset(vals, 0, sizeof(vals)); + if ((err = uc_reg_read_batch(uc, syscall_abi, ptrs, 7))) { + uc_perror("uc_reg_read_batch", err); + return 1; + } + printf("reg_read_batch = {"); + for (i = 0; i < 7; i++) { + if (i != 0) printf(", "); + printf("%llu", vals[i]); + } + printf("}\n"); + + // syscall + printf("\n"); + printf("running syscall shellcode\n"); + uc_hook sys_hook; + if ((err = uc_hook_add(uc, &sys_hook, UC_HOOK_INSN, hook_syscall, NULL, 1, 0, UC_X86_INS_SYSCALL))) { + uc_perror("uc_hook_add", err); + return 1; + } + if ((err = uc_mem_map(uc, BASE, 0x1000, UC_PROT_ALL))) { + uc_perror("uc_mem_map", err); + return 1; + } + if ((err = uc_mem_write(uc, BASE, CODE, sizeof(CODE) - 1))) { + uc_perror("uc_mem_write", err); + return 1; + } + if ((err = uc_emu_start(uc, BASE, BASE + sizeof(CODE) - 1, 0, 0))) { + uc_perror("uc_emu_start", err); + return 1; + } +} From 1120a22b4d2e8560b260ff814f2bdc2148642dd5 Mon Sep 17 00:00:00 2001 From: emdel Date: Tue, 5 Apr 2016 06:11:21 -0700 Subject: [PATCH 107/149] test case for the dynmaic translator buffer issue --- tests/regress/translator_buffer.py | 78 ++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 tests/regress/translator_buffer.py diff --git a/tests/regress/translator_buffer.py b/tests/regress/translator_buffer.py new file mode 100644 index 00000000..c302ff18 --- /dev/null +++ b/tests/regress/translator_buffer.py @@ -0,0 +1,78 @@ +#!/usr/bin/python +# By Mariano Graziano + +from unicorn import * +from unicorn.x86_const import * + +import regress, struct + + +class Emulator: + def __init__(self, code, stack): + self.mask = 0xFFFFFFFFFFFFF000 + self.unicorn_code = code + self.unicorn_stack = stack + self.mu = Uc(UC_ARCH_X86, UC_MODE_64) + size = 1 * 4096 + self.mu.mem_map(code & self.mask, size) + size = 1 * 4096 + self.mu.mem_map(stack & self.mask, size) + self.set_hooks() + + def set_hooks(self): + self.mu.hook_add(UC_HOOK_MEM_WRITE, self.hook_mem_access) + self.mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, self.hook_mem_invalid) + self.mu.hook_add(UC_HOOK_MEM_FETCH_UNMAPPED, self.hook_mem_fetch_unmapped) + + def hook_mem_fetch_unmapped(self, uc, access, address, size, value, user_data): + next_ip = self.unicorn_code + size + self.mu.reg_write(UC_X86_REG_RIP, next_ip) + self.mu.mem_write(next_ip, "\x90") + self.mu.reg_write(UC_X86_REG_RIP, address) + return True + + def hook_mem_invalid(self, uc, access, address, size, value, user_data): + return True + + def hook_mem_access(self, uc, access, address, size, value, user_data): + return True + + def emu(self, size): + ip = self.mu.reg_read(UC_X86_REG_RIP) + try: + self.mu.emu_start(ip, ip + size, timeout=10000, count=1) + except UcError as e: + print("Error %s" % e) + + def write_data(self, address, content): + self.mu.mem_write(address, content) + + +class Init(regress.RegressTest): + def init_unicorn(self, ip, sp, counter): + print "[+] Emulating IP: %x SP: %x - Counter: %x" % (ip, sp, counter) + E = Emulator(ip, sp) + E.write_data(ip, "\x90") + E.write_data(sp, self.generate_value(counter)) + E.mu.reg_write(UC_X86_REG_RSP, sp) + E.mu.reg_write(UC_X86_REG_RIP, ip) + E.emu(1) + + def generate_value(self, counter): + start = 0xffff880026f02000 + offset = counter * 8 + address = start + offset + return struct.pack(" Date: Tue, 5 Apr 2016 21:40:02 +0800 Subject: [PATCH 108/149] regress: chmod +x translator_buffer.py --- tests/regress/translator_buffer.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tests/regress/translator_buffer.py diff --git a/tests/regress/translator_buffer.py b/tests/regress/translator_buffer.py old mode 100644 new mode 100755 From 67ae30a2fbe7bcc9cfa69d7e8987e088fa42d96f Mon Sep 17 00:00:00 2001 From: Zach Riggle Date: Tue, 5 Apr 2016 09:51:44 -0700 Subject: [PATCH 109/149] Add test showing failure to track targets properly when single-stepping. This issue breaks emulation of conditional instructions on amd64. --- tests/regress/x86_64_conditional_jump.py | 39 ++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100755 tests/regress/x86_64_conditional_jump.py diff --git a/tests/regress/x86_64_conditional_jump.py b/tests/regress/x86_64_conditional_jump.py new file mode 100755 index 00000000..7a401052 --- /dev/null +++ b/tests/regress/x86_64_conditional_jump.py @@ -0,0 +1,39 @@ +#!/usr/bin/python +import regress +import unicorn as U + +class WrongConditionalPath(regress.RegressTest): + def test_eflags(self): + # 0: 4d 31 f6 xor r14, r14 + # 3: 45 85 f6 test r14d, r14d + # 6: 75 fe jne 0x6 + # 8: f4 hlt + CODE = 'M1\xf6E\x85\xf6u\xfe\xf4' + + uc = U.Uc(U.UC_ARCH_X86, U.UC_MODE_64) + uc.reg_write(U.x86_const.UC_X86_REG_RIP, 0x6000b0) + uc.reg_write(U.x86_const.UC_X86_REG_EFLAGS, 0x246) + + uc.mem_map(0x600000, 0x1000) + uc.mem_write(0x6000b0, CODE) + + uc.emu_start(0x6000b0 + 6, 0, count=1) + + # Here's the original execution trace for this on qemu-user. + # + # $ SC='xor r14,r14; test r14d, r14d; jne $; hlt' + # $ asm --context amd64 --format elf $SC > example + # $ qemu-x86_64-static -d cpu,in_asm -singlestep ./test \ + # | grep -E 'RFL|^0x' + # 0x00000000006000b0: xor %r14,%r14 + # RIP=00000000006000b0 RFL=00000202 [-------] CPL=3 II=0 A20=1 SMM=0 HLT=0 + # 0x00000000006000b3: test %r14d,%r14d + # RIP=00000000006000b3 RFL=00000246 [---Z-P-] CPL=3 II=0 A20=1 SMM=0 HLT=0 + # 0x00000000006000b6: jne 0x6000b6 + # RIP=00000000006000b6 RFL=00000246 [---Z-P-] CPL=3 II=0 A20=1 SMM=0 HLT=0 + # 0x00000000006000b8: hlt + # RIP=00000000006000b8 RFL=00000246 [---Z-P-] CPL=3 II=0 A20=1 SMM=0 HLT=0 + self.assertEqual(0x6000b0 + 8, uc.reg_read(U.x86_const.UC_X86_REG_RIP)) + +if __name__ == '__main__': + regress.main() From 74aaf3b321487be1e18c8de6f5dc26c3a39c12a6 Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Wed, 6 Apr 2016 09:21:36 +1000 Subject: [PATCH 110/149] Haskell bindings These Haskell bindings make large use of c2hs to generate much of the code, so Unicorn's const_generator is not used. The emulator is based on the Either monad transformer. The IO monad is used to run the underlying Unicorn library, while the Either monad is used to handle errors. Instructions on how to build the bindings are located in bindings/haskell/README.TXT. The same samples found in samples/ can be found in bindings/haskell/samples. They should produce the same output, with slight differences in their error handling and messaging. --- CREDITS.TXT | 1 + README.md | 2 +- bindings/README | 1 + bindings/haskell/.gitignore | 16 + bindings/haskell/README.TXT | 21 + bindings/haskell/Setup.hs | 2 + bindings/haskell/samples/SampleArm.hs | 133 ++++ bindings/haskell/samples/SampleArm64.hs | 85 +++ bindings/haskell/samples/SampleM68k.hs | 142 ++++ bindings/haskell/samples/SampleMips.hs | 129 ++++ bindings/haskell/samples/SampleSparc.hs | 85 +++ bindings/haskell/samples/SampleX86.hs | 675 ++++++++++++++++++ bindings/haskell/samples/Shellcode.hs | 153 ++++ bindings/haskell/src/Unicorn.hs | 284 ++++++++ bindings/haskell/src/Unicorn/CPU/Arm.chs | 29 + bindings/haskell/src/Unicorn/CPU/Arm64.chs | 29 + bindings/haskell/src/Unicorn/CPU/M68k.chs | 29 + bindings/haskell/src/Unicorn/CPU/Mips.chs | 61 ++ bindings/haskell/src/Unicorn/CPU/Sparc.chs | 29 + bindings/haskell/src/Unicorn/CPU/X86.chs | 65 ++ bindings/haskell/src/Unicorn/Hook.hs | 224 ++++++ .../haskell/src/Unicorn/Internal/Core.chs | 52 ++ .../haskell/src/Unicorn/Internal/Hook.chs | 415 +++++++++++ .../haskell/src/Unicorn/Internal/Unicorn.chs | 242 +++++++ bindings/haskell/src/Unicorn/Internal/Util.hs | 25 + bindings/haskell/src/cbits/unicorn_wrapper.c | 8 + .../haskell/src/include/unicorn_wrapper.h | 16 + bindings/haskell/unicorn.cabal | 42 ++ 28 files changed, 2994 insertions(+), 1 deletion(-) create mode 100644 bindings/haskell/.gitignore create mode 100644 bindings/haskell/README.TXT create mode 100644 bindings/haskell/Setup.hs create mode 100644 bindings/haskell/samples/SampleArm.hs create mode 100644 bindings/haskell/samples/SampleArm64.hs create mode 100644 bindings/haskell/samples/SampleM68k.hs create mode 100644 bindings/haskell/samples/SampleMips.hs create mode 100644 bindings/haskell/samples/SampleSparc.hs create mode 100644 bindings/haskell/samples/SampleX86.hs create mode 100644 bindings/haskell/samples/Shellcode.hs create mode 100644 bindings/haskell/src/Unicorn.hs create mode 100644 bindings/haskell/src/Unicorn/CPU/Arm.chs create mode 100644 bindings/haskell/src/Unicorn/CPU/Arm64.chs create mode 100644 bindings/haskell/src/Unicorn/CPU/M68k.chs create mode 100644 bindings/haskell/src/Unicorn/CPU/Mips.chs create mode 100644 bindings/haskell/src/Unicorn/CPU/Sparc.chs create mode 100644 bindings/haskell/src/Unicorn/CPU/X86.chs create mode 100644 bindings/haskell/src/Unicorn/Hook.hs create mode 100644 bindings/haskell/src/Unicorn/Internal/Core.chs create mode 100644 bindings/haskell/src/Unicorn/Internal/Hook.chs create mode 100644 bindings/haskell/src/Unicorn/Internal/Unicorn.chs create mode 100644 bindings/haskell/src/Unicorn/Internal/Util.hs create mode 100644 bindings/haskell/src/cbits/unicorn_wrapper.c create mode 100644 bindings/haskell/src/include/unicorn_wrapper.h create mode 100644 bindings/haskell/unicorn.cabal diff --git a/CREDITS.TXT b/CREDITS.TXT index 8156f74c..72a5ff4c 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -60,3 +60,4 @@ Ryan Hileman: Go binding Antonio Parata: .NET binding Jonathon Reinhart: C unit test Sascha Schirra: Ruby binding +Adrian Herrera: Haskell binding diff --git a/README.md b/README.md index 0f909c7d..8a5bbde8 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Unicorn offers some unparalleled features: - Multi-architecture: ARM, ARM64 (ARMv8), M68K, MIPS, SPARC, and X86 (16, 32, 64-bit) - Clean/simple/lightweight/intuitive architecture-neutral API -- Implemented in pure C language, with bindings for Ruby, Python, Java, MSVC, .NET, Go and Delphi/Free Pascal. +- Implemented in pure C language, with bindings for Ruby, Python, Java, MSVC, .NET, Go, Delphi/Free Pascal and Haskell. - Native support for Windows & *nix (with Mac OSX, Linux, *BSD & Solaris confirmed) - High performance via Just-In-Time compilation - Support for fine-grained instrumentation at various levels diff --git a/bindings/README b/bindings/README index 4c4a2430..a588e24c 100644 --- a/bindings/README +++ b/bindings/README @@ -8,6 +8,7 @@ The following bindings are contributed by community. - .NET binding: by Antonio Parata. - MSVC binding: by Zak Escano - Ruby binding: by Sascha Schirra +- Haskell binding: by Adrian Herrera. More bindings created & maintained externally by community are available as follows. diff --git a/bindings/haskell/.gitignore b/bindings/haskell/.gitignore new file mode 100644 index 00000000..3f4aa15b --- /dev/null +++ b/bindings/haskell/.gitignore @@ -0,0 +1,16 @@ +dist +cabal-dev +*.o +*.hi +*.chi +*.chs.h +*.dyn_o +*.dyn_hi +.virtualenv +.hpc +.hsenv +.cabal-sandbox/ +cabal.sandbox.config +*.prof +*.aux +*.hp diff --git a/bindings/haskell/README.TXT b/bindings/haskell/README.TXT new file mode 100644 index 00000000..dc629c95 --- /dev/null +++ b/bindings/haskell/README.TXT @@ -0,0 +1,21 @@ +This documentation explains how to install Haskell binding for Unicorn +from source. + + +0. Install the core engine as dependency + + Follow README in the root directory to compile & install the core. + + On *nix, this can simply be done by (project root directory): + + $ sudo ./make.sh install + + +1. Change directories into the Haskell bindings, build and install + + $ cd bindings/haskell + $ cabal build + $ cabal install + +If the build fails, try installing c2hs manually (cabal install c2hs) and make +sure that $HOME/.cabal/bin is on your PATH. diff --git a/bindings/haskell/Setup.hs b/bindings/haskell/Setup.hs new file mode 100644 index 00000000..9a994af6 --- /dev/null +++ b/bindings/haskell/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/bindings/haskell/samples/SampleArm.hs b/bindings/haskell/samples/SampleArm.hs new file mode 100644 index 00000000..3de51f36 --- /dev/null +++ b/bindings/haskell/samples/SampleArm.hs @@ -0,0 +1,133 @@ +-- Sample code to demonstrate how to emulate ARM code + +import Unicorn +import Unicorn.Hook +import qualified Unicorn.CPU.Arm as Arm + +import qualified Data.ByteString as BS +import Data.Word +import qualified Numeric as N (showHex) + +-- Code to be emulated +-- +-- mov r0, #0x37; sub r1, r2, r3 +armCode :: BS.ByteString +armCode = BS.pack [0x37, 0x00, 0xa0, 0xe3, 0x03, 0x10, 0x42, 0xe0] + +-- sub sp, #0xc +thumbCode :: BS.ByteString +thumbCode = BS.pack [0x83, 0xb0] + +-- Memory address where emulation starts +address :: Word64 +address = 0x10000 + +-- Pretty-print integral as hex +showHex :: (Integral a, Show a) => a -> String +showHex = + flip N.showHex "" + +-- Calculate code length +codeLength :: Num a => BS.ByteString -> a +codeLength = + fromIntegral . BS.length + +hookBlock :: BlockHook () +hookBlock _ addr size _ = + putStrLn $ ">>> Tracing basic block at 0x" ++ showHex addr ++ + ", block size = 0x" ++ (maybe "0" showHex size) + +hookCode :: CodeHook () +hookCode _ addr size _ = + putStrLn $ ">>> Tracing instruction at 0x" ++ showHex addr ++ + ", instruction size = 0x" ++ (maybe "0" showHex size) + +testArm :: IO () +testArm = do + putStrLn "Emulate ARM code" + + result <- runEmulator $ do + -- Initialize emulator in ARM mode + uc <- open ArchArm [ModeArm] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address armCode + + -- Initialize machine registers + regWrite uc Arm.R0 0x1234 + regWrite uc Arm.R2 0x6789 + regWrite uc Arm.R3 0x3333 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing one instruction at address with customized callback + codeHookAdd uc hookCode () address address + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all the code + let codeLen = codeLength armCode + start uc address (address + codeLen) Nothing Nothing + + -- Return the results + r0 <- regRead uc Arm.R0 + r1 <- regRead uc Arm.R1 + + return (r0, r1) + case result of + Right (r0, r1) -> do + -- Now print out some registers + putStrLn ">>> Emulation done. Below is the CPU context" + putStrLn $ ">>> R0 = 0x" ++ showHex r0 + putStrLn $ ">>> R1 = 0x" ++ showHex r1 + Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++ + strerror err ++ ")" + +testThumb :: IO () +testThumb = do + putStrLn "Emulate THUMB code" + + result <- runEmulator $ do + -- Initialize emulator in ARM mode + uc <- open ArchArm [ModeThumb] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address thumbCode + + -- Initialize machine registers + regWrite uc Arm.Sp 0x1234 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing one instruction at address with customized callback + codeHookAdd uc hookCode () address address + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all the code + let codeLen = codeLength thumbCode + start uc address (address + codeLen) Nothing Nothing + + -- Return the results + sp <- regRead uc Arm.Sp + + return sp + case result of + Right sp -> do + -- Now print out some registers + putStrLn ">>> Emulation done. Below is the CPU context" + putStrLn $ ">>> SP = 0x" ++ showHex sp + Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++ + strerror err ++ ")" + +main :: IO () +main = do + testArm + putStrLn "==========================" + testThumb diff --git a/bindings/haskell/samples/SampleArm64.hs b/bindings/haskell/samples/SampleArm64.hs new file mode 100644 index 00000000..fbed5659 --- /dev/null +++ b/bindings/haskell/samples/SampleArm64.hs @@ -0,0 +1,85 @@ +-- Sample code to demonstrate how to emulate ARM64 code + +import Unicorn +import Unicorn.Hook +import qualified Unicorn.CPU.Arm64 as Arm64 + +import qualified Data.ByteString as BS +import Data.Word +import qualified Numeric as N (showHex) + +-- Code to be emulated +-- +-- add x11, x13, x15 +armCode :: BS.ByteString +armCode = BS.pack [0xab, 0x01, 0x0f, 0x8b] + +-- Memory address where emulation starts +address :: Word64 +address = 0x10000 + +-- Pretty-print integral as hex +showHex :: (Integral a, Show a) => a -> String +showHex = + flip N.showHex "" + +-- Calculate code length +codeLength :: Num a => BS.ByteString -> a +codeLength = + fromIntegral . BS.length + +hookBlock :: BlockHook () +hookBlock _ addr size _ = + putStrLn $ ">>> Tracing basic block at 0x" ++ showHex addr ++ + ", block size = 0x" ++ (maybe "0" showHex size) + +hookCode :: CodeHook () +hookCode _ addr size _ = + putStrLn $ ">>> Tracing instruction at 0x" ++ showHex addr ++ + ", instruction size = 0x" ++ (maybe "0" showHex size) + +testArm64 :: IO () +testArm64 = do + putStrLn "Emulate ARM64 code" + + result <- runEmulator $ do + -- Initialize emulator in ARM mode + uc <- open ArchArm64 [ModeArm] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address armCode + + -- Initialize machine registers + regWrite uc Arm64.X11 0x1234 + regWrite uc Arm64.X13 0x6789 + regWrite uc Arm64.X15 0x3333 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing one instruction at address with customized callback + codeHookAdd uc hookCode ()address address + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all the code + let codeLen = codeLength armCode + start uc address (address + codeLen) Nothing Nothing + + -- Return the results + x11 <- regRead uc Arm64.X11 + + return x11 + case result of + Right x11 -> do + -- Now print out some registers + putStrLn $ ">>> Emulation done. Below is the CPU context" + putStrLn $ ">>> X11 = 0x" ++ showHex x11 + Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++ + strerror err ++ ")" + +main :: IO () +main = + testArm64 diff --git a/bindings/haskell/samples/SampleM68k.hs b/bindings/haskell/samples/SampleM68k.hs new file mode 100644 index 00000000..d77f4cfd --- /dev/null +++ b/bindings/haskell/samples/SampleM68k.hs @@ -0,0 +1,142 @@ +-- Sample code to demonstrate how to emulate m68k code + +import Unicorn +import Unicorn.Hook +import qualified Unicorn.CPU.M68k as M68k + +import qualified Data.ByteString as BS +import Data.Word +import qualified Numeric as N (showHex) + +-- Code to be emulated +-- +-- movq #-19, %d3 +m68kCode :: BS.ByteString +m68kCode = BS.pack [0x76, 0xed] + +-- Memory address where emulation starts +address :: Word64 +address = 0x10000 + +-- Pretty-print integral as hex +showHex :: (Integral a, Show a) => a -> String +showHex = + flip N.showHex "" + +-- Calculate code length +codeLength :: Num a => BS.ByteString -> a +codeLength = + fromIntegral . BS.length + +hookBlock :: BlockHook () +hookBlock _ addr size _ = + putStrLn $ ">>> Tracing basic block at 0x" ++ showHex addr ++ + ", block size = 0x" ++ (maybe "0" showHex size) + +hookCode :: CodeHook () +hookCode _ addr size _ = + putStrLn $ ">>> Tracing instruction at 0x" ++ showHex addr ++ + ", instruction size = 0x" ++ (maybe "0" showHex size) + +testM68k :: IO () +testM68k = do + putStrLn "Emulate M68K code" + + result <- runEmulator $ do + -- Initialize emulator in M68K mode + uc <- open ArchM68k [ModeBigEndian] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address m68kCode + + -- Initialize machine registers + regWrite uc M68k.D0 0x0000 + regWrite uc M68k.D1 0x0000 + regWrite uc M68k.D2 0x0000 + regWrite uc M68k.D3 0x0000 + regWrite uc M68k.D4 0x0000 + regWrite uc M68k.D5 0x0000 + regWrite uc M68k.D6 0x0000 + regWrite uc M68k.D7 0x0000 + + regWrite uc M68k.A0 0x0000 + regWrite uc M68k.A1 0x0000 + regWrite uc M68k.A2 0x0000 + regWrite uc M68k.A3 0x0000 + regWrite uc M68k.A4 0x0000 + regWrite uc M68k.A5 0x0000 + regWrite uc M68k.A6 0x0000 + regWrite uc M68k.A7 0x0000 + + regWrite uc M68k.Pc 0x0000 + regWrite uc M68k.Sr 0x0000 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing all instruction + codeHookAdd uc hookCode () 1 0 + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all the code + let codeLen = codeLength m68kCode + start uc address (address + codeLen) Nothing Nothing + + -- Return the results + d0 <- regRead uc M68k.D0 + d1 <- regRead uc M68k.D1 + d2 <- regRead uc M68k.D2 + d3 <- regRead uc M68k.D3 + d4 <- regRead uc M68k.D4 + d5 <- regRead uc M68k.D5 + d6 <- regRead uc M68k.D6 + d7 <- regRead uc M68k.D7 + + a0 <- regRead uc M68k.A0 + a1 <- regRead uc M68k.A1 + a2 <- regRead uc M68k.A2 + a3 <- regRead uc M68k.A3 + a4 <- regRead uc M68k.A4 + a5 <- regRead uc M68k.A5 + a6 <- regRead uc M68k.A6 + a7 <- regRead uc M68k.A7 + + pc <- regRead uc M68k.Pc + sr <- regRead uc M68k.Sr + + return (d0, d1, d2, d3, d4, d5, d6, d7, + a0, a1, a2, a3, a4, a5, a6, a7, + pc, sr) + case result of + Right (d0, d1, d2, d3, d4, d5, d6, d7, + a0, a1, a2, a3, a4, a5, a6, a7, + pc, sr) -> do + -- Now print out some registers + putStrLn ">>> Emulation done. Below is the CPU context" + putStrLn $ ">>> A0 = 0x" ++ showHex a0 ++ + "\t\t>>> D0 = 0x" ++ showHex d0 + putStrLn $ ">>> A1 = 0x" ++ showHex a1 ++ + "\t\t>>> D1 = 0x" ++ showHex d1 + putStrLn $ ">>> A2 = 0x" ++ showHex a2 ++ + "\t\t>>> D2 = 0x" ++ showHex d2 + putStrLn $ ">>> A3 = 0x" ++ showHex a3 ++ + "\t\t>>> D3 = 0x" ++ showHex d3 + putStrLn $ ">>> A4 = 0x" ++ showHex a4 ++ + "\t\t>>> D4 = 0x" ++ showHex d4 + putStrLn $ ">>> A5 = 0x" ++ showHex a5 ++ + "\t\t>>> D5 = 0x" ++ showHex d5 + putStrLn $ ">>> A6 = 0x" ++ showHex a6 ++ + "\t\t>>> D6 = 0x" ++ showHex d6 + putStrLn $ ">>> A7 = 0x" ++ showHex a7 ++ + "\t\t>>> D7 = 0x" ++ showHex d7 + putStrLn $ ">>> PC = 0x" ++ showHex pc + putStrLn $ ">>> SR = 0x" ++ showHex sr + Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++ + strerror err ++ ")" + +main :: IO () +main = + testM68k diff --git a/bindings/haskell/samples/SampleMips.hs b/bindings/haskell/samples/SampleMips.hs new file mode 100644 index 00000000..83efdbd3 --- /dev/null +++ b/bindings/haskell/samples/SampleMips.hs @@ -0,0 +1,129 @@ +-- Sample code to demonstrate how to emulate Mips code (big endian) + +import Unicorn +import Unicorn.Hook +import qualified Unicorn.CPU.Mips as Mips + +import qualified Data.ByteString as BS +import Data.Word +import qualified Numeric as N (showHex) + +-- Code to be emulated +-- +-- ori $at, $at, 0x3456 +mipsCodeEb :: BS.ByteString +mipsCodeEb = BS.pack [0x34, 0x21, 0x34, 0x56] + +-- ori $at, $at, 0x3456 +mipsCodeEl :: BS.ByteString +mipsCodeEl = BS.pack [0x56, 0x34, 0x21, 0x34] + +-- Memory address where emulation starts +address :: Word64 +address = 0x10000 + +-- Pretty-print integral as hex +showHex :: (Integral a, Show a) => a -> String +showHex = + flip N.showHex "" + +-- Calculate code length +codeLength :: Num a => BS.ByteString -> a +codeLength = + fromIntegral . BS.length + +hookBlock :: BlockHook () +hookBlock _ addr size _ = + putStrLn $ ">>> Tracing basic block at 0x" ++ showHex addr ++ + ", block size = 0x" ++ (maybe "0" showHex size) + +hookCode :: CodeHook () +hookCode _ addr size _ = + putStrLn $ ">>> Tracing instruction at 0x" ++ showHex addr ++ + ", instruction size = 0x" ++ (maybe "0" showHex size) + +testMipsEb :: IO () +testMipsEb = do + putStrLn "Emulate MIPS code (big-endian)" + + result <- runEmulator $ do + -- Initialize emulator in MIPS mode + uc <- open ArchMips [ModeMips32, ModeBigEndian] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address mipsCodeEb + + -- Initialise machine registers + regWrite uc Mips.Reg1 0x6789 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing one instruction at address with customized callback + codeHookAdd uc hookCode () address address + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all the code + let codeLen = codeLength mipsCodeEb + start uc address (address + codeLen) Nothing Nothing + + -- Return the results + r1 <- regRead uc Mips.Reg1 + + return r1 + case result of + Right r1 -> do + -- Now print out some registers + putStrLn ">>> Emulation done. Below is the CPU context" + putStrLn $ ">>> R1 = 0x" ++ showHex r1 + Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++ + strerror err ++ ")" + +testMipsEl :: IO () +testMipsEl = do + putStrLn "===========================" + putStrLn "Emulate MIPS code (little-endian)" + + result <- runEmulator $ do + -- Initialize emulator in MIPS mode + uc <- open ArchMips [ModeMips32, ModeLittleEndian] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address mipsCodeEl + + -- Initialize machine registers + regWrite uc Mips.Reg1 0x6789 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing one instruction at address with customized callback + codeHookAdd uc hookCode () address address + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all the code + let codeLen = codeLength mipsCodeEl + start uc address (address + codeLen) Nothing Nothing + + -- Return the results + r1 <- regRead uc Mips.Reg1 + + return r1 + case result of + Right r1 -> do + -- Now print out some registers + putStrLn ">>> Emulation done. Below is the CPU context" + putStrLn $ ">>> R1 = 0x" ++ showHex r1 + Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++ + strerror err ++ ")" + +main :: IO () +main = do + testMipsEb + testMipsEl diff --git a/bindings/haskell/samples/SampleSparc.hs b/bindings/haskell/samples/SampleSparc.hs new file mode 100644 index 00000000..02a0984b --- /dev/null +++ b/bindings/haskell/samples/SampleSparc.hs @@ -0,0 +1,85 @@ +-- Sample code to demonstrate how to emulate Sparc code + +import Unicorn +import Unicorn.Hook +import qualified Unicorn.CPU.Sparc as Sparc + +import qualified Data.ByteString as BS +import Data.Word +import qualified Numeric as N (showHex) + +-- Code to be emulated +-- +-- add %g1, %g2, %g3 +sparcCode :: BS.ByteString +sparcCode = BS.pack [0x86, 0x00, 0x40, 0x02] + +-- Memory address where emulation starts +address :: Word64 +address = 0x10000 + +-- Pretty-print integral as hex +showHex :: (Integral a, Show a) => a -> String +showHex = + flip N.showHex "" + +-- Calculate code length +codeLength :: Num a => BS.ByteString -> a +codeLength = + fromIntegral . BS.length + +hookBlock :: BlockHook () +hookBlock _ addr size _ = + putStrLn $ ">>> Tracing basic block at 0x" ++ showHex addr ++ + ", block size = 0x" ++ (maybe "0" showHex size) + +hookCode :: CodeHook () +hookCode _ addr size _ = + putStrLn $ ">>> Tracing instruction at 0x" ++ showHex addr ++ + ", instruction size = 0x" ++ (maybe "0" showHex size) + +testSparc :: IO () +testSparc = do + putStrLn "Emulate SPARC code" + + result <- runEmulator $ do + -- Initialize emulator in Sparc mode + uc <- open ArchSparc [ModeSparc32, ModeBigEndian] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address sparcCode + + -- Initialize machine registers + regWrite uc Sparc.G1 0x1230 + regWrite uc Sparc.G2 0x6789 + regWrite uc Sparc.G3 0x5555 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing all instructions with customized callback + codeHookAdd uc hookCode () 1 0 + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all the code + let codeLen = codeLength sparcCode + start uc address (address + codeLen) Nothing Nothing + + -- Return results + g3 <- regRead uc Sparc.G3 + + return g3 + case result of + Right g3 -> do + -- Now print out some registers + putStrLn ">>> Emulation done. Below is the CPU context" + putStrLn $ ">>> G3 = 0x" ++ showHex g3 + Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++ + strerror err ++ ")" + +main :: IO () +main = + testSparc diff --git a/bindings/haskell/samples/SampleX86.hs b/bindings/haskell/samples/SampleX86.hs new file mode 100644 index 00000000..fad686af --- /dev/null +++ b/bindings/haskell/samples/SampleX86.hs @@ -0,0 +1,675 @@ +-- Sample code to demonstrate how to emulate X86 code + +import Unicorn +import Unicorn.Hook +import qualified Unicorn.CPU.X86 as X86 + +import Control.Monad.Trans.Class (lift) +import qualified Data.ByteString as BS +import Data.Word +import qualified Numeric as N (showHex) +import System.Environment + +-- Code to be emulated +-- +-- inc ecx; dec edx +x86Code32 :: BS.ByteString +x86Code32 = BS.pack [0x41, 0x4a] + +-- jmp 4; nop; nop; nop; nop; nop; nop +x86Code32Jump :: BS.ByteString +x86Code32Jump = BS.pack [0xeb, 0x02, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90] + +-- inc ecx; dec edx; jmp self-loop +x86Code32Loop :: BS.ByteString +x86Code32Loop = BS.pack [0x41, 0x4a, 0xeb, 0xfe] + +-- mov [0xaaaaaaaa], ecx; inc ecx; dec edx +x86Code32MemWrite :: BS.ByteString +x86Code32MemWrite = BS.pack [0x89, 0x0d, 0xaa, 0xaa, 0xaa, 0xaa, 0x41, 0x4a] + +-- mov ecx, [0xaaaaaaaa]; inc ecx; dec edx +x86Code32MemRead :: BS.ByteString +x86Code32MemRead = BS.pack [0x8b, 0x0d, 0xaa, 0xaa, 0xaa, 0xaa, 0x41, 0x4a] + +-- jmp ouside; inc ecx; dec edx +x86Code32JmpInvalid :: BS.ByteString +x86Code32JmpInvalid = BS.pack [0xe9, 0xe9, 0xee, 0xee, 0xee, 0x41, 0x4a] + +-- inc ecx; in al, 0x3f; dec edx; out 0x46, al; inc ebx +x86Code32InOut :: BS.ByteString +x86Code32InOut = BS.pack [0x41, 0xe4, 0x3f, 0x4a, 0xe6, 0x46, 0x43] + +x86Code64 :: BS.ByteString +x86Code64 = BS.pack [0x41, 0xbc, 0x3b, 0xb0, 0x28, 0x2a, 0x49, 0x0f, 0xc9, + 0x90, 0x4d, 0x0f, 0xad, 0xcf, 0x49, 0x87, 0xfd, 0x90, + 0x48, 0x81, 0xd2, 0x8a, 0xce, 0x77, 0x35, 0x48, 0xf7, + 0xd9, 0x4d, 0x29, 0xf4, 0x49, 0x81, 0xc9, 0xf6, 0x8a, + 0xc6, 0x53, 0x4d, 0x87, 0xed, 0x48, 0x0f, 0xad, 0xd2, + 0x49, 0xf7, 0xd4, 0x48, 0xf7, 0xe1, 0x4d, 0x19, 0xc5, + 0x4d, 0x89, 0xc5, 0x48, 0xf7, 0xd6, 0x41, 0xb8, 0x4f, + 0x8d, 0x6b, 0x59, 0x4d, 0x87, 0xd0, 0x68, 0x6a, 0x1e, + 0x09, 0x3c, 0x59] + +-- add byte ptr [bx + si], al +x86Code16 :: BS.ByteString +x86Code16 = BS.pack [0x00, 0x00] + +-- SYSCALL +x86Code64Syscall :: BS.ByteString +x86Code64Syscall = BS.pack [0x0f, 0x05] + +-- Memory address where emulation starts +address :: Word64 +address = 0x1000000 + +-- Pretty-print integral as hex +showHex :: (Integral a, Show a) => a -> String +showHex i = + N.showHex (fromIntegral i :: Word64) "" + +-- Pretty-print byte string as hex +showHexBS :: BS.ByteString -> String +showHexBS = + concatMap (flip N.showHex "") . reverse . BS.unpack + +-- Write a string (with a newline character) to standard output in the emulator +emuPutStrLn :: String -> Emulator () +emuPutStrLn = + lift . putStrLn + +-- Calculate code length +codeLength :: Num a => BS.ByteString -> a +codeLength = + fromIntegral . BS.length + +-- Callback for tracing basic blocks +hookBlock :: BlockHook () +hookBlock _ addr size _ = + putStrLn $ ">>> Tracing basic block at 0x" ++ showHex addr ++ + ", block size = 0x" ++ (maybe "0" showHex size) + +-- Callback for tracing instruction +hookCode :: CodeHook () +hookCode uc addr size _ = do + runEmulator $ do + emuPutStrLn $ ">>> Tracing instruction at 0x" ++ showHex addr ++ + ", instruction size = 0x" ++ (maybe "0" showHex size) + + eflags <- regRead uc X86.Eflags + emuPutStrLn $ ">>> --- EFLAGS is 0x" ++ showHex eflags + return () + +-- Callback for tracing instruction +hookCode64 :: CodeHook () +hookCode64 uc addr size _ = do + runEmulator $ do + rip <- regRead uc X86.Rip + emuPutStrLn $ ">>> Tracing instruction at 0x" ++ showHex addr ++ + ", instruction size = 0x" ++ (maybe "0" showHex size) + emuPutStrLn $ ">>> RIP is 0x" ++ showHex rip + return () + +-- Callback for tracing memory access (READ or WRITE) +hookMemInvalid :: MemoryEventHook () +hookMemInvalid uc MemWriteUnmapped addr size (Just value) _ = do + runEmulator $ do + emuPutStrLn $ ">>> Missing memory is being WRITE at 0x" ++ + showHex addr ++ ", data size = " ++ show size ++ + ", data value = 0x" ++ showHex value + memMap uc 0xaaaa0000 (2 * 1024 * 1024) [ProtAll] + return True +hookMemInvalid _ _ _ _ _ _ = + return False + +hookMem64 :: MemoryHook () +hookMem64 _ MemRead addr size _ _ = + putStrLn $ ">>> Memory is being READ at 0x" ++ showHex addr ++ + ", data size = " ++ show size +hookMem64 _ MemWrite addr size (Just value) _ = + putStrLn $ ">>> Memory is being WRITE at 0x" ++ showHex addr ++ + ", data size = " ++ show size ++ ", data value = 0x" ++ + showHex value + +-- Callback for IN instruction (X86) +-- This returns the data read from the port +hookIn :: InHook () +hookIn uc port size _ = do + result <- runEmulator $ do + eip <- regRead uc X86.Eip + + emuPutStrLn $ "--- reading from port 0x" ++ showHex port ++ + ", size: " ++ show size ++ ", address: 0x" ++ showHex eip + + case size of + -- Read 1 byte to AL + 1 -> return 0xf1 + -- Read 2 byte to AX + 2 -> return 0xf2 + -- Read 4 byte to EAX + 4 -> return 0xf4 + -- Should never reach this + _ -> return 0 + case result of + Right r -> return r + Left _ -> return 0 + +-- Callback for OUT instruction (X86) +hookOut :: OutHook () +hookOut uc port size value _ = do + runEmulator $ do + eip <- regRead uc X86.Eip + + emuPutStrLn $ "--- writing to port 0x" ++ showHex port ++ ", size: " ++ + show size ++ ", value: 0x" ++ showHex value ++ + ", address: 0x" ++ showHex eip + + -- Confirm that value is indeed the value of AL/AX/EAX + case size of + 1 -> do + tmp <- regRead uc X86.Al + emuPutStrLn $ "--- register value = 0x" ++ showHex tmp + 2 -> do + tmp <- regRead uc X86.Ax + emuPutStrLn $ "--- register value = 0x" ++ showHex tmp + 4 -> do + tmp <- regRead uc X86.Eax + emuPutStrLn $ "--- register value = 0x" ++ showHex tmp + -- Should never reach this + _ -> return () + return () + +-- Callback for SYSCALL instruction (X86) +hookSyscall :: SyscallHook () +hookSyscall uc _ = do + runEmulator $ do + rax <- regRead uc X86.Rax + if rax == 0x100 then + regWrite uc X86.Rax 0x200 + else + emuPutStrLn $ "ERROR: was not expecting rax=0x" ++ showHex rax ++ + " in syscall" + return () + +testI386 :: IO () +testI386 = do + putStrLn "Emulate i386 code" + + result <- runEmulator $ do + -- Initialize emulator in X86-32bit mode + uc <- open ArchX86 [Mode32] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address x86Code32 + + -- Initialize machine registers + regWrite uc X86.Ecx 0x1234 + regWrite uc X86.Edx 0x7890 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing all instruction by having @begin > @end + codeHookAdd uc hookCode () 1 0 + + -- Emulate machine code in infinite time + let codeLen = codeLength x86Code32 + start uc address (address + codeLen) Nothing Nothing + + -- Now print out some registers + emuPutStrLn ">>> Emulation done. Below is the CPU context" + + ecx <- regRead uc X86.Ecx + edx <- regRead uc X86.Edx + emuPutStrLn $ ">>> ECX = 0x" ++ showHex ecx + emuPutStrLn $ ">>> EDX = 0x" ++ showHex edx + + -- Read from memory + tmp <- memRead uc address 4 + emuPutStrLn $ ">>> Read 4 bytes from [0x" ++ showHex address ++ + "] = 0x" ++ showHexBS tmp + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +testI386Jump :: IO () +testI386Jump = do + putStrLn "===================================" + putStrLn "Emulate i386 code with jump" + + result <- runEmulator $ do + -- Initialize emulator in X86-32bit mode + uc <- open ArchX86 [Mode32] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address x86Code32Jump + + -- Tracing 1 basic block with customized callback + blockHookAdd uc hookBlock () address address + + -- Tracing 1 instruction at address + codeHookAdd uc hookCode () address address + + -- Emulate machine code ininfinite time + let codeLen = codeLength x86Code32Jump + start uc address (address + codeLen) Nothing Nothing + + emuPutStrLn ">>> Emulation done. Below is the CPU context" + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +-- Emulate code that loop forever +testI386Loop :: IO () +testI386Loop = do + putStrLn "===================================" + putStrLn "Emulate i386 code that loop forever" + + result <- runEmulator $ do + -- Initialize emulator in X86-32bit mode + uc <- open ArchX86 [Mode32] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated in memory + memWrite uc address x86Code32Loop + + -- Initialize machine registers + regWrite uc X86.Ecx 0x1234 + regWrite uc X86.Edx 0x7890 + + -- Emulate machine code in 2 seconds, so we can quit even if the code + -- loops + let codeLen = codeLength x86Code32Loop + start uc address (address + codeLen) (Just $ 2 * 1000000) Nothing + + -- Now print out some registers + emuPutStrLn ">>> Emulation done. Below is the CPU context" + + ecx <- regRead uc X86.Ecx + edx <- regRead uc X86.Edx + + emuPutStrLn $ ">>> ECX = 0x" ++ showHex ecx + emuPutStrLn $ ">>> EDX = 0x" ++ showHex edx + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +-- Emulate code that read invalid memory +testI386InvalidMemRead :: IO () +testI386InvalidMemRead = do + putStrLn "===================================" + putStrLn "Emulate i386 code that read from invalid memory" + + result <- runEmulator $ do + -- Initialize emulator in X86-32bit mode + uc <- open ArchX86 [Mode32] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address x86Code32MemRead + + -- Initialize machine registers + regWrite uc X86.Ecx 0x1234 + regWrite uc X86.Edx 0x7890 + + -- Tracing all basic block with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing all instructions by having @beegin > @end + codeHookAdd uc hookCode () 1 0 + + -- Emulate machine code in infinite time + let codeLen = codeLength x86Code32MemRead + start uc address (address + codeLen) Nothing Nothing + + -- Now print out some registers + emuPutStrLn ">>> Emulation done. Below is the CPU context" + + ecx <- regRead uc X86.Ecx + edx <- regRead uc X86.Edx + + emuPutStrLn $ ">>> ECX = 0x" ++ showHex ecx + emuPutStrLn $ ">>> EDX = 0x" ++ showHex edx + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +-- Emulate code that write invalid memory +testI386InvalidMemWrite :: IO () +testI386InvalidMemWrite = do + putStrLn "===================================" + putStrLn "Emulate i386 code that write to invalid memory" + + result <- runEmulator $ do + -- Initialize emulator in X86-32bit mode + uc <- open ArchX86 [Mode32] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address x86Code32MemWrite + + -- Initialize machine registers + regWrite uc X86.Ecx 0x1234 + regWrite uc X86.Edx 0x7890 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing all instruction by having @begin > @end + codeHookAdd uc hookCode () 1 0 + + -- Intercept invalid memory events + memoryEventHookAdd uc HookMemReadUnmapped hookMemInvalid () 1 0 + memoryEventHookAdd uc HookMemWriteUnmapped hookMemInvalid () 1 0 + + -- Emulate machine code in infinite time + let codeLen = codeLength x86Code32MemWrite + start uc address (address + codeLen) Nothing Nothing + + -- Now print out some registers + emuPutStrLn ">>> Emulation done. Below is the CPU context" + + ecx <- regRead uc X86.Ecx + edx <- regRead uc X86.Edx + emuPutStrLn $ ">>> ECX = 0x" ++ showHex ecx + emuPutStrLn $ ">>> EDX = 0x" ++ showHex edx + + -- Read from memory + tmp <- memRead uc 0xaaaaaaaa 4 + emuPutStrLn $ ">>> Read 4 bytes from [0x" ++ showHex 0xaaaaaaaa ++ + "] = 0x" ++ showHexBS tmp + + tmp <- memRead uc 0xffffffaa 4 + emuPutStrLn $ ">>> Read 4 bytes from [0x" ++ showHex 0xffffffaa ++ + "] = 0x" ++ showHexBS tmp + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +-- Emulate code that jump to invalid memory +testI386JumpInvalid :: IO () +testI386JumpInvalid = do + putStrLn "===================================" + putStrLn "Emulate i386 code that jumps to invalid memory" + + result <- runEmulator $ do + -- Initialize emulator in X86-32bit mode + uc <- open ArchX86 [Mode32] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address x86Code32JmpInvalid + + -- Initialize machine registers + regWrite uc X86.Ecx 0x1234 + regWrite uc X86.Edx 0x7890 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing all instructions by having @begin > @end + codeHookAdd uc hookCode () 1 0 + + -- Emulate machine code in infinite time + let codeLen = codeLength x86Code32JmpInvalid + start uc address (address + codeLen) Nothing Nothing + + -- Now print out some registers + emuPutStrLn ">>> Emulation done. Below is the CPU context" + + ecx <- regRead uc X86.Ecx + edx <- regRead uc X86.Edx + + emuPutStrLn $ ">>> ECX = 0x" ++ showHex ecx + emuPutStrLn $ ">>> EDX = 0x" ++ showHex edx + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +testI386InOut :: IO () +testI386InOut = do + putStrLn "===================================" + putStrLn "Emulate i386 code with IN/OUT instructions" + + result <- runEmulator $ do + -- Initialize emulator in X86-32bit mode + uc <- open ArchX86 [Mode32] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address x86Code32InOut + + -- Initialize machine registers + regWrite uc X86.Eax 0x1234 + regWrite uc X86.Ecx 0x6789 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing all instructions + codeHookAdd uc hookCode () 1 0 + + -- uc IN instruction + inHookAdd uc hookIn () 1 0 + + -- uc OUT instruction + outHookAdd uc hookOut () 1 0 + + -- Emulate machine code in infinite time + let codeLen = codeLength x86Code32InOut + start uc address (address + codeLen) Nothing Nothing + + -- Now print out some registers + emuPutStrLn ">>> Emulation done. Below is the CPU context" + + eax <- regRead uc X86.Eax + ecx <- regRead uc X86.Ecx + + emuPutStrLn $ ">>> EAX = 0x" ++ showHex eax + emuPutStrLn $ ">>> ECX = 0x" ++ showHex ecx + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +testX8664 :: IO () +testX8664 = do + putStrLn "Emulate x86_64 code" + + result <- runEmulator $ do + -- Initialize emualator in X86-64bit mode + uc <- open ArchX86 [Mode64] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address x86Code64 + + -- Initialize machine registers + regWrite uc X86.Rsp (fromIntegral address + 0x200000) + + regWrite uc X86.Rax 0x71f3029efd49d41d + regWrite uc X86.Rbx 0xd87b45277f133ddb + regWrite uc X86.Rcx 0xab40d1ffd8afc461 + regWrite uc X86.Rdx 0x919317b4a733f01 + regWrite uc X86.Rsi 0x4c24e753a17ea358 + regWrite uc X86.Rdi 0xe509a57d2571ce96 + regWrite uc X86.R8 0xea5b108cc2b9ab1f + regWrite uc X86.R9 0x19ec097c8eb618c1 + regWrite uc X86.R10 0xec45774f00c5f682 + regWrite uc X86.R11 0xe17e9dbec8c074aa + regWrite uc X86.R12 0x80f86a8dc0f6d457 + regWrite uc X86.R13 0x48288ca5671c5492 + regWrite uc X86.R14 0x595f72f6e4017f6e + regWrite uc X86.R15 0x1efd97aea331cccc + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing all instructions in the range [address, address+20] + codeHookAdd uc hookCode64 () address (address + 20) + + -- Tracing all memory WRITE access (with @begin > @end) + memoryHookAdd uc HookMemWrite hookMem64 () 1 0 + + -- Tracing all memory READ access (with @begin > @end) + memoryHookAdd uc HookMemRead hookMem64 () 1 0 + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all the code + let codeLen = codeLength x86Code64 + start uc address (address + codeLen) Nothing Nothing + + -- Now print out some registers + emuPutStrLn ">>> Emulation done. Below is the CPU context" + + rax <- regRead uc X86.Rax + rbx <- regRead uc X86.Rbx + rcx <- regRead uc X86.Rcx + rdx <- regRead uc X86.Rdx + rsi <- regRead uc X86.Rsi + rdi <- regRead uc X86.Rdi + r8 <- regRead uc X86.R8 + r9 <- regRead uc X86.R9 + r10 <- regRead uc X86.R10 + r11 <- regRead uc X86.R11 + r12 <- regRead uc X86.R12 + r13 <- regRead uc X86.R13 + r14 <- regRead uc X86.R14 + r15 <- regRead uc X86.R15 + + emuPutStrLn $ ">>> RAX = 0x" ++ showHex rax + emuPutStrLn $ ">>> RBX = 0x" ++ showHex rbx + emuPutStrLn $ ">>> RCX = 0x" ++ showHex rcx + emuPutStrLn $ ">>> RDX = 0x" ++ showHex rdx + emuPutStrLn $ ">>> RSI = 0x" ++ showHex rsi + emuPutStrLn $ ">>> RDI = 0x" ++ showHex rdi + emuPutStrLn $ ">>> R8 = 0x" ++ showHex r8 + emuPutStrLn $ ">>> R9 = 0x" ++ showHex r9 + emuPutStrLn $ ">>> R10 = 0x" ++ showHex r10 + emuPutStrLn $ ">>> R11 = 0x" ++ showHex r11 + emuPutStrLn $ ">>> R12 = 0x" ++ showHex r12 + emuPutStrLn $ ">>> R13 = 0x" ++ showHex r13 + emuPutStrLn $ ">>> R14 = 0x" ++ showHex r14 + emuPutStrLn $ ">>> R15 = 0x" ++ showHex r15 + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +testX8664Syscall :: IO () +testX8664Syscall = do + putStrLn "===================================" + putStrLn "Emulate x86_64 code with 'syscall' instruction" + + result <- runEmulator $ do + -- Initialize emulator in X86-64bit mode + uc <- open ArchX86 [Mode64] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address x86Code64Syscall + + -- Hook interrupts for syscall + syscallHookAdd uc hookSyscall () 1 0 + + -- Initialize machine registers + regWrite uc X86.Rax 0x100 + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all code + let codeLen = codeLength x86Code64Syscall + start uc address (address + codeLen) Nothing Nothing + + -- Now print out some registers + emuPutStrLn ">>> Emulation done. Below is the CPU context" + + rax <- regRead uc X86.Rax + emuPutStrLn $ ">>> RAX = 0x" ++ showHex rax + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +testX8616 :: IO () +testX8616 = do + putStrLn "Emulate x86 16-bit code" + + result <- runEmulator $ do + -- Initialize emulator in X86-16bit mode + uc <- open ArchX86 [Mode16] + + -- Map 8KB memory for this emulation + memMap uc 0 (8 * 1024) [ProtAll] + + -- Write machine code to be emulated in memory + memWrite uc 0 x86Code16 + + -- Initialize machine registers + regWrite uc X86.Eax 7 + regWrite uc X86.Ebx 5 + regWrite uc X86.Esi 6 + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all the code + let codeLen = codeLength x86Code16 + start uc 0 codeLen Nothing Nothing + + -- Now print out some registers + emuPutStrLn ">>> Emulation done. Below is the CPU context" + + -- Read from memory + tmp <- memRead uc 11 1 + emuPutStrLn $ ">>> Read 1 bytes from [0x" ++ showHex 11 ++ + "] = 0x" ++ showHexBS tmp + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +main :: IO () +main = do + progName <- getProgName + args <- getArgs + case args of + ["-32"] -> do + testI386 + testI386InOut + testI386Jump + testI386Loop + testI386InvalidMemRead + testI386InvalidMemWrite + testI386JumpInvalid + ["-64"] -> do + testX8664 + testX8664Syscall + ["-16"] -> testX8616 + -- Test memleak + ["-0"] -> testI386 + _ -> putStrLn $ "Syntax: " ++ progName ++ " <-16|-32|-64>" + diff --git a/bindings/haskell/samples/Shellcode.hs b/bindings/haskell/samples/Shellcode.hs new file mode 100644 index 00000000..65ad979c --- /dev/null +++ b/bindings/haskell/samples/Shellcode.hs @@ -0,0 +1,153 @@ +-- Sample code to trace code with Linux code with syscall + +import Unicorn +import Unicorn.Hook +import qualified Unicorn.CPU.X86 as X86 + +import Control.Monad.Trans.Class (lift) +import qualified Data.ByteString as BS +import Data.Word +import qualified Numeric as N (showHex) +import System.Environment + +-- Code to be emulated +x86Code32 :: BS.ByteString +x86Code32 = BS.pack [0xeb, 0x19, 0x31, 0xc0, 0x31, 0xdb, 0x31, 0xd2, 0x31, + 0xc9, 0xb0, 0x04, 0xb3, 0x01, 0x59, 0xb2, 0x05, 0xcd, + 0x80, 0x31, 0xc0, 0xb0, 0x01, 0x31, 0xdb, 0xcd, 0x80, + 0xe8, 0xe2, 0xff, 0xff, 0xff, 0x68, 0x65, 0x6c, 0x6c, + 0x6f] + +x86Code32Self :: BS.ByteString +x86Code32Self = BS.pack [0xeb, 0x1c, 0x5a, 0x89, 0xd6, 0x8b, 0x02, 0x66, 0x3d, + 0xca, 0x7d, 0x75, 0x06, 0x66, 0x05, 0x03, 0x03, 0x89, + 0x02, 0xfe, 0xc2, 0x3d, 0x41, 0x41, 0x41, 0x41, 0x75, + 0xe9, 0xff, 0xe6, 0xe8, 0xdf, 0xff, 0xff, 0xff, 0x31, + 0xd2, 0x6a, 0x0b, 0x58, 0x99, 0x52, 0x68, 0x2f, 0x2f, + 0x73, 0x68, 0x68, 0x2f, 0x62, 0x69, 0x6e, 0x89, 0xe3, + 0x52, 0x53, 0x89, 0xe1, 0xca, 0x7d, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41] + +-- Memory address where emulation starts +address :: Word64 +address = 0x1000000 + +-- Pretty-print integral as hex +showHex :: (Integral a, Show a) => a -> String +showHex = + flip N.showHex "" + +-- Pretty-print byte string as hex +showHexBS :: BS.ByteString -> String +showHexBS = + concatMap (flip N.showHex " ") . BS.unpack + +-- Write a string (with a newline character) to standard output in the emulator +emuPutStrLn :: String -> Emulator () +emuPutStrLn = + lift . putStrLn + +-- Calculate code length +codeLength :: Num a => BS.ByteString -> a +codeLength = + fromIntegral . BS.length + +-- Callback for tracing instructions +hookCode :: CodeHook () +hookCode uc addr size _ = do + runEmulator $ do + emuPutStrLn $ "Tracing instruction at 0x" ++ showHex addr ++ + ", instruction size = 0x" ++ (maybe "0" showHex size) + + eip <- regRead uc X86.Eip + tmp <- memRead uc addr (maybe 0 id size) + + emuPutStrLn $ "*** EIP = " ++ showHex eip ++ " ***: " ++ showHexBS tmp + return () + +-- Callback for handling interrupts +-- ref: http://syscalls.kernelgrok.com +hookIntr :: InterruptHook () +hookIntr uc intno _ + | intno == 0x80 = do + runEmulator $ do + eax <- regRead uc X86.Eax + eip <- regRead uc X86.Eip + + case eax of + -- sys_exit + 1 -> do + emuPutStrLn $ ">>> 0x" ++ showHex eip ++ + ": interrupt 0x" ++ showHex intno ++ + ", SYS_EXIT. quit!\n" + stop uc + -- sys_write + 4 -> do + -- ECX = buffer address + ecx <- regRead uc X86.Ecx + + -- EDX = buffer size + edx <- regRead uc X86.Edx + + -- Read the buffer in + buffer <- memRead uc (fromIntegral ecx) (fromIntegral edx) + err <- errno uc + if err == ErrOk then + emuPutStrLn $ ">>> 0x" ++ showHex eip ++ + ": interrupt 0x" ++ showHex intno ++ + ", SYS_WRITE. buffer = 0x" ++ + showHex ecx ++ ", size = " ++ + show edx ++ ", content = " ++ + showHexBS buffer + else + emuPutStrLn $ ">>> 0x" ++ showHex eip ++ + ": interrupt 0x" ++ showHex intno ++ + ", SYS_WRITE. buffer = 0x" ++ + showHex ecx ++ ", size = " ++ show edx ++ + " (cannot get content)" + _ -> emuPutStrLn $ ">>> 0x" ++ showHex eip ++ + ": interrupt 0x" ++ showHex intno ++ + ", EAX = 0x" ++ showHex eax + return () + | otherwise = return () + +testI386 :: IO () +testI386 = do + result <- runEmulator $ do + emuPutStrLn "Emulate i386 code" + + -- Initialize emulator in X86-32bit mode + uc <- open ArchX86 [Mode32] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address x86Code32Self + + -- Initialize machine registers + regWrite uc X86.Esp (fromIntegral address + 0x200000) + + -- Tracing all instructions by having @begin > @end + codeHookAdd uc hookCode () 1 0 + + -- Handle interrupt ourself + interruptHookAdd uc hookIntr () 1 0 + + emuPutStrLn "\n>>> Start tracing this Linux code" + + -- Emulate machine code in infinite time + let codeLen = codeLength x86Code32Self + start uc address (address + codeLen) Nothing Nothing + case result of + Right _ -> putStrLn "\n>>> Emulation done." + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +main :: IO () +main = do + progName <- getProgName + args <- getArgs + case args of + ["-32"] -> testI386 + _ -> putStrLn $ "Syntax: " ++ progName ++ " <-32|-64>" diff --git a/bindings/haskell/src/Unicorn.hs b/bindings/haskell/src/Unicorn.hs new file mode 100644 index 00000000..856133ff --- /dev/null +++ b/bindings/haskell/src/Unicorn.hs @@ -0,0 +1,284 @@ +{-| +Module : Unicorn +Description : The Unicorn CPU emulator. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Unicorn is a lightweight, multi-platform, multi-architecture CPU emulator +framework based on QEMU. + +Further information is available at . +-} +module Unicorn ( + -- * Emulator control + Emulator, + Engine, + Architecture(..), + Mode(..), + QueryType(..), + runEmulator, + open, + query, + start, + stop, + + -- * Register operations + regWrite, + regRead, + + -- * Memory operations + MemoryPermission(..), + MemoryRegion(..), + memWrite, + memRead, + memMap, + memUnmap, + memProtect, + memRegions, + + -- * Error handling + Error(..), + errno, + strerror, + + -- * Misc. + version, +) where + +import Control.Monad (liftM) +import Control.Monad.Trans.Class (lift) +import Control.Monad.Trans.Either (hoistEither, left, right, runEitherT) +import Foreign + +import Prelude hiding (until) +import Data.ByteString (ByteString, pack) + +import Unicorn.Internal.Core +import Unicorn.Internal.Unicorn + +------------------------------------------------------------------------------- +-- Emulator control +------------------------------------------------------------------------------- + +-- | Run the Unicorn emulator and return a result on success, or an 'Error' on +-- failure. +runEmulator :: Emulator a -- ^ The emulation code to execute + -> IO (Either Error a) -- ^ A result on success, or an 'Error' on + -- failure +runEmulator = + runEitherT + +-- | Create a new instance of the Unicorn engine. +open :: Architecture -- ^ CPU architecture + -> [Mode] -- ^ CPU hardware mode + -> Emulator Engine -- ^ A 'Unicorn' engine on success, or an 'Error' on + -- failure +open arch mode = do + (err, ucPtr) <- lift $ ucOpen arch mode + if err == ErrOk then + -- Return a pointer to the unicorn engine if ucOpen completed + -- successfully + lift $ mkEngine ucPtr + else + -- Otherwise return the error + left err + +-- | Query internal status of the Unicorn engine. +query :: Engine -- ^ 'Unicorn' engine handle + -> QueryType -- ^ Query type + -> Emulator Int -- ^ The result of the query +query uc queryType = do + (err, result) <- lift $ ucQuery uc queryType + if err == ErrOk then + right result + else + left err + +-- | Emulate machine code for a specific duration of time. +start :: Engine -- ^ 'Unicorn' engine handle + -> Word64 -- ^ Address where emulation starts + -> Word64 -- ^ Address where emulation stops (i.e. when this + -- address is hit) + -> Maybe Int -- ^ Optional duration to emulate code (in + -- microseconds). + -- If 'Nothing' is provided, continue to emulate + -- until the code is finished + -> Maybe Int -- ^ Optional number of instructions to emulate. If + -- 'Nothing' is provided, emulate all the code + -- available, until the code is finished + -> Emulator () -- ^ An 'Error' on failure +start uc begin until timeout count = do + err <- lift $ ucEmuStart uc begin until (maybeZ timeout) (maybeZ count) + if err == ErrOk then + right () + else + left err + where maybeZ = maybe 0 id + +-- | Stop emulation (which was started by 'start'). +-- This is typically called from callback functions registered by tracing APIs. +-- +-- NOTE: For now, this will stop execution only after the current block. +stop :: Engine -- ^ 'Unicorn' engine handle + -> Emulator () -- ^ An 'Error' on failure +stop uc = do + err <- lift $ ucEmuStop uc + if err == ErrOk then + right () + else + left err + +------------------------------------------------------------------------------- +-- Register operations +------------------------------------------------------------------------------- + +-- | Write to register. +regWrite :: Reg r => + Engine -- ^ 'Unicorn' engine handle + -> r -- ^ Register ID to write to + -> Int64 -- ^ Value to write to register + -> Emulator () -- ^ An 'Error' on failure +regWrite uc regId value = do + err <- lift . alloca $ \ptr -> do + poke ptr value + ucRegWrite uc regId ptr + if err == ErrOk then + right () + else + left err + +-- | Read register value. +regRead :: Reg r => + Engine -- ^ 'Unicorn' engine handle + -> r -- ^ Register ID to read from + -> Emulator Int64 -- ^ The value read from the register on success, + -- or an 'Error' on failure +regRead uc regId = do + (err, val) <- lift $ ucRegRead uc regId + if err == ErrOk then + right val + else + left err + +------------------------------------------------------------------------------- +-- Memory operations +------------------------------------------------------------------------------- + +-- | Write to memory. +memWrite :: Engine -- ^ 'Unicorn' engine handle + -> Word64 -- ^ Starting memory address of bytes to write + -> ByteString -- ^ The data to write + -> Emulator () -- ^ An 'Error' on failure +memWrite uc address bytes = do + err <- lift $ ucMemWrite uc address bytes + if err == ErrOk then + right () + else + left err + +-- | Read memory contents. +memRead :: Engine -- ^ 'Unicorn' engine handle + -> Word64 -- ^ Starting memory address to read + -- from + -> Int -- ^ Size of memory to read (in bytes) + -> Emulator ByteString -- ^ The memory contents on success, or + -- an 'Error' on failure +memRead uc address size = do + -- Allocate an array of the given size + result <- lift . allocaArray size $ \ptr -> do + err <- ucMemRead uc address ptr size + if err == ErrOk then + -- If ucMemRead completed successfully, pack the contents of the + -- array into a ByteString and return it + liftM (Right . pack) (peekArray size ptr) + else + -- Otherwise return the error + return $ Left err + hoistEither result + +-- | Map a range of memory. +memMap :: Engine -- ^ 'Unicorn' engine handle + -> Word64 -- ^ Start address of the new memory region to + -- be mapped in. This address must be + -- aligned to 4KB, or this will return with + -- 'ErrArg' error + -> Int -- ^ Size of the new memory region to be mapped + -- in. This size must be a multiple of 4KB, or + -- this will return with an 'ErrArg' error + -> [MemoryPermission] -- ^ Permissions for the newly mapped region + -> Emulator () -- ^ An 'Error' on failure +memMap uc address size perms = do + err <- lift $ ucMemMap uc address size perms + if err == ErrOk then + right () + else + left err + +-- | Unmap a range of memory. +memUnmap :: Engine -- ^ 'Unicorn' engine handle + -> Word64 -- ^ Start addres of the memory region to be unmapped. + -- This address must be aligned to 4KB or this will + -- return with an 'ErrArg' error + -> Int -- ^ Size of the memory region to be modified. This + -- must be a multiple of 4KB, or this will return with + -- an 'ErrArg' error + -> Emulator () -- ^ An 'Error' on failure +memUnmap uc address size = do + err <- lift $ ucMemUnmap uc address size + if err == ErrOk then + right () + else + left err + +-- | Change permissions on a range of memory. +memProtect :: Engine -- ^ 'Unicorn' engine handle + -> Word64 -- ^ Start address of the memory region to + -- modify. This address must be aligned to + -- 4KB, or this will return with an + -- 'ErrArg' error + -> Int -- ^ Size of the memory region to be + -- modified. This size must be a multiple + -- of 4KB, or this will return with an + -- 'ErrArg' error + -> [MemoryPermission] -- ^ New permissions for the mapped region + -> Emulator () -- ^ An 'Error' on failure +memProtect uc address size perms = do + err <- lift $ ucMemProtect uc address size perms + if err == ErrOk then + right () + else + left err + +-- | Retrieve all memory regions mapped by 'memMap'. +memRegions :: Engine -- ^ 'Unicorn' engine handle + -> Emulator [MemoryRegion] -- ^ A list of memory regions +memRegions uc = do + (err, regionPtr, count) <- lift $ ucMemRegions uc + if err == ErrOk then do + regions <- lift $ peekArray count regionPtr + right regions + else + left err + +------------------------------------------------------------------------------- +-- Misc. +------------------------------------------------------------------------------- + +-- | Combined API version & major and minor version numbers. Returns a +-- hexadecimal number as (major << 8 | minor), which encodes both major and +-- minor versions. +version :: Int +version = + ucVersion nullPtr nullPtr + +-- | Report the 'Error' of the last failed API call. +errno :: Engine -- ^ 'Unicorn' engine handle + -> Emulator Error -- ^ The last 'Error' code +errno = + lift . ucErrno + +-- | Return a string describing the given 'Error'. +strerror :: Error -- ^ The 'Error' code + -> String -- ^ Description of the error code +strerror = + ucStrerror diff --git a/bindings/haskell/src/Unicorn/CPU/Arm.chs b/bindings/haskell/src/Unicorn/CPU/Arm.chs new file mode 100644 index 00000000..789b7e3e --- /dev/null +++ b/bindings/haskell/src/Unicorn/CPU/Arm.chs @@ -0,0 +1,29 @@ +{-# LANGUAGE ForeignFunctionInterface #-} + +{-| +Module : Unicorn.CPU.Arm +Description : Definitions for the ARM architecture. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Definitions for the ARM architecture. +-} +module Unicorn.CPU.Arm ( + Register(..), +) where + +import Unicorn.Internal.Core (Reg) + +{# context lib="unicorn" #} + +#include + +-- | ARM registers. +{# enum uc_arm_reg as Register + {underscoreToCase} + omit (UC_ARM_REG_INVALID, + UC_ARM_REG_ENDING) + with prefix="UC_ARM_REG_" + deriving (Show, Eq) #} + +instance Reg Register diff --git a/bindings/haskell/src/Unicorn/CPU/Arm64.chs b/bindings/haskell/src/Unicorn/CPU/Arm64.chs new file mode 100644 index 00000000..4c67c43e --- /dev/null +++ b/bindings/haskell/src/Unicorn/CPU/Arm64.chs @@ -0,0 +1,29 @@ +{-# LANGUAGE ForeignFunctionInterface #-} + +{-| +Module : Unicorn.CPU.Arm64 +Description : Definitions for the ARM64 (ARMv8) architecture. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Definitions for the ARM64 (ARMv8) architecture. +-} +module Unicorn.CPU.Arm64 ( + Register(..), +) where + +import Unicorn.Internal.Core (Reg) + +{# context lib="unicorn" #} + +#include + +-- | ARM64 registers. +{# enum uc_arm64_reg as Register + {underscoreToCase} + omit (UC_ARM64_REG_INVALID, + UC_ARM64_REG_ENDING) + with prefix="UC_ARM64_REG_" + deriving (Show, Eq) #} + +instance Reg Register diff --git a/bindings/haskell/src/Unicorn/CPU/M68k.chs b/bindings/haskell/src/Unicorn/CPU/M68k.chs new file mode 100644 index 00000000..457ced79 --- /dev/null +++ b/bindings/haskell/src/Unicorn/CPU/M68k.chs @@ -0,0 +1,29 @@ +{-# LANGUAGE ForeignFunctionInterface #-} + +{-| +Module : Unicorn.CPU.Mk68k +Description : Definitions for the MK68K architecture. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Definitions for the MK68K architecture. +-} +module Unicorn.CPU.M68k ( + Register(..), +) where + +import Unicorn.Internal.Core (Reg) + +{# context lib="unicorn" #} + +#include + +-- | M68K registers. +{# enum uc_m68k_reg as Register + {underscoreToCase} + omit (UC_M68K_REG_INVALID, + UC_M68K_REG_ENDING) + with prefix="UC_M68K_REG_" + deriving (Show, Eq) #} + +instance Reg Register diff --git a/bindings/haskell/src/Unicorn/CPU/Mips.chs b/bindings/haskell/src/Unicorn/CPU/Mips.chs new file mode 100644 index 00000000..fa14bc4c --- /dev/null +++ b/bindings/haskell/src/Unicorn/CPU/Mips.chs @@ -0,0 +1,61 @@ +{-# LANGUAGE ForeignFunctionInterface #-} + +{-| +Module : Unicorn.CPU.Mips +Description : Definitions for the MIPS architecture. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Definitions for the MIPS architecture. +-} +module Unicorn.CPU.Mips ( + Register(..), +) where + +import Unicorn.Internal.Core (Reg) + +{# context lib="unicorn" #} + +#include + +-- | MIPS registers. +{# enum UC_MIPS_REG as Register + {underscoreToCase, + UC_MIPS_REG_0 as Reg0, + UC_MIPS_REG_1 as Reg1, + UC_MIPS_REG_2 as Reg2, + UC_MIPS_REG_3 as Reg3, + UC_MIPS_REG_4 as Reg4, + UC_MIPS_REG_5 as Reg5, + UC_MIPS_REG_6 as Reg6, + UC_MIPS_REG_7 as Reg7, + UC_MIPS_REG_8 as Reg8, + UC_MIPS_REG_9 as Reg9, + UC_MIPS_REG_10 as Reg10, + UC_MIPS_REG_11 as Reg11, + UC_MIPS_REG_12 as Reg12, + UC_MIPS_REG_13 as Reg13, + UC_MIPS_REG_14 as Reg14, + UC_MIPS_REG_15 as Reg15, + UC_MIPS_REG_16 as Reg16, + UC_MIPS_REG_17 as Reg17, + UC_MIPS_REG_18 as Reg18, + UC_MIPS_REG_19 as Reg19, + UC_MIPS_REG_20 as Reg20, + UC_MIPS_REG_21 as Reg21, + UC_MIPS_REG_22 as Reg22, + UC_MIPS_REG_23 as Reg23, + UC_MIPS_REG_24 as Reg24, + UC_MIPS_REG_25 as Reg25, + UC_MIPS_REG_26 as Reg26, + UC_MIPS_REG_27 as Reg27, + UC_MIPS_REG_28 as Reg28, + UC_MIPS_REG_29 as Reg29, + UC_MIPS_REG_30 as Reg30, + UC_MIPS_REG_31 as Reg31} + omit (UC_MIPS_REG_INVALID, + UC_MIPS_REG_ENDING) + with prefix="UC_MIPS_REG_" + deriving (Show, Eq) #} + +instance Reg Register diff --git a/bindings/haskell/src/Unicorn/CPU/Sparc.chs b/bindings/haskell/src/Unicorn/CPU/Sparc.chs new file mode 100644 index 00000000..28d63702 --- /dev/null +++ b/bindings/haskell/src/Unicorn/CPU/Sparc.chs @@ -0,0 +1,29 @@ +{-# LANGUAGE ForeignFunctionInterface #-} + +{-| +Module : Unicorn.CPU.Sparc +Description : Definitions for the SPARC architecture. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Definitions for the SPARC architecture. +-} +module Unicorn.CPU.Sparc ( + Register(..), +) where + +import Unicorn.Internal.Core (Reg) + +{# context lib="unicorn" #} + +#include + +-- | SPARC registers. +{# enum uc_sparc_reg as Register + {underscoreToCase} + omit (UC_SPARC_REG_INVALID, + UC_SPARC_REG_ENDING) + with prefix="UC_SPARC_REG_" + deriving (Show, Eq) #} + +instance Reg Register diff --git a/bindings/haskell/src/Unicorn/CPU/X86.chs b/bindings/haskell/src/Unicorn/CPU/X86.chs new file mode 100644 index 00000000..eccb8b35 --- /dev/null +++ b/bindings/haskell/src/Unicorn/CPU/X86.chs @@ -0,0 +1,65 @@ +{-# LANGUAGE ForeignFunctionInterface #-} + +{-| +Module : Unicorn.CPU.X86 +Description : Definitions for the X86 architecture. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Definitions for the X86 architecture. +-} +module Unicorn.CPU.X86 ( + Mmr(..), + Register(..), + Instruction(..), +) where + +import Control.Applicative +import Data.Word +import Foreign + +import Unicorn.Internal.Core (Reg) + +{# context lib="unicorn" #} + +#include + +-- | Memory-managemen Register for instructions IDTR, GDTR, LDTR, TR. +-- Borrow from SegmentCache in qemu/target-i386/cpu.h +data Mmr = Mmr { + selector :: Word16, -- ^ Not used by GDTR and IDTR + base :: Word64, -- ^ Handle 32 or 64 bit CPUs + limit :: Word32, + flags :: Word32 -- ^ Not used by GDTR and IDTR +} + +instance Storable Mmr where + sizeOf _ = {# sizeof uc_x86_mmr #} + alignment _ = {# alignof uc_x86_mmr #} + peek p = Mmr <$> liftA fromIntegral ({# get uc_x86_mmr->selector #} p) + <*> liftA fromIntegral ({# get uc_x86_mmr->base #} p) + <*> liftA fromIntegral ({# get uc_x86_mmr->limit #} p) + <*> liftA fromIntegral ({# get uc_x86_mmr->flags #} p) + poke p mmr = do + {# set uc_x86_mmr.selector #} p (fromIntegral $ selector mmr) + {# set uc_x86_mmr.base #} p (fromIntegral $ base mmr) + {# set uc_x86_mmr.limit #} p (fromIntegral $ limit mmr) + {# set uc_x86_mmr.flags #} p (fromIntegral $ flags mmr) + +-- | X86 registers. +{# enum uc_x86_reg as Register + {underscoreToCase} + omit (UC_X86_REG_INVALID, + UC_X86_REG_ENDING) + with prefix="UC_X86_REG_" + deriving (Show, Eq) #} + +instance Reg Register + +-- | X86 instructions. +{# enum uc_x86_insn as Instruction + {underscoreToCase} + omit (UC_X86_INS_INVALID, + UC_X86_INS_ENDING) + with prefix="UC_X86_INS_" + deriving (Show, Eq) #} diff --git a/bindings/haskell/src/Unicorn/Hook.hs b/bindings/haskell/src/Unicorn/Hook.hs new file mode 100644 index 00000000..d716a9ba --- /dev/null +++ b/bindings/haskell/src/Unicorn/Hook.hs @@ -0,0 +1,224 @@ +{-| +Module : Unicorn.Hook +Description : Unicorn hooks. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Insert hook points into the Unicorn emulator engine. +-} +module Unicorn.Hook ( + -- * Hook types + Hook, + MemoryHookType(..), + MemoryEventHookType(..), + MemoryAccess(..), + + -- * Hook callbacks + CodeHook, + InterruptHook, + BlockHook, + InHook, + OutHook, + SyscallHook, + MemoryHook, + MemoryReadHook, + MemoryWriteHook, + MemoryEventHook, + + -- * Hook callback management + codeHookAdd, + interruptHookAdd, + blockHookAdd, + inHookAdd, + outHookAdd, + syscallHookAdd, + memoryHookAdd, + memoryEventHookAdd, + hookDel, +) where + +import Control.Monad +import Control.Monad.Trans.Class +import Control.Monad.Trans.Either (hoistEither, left, right) +import Foreign + +import Unicorn.Internal.Core +import Unicorn.Internal.Hook +import Unicorn.Internal.Util +import qualified Unicorn.CPU.X86 as X86 + +------------------------------------------------------------------------------- +-- Hook callback management (registration and deletion) +------------------------------------------------------------------------------- + +-- | Register a callback for a code hook event. +codeHookAdd :: Storable a + => Engine -- ^ 'Unicorn' engine handle + -> CodeHook a -- ^ Code hook callback + -> a -- ^ User-defined data. This will be passed to + -- the callback function + -> Word64 -- ^ Start address + -> Word64 -- ^ End address + -> Emulator Hook -- ^ The hook handle on success, or an 'Error' + -- on failure +codeHookAdd uc callback userData begin end = do + result <- lift . alloca $ \userDataPtr -> do + poke userDataPtr userData + funPtr <- marshalCodeHook callback + getResult $ ucHookAdd uc HookCode funPtr userDataPtr begin end + hoistEither result + +-- | Register a callback for an interrupt hook event. +interruptHookAdd :: Storable a + => Engine -- ^ 'Unicorn' engine handle + -> InterruptHook a -- ^ Interrupt callback + -> a -- ^ User-defined data. This will be passed + -- to the callback function + -> Word64 -- ^ Start address + -> Word64 -- ^ End address + -> Emulator Hook -- ^ The hook handle on success, or 'Error' + -- on failure +interruptHookAdd uc callback userData begin end = do + result <- lift . alloca $ \userDataPtr -> do + poke userDataPtr userData + funPtr <- marshalInterruptHook callback + getResult $ ucHookAdd uc HookIntr funPtr userDataPtr begin end + hoistEither result + +-- | Register a callback for a block hook event. +blockHookAdd :: Storable a + => Engine -- ^ 'Unicorn' engine handle + -> BlockHook a -- ^ Block callback + -> a -- ^ User-defined data. This will be passed to + -- the callback function + -> Word64 -- ^ Start address + -> Word64 -- ^ End address + -> Emulator Hook -- ^ The hook handle on success, or an 'Error' + -- on failure +blockHookAdd uc callback userData begin end = do + result <- lift . alloca $ \userDataPtr -> do + poke userDataPtr userData + funPtr <- marshalBlockHook callback + getResult $ ucHookAdd uc HookBlock funPtr userDataPtr begin end + hoistEither result + +-- | Register a callback for an IN instruction hook event (X86). +inHookAdd :: Storable a + => Engine -- ^ 'Unicorn' engine handle + -> InHook a -- ^ IN instruction callback + -> a -- ^ User-defined data. This will be passed to the + -- callback function + -> Word64 -- ^ Start address + -> Word64 -- ^ End address + -> Emulator Hook -- ^ The hook handle on success, or an 'Error' on + -- failure +inHookAdd uc callback userData begin end = do + result <- lift . alloca $ \userDataPtr -> do + poke userDataPtr userData + funPtr <- marshalInHook callback + getResult $ ucInsnHookAdd uc HookInsn funPtr userDataPtr begin end + X86.In + hoistEither result + +-- | Register a callback for an OUT instruction hook event (X86). +outHookAdd :: Storable a + => Engine -- ^ 'Unicorn' engine handle + -> OutHook a -- ^ OUT instruction callback + -> a -- ^ User-defined data. This will be passed to the + -- callback function + -> Word64 -- ^ Start address + -> Word64 -- ^ End address + -> Emulator Hook -- ^ The hook handle on success, or an 'Error' on + -- failure +outHookAdd uc callback userData begin end = do + result <- lift . alloca $ \userDataPtr -> do + poke userDataPtr userData + funPtr <- marshalOutHook callback + getResult $ ucInsnHookAdd uc HookInsn funPtr userDataPtr begin end + X86.Out + hoistEither result + +-- | Register a callback for a SYSCALL instruction hook event (X86). +syscallHookAdd :: Storable a + => Engine -- ^ 'Unicorn' engine handle + -> SyscallHook a -- ^ SYSCALL instruction callback + -> a -- ^ User-defined data. This will be passed to + -- the callback function + -> Word64 -- ^ Start address + -> Word64 -- ^ End address + -> Emulator Hook -- ^ The hook handle on success, or an 'Error' + -- on failure +syscallHookAdd uc callback userData begin end = do + result <- lift . alloca $ \userDataPtr -> do + poke userDataPtr userData + funPtr <- marshalSyscallHook callback + getResult $ ucInsnHookAdd uc HookInsn funPtr userDataPtr begin end + X86.Syscall + hoistEither result + +-- | Register a callback for a valid memory access event. +memoryHookAdd :: Storable a + => Engine -- ^ 'Unicorn' engine handle + -> MemoryHookType -- ^ A valid memory access (e.g. read, write, + -- etc.) to trigger the callback on + -> MemoryHook a -- ^ Memory access callback + -> a -- ^ User-defined data. This will be passed to + -- the callback function + -> Word64 -- ^ Start address + -> Word64 -- ^ End address + -> Emulator Hook -- ^ The hook handle on success, or an 'Error' + -- on failure +memoryHookAdd uc memHookType callback userData begin end = do + result <- lift . alloca $ \userDataPtr -> do + poke userDataPtr userData + funPtr <- marshalMemoryHook callback + getResult $ ucHookAdd uc memHookType funPtr userDataPtr begin end + hoistEither result + +-- | Register a callback for an invalid memory access event. +memoryEventHookAdd :: Storable a + => Engine -- ^ 'Unicorn' engine handle + -> MemoryEventHookType -- ^ An invalid memory access (e.g. + -- read, write, etc.) to trigger + -- the callback on + -> MemoryEventHook a -- ^ Invalid memory access callback + -> a -- ^ User-defined data. This will + -- be passed to the callback + -- function + -> Word64 -- ^ Start address + -> Word64 -- ^ End address + -> Emulator Hook -- ^ The hook handle on success, or + -- an 'Error' on failure +memoryEventHookAdd uc memEventHookType callback userData begin end = do + result <- lift . alloca $ \userDataPtr -> do + poke userDataPtr userData + funPtr <- marshalMemoryEventHook callback + getResult $ ucHookAdd uc memEventHookType funPtr userDataPtr begin end + hoistEither result + +-- | Unregister (remove) a hook callback. +hookDel :: Engine -- ^ 'Unicorn' engine handle + -> Hook -- ^ 'Hook' handle + -> Emulator () -- ^ 'ErrOk' on success, or other value on failure +hookDel uc hook = do + err <- lift $ ucHookDel uc hook + if err == ErrOk then + right () + else + left err + +------------------------------------------------------------------------------- +-- Helper functions +------------------------------------------------------------------------------- + +-- Takes the tuple returned by `ucHookAdd`, an IO (Error, Hook), and +-- returns either a `Right Hook` if no error occurred or a `Left Error` if an +-- error occurred +getResult :: IO (Error, Hook) -> IO (Either Error Hook) +getResult = + liftM (uncurry checkResult) + where checkResult err hook = + if err == ErrOk then + Right hook + else + Left err diff --git a/bindings/haskell/src/Unicorn/Internal/Core.chs b/bindings/haskell/src/Unicorn/Internal/Core.chs new file mode 100644 index 00000000..f3e08390 --- /dev/null +++ b/bindings/haskell/src/Unicorn/Internal/Core.chs @@ -0,0 +1,52 @@ +{-# LANGUAGE ForeignFunctionInterface #-} + +{-| +Module : Unicorn.Internal.Core +Description : Core Unicorn components. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Defines core Unicorn components. + +This module should not be directly imported; it is only exposed because of the +way cabal handles ordering of chs files. +-} +module Unicorn.Internal.Core where + +import Control.Monad +import Control.Monad.Trans.Either (EitherT) +import Foreign + +{# context lib="unicorn" #} + +#include +#include "unicorn_wrapper.h" + +-- | The Unicorn engine. +{# pointer *uc_engine as Engine + foreign finalizer uc_close_wrapper as close + newtype #} + +-- | A pointer to a Unicorn engine. +{# pointer *uc_engine as EnginePtr -> Engine #} + +-- | Make a new Unicorn engine out of an engine pointer. The returned Unicorn +-- engine will automatically close 'uc_close_wrapper' when it goes out of +-- scope. +mkEngine :: EnginePtr -> IO Engine +mkEngine ptr = + liftM Engine (newForeignPtr close ptr) + +-- | Errors encountered by the Unicorn API. These values are returned by +-- 'errno'. +{# enum uc_err as Error + {underscoreToCase} + with prefix = "UC_" + deriving (Show, Eq) #} + +-- | The emulator runs in the IO monad and allows for the handling of errors +-- "under the hood". +type Emulator a = EitherT Error IO a + +-- | An architecture-dependent register. +class Enum a => Reg a diff --git a/bindings/haskell/src/Unicorn/Internal/Hook.chs b/bindings/haskell/src/Unicorn/Internal/Hook.chs new file mode 100644 index 00000000..6af7a9ff --- /dev/null +++ b/bindings/haskell/src/Unicorn/Internal/Hook.chs @@ -0,0 +1,415 @@ +{-# LANGUAGE ForeignFunctionInterface #-} + +{-| +Module : Unicorn.Internal.Hook +Description : Unicorn hooks. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Low-level bindings for inserting hook points into the Unicorn emulator engine. + +This module should not be directly imported; it is only exposed because of the +way cabal handles ordering of chs files. +-} +module Unicorn.Internal.Hook ( + -- * Types + Hook, + HookType(..), + MemoryHookType(..), + MemoryEventHookType(..), + MemoryAccess(..), + + -- * Hook callback bindings + CodeHook, + InterruptHook, + BlockHook, + InHook, + OutHook, + SyscallHook, + MemoryHook, + MemoryReadHook, + MemoryWriteHook, + MemoryEventHook, + + -- * Hook marshalling + marshalCodeHook, + marshalInterruptHook, + marshalBlockHook, + marshalInHook, + marshalOutHook, + marshalSyscallHook, + marshalMemoryHook, + marshalMemoryReadHook, + marshalMemoryWriteHook, + marshalMemoryEventHook, + + -- * Hook registration and deletion bindings + ucHookAdd, + ucInsnHookAdd, + ucHookDel, +) where + +import Control.Monad +import Foreign + +import Unicorn.Internal.Util + +{# context lib="unicorn" #} + +{# import Unicorn.Internal.Core #} +{# import Unicorn.CPU.X86 #} + +#include +#include "unicorn_wrapper.h" + +------------------------------------------------------------------------------- +-- Types +------------------------------------------------------------------------------- + +-- When we pass a Unicorn engine to a hook callback, we do not want this engine +-- object to be freed automatically when the callback returns (which is what +-- would typically occur when using a ForeignPtr), because we want to continue +-- using the Unicorn engine outside the callback. To avoid this, +-- unicorn_wrapper.h provides a dummy "close" function that does nothing. When +-- we go to create a Unicorn engine to pass to a callback, we use a pointer to +-- this dummy close function as the finalizer pointer. When the callback +-- returns, the Unicorn engine remains untouched! +-- +-- XX Is there a better way to do this? +foreign import ccall "&uc_close_dummy" + closeDummy :: FunPtr (EnginePtr -> IO ()) + +mkEngineNC :: EnginePtr -> IO Engine +mkEngineNC ptr = + liftM Engine (newForeignPtr closeDummy ptr) + +-- | A Unicorn hook. +type Hook = {# type uc_hook #} + +-- Hook types. These are used internally within this module by the callback +-- registration functions and are not exposed to the user. +-- +-- Note that the both valid and invalid memory access hooks are omitted from +-- this enum (and are exposed to the user). +{# enum uc_hook_type as HookType + {underscoreToCase} + omit (UC_HOOK_MEM_READ_UNMAPPED, + UC_HOOK_MEM_WRITE_UNMAPPED, + UC_HOOK_MEM_FETCH_UNMAPPED, + UC_HOOK_MEM_READ_PROT, + UC_HOOK_MEM_WRITE_PROT, + UC_HOOK_MEM_FETCH_PROT, + UC_HOOK_MEM_READ, + UC_HOOK_MEM_WRITE, + UC_HOOK_MEM_FETCH) + with prefix="UC_" + deriving (Show, Eq) #} + +-- | Memory hook types (for valid memory accesses). +{# enum uc_hook_type as MemoryHookType + {underscoreToCase} + omit (UC_HOOK_INTR, + UC_HOOK_INSN, + UC_HOOK_CODE, + UC_HOOK_BLOCK, + UC_HOOK_MEM_READ_UNMAPPED, + UC_HOOK_MEM_WRITE_UNMAPPED, + UC_HOOK_MEM_FETCH_UNMAPPED, + UC_HOOK_MEM_READ_PROT, + UC_HOOK_MEM_WRITE_PROT, + UC_HOOK_MEM_FETCH_PROT) + with prefix="UC_" + deriving (Show, Eq) #} + +-- | Memory event hook types (for invalid memory accesses). +{# enum uc_hook_type as MemoryEventHookType + {underscoreToCase} + omit (UC_HOOK_INTR, + UC_HOOK_INSN, + UC_HOOK_CODE, + UC_HOOK_BLOCK, + UC_HOOK_MEM_READ, + UC_HOOK_MEM_WRITE, + UC_HOOK_MEM_FETCH) + with prefix="UC_" + deriving (Show, Eq) #} + +-- | Unify the hook types with a type class +class Enum a => HookTypeC a + +instance HookTypeC HookType +instance HookTypeC MemoryHookType +instance HookTypeC MemoryEventHookType + +-- | Memory access. +{# enum uc_mem_type as MemoryAccess + {underscoreToCase} + with prefix="UC_" + deriving (Show, Eq) #} + +------------------------------------------------------------------------------- +-- Hook callbacks +------------------------------------------------------------------------------- + +-- | Callback function for tracing code. +type CodeHook a = Engine -- ^ 'Unicorn' engine handle + -> Word64 -- ^ Addres where the code is being executed + -> Maybe Int -- ^ Size of machine instruction(s) being + -- executed, or 'Nothing' when size is unknown + -> a -- ^ User data passed to tracing APIs + -> IO () + +type CCodeHook = EnginePtr -> Word64 -> Word32 -> Ptr () -> IO () + +foreign import ccall "wrapper" + mkCodeHook :: CCodeHook -> IO {# type uc_cb_hookcode_t #} + +marshalCodeHook :: Storable a + => CodeHook a -> IO {# type uc_cb_hookcode_t #} +marshalCodeHook codeHook = + mkCodeHook $ \ucPtr address size userDataPtr -> do + uc <- mkEngineNC ucPtr + userData <- castPtrAndPeek userDataPtr + let maybeSize = if size == 0 then Nothing + else Just $ fromIntegral size + codeHook uc address maybeSize userData + +-- | Callback function for tracing interrupts. +type InterruptHook a = Engine -- ^ 'Unicorn' engine handle + -> Int -- ^ Interrupt number + -> a -- ^ User data passed to tracing APIs + -> IO () + +type CInterruptHook = EnginePtr -> Word32 -> Ptr () -> IO () + +foreign import ccall "wrapper" + mkInterruptHook :: CInterruptHook -> IO {# type uc_cb_hookintr_t #} + +marshalInterruptHook :: Storable a + => InterruptHook a -> IO {# type uc_cb_hookintr_t #} +marshalInterruptHook interruptHook = + mkInterruptHook $ \ucPtr intNo userDataPtr -> do + uc <- mkEngineNC ucPtr + userData <- castPtrAndPeek userDataPtr + interruptHook uc (fromIntegral intNo) userData + +-- | Callback function for tracing blocks. +type BlockHook a = CodeHook a + +marshalBlockHook :: Storable a + => BlockHook a -> IO {# type uc_cb_hookcode_t #} +marshalBlockHook = + marshalCodeHook + +-- | Callback function for tracing IN instructions (X86). +type InHook a = Engine -- ^ 'Unicorn' engine handle + -> Int -- ^ Port number + -> Int -- ^ Data size (1/2/4) to be read from this port + -> a -- ^ User data passed to tracing APIs + -> IO Word32 -- ^ The data read from the port + +type CInHook = EnginePtr -> Word32 -> Int32 -> Ptr () -> IO Word32 + +foreign import ccall "wrapper" + mkInHook :: CInHook -> IO {# type uc_cb_insn_in_t #} + +marshalInHook :: Storable a + => InHook a -> IO {# type uc_cb_insn_in_t #} +marshalInHook inHook = + mkInHook $ \ucPtr port size userDataPtr -> do + uc <- mkEngineNC ucPtr + userData <- castPtrAndPeek userDataPtr + inHook uc (fromIntegral port) (fromIntegral size) userData + +-- | Callback function for tracing OUT instructions (X86). +type OutHook a = Engine -- ^ 'Unicorn' engine handle + -> Int -- ^ Port number + -> Int -- ^ Data size (1/2/4) to be written to this port + -> Int -- ^ Data value to be written to this port + -> a -- ^ User data passed to tracing APIs + -> IO () + +type COutHook = EnginePtr -> Word32 -> Int32 -> Word32 -> Ptr () -> IO () + +foreign import ccall "wrapper" + mkOutHook :: COutHook -> IO {# type uc_cb_insn_out_t #} + +marshalOutHook :: Storable a + => OutHook a -> IO {# type uc_cb_insn_out_t #} +marshalOutHook outHook = + mkOutHook $ \ucPtr port size value userDataPtr -> do + uc <- mkEngineNC ucPtr + userData <- castPtrAndPeek userDataPtr + outHook uc (fromIntegral port) (fromIntegral size) (fromIntegral value) + userData + +-- | Callback function for tracing SYSCALL instructions (X86). +type SyscallHook a = Engine -- ^ 'Unicorn' engine handle + -> a -- ^ User data passed to tracing APIs + -> IO () + +type CSyscallHook = Ptr () -> Ptr () -> IO () + +foreign import ccall "wrapper" + mkSyscallHook :: CSyscallHook -> IO {# type uc_cb_insn_syscall_t #} + +marshalSyscallHook :: Storable a + => SyscallHook a -> IO {# type uc_cb_insn_syscall_t #} +marshalSyscallHook syscallHook = + mkSyscallHook $ \ucPtr userDataPtr -> do + uc <- mkEngineNC $ castPtr ucPtr + userData <- castPtrAndPeek userDataPtr + syscallHook uc userData + +-- | Callback function for hooking memory operations. +type MemoryHook a = Engine -- ^ 'Unicorn' engine handle + -> MemoryAccess -- ^ Memory access; read or write + -> Word64 -- ^ Address where the code is being + -- executed + -> Int -- ^ Size of data being read or written + -> Maybe Int -- ^ Value of data being wrriten, or + -- 'Nothing' if read + -> a -- ^ User data passed to tracing APIs + -> IO () + +type CMemoryHook = EnginePtr + -> Int32 + -> Word64 + -> Int32 + -> Int64 + -> Ptr () + -> IO () + +foreign import ccall "wrapper" + mkMemoryHook :: CMemoryHook -> IO {# type uc_cb_hookmem_t #} + +marshalMemoryHook :: Storable a + => MemoryHook a -> IO {# type uc_cb_hookmem_t #} +marshalMemoryHook memoryHook = + mkMemoryHook $ \ucPtr memAccessI address size value userDataPtr -> do + uc <- mkEngineNC ucPtr + userData <- castPtrAndPeek userDataPtr + let memAccess = toMemAccess memAccessI + maybeValue = case memAccess of + MemRead -> Nothing + MemWrite -> Just $ fromIntegral value + _ -> undefined -- XX Handle this? + memoryHook uc memAccess address (fromIntegral size) maybeValue userData + +-- | Callback function for hooking memory reads. +type MemoryReadHook a = Engine -- ^ 'Unicorn' engine handle + -> Word64 -- ^ Address where the code is being executed + -> Int -- ^ Size of data being read + -> a -- ^ User data passed to tracing APIs + -> IO () + +marshalMemoryReadHook :: Storable a + => MemoryReadHook a -> IO {# type uc_cb_hookmem_t #} +marshalMemoryReadHook memoryReadHook = + mkMemoryHook $ \ucPtr _ address size _ userDataPtr -> do + uc <- mkEngineNC ucPtr + userData <- castPtrAndPeek userDataPtr + memoryReadHook uc address (fromIntegral size) userData + +-- | Callback function for hooking memory writes. +type MemoryWriteHook a = Engine -- ^ 'Unicorn' engine handle + -> Word64 -- ^ Address where the code is being + -- executed + -> Int -- ^ Size of data being written + -> Int -- ^ Value of data being written + -> a -- ^ User data passed to tracing APIs + -> IO () + +marshalMemoryWriteHook :: Storable a + => MemoryWriteHook a -> IO {# type uc_cb_hookmem_t #} +marshalMemoryWriteHook memoryWriteHook = + mkMemoryHook $ \ucPtr _ address size value userDataPtr -> do + uc <- mkEngineNC ucPtr + userData <- castPtrAndPeek userDataPtr + memoryWriteHook uc address (fromIntegral size) (fromIntegral value) + userData + +-- | Callback function for handling invalid memory access events. +type MemoryEventHook a = Engine -- ^ 'Unicorn' engine handle + -> MemoryAccess -- ^ Memory access; read or write + -> Word64 -- ^ Address where the code is being + -- executed + -> Int -- ^ Size of data being read or written + -> Maybe Int -- ^ Value of data being written, or + -- 'Nothing' if read + -> a -- ^ User data passed to tracing APIs + -> IO Bool -- ^ Return 'True' to continue, or + -- 'False' to stop the program (due to + -- invalid memory) + +type CMemoryEventHook = EnginePtr + -> Int32 + -> Word64 + -> Int32 + -> Int64 + -> Ptr () + -> IO Int32 + +foreign import ccall "wrapper" + mkMemoryEventHook :: CMemoryEventHook -> IO {# type uc_cb_eventmem_t #} + +marshalMemoryEventHook :: Storable a + => MemoryEventHook a -> IO {# type uc_cb_eventmem_t #} +marshalMemoryEventHook eventMemoryHook = + mkMemoryEventHook $ \ucPtr memAccessI address size value userDataPtr -> do + uc <- mkEngineNC ucPtr + userData <- castPtrAndPeek userDataPtr + let memAccess = toMemAccess memAccessI + maybeValue = case memAccess of + MemReadUnmapped -> Nothing + MemReadProt -> Nothing + MemWriteUnmapped -> Just $ fromIntegral value + MemWriteProt -> Just $ fromIntegral value + _ -> undefined -- XX Handle this? + res <- eventMemoryHook uc memAccess address (fromIntegral size) + maybeValue userData + return $ boolToInt res + where boolToInt True = 1 + boolToInt False = 0 + + +------------------------------------------------------------------------------- +-- Hook callback registration (and deletion) +------------------------------------------------------------------------------- + +{# fun variadic uc_hook_add as ucHookAdd + `(Storable a, HookTypeC h)' => + {`Engine', + alloca- `Hook' peek*, + enumToNum `h', + castFunPtrToPtr `FunPtr b', + castPtr `Ptr a', + `Word64', + `Word64'} + -> `Error' #} + +{# fun variadic uc_hook_add[int] as ucInsnHookAdd + `(Storable a, HookTypeC h)' => + {`Engine', + alloca- `Hook' peek*, + enumToNum `h', + castFunPtrToPtr `FunPtr b', + castPtr `Ptr a', + `Word64', + `Word64', + enumToNum `Instruction'} + -> `Error' #} + +-- | Unregister (remove) a hook callback. +{# fun uc_hook_del as ^ + {`Engine', + fromIntegral `Hook'} + -> `Error' #} + +------------------------------------------------------------------------------- +-- Helper functions +------------------------------------------------------------------------------- + +toMemAccess :: Integral a => a -> MemoryAccess +toMemAccess = + toEnum . fromIntegral diff --git a/bindings/haskell/src/Unicorn/Internal/Unicorn.chs b/bindings/haskell/src/Unicorn/Internal/Unicorn.chs new file mode 100644 index 00000000..3e80b7bd --- /dev/null +++ b/bindings/haskell/src/Unicorn/Internal/Unicorn.chs @@ -0,0 +1,242 @@ +{-# LANGUAGE ForeignFunctionInterface #-} +{-# LANGUAGE ScopedTypeVariables #-} + +{-| +Module : Unicorn.Internal.Unicorn +Description : The Unicorn CPU emulator. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Low-level bindings for the Unicorn CPU emulator framework. + +This module should not be directly imported; it is only exposed because of the +way cabal handles ordering of chs files. +-} +module Unicorn.Internal.Unicorn ( + -- * Types + Architecture(..), + Mode(..), + MemoryPermission(..), + MemoryRegion(..), + QueryType(..), + + -- * Function bindings + ucOpen, + ucQuery, + ucEmuStart, + ucEmuStop, + ucRegWrite, + ucRegRead, + ucMemWrite, + ucMemRead, + ucMemMap, + ucMemUnmap, + ucMemProtect, + ucMemRegions, + ucVersion, + ucErrno, + ucStrerror, +) where + +import Foreign +import Foreign.C + +import Control.Applicative +import Data.ByteString (ByteString, useAsCStringLen) +import Prelude hiding (until) + +import Unicorn.Internal.Util + +{# context lib="unicorn" #} + +{# import Unicorn.Internal.Core #} + +#include + +------------------------------------------------------------------------------- +-- Types +------------------------------------------------------------------------------- + +-- | CPU architecture. +{# enum uc_arch as Architecture + {underscoreToCase} + with prefix = "UC_" + deriving (Show, Eq) #} + +-- | CPU hardware mode. +{# enum uc_mode as Mode + {underscoreToCase} + with prefix="UC_" + deriving (Show, Eq) #} + +-- | Memory permissions. +{# enum uc_prot as MemoryPermission + {underscoreToCase} + with prefix="UC_" + deriving (Show, Eq) #} + +-- | Memory region mapped by 'memMap'. Retrieve the list of memory regions with +-- 'memRegions'. +data MemoryRegion = MemoryRegion { + begin :: Word64, -- ^ Begin address of the region (inclusive) + end :: Word64, -- ^ End address of the region (inclusive) + perms :: [MemoryPermission] -- ^ Memory permissions of the region +} + +instance Storable MemoryRegion where + sizeOf _ = {# sizeof uc_mem_region #} + alignment _ = {# alignof uc_mem_region #} + peek p = MemoryRegion + <$> liftA fromIntegral ({# get uc_mem_region->begin #} p) + <*> liftA fromIntegral ({# get uc_mem_region->end #} p) + <*> liftA expandMemPerms ({# get uc_mem_region->perms #} p) + poke p mr = do + {# set uc_mem_region.begin #} p (fromIntegral $ begin mr) + {# set uc_mem_region.end #} p (fromIntegral $ end mr) + {# set uc_mem_region.perms #} p (combineEnums $ perms mr) + +-- | A pointer to a memory region. +{# pointer *uc_mem_region as MemoryRegionPtr -> MemoryRegion #} + +-- | Query types for the 'query' API. +{# enum uc_query_type as QueryType + {underscoreToCase} + with prefix="UC_" + deriving (Show, Eq) #} + +------------------------------------------------------------------------------- +-- Emulator control +------------------------------------------------------------------------------- + +{# fun uc_open as ^ + {`Architecture', + combineEnums `[Mode]', + alloca- `EnginePtr' peek*} + -> `Error' #} + +{# fun uc_query as ^ + {`Engine', + `QueryType', + alloca- `Int' castPtrAndPeek*} + -> `Error' #} + +{# fun uc_emu_start as ^ + {`Engine', + `Word64', + `Word64', + `Int', + `Int'} + -> `Error' #} + +{# fun uc_emu_stop as ^ + {`Engine'} + -> `Error' #} + +------------------------------------------------------------------------------- +-- Register operations +------------------------------------------------------------------------------- + +{# fun uc_reg_write as ^ + `Reg r' => + {`Engine', + enumToNum `r', + castPtr `Ptr Int64'} + -> `Error' #} + +{# fun uc_reg_read as ^ + `Reg r' => + {`Engine', + enumToNum `r', + allocaInt64ToVoid- `Int64' castPtrAndPeek*} + -> `Error' #} + +------------------------------------------------------------------------------- +-- Memory operations +------------------------------------------------------------------------------- + +{# fun uc_mem_write as ^ + {`Engine', + `Word64', + withByteStringLen* `ByteString'&} + -> `Error' #} + +{# fun uc_mem_read as ^ + {`Engine', + `Word64', + castPtr `Ptr Word8', + `Int'} + -> `Error' #} + +{# fun uc_mem_map as ^ + {`Engine', + `Word64', + `Int', + combineEnums `[MemoryPermission]'} + -> `Error' #} + +{# fun uc_mem_unmap as ^ + {`Engine', + `Word64', + `Int'} + -> `Error' #} + +{# fun uc_mem_protect as ^ + {`Engine', + `Word64', + `Int', + combineEnums `[MemoryPermission]'} + -> `Error' #} + +{# fun uc_mem_regions as ^ + {`Engine', + alloca- `MemoryRegionPtr' peek*, + alloca- `Int' castPtrAndPeek*} + -> `Error' #} + +------------------------------------------------------------------------------- +-- Misc. +------------------------------------------------------------------------------- + +{# fun pure unsafe uc_version as ^ + {id `Ptr CUInt', + id `Ptr CUInt'} + -> `Int' #} + +{# fun unsafe uc_errno as ^ + {`Engine'} + -> `Error' #} + +{# fun pure unsafe uc_strerror as ^ + {`Error'} + -> `String' #} + +------------------------------------------------------------------------------- +-- Helper functions +------------------------------------------------------------------------------- + +expandMemPerms :: (Integral a, Bits a) => a -> [MemoryPermission] +expandMemPerms perms = + -- Only interested in the 3 least-significant bits + let maskedPerms = fromIntegral $ perms .&. 0x7 in + if maskedPerms == 0x0 then + [ProtNone] + else if maskedPerms == 0x7 then + [ProtAll] + else + checkRWE maskedPerms [ProtRead, ProtWrite, ProtExec] + where + checkRWE perms (prot:prots) = + if perms .&. (fromEnum prot) /= 0 then + prot : checkRWE perms prots + else + checkRWE perms prots + checkRWE _ [] = + [] + +allocaInt64ToVoid :: (Ptr () -> IO b) -> IO b +allocaInt64ToVoid f = + alloca $ \(ptr :: Ptr Int64) -> poke ptr 0 >> f (castPtr ptr) + +withByteStringLen :: ByteString -> ((Ptr (), CULong) -> IO a) -> IO a +withByteStringLen bs f = + useAsCStringLen bs $ \(ptr, len) -> f (castPtr ptr, fromIntegral len) diff --git a/bindings/haskell/src/Unicorn/Internal/Util.hs b/bindings/haskell/src/Unicorn/Internal/Util.hs new file mode 100644 index 00000000..ecd70aab --- /dev/null +++ b/bindings/haskell/src/Unicorn/Internal/Util.hs @@ -0,0 +1,25 @@ +{-| +Module : Unicorn.Internal.Util +Description : Utility (aka helper) functions for the Unicorn emulator. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 +-} +module Unicorn.Internal.Util where + +import Data.Bits +import Foreign + +-- | Combine a list of Enums by performing a bitwise-OR. +combineEnums :: (Enum a, Num b, Bits b) => [a] -> b +combineEnums = + foldr (\p -> (.|.) (enumToNum p)) 0 + +-- | Cast a pointer and then peek inside it. +castPtrAndPeek :: Storable a => Ptr b -> IO a +castPtrAndPeek = + peek . castPtr + +-- | Convert an 'Eum' to a 'Num'. +enumToNum :: (Enum a, Num b) => a -> b +enumToNum = + fromIntegral . fromEnum diff --git a/bindings/haskell/src/cbits/unicorn_wrapper.c b/bindings/haskell/src/cbits/unicorn_wrapper.c new file mode 100644 index 00000000..1ee60706 --- /dev/null +++ b/bindings/haskell/src/cbits/unicorn_wrapper.c @@ -0,0 +1,8 @@ +#include "unicorn_wrapper.h" + +void uc_close_wrapper(uc_engine *uc) { + uc_close(uc); +} + +void uc_close_dummy(uc_engine *uc) { +} diff --git a/bindings/haskell/src/include/unicorn_wrapper.h b/bindings/haskell/src/include/unicorn_wrapper.h new file mode 100644 index 00000000..76d414aa --- /dev/null +++ b/bindings/haskell/src/include/unicorn_wrapper.h @@ -0,0 +1,16 @@ +#ifndef UNICORN_WRAPPER_H +#define UNICORN_WRAPPER_H + +#include + +/* + * Wrap Unicorn's uc_close function and ignore the returned error code. + */ +void uc_close_wrapper(uc_engine *uc); + +/* + * Doesn't actually do anything. + */ +void uc_close_dummy(uc_engine *uc); + +#endif diff --git a/bindings/haskell/unicorn.cabal b/bindings/haskell/unicorn.cabal new file mode 100644 index 00000000..77af442e --- /dev/null +++ b/bindings/haskell/unicorn.cabal @@ -0,0 +1,42 @@ +-- Initial unicorn.cabal generated by cabal init. For further +-- documentation, see http://haskell.org/cabal/users-guide/ + +name: unicorn +version: 0.1.0.0 +category: FFI, Emulation +synopsis: Unicorn CPU emulator engine +description: Haskell bindings for the Unicorn CPU emulator engine. +homepage: https://github.com/unicorn-engine/unicorn +author: Adrian Herrera +license: GPL +copyright: (c) 2016, Adrian Herrera +category: System +build-type: Simple +stability: experimental +cabal-version: >=1.10 +extra-source-files: cbits/, include/ + +library + exposed-modules: Unicorn.Internal.Core + Unicorn.Internal.Unicorn + Unicorn.CPU.Arm64 + Unicorn.CPU.Arm + Unicorn.CPU.M68k + Unicorn.CPU.Mips + Unicorn.CPU.Sparc + Unicorn.CPU.X86 + Unicorn.Internal.Hook + Unicorn.Hook + Unicorn + other-modules: Unicorn.Internal.Util + build-depends: base >=4 && <5, + bytestring >= 0.9.1, + transformers <= 0.5, + either >= 4.4 + hs-source-dirs: src + c-sources: src/cbits/unicorn_wrapper.c + include-dirs: src/include + build-tools: c2hs + pkgconfig-depends: unicorn + default-language: Haskell2010 + ghc-options: -Wall From 47f9a0cdac7b1258b43a92e91a5f9da1d90799cc Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Wed, 6 Apr 2016 09:51:45 +1000 Subject: [PATCH 111/149] Added cabal clean, configure and build commands to the bindings Makefile This ensures that c2hs is called when const_generator.py generates code for the other language bindings --- bindings/Makefile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bindings/Makefile b/bindings/Makefile index 652a6457..2e29e365 100644 --- a/bindings/Makefile +++ b/bindings/Makefile @@ -18,6 +18,7 @@ all: cd go && $(MAKE) gen_const cd java && $(MAKE) gen_const python const_generator.py dotnet + cd haskell && cabal configure && cabal build samples: expected python @@ -54,6 +55,7 @@ sample_diff: FORCE clean: rm -rf $(TMPDIR) cd python && $(MAKE) clean + cd haskell && cabal clean check: make -C python check From 431035b335606b621090c92cfbc4b424f21463b8 Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Wed, 6 Apr 2016 09:54:05 +1000 Subject: [PATCH 112/149] Fixed some GHC warnings --- bindings/haskell/src/Unicorn/Hook.hs | 1 - .../haskell/src/Unicorn/Internal/Unicorn.chs | 20 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/bindings/haskell/src/Unicorn/Hook.hs b/bindings/haskell/src/Unicorn/Hook.hs index d716a9ba..2e13ebc4 100644 --- a/bindings/haskell/src/Unicorn/Hook.hs +++ b/bindings/haskell/src/Unicorn/Hook.hs @@ -44,7 +44,6 @@ import Foreign import Unicorn.Internal.Core import Unicorn.Internal.Hook -import Unicorn.Internal.Util import qualified Unicorn.CPU.X86 as X86 ------------------------------------------------------------------------------- diff --git a/bindings/haskell/src/Unicorn/Internal/Unicorn.chs b/bindings/haskell/src/Unicorn/Internal/Unicorn.chs index 3e80b7bd..f6a4f71d 100644 --- a/bindings/haskell/src/Unicorn/Internal/Unicorn.chs +++ b/bindings/haskell/src/Unicorn/Internal/Unicorn.chs @@ -78,9 +78,9 @@ import Unicorn.Internal.Util -- | Memory region mapped by 'memMap'. Retrieve the list of memory regions with -- 'memRegions'. data MemoryRegion = MemoryRegion { - begin :: Word64, -- ^ Begin address of the region (inclusive) - end :: Word64, -- ^ End address of the region (inclusive) - perms :: [MemoryPermission] -- ^ Memory permissions of the region + mrBegin :: Word64, -- ^ Begin address of the region (inclusive) + mrEnd :: Word64, -- ^ End address of the region (inclusive) + mrPerms :: [MemoryPermission] -- ^ Memory permissions of the region } instance Storable MemoryRegion where @@ -91,9 +91,9 @@ instance Storable MemoryRegion where <*> liftA fromIntegral ({# get uc_mem_region->end #} p) <*> liftA expandMemPerms ({# get uc_mem_region->perms #} p) poke p mr = do - {# set uc_mem_region.begin #} p (fromIntegral $ begin mr) - {# set uc_mem_region.end #} p (fromIntegral $ end mr) - {# set uc_mem_region.perms #} p (combineEnums $ perms mr) + {# set uc_mem_region.begin #} p (fromIntegral $ mrBegin mr) + {# set uc_mem_region.end #} p (fromIntegral $ mrEnd mr) + {# set uc_mem_region.perms #} p (combineEnums $ mrPerms mr) -- | A pointer to a memory region. {# pointer *uc_mem_region as MemoryRegionPtr -> MemoryRegion #} @@ -225,11 +225,11 @@ expandMemPerms perms = else checkRWE maskedPerms [ProtRead, ProtWrite, ProtExec] where - checkRWE perms (prot:prots) = - if perms .&. (fromEnum prot) /= 0 then - prot : checkRWE perms prots + checkRWE p (x:xs) = + if p .&. (fromEnum x) /= 0 then + x : checkRWE p xs else - checkRWE perms prots + checkRWE p xs checkRWE _ [] = [] From 70da2485fcde5b1fb488f91496af190197725651 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 6 Apr 2016 09:36:06 +0800 Subject: [PATCH 113/149] x86: comment out restore_eflags() because it breaks some executions. see #505 --- qemu/target-i386/translate.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/qemu/target-i386/translate.c b/qemu/target-i386/translate.c index e78ff694..e176c417 100644 --- a/qemu/target-i386/translate.c +++ b/qemu/target-i386/translate.c @@ -4721,6 +4721,7 @@ static void sync_eflags(DisasContext *s, TCGContext *tcg_ctx) tcg_gen_st_tl(tcg_ctx, *cpu_T[0], cpu_env, offsetof(CPUX86State, eflags)); } +/* static void restore_eflags(DisasContext *s, TCGContext *tcg_ctx) { TCGv **cpu_T = (TCGv **)tcg_ctx->cpu_T; @@ -4731,6 +4732,7 @@ static void restore_eflags(DisasContext *s, TCGContext *tcg_ctx) tcg_const_i32(tcg_ctx, (TF_MASK | AC_MASK | ID_MASK | NT_MASK) & 0xffff)); set_cc_op(s, CC_OP_EFLAGS); } +*/ /* convert one instruction. s->is_jmp is set if the translation must be stopped. Return the next pc value */ From f2c99bc80e57f8b299b187e3c2c35faa066f0e4f Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 6 Apr 2016 09:48:14 +0800 Subject: [PATCH 114/149] update .gitignore --- .gitignore | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 92832daa..978d3cab 100644 --- a/.gitignore +++ b/.gitignore @@ -70,7 +70,12 @@ mem_unmap.static mem_apis mem_apis.exe mem_apis.static - +sample_batch_reg +sample_batch_reg.exe +sample_batch_reg.static +sample_x86_32_gdt_and_seg_regs +sample_x86_32_gdt_and_seg_regs.exe +sample_x86_32_gdt_and_seg_regs.static libunicorn*.dll libunicorn*.so From 400f396a2aa3deef435d3151348ab14c9a6b8046 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 6 Apr 2016 09:48:38 +0800 Subject: [PATCH 115/149] samples: code style for sample_batch_reg.c --- samples/sample_batch_reg.c | 42 ++++++++++++++++++++++++++++++-------- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/samples/sample_batch_reg.c b/samples/sample_batch_reg.c index 2e5e0468..abbee210 100644 --- a/samples/sample_batch_reg.c +++ b/samples/sample_batch_reg.c @@ -3,14 +3,20 @@ #include #include -int syscall_abi[] = {UC_X86_REG_RAX, UC_X86_REG_RDI, UC_X86_REG_RSI, UC_X86_REG_RDX, UC_X86_REG_R10, UC_X86_REG_R8, UC_X86_REG_R9}; -uint64_t vals[7] = {200, 10, 11, 12, 13, 14, 15}; +int syscall_abi[] = { + UC_X86_REG_RAX, UC_X86_REG_RDI, UC_X86_REG_RSI, UC_X86_REG_RDX, + UC_X86_REG_R10, UC_X86_REG_R8, UC_X86_REG_R9 +}; + +uint64_t vals[7] = { 200, 10, 11, 12, 13, 14, 15 }; + // This part of the API is less... clean... because Unicorn supports arbitrary register types. // So the least intrusive solution is passing individual pointers. // On the plus side, you only need to make this pointer array once. void *ptrs[7]; -void uc_perror(const char *func, uc_err err) { +void uc_perror(const char *func, uc_err err) +{ fprintf(stderr, "Error in %s(): %s\n", func, uc_strerror(err)); } @@ -19,30 +25,39 @@ void uc_perror(const char *func, uc_err err) { // mov rax, 100; mov rdi, 1; mov rsi, 2; mov rdx, 3; mov r10, 4; mov r8, 5; mov r9, 6; syscall #define CODE "\x48\xc7\xc0\x64\x00\x00\x00\x48\xc7\xc7\x01\x00\x00\x00\x48\xc7\xc6\x02\x00\x00\x00\x48\xc7\xc2\x03\x00\x00\x00\x49\xc7\xc2\x04\x00\x00\x00\x49\xc7\xc0\x05\x00\x00\x00\x49\xc7\xc1\x06\x00\x00\x00\x0f\x05" -void hook_syscall(uc_engine *uc, void *user_data) { +void hook_syscall(uc_engine *uc, void *user_data) +{ int i; + uc_reg_read_batch(uc, syscall_abi, ptrs, 7); + printf("syscall: {"); + for (i = 0; i < 7; i++) { if (i != 0) printf(", "); printf("%llu", vals[i]); } + printf("}\n"); } -void hook_code(uc_engine *uc, uint64_t addr, uint32_t size, void *user_data) { +void hook_code(uc_engine *uc, uint64_t addr, uint32_t size, void *user_data) +{ printf("HOOK_CODE: 0x%llx, 0x%x\n", addr, size); } -int main() { +int main() +{ int i; + uc_hook sys_hook; + uc_err err; + uc_engine *uc; + // set up register pointers for (i = 0; i < 7; i++) { ptrs[i] = &vals[i]; } - uc_err err; - uc_engine *uc; if ((err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc))) { uc_perror("uc_open", err); return 1; @@ -54,37 +69,46 @@ int main() { uc_perror("uc_reg_write_batch", err); return 1; } + // reg_read_batch memset(vals, 0, sizeof(vals)); if ((err = uc_reg_read_batch(uc, syscall_abi, ptrs, 7))) { uc_perror("uc_reg_read_batch", err); return 1; } + printf("reg_read_batch = {"); + for (i = 0; i < 7; i++) { if (i != 0) printf(", "); printf("%llu", vals[i]); } + printf("}\n"); // syscall printf("\n"); printf("running syscall shellcode\n"); - uc_hook sys_hook; + if ((err = uc_hook_add(uc, &sys_hook, UC_HOOK_INSN, hook_syscall, NULL, 1, 0, UC_X86_INS_SYSCALL))) { uc_perror("uc_hook_add", err); return 1; } + if ((err = uc_mem_map(uc, BASE, 0x1000, UC_PROT_ALL))) { uc_perror("uc_mem_map", err); return 1; } + if ((err = uc_mem_write(uc, BASE, CODE, sizeof(CODE) - 1))) { uc_perror("uc_mem_write", err); return 1; } + if ((err = uc_emu_start(uc, BASE, BASE + sizeof(CODE) - 1, 0, 0))) { uc_perror("uc_emu_start", err); return 1; } + + return 0; } From 4e9dc1d8e6f1e0b3e8a9052e9940b30736f8a3b4 Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Tue, 5 Apr 2016 19:32:19 -0700 Subject: [PATCH 116/149] fix Go binding C99 regression --- bindings/go/unicorn/uc.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/bindings/go/unicorn/uc.c b/bindings/go/unicorn/uc.c index 7d67c798..d21e66fa 100644 --- a/bindings/go/unicorn/uc.c +++ b/bindings/go/unicorn/uc.c @@ -4,7 +4,8 @@ uc_err uc_reg_read_batch_helper(uc_engine *handle, int *regs, uint64_t *val_out, int count) { void **val_ref = malloc(sizeof(void *) * count); - for (int i = 0; i < count; i++) { + int i; + for (i = 0; i < count; i++) { val_ref[i] = (void *)&val_out[i]; } uc_err ret = uc_reg_read_batch(handle, regs, val_ref, count); @@ -13,11 +14,12 @@ uc_err uc_reg_read_batch_helper(uc_engine *handle, int *regs, uint64_t *val_out, } uc_err uc_reg_write_batch_helper(uc_engine *handle, int *regs, uint64_t *val_in, int count) { - const void **val_ref = malloc(sizeof(void *) * count); - for (int i = 0; i < count; i++) { + void **val_ref = malloc(sizeof(void *) * count); + int i; + for (i = 0; i < count; i++) { val_ref[i] = (void *)&val_in[i]; } - uc_err ret = uc_reg_write_batch(handle, regs, val_ref, count); + uc_err ret = uc_reg_write_batch(handle, regs, (void *const *)val_ref, count); free(val_ref); return ret; } From 8cb77a2a931d1dcc4dce4d0bd009d5e5fe8e7f23 Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Thu, 7 Apr 2016 22:27:38 +1000 Subject: [PATCH 117/149] Fixed Makefile build step for Haskell bindings --- bindings/Makefile | 2 +- bindings/haskell/README.TXT | 10 ++++++++-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/bindings/Makefile b/bindings/Makefile index 2e29e365..d5d58c5d 100644 --- a/bindings/Makefile +++ b/bindings/Makefile @@ -18,7 +18,7 @@ all: cd go && $(MAKE) gen_const cd java && $(MAKE) gen_const python const_generator.py dotnet - cd haskell && cabal configure && cabal build + cd haskell && cabal install --dependencies-only && cabal configure && cabal build samples: expected python diff --git a/bindings/haskell/README.TXT b/bindings/haskell/README.TXT index dc629c95..b5cdccb8 100644 --- a/bindings/haskell/README.TXT +++ b/bindings/haskell/README.TXT @@ -14,8 +14,14 @@ from source. 1. Change directories into the Haskell bindings, build and install $ cd bindings/haskell + $ cabal install --dependencies-only + $ cabal configure $ cabal build $ cabal install -If the build fails, try installing c2hs manually (cabal install c2hs) and make -sure that $HOME/.cabal/bin is on your PATH. +If you are installing into a sandbox, run `cabal sandbox init` before +installing Unicorn's dependencies. + +If the build fails, try installing c2hs manually via `cabal install c2hs` (note +that this is a known problem). If you are NOT using a sandbox, make sure that +`$HOME/.cabal/bin` is on your PATH. From 8f43bf7ffccccb7156543702351d0f2f3ca2aeba Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Thu, 7 Apr 2016 22:34:07 +1000 Subject: [PATCH 118/149] Improved namespacing for MMR record-style data type --- bindings/haskell/src/Unicorn/CPU/X86.chs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/bindings/haskell/src/Unicorn/CPU/X86.chs b/bindings/haskell/src/Unicorn/CPU/X86.chs index eccb8b35..d96352e6 100644 --- a/bindings/haskell/src/Unicorn/CPU/X86.chs +++ b/bindings/haskell/src/Unicorn/CPU/X86.chs @@ -27,10 +27,10 @@ import Unicorn.Internal.Core (Reg) -- | Memory-managemen Register for instructions IDTR, GDTR, LDTR, TR. -- Borrow from SegmentCache in qemu/target-i386/cpu.h data Mmr = Mmr { - selector :: Word16, -- ^ Not used by GDTR and IDTR - base :: Word64, -- ^ Handle 32 or 64 bit CPUs - limit :: Word32, - flags :: Word32 -- ^ Not used by GDTR and IDTR + mmrSelector :: Word16, -- ^ Not used by GDTR and IDTR + mmrBase :: Word64, -- ^ Handle 32 or 64 bit CPUs + mmrLimit :: Word32, + mmrFlags :: Word32 -- ^ Not used by GDTR and IDTR } instance Storable Mmr where @@ -41,10 +41,10 @@ instance Storable Mmr where <*> liftA fromIntegral ({# get uc_x86_mmr->limit #} p) <*> liftA fromIntegral ({# get uc_x86_mmr->flags #} p) poke p mmr = do - {# set uc_x86_mmr.selector #} p (fromIntegral $ selector mmr) - {# set uc_x86_mmr.base #} p (fromIntegral $ base mmr) - {# set uc_x86_mmr.limit #} p (fromIntegral $ limit mmr) - {# set uc_x86_mmr.flags #} p (fromIntegral $ flags mmr) + {# set uc_x86_mmr.selector #} p (fromIntegral $ mmrSelector mmr) + {# set uc_x86_mmr.base #} p (fromIntegral $ mmrBase mmr) + {# set uc_x86_mmr.limit #} p (fromIntegral $ mmrLimit mmr) + {# set uc_x86_mmr.flags #} p (fromIntegral $ mmrFlags mmr) -- | X86 registers. {# enum uc_x86_reg as Register From 20e089a774d90d806c8adc85844b9c64ee9f355f Mon Sep 17 00:00:00 2001 From: Ryan Hileman Date: Thu, 7 Apr 2016 12:08:50 -0700 Subject: [PATCH 119/149] Go bindings: fix HookAdd in sample --- bindings/go/sample.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/bindings/go/sample.go b/bindings/go/sample.go index 0128cfea..6c66ace7 100644 --- a/bindings/go/sample.go +++ b/bindings/go/sample.go @@ -19,10 +19,10 @@ var asm = strings.Join([]string{ func addHooks(mu uc.Unicorn) { mu.HookAdd(uc.HOOK_BLOCK, func(mu uc.Unicorn, addr uint64, size uint32) { fmt.Printf("Block: 0x%x, 0x%x\n", addr, size) - }) + }, 1, 0) mu.HookAdd(uc.HOOK_CODE, func(mu uc.Unicorn, addr uint64, size uint32) { fmt.Printf("Code: 0x%x, 0x%x\n", addr, size) - }) + }, 1, 0) mu.HookAdd(uc.HOOK_MEM_READ|uc.HOOK_MEM_WRITE, func(mu uc.Unicorn, access int, addr uint64, size int, value int64) { if access == uc.MEM_WRITE { fmt.Printf("Mem write") @@ -30,7 +30,7 @@ func addHooks(mu uc.Unicorn) { fmt.Printf("Mem read") } fmt.Printf(": @0x%x, 0x%x = 0x%x\n", addr, size, value) - }) + }, 1, 0) invalid := uc.HOOK_MEM_READ_INVALID | uc.HOOK_MEM_WRITE_INVALID | uc.HOOK_MEM_FETCH_INVALID mu.HookAdd(invalid, func(mu uc.Unicorn, access int, addr uint64, size int, value int64) bool { switch access { @@ -45,11 +45,11 @@ func addHooks(mu uc.Unicorn) { } fmt.Printf(": @0x%x, 0x%x = 0x%x\n", addr, size, value) return false - }) + }, 1, 0) mu.HookAdd(uc.HOOK_INSN, func(mu uc.Unicorn) { rax, _ := mu.RegRead(uc.X86_REG_RAX) fmt.Printf("Syscall: %d\n", rax) - }, uc.X86_INS_SYSCALL) + }, 1, 0, uc.X86_INS_SYSCALL) } func run() error { From 34a203d4c946b369bae852fa8b867f4fb17e26ce Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Fri, 8 Apr 2016 17:58:11 +1000 Subject: [PATCH 120/149] Updated Haskell README to make it clear that Alex and Happy are required for c2hs --- bindings/haskell/README.TXT | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/bindings/haskell/README.TXT b/bindings/haskell/README.TXT index b5cdccb8..0591dce2 100644 --- a/bindings/haskell/README.TXT +++ b/bindings/haskell/README.TXT @@ -22,6 +22,7 @@ from source. If you are installing into a sandbox, run `cabal sandbox init` before installing Unicorn's dependencies. -If the build fails, try installing c2hs manually via `cabal install c2hs` (note -that this is a known problem). If you are NOT using a sandbox, make sure that -`$HOME/.cabal/bin` is on your PATH. +If the build fails, install c2hs manually `cabal install c2hs` (note that this +will probably also require you to run `cabal install alex` and `cabal install +happy` as well). If you are NOT using a sandbox, ensure that `$HOME/.cabal/bin` +is on your PATH. From 689be9356fee79baf6bdd6013cf47fa91855e5c3 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Fri, 8 Apr 2016 16:39:20 +0800 Subject: [PATCH 121/149] haskell: rename TMPDIR in bindings/Makefile to TMP_DIR --- bindings/Makefile | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/bindings/Makefile b/bindings/Makefile index d5d58c5d..72c4306a 100644 --- a/bindings/Makefile +++ b/bindings/Makefile @@ -1,15 +1,15 @@ # Unicorn Engine # By Nguyen Anh Quynh & Dang Hoang Vu, 2015 -TMPDIR = /tmp/unicorn_sample +TMP_DIR = /tmp/unicorn_sample DIFF = diff -u -w -SAMPLE_ARM = $(TMPDIR)/sample_arm -SAMPLE_ARM64 = $(TMPDIR)/sample_arm64 -SAMPLE_MIPS = $(TMPDIR)/sample_mips -SAMPLE_M68K = $(TMPDIR)/sample_m68k -SAMPLE_SPARC = $(TMPDIR)/sample_sparc -SAMPLE_X86 = $(TMPDIR)/sample_x86 +SAMPLE_ARM = $(TMP_DIR)/sample_arm +SAMPLE_ARM64 = $(TMP_DIR)/sample_arm64 +SAMPLE_MIPS = $(TMP_DIR)/sample_mips +SAMPLE_M68K = $(TMP_DIR)/sample_m68k +SAMPLE_SPARC = $(TMP_DIR)/sample_sparc +SAMPLE_X86 = $(TMP_DIR)/sample_x86 .PHONY: all expected python @@ -26,7 +26,7 @@ sample_python: expected python expected: cd ../samples && $(MAKE) - mkdir -p $(TMPDIR) + mkdir -p $(TMP_DIR) ../samples/sample_arm > $(SAMPLE_ARM)_e ../samples/sample_arm64 > $(SAMPLE_ARM64)_e ../samples/sample_mips > $(SAMPLE_MIPS)_e @@ -53,7 +53,7 @@ sample_diff: FORCE $(DIFF) $(SAMPLE_X86)_e $(SAMPLE_X86)_o clean: - rm -rf $(TMPDIR) + rm -rf $(TMP_DIR) cd python && $(MAKE) clean cd haskell && cabal clean From b53bab13626e8ba3f490195a46801aa226725a1e Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Fri, 8 Apr 2016 17:33:11 +0800 Subject: [PATCH 122/149] haskell: update .gitignore --- bindings/haskell/.gitignore | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/bindings/haskell/.gitignore b/bindings/haskell/.gitignore index 3f4aa15b..3b5b7859 100644 --- a/bindings/haskell/.gitignore +++ b/bindings/haskell/.gitignore @@ -14,3 +14,10 @@ cabal.sandbox.config *.prof *.aux *.hp +SampleArm +SampleArm64 +SampleM68k +SampleMips +SampleSparc +SampleX86 +Shellcode From 4cbe52a701d4b5cec22359543fc3ff1c51ad7b17 Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Fri, 8 Apr 2016 19:29:43 +1000 Subject: [PATCH 123/149] Updated Makefile to install bindings (in addition to building) Updated Haskell README to explain how to build the samples --- bindings/Makefile | 10 ++++++++-- bindings/haskell/README.TXT | 5 +++++ 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/bindings/Makefile b/bindings/Makefile index 72c4306a..4648e202 100644 --- a/bindings/Makefile +++ b/bindings/Makefile @@ -11,15 +11,20 @@ SAMPLE_M68K = $(TMP_DIR)/sample_m68k SAMPLE_SPARC = $(TMP_DIR)/sample_sparc SAMPLE_X86 = $(TMP_DIR)/sample_x86 -.PHONY: all expected python +.PHONY: build install samples sample_python expected python sample_diff clean check -all: +build: cd python && $(MAKE) gen_const cd go && $(MAKE) gen_const cd java && $(MAKE) gen_const python const_generator.py dotnet cd haskell && cabal install --dependencies-only && cabal configure && cabal build +install: build + cd python && $(MAKE) install + cd java && $(MAKE) install + cd haskell && cabal install + samples: expected python sample_python: expected python @@ -55,6 +60,7 @@ sample_diff: FORCE clean: rm -rf $(TMP_DIR) cd python && $(MAKE) clean + cd java && $(MAKE) clean cd haskell && cabal clean check: diff --git a/bindings/haskell/README.TXT b/bindings/haskell/README.TXT index 0591dce2..10f30032 100644 --- a/bindings/haskell/README.TXT +++ b/bindings/haskell/README.TXT @@ -26,3 +26,8 @@ If the build fails, install c2hs manually `cabal install c2hs` (note that this will probably also require you to run `cabal install alex` and `cabal install happy` as well). If you are NOT using a sandbox, ensure that `$HOME/.cabal/bin` is on your PATH. + +To build a sample (after having built and installed the Haskell bindings) + + $ cd bindings/haskell + $ ghc --make samples/SampleArm.hs From 2b1454468ca0a856889b1924f2e0a876f0df4f75 Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Fri, 8 Apr 2016 19:55:29 +1000 Subject: [PATCH 124/149] On second thought, you only really need to run `cabal install`, and that will run all the other intermediate steps for you... --- bindings/haskell/README.TXT | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/bindings/haskell/README.TXT b/bindings/haskell/README.TXT index 10f30032..93766f6d 100644 --- a/bindings/haskell/README.TXT +++ b/bindings/haskell/README.TXT @@ -14,11 +14,9 @@ from source. 1. Change directories into the Haskell bindings, build and install $ cd bindings/haskell - $ cabal install --dependencies-only - $ cabal configure - $ cabal build $ cabal install + If you are installing into a sandbox, run `cabal sandbox init` before installing Unicorn's dependencies. From b250d599b951f5bdb3a254f2e6e38b0c980074ad Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Fri, 8 Apr 2016 20:50:08 +1000 Subject: [PATCH 125/149] Removed Haskell build from Makefile - it is better to let cabal take care of this --- bindings/Makefile | 3 --- 1 file changed, 3 deletions(-) diff --git a/bindings/Makefile b/bindings/Makefile index 4648e202..ed232686 100644 --- a/bindings/Makefile +++ b/bindings/Makefile @@ -18,12 +18,10 @@ build: cd go && $(MAKE) gen_const cd java && $(MAKE) gen_const python const_generator.py dotnet - cd haskell && cabal install --dependencies-only && cabal configure && cabal build install: build cd python && $(MAKE) install cd java && $(MAKE) install - cd haskell && cabal install samples: expected python @@ -61,7 +59,6 @@ clean: rm -rf $(TMP_DIR) cd python && $(MAKE) clean cd java && $(MAKE) clean - cd haskell && cabal clean check: make -C python check From 87b65d1dda66df64a3df0f323fddf43c7c8cb088 Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Fri, 8 Apr 2016 23:31:13 +1000 Subject: [PATCH 126/149] Small formatting fix --- bindings/haskell/samples/SampleArm64.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/haskell/samples/SampleArm64.hs b/bindings/haskell/samples/SampleArm64.hs index fbed5659..db1158ae 100644 --- a/bindings/haskell/samples/SampleArm64.hs +++ b/bindings/haskell/samples/SampleArm64.hs @@ -61,7 +61,7 @@ testArm64 = do blockHookAdd uc hookBlock () 1 0 -- Tracing one instruction at address with customized callback - codeHookAdd uc hookCode ()address address + codeHookAdd uc hookCode () address address -- Emulate machine code in infinite time (last param = Nothing), or -- when finishing all the code From 0a3f83a20ce9a70dc4a03909e56ec4e9c7303121 Mon Sep 17 00:00:00 2001 From: Adrian Herrera Date: Sat, 9 Apr 2016 00:13:25 +1000 Subject: [PATCH 127/149] Small changes to align with hapstone (Haskell bindings for Capstone) Enums now derive bounded and made use of Applicative in Utils module --- bindings/haskell/src/Unicorn/CPU/Arm.chs | 2 +- bindings/haskell/src/Unicorn/CPU/Arm64.chs | 2 +- bindings/haskell/src/Unicorn/CPU/M68k.chs | 2 +- bindings/haskell/src/Unicorn/CPU/Mips.chs | 2 +- bindings/haskell/src/Unicorn/CPU/Sparc.chs | 2 +- bindings/haskell/src/Unicorn/CPU/X86.chs | 4 ++-- bindings/haskell/src/Unicorn/Internal/Core.chs | 2 +- bindings/haskell/src/Unicorn/Internal/Hook.chs | 8 ++++---- bindings/haskell/src/Unicorn/Internal/Unicorn.chs | 8 ++++---- bindings/haskell/src/Unicorn/Internal/Util.hs | 3 ++- 10 files changed, 18 insertions(+), 17 deletions(-) diff --git a/bindings/haskell/src/Unicorn/CPU/Arm.chs b/bindings/haskell/src/Unicorn/CPU/Arm.chs index 789b7e3e..fbc3294c 100644 --- a/bindings/haskell/src/Unicorn/CPU/Arm.chs +++ b/bindings/haskell/src/Unicorn/CPU/Arm.chs @@ -24,6 +24,6 @@ import Unicorn.Internal.Core (Reg) omit (UC_ARM_REG_INVALID, UC_ARM_REG_ENDING) with prefix="UC_ARM_REG_" - deriving (Show, Eq) #} + deriving (Show, Eq, Bounded) #} instance Reg Register diff --git a/bindings/haskell/src/Unicorn/CPU/Arm64.chs b/bindings/haskell/src/Unicorn/CPU/Arm64.chs index 4c67c43e..6174ef89 100644 --- a/bindings/haskell/src/Unicorn/CPU/Arm64.chs +++ b/bindings/haskell/src/Unicorn/CPU/Arm64.chs @@ -24,6 +24,6 @@ import Unicorn.Internal.Core (Reg) omit (UC_ARM64_REG_INVALID, UC_ARM64_REG_ENDING) with prefix="UC_ARM64_REG_" - deriving (Show, Eq) #} + deriving (Show, Eq, Bounded) #} instance Reg Register diff --git a/bindings/haskell/src/Unicorn/CPU/M68k.chs b/bindings/haskell/src/Unicorn/CPU/M68k.chs index 457ced79..25753aa4 100644 --- a/bindings/haskell/src/Unicorn/CPU/M68k.chs +++ b/bindings/haskell/src/Unicorn/CPU/M68k.chs @@ -24,6 +24,6 @@ import Unicorn.Internal.Core (Reg) omit (UC_M68K_REG_INVALID, UC_M68K_REG_ENDING) with prefix="UC_M68K_REG_" - deriving (Show, Eq) #} + deriving (Show, Eq, Bounded) #} instance Reg Register diff --git a/bindings/haskell/src/Unicorn/CPU/Mips.chs b/bindings/haskell/src/Unicorn/CPU/Mips.chs index fa14bc4c..b234ba72 100644 --- a/bindings/haskell/src/Unicorn/CPU/Mips.chs +++ b/bindings/haskell/src/Unicorn/CPU/Mips.chs @@ -56,6 +56,6 @@ import Unicorn.Internal.Core (Reg) omit (UC_MIPS_REG_INVALID, UC_MIPS_REG_ENDING) with prefix="UC_MIPS_REG_" - deriving (Show, Eq) #} + deriving (Show, Eq, Bounded) #} instance Reg Register diff --git a/bindings/haskell/src/Unicorn/CPU/Sparc.chs b/bindings/haskell/src/Unicorn/CPU/Sparc.chs index 28d63702..a94c1b22 100644 --- a/bindings/haskell/src/Unicorn/CPU/Sparc.chs +++ b/bindings/haskell/src/Unicorn/CPU/Sparc.chs @@ -24,6 +24,6 @@ import Unicorn.Internal.Core (Reg) omit (UC_SPARC_REG_INVALID, UC_SPARC_REG_ENDING) with prefix="UC_SPARC_REG_" - deriving (Show, Eq) #} + deriving (Show, Eq, Bounded) #} instance Reg Register diff --git a/bindings/haskell/src/Unicorn/CPU/X86.chs b/bindings/haskell/src/Unicorn/CPU/X86.chs index d96352e6..eb99c978 100644 --- a/bindings/haskell/src/Unicorn/CPU/X86.chs +++ b/bindings/haskell/src/Unicorn/CPU/X86.chs @@ -52,7 +52,7 @@ instance Storable Mmr where omit (UC_X86_REG_INVALID, UC_X86_REG_ENDING) with prefix="UC_X86_REG_" - deriving (Show, Eq) #} + deriving (Show, Eq, Bounded) #} instance Reg Register @@ -62,4 +62,4 @@ instance Reg Register omit (UC_X86_INS_INVALID, UC_X86_INS_ENDING) with prefix="UC_X86_INS_" - deriving (Show, Eq) #} + deriving (Show, Eq, Bounded) #} diff --git a/bindings/haskell/src/Unicorn/Internal/Core.chs b/bindings/haskell/src/Unicorn/Internal/Core.chs index f3e08390..ec1d5db8 100644 --- a/bindings/haskell/src/Unicorn/Internal/Core.chs +++ b/bindings/haskell/src/Unicorn/Internal/Core.chs @@ -42,7 +42,7 @@ mkEngine ptr = {# enum uc_err as Error {underscoreToCase} with prefix = "UC_" - deriving (Show, Eq) #} + deriving (Show, Eq, Bounded) #} -- | The emulator runs in the IO monad and allows for the handling of errors -- "under the hood". diff --git a/bindings/haskell/src/Unicorn/Internal/Hook.chs b/bindings/haskell/src/Unicorn/Internal/Hook.chs index 6af7a9ff..00a8a123 100644 --- a/bindings/haskell/src/Unicorn/Internal/Hook.chs +++ b/bindings/haskell/src/Unicorn/Internal/Hook.chs @@ -103,7 +103,7 @@ type Hook = {# type uc_hook #} UC_HOOK_MEM_WRITE, UC_HOOK_MEM_FETCH) with prefix="UC_" - deriving (Show, Eq) #} + deriving (Show, Eq, Bounded) #} -- | Memory hook types (for valid memory accesses). {# enum uc_hook_type as MemoryHookType @@ -119,7 +119,7 @@ type Hook = {# type uc_hook #} UC_HOOK_MEM_WRITE_PROT, UC_HOOK_MEM_FETCH_PROT) with prefix="UC_" - deriving (Show, Eq) #} + deriving (Show, Eq, Bounded) #} -- | Memory event hook types (for invalid memory accesses). {# enum uc_hook_type as MemoryEventHookType @@ -132,7 +132,7 @@ type Hook = {# type uc_hook #} UC_HOOK_MEM_WRITE, UC_HOOK_MEM_FETCH) with prefix="UC_" - deriving (Show, Eq) #} + deriving (Show, Eq, Bounded) #} -- | Unify the hook types with a type class class Enum a => HookTypeC a @@ -145,7 +145,7 @@ instance HookTypeC MemoryEventHookType {# enum uc_mem_type as MemoryAccess {underscoreToCase} with prefix="UC_" - deriving (Show, Eq) #} + deriving (Show, Eq, Bounded) #} ------------------------------------------------------------------------------- -- Hook callbacks diff --git a/bindings/haskell/src/Unicorn/Internal/Unicorn.chs b/bindings/haskell/src/Unicorn/Internal/Unicorn.chs index f6a4f71d..f5d179dd 100644 --- a/bindings/haskell/src/Unicorn/Internal/Unicorn.chs +++ b/bindings/haskell/src/Unicorn/Internal/Unicorn.chs @@ -61,19 +61,19 @@ import Unicorn.Internal.Util {# enum uc_arch as Architecture {underscoreToCase} with prefix = "UC_" - deriving (Show, Eq) #} + deriving (Show, Eq, Bounded) #} -- | CPU hardware mode. {# enum uc_mode as Mode {underscoreToCase} with prefix="UC_" - deriving (Show, Eq) #} + deriving (Show, Eq, Bounded) #} -- | Memory permissions. {# enum uc_prot as MemoryPermission {underscoreToCase} with prefix="UC_" - deriving (Show, Eq) #} + deriving (Show, Eq, Bounded) #} -- | Memory region mapped by 'memMap'. Retrieve the list of memory regions with -- 'memRegions'. @@ -102,7 +102,7 @@ instance Storable MemoryRegion where {# enum uc_query_type as QueryType {underscoreToCase} with prefix="UC_" - deriving (Show, Eq) #} + deriving (Show, Eq, Bounded) #} ------------------------------------------------------------------------------- -- Emulator control diff --git a/bindings/haskell/src/Unicorn/Internal/Util.hs b/bindings/haskell/src/Unicorn/Internal/Util.hs index ecd70aab..5ec07f7e 100644 --- a/bindings/haskell/src/Unicorn/Internal/Util.hs +++ b/bindings/haskell/src/Unicorn/Internal/Util.hs @@ -6,13 +6,14 @@ License : GPL-2 -} module Unicorn.Internal.Util where +import Control.Applicative import Data.Bits import Foreign -- | Combine a list of Enums by performing a bitwise-OR. combineEnums :: (Enum a, Num b, Bits b) => [a] -> b combineEnums = - foldr (\p -> (.|.) (enumToNum p)) 0 + foldr ((.|.) <$> enumToNum) 0 -- | Cast a pointer and then peek inside it. castPtrAndPeek :: Storable a => Ptr b -> IO a From 06a64dc3b0439e56e47d37b16f9ed509ffecc5bc Mon Sep 17 00:00:00 2001 From: practicalswift Date: Sat, 9 Apr 2016 15:27:20 -0400 Subject: [PATCH 128/149] Add six crash cases (2 * ARM + 4 * M68K) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * 001-bad_condition_code_0xe.c (ARM) * 002-qemu__fatal__unimplemented_control_register_write_0xffb___0x0.c (M68K) * 003-qemu__fatal__wdebug_not_implemented.c (M68K) * 004-segmentation_fault_1.c (ARM) * 005-qemu__fatal__illegal_instruction__0000___00000404.c (M68K) * 006-qemu__fatal__illegal_instruction__0421___00040026.c (M68K) ``` $ ./001-bad_condition_code_0xe # ARM uc_emu_start(…) Bad condition code 0xe Aborted $ ./002-qemu__fatal__unimplemented_control_register_write_0xffb___0x0 # M68K uc_emu_start(…) hook_code(…) called qemu: fatal: Unimplemented control register write 0xffb = 0x0 Aborted $ ./003-qemu__fatal__wdebug_not_implemented # M68K uc_emu_start(…) qemu: fatal: WDEBUG not implemented Aborted $ ./004-segmentation_fault_1 # ARM uc_emu_start(…) hook_code(…) called Segmentation fault $ ./005-qemu__fatal__illegal_instruction__0000___00000404 # M68K uc_emu_start(…) qemu: fatal: Illegal instruction: 0000 @ 00000404 Aborted $ ./006-qemu__fatal__illegal_instruction__0421___00040026 # M68K uc_emu_start(…) hook_code(…) called qemu: fatal: Illegal instruction: 0421 @ 00040026 Aborted ``` --- .gitignore | 6 ++++ tests/regress/001-bad_condition_code_0xe.c | 31 +++++++++++++++++++ ...ented_control_register_write_0xffb___0x0.c | 31 +++++++++++++++++++ .../003-qemu__fatal__wdebug_not_implemented.c | 31 +++++++++++++++++++ tests/regress/004-segmentation_fault_1.c | 31 +++++++++++++++++++ ...al__illegal_instruction__0000___00000404.c | 31 +++++++++++++++++++ ...al__illegal_instruction__0421___00040026.c | 31 +++++++++++++++++++ tests/regress/Makefile | 6 ++++ 8 files changed, 198 insertions(+) create mode 100644 tests/regress/001-bad_condition_code_0xe.c create mode 100644 tests/regress/002-qemu__fatal__unimplemented_control_register_write_0xffb___0x0.c create mode 100644 tests/regress/003-qemu__fatal__wdebug_not_implemented.c create mode 100644 tests/regress/004-segmentation_fault_1.c create mode 100644 tests/regress/005-qemu__fatal__illegal_instruction__0000___00000404.c create mode 100644 tests/regress/006-qemu__fatal__illegal_instruction__0421___00040026.c diff --git a/.gitignore b/.gitignore index 978d3cab..d80af2ce 100644 --- a/.gitignore +++ b/.gitignore @@ -133,6 +133,12 @@ threaded_emu_start emu_stop_in_hook_overrun mips_branch_likely_issue emu_clear_errors +001-bad_condition_code_0xe +002-qemu__fatal__unimplemented_control_register_write_0xffb___0x0 +003-qemu__fatal__wdebug_not_implemented +004-segmentation_fault_1 +005-qemu__fatal__illegal_instruction__0000___00000404 +006-qemu__fatal__illegal_instruction__0421___00040026 test_mem_map_ptr test_mem_high diff --git a/tests/regress/001-bad_condition_code_0xe.c b/tests/regress/001-bad_condition_code_0xe.c new file mode 100644 index 00000000..bcc51e8b --- /dev/null +++ b/tests/regress/001-bad_condition_code_0xe.c @@ -0,0 +1,31 @@ +#include + +#define HARDWARE_ARCHITECTURE UC_ARCH_ARM +#define HARDWARE_MODE 16 +#define MEMORY_STARTING_ADDRESS 8192 +#define MEMORY_SIZE 4096 +#define MEMORY_PERMISSIONS 6 +#define BINARY_CODE "\x56\xe8\x46\x46\x80\xf6\x8c\x56\xff\xbf\xcd\x90\xda\xa0\xed\xe8\x46\x43\x45\xe5\x80\x90\x44\x46\x04" + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { + printf("hook_code(…) called\n"); +} + +int main(int argc, char **argv, char **envp) { + uc_engine *uc; + if (uc_open(HARDWARE_ARCHITECTURE, HARDWARE_MODE, &uc)) { + printf("uc_open(…) failed\n"); + return 1; + } + uc_mem_map(uc, MEMORY_STARTING_ADDRESS, MEMORY_SIZE, MEMORY_PERMISSIONS); + if (uc_mem_write(uc, MEMORY_STARTING_ADDRESS, BINARY_CODE, sizeof(BINARY_CODE) - 1)) { + printf("uc_mem_write(…) failed\n"); + return 1; + } + uc_hook trace; + uc_hook_add(uc, &trace, UC_HOOK_CODE, hook_code, NULL, (uint64_t)MEMORY_STARTING_ADDRESS, (uint64_t)(MEMORY_STARTING_ADDRESS + 1)); + printf("uc_emu_start(…)\n"); + uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 0); + printf("done\n"); + return 0; +} diff --git a/tests/regress/002-qemu__fatal__unimplemented_control_register_write_0xffb___0x0.c b/tests/regress/002-qemu__fatal__unimplemented_control_register_write_0xffb___0x0.c new file mode 100644 index 00000000..6f8575be --- /dev/null +++ b/tests/regress/002-qemu__fatal__unimplemented_control_register_write_0xffb___0x0.c @@ -0,0 +1,31 @@ +#include + +#define HARDWARE_ARCHITECTURE UC_ARCH_M68K +#define HARDWARE_MODE 1073741824 +#define MEMORY_STARTING_ADDRESS 8388608 +#define MEMORY_SIZE 2097152 +#define MEMORY_PERMISSIONS 7 +#define BINARY_CODE "\xaf\x80\x4e\x7b\xff\xfb\x80\x4e\x3e\x80" + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { + printf("hook_code(…) called\n"); +} + +int main(int argc, char **argv, char **envp) { + uc_engine *uc; + if (uc_open(HARDWARE_ARCHITECTURE, HARDWARE_MODE, &uc)) { + printf("uc_open(…) failed\n"); + return 1; + } + uc_mem_map(uc, MEMORY_STARTING_ADDRESS, MEMORY_SIZE, MEMORY_PERMISSIONS); + if (uc_mem_write(uc, MEMORY_STARTING_ADDRESS, BINARY_CODE, sizeof(BINARY_CODE) - 1)) { + printf("uc_mem_write(…) failed\n"); + return 1; + } + uc_hook trace; + uc_hook_add(uc, &trace, UC_HOOK_CODE, hook_code, NULL, (uint64_t)MEMORY_STARTING_ADDRESS, (uint64_t)(MEMORY_STARTING_ADDRESS + 1)); + printf("uc_emu_start(…)\n"); + uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 0); + printf("done\n"); + return 0; +} diff --git a/tests/regress/003-qemu__fatal__wdebug_not_implemented.c b/tests/regress/003-qemu__fatal__wdebug_not_implemented.c new file mode 100644 index 00000000..4e07235b --- /dev/null +++ b/tests/regress/003-qemu__fatal__wdebug_not_implemented.c @@ -0,0 +1,31 @@ +#include + +#define HARDWARE_ARCHITECTURE UC_ARCH_M68K +#define HARDWARE_MODE 1073741824 +#define MEMORY_STARTING_ADDRESS 1048576 +#define MEMORY_SIZE 403456 +#define MEMORY_PERMISSIONS 7 +#define BINARY_CODE "\x42\xc7\xfb\xfb\x54\x36" + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { + printf("hook_code(…) called\n"); +} + +int main(int argc, char **argv, char **envp) { + uc_engine *uc; + if (uc_open(HARDWARE_ARCHITECTURE, HARDWARE_MODE, &uc)) { + printf("uc_open(…) failed\n"); + return 1; + } + uc_mem_map(uc, MEMORY_STARTING_ADDRESS, MEMORY_SIZE, MEMORY_PERMISSIONS); + if (uc_mem_write(uc, MEMORY_STARTING_ADDRESS, BINARY_CODE, sizeof(BINARY_CODE) - 1)) { + printf("uc_mem_write(…) failed\n"); + return 1; + } + uc_hook trace; + uc_hook_add(uc, &trace, UC_HOOK_CODE, hook_code, NULL, (uint64_t)MEMORY_STARTING_ADDRESS, (uint64_t)(MEMORY_STARTING_ADDRESS + 1)); + printf("uc_emu_start(…)\n"); + uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 0); + printf("done\n"); + return 0; +} diff --git a/tests/regress/004-segmentation_fault_1.c b/tests/regress/004-segmentation_fault_1.c new file mode 100644 index 00000000..636cae7e --- /dev/null +++ b/tests/regress/004-segmentation_fault_1.c @@ -0,0 +1,31 @@ +#include + +#define HARDWARE_ARCHITECTURE UC_ARCH_ARM +#define HARDWARE_MODE 16 +#define MEMORY_STARTING_ADDRESS 1024 +#define MEMORY_SIZE 1796096 +#define MEMORY_PERMISSIONS 7 +#define BINARY_CODE "\x20\xbf\xbf\xbf\xbf\xdd\x5d\x74\x5e\x66\x72\x10" + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { + printf("hook_code(…) called\n"); +} + +int main(int argc, char **argv, char **envp) { + uc_engine *uc; + if (uc_open(HARDWARE_ARCHITECTURE, HARDWARE_MODE, &uc)) { + printf("uc_open(…) failed\n"); + return 1; + } + uc_mem_map(uc, MEMORY_STARTING_ADDRESS, MEMORY_SIZE, MEMORY_PERMISSIONS); + if (uc_mem_write(uc, MEMORY_STARTING_ADDRESS, BINARY_CODE, sizeof(BINARY_CODE) - 1)) { + printf("uc_mem_write(…) failed\n"); + return 1; + } + uc_hook trace; + uc_hook_add(uc, &trace, UC_HOOK_CODE, hook_code, NULL, (uint64_t)MEMORY_STARTING_ADDRESS, (uint64_t)(MEMORY_STARTING_ADDRESS + 1)); + printf("uc_emu_start(…)\n"); + uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 0); + printf("done\n"); + return 0; +} diff --git a/tests/regress/005-qemu__fatal__illegal_instruction__0000___00000404.c b/tests/regress/005-qemu__fatal__illegal_instruction__0000___00000404.c new file mode 100644 index 00000000..b2bea73c --- /dev/null +++ b/tests/regress/005-qemu__fatal__illegal_instruction__0000___00000404.c @@ -0,0 +1,31 @@ +#include + +#define HARDWARE_ARCHITECTURE UC_ARCH_M68K +#define HARDWARE_MODE 1073741824 +#define MEMORY_STARTING_ADDRESS 1024 +#define MEMORY_SIZE 1044480 +#define MEMORY_PERMISSIONS 5 +#define BINARY_CODE "\x4c\x4c" + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { + printf("hook_code(…) called\n"); +} + +int main(int argc, char **argv, char **envp) { + uc_engine *uc; + if (uc_open(HARDWARE_ARCHITECTURE, HARDWARE_MODE, &uc)) { + printf("uc_open(…) failed\n"); + return 1; + } + uc_mem_map(uc, MEMORY_STARTING_ADDRESS, MEMORY_SIZE, MEMORY_PERMISSIONS); + if (uc_mem_write(uc, MEMORY_STARTING_ADDRESS, BINARY_CODE, sizeof(BINARY_CODE) - 1)) { + printf("uc_mem_write(…) failed\n"); + return 1; + } + uc_hook trace; + uc_hook_add(uc, &trace, UC_HOOK_CODE, hook_code, NULL, (uint64_t)MEMORY_STARTING_ADDRESS, (uint64_t)(MEMORY_STARTING_ADDRESS + 1)); + printf("uc_emu_start(…)\n"); + uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 0); + printf("done\n"); + return 0; +} diff --git a/tests/regress/006-qemu__fatal__illegal_instruction__0421___00040026.c b/tests/regress/006-qemu__fatal__illegal_instruction__0421___00040026.c new file mode 100644 index 00000000..607c9d5d --- /dev/null +++ b/tests/regress/006-qemu__fatal__illegal_instruction__0421___00040026.c @@ -0,0 +1,31 @@ +#include + +#define HARDWARE_ARCHITECTURE UC_ARCH_M68K +#define HARDWARE_MODE 1073741824 +#define MEMORY_STARTING_ADDRESS 262144 +#define MEMORY_SIZE 403456 +#define MEMORY_PERMISSIONS 7 +#define BINARY_CODE "\xe2\x86\x09\xbc\xf2\x17\x09\xca\xca\xca\xca\x09\x09\x09\xf2\x17\x09\x20\x09\x09\xf2\x08\x09\x03\x09\xca\x6b\x6b\x6b\x1e\xca\xca\x86\x09\x09\xf2\x17\x09\x04\x21\x09\x09\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf2" + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { + printf("hook_code(…) called\n"); +} + +int main(int argc, char **argv, char **envp) { + uc_engine *uc; + if (uc_open(HARDWARE_ARCHITECTURE, HARDWARE_MODE, &uc)) { + printf("uc_open(…) failed\n"); + return 1; + } + uc_mem_map(uc, MEMORY_STARTING_ADDRESS, MEMORY_SIZE, MEMORY_PERMISSIONS); + if (uc_mem_write(uc, MEMORY_STARTING_ADDRESS, BINARY_CODE, sizeof(BINARY_CODE) - 1)) { + printf("uc_mem_write(…) failed\n"); + return 1; + } + uc_hook trace; + uc_hook_add(uc, &trace, UC_HOOK_CODE, hook_code, NULL, (uint64_t)MEMORY_STARTING_ADDRESS, (uint64_t)(MEMORY_STARTING_ADDRESS + 1)); + printf("uc_emu_start(…)\n"); + uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 0); + printf("done\n"); + return 0; +} diff --git a/tests/regress/Makefile b/tests/regress/Makefile index 6b8381a9..ea965593 100644 --- a/tests/regress/Makefile +++ b/tests/regress/Makefile @@ -38,6 +38,12 @@ TESTS += hook_extrainvoke TESTS += sysenter_hook_x86 TESTS += emu_clear_errors TESTS += mem_fuzz +TESTS += 001-bad_condition_code_0xe +TESTS += 002-qemu__fatal__unimplemented_control_register_write_0xffb___0x0 +TESTS += 003-qemu__fatal__wdebug_not_implemented +TESTS += 004-segmentation_fault_1 +TESTS += 005-qemu__fatal__illegal_instruction__0000___00000404 +TESTS += 006-qemu__fatal__illegal_instruction__0421___00040026 all: $(TESTS) From 78c3f6876503612db670be0b92cabd47374cd2f0 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 10 Apr 2016 22:47:12 +0800 Subject: [PATCH 129/149] update CREDITS.TXT --- CREDITS.TXT | 1 + 1 file changed, 1 insertion(+) diff --git a/CREDITS.TXT b/CREDITS.TXT index 72a5ff4c..2cffd9b3 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -61,3 +61,4 @@ Antonio Parata: .NET binding Jonathon Reinhart: C unit test Sascha Schirra: Ruby binding Adrian Herrera: Haskell binding +practicalswift: Various cool bugs found by fuzzing. From ba31be79f47960a082fc40fe93d55054bfe28d89 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 17 Apr 2016 23:37:25 +0800 Subject: [PATCH 130/149] update qemu/powerpc.h --- qemu/powerpc.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/qemu/powerpc.h b/qemu/powerpc.h index 1e46c3b4..dbdb4196 100644 --- a/qemu/powerpc.h +++ b/qemu/powerpc.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_powerpc #define par_write par_write_powerpc #define patch_reloc patch_reloc_powerpc -#define pause_all_vcpus pause_all_vcpus_powerpc #define phys_map_node_alloc phys_map_node_alloc_powerpc #define phys_map_node_reserve phys_map_node_reserve_powerpc #define phys_mem_alloc phys_mem_alloc_powerpc @@ -2418,7 +2417,6 @@ #define qemu_clock_ptr qemu_clock_ptr_powerpc #define qemu_clocks qemu_clocks_powerpc #define qemu_cond_destroy qemu_cond_destroy_powerpc -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_powerpc #define qemu_daemon qemu_daemon_powerpc #define qemu_event_destroy qemu_event_destroy_powerpc #define qemu_event_init qemu_event_init_powerpc @@ -2516,7 +2514,6 @@ #define qemu_strnlen qemu_strnlen_powerpc #define qemu_strsep qemu_strsep_powerpc #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_powerpc -#define qemu_thread_exit qemu_thread_exit_powerpc #define qemu_try_memalign qemu_try_memalign_powerpc #define qentry_destroy qentry_destroy_powerpc #define qerror_human qerror_human_powerpc From a015ddc348e97c8b6f247f89647b8ffddbaad128 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 18 Apr 2016 10:18:39 +0800 Subject: [PATCH 131/149] add link to Rust binding --- README.md | 2 +- bindings/README | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8a5bbde8..5acff9a5 100644 --- a/README.md +++ b/README.md @@ -13,7 +13,7 @@ Unicorn offers some unparalleled features: - Multi-architecture: ARM, ARM64 (ARMv8), M68K, MIPS, SPARC, and X86 (16, 32, 64-bit) - Clean/simple/lightweight/intuitive architecture-neutral API -- Implemented in pure C language, with bindings for Ruby, Python, Java, MSVC, .NET, Go, Delphi/Free Pascal and Haskell. +- Implemented in pure C language, with bindings for Rust, Ruby, Python, Java, MSVC, .NET, Go, Delphi/Free Pascal and Haskell. - Native support for Windows & *nix (with Mac OSX, Linux, *BSD & Solaris confirmed) - High performance via Just-In-Time compilation - Support for fine-grained instrumentation at various levels diff --git a/bindings/README b/bindings/README index a588e24c..292c5796 100644 --- a/bindings/README +++ b/bindings/README @@ -14,3 +14,6 @@ More bindings created & maintained externally by community are available as foll - UnicornPascal: Delphi/Free Pascal binding (by Stievie). https://github.com/stievie/UnicornPascal + +- Unicorn-Rs: Rust binding (by Sébastien Duquette) + https://github.com/ekse/unicorn-rs From d2ccc27cc833ec1a146c25c0e387195e1b35a28c Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Mon, 18 Apr 2016 12:54:21 +0800 Subject: [PATCH 132/149] samples: fix warning on printing 64bit int in sample_batch_reg.c --- samples/sample_batch_reg.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/samples/sample_batch_reg.c b/samples/sample_batch_reg.c index abbee210..90684d75 100644 --- a/samples/sample_batch_reg.c +++ b/samples/sample_batch_reg.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -35,7 +36,7 @@ void hook_syscall(uc_engine *uc, void *user_data) for (i = 0; i < 7; i++) { if (i != 0) printf(", "); - printf("%llu", vals[i]); + printf("%" PRIu64, vals[i]); } printf("}\n"); @@ -43,7 +44,7 @@ void hook_syscall(uc_engine *uc, void *user_data) void hook_code(uc_engine *uc, uint64_t addr, uint32_t size, void *user_data) { - printf("HOOK_CODE: 0x%llx, 0x%x\n", addr, size); + printf("HOOK_CODE: 0x%" PRIx64 ", 0x%x\n", addr, size); } int main() @@ -81,7 +82,7 @@ int main() for (i = 0; i < 7; i++) { if (i != 0) printf(", "); - printf("%llu", vals[i]); + printf("%" PRIu64, vals[i]); } printf("}\n"); From 283672426e4ff2b531b5b4b9a8860e3e7b4972ab Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Tue, 19 Apr 2016 09:42:48 +0800 Subject: [PATCH 133/149] update CREDITS.TXT --- CREDITS.TXT | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/CREDITS.TXT b/CREDITS.TXT index 2cffd9b3..a79b053b 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -61,4 +61,5 @@ Antonio Parata: .NET binding Jonathon Reinhart: C unit test Sascha Schirra: Ruby binding Adrian Herrera: Haskell binding -practicalswift: Various cool bugs found by fuzzing. +practicalswift: Various cool bugs found by fuzzing +farmdve: Memory leaking fix From 8932463f9dde4da77b78befbbe096d8a70d62bf5 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 20 Apr 2016 12:04:15 +0800 Subject: [PATCH 134/149] arm: qutie emulation on EXCP_YIELD exception. this fixes testcase 004-segmentation_fault_1 in #520 --- qemu/target-arm/unicorn_arm.c | 1 + 1 file changed, 1 insertion(+) diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index 40510b38..bf7c5dda 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -122,6 +122,7 @@ static bool arm_stop_interrupt(int intno) default: return false; case EXCP_UDEF: + case EXCP_YIELD: return true; } } From 9f94191a6417e2ebeb2900533b876187420f68cd Mon Sep 17 00:00:00 2001 From: Zach Riggle Date: Wed, 20 Apr 2016 15:34:55 -0700 Subject: [PATCH 135/149] Remove double-free This was previously released at uc_close ../uc.c:286 if (uc->release) uc->release(uc->tcg_ctx); Which effectively does: object_unref(uc, OBJECT(uc->root)); --- uc.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/uc.c b/uc.c index 188affab..c8ba7741 100644 --- a/uc.c +++ b/uc.c @@ -299,9 +299,6 @@ uc_err uc_close(uc_engine *uc) free(uc->ram_list.dirty_memory[i]); } - // TODO: remove uc->root (created with object_new()) - uc->root->free(uc->root); - // free hooks and hook lists for (i = 0; i < UC_HOOK_MAX; i++) { cur = uc->hook[i].head; From 93063d089b743868dc7e3ec62d0c1935cd2dad72 Mon Sep 17 00:00:00 2001 From: Zach Riggle Date: Wed, 20 Apr 2016 15:38:27 -0700 Subject: [PATCH 136/149] Add ASAN build target with UNICORN_ASAN or via './make.sh asan' --- Makefile | 14 ++++++++++---- make.sh | 8 ++++++++ samples/Makefile | 7 +++++++ tests/unit/Makefile | 7 +++++++ 4 files changed, 32 insertions(+), 4 deletions(-) diff --git a/Makefile b/Makefile index ad237953..2d577767 100644 --- a/Makefile +++ b/Makefile @@ -64,6 +64,13 @@ else CFLAGS += -O3 endif +ifeq ($(UNICORN_ASAN),yes) +CC = clang -fsanitize=address -fno-omit-frame-pointer +CXX = clang++ -fsanitize=address -fno-omit-frame-pointer +AR = llvm-ar +LDFLAGS := -fsanitize=address ${LDFLAGS} +endif + ifeq ($(CROSS),) CC ?= cc AR ?= ar @@ -122,7 +129,7 @@ EXT = so VERSION_EXT = $(EXT).$(API_MAJOR) AR_EXT = a $(LIBNAME)_LDFLAGS += -Wl,-Bsymbolic-functions,-soname,lib$(LIBNAME).$(VERSION_EXT) -UNICORN_CFLAGS += -fvisibility=hidden +# UNICORN_CFLAGS += -fvisibility=hidden endif endif endif @@ -213,11 +220,11 @@ config: qemu/config-host.h-timestamp: ifeq ($(UNICORN_DEBUG),yes) cd qemu && \ - ./configure --extra-cflags="$(UNICORN_CFLAGS)" --target-list="$(UNICORN_TARGETS)" ${UNICORN_QEMU_FLAGS} + ./configure --cc="${CC}" --extra-cflags="$(UNICORN_CFLAGS)" --target-list="$(UNICORN_TARGETS)" ${UNICORN_QEMU_FLAGS} printf "$(UNICORN_ARCHS)" > config.log else cd qemu && \ - ./configure --disable-debug-info --extra-cflags="$(UNICORN_CFLAGS)" --target-list="$(UNICORN_TARGETS)" ${UNICORN_QEMU_FLAGS} + ./configure --cc="${CC}" --disable-debug-info --extra-cflags="$(UNICORN_CFLAGS)" --target-list="$(UNICORN_TARGETS)" ${UNICORN_QEMU_FLAGS} printf "$(UNICORN_ARCHS)" > config.log endif @@ -264,7 +271,6 @@ endif test: all $(MAKE) -C tests/unit test - install: compile_lib $(PKGCFGF) mkdir -p $(DESTDIR)$(LIBDIR) ifeq ($(UNICORN_SHARED),yes) diff --git a/make.sh b/make.sh index db258df5..bb234572 100755 --- a/make.sh +++ b/make.sh @@ -10,6 +10,13 @@ MAKE_JOBS=$((${MAKE_JOBS}+0)) [ ${MAKE_JOBS} -lt 1 ] && \ MAKE_JOBS=4 +# build for ASAN +asan() { + UNICORN_DEBUG=yes + UNICORN_ASAN=yes + ${MAKE} V=1 +} + # build iOS lib for all iDevices, or only specific device build_iOS() { IOS_SDK=`xcrun --sdk iphoneos --show-sdk-path` @@ -90,6 +97,7 @@ export CC INSTALL_BIN PREFIX PKGCFGDIR LIBDIRARCH LIBARCHS CFLAGS LDFLAGS case "$1" in "" ) build;; + "asan" ) asan;; "default" ) build;; "install" ) install;; "uninstall" ) uninstall;; diff --git a/samples/Makefile b/samples/Makefile index 3cbaf69b..15030da8 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -37,6 +37,13 @@ else CC = $(CROSS)gcc endif +ifeq ($(UNICORN_ASAN),yes) +CC = clang -fsanitize=address -fno-omit-frame-pointer +CXX = clang++ -fsanitize=address -fno-omit-frame-pointer +AR = llvm-ar +LDFLAGS := -fsanitize=address ${LDFLAGS} +endif + #CFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch)) #LDFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch)) diff --git a/tests/unit/Makefile b/tests/unit/Makefile index b99570da..fd4f3eef 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile @@ -4,6 +4,13 @@ CFLAGS += -L ../../ CFLAGS += -lcmocka -lunicorn CFLAGS += -I ../../include +ifeq ($(UNICORN_ASAN),yes) +CC = clang -fsanitize=address -fno-omit-frame-pointer +CXX = clang++ -fsanitize=address -fno-omit-frame-pointer +AR = llvm-ar +LDFLAGS := -fsanitize=address ${LDFLAGS} +endif + ALL_TESTS = test_sanity test_x86 test_mem_map test_mem_high test_mem_map_ptr \ test_tb_x86 test_multihook test_pc_change test_x86_soft_paging \ test_hookcounts From 72ba554738f94b4ad3cd745053e5eb6ba3b344b8 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 23 Apr 2016 10:17:04 +0800 Subject: [PATCH 137/149] qemu_thread_join() takes only 1 arg --- qemu/util/qemu-thread-posix.c | 2 +- qemu/util/qemu-thread-win32.c | 3 +-- uc.c | 2 +- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/qemu/util/qemu-thread-posix.c b/qemu/util/qemu-thread-posix.c index 59f2a8fb..78bbb75c 100644 --- a/qemu/util/qemu-thread-posix.c +++ b/qemu/util/qemu-thread-posix.c @@ -431,7 +431,7 @@ void qemu_thread_exit(struct uc_struct *uc, void *retval) pthread_exit(retval); } -void *qemu_thread_join(struct uc_struct *uc, QemuThread *thread) +void *qemu_thread_join(QemuThread *thread) { int err; void *ret; diff --git a/qemu/util/qemu-thread-win32.c b/qemu/util/qemu-thread-win32.c index 6aa1e595..97ba69c6 100644 --- a/qemu/util/qemu-thread-win32.c +++ b/qemu/util/qemu-thread-win32.c @@ -298,7 +298,7 @@ void qemu_thread_exit(struct uc_struct *uc, void *arg) _endthreadex(0); } -void *qemu_thread_join(struct uc_struct *uc, QemuThread *thread) +void *qemu_thread_join(QemuThread *thread) { QemuThreadData *data; void *ret; @@ -323,7 +323,6 @@ void *qemu_thread_join(struct uc_struct *uc, QemuThread *thread) ret = data->ret; assert(data->mode != QEMU_THREAD_DETACHED); DeleteCriticalSection(&data->cs); - uc->qemu_thread_data = NULL; g_free(data); return ret; } diff --git a/uc.c b/uc.c index 7bf5b82a..6ab6d3c6 100644 --- a/uc.c +++ b/uc.c @@ -578,7 +578,7 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time if (timeout) { // wait for the timer to finish - qemu_thread_join(uc, &uc->timer); + qemu_thread_join(&uc->timer); } return uc->invalid_error; From f4723916dfc457701f6a757e34f9bf3bfdf6b331 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 23 Apr 2016 10:23:09 +0800 Subject: [PATCH 138/149] remove qemu_cond_destroy from qemu/header_gen.py --- qemu/aarch64.h | 1 - qemu/arm.h | 1 - qemu/header_gen.py | 1 - qemu/m68k.h | 1 - qemu/mips.h | 1 - qemu/mips64.h | 1 - qemu/mips64el.h | 1 - qemu/mipsel.h | 1 - qemu/powerpc.h | 1 - qemu/sparc.h | 1 - qemu/sparc64.h | 1 - qemu/x86_64.h | 1 - 12 files changed, 12 deletions(-) diff --git a/qemu/aarch64.h b/qemu/aarch64.h index 9675aecb..09352a6a 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -2416,7 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_aarch64 #define qemu_clock_ptr qemu_clock_ptr_aarch64 #define qemu_clocks qemu_clocks_aarch64 -#define qemu_cond_destroy qemu_cond_destroy_aarch64 #define qemu_daemon qemu_daemon_aarch64 #define qemu_event_destroy qemu_event_destroy_aarch64 #define qemu_event_init qemu_event_init_aarch64 diff --git a/qemu/arm.h b/qemu/arm.h index ecbca369..6b955375 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -2416,7 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_arm #define qemu_clock_ptr qemu_clock_ptr_arm #define qemu_clocks qemu_clocks_arm -#define qemu_cond_destroy qemu_cond_destroy_arm #define qemu_daemon qemu_daemon_arm #define qemu_event_destroy qemu_event_destroy_arm #define qemu_event_init qemu_event_init_arm diff --git a/qemu/header_gen.py b/qemu/header_gen.py index 71d57f1b..95476877 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -2422,7 +2422,6 @@ symbols = ( 'qemu_clock_get_us', 'qemu_clock_ptr', 'qemu_clocks', - 'qemu_cond_destroy', 'qemu_daemon', 'qemu_event_destroy', 'qemu_event_init', diff --git a/qemu/m68k.h b/qemu/m68k.h index 060bc3cb..bb37dedb 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -2416,7 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_m68k #define qemu_clock_ptr qemu_clock_ptr_m68k #define qemu_clocks qemu_clocks_m68k -#define qemu_cond_destroy qemu_cond_destroy_m68k #define qemu_daemon qemu_daemon_m68k #define qemu_event_destroy qemu_event_destroy_m68k #define qemu_event_init qemu_event_init_m68k diff --git a/qemu/mips.h b/qemu/mips.h index bf43f675..58113dce 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -2416,7 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_mips #define qemu_clock_ptr qemu_clock_ptr_mips #define qemu_clocks qemu_clocks_mips -#define qemu_cond_destroy qemu_cond_destroy_mips #define qemu_daemon qemu_daemon_mips #define qemu_event_destroy qemu_event_destroy_mips #define qemu_event_init qemu_event_init_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index 06d21f1c..d1a106f0 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -2416,7 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_mips64 #define qemu_clock_ptr qemu_clock_ptr_mips64 #define qemu_clocks qemu_clocks_mips64 -#define qemu_cond_destroy qemu_cond_destroy_mips64 #define qemu_daemon qemu_daemon_mips64 #define qemu_event_destroy qemu_event_destroy_mips64 #define qemu_event_init qemu_event_init_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index 9532e07f..95505a7b 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -2416,7 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_mips64el #define qemu_clock_ptr qemu_clock_ptr_mips64el #define qemu_clocks qemu_clocks_mips64el -#define qemu_cond_destroy qemu_cond_destroy_mips64el #define qemu_daemon qemu_daemon_mips64el #define qemu_event_destroy qemu_event_destroy_mips64el #define qemu_event_init qemu_event_init_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 96ba3373..beabca5e 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -2416,7 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_mipsel #define qemu_clock_ptr qemu_clock_ptr_mipsel #define qemu_clocks qemu_clocks_mipsel -#define qemu_cond_destroy qemu_cond_destroy_mipsel #define qemu_daemon qemu_daemon_mipsel #define qemu_event_destroy qemu_event_destroy_mipsel #define qemu_event_init qemu_event_init_mipsel diff --git a/qemu/powerpc.h b/qemu/powerpc.h index f6c82f16..6b5e109d 100644 --- a/qemu/powerpc.h +++ b/qemu/powerpc.h @@ -2416,7 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_powerpc #define qemu_clock_ptr qemu_clock_ptr_powerpc #define qemu_clocks qemu_clocks_powerpc -#define qemu_cond_destroy qemu_cond_destroy_powerpc #define qemu_daemon qemu_daemon_powerpc #define qemu_event_destroy qemu_event_destroy_powerpc #define qemu_event_init qemu_event_init_powerpc diff --git a/qemu/sparc.h b/qemu/sparc.h index 4fc2b954..32f5512d 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -2416,7 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_sparc #define qemu_clock_ptr qemu_clock_ptr_sparc #define qemu_clocks qemu_clocks_sparc -#define qemu_cond_destroy qemu_cond_destroy_sparc #define qemu_daemon qemu_daemon_sparc #define qemu_event_destroy qemu_event_destroy_sparc #define qemu_event_init qemu_event_init_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index 75f8e6eb..d42eb1fd 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -2416,7 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_sparc64 #define qemu_clock_ptr qemu_clock_ptr_sparc64 #define qemu_clocks qemu_clocks_sparc64 -#define qemu_cond_destroy qemu_cond_destroy_sparc64 #define qemu_daemon qemu_daemon_sparc64 #define qemu_event_destroy qemu_event_destroy_sparc64 #define qemu_event_init qemu_event_init_sparc64 diff --git a/qemu/x86_64.h b/qemu/x86_64.h index 48e83728..df78a28a 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -2416,7 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_x86_64 #define qemu_clock_ptr qemu_clock_ptr_x86_64 #define qemu_clocks qemu_clocks_x86_64 -#define qemu_cond_destroy qemu_cond_destroy_x86_64 #define qemu_daemon qemu_daemon_x86_64 #define qemu_event_destroy qemu_event_destroy_x86_64 #define qemu_event_init qemu_event_init_x86_64 From 0e52b913e772f4e27c8c6877342fb308e1f7b031 Mon Sep 17 00:00:00 2001 From: Tim Blazytko Date: Sun, 24 Apr 2016 11:47:04 +0200 Subject: [PATCH 139/149] added regression test write_before_map.py --- tests/regress/write_before_map.py | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 tests/regress/write_before_map.py diff --git a/tests/regress/write_before_map.py b/tests/regress/write_before_map.py new file mode 100644 index 00000000..7bdb1e45 --- /dev/null +++ b/tests/regress/write_before_map.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python + +from __future__ import print_function +from unicorn import * +from unicorn.x86_const import * + +import regress + +X86_CODE64 = "\x90" # NOP + + +class WriteBeforeMap(regress.RegressTest): + def runTest(self): + # Initialize emulator in X86-32bit mode + mu = Uc(UC_ARCH_X86, UC_MODE_64) + + # memory address where emulation starts + ADDRESS = 0x1000000 + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, X86_CODE64) + + +if __name__ == '__main__': + regress.main() From df1de25db0b1bdeaea4998289ef1c3682652288d Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 24 Apr 2016 18:09:06 +0800 Subject: [PATCH 140/149] regress: chmod +x write_before_map.py --- tests/regress/write_before_map.py | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tests/regress/write_before_map.py diff --git a/tests/regress/write_before_map.py b/tests/regress/write_before_map.py old mode 100644 new mode 100755 From 4084a385c2853cd1b34ad65c418abcf5e31485a3 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sun, 24 Apr 2016 22:53:30 +0800 Subject: [PATCH 141/149] regress: add mem_64_c.c from issue #523 by Chris Eagle --- .gitignore | 1 + tests/regress/Makefile | 1 + tests/regress/mem_64_c.c | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 tests/regress/mem_64_c.c diff --git a/.gitignore b/.gitignore index bcce4e55..03e0ab10 100644 --- a/.gitignore +++ b/.gitignore @@ -76,6 +76,7 @@ sample_batch_reg.static sample_x86_32_gdt_and_seg_regs sample_x86_32_gdt_and_seg_regs.exe sample_x86_32_gdt_and_seg_regs.static +mem_64_c libunicorn*.dll libunicorn*.so diff --git a/tests/regress/Makefile b/tests/regress/Makefile index e50a0b06..9fc1f39c 100644 --- a/tests/regress/Makefile +++ b/tests/regress/Makefile @@ -44,6 +44,7 @@ TESTS += 003-qemu__fatal__wdebug_not_implemented TESTS += 004-segmentation_fault_1 TESTS += 005-qemu__fatal__illegal_instruction__0000___00000404 TESTS += 006-qemu__fatal__illegal_instruction__0421___00040026 +TESTS += mem_64_c TESTS += memleak_x86 TESTS += memleak_arm diff --git a/tests/regress/mem_64_c.c b/tests/regress/mem_64_c.c new file mode 100644 index 00000000..e09a90da --- /dev/null +++ b/tests/regress/mem_64_c.c @@ -0,0 +1,39 @@ +#include +#include + +uint64_t starts[] = {0x10000000, 0x110004000ll}; + +int main(int argc, char **argv, char **envp) { + uc_engine *uc; + uc_err err; + int i; + // Initialize emulator in X86-64bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u\n", err); + return 1; + } + + for (i = 0; i < (sizeof(starts) / sizeof(uint64_t)); i++) { + uc_mem_map(uc, starts[i], 4096, UC_PROT_ALL); + } + + uint32_t count; + uc_mem_region *regions; + int err_count = 0; + err = uc_mem_regions(uc, ®ions, &count); + if (err == UC_ERR_OK) { + for (i = 0; i < count; i++) { + fprintf(stderr, "region %d: 0x%llx-0x%llx (%d)\n", i, regions[i].begin, regions[i].end - 1, regions[i].perms); + if (regions[i].begin != starts[i]) { + err_count++; + fprintf(stderr, " ERROR: region start does not match requested start address, expected 0x%llx, found 0x%llx\n", + starts[i], regions[i].begin); + } + } + free(regions); + } + + uc_close(uc); + return err_count; +} From fef59a4e3c944784eb01780e87c640611da708c9 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Wed, 27 Apr 2016 16:32:30 +0800 Subject: [PATCH 142/149] Makefile: re-enable CC flag -fvisibility=hidden --- Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Makefile b/Makefile index 2d577767..e2216003 100644 --- a/Makefile +++ b/Makefile @@ -129,7 +129,7 @@ EXT = so VERSION_EXT = $(EXT).$(API_MAJOR) AR_EXT = a $(LIBNAME)_LDFLAGS += -Wl,-Bsymbolic-functions,-soname,lib$(LIBNAME).$(VERSION_EXT) -# UNICORN_CFLAGS += -fvisibility=hidden +UNICORN_CFLAGS += -fvisibility=hidden endif endif endif From c45f791dd28dd5e174badd486a2b516ac7205e4b Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 30 Apr 2016 08:41:12 +0800 Subject: [PATCH 143/149] delete include/unicorn/platform.h --- include/unicorn/m68k.h | 1 - include/unicorn/platform.h | 28 ---------------------------- include/unicorn/sparc.h | 1 - include/unicorn/unicorn.h | 3 +-- 4 files changed, 1 insertion(+), 32 deletions(-) delete mode 100644 include/unicorn/platform.h diff --git a/include/unicorn/m68k.h b/include/unicorn/m68k.h index 80350c13..201a4e78 100644 --- a/include/unicorn/m68k.h +++ b/include/unicorn/m68k.h @@ -9,7 +9,6 @@ extern "C" { #endif #include -#include "platform.h" #ifdef _MSC_VER #pragma warning(disable:4201) diff --git a/include/unicorn/platform.h b/include/unicorn/platform.h deleted file mode 100644 index c1e80623..00000000 --- a/include/unicorn/platform.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Unicorn Emulator Engine */ -/* By Axel Souchet & Nguyen Anh Quynh, 2014 */ - -// handle C99 issue (for pre-2013 VisualStudio) -#ifndef UNICORN_PLATFORM_H -#define UNICORN_PLATFORM_H - -#if !defined(__MINGW32__) && !defined(__MINGW64__) && (defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64)) -// MSVC - -// stdbool.h -#if (_MSC_VER < 1800) -#ifndef __cplusplus -typedef unsigned char bool; -#define false 0 -#define true 1 -#endif - -#else -// VisualStudio 2013+ -> C99 is supported -#include -#endif - -#else // not MSVC -> C99 is supported -#include -#endif - -#endif diff --git a/include/unicorn/sparc.h b/include/unicorn/sparc.h index 353dbb34..57a483b7 100644 --- a/include/unicorn/sparc.h +++ b/include/unicorn/sparc.h @@ -9,7 +9,6 @@ extern "C" { #endif #include -#include "platform.h" // GCC SPARC toolchain has a default macro called "sparc" which breaks // compilation diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 0eb5390e..b5d901f9 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -9,6 +9,7 @@ extern "C" { #endif #include +#include #include #if defined(UNICORN_HAS_OSXKERNEL) #include @@ -17,8 +18,6 @@ extern "C" { #include #endif -#include "platform.h" - struct uc_struct; typedef struct uc_struct uc_engine; From 0d5a4f46310882e2c98f181ea9d8b10e2d7de586 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 30 Apr 2016 09:25:50 +0800 Subject: [PATCH 144/149] remove platform.h from COMPILE.TXT --- COMPILE.TXT | 1 - 1 file changed, 1 deletion(-) diff --git a/COMPILE.TXT b/COMPILE.TXT index e2e932dd..2f4a7104 100644 --- a/COMPILE.TXT +++ b/COMPILE.TXT @@ -141,7 +141,6 @@ Unicorn requires few dependent packages as follows. /usr/include/unicorn/ppc.h /usr/include/unicorn/sparc.h /usr/include/unicorn/m68k.h - /usr/include/unicorn/platform.h /usr/lib/libunicorn.so (for Linux/*nix), or /usr/lib/libunicorn.dylib (OSX) /usr/lib/libunicorn.a From fdd01588f18ca2e93e139c4e5e46acdfc3bdaafe Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 30 Apr 2016 09:49:00 +0800 Subject: [PATCH 145/149] docs: move COMPILE.TXT to docs/, and split it into separate files for *nix & Windows --- COMPILE.TXT | 303 ---------------------------------------- README.md | 2 +- docs/COMPILE-NIX.md | 169 ++++++++++++++++++++++ docs/COMPILE-WINDOWS.md | 200 ++++++++++++++++++++++++++ docs/COMPILE.md | 10 ++ 5 files changed, 380 insertions(+), 304 deletions(-) delete mode 100644 COMPILE.TXT create mode 100644 docs/COMPILE-NIX.md create mode 100644 docs/COMPILE-WINDOWS.md create mode 100644 docs/COMPILE.md diff --git a/COMPILE.TXT b/COMPILE.TXT deleted file mode 100644 index 2f4a7104..00000000 --- a/COMPILE.TXT +++ /dev/null @@ -1,303 +0,0 @@ -This documentation explains how to compile, install & run Unicorn on MacOSX, -Linux, *BSD & Solaris. We also show steps to cross-compile for Microsoft Windows. - - *-*-*-*-*-* - -[0] Dependencies - -Unicorn requires few dependent packages as follows. - -- For Mac OS X, "pkg-config" and "glib" are needed. - Brew users can install "pkg-config" and "glib" with: - - $ brew install pkg-config glib - -- For Linux, "glib2-dev" is needed. - Ubuntu/Debian users can install this with: - - $ sudo apt-get install libglib2.0-dev - -- For Windows, cross-compile requires Mingw. Mingw-glib2 is needed. - At the moment, it is confirmed that Unicorn can be compiled either on Ubuntu - or Windows. - - - On Ubuntu 14.04 64-bit, do: - - 1. Download DEB packages for Mingw64 from: - - https://launchpad.net/~greg-hellings/+archive/ubuntu/mingw-libs/+build/2924251 - - 2. To cross-compile for Windows 32-bit, install Mingw with (ignore all the warnings): - - $ sudo dpkg -i --force-depends mingw64-x86-glib2_2.31.0_all.deb - - To cross-compile for Windows 64-bit, install Mingw with: - - $ sudo dpkg -i --force-depends mingw64-x64-glib2_2.31.0_all.deb - - - - On Windows, install MinGW via package MSYS2 at https://msys2.github.io/ - - Follow the install instructions and don't forget to update the system packages with: - - $ pacman --needed -Sy bash pacman pacman-mirrors msys2-runtime - - Then close MSYS2, run it again from Start menu and update the rest with: - - $ pacman -Su - - Finally, install required toolchain to build C projects. - - - To compile for Windows 32-bit, run: - $ pacman -S python2 - $ pacman -S make - $ pacman -S pkg-config - $ pacman -S mingw-w64-i686-glib2 - $ pacman -S mingw-w64-i686-toolchain - - - To compile for Windows 64-bit, run: - $ pacman -S python2 - $ pacman -S make - $ pacman -S pkg-config - $ pacman -S mingw-w64-x86_64-glib2 - $ pacman -S mingw-w64-x86_64-toolchain - -- For Cygwin, "make", "gcc-core", "pkg-config", "libpcre-devel", "zlib-devel" - and "libglib2.0-devel" are needed. - - If apt-cyg is available, you can install these with: - - $ apt-cyg install make gcc-core pkg-config libpcre-devel zlib-devel libglib2.0-devel - - - -[1] Tailor Unicorn to your need. - - Out of 6 archtitectures supported by Unicorn (Arm, Arm64, M68K, Mips, Sparc, - & X86), if you just need several selected archs, choose which ones you want - to compile in by editing "config.mk" before going to next steps. - - By default, all 6 architectures are compiled. - - The other way of customize Unicorn without having to edit config.mk is to - pass the desired options on the commandline to ./make.sh. Currently, - Unicorn supports 4 options, as follows. - - - UNICORN_ARCHS: specify list of architectures to compiled in. - - UNICORN_STATIC: build static library. - - UNICORN_SHARED: build dynamic (shared) library. - - UNICORN_QEMU_FLAGS: specify extra flags for qemu's configure script - - To avoid editing config.mk for these customization, we can pass their values to - make.sh, as follows. - - $ UNICORN_ARCHS="arm aarch64 x86" ./make.sh - - NOTE: on commandline, put these values in front of ./make.sh, not after it. - - For each option, refer to docs/README for more details. - - - -[2] Compile and install from source on *nix - - To build Unicorn on *nix (such as MacOSX, Linux, *BSD, Solaris): - - - To compile for current platform, run: - - $ ./make.sh - - - Unicorn requires Python 2.x to compile. If Python 2.x is not the default - Python interpreter, ensure that the appropriate option is set: - - $ UNICORN_QEMU_FLAGS="--python=/path/to/python2" ./make.sh - - - To cross-compile Unicorn on 64-bit OS to target 32-bit binary, run: - - $ ./make.sh nix32 - - After compiling, install Unicorn with: - - $ sudo ./make.sh install - - For FreeBSD/OpenBSD, where sudo is unavailable, run: - - $ su; ./make.sh install - - Users are then required to enter root password to copy Unicorn into machine - system directories. - - Afterwards, run ./samples/sample_all.sh to test the sample emulations. - - - NOTE: The core framework installed by "./make.sh install" consist of - following files: - - /usr/include/unicorn/unicorn.h - /usr/include/unicorn/x86.h - /usr/include/unicorn/arm.h - /usr/include/unicorn/arm64.h - /usr/include/unicorn/mips.h - /usr/include/unicorn/ppc.h - /usr/include/unicorn/sparc.h - /usr/include/unicorn/m68k.h - /usr/lib/libunicorn.so (for Linux/*nix), or /usr/lib/libunicorn.dylib (OSX) - /usr/lib/libunicorn.a - - - -[3] Compile from source on Windows - with MinGW (MSYS2) - - To compile with MinGW, install MSYS2 as instructed in the first section. - Then, build Unicorn with the next steps: - - - To compile Windows 32-bit binary with MinGW, run: - $ ./make.sh cross-win32 - - - To compile Windows 64-bit binary with MinGW, run: - $ ./make.sh cross-win64 - - Resulted files unicorn.dll, unicorn.lib & samples/sample*.exe can then - be used on Windows machine. - - To run sample_x86.exe on Windows 32-bit, you need the following files: - - unicorn.dll - - %MSYS2%\mingw32\bin\libiconv-2.dll - - %MSYS2%\mingw32\bin\libintl-8.dll - - %MSYS2%\mingw32\bin\libglib-2.0-0.dll - - %MSYS2%\mingw32\bin\libgcc_s_dw2-1.dll - - %MSYS2%\mingw32\bin\libwinpthread-1.dll - - To run sample_x86.exe on Windows 64-bit, you need the following files: - - unicorn.dll - - %MSYS2%\mingw64\bin\libiconv-2.dll - - %MSYS2%\mingw64\bin\libintl-8.dll - - %MSYS2%\mingw64\bin\libglib-2.0-0.dll - - %MSYS2%\mingw64\bin\libgcc_s_seh-1.dll - - %MSYS2%\mingw64\bin\libwinpthread-1.dll - - - -[4] Compile and install from source on Cygwin - - To build Unicorn on Cygwin, run: - - $ ./make.sh - - After compiling, install Unicorn with: - - $ ./make.sh install - - Resulted files cygunicorn.dll, libunicorn.dll.a and libunicorn.a can be - used on Cygwin but not native Windows. - - NOTE: The core framework installed by "./make.sh install" consist of - following files: - - /usr/include/unicorn/*.h - /usr/bin/cygunicorn.dll - /usr/lib/libunicorn.dll.a - /usr/lib/libunicorn.a - - - -[5] Cross-compile for Windows from *nix - - To cross-compile for Windows, Linux & gcc-mingw-w64-i686 (and also gcc-mingw-w64-x86-64 - for 64-bit binaries) are required. - - - To cross-compile Windows 32-bit binary, simply run: - - $ ./make.sh cross-win32 - - - To cross-compile Windows 64-bit binary, run: - - $ ./make.sh cross-win64 - - Resulted files unicorn.dll, unicorn.lib & samples/sample*.exe can then - be used on Windows machine. - - To run sample_x86.exe on Windows 32-bit, you need the following files: - - unicorn.dll - - /usr/i686-w64-mingw32/sys-root/mingw/bin/libglib-2.0-0.dll - - /usr/lib/gcc/i686-w64-mingw32/4.8/libgcc_s_sjlj-1.dll - - /usr/i686-w64-mingw32/lib/libwinpthread-1.dll - - To run sample_x86.exe on Windows 64-bit, you need the following files: - - unicorn.dll - - /usr/x86_64-w64-mingw32/sys-root/mingw/bin/libglib-2.0-0.dll - - /usr/lib/gcc/x86_64-w64-mingw32/4.8/libgcc_s_sjlj-1.dll - - /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll - - Then run either "sample_x86.exe -32" or "sample_x86.exe -64" to test emulators for X86 32-bit or X86 64-bit. - For other architectures, run "sample_xxx.exe" found in the same directory. - - - -[6] Cross-compile for iOS from Mac OSX. - - To cross-compile for iOS (iPhone/iPad/iPod), Mac OSX with XCode installed is required. - - - To cross-compile for ArmV7 (iPod 4, iPad 1/2/3, iPhone4, iPhone4S), run: - $ ./make.sh ios_armv7 - - - To cross-compile for ArmV7s (iPad 4, iPhone 5C, iPad mini), run: - $ ./make.sh ios_armv7s - - - To cross-compile for Arm64 (iPhone 5S, iPad mini Retina, iPad Air), run: - $ ./make.sh ios_arm64 - - - To cross-compile for all iDevices (armv7 + armv7s + arm64), run: - $ ./make.sh ios - - Resulted files libunicorn.dylib, libunicorn.a & tests/test* can then - be used on iOS devices. - - - -[7] Cross-compile for Android - - To cross-compile for Android (smartphone/tablet), Android NDK is required. - NOTE: Only ARM and ARM64 are currently supported. - - $ NDK=/android/android-ndk-r10e ./make.sh cross-android arm - or - $ NDK=/android/android-ndk-r10e ./make.sh cross-android arm64 - - Resulted files libunicorn.so, libunicorn.a & tests/test* can then - be used on Android devices. - - - -[8] By default, "cc" (default C compiler on the system) is used as compiler. - - - To use "clang" compiler instead, run the command below: - - $ ./make.sh clang - - - To use "gcc" compiler instead, run: - - $ ./make.sh gcc - - - -[9] To uninstall Unicorn, run the command below: - - $ sudo ./make.sh uninstall - - - -[10] Language bindings - - Look for the bindings under directory bindings/, and refer to README file - of corresponding languages. - - - -[11] Unit tests - - Automated unit tests use the cmocka unit testing framework (https://cmocka.org/). - It can be installed in most Linux distros using the package manager, e.g. - `sudo yum install libcmocka libcmocka-devel`, or you can easily build and install it from source. - - You can run the tests by running `make test` in the project directory. diff --git a/README.md b/README.md index 5acff9a5..eb061cdd 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,7 @@ This project is released under the [GPL license](COPYING). Compilation & Docs ------------------ -See [COMPILE.TXT](COMPILE.TXT) file for how to compile and install Unicorn. +See [docs/COMPILE.md](docs/COMPILE.md) file for how to compile and install Unicorn. More documentation is available in [docs/README.md](docs/README.md). diff --git a/docs/COMPILE-NIX.md b/docs/COMPILE-NIX.md new file mode 100644 index 00000000..811ad8a9 --- /dev/null +++ b/docs/COMPILE-NIX.md @@ -0,0 +1,169 @@ +This documentation explains how to compile, install & run Unicorn on MacOSX, +Linux, *BSD, Solaris, Android & iOS. + +To compile for Microsoft Windows, see [COMPILE-WINDOWS.md](COMPILE-WINDOWS.md) + + *-*-*-*-*-* + +[0] Dependencies + +Unicorn requires few dependent packages as follows. + +- For Mac OS X, "pkg-config" and "glib" are needed. + Brew users can install "pkg-config" and "glib" with: + + $ brew install pkg-config glib + +- For Linux, "glib2-dev" is needed. + Ubuntu/Debian users can install this with: + + $ sudo apt-get install libglib2.0-dev + + + +[1] Tailor Unicorn to your need. + + Out of 6 archtitectures supported by Unicorn (Arm, Arm64, M68K, Mips, Sparc, + & X86), if you just need several selected archs, choose which ones you want + to compile in by editing "config.mk" before going to next steps. + + By default, all 6 architectures are compiled. + + The other way of customize Unicorn without having to edit config.mk is to + pass the desired options on the commandline to ./make.sh. Currently, + Unicorn supports 4 options, as follows. + + - UNICORN_ARCHS: specify list of architectures to compiled in. + - UNICORN_STATIC: build static library. + - UNICORN_SHARED: build dynamic (shared) library. + - UNICORN_QEMU_FLAGS: specify extra flags for qemu's configure script + + To avoid editing config.mk for these customization, we can pass their values to + make.sh, as follows. + + $ UNICORN_ARCHS="arm aarch64 x86" ./make.sh + + NOTE: on commandline, put these values in front of ./make.sh, not after it. + + For each option, refer to docs/README for more details. + + + +[2] Compile and install from source on *nix + + To build Unicorn on *nix (such as MacOSX, Linux, *BSD, Solaris): + + - To compile for current platform, run: + + $ ./make.sh + + - Unicorn requires Python 2.x to compile. If Python 2.x is not the default + Python interpreter, ensure that the appropriate option is set: + + $ UNICORN_QEMU_FLAGS="--python=/path/to/python2" ./make.sh + + - To cross-compile Unicorn on 64-bit OS to target 32-bit binary, run: + + $ ./make.sh nix32 + + After compiling, install Unicorn with: + + $ sudo ./make.sh install + + For FreeBSD/OpenBSD, where sudo is unavailable, run: + + $ su; ./make.sh install + + Users are then required to enter root password to copy Unicorn into machine + system directories. + + Afterwards, run ./samples/sample_all.sh to test the sample emulations. + + + NOTE: The core framework installed by "./make.sh install" consist of + following files: + + /usr/include/unicorn/unicorn.h + /usr/include/unicorn/x86.h + /usr/include/unicorn/arm.h + /usr/include/unicorn/arm64.h + /usr/include/unicorn/mips.h + /usr/include/unicorn/ppc.h + /usr/include/unicorn/sparc.h + /usr/include/unicorn/m68k.h + /usr/lib/libunicorn.so (for Linux/*nix), or /usr/lib/libunicorn.dylib (OSX) + /usr/lib/libunicorn.a + + + +[3] Cross-compile for iOS from Mac OSX. + + To cross-compile for iOS (iPhone/iPad/iPod), Mac OSX with XCode installed is required. + + - To cross-compile for ArmV7 (iPod 4, iPad 1/2/3, iPhone4, iPhone4S), run: + + $ ./make.sh ios_armv7 + + - To cross-compile for ArmV7s (iPad 4, iPhone 5C, iPad mini), run: + + $ ./make.sh ios_armv7s + + - To cross-compile for Arm64 (iPhone 5S, iPad mini Retina, iPad Air), run: + + $ ./make.sh ios_arm64 + + - To cross-compile for all iDevices (armv7 + armv7s + arm64), run: + + $ ./make.sh ios + + Resulted files libunicorn.dylib, libunicorn.a & tests/test* can then + be used on iOS devices. + + + +[4] Cross-compile for Android + + To cross-compile for Android (smartphone/tablet), Android NDK is required. + NOTE: Only ARM and ARM64 are currently supported. + + $ NDK=/android/android-ndk-r10e ./make.sh cross-android arm + or + $ NDK=/android/android-ndk-r10e ./make.sh cross-android arm64 + + Resulted files libunicorn.so, libunicorn.a & tests/test* can then + be used on Android devices. + + + +[5] By default, "cc" (default C compiler on the system) is used as compiler. + + - To use "clang" compiler instead, run the command below: + + $ ./make.sh clang + + - To use "gcc" compiler instead, run: + + $ ./make.sh gcc + + + +[6] To uninstall Unicorn, run the command below: + + $ sudo ./make.sh uninstall + + + +[7] Language bindings + + Look for the bindings under directory bindings/, and refer to README file + of corresponding languages. + + + +[8] Unit tests + + Automated unit tests use the cmocka unit testing framework (https://cmocka.org/). + It can be installed in most Linux distros using the package manager, e.g. + `sudo yum install libcmocka libcmocka-devel`, or you can easily build and install it from source. + + You can run the tests by running `make test` in the project directory. diff --git a/docs/COMPILE-WINDOWS.md b/docs/COMPILE-WINDOWS.md new file mode 100644 index 00000000..0a94687f --- /dev/null +++ b/docs/COMPILE-WINDOWS.md @@ -0,0 +1,200 @@ +We also show steps to cross-compile Unicorn for Microsoft Windows. + +To compile for *nix OS, see [COMPILE-NIX.md](COMPILE-NIX.md) + + *-*-*-*-*-* + +[0] Dependencies + + For Windows, cross-compile requires Mingw. Mingw-glib2 is needed. + At the moment, it is confirmed that Unicorn can be compiled either on Ubuntu + or Windows. + + - On Ubuntu 14.04 64-bit, do: + + 1. Download DEB packages for Mingw64 from: + + https://launchpad.net/~greg-hellings/+archive/ubuntu/mingw-libs/+build/2924251 + + 2. To cross-compile for Windows 32-bit, install Mingw with (ignore all the warnings): + + $ sudo dpkg -i --force-depends mingw64-x86-glib2_2.31.0_all.deb + + To cross-compile for Windows 64-bit, install Mingw with: + + $ sudo dpkg -i --force-depends mingw64-x64-glib2_2.31.0_all.deb + + + - On Windows, install MinGW via package MSYS2 at https://msys2.github.io/ + + Follow the install instructions and don't forget to update the system packages with: + + $ pacman --needed -Sy bash pacman pacman-mirrors msys2-runtime + + Then close MSYS2, run it again from Start menu and update the rest with: + + $ pacman -Su + + Finally, install required toolchain to build C projects. + + - To compile for Windows 32-bit, run: + + $ pacman -S python2 + $ pacman -S make + $ pacman -S pkg-config + $ pacman -S mingw-w64-i686-glib2 + $ pacman -S mingw-w64-i686-toolchain + + - To compile for Windows 64-bit, run: + + $ pacman -S python2 + $ pacman -S make + $ pacman -S pkg-config + $ pacman -S mingw-w64-x86_64-glib2 + $ pacman -S mingw-w64-x86_64-toolchain + +- For Cygwin, "make", "gcc-core", "pkg-config", "libpcre-devel", "zlib-devel" + and "libglib2.0-devel" are needed. + + If apt-cyg is available, you can install these with: + + $ apt-cyg install make gcc-core pkg-config libpcre-devel zlib-devel libglib2.0-devel + + + +[1] Tailor Unicorn to your need. + + Out of 6 archtitectures supported by Unicorn (Arm, Arm64, M68K, Mips, Sparc, + & X86), if you just need several selected archs, choose which ones you want + to compile in by editing "config.mk" before going to next steps. + + By default, all 6 architectures are compiled. + + The other way of customize Unicorn without having to edit config.mk is to + pass the desired options on the commandline to ./make.sh. Currently, + Unicorn supports 4 options, as follows. + + - UNICORN_ARCHS: specify list of architectures to compiled in. + - UNICORN_STATIC: build static library. + - UNICORN_SHARED: build dynamic (shared) library. + - UNICORN_QEMU_FLAGS: specify extra flags for qemu's configure script + + To avoid editing config.mk for these customization, we can pass their values to + make.sh, as follows. + + $ UNICORN_ARCHS="arm aarch64 x86" ./make.sh + + NOTE: on commandline, put these values in front of ./make.sh, not after it. + + For each option, refer to docs/README for more details. + + + +[2] Compile from source on Windows - with MinGW (MSYS2) + + To compile with MinGW, install MSYS2 as instructed in the first section. + Then, build Unicorn with the next steps: + + - To compile Windows 32-bit binary with MinGW, run: + + $ ./make.sh cross-win32 + + - To compile Windows 64-bit binary with MinGW, run: + + $ ./make.sh cross-win64 + + Resulted files unicorn.dll, unicorn.lib & samples/sample*.exe can then + be used on Windows machine. + + To run sample_x86.exe on Windows 32-bit, you need the following files: + + unicorn.dll + %MSYS2%\mingw32\bin\libiconv-2.dll + %MSYS2%\mingw32\bin\libintl-8.dll + %MSYS2%\mingw32\bin\libglib-2.0-0.dll + %MSYS2%\mingw32\bin\libgcc_s_dw2-1.dll + %MSYS2%\mingw32\bin\libwinpthread-1.dll + + To run sample_x86.exe on Windows 64-bit, you need the following files: + + unicorn.dll + %MSYS2%\mingw64\bin\libiconv-2.dll + %MSYS2%\mingw64\bin\libintl-8.dll + %MSYS2%\mingw64\bin\libglib-2.0-0.dll + %MSYS2%\mingw64\bin\libgcc_s_seh-1.dll + %MSYS2%\mingw64\bin\libwinpthread-1.dll + + + +[3] Compile and install from source on Cygwin + + To build Unicorn on Cygwin, run: + + $ ./make.sh + + After compiling, install Unicorn with: + + $ ./make.sh install + + Resulted files cygunicorn.dll, libunicorn.dll.a and libunicorn.a can be + used on Cygwin but not native Windows. + + NOTE: The core framework installed by "./make.sh install" consist of + following files: + + /usr/include/unicorn/*.h + /usr/bin/cygunicorn.dll + /usr/lib/libunicorn.dll.a + /usr/lib/libunicorn.a + + + +[4] Cross-compile for Windows from *nix + + To cross-compile for Windows, Linux & gcc-mingw-w64-i686 (and also gcc-mingw-w64-x86-64 + for 64-bit binaries) are required. + + - To cross-compile Windows 32-bit binary, simply run: + + $ ./make.sh cross-win32 + + - To cross-compile Windows 64-bit binary, run: + + $ ./make.sh cross-win64 + + Resulted files unicorn.dll, unicorn.lib & samples/sample*.exe can then + be used on Windows machine. + + To run sample_x86.exe on Windows 32-bit, you need the following files: + + unicorn.dll + /usr/i686-w64-mingw32/sys-root/mingw/bin/libglib-2.0-0.dll + /usr/lib/gcc/i686-w64-mingw32/4.8/libgcc_s_sjlj-1.dll + /usr/i686-w64-mingw32/lib/libwinpthread-1.dll + + To run sample_x86.exe on Windows 64-bit, you need the following files: + + unicorn.dll + /usr/x86_64-w64-mingw32/sys-root/mingw/bin/libglib-2.0-0.dll + /usr/lib/gcc/x86_64-w64-mingw32/4.8/libgcc_s_sjlj-1.dll + /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll + + Then run either "sample_x86.exe -32" or "sample_x86.exe -64" to test emulators for X86 32-bit or X86 64-bit. + For other architectures, run "sample_xxx.exe" found in the same directory. + + + +[5] Language bindings + + Look for the bindings under directory bindings/, and refer to README file + of corresponding languages. + + + +[6] Unit tests + + Automated unit tests use the cmocka unit testing framework (https://cmocka.org/). + It can be installed in most Linux distros using the package manager, e.g. + `sudo yum install libcmocka libcmocka-devel`, or you can easily build and install it from source. + + You can run the tests by running `make test` in the project directory. diff --git a/docs/COMPILE.md b/docs/COMPILE.md new file mode 100644 index 00000000..2953b9b8 --- /dev/null +++ b/docs/COMPILE.md @@ -0,0 +1,10 @@ +To compile Keystone on Mac OS X, Linux, BSD, Solaris and all kind of nix OS, +see [COMPILE-NIX.md](COMPILE-NIX.md) + +To compile Keystone on Windows, see [COMPILE-WINDOWS.md](COMPILE-WINDOWS.md) + +Then learn more on how to code your own tools with our samples. + + - For C sample code, see code in directory samples/sample*.c + - For Python sample code, see code in directory bindings/python/sample*.py + - For samples of other bindings, look into directories bindings// From 9236eb4597a4b10a16050154a60fa16f89b48180 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 30 Apr 2016 12:03:07 +0800 Subject: [PATCH 146/149] correct docs/COMPILE.md --- docs/COMPILE.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/COMPILE.md b/docs/COMPILE.md index 2953b9b8..28c9636f 100644 --- a/docs/COMPILE.md +++ b/docs/COMPILE.md @@ -1,7 +1,7 @@ -To compile Keystone on Mac OS X, Linux, BSD, Solaris and all kind of nix OS, +To compile Unicorn on Mac OS X, Linux, BSD, Solaris and all kind of nix OS, see [COMPILE-NIX.md](COMPILE-NIX.md) -To compile Keystone on Windows, see [COMPILE-WINDOWS.md](COMPILE-WINDOWS.md) +To compile Unicorn on Windows, see [COMPILE-WINDOWS.md](COMPILE-WINDOWS.md) Then learn more on how to code your own tools with our samples. From 38b4e35b2026d2dcb7e02fd68314658aa23ef9eb Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 30 Apr 2016 13:03:39 +0800 Subject: [PATCH 147/149] docs: fix markdown for COMPILE*md --- docs/COMPILE-NIX.md | 72 ++++++++++----------- docs/COMPILE-WINDOWS.md | 134 ++++++++++++++++++++-------------------- 2 files changed, 103 insertions(+), 103 deletions(-) diff --git a/docs/COMPILE-NIX.md b/docs/COMPILE-NIX.md index 811ad8a9..1dd545b9 100644 --- a/docs/COMPILE-NIX.md +++ b/docs/COMPILE-NIX.md @@ -2,8 +2,8 @@ This documentation explains how to compile, install & run Unicorn on MacOSX, Linux, *BSD, Solaris, Android & iOS. To compile for Microsoft Windows, see [COMPILE-WINDOWS.md](COMPILE-WINDOWS.md) +---- - *-*-*-*-*-* [0] Dependencies @@ -23,46 +23,46 @@ Unicorn requires few dependent packages as follows. [1] Tailor Unicorn to your need. - Out of 6 archtitectures supported by Unicorn (Arm, Arm64, M68K, Mips, Sparc, - & X86), if you just need several selected archs, choose which ones you want - to compile in by editing "config.mk" before going to next steps. +Out of 6 archtitectures supported by Unicorn (Arm, Arm64, M68K, Mips, Sparc, +& X86), if you just need several selected archs, choose which ones you want +to compile in by editing "config.mk" before going to next steps. - By default, all 6 architectures are compiled. +By default, all 6 architectures are compiled. - The other way of customize Unicorn without having to edit config.mk is to - pass the desired options on the commandline to ./make.sh. Currently, - Unicorn supports 4 options, as follows. +The other way of customize Unicorn without having to edit config.mk is to +pass the desired options on the commandline to ./make.sh. Currently, +Unicorn supports 4 options, as follows. - UNICORN_ARCHS: specify list of architectures to compiled in. - UNICORN_STATIC: build static library. - UNICORN_SHARED: build dynamic (shared) library. - UNICORN_QEMU_FLAGS: specify extra flags for qemu's configure script - To avoid editing config.mk for these customization, we can pass their values to - make.sh, as follows. +To avoid editing config.mk for these customization, we can pass their values to +make.sh, as follows. $ UNICORN_ARCHS="arm aarch64 x86" ./make.sh - NOTE: on commandline, put these values in front of ./make.sh, not after it. +NOTE: on commandline, put these values in front of ./make.sh, not after it. - For each option, refer to docs/README for more details. +For each option, refer to docs/README for more details. [2] Compile and install from source on *nix - To build Unicorn on *nix (such as MacOSX, Linux, *BSD, Solaris): +To build Unicorn on *nix (such as MacOSX, Linux, *BSD, Solaris): - - To compile for current platform, run: +- To compile for current platform, run: $ ./make.sh - - Unicorn requires Python 2.x to compile. If Python 2.x is not the default +- Unicorn requires Python 2.x to compile. If Python 2.x is not the default Python interpreter, ensure that the appropriate option is set: $ UNICORN_QEMU_FLAGS="--python=/path/to/python2" ./make.sh - - To cross-compile Unicorn on 64-bit OS to target 32-bit binary, run: +- To cross-compile Unicorn on 64-bit OS to target 32-bit binary, run: $ ./make.sh nix32 @@ -98,50 +98,50 @@ Unicorn requires few dependent packages as follows. [3] Cross-compile for iOS from Mac OSX. - To cross-compile for iOS (iPhone/iPad/iPod), Mac OSX with XCode installed is required. +To cross-compile for iOS (iPhone/iPad/iPod), Mac OSX with XCode installed is required. - - To cross-compile for ArmV7 (iPod 4, iPad 1/2/3, iPhone4, iPhone4S), run: +- To cross-compile for ArmV7 (iPod 4, iPad 1/2/3, iPhone4, iPhone4S), run: $ ./make.sh ios_armv7 - - To cross-compile for ArmV7s (iPad 4, iPhone 5C, iPad mini), run: +- To cross-compile for ArmV7s (iPad 4, iPhone 5C, iPad mini), run: $ ./make.sh ios_armv7s - - To cross-compile for Arm64 (iPhone 5S, iPad mini Retina, iPad Air), run: +- To cross-compile for Arm64 (iPhone 5S, iPad mini Retina, iPad Air), run: $ ./make.sh ios_arm64 - - To cross-compile for all iDevices (armv7 + armv7s + arm64), run: +- To cross-compile for all iDevices (armv7 + armv7s + arm64), run: $ ./make.sh ios - Resulted files libunicorn.dylib, libunicorn.a & tests/test* can then - be used on iOS devices. +Resulted files libunicorn.dylib, libunicorn.a & tests/test* can then +be used on iOS devices. [4] Cross-compile for Android - To cross-compile for Android (smartphone/tablet), Android NDK is required. - NOTE: Only ARM and ARM64 are currently supported. +To cross-compile for Android (smartphone/tablet), Android NDK is required. +NOTE: Only ARM and ARM64 are currently supported. $ NDK=/android/android-ndk-r10e ./make.sh cross-android arm - or +or $ NDK=/android/android-ndk-r10e ./make.sh cross-android arm64 - Resulted files libunicorn.so, libunicorn.a & tests/test* can then - be used on Android devices. +Resulted files libunicorn.so, libunicorn.a & tests/test* can then +be used on Android devices. [5] By default, "cc" (default C compiler on the system) is used as compiler. - - To use "clang" compiler instead, run the command below: +- To use "clang" compiler instead, run the command below: $ ./make.sh clang - - To use "gcc" compiler instead, run: +- To use "gcc" compiler instead, run: $ ./make.sh gcc @@ -155,15 +155,15 @@ Unicorn requires few dependent packages as follows. [7] Language bindings - Look for the bindings under directory bindings/, and refer to README file - of corresponding languages. +Look for the bindings under directory bindings/, and refer to README file +of corresponding languages. [8] Unit tests - Automated unit tests use the cmocka unit testing framework (https://cmocka.org/). - It can be installed in most Linux distros using the package manager, e.g. - `sudo yum install libcmocka libcmocka-devel`, or you can easily build and install it from source. +Automated unit tests use the cmocka unit testing framework (https://cmocka.org/). +It can be installed in most Linux distros using the package manager, e.g. +`sudo yum install libcmocka libcmocka-devel`, or you can easily build and install it from source. - You can run the tests by running `make test` in the project directory. +You can run the tests by running `make test` in the project directory. diff --git a/docs/COMPILE-WINDOWS.md b/docs/COMPILE-WINDOWS.md index 0a94687f..c1a036c3 100644 --- a/docs/COMPILE-WINDOWS.md +++ b/docs/COMPILE-WINDOWS.md @@ -1,112 +1,112 @@ We also show steps to cross-compile Unicorn for Microsoft Windows. To compile for *nix OS, see [COMPILE-NIX.md](COMPILE-NIX.md) +--- - *-*-*-*-*-* [0] Dependencies - For Windows, cross-compile requires Mingw. Mingw-glib2 is needed. - At the moment, it is confirmed that Unicorn can be compiled either on Ubuntu - or Windows. +For Windows, cross-compile requires Mingw. Mingw-glib2 is needed. +At the moment, it is confirmed that Unicorn can be compiled either on Ubuntu +or Windows. - - On Ubuntu 14.04 64-bit, do: +- On Ubuntu 14.04 64-bit, do: - 1. Download DEB packages for Mingw64 from: + 1. Download DEB packages for Mingw64 from: - https://launchpad.net/~greg-hellings/+archive/ubuntu/mingw-libs/+build/2924251 + https://launchpad.net/~greg-hellings/+archive/ubuntu/mingw-libs/+build/2924251 - 2. To cross-compile for Windows 32-bit, install Mingw with (ignore all the warnings): + 2. To cross-compile for Windows 32-bit, install Mingw with (ignore all the warnings): $ sudo dpkg -i --force-depends mingw64-x86-glib2_2.31.0_all.deb - To cross-compile for Windows 64-bit, install Mingw with: + To cross-compile for Windows 64-bit, install Mingw with: $ sudo dpkg -i --force-depends mingw64-x64-glib2_2.31.0_all.deb - - On Windows, install MinGW via package MSYS2 at https://msys2.github.io/ +- On Windows, install MinGW via package MSYS2 at https://msys2.github.io/ - Follow the install instructions and don't forget to update the system packages with: + Follow the install instructions and don't forget to update the system packages with: $ pacman --needed -Sy bash pacman pacman-mirrors msys2-runtime - Then close MSYS2, run it again from Start menu and update the rest with: + Then close MSYS2, run it again from Start menu and update the rest with: $ pacman -Su - Finally, install required toolchain to build C projects. + Finally, install required toolchain to build C projects. - - To compile for Windows 32-bit, run: + - To compile for Windows 32-bit, run: - $ pacman -S python2 - $ pacman -S make - $ pacman -S pkg-config - $ pacman -S mingw-w64-i686-glib2 - $ pacman -S mingw-w64-i686-toolchain + $ pacman -S python2 + $ pacman -S make + $ pacman -S pkg-config + $ pacman -S mingw-w64-i686-glib2 + $ pacman -S mingw-w64-i686-toolchain - - To compile for Windows 64-bit, run: + - To compile for Windows 64-bit, run: - $ pacman -S python2 - $ pacman -S make - $ pacman -S pkg-config - $ pacman -S mingw-w64-x86_64-glib2 - $ pacman -S mingw-w64-x86_64-toolchain + $ pacman -S python2 + $ pacman -S make + $ pacman -S pkg-config + $ pacman -S mingw-w64-x86_64-glib2 + $ pacman -S mingw-w64-x86_64-toolchain - For Cygwin, "make", "gcc-core", "pkg-config", "libpcre-devel", "zlib-devel" and "libglib2.0-devel" are needed. If apt-cyg is available, you can install these with: - $ apt-cyg install make gcc-core pkg-config libpcre-devel zlib-devel libglib2.0-devel + $ apt-cyg install make gcc-core pkg-config libpcre-devel zlib-devel libglib2.0-devel [1] Tailor Unicorn to your need. - Out of 6 archtitectures supported by Unicorn (Arm, Arm64, M68K, Mips, Sparc, - & X86), if you just need several selected archs, choose which ones you want - to compile in by editing "config.mk" before going to next steps. +Out of 6 archtitectures supported by Unicorn (Arm, Arm64, M68K, Mips, Sparc, +& X86), if you just need several selected archs, choose which ones you want +to compile in by editing "config.mk" before going to next steps. - By default, all 6 architectures are compiled. +By default, all 6 architectures are compiled. - The other way of customize Unicorn without having to edit config.mk is to - pass the desired options on the commandline to ./make.sh. Currently, - Unicorn supports 4 options, as follows. +The other way of customize Unicorn without having to edit config.mk is to +pass the desired options on the commandline to ./make.sh. Currently, +Unicorn supports 4 options, as follows. - UNICORN_ARCHS: specify list of architectures to compiled in. - UNICORN_STATIC: build static library. - UNICORN_SHARED: build dynamic (shared) library. - UNICORN_QEMU_FLAGS: specify extra flags for qemu's configure script - To avoid editing config.mk for these customization, we can pass their values to - make.sh, as follows. +To avoid editing config.mk for these customization, we can pass their values to +make.sh, as follows. $ UNICORN_ARCHS="arm aarch64 x86" ./make.sh - NOTE: on commandline, put these values in front of ./make.sh, not after it. +NOTE: on commandline, put these values in front of ./make.sh, not after it. - For each option, refer to docs/README for more details. +For each option, refer to docs/README for more details. [2] Compile from source on Windows - with MinGW (MSYS2) - To compile with MinGW, install MSYS2 as instructed in the first section. - Then, build Unicorn with the next steps: +To compile with MinGW, install MSYS2 as instructed in the first section. +Then, build Unicorn with the next steps: - - To compile Windows 32-bit binary with MinGW, run: +- To compile Windows 32-bit binary with MinGW, run: $ ./make.sh cross-win32 - - To compile Windows 64-bit binary with MinGW, run: +- To compile Windows 64-bit binary with MinGW, run: $ ./make.sh cross-win64 - Resulted files unicorn.dll, unicorn.lib & samples/sample*.exe can then - be used on Windows machine. +Resulted files unicorn.dll, unicorn.lib & samples/sample*.exe can then +be used on Windows machine. - To run sample_x86.exe on Windows 32-bit, you need the following files: +To run sample_x86.exe on Windows 32-bit, you need the following files: unicorn.dll %MSYS2%\mingw32\bin\libiconv-2.dll @@ -115,7 +115,7 @@ To compile for *nix OS, see [COMPILE-NIX.md](COMPILE-NIX.md) %MSYS2%\mingw32\bin\libgcc_s_dw2-1.dll %MSYS2%\mingw32\bin\libwinpthread-1.dll - To run sample_x86.exe on Windows 64-bit, you need the following files: +To run sample_x86.exe on Windows 64-bit, you need the following files: unicorn.dll %MSYS2%\mingw64\bin\libiconv-2.dll @@ -128,19 +128,19 @@ To compile for *nix OS, see [COMPILE-NIX.md](COMPILE-NIX.md) [3] Compile and install from source on Cygwin - To build Unicorn on Cygwin, run: +To build Unicorn on Cygwin, run: $ ./make.sh - After compiling, install Unicorn with: +After compiling, install Unicorn with: $ ./make.sh install - Resulted files cygunicorn.dll, libunicorn.dll.a and libunicorn.a can be - used on Cygwin but not native Windows. +Resulted files cygunicorn.dll, libunicorn.dll.a and libunicorn.a can be +used on Cygwin but not native Windows. - NOTE: The core framework installed by "./make.sh install" consist of - following files: +NOTE: The core framework installed by "./make.sh install" consist of +following files: /usr/include/unicorn/*.h /usr/bin/cygunicorn.dll @@ -151,50 +151,50 @@ To compile for *nix OS, see [COMPILE-NIX.md](COMPILE-NIX.md) [4] Cross-compile for Windows from *nix - To cross-compile for Windows, Linux & gcc-mingw-w64-i686 (and also gcc-mingw-w64-x86-64 - for 64-bit binaries) are required. +To cross-compile for Windows, Linux & gcc-mingw-w64-i686 (and also gcc-mingw-w64-x86-64 +for 64-bit binaries) are required. - - To cross-compile Windows 32-bit binary, simply run: +- To cross-compile Windows 32-bit binary, simply run: $ ./make.sh cross-win32 - - To cross-compile Windows 64-bit binary, run: +- To cross-compile Windows 64-bit binary, run: $ ./make.sh cross-win64 - Resulted files unicorn.dll, unicorn.lib & samples/sample*.exe can then - be used on Windows machine. +Resulted files unicorn.dll, unicorn.lib & samples/sample*.exe can then +be used on Windows machine. - To run sample_x86.exe on Windows 32-bit, you need the following files: +To run sample_x86.exe on Windows 32-bit, you need the following files: unicorn.dll /usr/i686-w64-mingw32/sys-root/mingw/bin/libglib-2.0-0.dll /usr/lib/gcc/i686-w64-mingw32/4.8/libgcc_s_sjlj-1.dll /usr/i686-w64-mingw32/lib/libwinpthread-1.dll - To run sample_x86.exe on Windows 64-bit, you need the following files: +To run sample_x86.exe on Windows 64-bit, you need the following files: unicorn.dll /usr/x86_64-w64-mingw32/sys-root/mingw/bin/libglib-2.0-0.dll /usr/lib/gcc/x86_64-w64-mingw32/4.8/libgcc_s_sjlj-1.dll /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll - Then run either "sample_x86.exe -32" or "sample_x86.exe -64" to test emulators for X86 32-bit or X86 64-bit. - For other architectures, run "sample_xxx.exe" found in the same directory. +Then run either "sample_x86.exe -32" or "sample_x86.exe -64" to test emulators for X86 32-bit or X86 64-bit. +For other architectures, run "sample_xxx.exe" found in the same directory. [5] Language bindings - Look for the bindings under directory bindings/, and refer to README file - of corresponding languages. +Look for the bindings under directory bindings/, and refer to README file +of corresponding languages. [6] Unit tests - Automated unit tests use the cmocka unit testing framework (https://cmocka.org/). - It can be installed in most Linux distros using the package manager, e.g. - `sudo yum install libcmocka libcmocka-devel`, or you can easily build and install it from source. +Automated unit tests use the cmocka unit testing framework (https://cmocka.org/). +It can be installed in most Linux distros using the package manager, e.g. +`sudo yum install libcmocka libcmocka-devel`, or you can easily build and install it from source. - You can run the tests by running `make test` in the project directory. +You can run the tests by running `make test` in the project directory. From 822e7625615f886da9163882347a20a8719f4aa2 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 30 Apr 2016 13:05:35 +0800 Subject: [PATCH 148/149] docs: fix markdown for COMPILE*md --- docs/COMPILE-NIX.md | 3 ++- docs/COMPILE-WINDOWS.md | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/COMPILE-NIX.md b/docs/COMPILE-NIX.md index 1dd545b9..06341b19 100644 --- a/docs/COMPILE-NIX.md +++ b/docs/COMPILE-NIX.md @@ -1,7 +1,8 @@ This documentation explains how to compile, install & run Unicorn on MacOSX, -Linux, *BSD, Solaris, Android & iOS. +Linux, BSD, Solaris, Android & iOS. To compile for Microsoft Windows, see [COMPILE-WINDOWS.md](COMPILE-WINDOWS.md) + ---- diff --git a/docs/COMPILE-WINDOWS.md b/docs/COMPILE-WINDOWS.md index c1a036c3..05143f5c 100644 --- a/docs/COMPILE-WINDOWS.md +++ b/docs/COMPILE-WINDOWS.md @@ -1,6 +1,7 @@ We also show steps to cross-compile Unicorn for Microsoft Windows. -To compile for *nix OS, see [COMPILE-NIX.md](COMPILE-NIX.md) +To compile for Linux, Mac OS X and Unix-based OS, see [COMPILE-NIX.md](COMPILE-NIX.md) + --- From ebac94c43153327eba45925632ca61dfd86046c4 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 30 Apr 2016 13:08:40 +0800 Subject: [PATCH 149/149] docs: more markdown fix for COMPILE*md --- docs/COMPILE-WINDOWS.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/COMPILE-WINDOWS.md b/docs/COMPILE-WINDOWS.md index 05143f5c..f8d60f90 100644 --- a/docs/COMPILE-WINDOWS.md +++ b/docs/COMPILE-WINDOWS.md @@ -13,11 +13,11 @@ or Windows. - On Ubuntu 14.04 64-bit, do: - 1. Download DEB packages for Mingw64 from: + - Download DEB packages for Mingw64 from: https://launchpad.net/~greg-hellings/+archive/ubuntu/mingw-libs/+build/2924251 - 2. To cross-compile for Windows 32-bit, install Mingw with (ignore all the warnings): + - To cross-compile for Windows 32-bit, install Mingw with (ignore all the warnings): $ sudo dpkg -i --force-depends mingw64-x86-glib2_2.31.0_all.deb