fix merge conflict
This commit is contained in:
498
uc.c
498
uc.c
@ -20,7 +20,6 @@
|
||||
#endif
|
||||
|
||||
#include "uc_priv.h"
|
||||
#include "hook.h"
|
||||
|
||||
// target specific headers
|
||||
#include "qemu/target-m68k/unicorn.h"
|
||||
@ -95,8 +94,6 @@ const char *uc_strerror(uc_err code)
|
||||
return "Write to unaligned memory (UC_ERR_WRITE_UNALIGNED)";
|
||||
case UC_ERR_FETCH_UNALIGNED:
|
||||
return "Fetch from unaligned memory (UC_ERR_FETCH_UNALIGNED)";
|
||||
case UC_ERR_HOOK_EXIST:
|
||||
return "Hook for this type event already exists (UC_ERR_HOOK_EXIST)";
|
||||
case UC_ERR_RESOURCE:
|
||||
return "Insufficient resource (UC_ERR_RESOURCE)";
|
||||
}
|
||||
@ -171,36 +168,56 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
|
||||
break;
|
||||
#ifdef UNICORN_HAS_M68K
|
||||
case UC_ARCH_M68K:
|
||||
if ((mode & ~UC_MODE_M68K_MASK) ||
|
||||
!(mode & UC_MODE_BIG_ENDIAN)) {
|
||||
free(uc);
|
||||
return UC_ERR_MODE;
|
||||
}
|
||||
uc->init_arch = m68k_uc_init;
|
||||
break;
|
||||
#endif
|
||||
#ifdef UNICORN_HAS_X86
|
||||
case UC_ARCH_X86:
|
||||
if ((mode & ~UC_MODE_X86_MASK) ||
|
||||
(mode & UC_MODE_BIG_ENDIAN) ||
|
||||
!(mode & (UC_MODE_16|UC_MODE_32|UC_MODE_64))) {
|
||||
free(uc);
|
||||
return UC_ERR_MODE;
|
||||
}
|
||||
uc->init_arch = x86_uc_init;
|
||||
break;
|
||||
#endif
|
||||
#ifdef UNICORN_HAS_ARM
|
||||
case UC_ARCH_ARM:
|
||||
uc->init_arch = arm_uc_init;
|
||||
|
||||
// verify mode
|
||||
if (mode != UC_MODE_ARM && mode != UC_MODE_THUMB) {
|
||||
if ((mode & ~UC_MODE_ARM_MASK) ||
|
||||
(mode & UC_MODE_BIG_ENDIAN)) {
|
||||
free(uc);
|
||||
return UC_ERR_MODE;
|
||||
}
|
||||
uc->init_arch = arm_uc_init;
|
||||
|
||||
if (mode == UC_MODE_THUMB)
|
||||
if (mode & UC_MODE_THUMB)
|
||||
uc->thumb = 1;
|
||||
break;
|
||||
#endif
|
||||
#ifdef UNICORN_HAS_ARM64
|
||||
case UC_ARCH_ARM64:
|
||||
if ((mode & ~UC_MODE_ARM_MASK) ||
|
||||
(mode & UC_MODE_BIG_ENDIAN)) {
|
||||
free(uc);
|
||||
return UC_ERR_MODE;
|
||||
}
|
||||
uc->init_arch = arm64_uc_init;
|
||||
break;
|
||||
#endif
|
||||
|
||||
#if defined(UNICORN_HAS_MIPS) || defined(UNICORN_HAS_MIPSEL) || defined(UNICORN_HAS_MIPS64) || defined(UNICORN_HAS_MIPS64EL)
|
||||
case UC_ARCH_MIPS:
|
||||
if ((mode & ~UC_MODE_MIPS_MASK) ||
|
||||
!(mode & (UC_MODE_MIPS32|UC_MODE_MIPS64))) {
|
||||
free(uc);
|
||||
return UC_ERR_MODE;
|
||||
}
|
||||
if (mode & UC_MODE_BIG_ENDIAN) {
|
||||
#ifdef UNICORN_HAS_MIPS
|
||||
if (mode & UC_MODE_MIPS32)
|
||||
@ -225,7 +242,13 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
|
||||
|
||||
#ifdef UNICORN_HAS_SPARC
|
||||
case UC_ARCH_SPARC:
|
||||
if (mode & UC_MODE_64)
|
||||
if ((mode & ~UC_MODE_SPARC_MASK) ||
|
||||
!(mode & UC_MODE_BIG_ENDIAN) ||
|
||||
!(mode & (UC_MODE_SPARC32|UC_MODE_SPARC64))) {
|
||||
free(uc);
|
||||
return UC_ERR_MODE;
|
||||
}
|
||||
if (mode & UC_MODE_SPARC64)
|
||||
uc->init_arch = sparc64_uc_init;
|
||||
else
|
||||
uc->init_arch = sparc_uc_init;
|
||||
@ -245,9 +268,6 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
|
||||
if (uc->reg_reset)
|
||||
uc->reg_reset(uc);
|
||||
|
||||
uc->hook_size = HOOK_SIZE;
|
||||
uc->hook_callbacks = calloc(1, sizeof(uc->hook_callbacks[0]) * HOOK_SIZE);
|
||||
|
||||
return UC_ERR_OK;
|
||||
} else {
|
||||
return UC_ERR_ARCH;
|
||||
@ -259,6 +279,8 @@ UNICORN_EXPORT
|
||||
uc_err uc_close(uc_engine *uc)
|
||||
{
|
||||
int i;
|
||||
struct list_item *cur;
|
||||
struct hook *hook;
|
||||
|
||||
if (uc->release)
|
||||
uc->release(uc->tcg_ctx);
|
||||
@ -277,7 +299,23 @@ uc_err uc_close(uc_engine *uc)
|
||||
free(uc->ram_list.dirty_memory[i]);
|
||||
}
|
||||
|
||||
free(uc->hook_callbacks);
|
||||
// TODO: remove uc->root (created with object_new())
|
||||
uc->root->free(uc->root);
|
||||
|
||||
// free hooks and hook lists
|
||||
for (i = 0; i < UC_HOOK_MAX; i++) {
|
||||
cur = uc->hook[i].head;
|
||||
// hook can be in more than one list
|
||||
// so we refcount to know when to free
|
||||
while (cur) {
|
||||
hook = (struct hook *)cur->data;
|
||||
if (--hook->refs == 0) {
|
||||
free(hook);
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
list_clear(&uc->hook[i]);
|
||||
}
|
||||
|
||||
free(uc->mapped_blocks);
|
||||
|
||||
@ -438,12 +476,20 @@ static void enable_emu_timer(uc_engine *uc, uint64_t timeout)
|
||||
uc, QEMU_THREAD_JOINABLE);
|
||||
}
|
||||
|
||||
static void hook_count_cb(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data)
|
||||
{
|
||||
// count this instruction. ah ah ah.
|
||||
uc->emu_counter++;
|
||||
|
||||
if (uc->emu_counter > uc->emu_count)
|
||||
uc_emu_stop(uc);
|
||||
}
|
||||
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count)
|
||||
{
|
||||
// reset the counter
|
||||
uc->emu_counter = 0;
|
||||
uc->stop_request = false;
|
||||
uc->invalid_error = UC_ERR_OK;
|
||||
uc->block_full = false;
|
||||
uc->emulation_done = false;
|
||||
@ -473,14 +519,7 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time
|
||||
break;
|
||||
|
||||
case UC_ARCH_ARM:
|
||||
switch(uc->mode) {
|
||||
default:
|
||||
break;
|
||||
case UC_MODE_THUMB:
|
||||
case UC_MODE_ARM:
|
||||
uc_reg_write(uc, UC_ARM_REG_R15, &begin);
|
||||
break;
|
||||
}
|
||||
uc_reg_write(uc, UC_ARM_REG_R15, &begin);
|
||||
break;
|
||||
|
||||
case UC_ARCH_ARM64:
|
||||
@ -498,9 +537,20 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time
|
||||
break;
|
||||
}
|
||||
|
||||
uc->stop_request = false;
|
||||
|
||||
uc->emu_count = count;
|
||||
if (count > 0) {
|
||||
uc->hook_insn = true;
|
||||
// remove count hook if counting isn't necessary
|
||||
if (count <= 0 && uc->count_hook != 0) {
|
||||
uc_hook_del(uc, uc->count_hook);
|
||||
uc->count_hook = 0;
|
||||
}
|
||||
// set up count hook to count instructions.
|
||||
if (count > 0 && uc->count_hook == 0) {
|
||||
uc_err err = uc_hook_add(uc, &uc->count_hook, UC_HOOK_CODE, hook_count_cb, NULL);
|
||||
if (err != UC_ERR_OK) {
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
uc->addr_end = until;
|
||||
@ -539,37 +589,6 @@ uc_err uc_emu_stop(uc_engine *uc)
|
||||
return UC_ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
static int _hook_code(uc_engine *uc, int type, uint64_t begin, uint64_t end,
|
||||
void *callback, void *user_data, uc_hook *hh)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = hook_add(uc, type, begin, end, callback, user_data);
|
||||
if (i == 0)
|
||||
return UC_ERR_NOMEM;
|
||||
|
||||
*hh = i;
|
||||
|
||||
return UC_ERR_OK;
|
||||
}
|
||||
|
||||
|
||||
static uc_err _hook_mem_access(uc_engine *uc, uc_hook_type type,
|
||||
uint64_t begin, uint64_t end,
|
||||
void *callback, void *user_data, uc_hook *hh)
|
||||
{
|
||||
int i;
|
||||
|
||||
i = hook_add(uc, type, begin, end, callback, user_data);
|
||||
if (i == 0)
|
||||
return UC_ERR_NOMEM;
|
||||
|
||||
*hh = i;
|
||||
|
||||
return UC_ERR_OK;
|
||||
}
|
||||
|
||||
// find if a memory range overlaps with existing mapped regions
|
||||
static bool memory_overlap(struct uc_struct *uc, uint64_t begin, size_t size)
|
||||
{
|
||||
@ -599,26 +618,6 @@ static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t per
|
||||
{
|
||||
MemoryRegion **regions;
|
||||
|
||||
if (size == 0)
|
||||
// invalid memory mapping
|
||||
return UC_ERR_ARG;
|
||||
|
||||
// address cannot wrapp around
|
||||
if (address + size - 1 < address)
|
||||
return UC_ERR_ARG;
|
||||
|
||||
// address must be aligned to uc->target_page_size
|
||||
if ((address & uc->target_page_align) != 0)
|
||||
return UC_ERR_ARG;
|
||||
|
||||
// size must be multiple of uc->target_page_size
|
||||
if ((size & uc->target_page_align) != 0)
|
||||
return UC_ERR_ARG;
|
||||
|
||||
// check for only valid permissions
|
||||
if ((perms & ~UC_PROT_ALL) != 0)
|
||||
return UC_ERR_ARG;
|
||||
|
||||
// this area overlaps existing mapped regions?
|
||||
if (memory_overlap(uc, address, size))
|
||||
return UC_ERR_MAP;
|
||||
@ -641,19 +640,52 @@ static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t per
|
||||
return UC_ERR_OK;
|
||||
}
|
||||
|
||||
static uc_err mem_map_check(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
|
||||
{
|
||||
if (size == 0)
|
||||
// invalid memory mapping
|
||||
return UC_ERR_ARG;
|
||||
|
||||
// address cannot wrapp around
|
||||
if (address + size - 1 < address)
|
||||
return UC_ERR_ARG;
|
||||
|
||||
// address must be aligned to uc->target_page_size
|
||||
if ((address & uc->target_page_align) != 0)
|
||||
return UC_ERR_ARG;
|
||||
|
||||
// size must be multiple of uc->target_page_size
|
||||
if ((size & uc->target_page_align) != 0)
|
||||
return UC_ERR_ARG;
|
||||
|
||||
// check for only valid permissions
|
||||
if ((perms & ~UC_PROT_ALL) != 0)
|
||||
return UC_ERR_ARG;
|
||||
|
||||
return UC_ERR_OK;
|
||||
}
|
||||
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
|
||||
{
|
||||
uc_err res;
|
||||
|
||||
if (uc->mem_redirect) {
|
||||
address = uc->mem_redirect(address);
|
||||
}
|
||||
|
||||
res = mem_map_check(uc, address, size, perms);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
return mem_map(uc, address, size, perms, uc->memory_map(uc, address, size, perms));
|
||||
}
|
||||
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr)
|
||||
{
|
||||
uc_err res;
|
||||
|
||||
if (ptr == NULL)
|
||||
return UC_ERR_ARG;
|
||||
|
||||
@ -661,6 +693,10 @@ uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t per
|
||||
address = uc->mem_redirect(address);
|
||||
}
|
||||
|
||||
res = mem_map_check(uc, address, size, perms);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
return mem_map(uc, address, size, UC_PROT_ALL, uc->memory_map_ptr(uc, address, size, perms, ptr));
|
||||
}
|
||||
|
||||
@ -787,6 +823,7 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, uint3
|
||||
MemoryRegion *mr;
|
||||
uint64_t addr = address;
|
||||
size_t count, len;
|
||||
bool remove_exec = false;
|
||||
|
||||
if (size == 0)
|
||||
// trivial case, no change
|
||||
@ -823,12 +860,22 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, uint3
|
||||
return UC_ERR_NOMEM;
|
||||
|
||||
mr = memory_mapping(uc, addr);
|
||||
// will this remove EXEC permission?
|
||||
if (((mr->perms & UC_PROT_EXEC) != 0) && ((perms & UC_PROT_EXEC) == 0))
|
||||
remove_exec = true;
|
||||
mr->perms = perms;
|
||||
uc->readonly_mem(mr, (perms & UC_PROT_WRITE) == 0);
|
||||
|
||||
count += len;
|
||||
addr += len;
|
||||
}
|
||||
|
||||
// if EXEC permission is removed, then quit TB and continue at the same place
|
||||
if (remove_exec) {
|
||||
uc->quit_request = true;
|
||||
uc_emu_stop(uc);
|
||||
}
|
||||
|
||||
return UC_ERR_OK;
|
||||
}
|
||||
|
||||
@ -911,206 +958,141 @@ MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static uc_err _hook_mem_invalid(struct uc_struct* uc, int type, uc_cb_eventmem_t callback,
|
||||
void *user_data, uc_hook *evh)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
// only one event handler at the same time
|
||||
if ((type & UC_HOOK_MEM_READ_UNMAPPED) != 0 && (uc->hook_mem_read_idx != 0))
|
||||
return UC_ERR_HOOK_EXIST;
|
||||
|
||||
if ((type & UC_HOOK_MEM_READ_PROT) != 0 && (uc->hook_mem_read_prot_idx != 0))
|
||||
return UC_ERR_HOOK_EXIST;
|
||||
|
||||
if ((type & UC_HOOK_MEM_WRITE_UNMAPPED) != 0 && (uc->hook_mem_write_idx != 0))
|
||||
return UC_ERR_HOOK_EXIST;
|
||||
|
||||
if ((type & UC_HOOK_MEM_WRITE_PROT) != 0 && (uc->hook_mem_write_prot_idx != 0))
|
||||
return UC_ERR_HOOK_EXIST;
|
||||
|
||||
if ((type & UC_HOOK_MEM_FETCH_UNMAPPED) != 0 && (uc->hook_mem_fetch_idx != 0))
|
||||
return UC_ERR_HOOK_EXIST;
|
||||
|
||||
if ((type & UC_HOOK_MEM_FETCH_PROT) != 0 && (uc->hook_mem_fetch_prot_idx != 0))
|
||||
return UC_ERR_HOOK_EXIST;
|
||||
|
||||
i = hook_find_new(uc);
|
||||
if (i) {
|
||||
uc->hook_callbacks[i].callback = callback;
|
||||
uc->hook_callbacks[i].user_data = user_data;
|
||||
*evh = i;
|
||||
if (type & UC_HOOK_MEM_READ_UNMAPPED)
|
||||
uc->hook_mem_read_idx = i;
|
||||
if (type & UC_HOOK_MEM_READ_PROT)
|
||||
uc->hook_mem_read_prot_idx = i;
|
||||
if (type & UC_HOOK_MEM_WRITE_UNMAPPED)
|
||||
uc->hook_mem_write_idx = i;
|
||||
if (type & UC_HOOK_MEM_WRITE_PROT)
|
||||
uc->hook_mem_write_prot_idx = i;
|
||||
if (type & UC_HOOK_MEM_FETCH_UNMAPPED)
|
||||
uc->hook_mem_fetch_idx = i;
|
||||
if (type & UC_HOOK_MEM_FETCH_PROT)
|
||||
uc->hook_mem_fetch_prot_idx = i;
|
||||
return UC_ERR_OK;
|
||||
} else
|
||||
return UC_ERR_NOMEM;
|
||||
}
|
||||
|
||||
|
||||
static uc_err _hook_intr(struct uc_struct* uc, void *callback,
|
||||
void *user_data, uc_hook *evh)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
// only one event handler at the same time
|
||||
if (uc->hook_intr_idx)
|
||||
return UC_ERR_HOOK_EXIST;
|
||||
|
||||
i = hook_find_new(uc);
|
||||
if (i) {
|
||||
uc->hook_callbacks[i].callback = callback;
|
||||
uc->hook_callbacks[i].user_data = user_data;
|
||||
*evh = i;
|
||||
uc->hook_intr_idx = i;
|
||||
return UC_ERR_OK;
|
||||
} else
|
||||
return UC_ERR_NOMEM;
|
||||
}
|
||||
|
||||
|
||||
static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callback,
|
||||
void *user_data, uc_hook *evh)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
switch(uc->arch) {
|
||||
default: break;
|
||||
case UC_ARCH_X86:
|
||||
switch(insn_id) {
|
||||
default: break;
|
||||
case UC_X86_INS_OUT:
|
||||
// only one event handler at the same time
|
||||
if (uc->hook_out_idx)
|
||||
return UC_ERR_HOOK_EXIST;
|
||||
|
||||
i = hook_find_new(uc);
|
||||
if (i) {
|
||||
uc->hook_callbacks[i].callback = callback;
|
||||
uc->hook_callbacks[i].user_data = user_data;
|
||||
*evh = i;
|
||||
uc->hook_out_idx = i;
|
||||
return UC_ERR_OK;
|
||||
} else
|
||||
return UC_ERR_NOMEM;
|
||||
case UC_X86_INS_IN:
|
||||
// only one event handler at the same time
|
||||
if (uc->hook_in_idx)
|
||||
return UC_ERR_HOOK_EXIST;
|
||||
|
||||
i = hook_find_new(uc);
|
||||
if (i) {
|
||||
uc->hook_callbacks[i].callback = callback;
|
||||
uc->hook_callbacks[i].user_data = user_data;
|
||||
*evh = i;
|
||||
uc->hook_in_idx = i;
|
||||
return UC_ERR_OK;
|
||||
} else
|
||||
return UC_ERR_NOMEM;
|
||||
case UC_X86_INS_SYSCALL:
|
||||
case UC_X86_INS_SYSENTER:
|
||||
// only one event handler at the same time
|
||||
if (uc->hook_syscall_idx)
|
||||
return UC_ERR_HOOK_EXIST;
|
||||
|
||||
i = hook_find_new(uc);
|
||||
if (i) {
|
||||
uc->hook_callbacks[i].callback = callback;
|
||||
uc->hook_callbacks[i].user_data = user_data;
|
||||
*evh = i;
|
||||
uc->hook_syscall_idx = i;
|
||||
return UC_ERR_OK;
|
||||
} else
|
||||
return UC_ERR_NOMEM;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return UC_ERR_OK;
|
||||
}
|
||||
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...)
|
||||
{
|
||||
va_list valist;
|
||||
int ret = UC_ERR_OK;
|
||||
int id;
|
||||
uint64_t begin, end;
|
||||
|
||||
va_start(valist, user_data);
|
||||
|
||||
if (type & UC_HOOK_MEM_READ_UNMAPPED)
|
||||
ret = _hook_mem_invalid(uc, UC_HOOK_MEM_READ_UNMAPPED, callback, user_data, hh);
|
||||
struct hook *hook = calloc(1, sizeof(struct hook));
|
||||
if (hook == NULL) {
|
||||
return UC_ERR_NOMEM;
|
||||
}
|
||||
hook->type = type;
|
||||
hook->callback = callback;
|
||||
hook->user_data = user_data;
|
||||
hook->refs = 0;
|
||||
*hh = (uc_hook)hook;
|
||||
|
||||
if (type & UC_HOOK_MEM_WRITE_UNMAPPED)
|
||||
ret = _hook_mem_invalid(uc, UC_HOOK_MEM_WRITE_UNMAPPED, callback, user_data, hh);
|
||||
|
||||
if (type & UC_HOOK_MEM_FETCH_UNMAPPED)
|
||||
ret = _hook_mem_invalid(uc, UC_HOOK_MEM_FETCH_UNMAPPED, callback, user_data, hh);
|
||||
|
||||
if (type & UC_HOOK_MEM_READ_PROT)
|
||||
ret = _hook_mem_invalid(uc, UC_HOOK_MEM_READ_PROT, callback, user_data, hh);
|
||||
|
||||
if (type & UC_HOOK_MEM_WRITE_PROT)
|
||||
ret = _hook_mem_invalid(uc, UC_HOOK_MEM_WRITE_PROT, callback, user_data, hh);
|
||||
|
||||
if (type & UC_HOOK_MEM_FETCH_PROT)
|
||||
ret = _hook_mem_invalid(uc, UC_HOOK_MEM_FETCH_PROT, callback, user_data, hh);
|
||||
|
||||
switch(type) {
|
||||
default:
|
||||
break;
|
||||
case UC_HOOK_INTR:
|
||||
ret = _hook_intr(uc, callback, user_data, hh);
|
||||
break;
|
||||
case UC_HOOK_INSN:
|
||||
id = va_arg(valist, int);
|
||||
ret = _hook_insn(uc, id, callback, user_data, hh);
|
||||
break;
|
||||
case UC_HOOK_CODE:
|
||||
begin = va_arg(valist, uint64_t);
|
||||
end = va_arg(valist, uint64_t);
|
||||
ret = _hook_code(uc, UC_HOOK_CODE, begin, end, callback, user_data, hh);
|
||||
break;
|
||||
case UC_HOOK_BLOCK:
|
||||
begin = va_arg(valist, uint64_t);
|
||||
end = va_arg(valist, uint64_t);
|
||||
ret = _hook_code(uc, UC_HOOK_BLOCK, begin, end, callback, user_data, hh);
|
||||
break;
|
||||
case UC_HOOK_MEM_READ:
|
||||
begin = va_arg(valist, uint64_t);
|
||||
end = va_arg(valist, uint64_t);
|
||||
ret = _hook_mem_access(uc, UC_HOOK_MEM_READ, begin, end, callback, user_data, hh);
|
||||
break;
|
||||
case UC_HOOK_MEM_WRITE:
|
||||
begin = va_arg(valist, uint64_t);
|
||||
end = va_arg(valist, uint64_t);
|
||||
ret = _hook_mem_access(uc, UC_HOOK_MEM_WRITE, begin, end, callback, user_data, hh);
|
||||
break;
|
||||
case UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE:
|
||||
begin = va_arg(valist, uint64_t);
|
||||
end = va_arg(valist, uint64_t);
|
||||
ret = _hook_mem_access(uc, UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, begin, end, callback, user_data, hh);
|
||||
break;
|
||||
// everybody but HOOK_INSN gets begin/end, so exit early here.
|
||||
if (type & UC_HOOK_INSN) {
|
||||
hook->insn = va_arg(valist, int);
|
||||
hook->begin = 1;
|
||||
hook->end = 0;
|
||||
if (list_append(&uc->hook[UC_HOOK_INSN_IDX], hook) == NULL) {
|
||||
free(hook);
|
||||
return UC_ERR_NOMEM;
|
||||
}
|
||||
hook->refs++;
|
||||
return UC_ERR_OK;
|
||||
}
|
||||
|
||||
hook->begin = va_arg(valist, uint64_t);
|
||||
hook->end = va_arg(valist, uint64_t);
|
||||
va_end(valist);
|
||||
|
||||
int i = 0;
|
||||
while ((type >> i) > 0) {
|
||||
if ((type >> i) & 1) {
|
||||
// TODO: invalid hook error?
|
||||
if (i < UC_HOOK_MAX) {
|
||||
if (list_append(&uc->hook[i], hook) == NULL) {
|
||||
if (hook->refs == 0) {
|
||||
free(hook);
|
||||
}
|
||||
return UC_ERR_NOMEM;
|
||||
}
|
||||
hook->refs++;
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// we didn't use the hook
|
||||
// TODO: return an error?
|
||||
if (hook->refs == 0) {
|
||||
free(hook);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_hook_del(uc_engine *uc, uc_hook hh)
|
||||
{
|
||||
return hook_del(uc, hh);
|
||||
int i;
|
||||
struct hook *hook;
|
||||
for (i = 0; i < UC_HOOK_MAX; i++) {
|
||||
if (list_remove(&uc->hook[i], (void *)hh)) {
|
||||
hook = (struct hook *)hh;
|
||||
if (--hook->refs == 0) {
|
||||
free(hook);
|
||||
}
|
||||
}
|
||||
}
|
||||
return UC_ERR_OK;
|
||||
}
|
||||
|
||||
// TCG helper
|
||||
void helper_uc_tracecode(int32_t size, uc_hook_type type, void *handle, int64_t address);
|
||||
void helper_uc_tracecode(int32_t size, uc_hook_type type, void *handle, int64_t address)
|
||||
{
|
||||
struct uc_struct *uc = handle;
|
||||
struct list_item *cur = uc->hook[type].head;
|
||||
struct hook *hook;
|
||||
|
||||
// sync PC in CPUArchState with address
|
||||
if (uc->set_pc) {
|
||||
uc->set_pc(uc, address);
|
||||
}
|
||||
|
||||
while (cur != NULL && !uc->stop_request) {
|
||||
hook = (struct hook *)cur->data;
|
||||
if (HOOK_BOUND_CHECK(hook, address)) {
|
||||
((uc_cb_hookcode_t)hook->callback)(uc, address, size, hook->user_data);
|
||||
}
|
||||
cur = cur->next;
|
||||
}
|
||||
}
|
||||
|
||||
UNICORN_EXPORT
|
||||
uint32_t uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count)
|
||||
{
|
||||
uint32_t i;
|
||||
uc_mem_region *r = NULL;
|
||||
|
||||
*count = uc->mapped_block_count;
|
||||
|
||||
if (*count) {
|
||||
r = malloc(*count * sizeof(uc_mem_region));
|
||||
if (r == NULL) {
|
||||
// out of memory
|
||||
return UC_ERR_NOMEM;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < *count; i++) {
|
||||
r[i].begin = uc->mapped_blocks[i]->addr;
|
||||
r[i].end = uc->mapped_blocks[i]->end - 1;
|
||||
r[i].perms = uc->mapped_blocks[i]->perms;
|
||||
}
|
||||
|
||||
*regions = r;
|
||||
|
||||
return UC_ERR_OK;
|
||||
}
|
||||
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result)
|
||||
{
|
||||
switch(uc->arch) {
|
||||
case UC_ARCH_ARM:
|
||||
return uc->query(uc, type, result);
|
||||
default:
|
||||
return UC_ERR_ARG;
|
||||
}
|
||||
|
||||
return UC_ERR_OK;
|
||||
}
|
||||
|
Reference in New Issue
Block a user