mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-12-22 19:15:36 +00:00
Merge branch 'memleak' into m2
This commit is contained in:
commit
cc6cbc5cf7
7
.gitignore
vendored
7
.gitignore
vendored
|
@ -152,6 +152,13 @@ mem_fuzz
|
|||
test_x86_soft_paging
|
||||
test_hookcounts
|
||||
|
||||
memleak_x86
|
||||
memleak_arm
|
||||
memleak_arm64
|
||||
memleak_mips
|
||||
memleak_m68k
|
||||
memleak_sparc
|
||||
|
||||
|
||||
#################
|
||||
## Visual Studio
|
||||
|
|
|
@ -199,10 +199,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];
|
||||
|
|
|
@ -2417,7 +2417,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
|
||||
|
@ -2445,7 +2444,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
|
||||
|
|
|
@ -2417,7 +2417,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
|
||||
|
@ -2445,7 +2444,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
|
||||
|
|
23
qemu/cpus.c
23
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);
|
||||
free(cpu->thread);
|
||||
cpu->thread = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -146,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;
|
||||
}
|
||||
|
@ -164,6 +156,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);
|
||||
|
|
|
@ -2423,7 +2423,6 @@ symbols = (
|
|||
'qemu_clock_get_us',
|
||||
'qemu_clock_ptr',
|
||||
'qemu_clocks',
|
||||
'qemu_cond_destroy',
|
||||
'qemu_cpu_is_self',
|
||||
'qemu_cpu_kick_thread',
|
||||
'qemu_daemon',
|
||||
|
@ -2451,7 +2450,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',
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -2417,7 +2417,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
|
||||
|
@ -2445,7 +2444,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
|
||||
|
|
|
@ -90,6 +90,9 @@ static void qemu_cpu_kick_thread(CPUState *cpu)
|
|||
GetLastError());
|
||||
exit(1);
|
||||
}
|
||||
|
||||
CloseHandle(cpu->hThread);
|
||||
cpu->hThread = 0;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -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
|
||||
memmove(&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);
|
||||
|
|
|
@ -2417,7 +2417,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
|
||||
|
@ -2445,7 +2444,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
|
||||
|
|
|
@ -2417,7 +2417,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
|
||||
|
@ -2445,7 +2444,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
|
||||
|
|
|
@ -2417,7 +2417,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
|
||||
|
@ -2445,7 +2444,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
|
||||
|
|
|
@ -2417,7 +2417,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
|
||||
|
@ -2445,7 +2444,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
|
||||
|
|
|
@ -2417,7 +2417,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
|
||||
|
@ -2445,7 +2444,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
|
||||
|
|
|
@ -2417,7 +2417,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
|
||||
|
@ -2445,7 +2444,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
|
||||
|
|
|
@ -2417,7 +2417,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
|
||||
|
@ -2445,7 +2444,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
|
||||
|
|
|
@ -15,6 +15,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;
|
||||
|
@ -101,5 +118,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);
|
||||
}
|
||||
|
|
|
@ -16,6 +16,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;
|
||||
|
@ -137,6 +154,7 @@ 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->query = arm_query;
|
||||
uc_common_init(uc);
|
||||
}
|
||||
|
|
|
@ -21,9 +21,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]);
|
||||
|
@ -35,7 +37,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]);
|
||||
}
|
||||
|
|
|
@ -35,12 +35,17 @@ 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];
|
||||
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;
|
||||
|
@ -55,9 +60,46 @@ 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(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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -115,7 +115,7 @@ int machine_initialize(struct uc_struct *uc)
|
|||
|
||||
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);
|
||||
|
||||
|
|
|
@ -2417,7 +2417,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
|
||||
|
@ -2445,7 +2444,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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
@ -913,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]);
|
||||
}
|
||||
|
|
|
@ -45,6 +45,13 @@ TESTS += 004-segmentation_fault_1
|
|||
TESTS += 005-qemu__fatal__illegal_instruction__0000___00000404
|
||||
TESTS += 006-qemu__fatal__illegal_instruction__0421___00040026
|
||||
|
||||
TESTS += memleak_x86
|
||||
TESTS += memleak_arm
|
||||
TESTS += memleak_arm64
|
||||
TESTS += memleak_mips
|
||||
TESTS += memleak_m68k
|
||||
TESTS += memleak_sparc
|
||||
|
||||
all: $(TESTS)
|
||||
|
||||
clean:
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
178
tests/regress/memleak_arm.c
Normal file
178
tests/regress/memleak_arm.c
Normal file
|
@ -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 <io.h>
|
||||
#include <windows.h>
|
||||
#define PRIx64 "llX"
|
||||
#ifdef DYNLOAD
|
||||
#include "unicorn_dynload.h"
|
||||
#else // DYNLOAD
|
||||
#include <unicorn/unicorn.h>
|
||||
#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 <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <unicorn/unicorn.h>
|
||||
#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;
|
||||
}
|
122
tests/regress/memleak_arm64.c
Normal file
122
tests/regress/memleak_arm64.c
Normal file
|
@ -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 <io.h>
|
||||
#include <windows.h>
|
||||
#define PRIx64 "llX"
|
||||
#ifdef DYNLOAD
|
||||
#include "unicorn_dynload.h"
|
||||
#else // DYNLOAD
|
||||
#include <unicorn/unicorn.h>
|
||||
#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 <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <unicorn/unicorn.h>
|
||||
#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;
|
||||
}
|
185
tests/regress/memleak_m68k.c
Normal file
185
tests/regress/memleak_m68k.c
Normal file
|
@ -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 <io.h>
|
||||
#include <windows.h>
|
||||
#define PRIx64 "llX"
|
||||
#ifdef DYNLOAD
|
||||
#include "unicorn_dynload.h"
|
||||
#else // DYNLOAD
|
||||
#include <unicorn/unicorn.h>
|
||||
#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 <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <unicorn/unicorn.h>
|
||||
#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;
|
||||
}
|
171
tests/regress/memleak_mips.c
Normal file
171
tests/regress/memleak_mips.c
Normal file
|
@ -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 <io.h>
|
||||
#include <windows.h>
|
||||
#define PRIx64 "llX"
|
||||
#ifdef DYNLOAD
|
||||
#include "unicorn_dynload.h"
|
||||
#else // DYNLOAD
|
||||
#include <unicorn/unicorn.h>
|
||||
#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 <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <unicorn/unicorn.h>
|
||||
#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;
|
||||
}
|
125
tests/regress/memleak_sparc.c
Normal file
125
tests/regress/memleak_sparc.c
Normal file
|
@ -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 <io.h>
|
||||
#include <windows.h>
|
||||
#define PRIx64 "llX"
|
||||
#ifdef DYNLOAD
|
||||
#include "unicorn_dynload.h"
|
||||
#else // DYNLOAD
|
||||
#include <unicorn/unicorn.h>
|
||||
#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 <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <unicorn/unicorn.h>
|
||||
#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;
|
||||
}
|
306
tests/regress/memleak_x86.c
Normal file
306
tests/regress/memleak_x86.c
Normal file
|
@ -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 <io.h>
|
||||
#include <windows.h>
|
||||
#define PRIx64 "llX"
|
||||
#ifdef DYNLOAD
|
||||
#include "unicorn_dynload.h"
|
||||
#else // DYNLOAD
|
||||
#include <unicorn/unicorn.h>
|
||||
#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 <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <unicorn/unicorn.h>
|
||||
#endif // _MSC_VER
|
||||
|
||||
// common includes
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// 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;
|
||||
}
|
|
@ -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");
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
6
uc.c
6
uc.c
|
@ -285,9 +285,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);
|
||||
|
@ -295,8 +293,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++) {
|
||||
|
@ -586,7 +582,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;
|
||||
|
|
Loading…
Reference in a new issue