From 036763d6aec6a725930989090f47049471d173fa Mon Sep 17 00:00:00 2001 From: farmdve Date: Fri, 8 Jan 2016 01:41:45 +0200 Subject: [PATCH 01/11] 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 02/11] 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 03/11] 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 04/11] 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 05/11] 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 06/11] 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 07/11] 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 08/11] 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 09/11] 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 10/11] 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 11/11] 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);