Merge pull request #1474 from unicorn-engine/clangfmt
Import clang-format
This commit is contained in:
commit
1856e940e4
|
@ -0,0 +1,16 @@
|
||||||
|
BasedOnStyle: LLVM
|
||||||
|
IndentWidth: 4
|
||||||
|
UseTab: Never
|
||||||
|
BreakBeforeBraces: Linux
|
||||||
|
AllowShortIfStatementsOnASingleLine: Never
|
||||||
|
AllowShortCaseLabelsOnASingleLine: false
|
||||||
|
AllowShortBlocksOnASingleLine: Empty
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
AllowShortLoopsOnASingleLine: false
|
||||||
|
IndentCaseLabels: false
|
||||||
|
ColumnLimit: 80
|
||||||
|
SortIncludes: false
|
||||||
|
AllowShortLambdasOnASingleLine: Inline
|
||||||
|
AlwaysBreakBeforeMultilineStrings: false
|
||||||
|
BreakStringLiterals: true
|
||||||
|
PointerAlignment: Right
|
|
@ -0,0 +1,8 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
find . -maxdepth 1 "(" -name "*.c" -or -name "*.h" ")" -exec clang-format -i -style=file "{}" ";"
|
||||||
|
find ./msvc -maxdepth 1 "(" -name "*.c" -or -name "*.h" ")" -exec clang-format -i -style=file "{}" ";"
|
||||||
|
find ./include -maxdepth 2 "(" -name "*.c" -or -name "*.h" ")" -exec clang-format -i -style=file "{}" ";"
|
||||||
|
find ./tests/unit -maxdepth 1 "(" -name "*.c" -or -name "*.h" ")" -exec clang-format -i -style=file "{}" ";"
|
||||||
|
find ./samples -maxdepth 1 "(" -name "*.c" -or -name "*.h" ")" -exec clang-format -i -style=file "{}" ";"
|
||||||
|
find ./qemu "(" -name "unicorn.c" -or -name "unicorn.h" ")" -exec clang-format -i -style=file "{}" ";"
|
|
@ -2,7 +2,6 @@
|
||||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
||||||
/* Modified for Unicorn Engine by Chen Huitao<chenhuitao@hfmrit.com>, 2020 */
|
/* Modified for Unicorn Engine by Chen Huitao<chenhuitao@hfmrit.com>, 2020 */
|
||||||
|
|
||||||
|
|
||||||
#ifndef UC_PRIV_H
|
#ifndef UC_PRIV_H
|
||||||
#define UC_PRIV_H
|
#define UC_PRIV_H
|
||||||
|
|
||||||
|
@ -15,16 +14,22 @@
|
||||||
|
|
||||||
// These are masks of supported modes for each cpu/arch.
|
// These are masks of supported modes for each cpu/arch.
|
||||||
// They should be updated when changes are made to the uc_mode enum typedef.
|
// They should be updated when changes are made to the uc_mode enum typedef.
|
||||||
#define UC_MODE_ARM_MASK (UC_MODE_ARM|UC_MODE_THUMB|UC_MODE_LITTLE_ENDIAN|UC_MODE_MCLASS \
|
#define UC_MODE_ARM_MASK \
|
||||||
|UC_MODE_ARM926|UC_MODE_ARM946|UC_MODE_ARM1176|UC_MODE_BIG_ENDIAN)
|
(UC_MODE_ARM | UC_MODE_THUMB | UC_MODE_LITTLE_ENDIAN | UC_MODE_MCLASS | \
|
||||||
#define UC_MODE_MIPS_MASK (UC_MODE_MIPS32|UC_MODE_MIPS64|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN)
|
UC_MODE_ARM926 | UC_MODE_ARM946 | UC_MODE_ARM1176 | UC_MODE_BIG_ENDIAN)
|
||||||
#define UC_MODE_X86_MASK (UC_MODE_16|UC_MODE_32|UC_MODE_64|UC_MODE_LITTLE_ENDIAN)
|
#define UC_MODE_MIPS_MASK \
|
||||||
#define UC_MODE_PPC_MASK (UC_MODE_PPC32|UC_MODE_PPC64|UC_MODE_BIG_ENDIAN)
|
(UC_MODE_MIPS32 | UC_MODE_MIPS64 | UC_MODE_LITTLE_ENDIAN | \
|
||||||
#define UC_MODE_SPARC_MASK (UC_MODE_SPARC32|UC_MODE_SPARC64|UC_MODE_BIG_ENDIAN)
|
UC_MODE_BIG_ENDIAN)
|
||||||
|
#define UC_MODE_X86_MASK \
|
||||||
|
(UC_MODE_16 | UC_MODE_32 | UC_MODE_64 | UC_MODE_LITTLE_ENDIAN)
|
||||||
|
#define UC_MODE_PPC_MASK (UC_MODE_PPC32 | UC_MODE_PPC64 | UC_MODE_BIG_ENDIAN)
|
||||||
|
#define UC_MODE_SPARC_MASK \
|
||||||
|
(UC_MODE_SPARC32 | UC_MODE_SPARC64 | UC_MODE_BIG_ENDIAN)
|
||||||
#define UC_MODE_M68K_MASK (UC_MODE_BIG_ENDIAN)
|
#define UC_MODE_M68K_MASK (UC_MODE_BIG_ENDIAN)
|
||||||
#define UC_MODE_RISCV_MASK (UC_MODE_RISCV32|UC_MODE_RISCV64|UC_MODE_LITTLE_ENDIAN)
|
#define UC_MODE_RISCV_MASK \
|
||||||
|
(UC_MODE_RISCV32 | UC_MODE_RISCV64 | UC_MODE_LITTLE_ENDIAN)
|
||||||
|
|
||||||
#define ARR_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
#define ARR_SIZE(a) (sizeof(a) / sizeof(a[0]))
|
||||||
|
|
||||||
#define READ_QWORD(x) ((uint64_t)x)
|
#define READ_QWORD(x) ((uint64_t)x)
|
||||||
#define READ_DWORD(x) (x & 0xffffffff)
|
#define READ_DWORD(x) (x & 0xffffffff)
|
||||||
|
@ -36,15 +41,19 @@
|
||||||
#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8))
|
#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8))
|
||||||
#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff))
|
#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff))
|
||||||
|
|
||||||
|
typedef uc_err (*query_t)(struct uc_struct *uc, uc_query_type type,
|
||||||
typedef uc_err (*query_t)(struct uc_struct *uc, uc_query_type type, size_t *result);
|
size_t *result);
|
||||||
|
|
||||||
// return 0 on success, -1 on failure
|
// return 0 on success, -1 on failure
|
||||||
typedef int (*reg_read_t)(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
typedef int (*reg_read_t)(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||||
typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
int count);
|
||||||
|
typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int *regs,
|
||||||
|
void *const *vals, int count);
|
||||||
|
|
||||||
typedef int (*context_reg_read_t)(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
typedef int (*context_reg_read_t)(struct uc_context *ctx, unsigned int *regs,
|
||||||
typedef int (*context_reg_write_t)(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
void **vals, int count);
|
||||||
|
typedef int (*context_reg_write_t)(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count);
|
||||||
typedef struct {
|
typedef struct {
|
||||||
context_reg_read_t context_reg_read;
|
context_reg_read_t context_reg_read;
|
||||||
context_reg_write_t context_reg_write;
|
context_reg_write_t context_reg_write;
|
||||||
|
@ -52,30 +61,40 @@ typedef struct {
|
||||||
|
|
||||||
typedef void (*reg_reset_t)(struct uc_struct *uc);
|
typedef void (*reg_reset_t)(struct uc_struct *uc);
|
||||||
|
|
||||||
typedef bool (*uc_write_mem_t)(AddressSpace *as, hwaddr addr, const uint8_t *buf, int len);
|
typedef bool (*uc_write_mem_t)(AddressSpace *as, hwaddr addr,
|
||||||
|
const uint8_t *buf, int len);
|
||||||
|
|
||||||
typedef bool (*uc_read_mem_t)(AddressSpace *as, hwaddr addr, uint8_t *buf, int len);
|
typedef bool (*uc_read_mem_t)(AddressSpace *as, hwaddr addr, uint8_t *buf,
|
||||||
|
int len);
|
||||||
|
|
||||||
typedef void (*uc_args_void_t)(void*);
|
typedef void (*uc_args_void_t)(void *);
|
||||||
|
|
||||||
typedef void (*uc_args_uc_t)(struct uc_struct*);
|
typedef void (*uc_args_uc_t)(struct uc_struct *);
|
||||||
typedef void (*uc_args_int_uc_t)(struct uc_struct*);
|
typedef void (*uc_args_int_uc_t)(struct uc_struct *);
|
||||||
|
|
||||||
typedef void (*uc_args_uc_long_t)(struct uc_struct*, unsigned long);
|
typedef void (*uc_args_uc_long_t)(struct uc_struct *, unsigned long);
|
||||||
|
|
||||||
typedef void (*uc_args_uc_u64_t)(struct uc_struct *, uint64_t addr);
|
typedef void (*uc_args_uc_u64_t)(struct uc_struct *, uint64_t addr);
|
||||||
|
|
||||||
typedef MemoryRegion* (*uc_args_uc_ram_size_t)(struct uc_struct*, hwaddr begin, size_t size, uint32_t perms);
|
typedef MemoryRegion *(*uc_args_uc_ram_size_t)(struct uc_struct *, hwaddr begin,
|
||||||
|
size_t size, uint32_t perms);
|
||||||
|
|
||||||
typedef MemoryRegion* (*uc_args_uc_ram_size_ptr_t)(struct uc_struct*, hwaddr begin, size_t size, uint32_t perms, void *ptr);
|
typedef MemoryRegion *(*uc_args_uc_ram_size_ptr_t)(struct uc_struct *,
|
||||||
|
hwaddr begin, size_t size,
|
||||||
|
uint32_t perms, void *ptr);
|
||||||
|
|
||||||
typedef void (*uc_mem_unmap_t)(struct uc_struct*, MemoryRegion *mr);
|
typedef void (*uc_mem_unmap_t)(struct uc_struct *, MemoryRegion *mr);
|
||||||
|
|
||||||
typedef void (*uc_readonly_mem_t)(MemoryRegion *mr, bool readonly);
|
typedef void (*uc_readonly_mem_t)(MemoryRegion *mr, bool readonly);
|
||||||
|
|
||||||
typedef int (*uc_cpus_init)(struct uc_struct *, const char *);
|
typedef int (*uc_cpus_init)(struct uc_struct *, const char *);
|
||||||
|
|
||||||
typedef MemoryRegion* (*uc_memory_map_io_t)(struct uc_struct *uc, ram_addr_t begin, size_t size, uc_cb_mmio_read_t read_cb, uc_cb_mmio_write_t write_cb, void *user_data_read, void *user_data_write);
|
typedef MemoryRegion *(*uc_memory_map_io_t)(struct uc_struct *uc,
|
||||||
|
ram_addr_t begin, size_t size,
|
||||||
|
uc_cb_mmio_read_t read_cb,
|
||||||
|
uc_cb_mmio_write_t write_cb,
|
||||||
|
void *user_data_read,
|
||||||
|
void *user_data_write);
|
||||||
|
|
||||||
// which interrupt should make emulation stop?
|
// which interrupt should make emulation stop?
|
||||||
typedef bool (*uc_args_int_t)(struct uc_struct *uc, int intno);
|
typedef bool (*uc_args_int_t)(struct uc_struct *uc, int intno);
|
||||||
|
@ -84,7 +103,7 @@ typedef bool (*uc_args_int_t)(struct uc_struct *uc, int intno);
|
||||||
typedef uint64_t (*uc_mem_redirect_t)(uint64_t address);
|
typedef uint64_t (*uc_mem_redirect_t)(uint64_t address);
|
||||||
|
|
||||||
// validate if Unicorn supports hooking a given instruction
|
// validate if Unicorn supports hooking a given instruction
|
||||||
typedef bool(*uc_insn_hook_validate)(uint32_t insn_enum);
|
typedef bool (*uc_insn_hook_validate)(uint32_t insn_enum);
|
||||||
|
|
||||||
// init target page
|
// init target page
|
||||||
typedef void (*uc_target_page_init)(struct uc_struct *);
|
typedef void (*uc_target_page_init)(struct uc_struct *);
|
||||||
|
@ -99,8 +118,10 @@ struct hook {
|
||||||
int type; // UC_HOOK_*
|
int type; // UC_HOOK_*
|
||||||
int insn; // instruction for HOOK_INSN
|
int insn; // instruction for HOOK_INSN
|
||||||
int refs; // reference count to free hook stored in multiple lists
|
int refs; // reference count to free hook stored in multiple lists
|
||||||
bool to_delete; // set to true when the hook is deleted by the user. The destruction of the hook is delayed.
|
bool to_delete; // set to true when the hook is deleted by the user. The
|
||||||
uint64_t begin, end; // only trigger if PC or memory access is in this address (depends on hook type)
|
// destruction of the hook is delayed.
|
||||||
|
uint64_t begin, end; // only trigger if PC or memory access is in this
|
||||||
|
// address (depends on hook type)
|
||||||
void *callback; // a uc_cb_* type
|
void *callback; // a uc_cb_* type
|
||||||
void *user_data;
|
void *user_data;
|
||||||
};
|
};
|
||||||
|
@ -132,31 +153,31 @@ typedef enum uc_hook_idx {
|
||||||
} uc_hook_idx;
|
} uc_hook_idx;
|
||||||
|
|
||||||
// The lowest 6 bits are used for hook type index.
|
// The lowest 6 bits are used for hook type index.
|
||||||
#define UC_HOOK_IDX_MASK ((1<<6)-1)
|
#define UC_HOOK_IDX_MASK ((1 << 6) - 1)
|
||||||
|
|
||||||
// hook flags
|
// hook flags
|
||||||
#define UC_HOOK_FLAG_NO_STOP (1 << 6) // Don't stop emulation in this uc_tracecode.
|
#define UC_HOOK_FLAG_NO_STOP \
|
||||||
|
(1 << 6) // Don't stop emulation in this uc_tracecode.
|
||||||
|
|
||||||
// The rest of bits are reserved for hook flags.
|
// The rest of bits are reserved for hook flags.
|
||||||
#define UC_HOOK_FLAG_MASK (~(UC_HOOK_IDX_MASK))
|
#define UC_HOOK_FLAG_MASK (~(UC_HOOK_IDX_MASK))
|
||||||
|
|
||||||
#define HOOK_FOREACH_VAR_DECLARE \
|
#define HOOK_FOREACH_VAR_DECLARE struct list_item *cur
|
||||||
struct list_item *cur
|
|
||||||
|
|
||||||
// for loop macro to loop over hook lists
|
// for loop macro to loop over hook lists
|
||||||
#define HOOK_FOREACH(uc, hh, idx) \
|
#define HOOK_FOREACH(uc, hh, idx) \
|
||||||
for ( \
|
for (cur = (uc)->hook[idx##_IDX].head; \
|
||||||
cur = (uc)->hook[idx##_IDX].head; \
|
cur != NULL && ((hh) = (struct hook *)cur->data); cur = cur->next)
|
||||||
cur != NULL && ((hh) = (struct hook *)cur->data); \
|
|
||||||
cur = cur->next)
|
|
||||||
|
|
||||||
// if statement to check hook bounds
|
// if statement to check hook bounds
|
||||||
#define HOOK_BOUND_CHECK(hh, addr) \
|
#define HOOK_BOUND_CHECK(hh, addr) \
|
||||||
((((addr) >= (hh)->begin && (addr) <= (hh)->end) \
|
((((addr) >= (hh)->begin && (addr) <= (hh)->end) || \
|
||||||
|| (hh)->begin > (hh)->end) && !((hh)->to_delete))
|
(hh)->begin > (hh)->end) && \
|
||||||
|
!((hh)->to_delete))
|
||||||
|
|
||||||
#define HOOK_EXISTS(uc, idx) ((uc)->hook[idx##_IDX].head != NULL)
|
#define HOOK_EXISTS(uc, idx) ((uc)->hook[idx##_IDX].head != NULL)
|
||||||
#define HOOK_EXISTS_BOUNDED(uc, idx, addr) _hook_exists_bounded((uc)->hook[idx##_IDX].head, addr)
|
#define HOOK_EXISTS_BOUNDED(uc, idx, addr) \
|
||||||
|
_hook_exists_bounded((uc)->hook[idx##_IDX].head, addr)
|
||||||
|
|
||||||
static inline bool _hook_exists_bounded(struct list_item *cur, uint64_t addr)
|
static inline bool _hook_exists_bounded(struct list_item *cur, uint64_t addr)
|
||||||
{
|
{
|
||||||
|
@ -168,7 +189,7 @@ static inline bool _hook_exists_bounded(struct list_item *cur, uint64_t addr)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
//relloc increment, KEEP THIS A POWER OF 2!
|
// relloc increment, KEEP THIS A POWER OF 2!
|
||||||
#define MEM_BLOCK_INCR 32
|
#define MEM_BLOCK_INCR 32
|
||||||
|
|
||||||
typedef struct TargetPageBits TargetPageBits;
|
typedef struct TargetPageBits TargetPageBits;
|
||||||
|
@ -189,7 +210,8 @@ struct uc_struct {
|
||||||
uc_read_mem_t read_mem;
|
uc_read_mem_t read_mem;
|
||||||
uc_args_void_t release; // release resource when uc_close()
|
uc_args_void_t release; // release resource when uc_close()
|
||||||
uc_args_uc_u64_t set_pc; // set PC for tracecode
|
uc_args_uc_u64_t set_pc; // set PC for tracecode
|
||||||
uc_args_int_t stop_interrupt; // check if the interrupt should stop emulation
|
uc_args_int_t
|
||||||
|
stop_interrupt; // check if the interrupt should stop emulation
|
||||||
uc_memory_map_io_t memory_map_io;
|
uc_memory_map_io_t memory_map_io;
|
||||||
|
|
||||||
uc_args_uc_t init_arch, cpu_exec_init_all;
|
uc_args_uc_t init_arch, cpu_exec_init_all;
|
||||||
|
@ -253,23 +275,28 @@ struct uc_struct {
|
||||||
int size_recur_mem; // size for mem access when in a recursive call
|
int size_recur_mem; // size for mem access when in a recursive call
|
||||||
|
|
||||||
bool init_tcg; // already initialized local TCGv variables?
|
bool init_tcg; // already initialized local TCGv variables?
|
||||||
bool stop_request; // request to immediately stop emulation - for uc_emu_stop()
|
bool stop_request; // request to immediately stop emulation - for
|
||||||
bool quit_request; // request to quit the current TB, but continue to emulate - for uc_mem_protect()
|
// uc_emu_stop()
|
||||||
|
bool quit_request; // request to quit the current TB, but continue to
|
||||||
|
// emulate - for uc_mem_protect()
|
||||||
bool emulation_done; // emulation is done by uc_emu_start()
|
bool emulation_done; // emulation is done by uc_emu_start()
|
||||||
bool timed_out; // emulation timed out, that can retrieve via uc_query(UC_QUERY_TIMEOUT)
|
bool timed_out; // emulation timed out, that can retrieve via
|
||||||
|
// uc_query(UC_QUERY_TIMEOUT)
|
||||||
QemuThread timer; // timer for emulation timeout
|
QemuThread timer; // timer for emulation timeout
|
||||||
uint64_t timeout; // timeout for uc_emu_start()
|
uint64_t timeout; // timeout for uc_emu_start()
|
||||||
|
|
||||||
uint64_t invalid_addr; // invalid address to be accessed
|
uint64_t invalid_addr; // invalid address to be accessed
|
||||||
int invalid_error; // invalid memory code: 1 = READ, 2 = WRITE, 3 = CODE
|
int invalid_error; // invalid memory code: 1 = READ, 2 = WRITE, 3 = CODE
|
||||||
|
|
||||||
uint64_t addr_end; // address where emulation stops (@end param of uc_emu_start())
|
uint64_t addr_end; // address where emulation stops (@end param of
|
||||||
|
// uc_emu_start())
|
||||||
|
|
||||||
int thumb; // thumb mode for ARM
|
int thumb; // thumb mode for ARM
|
||||||
MemoryRegion **mapped_blocks;
|
MemoryRegion **mapped_blocks;
|
||||||
uint32_t mapped_block_count;
|
uint32_t mapped_block_count;
|
||||||
uint32_t mapped_block_cache_index;
|
uint32_t mapped_block_cache_index;
|
||||||
void *qemu_thread_data; // to support cross compile to Windows (qemu-thread-win32.c)
|
void *qemu_thread_data; // to support cross compile to Windows
|
||||||
|
// (qemu-thread-win32.c)
|
||||||
uint32_t target_page_size;
|
uint32_t target_page_size;
|
||||||
uint32_t target_page_align;
|
uint32_t target_page_align;
|
||||||
uint64_t qemu_host_page_size;
|
uint64_t qemu_host_page_size;
|
||||||
|
@ -278,10 +305,13 @@ struct uc_struct {
|
||||||
/* ARCH_REGS_STORAGE_SIZE */
|
/* ARCH_REGS_STORAGE_SIZE */
|
||||||
int cpu_context_size;
|
int cpu_context_size;
|
||||||
uint64_t next_pc; // save next PC for some special cases
|
uint64_t next_pc; // save next PC for some special cases
|
||||||
bool hook_insert; // insert new hook at begin of the hook list (append by default)
|
bool hook_insert; // insert new hook at begin of the hook list (append by
|
||||||
bool first_tb; // is this the first Translation-Block ever generated since uc_emu_start()?
|
// default)
|
||||||
|
bool first_tb; // is this the first Translation-Block ever generated since
|
||||||
|
// uc_emu_start()?
|
||||||
struct list saved_contexts; // The contexts saved by this uc_struct.
|
struct list saved_contexts; // The contexts saved by this uc_struct.
|
||||||
bool no_exit_request; // Disable check_exit_request temporarily. A workaround to treat the IT block as a whole block.
|
bool no_exit_request; // Disable check_exit_request temporarily. A
|
||||||
|
// workaround to treat the IT block as a whole block.
|
||||||
};
|
};
|
||||||
|
|
||||||
// Metadata stub for the variable-size cpu context used with uc_context_*()
|
// Metadata stub for the variable-size cpu context used with uc_context_*()
|
||||||
|
@ -296,7 +326,7 @@ struct uc_context {
|
||||||
};
|
};
|
||||||
|
|
||||||
// check if this address is mapped in (via uc_mem_map())
|
// check if this address is mapped in (via uc_mem_map())
|
||||||
MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address);
|
MemoryRegion *memory_mapping(struct uc_struct *uc, uint64_t address);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
/* vim: set ts=4 noet: */
|
/* vim: set ts=4 noet: */
|
||||||
|
|
|
@ -12,7 +12,7 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(disable:4201)
|
#pragma warning(disable : 4201)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//> ARM registers
|
//> ARM registers
|
||||||
|
|
|
@ -12,7 +12,7 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(disable:4201)
|
#pragma warning(disable : 4201)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//> ARM64 registers
|
//> ARM64 registers
|
||||||
|
|
|
@ -12,7 +12,7 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(disable:4201)
|
#pragma warning(disable : 4201)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//> M68K registers
|
//> M68K registers
|
||||||
|
|
|
@ -16,7 +16,7 @@ extern "C" {
|
||||||
#undef mips
|
#undef mips
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(disable:4201)
|
#pragma warning(disable : 4201)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//> MIPS registers
|
//> MIPS registers
|
||||||
|
@ -212,7 +212,8 @@ typedef enum UC_MIPS_REG {
|
||||||
UC_MIPS_REG_K1 = UC_MIPS_REG_27,
|
UC_MIPS_REG_K1 = UC_MIPS_REG_27,
|
||||||
UC_MIPS_REG_GP = UC_MIPS_REG_28,
|
UC_MIPS_REG_GP = UC_MIPS_REG_28,
|
||||||
UC_MIPS_REG_SP = UC_MIPS_REG_29,
|
UC_MIPS_REG_SP = UC_MIPS_REG_29,
|
||||||
UC_MIPS_REG_FP = UC_MIPS_REG_30, UC_MIPS_REG_S8 = UC_MIPS_REG_30,
|
UC_MIPS_REG_FP = UC_MIPS_REG_30,
|
||||||
|
UC_MIPS_REG_S8 = UC_MIPS_REG_30,
|
||||||
UC_MIPS_REG_RA = UC_MIPS_REG_31,
|
UC_MIPS_REG_RA = UC_MIPS_REG_31,
|
||||||
|
|
||||||
UC_MIPS_REG_HI0 = UC_MIPS_REG_AC0,
|
UC_MIPS_REG_HI0 = UC_MIPS_REG_AC0,
|
||||||
|
|
|
@ -31,7 +31,8 @@ MSVC++ 5.0 _MSC_VER == 1100
|
||||||
#define MSC_VER_VS2015 1900
|
#define MSC_VER_VS2015 1900
|
||||||
|
|
||||||
// handle stdbool.h compatibility
|
// handle stdbool.h compatibility
|
||||||
#if !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__MINGW64__) && (defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64))
|
#if !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__MINGW64__) && \
|
||||||
|
(defined(WIN32) || defined(WIN64) || defined(_WIN32) || defined(_WIN64))
|
||||||
// MSVC
|
// MSVC
|
||||||
|
|
||||||
// stdbool.h
|
// stdbool.h
|
||||||
|
@ -51,7 +52,9 @@ typedef unsigned char bool;
|
||||||
#else
|
#else
|
||||||
// not MSVC -> C99 is supported
|
// not MSVC -> C99 is supported
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#endif // !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__MINGW64__) && (defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64))
|
#endif // !defined(__CYGWIN__) && !defined(__MINGW32__) && !defined(__MINGW64__)
|
||||||
|
// && (defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined
|
||||||
|
// (_WIN64))
|
||||||
|
|
||||||
#if (defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2010)) || defined(_KERNEL_MODE)
|
#if (defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2010)) || defined(_KERNEL_MODE)
|
||||||
// this system does not have stdint.h
|
// this system does not have stdint.h
|
||||||
|
@ -65,21 +68,21 @@ typedef signed long long int64_t;
|
||||||
typedef unsigned long long uint64_t;
|
typedef unsigned long long uint64_t;
|
||||||
|
|
||||||
#ifndef _INTPTR_T_DEFINED
|
#ifndef _INTPTR_T_DEFINED
|
||||||
#define _INTPTR_T_DEFINED
|
#define _INTPTR_T_DEFINED
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
typedef long long intptr_t;
|
typedef long long intptr_t;
|
||||||
#else /* _WIN64 */
|
#else /* _WIN64 */
|
||||||
typedef _W64 int intptr_t;
|
typedef _W64 int intptr_t;
|
||||||
#endif /* _WIN64 */
|
#endif /* _WIN64 */
|
||||||
#endif /* _INTPTR_T_DEFINED */
|
#endif /* _INTPTR_T_DEFINED */
|
||||||
|
|
||||||
#ifndef _UINTPTR_T_DEFINED
|
#ifndef _UINTPTR_T_DEFINED
|
||||||
#define _UINTPTR_T_DEFINED
|
#define _UINTPTR_T_DEFINED
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
typedef unsigned long long uintptr_t;
|
typedef unsigned long long uintptr_t;
|
||||||
#else /* _WIN64 */
|
#else /* _WIN64 */
|
||||||
typedef _W64 unsigned int uintptr_t;
|
typedef _W64 unsigned int uintptr_t;
|
||||||
#endif /* _WIN64 */
|
#endif /* _WIN64 */
|
||||||
#endif /* _UINTPTR_T_DEFINED */
|
#endif /* _UINTPTR_T_DEFINED */
|
||||||
|
|
||||||
#define INT8_MIN (-127i8 - 1)
|
#define INT8_MIN (-127i8 - 1)
|
||||||
|
@ -96,7 +99,8 @@ typedef _W64 unsigned int uintptr_t;
|
||||||
#define UINT64_MAX 0xffffffffffffffffui64
|
#define UINT64_MAX 0xffffffffffffffffui64
|
||||||
#else // this system has stdint.h
|
#else // this system has stdint.h
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#endif // (defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2010)) || defined(_KERNEL_MODE)
|
#endif // (defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2010)) ||
|
||||||
|
// defined(_KERNEL_MODE)
|
||||||
|
|
||||||
// handle inttypes.h compatibility
|
// handle inttypes.h compatibility
|
||||||
#if (defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2013)) || defined(_KERNEL_MODE)
|
#if (defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2013)) || defined(_KERNEL_MODE)
|
||||||
|
@ -150,7 +154,8 @@ typedef _W64 unsigned int uintptr_t;
|
||||||
#else
|
#else
|
||||||
// this system has inttypes.h by default
|
// this system has inttypes.h by default
|
||||||
#include <inttypes.h>
|
#include <inttypes.h>
|
||||||
#endif // #if defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2013) || defined(_KERNEL_MODE)
|
#endif // #if defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2013) ||
|
||||||
|
// defined(_KERNEL_MODE)
|
||||||
|
|
||||||
// sys/time.h compatibility
|
// sys/time.h compatibility
|
||||||
#if defined(_MSC_VER)
|
#if defined(_MSC_VER)
|
||||||
|
@ -174,7 +179,7 @@ static int usleep(uint32_t usec)
|
||||||
if (!timer)
|
if (!timer)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
due.QuadPart = (-((int64_t) usec)) * 10LL;
|
due.QuadPart = (-((int64_t)usec)) * 10LL;
|
||||||
if (!SetWaitableTimer(timer, &due, 0, NULL, NULL, 0)) {
|
if (!SetWaitableTimer(timer, &due, 0, NULL, NULL, 0)) {
|
||||||
CloseHandle(timer);
|
CloseHandle(timer);
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -198,7 +203,7 @@ typedef _W64 signed int ssize_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifndef va_copy
|
#ifndef va_copy
|
||||||
#define va_copy(d,s) ((d) = (s))
|
#define va_copy(d, s) ((d) = (s))
|
||||||
#endif
|
#endif
|
||||||
#define strcasecmp _stricmp
|
#define strcasecmp _stricmp
|
||||||
#if (_MSC_VER < MSC_VER_VS2015)
|
#if (_MSC_VER < MSC_VER_VS2015)
|
||||||
|
@ -209,5 +214,4 @@ typedef _W64 signed int ssize_t;
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#endif // UNICORN_PLATFORM_H
|
#endif // UNICORN_PLATFORM_H
|
||||||
|
|
|
@ -12,7 +12,7 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(disable:4201)
|
#pragma warning(disable : 4201)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//> PPC registers
|
//> PPC registers
|
||||||
|
|
|
@ -12,7 +12,7 @@ extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(disable:4201)
|
#pragma warning(disable : 4201)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//> RISCV registers
|
//> RISCV registers
|
||||||
|
|
|
@ -16,7 +16,7 @@ extern "C" {
|
||||||
#undef sparc
|
#undef sparc
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(disable:4201)
|
#pragma warning(disable : 4201)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//> SPARC registers
|
//> SPARC registers
|
||||||
|
|
|
@ -42,8 +42,8 @@ typedef size_t uc_hook;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(disable:4201)
|
#pragma warning(disable : 4201)
|
||||||
#pragma warning(disable:4100)
|
#pragma warning(disable : 4100)
|
||||||
#ifdef UNICORN_SHARED
|
#ifdef UNICORN_SHARED
|
||||||
#define UNICORN_EXPORT __declspec(dllexport)
|
#define UNICORN_EXPORT __declspec(dllexport)
|
||||||
#else // defined(UNICORN_STATIC)
|
#else // defined(UNICORN_STATIC)
|
||||||
|
@ -62,7 +62,8 @@ typedef size_t uc_hook;
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
#define UNICORN_DEPRECATED __declspec(deprecated)
|
#define UNICORN_DEPRECATED __declspec(deprecated)
|
||||||
#else
|
#else
|
||||||
#pragma message("WARNING: You need to implement UNICORN_DEPRECATED for this compiler")
|
#pragma message( \
|
||||||
|
"WARNING: You need to implement UNICORN_DEPRECATED for this compiler")
|
||||||
#define UNICORN_DEPRECATED
|
#define UNICORN_DEPRECATED
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -75,7 +76,6 @@ typedef size_t uc_hook;
|
||||||
#define UC_VERSION_MINOR UC_API_MINOR
|
#define UC_VERSION_MINOR UC_API_MINOR
|
||||||
#define UC_VERSION_EXTRA 0
|
#define UC_VERSION_EXTRA 0
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Macro to create combined version which can be compared to
|
Macro to create combined version which can be compared to
|
||||||
result of uc_version() API.
|
result of uc_version() API.
|
||||||
|
@ -132,7 +132,8 @@ typedef enum uc_mode {
|
||||||
// ppc
|
// ppc
|
||||||
UC_MODE_PPC32 = 1 << 2, // 32-bit mode
|
UC_MODE_PPC32 = 1 << 2, // 32-bit mode
|
||||||
UC_MODE_PPC64 = 1 << 3, // 64-bit mode (currently unsupported)
|
UC_MODE_PPC64 = 1 << 3, // 64-bit mode (currently unsupported)
|
||||||
UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (currently unsupported)
|
UC_MODE_QPX =
|
||||||
|
1 << 4, // Quad Processing eXtensions mode (currently unsupported)
|
||||||
|
|
||||||
// sparc
|
// sparc
|
||||||
UC_MODE_SPARC32 = 1 << 2, // 32-bit mode
|
UC_MODE_SPARC32 = 1 << 2, // 32-bit mode
|
||||||
|
@ -155,16 +156,24 @@ typedef enum uc_err {
|
||||||
UC_ERR_HANDLE, // Invalid handle
|
UC_ERR_HANDLE, // Invalid handle
|
||||||
UC_ERR_MODE, // Invalid/unsupported mode: uc_open()
|
UC_ERR_MODE, // Invalid/unsupported mode: uc_open()
|
||||||
UC_ERR_VERSION, // Unsupported version (bindings)
|
UC_ERR_VERSION, // Unsupported version (bindings)
|
||||||
UC_ERR_READ_UNMAPPED, // Quit emulation due to READ on unmapped memory: uc_emu_start()
|
UC_ERR_READ_UNMAPPED, // Quit emulation due to READ on unmapped memory:
|
||||||
UC_ERR_WRITE_UNMAPPED, // Quit emulation due to WRITE on unmapped memory: uc_emu_start()
|
// uc_emu_start()
|
||||||
UC_ERR_FETCH_UNMAPPED, // Quit emulation due to FETCH on unmapped memory: uc_emu_start()
|
UC_ERR_WRITE_UNMAPPED, // Quit emulation due to WRITE on unmapped memory:
|
||||||
|
// uc_emu_start()
|
||||||
|
UC_ERR_FETCH_UNMAPPED, // Quit emulation due to FETCH on unmapped memory:
|
||||||
|
// uc_emu_start()
|
||||||
UC_ERR_HOOK, // Invalid hook type: uc_hook_add()
|
UC_ERR_HOOK, // Invalid hook type: uc_hook_add()
|
||||||
UC_ERR_INSN_INVALID, // Quit emulation due to invalid instruction: uc_emu_start()
|
UC_ERR_INSN_INVALID, // Quit emulation due to invalid instruction:
|
||||||
|
// uc_emu_start()
|
||||||
UC_ERR_MAP, // Invalid memory mapping: uc_mem_map()
|
UC_ERR_MAP, // Invalid memory mapping: uc_mem_map()
|
||||||
UC_ERR_WRITE_PROT, // Quit emulation due to UC_MEM_WRITE_PROT violation: uc_emu_start()
|
UC_ERR_WRITE_PROT, // Quit emulation due to UC_MEM_WRITE_PROT violation:
|
||||||
UC_ERR_READ_PROT, // Quit emulation due to UC_MEM_READ_PROT violation: uc_emu_start()
|
// uc_emu_start()
|
||||||
UC_ERR_FETCH_PROT, // Quit emulation due to UC_MEM_FETCH_PROT violation: uc_emu_start()
|
UC_ERR_READ_PROT, // Quit emulation due to UC_MEM_READ_PROT violation:
|
||||||
UC_ERR_ARG, // Inavalid argument provided to uc_xxx function (See specific function API)
|
// uc_emu_start()
|
||||||
|
UC_ERR_FETCH_PROT, // Quit emulation due to UC_MEM_FETCH_PROT violation:
|
||||||
|
// uc_emu_start()
|
||||||
|
UC_ERR_ARG, // Inavalid argument provided to uc_xxx function (See specific
|
||||||
|
// function API)
|
||||||
UC_ERR_READ_UNALIGNED, // Unaligned read
|
UC_ERR_READ_UNALIGNED, // Unaligned read
|
||||||
UC_ERR_WRITE_UNALIGNED, // Unaligned write
|
UC_ERR_WRITE_UNALIGNED, // Unaligned write
|
||||||
UC_ERR_FETCH_UNALIGNED, // Unaligned fetch
|
UC_ERR_FETCH_UNALIGNED, // Unaligned fetch
|
||||||
|
@ -173,15 +182,16 @@ typedef enum uc_err {
|
||||||
UC_ERR_EXCEPTION, // Unhandled CPU exception
|
UC_ERR_EXCEPTION, // Unhandled CPU exception
|
||||||
} uc_err;
|
} uc_err;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Callback function for tracing code (UC_HOOK_CODE & UC_HOOK_BLOCK)
|
Callback function for tracing code (UC_HOOK_CODE & UC_HOOK_BLOCK)
|
||||||
|
|
||||||
@address: address where the code is being executed
|
@address: address where the code is being executed
|
||||||
@size: size of machine instruction(s) being executed, or 0 when size is unknown
|
@size: size of machine instruction(s) being executed, or 0 when size is
|
||||||
|
unknown
|
||||||
@user_data: user data passed to tracing APIs.
|
@user_data: user data passed to tracing APIs.
|
||||||
*/
|
*/
|
||||||
typedef void (*uc_cb_hookcode_t)(uc_engine *uc, uint64_t address, uint32_t size, void *user_data);
|
typedef void (*uc_cb_hookcode_t)(uc_engine *uc, uint64_t address, uint32_t size,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Callback function for tracing interrupts (for uc_hook_intr())
|
Callback function for tracing interrupts (for uc_hook_intr())
|
||||||
|
@ -189,14 +199,16 @@ typedef void (*uc_cb_hookcode_t)(uc_engine *uc, uint64_t address, uint32_t size,
|
||||||
@intno: interrupt number
|
@intno: interrupt number
|
||||||
@user_data: user data passed to tracing APIs.
|
@user_data: user data passed to tracing APIs.
|
||||||
*/
|
*/
|
||||||
typedef void (*uc_cb_hookintr_t)(uc_engine *uc, uint32_t intno, void *user_data);
|
typedef void (*uc_cb_hookintr_t)(uc_engine *uc, uint32_t intno,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Callback function for tracing invalid instructions
|
Callback function for tracing invalid instructions
|
||||||
|
|
||||||
@user_data: user data passed to tracing APIs.
|
@user_data: user data passed to tracing APIs.
|
||||||
|
|
||||||
@return: return true to continue, or false to stop program (due to invalid instruction).
|
@return: return true to continue, or false to stop program (due to invalid
|
||||||
|
instruction).
|
||||||
*/
|
*/
|
||||||
typedef bool (*uc_cb_hookinsn_invalid_t)(uc_engine *uc, void *user_data);
|
typedef bool (*uc_cb_hookinsn_invalid_t)(uc_engine *uc, void *user_data);
|
||||||
|
|
||||||
|
@ -207,7 +219,8 @@ typedef bool (*uc_cb_hookinsn_invalid_t)(uc_engine *uc, void *user_data);
|
||||||
@size: data size (1/2/4) to be read from this port
|
@size: data size (1/2/4) to be read from this port
|
||||||
@user_data: user data passed to tracing APIs.
|
@user_data: user data passed to tracing APIs.
|
||||||
*/
|
*/
|
||||||
typedef uint32_t (*uc_cb_insn_in_t)(uc_engine *uc, uint32_t port, int size, void *user_data);
|
typedef uint32_t (*uc_cb_insn_in_t)(uc_engine *uc, uint32_t port, int size,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Callback function for OUT instruction of X86
|
Callback function for OUT instruction of X86
|
||||||
|
@ -216,7 +229,8 @@ typedef uint32_t (*uc_cb_insn_in_t)(uc_engine *uc, uint32_t port, int size, void
|
||||||
@size: data size (1/2/4) to be written to this port
|
@size: data size (1/2/4) to be written to this port
|
||||||
@value: data value to be written to this port
|
@value: data value to be written to this port
|
||||||
*/
|
*/
|
||||||
typedef void (*uc_cb_insn_out_t)(uc_engine *uc, uint32_t port, int size, uint32_t value, void *user_data);
|
typedef void (*uc_cb_insn_out_t)(uc_engine *uc, uint32_t port, int size,
|
||||||
|
uint32_t value, void *user_data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Callback function for MMIO read
|
Callback function for MMIO read
|
||||||
|
@ -225,7 +239,8 @@ typedef void (*uc_cb_insn_out_t)(uc_engine *uc, uint32_t port, int size, uint32_
|
||||||
@size: data size to read
|
@size: data size to read
|
||||||
@user_data: user data passed to uc_mmio_map()
|
@user_data: user data passed to uc_mmio_map()
|
||||||
*/
|
*/
|
||||||
typedef uint64_t (*uc_cb_mmio_read_t)(uc_engine *uc, uint64_t offset, unsigned size, void *user_data);
|
typedef uint64_t (*uc_cb_mmio_read_t)(uc_engine *uc, uint64_t offset,
|
||||||
|
unsigned size, void *user_data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Callback function for MMIO write
|
Callback function for MMIO write
|
||||||
|
@ -235,8 +250,9 @@ typedef uint64_t (*uc_cb_mmio_read_t)(uc_engine *uc, uint64_t offset, unsigned s
|
||||||
@value: data value to be written
|
@value: data value to be written
|
||||||
@user_data: user data passed to uc_mmio_map()
|
@user_data: user data passed to uc_mmio_map()
|
||||||
*/
|
*/
|
||||||
typedef void (*uc_cb_mmio_write_t)(uc_engine *uc, uint64_t offset, unsigned size, uint64_t value, void *user_data);
|
typedef void (*uc_cb_mmio_write_t)(uc_engine *uc, uint64_t offset,
|
||||||
|
unsigned size, uint64_t value,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
// All type of memory accesses for UC_HOOK_MEM_*
|
// All type of memory accesses for UC_HOOK_MEM_*
|
||||||
typedef enum uc_mem_type {
|
typedef enum uc_mem_type {
|
||||||
|
@ -256,7 +272,8 @@ typedef enum uc_mem_type {
|
||||||
typedef enum uc_hook_type {
|
typedef enum uc_hook_type {
|
||||||
// Hook all interrupt/syscall events
|
// Hook all interrupt/syscall events
|
||||||
UC_HOOK_INTR = 1 << 0,
|
UC_HOOK_INTR = 1 << 0,
|
||||||
// Hook a particular instruction - only a very small subset of instructions supported here
|
// Hook a particular instruction - only a very small subset of instructions
|
||||||
|
// supported here
|
||||||
UC_HOOK_INSN = 1 << 1,
|
UC_HOOK_INSN = 1 << 1,
|
||||||
// Hook a range of code
|
// Hook a range of code
|
||||||
UC_HOOK_CODE = 1 << 2,
|
UC_HOOK_CODE = 1 << 2,
|
||||||
|
@ -288,21 +305,29 @@ typedef enum uc_hook_type {
|
||||||
} uc_hook_type;
|
} uc_hook_type;
|
||||||
|
|
||||||
// Hook type for all events of unmapped memory access
|
// Hook type for all events of unmapped memory access
|
||||||
#define UC_HOOK_MEM_UNMAPPED (UC_HOOK_MEM_READ_UNMAPPED + UC_HOOK_MEM_WRITE_UNMAPPED + UC_HOOK_MEM_FETCH_UNMAPPED)
|
#define UC_HOOK_MEM_UNMAPPED \
|
||||||
|
(UC_HOOK_MEM_READ_UNMAPPED + UC_HOOK_MEM_WRITE_UNMAPPED + \
|
||||||
|
UC_HOOK_MEM_FETCH_UNMAPPED)
|
||||||
// Hook type for all events of illegal protected memory access
|
// Hook type for all events of illegal protected memory access
|
||||||
#define UC_HOOK_MEM_PROT (UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_FETCH_PROT)
|
#define UC_HOOK_MEM_PROT \
|
||||||
|
(UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_FETCH_PROT)
|
||||||
// Hook type for all events of illegal read memory access
|
// Hook type for all events of illegal read memory access
|
||||||
#define UC_HOOK_MEM_READ_INVALID (UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_READ_UNMAPPED)
|
#define UC_HOOK_MEM_READ_INVALID \
|
||||||
|
(UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_READ_UNMAPPED)
|
||||||
// Hook type for all events of illegal write memory access
|
// Hook type for all events of illegal write memory access
|
||||||
#define UC_HOOK_MEM_WRITE_INVALID (UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_WRITE_UNMAPPED)
|
#define UC_HOOK_MEM_WRITE_INVALID \
|
||||||
|
(UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_WRITE_UNMAPPED)
|
||||||
// Hook type for all events of illegal fetch memory access
|
// Hook type for all events of illegal fetch memory access
|
||||||
#define UC_HOOK_MEM_FETCH_INVALID (UC_HOOK_MEM_FETCH_PROT + UC_HOOK_MEM_FETCH_UNMAPPED)
|
#define UC_HOOK_MEM_FETCH_INVALID \
|
||||||
|
(UC_HOOK_MEM_FETCH_PROT + UC_HOOK_MEM_FETCH_UNMAPPED)
|
||||||
// Hook type for all events of illegal memory access
|
// Hook type for all events of illegal memory access
|
||||||
#define UC_HOOK_MEM_INVALID (UC_HOOK_MEM_UNMAPPED + UC_HOOK_MEM_PROT)
|
#define UC_HOOK_MEM_INVALID (UC_HOOK_MEM_UNMAPPED + UC_HOOK_MEM_PROT)
|
||||||
// Hook type for all events of valid memory access
|
// Hook type for all events of valid memory access
|
||||||
// NOTE: UC_HOOK_MEM_READ is triggered before UC_HOOK_MEM_READ_PROT and UC_HOOK_MEM_READ_UNMAPPED, so
|
// NOTE: UC_HOOK_MEM_READ is triggered before UC_HOOK_MEM_READ_PROT and
|
||||||
|
// UC_HOOK_MEM_READ_UNMAPPED, so
|
||||||
// this hook may technically trigger on some invalid reads.
|
// this hook may technically trigger on some invalid reads.
|
||||||
#define UC_HOOK_MEM_VALID (UC_HOOK_MEM_READ + UC_HOOK_MEM_WRITE + UC_HOOK_MEM_FETCH)
|
#define UC_HOOK_MEM_VALID \
|
||||||
|
(UC_HOOK_MEM_READ + UC_HOOK_MEM_WRITE + UC_HOOK_MEM_FETCH)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Callback function for hooking memory (READ, WRITE & FETCH)
|
Callback function for hooking memory (READ, WRITE & FETCH)
|
||||||
|
@ -314,7 +339,8 @@ typedef enum uc_hook_type {
|
||||||
@user_data: user data passed to tracing APIs
|
@user_data: user data passed to tracing APIs
|
||||||
*/
|
*/
|
||||||
typedef void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type,
|
typedef void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type,
|
||||||
uint64_t address, int size, int64_t value, void *user_data);
|
uint64_t address, int size, int64_t value,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Callback function for handling invalid memory access events (UNMAPPED and
|
Callback function for handling invalid memory access events (UNMAPPED and
|
||||||
|
@ -326,21 +352,24 @@ typedef void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type,
|
||||||
@value: value of data being written to memory, or irrelevant if type = READ.
|
@value: value of data being written to memory, or irrelevant if type = READ.
|
||||||
@user_data: user data passed to tracing APIs
|
@user_data: user data passed to tracing APIs
|
||||||
|
|
||||||
@return: return true to continue, or false to stop program (due to invalid memory).
|
@return: return true to continue, or false to stop program (due to invalid
|
||||||
NOTE: returning true to continue execution will only work if if the accessed
|
memory). NOTE: returning true to continue execution will only work if if the
|
||||||
memory is made accessible with the correct permissions during the hook.
|
accessed memory is made accessible with the correct permissions during the
|
||||||
|
hook.
|
||||||
|
|
||||||
In the event of a UC_MEM_READ_UNMAPPED or UC_MEM_WRITE_UNMAPPED callback,
|
In the event of a UC_MEM_READ_UNMAPPED or UC_MEM_WRITE_UNMAPPED
|
||||||
the memory should be uc_mem_map()-ed with the correct permissions, and the
|
callback, the memory should be uc_mem_map()-ed with the correct permissions,
|
||||||
instruction will then read or write to the address as it was supposed to.
|
and the instruction will then read or write to the address as it was supposed
|
||||||
|
to.
|
||||||
|
|
||||||
In the event of a UC_MEM_FETCH_UNMAPPED callback, the memory can be mapped
|
In the event of a UC_MEM_FETCH_UNMAPPED callback, the memory can be
|
||||||
in as executable, in which case execution will resume from the fetched address.
|
mapped in as executable, in which case execution will resume from the fetched
|
||||||
The instruction pointer may be written to in order to change where execution resumes,
|
address. The instruction pointer may be written to in order to change where
|
||||||
but the fetch must succeed if execution is to resume.
|
execution resumes, but the fetch must succeed if execution is to resume.
|
||||||
*/
|
*/
|
||||||
typedef bool (*uc_cb_eventmem_t)(uc_engine *uc, uc_mem_type type,
|
typedef bool (*uc_cb_eventmem_t)(uc_engine *uc, uc_mem_type type,
|
||||||
uint64_t address, int size, int64_t value, void *user_data);
|
uint64_t address, int size, int64_t value,
|
||||||
|
void *user_data);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Memory region mapped by uc_mem_map() and uc_mem_map_ptr()
|
Memory region mapped by uc_mem_map() and uc_mem_map_ptr()
|
||||||
|
@ -358,7 +387,8 @@ typedef enum uc_query_type {
|
||||||
UC_QUERY_MODE = 1,
|
UC_QUERY_MODE = 1,
|
||||||
UC_QUERY_PAGE_SIZE, // query pagesize of engine
|
UC_QUERY_PAGE_SIZE, // query pagesize of engine
|
||||||
UC_QUERY_ARCH, // query architecture of engine (for ARM to query Thumb mode)
|
UC_QUERY_ARCH, // query architecture of engine (for ARM to query Thumb mode)
|
||||||
UC_QUERY_TIMEOUT, // query if emulation stops due to timeout (indicated if result = True)
|
UC_QUERY_TIMEOUT, // query if emulation stops due to timeout (indicated if
|
||||||
|
// result = True)
|
||||||
} uc_query_type;
|
} uc_query_type;
|
||||||
|
|
||||||
// Opaque storage for CPU context, used with uc_context_*()
|
// Opaque storage for CPU context, used with uc_context_*()
|
||||||
|
@ -385,7 +415,6 @@ typedef struct uc_context uc_context;
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
unsigned int uc_version(unsigned int *major, unsigned int *minor);
|
unsigned int uc_version(unsigned int *major, unsigned int *minor);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Determine if the given architecture is supported by this library.
|
Determine if the given architecture is supported by this library.
|
||||||
|
|
||||||
|
@ -396,7 +425,6 @@ unsigned int uc_version(unsigned int *major, unsigned int *minor);
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
bool uc_arch_supported(uc_arch arch);
|
bool uc_arch_supported(uc_arch arch);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Create new instance of unicorn engine.
|
Create new instance of unicorn engine.
|
||||||
|
|
||||||
|
@ -499,7 +527,8 @@ uc_err uc_reg_read(uc_engine *uc, int regid, void *value);
|
||||||
for detailed error).
|
for detailed error).
|
||||||
*/
|
*/
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_reg_write_batch(uc_engine *uc, int *regs, void *const *vals, int count);
|
uc_err uc_reg_write_batch(uc_engine *uc, int *regs, void *const *vals,
|
||||||
|
int count);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read multiple register values.
|
Read multiple register values.
|
||||||
|
@ -529,7 +558,8 @@ uc_err uc_reg_read_batch(uc_engine *uc, int *regs, void **vals, int count);
|
||||||
for detailed error).
|
for detailed error).
|
||||||
*/
|
*/
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *bytes, size_t size);
|
uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *bytes,
|
||||||
|
size_t size);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read a range of bytes in memory.
|
Read a range of bytes in memory.
|
||||||
|
@ -566,7 +596,8 @@ uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t size);
|
||||||
for detailed error).
|
for detailed error).
|
||||||
*/
|
*/
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count);
|
uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until,
|
||||||
|
uint64_t timeout, size_t count);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Stop emulation (which was started by uc_emu_start() API.
|
Stop emulation (which was started by uc_emu_start() API.
|
||||||
|
@ -585,15 +616,17 @@ uc_err uc_emu_stop(uc_engine *uc);
|
||||||
The callback will be run when the hook event is hit.
|
The callback will be run when the hook event is hit.
|
||||||
|
|
||||||
@uc: handle returned by uc_open()
|
@uc: handle returned by uc_open()
|
||||||
@hh: hook handle returned from this registration. To be used in uc_hook_del() API
|
@hh: hook handle returned from this registration. To be used in uc_hook_del()
|
||||||
|
API
|
||||||
@type: hook type
|
@type: hook type
|
||||||
@callback: callback to be run when instruction is hit
|
@callback: callback to be run when instruction is hit
|
||||||
@user_data: user-defined data. This will be passed to callback function in its
|
@user_data: user-defined data. This will be passed to callback function in its
|
||||||
last argument @user_data
|
last argument @user_data
|
||||||
@begin: start address of the area where the callback is effect (inclusive)
|
@begin: start address of the area where the callback is effect (inclusive)
|
||||||
@end: end address of the area where the callback is effect (inclusive)
|
@end: end address of the area where the callback is effect (inclusive)
|
||||||
NOTE 1: the callback is called only if related address is in range [@begin, @end]
|
NOTE 1: the callback is called only if related address is in range [@begin,
|
||||||
NOTE 2: if @begin > @end, callback is called whenever this hook type is triggered
|
@end] NOTE 2: if @begin > @end, callback is called whenever this hook type is
|
||||||
|
triggered
|
||||||
@...: variable arguments (depending on @type)
|
@...: variable arguments (depending on @type)
|
||||||
NOTE: if @type = UC_HOOK_INSN, this is the instruction ID.
|
NOTE: if @type = UC_HOOK_INSN, this is the instruction ID.
|
||||||
currently, only x86 in, out, syscall, sysenter, cpuid are supported.
|
currently, only x86 in, out, syscall, sysenter, cpuid are supported.
|
||||||
|
@ -634,12 +667,14 @@ typedef enum uc_prot {
|
||||||
|
|
||||||
@uc: handle returned by uc_open()
|
@uc: handle returned by uc_open()
|
||||||
@address: starting address of the new memory region to be mapped in.
|
@address: starting address of the new memory region to be mapped in.
|
||||||
This address must be aligned to 4KB, or this will return with UC_ERR_ARG error.
|
This address must be aligned to 4KB, or this will return with UC_ERR_ARG
|
||||||
|
error.
|
||||||
@size: size of the new memory region to be mapped in.
|
@size: size of the new memory region to be mapped in.
|
||||||
This size must be multiple of 4KB, or this will return with UC_ERR_ARG error.
|
This size must be multiple of 4KB, or this will return with UC_ERR_ARG
|
||||||
|
error.
|
||||||
@perms: Permissions for the newly mapped region.
|
@perms: Permissions for the newly mapped region.
|
||||||
This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC,
|
This must be some combination of UC_PROT_READ | UC_PROT_WRITE |
|
||||||
or this will return with UC_ERR_ARG error.
|
UC_PROT_EXEC, or this will return with UC_ERR_ARG error.
|
||||||
|
|
||||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||||
for detailed error).
|
for detailed error).
|
||||||
|
@ -653,21 +688,25 @@ uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms);
|
||||||
|
|
||||||
@uc: handle returned by uc_open()
|
@uc: handle returned by uc_open()
|
||||||
@address: starting address of the new memory region to be mapped in.
|
@address: starting address of the new memory region to be mapped in.
|
||||||
This address must be aligned to 4KB, or this will return with UC_ERR_ARG error.
|
This address must be aligned to 4KB, or this will return with UC_ERR_ARG
|
||||||
|
error.
|
||||||
@size: size of the new memory region to be mapped in.
|
@size: size of the new memory region to be mapped in.
|
||||||
This size must be multiple of 4KB, or this will return with UC_ERR_ARG error.
|
This size must be multiple of 4KB, or this will return with UC_ERR_ARG
|
||||||
|
error.
|
||||||
@perms: Permissions for the newly mapped region.
|
@perms: Permissions for the newly mapped region.
|
||||||
This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC,
|
This must be some combination of UC_PROT_READ | UC_PROT_WRITE |
|
||||||
or this will return with UC_ERR_ARG error.
|
UC_PROT_EXEC, or this will return with UC_ERR_ARG error.
|
||||||
@ptr: pointer to host memory backing the newly mapped memory. This host memory is
|
@ptr: pointer to host memory backing the newly mapped memory. This host memory
|
||||||
expected to be an equal or larger size than provided, and be mapped with at
|
is expected to be an equal or larger size than provided, and be mapped with at
|
||||||
least PROT_READ | PROT_WRITE. If it is not, the resulting behavior is undefined.
|
least PROT_READ | PROT_WRITE. If it is not, the resulting behavior is
|
||||||
|
undefined.
|
||||||
|
|
||||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||||
for detailed error).
|
for detailed error).
|
||||||
*/
|
*/
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr);
|
uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size,
|
||||||
|
uint32_t perms, void *ptr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Map MMIO in for emulation.
|
Map MMIO in for emulation.
|
||||||
|
@ -675,15 +714,16 @@ uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t per
|
||||||
|
|
||||||
@uc: handle returned by uc_open()
|
@uc: handle returned by uc_open()
|
||||||
@address: starting address of the new MMIO region to be mapped in.
|
@address: starting address of the new MMIO region to be mapped in.
|
||||||
This address must be aligned to 4KB, or this will return with UC_ERR_ARG error.
|
This address must be aligned to 4KB, or this will return with UC_ERR_ARG
|
||||||
|
error.
|
||||||
@size: size of the new MMIO region to be mapped in.
|
@size: size of the new MMIO region to be mapped in.
|
||||||
This size must be multiple of 4KB, or this will return with UC_ERR_ARG error.
|
This size must be multiple of 4KB, or this will return with UC_ERR_ARG error.
|
||||||
@read_cb: function for handling reads from this MMIO region.
|
@read_cb: function for handling reads from this MMIO region.
|
||||||
@user_data_read: user-defined data. This will be passed to @read_cb function in its
|
@user_data_read: user-defined data. This will be passed to @read_cb function in
|
||||||
last argument @user_data
|
its last argument @user_data
|
||||||
@write_cb: function for handling writes to this MMIO region.
|
@write_cb: function for handling writes to this MMIO region.
|
||||||
@user_data_write: user-defined data. This will be passed to @write_cb function in its
|
@user_data_write: user-defined data. This will be passed to @write_cb function
|
||||||
last argument @user_data
|
in its last argument @user_data
|
||||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||||
for detailed error).
|
for detailed error).
|
||||||
*/
|
*/
|
||||||
|
@ -698,9 +738,11 @@ uc_err uc_mmio_map(uc_engine *uc, uint64_t address, size_t size,
|
||||||
|
|
||||||
@uc: handle returned by uc_open()
|
@uc: handle returned by uc_open()
|
||||||
@address: starting address of the memory region to be unmapped.
|
@address: starting address of the memory region to be unmapped.
|
||||||
This address must be aligned to 4KB, or this will return with UC_ERR_ARG error.
|
This address must be aligned to 4KB, or this will return with UC_ERR_ARG
|
||||||
|
error.
|
||||||
@size: size of the memory region to be modified.
|
@size: size of the memory region to be modified.
|
||||||
This size must be multiple of 4KB, or this will return with UC_ERR_ARG error.
|
This size must be multiple of 4KB, or this will return with UC_ERR_ARG
|
||||||
|
error.
|
||||||
|
|
||||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||||
for detailed error).
|
for detailed error).
|
||||||
|
@ -714,18 +756,21 @@ uc_err uc_mem_unmap(uc_engine *uc, uint64_t address, size_t size);
|
||||||
|
|
||||||
@uc: handle returned by uc_open()
|
@uc: handle returned by uc_open()
|
||||||
@address: starting address of the memory region to be modified.
|
@address: starting address of the memory region to be modified.
|
||||||
This address must be aligned to 4KB, or this will return with UC_ERR_ARG error.
|
This address must be aligned to 4KB, or this will return with UC_ERR_ARG
|
||||||
|
error.
|
||||||
@size: size of the memory region to be modified.
|
@size: size of the memory region to be modified.
|
||||||
This size must be multiple of 4KB, or this will return with UC_ERR_ARG error.
|
This size must be multiple of 4KB, or this will return with UC_ERR_ARG
|
||||||
|
error.
|
||||||
@perms: New permissions for the mapped region.
|
@perms: New permissions for the mapped region.
|
||||||
This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC,
|
This must be some combination of UC_PROT_READ | UC_PROT_WRITE |
|
||||||
or this will return with UC_ERR_ARG error.
|
UC_PROT_EXEC, or this will return with UC_ERR_ARG error.
|
||||||
|
|
||||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||||
for detailed error).
|
for detailed error).
|
||||||
*/
|
*/
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size, uint32_t perms);
|
uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size,
|
||||||
|
uint32_t perms);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Retrieve all memory regions mapped by uc_mem_map() and uc_mem_map_ptr()
|
Retrieve all memory regions mapped by uc_mem_map() and uc_mem_map_ptr()
|
||||||
|
@ -763,9 +808,9 @@ uc_err uc_context_alloc(uc_engine *uc, uc_context **context);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Free the memory allocated by uc_mem_regions.
|
Free the memory allocated by uc_mem_regions.
|
||||||
WARNING: After Unicorn 1.0.1rc5, the memory allocated by uc_context_alloc should
|
WARNING: After Unicorn 1.0.1rc5, the memory allocated by uc_context_alloc
|
||||||
be free-ed by uc_context_free(). Calling uc_free() may still work, but the result
|
should be free-ed by uc_context_free(). Calling uc_free() may still work, but
|
||||||
is **undefined**.
|
the result is **undefined**.
|
||||||
|
|
||||||
@mem: memory allocated by uc_mem_regions (returned in *regions).
|
@mem: memory allocated by uc_mem_regions (returned in *regions).
|
||||||
|
|
||||||
|
@ -827,7 +872,8 @@ uc_err uc_context_reg_read(uc_context *ctx, int regid, void *value);
|
||||||
for detailed error).
|
for detailed error).
|
||||||
*/
|
*/
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_context_reg_write_batch(uc_context *ctx, int *regs, void *const *vals, int count);
|
uc_err uc_context_reg_write_batch(uc_context *ctx, int *regs, void *const *vals,
|
||||||
|
int count);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Read multiple register values from a context.
|
Read multiple register values from a context.
|
||||||
|
@ -841,7 +887,8 @@ uc_err uc_context_reg_write_batch(uc_context *ctx, int *regs, void *const *vals,
|
||||||
for detailed error).
|
for detailed error).
|
||||||
*/
|
*/
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_context_reg_read_batch(uc_context *ctx, int *regs, void **vals, int count);
|
uc_err uc_context_reg_read_batch(uc_context *ctx, int *regs, void **vals,
|
||||||
|
int count);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Restore the current CPU context from a saved copy.
|
Restore the current CPU context from a saved copy.
|
||||||
|
@ -849,7 +896,8 @@ uc_err uc_context_reg_read_batch(uc_context *ctx, int *regs, void **vals, int co
|
||||||
state saved by uc_context_save().
|
state saved by uc_context_save().
|
||||||
|
|
||||||
@uc: handle returned by uc_open()
|
@uc: handle returned by uc_open()
|
||||||
@context: handle returned by uc_context_alloc that has been used with uc_context_save
|
@context: handle returned by uc_context_alloc that has been used with
|
||||||
|
uc_context_save
|
||||||
|
|
||||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||||
for detailed error).
|
for detailed error).
|
||||||
|
@ -857,10 +905,9 @@ uc_err uc_context_reg_read_batch(uc_context *ctx, int *regs, void **vals, int co
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_context_restore(uc_engine *uc, uc_context *context);
|
uc_err uc_context_restore(uc_engine *uc, uc_context *context);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Return the size needed to store the cpu context. Can be used to allocate a buffer
|
Return the size needed to store the cpu context. Can be used to allocate a
|
||||||
to contain the cpu context and directly call uc_context_save.
|
buffer to contain the cpu context and directly call uc_context_save.
|
||||||
|
|
||||||
@uc: handle returned by uc_open()
|
@uc: handle returned by uc_open()
|
||||||
|
|
||||||
|
@ -869,7 +916,6 @@ uc_err uc_context_restore(uc_engine *uc, uc_context *context);
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
size_t uc_context_size(uc_engine *uc);
|
size_t uc_context_size(uc_engine *uc);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Free the context allocated by uc_context_alloc().
|
Free the context allocated by uc_context_alloc().
|
||||||
|
|
||||||
|
|
|
@ -22,8 +22,8 @@ typedef struct uc_x86_mmr {
|
||||||
uint32_t flags; /* not used by GDTR and IDTR */
|
uint32_t flags; /* not used by GDTR and IDTR */
|
||||||
} uc_x86_mmr;
|
} uc_x86_mmr;
|
||||||
|
|
||||||
// Model-Specific Register structure, use this with UC_X86_REG_MSR (as the register ID) in
|
// Model-Specific Register structure, use this with UC_X86_REG_MSR (as the
|
||||||
// call to uc_reg_write/uc_reg_read() to manipulate MSRs.
|
// register ID) in call to uc_reg_write/uc_reg_read() to manipulate MSRs.
|
||||||
typedef struct uc_x86_msr {
|
typedef struct uc_x86_msr {
|
||||||
uint32_t rid; // MSR id
|
uint32_t rid; // MSR id
|
||||||
uint64_t value; // MSR value
|
uint64_t value; // MSR value
|
||||||
|
@ -36,53 +36,232 @@ typedef void (*uc_cb_insn_syscall_t)(struct uc_struct *uc, void *user_data);
|
||||||
//> X86 registers
|
//> X86 registers
|
||||||
typedef enum uc_x86_reg {
|
typedef enum uc_x86_reg {
|
||||||
UC_X86_REG_INVALID = 0,
|
UC_X86_REG_INVALID = 0,
|
||||||
UC_X86_REG_AH, UC_X86_REG_AL, UC_X86_REG_AX, UC_X86_REG_BH, UC_X86_REG_BL,
|
UC_X86_REG_AH,
|
||||||
UC_X86_REG_BP, UC_X86_REG_BPL, UC_X86_REG_BX, UC_X86_REG_CH, UC_X86_REG_CL,
|
UC_X86_REG_AL,
|
||||||
UC_X86_REG_CS, UC_X86_REG_CX, UC_X86_REG_DH, UC_X86_REG_DI, UC_X86_REG_DIL,
|
UC_X86_REG_AX,
|
||||||
UC_X86_REG_DL, UC_X86_REG_DS, UC_X86_REG_DX, UC_X86_REG_EAX, UC_X86_REG_EBP,
|
UC_X86_REG_BH,
|
||||||
UC_X86_REG_EBX, UC_X86_REG_ECX, UC_X86_REG_EDI, UC_X86_REG_EDX, UC_X86_REG_EFLAGS,
|
UC_X86_REG_BL,
|
||||||
UC_X86_REG_EIP, UC_X86_REG_ES, UC_X86_REG_ESI, UC_X86_REG_ESP,
|
UC_X86_REG_BP,
|
||||||
UC_X86_REG_FPSW, UC_X86_REG_FS, UC_X86_REG_GS, UC_X86_REG_IP, UC_X86_REG_RAX,
|
UC_X86_REG_BPL,
|
||||||
UC_X86_REG_RBP, UC_X86_REG_RBX, UC_X86_REG_RCX, UC_X86_REG_RDI, UC_X86_REG_RDX,
|
UC_X86_REG_BX,
|
||||||
UC_X86_REG_RIP, UC_X86_REG_RSI, UC_X86_REG_RSP, UC_X86_REG_SI,
|
UC_X86_REG_CH,
|
||||||
UC_X86_REG_SIL, UC_X86_REG_SP, UC_X86_REG_SPL, UC_X86_REG_SS, UC_X86_REG_CR0,
|
UC_X86_REG_CL,
|
||||||
UC_X86_REG_CR1, UC_X86_REG_CR2, UC_X86_REG_CR3, UC_X86_REG_CR4, UC_X86_REG_CR8,
|
UC_X86_REG_CS,
|
||||||
UC_X86_REG_DR0, UC_X86_REG_DR1, UC_X86_REG_DR2, UC_X86_REG_DR3, UC_X86_REG_DR4,
|
UC_X86_REG_CX,
|
||||||
UC_X86_REG_DR5, UC_X86_REG_DR6, UC_X86_REG_DR7, UC_X86_REG_FP0, UC_X86_REG_FP1,
|
UC_X86_REG_DH,
|
||||||
UC_X86_REG_FP2, UC_X86_REG_FP3,
|
UC_X86_REG_DI,
|
||||||
UC_X86_REG_FP4, UC_X86_REG_FP5, UC_X86_REG_FP6, UC_X86_REG_FP7,
|
UC_X86_REG_DIL,
|
||||||
UC_X86_REG_K0, UC_X86_REG_K1, UC_X86_REG_K2, UC_X86_REG_K3, UC_X86_REG_K4,
|
UC_X86_REG_DL,
|
||||||
UC_X86_REG_K5, UC_X86_REG_K6, UC_X86_REG_K7, UC_X86_REG_MM0, UC_X86_REG_MM1,
|
UC_X86_REG_DS,
|
||||||
UC_X86_REG_MM2, UC_X86_REG_MM3, UC_X86_REG_MM4, UC_X86_REG_MM5, UC_X86_REG_MM6,
|
UC_X86_REG_DX,
|
||||||
UC_X86_REG_MM7, UC_X86_REG_R8, UC_X86_REG_R9, UC_X86_REG_R10, UC_X86_REG_R11,
|
UC_X86_REG_EAX,
|
||||||
UC_X86_REG_R12, UC_X86_REG_R13, UC_X86_REG_R14, UC_X86_REG_R15,
|
UC_X86_REG_EBP,
|
||||||
UC_X86_REG_ST0, UC_X86_REG_ST1, UC_X86_REG_ST2, UC_X86_REG_ST3,
|
UC_X86_REG_EBX,
|
||||||
UC_X86_REG_ST4, UC_X86_REG_ST5, UC_X86_REG_ST6, UC_X86_REG_ST7,
|
UC_X86_REG_ECX,
|
||||||
UC_X86_REG_XMM0, UC_X86_REG_XMM1, UC_X86_REG_XMM2, UC_X86_REG_XMM3, UC_X86_REG_XMM4,
|
UC_X86_REG_EDI,
|
||||||
UC_X86_REG_XMM5, UC_X86_REG_XMM6, UC_X86_REG_XMM7, UC_X86_REG_XMM8, UC_X86_REG_XMM9,
|
UC_X86_REG_EDX,
|
||||||
UC_X86_REG_XMM10, UC_X86_REG_XMM11, UC_X86_REG_XMM12, UC_X86_REG_XMM13, UC_X86_REG_XMM14,
|
UC_X86_REG_EFLAGS,
|
||||||
UC_X86_REG_XMM15, UC_X86_REG_XMM16, UC_X86_REG_XMM17, UC_X86_REG_XMM18, UC_X86_REG_XMM19,
|
UC_X86_REG_EIP,
|
||||||
UC_X86_REG_XMM20, UC_X86_REG_XMM21, UC_X86_REG_XMM22, UC_X86_REG_XMM23, UC_X86_REG_XMM24,
|
UC_X86_REG_ES,
|
||||||
UC_X86_REG_XMM25, UC_X86_REG_XMM26, UC_X86_REG_XMM27, UC_X86_REG_XMM28, UC_X86_REG_XMM29,
|
UC_X86_REG_ESI,
|
||||||
UC_X86_REG_XMM30, UC_X86_REG_XMM31, UC_X86_REG_YMM0, UC_X86_REG_YMM1, UC_X86_REG_YMM2,
|
UC_X86_REG_ESP,
|
||||||
UC_X86_REG_YMM3, UC_X86_REG_YMM4, UC_X86_REG_YMM5, UC_X86_REG_YMM6, UC_X86_REG_YMM7,
|
UC_X86_REG_FPSW,
|
||||||
UC_X86_REG_YMM8, UC_X86_REG_YMM9, UC_X86_REG_YMM10, UC_X86_REG_YMM11, UC_X86_REG_YMM12,
|
UC_X86_REG_FS,
|
||||||
UC_X86_REG_YMM13, UC_X86_REG_YMM14, UC_X86_REG_YMM15, UC_X86_REG_YMM16, UC_X86_REG_YMM17,
|
UC_X86_REG_GS,
|
||||||
UC_X86_REG_YMM18, UC_X86_REG_YMM19, UC_X86_REG_YMM20, UC_X86_REG_YMM21, UC_X86_REG_YMM22,
|
UC_X86_REG_IP,
|
||||||
UC_X86_REG_YMM23, UC_X86_REG_YMM24, UC_X86_REG_YMM25, UC_X86_REG_YMM26, UC_X86_REG_YMM27,
|
UC_X86_REG_RAX,
|
||||||
UC_X86_REG_YMM28, UC_X86_REG_YMM29, UC_X86_REG_YMM30, UC_X86_REG_YMM31, UC_X86_REG_ZMM0,
|
UC_X86_REG_RBP,
|
||||||
UC_X86_REG_ZMM1, UC_X86_REG_ZMM2, UC_X86_REG_ZMM3, UC_X86_REG_ZMM4, UC_X86_REG_ZMM5,
|
UC_X86_REG_RBX,
|
||||||
UC_X86_REG_ZMM6, UC_X86_REG_ZMM7, UC_X86_REG_ZMM8, UC_X86_REG_ZMM9, UC_X86_REG_ZMM10,
|
UC_X86_REG_RCX,
|
||||||
UC_X86_REG_ZMM11, UC_X86_REG_ZMM12, UC_X86_REG_ZMM13, UC_X86_REG_ZMM14, UC_X86_REG_ZMM15,
|
UC_X86_REG_RDI,
|
||||||
UC_X86_REG_ZMM16, UC_X86_REG_ZMM17, UC_X86_REG_ZMM18, UC_X86_REG_ZMM19, UC_X86_REG_ZMM20,
|
UC_X86_REG_RDX,
|
||||||
UC_X86_REG_ZMM21, UC_X86_REG_ZMM22, UC_X86_REG_ZMM23, UC_X86_REG_ZMM24, UC_X86_REG_ZMM25,
|
UC_X86_REG_RIP,
|
||||||
UC_X86_REG_ZMM26, UC_X86_REG_ZMM27, UC_X86_REG_ZMM28, UC_X86_REG_ZMM29, UC_X86_REG_ZMM30,
|
UC_X86_REG_RSI,
|
||||||
UC_X86_REG_ZMM31, UC_X86_REG_R8B, UC_X86_REG_R9B, UC_X86_REG_R10B, UC_X86_REG_R11B,
|
UC_X86_REG_RSP,
|
||||||
UC_X86_REG_R12B, UC_X86_REG_R13B, UC_X86_REG_R14B, UC_X86_REG_R15B, UC_X86_REG_R8D,
|
UC_X86_REG_SI,
|
||||||
UC_X86_REG_R9D, UC_X86_REG_R10D, UC_X86_REG_R11D, UC_X86_REG_R12D, UC_X86_REG_R13D,
|
UC_X86_REG_SIL,
|
||||||
UC_X86_REG_R14D, UC_X86_REG_R15D, UC_X86_REG_R8W, UC_X86_REG_R9W, UC_X86_REG_R10W,
|
UC_X86_REG_SP,
|
||||||
UC_X86_REG_R11W, UC_X86_REG_R12W, UC_X86_REG_R13W, UC_X86_REG_R14W, UC_X86_REG_R15W,
|
UC_X86_REG_SPL,
|
||||||
UC_X86_REG_IDTR, UC_X86_REG_GDTR, UC_X86_REG_LDTR, UC_X86_REG_TR, UC_X86_REG_FPCW,
|
UC_X86_REG_SS,
|
||||||
|
UC_X86_REG_CR0,
|
||||||
|
UC_X86_REG_CR1,
|
||||||
|
UC_X86_REG_CR2,
|
||||||
|
UC_X86_REG_CR3,
|
||||||
|
UC_X86_REG_CR4,
|
||||||
|
UC_X86_REG_CR8,
|
||||||
|
UC_X86_REG_DR0,
|
||||||
|
UC_X86_REG_DR1,
|
||||||
|
UC_X86_REG_DR2,
|
||||||
|
UC_X86_REG_DR3,
|
||||||
|
UC_X86_REG_DR4,
|
||||||
|
UC_X86_REG_DR5,
|
||||||
|
UC_X86_REG_DR6,
|
||||||
|
UC_X86_REG_DR7,
|
||||||
|
UC_X86_REG_FP0,
|
||||||
|
UC_X86_REG_FP1,
|
||||||
|
UC_X86_REG_FP2,
|
||||||
|
UC_X86_REG_FP3,
|
||||||
|
UC_X86_REG_FP4,
|
||||||
|
UC_X86_REG_FP5,
|
||||||
|
UC_X86_REG_FP6,
|
||||||
|
UC_X86_REG_FP7,
|
||||||
|
UC_X86_REG_K0,
|
||||||
|
UC_X86_REG_K1,
|
||||||
|
UC_X86_REG_K2,
|
||||||
|
UC_X86_REG_K3,
|
||||||
|
UC_X86_REG_K4,
|
||||||
|
UC_X86_REG_K5,
|
||||||
|
UC_X86_REG_K6,
|
||||||
|
UC_X86_REG_K7,
|
||||||
|
UC_X86_REG_MM0,
|
||||||
|
UC_X86_REG_MM1,
|
||||||
|
UC_X86_REG_MM2,
|
||||||
|
UC_X86_REG_MM3,
|
||||||
|
UC_X86_REG_MM4,
|
||||||
|
UC_X86_REG_MM5,
|
||||||
|
UC_X86_REG_MM6,
|
||||||
|
UC_X86_REG_MM7,
|
||||||
|
UC_X86_REG_R8,
|
||||||
|
UC_X86_REG_R9,
|
||||||
|
UC_X86_REG_R10,
|
||||||
|
UC_X86_REG_R11,
|
||||||
|
UC_X86_REG_R12,
|
||||||
|
UC_X86_REG_R13,
|
||||||
|
UC_X86_REG_R14,
|
||||||
|
UC_X86_REG_R15,
|
||||||
|
UC_X86_REG_ST0,
|
||||||
|
UC_X86_REG_ST1,
|
||||||
|
UC_X86_REG_ST2,
|
||||||
|
UC_X86_REG_ST3,
|
||||||
|
UC_X86_REG_ST4,
|
||||||
|
UC_X86_REG_ST5,
|
||||||
|
UC_X86_REG_ST6,
|
||||||
|
UC_X86_REG_ST7,
|
||||||
|
UC_X86_REG_XMM0,
|
||||||
|
UC_X86_REG_XMM1,
|
||||||
|
UC_X86_REG_XMM2,
|
||||||
|
UC_X86_REG_XMM3,
|
||||||
|
UC_X86_REG_XMM4,
|
||||||
|
UC_X86_REG_XMM5,
|
||||||
|
UC_X86_REG_XMM6,
|
||||||
|
UC_X86_REG_XMM7,
|
||||||
|
UC_X86_REG_XMM8,
|
||||||
|
UC_X86_REG_XMM9,
|
||||||
|
UC_X86_REG_XMM10,
|
||||||
|
UC_X86_REG_XMM11,
|
||||||
|
UC_X86_REG_XMM12,
|
||||||
|
UC_X86_REG_XMM13,
|
||||||
|
UC_X86_REG_XMM14,
|
||||||
|
UC_X86_REG_XMM15,
|
||||||
|
UC_X86_REG_XMM16,
|
||||||
|
UC_X86_REG_XMM17,
|
||||||
|
UC_X86_REG_XMM18,
|
||||||
|
UC_X86_REG_XMM19,
|
||||||
|
UC_X86_REG_XMM20,
|
||||||
|
UC_X86_REG_XMM21,
|
||||||
|
UC_X86_REG_XMM22,
|
||||||
|
UC_X86_REG_XMM23,
|
||||||
|
UC_X86_REG_XMM24,
|
||||||
|
UC_X86_REG_XMM25,
|
||||||
|
UC_X86_REG_XMM26,
|
||||||
|
UC_X86_REG_XMM27,
|
||||||
|
UC_X86_REG_XMM28,
|
||||||
|
UC_X86_REG_XMM29,
|
||||||
|
UC_X86_REG_XMM30,
|
||||||
|
UC_X86_REG_XMM31,
|
||||||
|
UC_X86_REG_YMM0,
|
||||||
|
UC_X86_REG_YMM1,
|
||||||
|
UC_X86_REG_YMM2,
|
||||||
|
UC_X86_REG_YMM3,
|
||||||
|
UC_X86_REG_YMM4,
|
||||||
|
UC_X86_REG_YMM5,
|
||||||
|
UC_X86_REG_YMM6,
|
||||||
|
UC_X86_REG_YMM7,
|
||||||
|
UC_X86_REG_YMM8,
|
||||||
|
UC_X86_REG_YMM9,
|
||||||
|
UC_X86_REG_YMM10,
|
||||||
|
UC_X86_REG_YMM11,
|
||||||
|
UC_X86_REG_YMM12,
|
||||||
|
UC_X86_REG_YMM13,
|
||||||
|
UC_X86_REG_YMM14,
|
||||||
|
UC_X86_REG_YMM15,
|
||||||
|
UC_X86_REG_YMM16,
|
||||||
|
UC_X86_REG_YMM17,
|
||||||
|
UC_X86_REG_YMM18,
|
||||||
|
UC_X86_REG_YMM19,
|
||||||
|
UC_X86_REG_YMM20,
|
||||||
|
UC_X86_REG_YMM21,
|
||||||
|
UC_X86_REG_YMM22,
|
||||||
|
UC_X86_REG_YMM23,
|
||||||
|
UC_X86_REG_YMM24,
|
||||||
|
UC_X86_REG_YMM25,
|
||||||
|
UC_X86_REG_YMM26,
|
||||||
|
UC_X86_REG_YMM27,
|
||||||
|
UC_X86_REG_YMM28,
|
||||||
|
UC_X86_REG_YMM29,
|
||||||
|
UC_X86_REG_YMM30,
|
||||||
|
UC_X86_REG_YMM31,
|
||||||
|
UC_X86_REG_ZMM0,
|
||||||
|
UC_X86_REG_ZMM1,
|
||||||
|
UC_X86_REG_ZMM2,
|
||||||
|
UC_X86_REG_ZMM3,
|
||||||
|
UC_X86_REG_ZMM4,
|
||||||
|
UC_X86_REG_ZMM5,
|
||||||
|
UC_X86_REG_ZMM6,
|
||||||
|
UC_X86_REG_ZMM7,
|
||||||
|
UC_X86_REG_ZMM8,
|
||||||
|
UC_X86_REG_ZMM9,
|
||||||
|
UC_X86_REG_ZMM10,
|
||||||
|
UC_X86_REG_ZMM11,
|
||||||
|
UC_X86_REG_ZMM12,
|
||||||
|
UC_X86_REG_ZMM13,
|
||||||
|
UC_X86_REG_ZMM14,
|
||||||
|
UC_X86_REG_ZMM15,
|
||||||
|
UC_X86_REG_ZMM16,
|
||||||
|
UC_X86_REG_ZMM17,
|
||||||
|
UC_X86_REG_ZMM18,
|
||||||
|
UC_X86_REG_ZMM19,
|
||||||
|
UC_X86_REG_ZMM20,
|
||||||
|
UC_X86_REG_ZMM21,
|
||||||
|
UC_X86_REG_ZMM22,
|
||||||
|
UC_X86_REG_ZMM23,
|
||||||
|
UC_X86_REG_ZMM24,
|
||||||
|
UC_X86_REG_ZMM25,
|
||||||
|
UC_X86_REG_ZMM26,
|
||||||
|
UC_X86_REG_ZMM27,
|
||||||
|
UC_X86_REG_ZMM28,
|
||||||
|
UC_X86_REG_ZMM29,
|
||||||
|
UC_X86_REG_ZMM30,
|
||||||
|
UC_X86_REG_ZMM31,
|
||||||
|
UC_X86_REG_R8B,
|
||||||
|
UC_X86_REG_R9B,
|
||||||
|
UC_X86_REG_R10B,
|
||||||
|
UC_X86_REG_R11B,
|
||||||
|
UC_X86_REG_R12B,
|
||||||
|
UC_X86_REG_R13B,
|
||||||
|
UC_X86_REG_R14B,
|
||||||
|
UC_X86_REG_R15B,
|
||||||
|
UC_X86_REG_R8D,
|
||||||
|
UC_X86_REG_R9D,
|
||||||
|
UC_X86_REG_R10D,
|
||||||
|
UC_X86_REG_R11D,
|
||||||
|
UC_X86_REG_R12D,
|
||||||
|
UC_X86_REG_R13D,
|
||||||
|
UC_X86_REG_R14D,
|
||||||
|
UC_X86_REG_R15D,
|
||||||
|
UC_X86_REG_R8W,
|
||||||
|
UC_X86_REG_R9W,
|
||||||
|
UC_X86_REG_R10W,
|
||||||
|
UC_X86_REG_R11W,
|
||||||
|
UC_X86_REG_R12W,
|
||||||
|
UC_X86_REG_R13W,
|
||||||
|
UC_X86_REG_R14W,
|
||||||
|
UC_X86_REG_R15W,
|
||||||
|
UC_X86_REG_IDTR,
|
||||||
|
UC_X86_REG_GDTR,
|
||||||
|
UC_X86_REG_LDTR,
|
||||||
|
UC_X86_REG_TR,
|
||||||
|
UC_X86_REG_FPCW,
|
||||||
UC_X86_REG_FPTAG,
|
UC_X86_REG_FPTAG,
|
||||||
UC_X86_REG_MSR, // Model-Specific Register
|
UC_X86_REG_MSR, // Model-Specific Register
|
||||||
UC_X86_REG_MXCSR,
|
UC_X86_REG_MXCSR,
|
||||||
|
|
|
@ -5,26 +5,38 @@
|
||||||
#define UC_QEMU_TARGET_ARM_H
|
#define UC_QEMU_TARGET_ARM_H
|
||||||
|
|
||||||
// functions to read & write registers
|
// functions to read & write registers
|
||||||
int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||||
int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
int count);
|
||||||
int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
int count);
|
||||||
|
int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||||
|
int count);
|
||||||
|
int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
|
int count);
|
||||||
|
|
||||||
int arm_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
int arm_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
int arm_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
void **vals, int count);
|
||||||
int armeb_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
int arm_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
int armeb_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
void *const *vals, int count);
|
||||||
int arm64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
int armeb_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
int arm64_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
void **vals, int count);
|
||||||
int arm64eb_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
int armeb_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
int arm64eb_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
void *const *vals, int count);
|
||||||
|
int arm64_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count);
|
||||||
|
int arm64_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count);
|
||||||
|
int arm64eb_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count);
|
||||||
|
int arm64eb_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count);
|
||||||
|
|
||||||
void arm_reg_reset(struct uc_struct *uc);
|
void arm_reg_reset(struct uc_struct *uc);
|
||||||
void arm64_reg_reset(struct uc_struct *uc);
|
void arm64_reg_reset(struct uc_struct *uc);
|
||||||
|
|
||||||
void arm_uc_init(struct uc_struct* uc);
|
void arm_uc_init(struct uc_struct *uc);
|
||||||
void armeb_uc_init(struct uc_struct* uc);
|
void armeb_uc_init(struct uc_struct *uc);
|
||||||
|
|
||||||
void arm64_uc_init(struct uc_struct* uc);
|
void arm64_uc_init(struct uc_struct *uc);
|
||||||
void arm64eb_uc_init(struct uc_struct* uc);
|
void arm64eb_uc_init(struct uc_struct *uc);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,10 +14,10 @@
|
||||||
#define X86_NON_CS_FLAGS (DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | DESC_A_MASK)
|
#define X86_NON_CS_FLAGS (DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | DESC_A_MASK)
|
||||||
static void load_seg_16_helper(CPUX86State *env, int seg, uint32_t selector)
|
static void load_seg_16_helper(CPUX86State *env, int seg, uint32_t selector)
|
||||||
{
|
{
|
||||||
cpu_x86_load_seg_cache(env, seg, selector, (selector << 4), 0xffff, X86_NON_CS_FLAGS);
|
cpu_x86_load_seg_cache(env, seg, selector, (selector << 4), 0xffff,
|
||||||
|
X86_NON_CS_FLAGS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f);
|
void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f);
|
||||||
floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper);
|
floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper);
|
||||||
|
|
||||||
|
@ -28,7 +28,7 @@ static void x86_set_pc(struct uc_struct *uc, uint64_t address)
|
||||||
{
|
{
|
||||||
if (uc->mode == UC_MODE_16) {
|
if (uc->mode == UC_MODE_16) {
|
||||||
int16_t cs = (uint16_t)X86_CPU(uc->cpu)->env.segs[R_CS].selector;
|
int16_t cs = (uint16_t)X86_CPU(uc->cpu)->env.segs[R_CS].selector;
|
||||||
((CPUX86State *)uc->cpu->env_ptr)->eip = address - cs*16;
|
((CPUX86State *)uc->cpu->env_ptr)->eip = address - cs * 16;
|
||||||
} else
|
} else
|
||||||
((CPUX86State *)uc->cpu->env_ptr)->eip = address;
|
((CPUX86State *)uc->cpu->env_ptr)->eip = address;
|
||||||
}
|
}
|
||||||
|
@ -59,11 +59,16 @@ void x86_reg_reset(struct uc_struct *uc)
|
||||||
{
|
{
|
||||||
CPUArchState *env = uc->cpu->env_ptr;
|
CPUArchState *env = uc->cpu->env_ptr;
|
||||||
|
|
||||||
env->features[FEAT_1_EDX] = CPUID_CX8 | CPUID_CMOV | CPUID_SSE2 | CPUID_FXSR | CPUID_SSE | CPUID_CLFLUSH;
|
env->features[FEAT_1_EDX] = CPUID_CX8 | CPUID_CMOV | CPUID_SSE2 |
|
||||||
env->features[FEAT_1_ECX] = CPUID_EXT_SSSE3 | CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_AES | CPUID_EXT_CX16;
|
CPUID_FXSR | CPUID_SSE | CPUID_CLFLUSH;
|
||||||
|
env->features[FEAT_1_ECX] = CPUID_EXT_SSSE3 | CPUID_EXT_SSE41 |
|
||||||
|
CPUID_EXT_SSE42 | CPUID_EXT_AES |
|
||||||
|
CPUID_EXT_CX16;
|
||||||
env->features[FEAT_8000_0001_EDX] = CPUID_EXT2_3DNOW | CPUID_EXT2_RDTSCP;
|
env->features[FEAT_8000_0001_EDX] = CPUID_EXT2_3DNOW | CPUID_EXT2_RDTSCP;
|
||||||
env->features[FEAT_8000_0001_ECX] = CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | CPUID_EXT3_SKINIT | CPUID_EXT3_CR8LEG;
|
env->features[FEAT_8000_0001_ECX] = CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM |
|
||||||
env->features[FEAT_7_0_EBX] = CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP;
|
CPUID_EXT3_SKINIT | CPUID_EXT3_CR8LEG;
|
||||||
|
env->features[FEAT_7_0_EBX] = CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 |
|
||||||
|
CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP;
|
||||||
|
|
||||||
memset(env->regs, 0, sizeof(env->regs));
|
memset(env->regs, 0, sizeof(env->regs));
|
||||||
memset(env->segs, 0, sizeof(env->segs));
|
memset(env->segs, 0, sizeof(env->segs));
|
||||||
|
@ -129,18 +134,18 @@ void x86_reg_reset(struct uc_struct *uc)
|
||||||
// TODO: reset other registers in CPUX86State qemu/target-i386/cpu.h
|
// TODO: reset other registers in CPUX86State qemu/target-i386/cpu.h
|
||||||
|
|
||||||
// properly initialize internal setup for each mode
|
// properly initialize internal setup for each mode
|
||||||
switch(uc->mode) {
|
switch (uc->mode) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case UC_MODE_16:
|
case UC_MODE_16:
|
||||||
env->hflags = 0;
|
env->hflags = 0;
|
||||||
env->cr[0] = 0;
|
env->cr[0] = 0;
|
||||||
//undo the damage done by the memset of env->segs above
|
// undo the damage done by the memset of env->segs above
|
||||||
//for R_CS, not quite the same as x86_cpu_reset
|
// for R_CS, not quite the same as x86_cpu_reset
|
||||||
cpu_x86_load_seg_cache(env, R_CS, 0, 0, 0xffff,
|
cpu_x86_load_seg_cache(env, R_CS, 0, 0, 0xffff,
|
||||||
DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
|
DESC_P_MASK | DESC_S_MASK | DESC_CS_MASK |
|
||||||
DESC_R_MASK | DESC_A_MASK);
|
DESC_R_MASK | DESC_A_MASK);
|
||||||
//remainder yields same state as x86_cpu_reset
|
// remainder yields same state as x86_cpu_reset
|
||||||
load_seg_16_helper(env, R_DS, 0);
|
load_seg_16_helper(env, R_DS, 0);
|
||||||
load_seg_16_helper(env, R_ES, 0);
|
load_seg_16_helper(env, R_ES, 0);
|
||||||
load_seg_16_helper(env, R_SS, 0);
|
load_seg_16_helper(env, R_SS, 0);
|
||||||
|
@ -153,7 +158,8 @@ void x86_reg_reset(struct uc_struct *uc)
|
||||||
cpu_x86_update_cr0(env, CR0_PE_MASK); // protected mode
|
cpu_x86_update_cr0(env, CR0_PE_MASK); // protected mode
|
||||||
break;
|
break;
|
||||||
case UC_MODE_64:
|
case UC_MODE_64:
|
||||||
env->hflags |= HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK | HF_LMA_MASK | HF_OSFXSR_MASK;
|
env->hflags |= HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK |
|
||||||
|
HF_LMA_MASK | HF_OSFXSR_MASK;
|
||||||
env->hflags &= ~(HF_ADDSEG_MASK);
|
env->hflags &= ~(HF_ADDSEG_MASK);
|
||||||
env->efer |= MSR_EFER_LMA | MSR_EFER_LME; // extended mode activated
|
env->efer |= MSR_EFER_LMA | MSR_EFER_LME; // extended mode activated
|
||||||
cpu_x86_update_cr0(env, CR0_PE_MASK); // protected mode
|
cpu_x86_update_cr0(env, CR0_PE_MASK); // protected mode
|
||||||
|
@ -181,8 +187,8 @@ static int x86_msr_read(CPUX86State *env, uc_x86_msr *msr)
|
||||||
env->regs[R_ECX] = ecx;
|
env->regs[R_ECX] = ecx;
|
||||||
env->regs[R_EDX] = edx;
|
env->regs[R_EDX] = edx;
|
||||||
|
|
||||||
/* The implementation doesn't throw exception or return an error if there is one, so
|
/* The implementation doesn't throw exception or return an error if there is
|
||||||
* we will return 0. */
|
* one, so we will return 0. */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,14 +207,15 @@ static int x86_msr_write(CPUX86State *env, uc_x86_msr *msr)
|
||||||
env->regs[R_EAX] = eax;
|
env->regs[R_EAX] = eax;
|
||||||
env->regs[R_EDX] = edx;
|
env->regs[R_EDX] = edx;
|
||||||
|
|
||||||
/* The implementation doesn't throw exception or return an error if there is one, so
|
/* The implementation doesn't throw exception or return an error if there is
|
||||||
* we will return 0. */
|
* one, so we will return 0. */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode mode)
|
static void reg_read(CPUX86State *env, unsigned int regid, void *value,
|
||||||
|
uc_mode mode)
|
||||||
{
|
{
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_FP0:
|
case UC_X86_REG_FP0:
|
||||||
|
@ -218,28 +225,26 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode
|
||||||
case UC_X86_REG_FP4:
|
case UC_X86_REG_FP4:
|
||||||
case UC_X86_REG_FP5:
|
case UC_X86_REG_FP5:
|
||||||
case UC_X86_REG_FP6:
|
case UC_X86_REG_FP6:
|
||||||
case UC_X86_REG_FP7:
|
case UC_X86_REG_FP7: {
|
||||||
{
|
|
||||||
floatx80 reg = env->fpregs[regid - UC_X86_REG_FP0].d;
|
floatx80 reg = env->fpregs[regid - UC_X86_REG_FP0].d;
|
||||||
cpu_get_fp80(value, (uint16_t*)((char*)value+sizeof(uint64_t)), reg);
|
cpu_get_fp80(value, (uint16_t *)((char *)value + sizeof(uint64_t)),
|
||||||
|
reg);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case UC_X86_REG_FPSW:
|
case UC_X86_REG_FPSW: {
|
||||||
{
|
|
||||||
uint16_t fpus = env->fpus;
|
uint16_t fpus = env->fpus;
|
||||||
fpus = fpus & ~0x3800;
|
fpus = fpus & ~0x3800;
|
||||||
fpus |= ( env->fpstt & 0x7 ) << 11;
|
fpus |= (env->fpstt & 0x7) << 11;
|
||||||
*(uint16_t*) value = fpus;
|
*(uint16_t *)value = fpus;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case UC_X86_REG_FPCW:
|
case UC_X86_REG_FPCW:
|
||||||
*(uint16_t*) value = env->fpuc;
|
*(uint16_t *)value = env->fpuc;
|
||||||
return;
|
return;
|
||||||
case UC_X86_REG_FPTAG:
|
case UC_X86_REG_FPTAG: {
|
||||||
{
|
#define EXPD(fp) (fp.l.upper & 0x7fff)
|
||||||
#define EXPD(fp) (fp.l.upper & 0x7fff)
|
#define MANTD(fp) (fp.l.lower)
|
||||||
#define MANTD(fp) (fp.l.lower)
|
#define MAXEXPD 0x7fff
|
||||||
#define MAXEXPD 0x7fff
|
|
||||||
int fptag, exp, i;
|
int fptag, exp, i;
|
||||||
uint64_t mant;
|
uint64_t mant;
|
||||||
CPU_LDoubleU tmp;
|
CPU_LDoubleU tmp;
|
||||||
|
@ -255,14 +260,14 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode
|
||||||
if (exp == 0 && mant == 0) {
|
if (exp == 0 && mant == 0) {
|
||||||
/* zero */
|
/* zero */
|
||||||
fptag |= 1;
|
fptag |= 1;
|
||||||
} else if (exp == 0 || exp == MAXEXPD
|
} else if (exp == 0 || exp == MAXEXPD ||
|
||||||
|| (mant & (1LL << 63)) == 0) {
|
(mant & (1LL << 63)) == 0) {
|
||||||
/* NaNs, infinity, denormal */
|
/* NaNs, infinity, denormal */
|
||||||
fptag |= 2;
|
fptag |= 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*(uint16_t*) value = fptag;
|
*(uint16_t *)value = fptag;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case UC_X86_REG_XMM0:
|
case UC_X86_REG_XMM0:
|
||||||
|
@ -272,9 +277,8 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode
|
||||||
case UC_X86_REG_XMM4:
|
case UC_X86_REG_XMM4:
|
||||||
case UC_X86_REG_XMM5:
|
case UC_X86_REG_XMM5:
|
||||||
case UC_X86_REG_XMM6:
|
case UC_X86_REG_XMM6:
|
||||||
case UC_X86_REG_XMM7:
|
case UC_X86_REG_XMM7: {
|
||||||
{
|
float64 *dst = (float64 *)value;
|
||||||
float64 *dst = (float64*)value;
|
|
||||||
XMMReg *reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
|
XMMReg *reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
|
||||||
dst[0] = reg->_d[0];
|
dst[0] = reg->_d[0];
|
||||||
dst[1] = reg->_d[1];
|
dst[1] = reg->_d[1];
|
||||||
|
@ -287,8 +291,7 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode
|
||||||
case UC_X86_REG_ST4:
|
case UC_X86_REG_ST4:
|
||||||
case UC_X86_REG_ST5:
|
case UC_X86_REG_ST5:
|
||||||
case UC_X86_REG_ST6:
|
case UC_X86_REG_ST6:
|
||||||
case UC_X86_REG_ST7:
|
case UC_X86_REG_ST7: {
|
||||||
{
|
|
||||||
// value must be big enough to keep 80 bits (10 bytes)
|
// value must be big enough to keep 80 bits (10 bytes)
|
||||||
memcpy(value, &FPST(regid - UC_X86_REG_ST0), 10);
|
memcpy(value, &FPST(regid - UC_X86_REG_ST0), 10);
|
||||||
return;
|
return;
|
||||||
|
@ -308,9 +311,8 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode
|
||||||
case UC_X86_REG_YMM12:
|
case UC_X86_REG_YMM12:
|
||||||
case UC_X86_REG_YMM13:
|
case UC_X86_REG_YMM13:
|
||||||
case UC_X86_REG_YMM14:
|
case UC_X86_REG_YMM14:
|
||||||
case UC_X86_REG_YMM15:
|
case UC_X86_REG_YMM15: {
|
||||||
{
|
float64 *dst = (float64 *)value;
|
||||||
float64 *dst = (float64*)value;
|
|
||||||
XMMReg *lo_reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_YMM0];
|
XMMReg *lo_reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_YMM0];
|
||||||
XMMReg *hi_reg = &env->ymmh_regs[regid - UC_X86_REG_YMM0];
|
XMMReg *hi_reg = &env->ymmh_regs[regid - UC_X86_REG_YMM0];
|
||||||
dst[0] = lo_reg->_d[0];
|
dst[0] = lo_reg->_d[0];
|
||||||
|
@ -321,12 +323,13 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(mode) {
|
switch (mode) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case UC_MODE_16:
|
case UC_MODE_16:
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
default: break;
|
default:
|
||||||
|
break;
|
||||||
case UC_X86_REG_ES:
|
case UC_X86_REG_ES:
|
||||||
*(int16_t *)value = env->segs[R_ES].selector;
|
*(int16_t *)value = env->segs[R_ES].selector;
|
||||||
return;
|
return;
|
||||||
|
@ -348,7 +351,7 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode
|
||||||
}
|
}
|
||||||
// fall-thru
|
// fall-thru
|
||||||
case UC_MODE_32:
|
case UC_MODE_32:
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_CR0:
|
case UC_X86_REG_CR0:
|
||||||
|
@ -504,7 +507,7 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode
|
||||||
|
|
||||||
#ifdef TARGET_X86_64
|
#ifdef TARGET_X86_64
|
||||||
case UC_MODE_64:
|
case UC_MODE_64:
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_CR0:
|
case UC_X86_REG_CR0:
|
||||||
|
@ -797,9 +800,8 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode
|
||||||
case UC_X86_REG_XMM12:
|
case UC_X86_REG_XMM12:
|
||||||
case UC_X86_REG_XMM13:
|
case UC_X86_REG_XMM13:
|
||||||
case UC_X86_REG_XMM14:
|
case UC_X86_REG_XMM14:
|
||||||
case UC_X86_REG_XMM15:
|
case UC_X86_REG_XMM15: {
|
||||||
{
|
float64 *dst = (float64 *)value;
|
||||||
float64 *dst = (float64*)value;
|
|
||||||
XMMReg *reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
|
XMMReg *reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
|
||||||
dst[0] = reg->_d[0];
|
dst[0] = reg->_d[0];
|
||||||
dst[1] = reg->_d[1];
|
dst[1] = reg->_d[1];
|
||||||
|
@ -819,11 +821,12 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc_mode mode)
|
static int reg_write(CPUX86State *env, unsigned int regid, const void *value,
|
||||||
|
uc_mode mode)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_FP0:
|
case UC_X86_REG_FP0:
|
||||||
|
@ -833,16 +836,14 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
|
||||||
case UC_X86_REG_FP4:
|
case UC_X86_REG_FP4:
|
||||||
case UC_X86_REG_FP5:
|
case UC_X86_REG_FP5:
|
||||||
case UC_X86_REG_FP6:
|
case UC_X86_REG_FP6:
|
||||||
case UC_X86_REG_FP7:
|
case UC_X86_REG_FP7: {
|
||||||
{
|
uint64_t mant = *(uint64_t *)value;
|
||||||
uint64_t mant = *(uint64_t*) value;
|
uint16_t upper = *(uint16_t *)((char *)value + sizeof(uint64_t));
|
||||||
uint16_t upper = *(uint16_t*) ((char*)value + sizeof(uint64_t));
|
|
||||||
env->fpregs[regid - UC_X86_REG_FP0].d = cpu_set_fp80(mant, upper);
|
env->fpregs[regid - UC_X86_REG_FP0].d = cpu_set_fp80(mant, upper);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
case UC_X86_REG_FPSW:
|
case UC_X86_REG_FPSW: {
|
||||||
{
|
uint16_t fpus = *(uint16_t *)value;
|
||||||
uint16_t fpus = *(uint16_t*) value;
|
|
||||||
env->fpus = fpus & ~0x3800;
|
env->fpus = fpus & ~0x3800;
|
||||||
env->fpstt = (fpus >> 11) & 0x7;
|
env->fpstt = (fpus >> 11) & 0x7;
|
||||||
}
|
}
|
||||||
|
@ -850,18 +851,16 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
|
||||||
case UC_X86_REG_FPCW:
|
case UC_X86_REG_FPCW:
|
||||||
cpu_set_fpuc(env, *(uint16_t *)value);
|
cpu_set_fpuc(env, *(uint16_t *)value);
|
||||||
return 0;
|
return 0;
|
||||||
case UC_X86_REG_FPTAG:
|
case UC_X86_REG_FPTAG: {
|
||||||
{
|
|
||||||
int i;
|
int i;
|
||||||
uint16_t fptag = *(uint16_t*) value;
|
uint16_t fptag = *(uint16_t *)value;
|
||||||
for (i = 0; i < 8; i++) {
|
for (i = 0; i < 8; i++) {
|
||||||
env->fptags[i] = ((fptag & 3) == 3);
|
env->fptags[i] = ((fptag & 3) == 3);
|
||||||
fptag >>= 2;
|
fptag >>= 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
} break;
|
||||||
break;
|
|
||||||
case UC_X86_REG_XMM0:
|
case UC_X86_REG_XMM0:
|
||||||
case UC_X86_REG_XMM1:
|
case UC_X86_REG_XMM1:
|
||||||
case UC_X86_REG_XMM2:
|
case UC_X86_REG_XMM2:
|
||||||
|
@ -869,9 +868,8 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
|
||||||
case UC_X86_REG_XMM4:
|
case UC_X86_REG_XMM4:
|
||||||
case UC_X86_REG_XMM5:
|
case UC_X86_REG_XMM5:
|
||||||
case UC_X86_REG_XMM6:
|
case UC_X86_REG_XMM6:
|
||||||
case UC_X86_REG_XMM7:
|
case UC_X86_REG_XMM7: {
|
||||||
{
|
float64 *src = (float64 *)value;
|
||||||
float64 *src = (float64*)value;
|
|
||||||
XMMReg *reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
|
XMMReg *reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
|
||||||
reg->_d[0] = src[0];
|
reg->_d[0] = src[0];
|
||||||
reg->_d[1] = src[1];
|
reg->_d[1] = src[1];
|
||||||
|
@ -884,8 +882,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
|
||||||
case UC_X86_REG_ST4:
|
case UC_X86_REG_ST4:
|
||||||
case UC_X86_REG_ST5:
|
case UC_X86_REG_ST5:
|
||||||
case UC_X86_REG_ST6:
|
case UC_X86_REG_ST6:
|
||||||
case UC_X86_REG_ST7:
|
case UC_X86_REG_ST7: {
|
||||||
{
|
|
||||||
// value must be big enough to keep 80 bits (10 bytes)
|
// value must be big enough to keep 80 bits (10 bytes)
|
||||||
memcpy(&FPST(regid - UC_X86_REG_ST0), value, 10);
|
memcpy(&FPST(regid - UC_X86_REG_ST0), value, 10);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -905,9 +902,8 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
|
||||||
case UC_X86_REG_YMM12:
|
case UC_X86_REG_YMM12:
|
||||||
case UC_X86_REG_YMM13:
|
case UC_X86_REG_YMM13:
|
||||||
case UC_X86_REG_YMM14:
|
case UC_X86_REG_YMM14:
|
||||||
case UC_X86_REG_YMM15:
|
case UC_X86_REG_YMM15: {
|
||||||
{
|
float64 *src = (float64 *)value;
|
||||||
float64 *src = (float64*)value;
|
|
||||||
XMMReg *lo_reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_YMM0];
|
XMMReg *lo_reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_YMM0];
|
||||||
XMMReg *hi_reg = &env->ymmh_regs[regid - UC_X86_REG_YMM0];
|
XMMReg *hi_reg = &env->ymmh_regs[regid - UC_X86_REG_YMM0];
|
||||||
lo_reg->_d[0] = src[0];
|
lo_reg->_d[0] = src[0];
|
||||||
|
@ -918,13 +914,14 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch(mode) {
|
switch (mode) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UC_MODE_16:
|
case UC_MODE_16:
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
default: break;
|
default:
|
||||||
|
break;
|
||||||
case UC_X86_REG_ES:
|
case UC_X86_REG_ES:
|
||||||
load_seg_16_helper(env, R_ES, *(uint16_t *)value);
|
load_seg_16_helper(env, R_ES, *(uint16_t *)value);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -943,7 +940,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
|
||||||
}
|
}
|
||||||
// fall-thru
|
// fall-thru
|
||||||
case UC_MODE_32:
|
case UC_MODE_32:
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_CR0:
|
case UC_X86_REG_CR0:
|
||||||
|
@ -964,7 +961,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
|
||||||
env->dr[regid - UC_X86_REG_DR0] = *(uint32_t *)value;
|
env->dr[regid - UC_X86_REG_DR0] = *(uint32_t *)value;
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_FLAGS:
|
case UC_X86_REG_FLAGS:
|
||||||
cpu_load_eflags(env, *(uint16_t*)value, -1);
|
cpu_load_eflags(env, *(uint16_t *)value, -1);
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_EFLAGS:
|
case UC_X86_REG_EFLAGS:
|
||||||
cpu_load_eflags(env, *(uint32_t *)value, -1);
|
cpu_load_eflags(env, *(uint32_t *)value, -1);
|
||||||
|
@ -1129,7 +1126,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
|
||||||
|
|
||||||
#ifdef TARGET_X86_64
|
#ifdef TARGET_X86_64
|
||||||
case UC_MODE_64:
|
case UC_MODE_64:
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_CR0:
|
case UC_X86_REG_CR0:
|
||||||
|
@ -1150,7 +1147,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
|
||||||
env->dr[regid - UC_X86_REG_DR0] = *(uint64_t *)value;
|
env->dr[regid - UC_X86_REG_DR0] = *(uint64_t *)value;
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_FLAGS:
|
case UC_X86_REG_FLAGS:
|
||||||
cpu_load_eflags(env, *(uint16_t*)value, -1);
|
cpu_load_eflags(env, *(uint16_t *)value, -1);
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_EFLAGS:
|
case UC_X86_REG_EFLAGS:
|
||||||
cpu_load_eflags(env, *(uint32_t *)value, -1);
|
cpu_load_eflags(env, *(uint32_t *)value, -1);
|
||||||
|
@ -1430,9 +1427,8 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
|
||||||
case UC_X86_REG_XMM12:
|
case UC_X86_REG_XMM12:
|
||||||
case UC_X86_REG_XMM13:
|
case UC_X86_REG_XMM13:
|
||||||
case UC_X86_REG_XMM14:
|
case UC_X86_REG_XMM14:
|
||||||
case UC_X86_REG_XMM15:
|
case UC_X86_REG_XMM15: {
|
||||||
{
|
float64 *src = (float64 *)value;
|
||||||
float64 *src = (float64*)value;
|
|
||||||
XMMReg *reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
|
XMMReg *reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
|
||||||
reg->_d[0] = src[0];
|
reg->_d[0] = src[0];
|
||||||
reg->_d[1] = src[1];
|
reg->_d[1] = src[1];
|
||||||
|
@ -1452,7 +1448,8 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
|
int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||||
|
int count)
|
||||||
{
|
{
|
||||||
CPUX86State *env = &(X86_CPU(uc->cpu)->env);
|
CPUX86State *env = &(X86_CPU(uc->cpu)->env);
|
||||||
int i;
|
int i;
|
||||||
|
@ -1466,9 +1463,10 @@ int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int coun
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count)
|
int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
|
int count)
|
||||||
{
|
{
|
||||||
CPUX86State* env = &(X86_CPU(uc->cpu)->env);
|
CPUX86State *env = &(X86_CPU(uc->cpu)->env);
|
||||||
int i;
|
int i;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
@ -1476,14 +1474,14 @@ int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, i
|
||||||
unsigned int regid = regs[i];
|
unsigned int regid = regs[i];
|
||||||
const void *value = vals[i];
|
const void *value = vals[i];
|
||||||
ret = reg_write(env, regid, value, uc->mode);
|
ret = reg_write(env, regid, value, uc->mode);
|
||||||
if (ret){
|
if (ret) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
switch(uc->mode) {
|
switch (uc->mode) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case UC_MODE_32:
|
case UC_MODE_32:
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_EIP:
|
case UC_X86_REG_EIP:
|
||||||
|
@ -1496,7 +1494,7 @@ int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, i
|
||||||
|
|
||||||
#ifdef TARGET_X86_64
|
#ifdef TARGET_X86_64
|
||||||
case UC_MODE_64:
|
case UC_MODE_64:
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_RIP:
|
case UC_X86_REG_RIP:
|
||||||
|
@ -1515,7 +1513,8 @@ int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, i
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_VISIBILITY
|
DEFAULT_VISIBILITY
|
||||||
int x86_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
|
int x86_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count)
|
||||||
{
|
{
|
||||||
CPUX86State *env = (CPUX86State *)ctx->data;
|
CPUX86State *env = (CPUX86State *)ctx->data;
|
||||||
int i;
|
int i;
|
||||||
|
@ -1530,7 +1529,8 @@ int x86_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_VISIBILITY
|
DEFAULT_VISIBILITY
|
||||||
int x86_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
|
int x86_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count)
|
||||||
{
|
{
|
||||||
CPUX86State *env = (CPUX86State *)ctx->data;
|
CPUX86State *env = (CPUX86State *)ctx->data;
|
||||||
int i;
|
int i;
|
||||||
|
@ -1540,7 +1540,7 @@ int x86_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *cons
|
||||||
unsigned int regid = regs[i];
|
unsigned int regid = regs[i];
|
||||||
const void *value = vals[i];
|
const void *value = vals[i];
|
||||||
ret = reg_write(env, regid, value, ctx->mode);
|
ret = reg_write(env, regid, value, ctx->mode);
|
||||||
if (ret){
|
if (ret) {
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1550,7 +1550,7 @@ int x86_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *cons
|
||||||
|
|
||||||
static bool x86_stop_interrupt(struct uc_struct *uc, int intno)
|
static bool x86_stop_interrupt(struct uc_struct *uc, int intno)
|
||||||
{
|
{
|
||||||
switch(intno) {
|
switch (intno) {
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
case EXCP06_ILLOP:
|
case EXCP06_ILLOP:
|
||||||
|
@ -1560,12 +1560,10 @@ static bool x86_stop_interrupt(struct uc_struct *uc, int intno)
|
||||||
|
|
||||||
static bool x86_insn_hook_validate(uint32_t insn_enum)
|
static bool x86_insn_hook_validate(uint32_t insn_enum)
|
||||||
{
|
{
|
||||||
//for x86 we can only hook IN, OUT, and SYSCALL
|
// for x86 we can only hook IN, OUT, and SYSCALL
|
||||||
if (insn_enum != UC_X86_INS_IN
|
if (insn_enum != UC_X86_INS_IN && insn_enum != UC_X86_INS_OUT &&
|
||||||
&& insn_enum != UC_X86_INS_OUT
|
insn_enum != UC_X86_INS_SYSCALL && insn_enum != UC_X86_INS_SYSENTER &&
|
||||||
&& insn_enum != UC_X86_INS_SYSCALL
|
insn_enum != UC_X86_INS_CPUID) {
|
||||||
&& insn_enum != UC_X86_INS_SYSENTER
|
|
||||||
&& insn_enum != UC_X86_INS_CPUID) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
@ -1585,7 +1583,7 @@ static int x86_cpus_init(struct uc_struct *uc, const char *cpu_model)
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_VISIBILITY
|
DEFAULT_VISIBILITY
|
||||||
void x86_uc_init(struct uc_struct* uc)
|
void x86_uc_init(struct uc_struct *uc)
|
||||||
{
|
{
|
||||||
uc->reg_read = x86_reg_read;
|
uc->reg_read = x86_reg_read;
|
||||||
uc->reg_write = x86_reg_write;
|
uc->reg_write = x86_reg_write;
|
||||||
|
|
|
@ -6,12 +6,16 @@
|
||||||
#define UC_QEMU_TARGET_I386_H
|
#define UC_QEMU_TARGET_I386_H
|
||||||
|
|
||||||
// functions to read & write registers
|
// functions to read & write registers
|
||||||
int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||||
int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
int count);
|
||||||
int x86_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
int x86_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
int count);
|
||||||
|
int x86_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count);
|
||||||
|
int x86_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count);
|
||||||
|
|
||||||
void x86_reg_reset(struct uc_struct *uc);
|
void x86_reg_reset(struct uc_struct *uc);
|
||||||
|
|
||||||
void x86_uc_init(struct uc_struct* uc);
|
void x86_uc_init(struct uc_struct *uc);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -15,7 +15,7 @@ static void m68k_set_pc(struct uc_struct *uc, uint64_t address)
|
||||||
((CPUM68KState *)uc->cpu->env_ptr)->pc = address;
|
((CPUM68KState *)uc->cpu->env_ptr)->pc = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void m68k_release(void* ctx)
|
static void m68k_release(void *ctx)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
TCGContext *tcg_ctx = (TCGContext *)ctx;
|
TCGContext *tcg_ctx = (TCGContext *)ctx;
|
||||||
|
@ -51,8 +51,9 @@ static void reg_read(CPUM68KState *env, unsigned int regid, void *value)
|
||||||
else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7)
|
else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7)
|
||||||
*(int32_t *)value = env->dregs[regid - UC_M68K_REG_D0];
|
*(int32_t *)value = env->dregs[regid - UC_M68K_REG_D0];
|
||||||
else {
|
else {
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
default: break;
|
default:
|
||||||
|
break;
|
||||||
case UC_M68K_REG_PC:
|
case UC_M68K_REG_PC:
|
||||||
*(int32_t *)value = env->pc;
|
*(int32_t *)value = env->pc;
|
||||||
break;
|
break;
|
||||||
|
@ -69,8 +70,9 @@ static void reg_write(CPUM68KState *env, unsigned int regid, const void *value)
|
||||||
else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7)
|
else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7)
|
||||||
env->dregs[regid - UC_M68K_REG_D0] = *(uint32_t *)value;
|
env->dregs[regid - UC_M68K_REG_D0] = *(uint32_t *)value;
|
||||||
else {
|
else {
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
default: break;
|
default:
|
||||||
|
break;
|
||||||
case UC_M68K_REG_PC:
|
case UC_M68K_REG_PC:
|
||||||
env->pc = *(uint32_t *)value;
|
env->pc = *(uint32_t *)value;
|
||||||
break;
|
break;
|
||||||
|
@ -78,9 +80,10 @@ static void reg_write(CPUM68KState *env, unsigned int regid, const void *value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
|
int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||||
|
int count)
|
||||||
{
|
{
|
||||||
CPUM68KState* env = &(M68K_CPU(uc->cpu)->env);
|
CPUM68KState *env = &(M68K_CPU(uc->cpu)->env);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
|
@ -92,16 +95,17 @@ int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int cou
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count)
|
int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
|
int count)
|
||||||
{
|
{
|
||||||
CPUM68KState* env = &(M68K_CPU(uc->cpu)->env);
|
CPUM68KState *env = &(M68K_CPU(uc->cpu)->env);
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
unsigned int regid = regs[i];
|
unsigned int regid = regs[i];
|
||||||
const void *value = vals[i];
|
const void *value = vals[i];
|
||||||
reg_write(env, regid, value);
|
reg_write(env, regid, value);
|
||||||
if (regid == UC_M68K_REG_PC){
|
if (regid == UC_M68K_REG_PC) {
|
||||||
// force to quit execution and flush TB
|
// force to quit execution and flush TB
|
||||||
uc->quit_request = true;
|
uc->quit_request = true;
|
||||||
uc_emu_stop(uc);
|
uc_emu_stop(uc);
|
||||||
|
@ -112,9 +116,10 @@ int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_VISIBILITY
|
DEFAULT_VISIBILITY
|
||||||
int m68k_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
|
int m68k_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count)
|
||||||
{
|
{
|
||||||
CPUM68KState* env = (CPUM68KState* )ctx->data;
|
CPUM68KState *env = (CPUM68KState *)ctx->data;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
|
@ -127,9 +132,10 @@ int m68k_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **val
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_VISIBILITY
|
DEFAULT_VISIBILITY
|
||||||
int m68k_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
|
int m68k_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count)
|
||||||
{
|
{
|
||||||
CPUM68KState* env = (CPUM68KState* )ctx->data;
|
CPUM68KState *env = (CPUM68KState *)ctx->data;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
|
@ -153,7 +159,7 @@ static int m68k_cpus_init(struct uc_struct *uc, const char *cpu_model)
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_VISIBILITY
|
DEFAULT_VISIBILITY
|
||||||
void m68k_uc_init(struct uc_struct* uc)
|
void m68k_uc_init(struct uc_struct *uc)
|
||||||
{
|
{
|
||||||
uc->release = m68k_release;
|
uc->release = m68k_release;
|
||||||
uc->reg_read = m68k_reg_read;
|
uc->reg_read = m68k_reg_read;
|
||||||
|
|
|
@ -5,12 +5,16 @@
|
||||||
#define UC_QEMU_TARGET_M68K_H
|
#define UC_QEMU_TARGET_M68K_H
|
||||||
|
|
||||||
// functions to read & write registers
|
// functions to read & write registers
|
||||||
int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||||
int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
int count);
|
||||||
int m68k_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
int m68k_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
int count);
|
||||||
|
int m68k_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count);
|
||||||
|
int m68k_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count);
|
||||||
|
|
||||||
void m68k_reg_reset(struct uc_struct *uc);
|
void m68k_reg_reset(struct uc_struct *uc);
|
||||||
|
|
||||||
void m68k_uc_init(struct uc_struct* uc);
|
void m68k_uc_init(struct uc_struct *uc);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -37,7 +37,6 @@ static void mips_set_pc(struct uc_struct *uc, uint64_t address)
|
||||||
((CPUMIPSState *)uc->cpu->env_ptr)->active_tc.PC = address;
|
((CPUMIPSState *)uc->cpu->env_ptr)->active_tc.PC = address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void mips_release(void *ctx)
|
static void mips_release(void *ctx)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -75,8 +74,9 @@ static void reg_read(CPUMIPSState *env, unsigned int regid, void *value)
|
||||||
if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31)
|
if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31)
|
||||||
*(mipsreg_t *)value = env->active_tc.gpr[regid - UC_MIPS_REG_0];
|
*(mipsreg_t *)value = env->active_tc.gpr[regid - UC_MIPS_REG_0];
|
||||||
else {
|
else {
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
default: break;
|
default:
|
||||||
|
break;
|
||||||
case UC_MIPS_REG_PC:
|
case UC_MIPS_REG_PC:
|
||||||
*(mipsreg_t *)value = env->active_tc.PC;
|
*(mipsreg_t *)value = env->active_tc.PC;
|
||||||
break;
|
break;
|
||||||
|
@ -100,8 +100,9 @@ static void reg_write(CPUMIPSState *env, unsigned int regid, const void *value)
|
||||||
if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31)
|
if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31)
|
||||||
env->active_tc.gpr[regid - UC_MIPS_REG_0] = *(mipsreg_t *)value;
|
env->active_tc.gpr[regid - UC_MIPS_REG_0] = *(mipsreg_t *)value;
|
||||||
else {
|
else {
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
default: break;
|
default:
|
||||||
|
break;
|
||||||
case UC_MIPS_REG_PC:
|
case UC_MIPS_REG_PC:
|
||||||
env->active_tc.PC = *(mipsreg_t *)value;
|
env->active_tc.PC = *(mipsreg_t *)value;
|
||||||
break;
|
break;
|
||||||
|
@ -124,7 +125,8 @@ static void reg_write(CPUMIPSState *env, unsigned int regid, const void *value)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
|
int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||||
|
int count)
|
||||||
{
|
{
|
||||||
CPUMIPSState *env = &(MIPS_CPU(uc->cpu)->env);
|
CPUMIPSState *env = &(MIPS_CPU(uc->cpu)->env);
|
||||||
int i;
|
int i;
|
||||||
|
@ -138,7 +140,8 @@ int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int cou
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count)
|
int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
|
int count)
|
||||||
{
|
{
|
||||||
CPUMIPSState *env = &(MIPS_CPU(uc->cpu)->env);
|
CPUMIPSState *env = &(MIPS_CPU(uc->cpu)->env);
|
||||||
int i;
|
int i;
|
||||||
|
@ -147,7 +150,7 @@ int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
unsigned int regid = regs[i];
|
unsigned int regid = regs[i];
|
||||||
const void *value = vals[i];
|
const void *value = vals[i];
|
||||||
reg_write(env, regid, value);
|
reg_write(env, regid, value);
|
||||||
if(regid == UC_MIPS_REG_PC){
|
if (regid == UC_MIPS_REG_PC) {
|
||||||
// force to quit execution and flush TB
|
// force to quit execution and flush TB
|
||||||
uc->quit_request = true;
|
uc->quit_request = true;
|
||||||
uc_emu_stop(uc);
|
uc_emu_stop(uc);
|
||||||
|
@ -160,15 +163,19 @@ int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
DEFAULT_VISIBILITY
|
DEFAULT_VISIBILITY
|
||||||
#ifdef TARGET_MIPS64
|
#ifdef TARGET_MIPS64
|
||||||
#ifdef TARGET_WORDS_BIGENDIAN
|
#ifdef TARGET_WORDS_BIGENDIAN
|
||||||
int mips64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
|
int mips64_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count)
|
||||||
#else
|
#else
|
||||||
int mips64el_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
|
int mips64el_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count)
|
||||||
#endif
|
#endif
|
||||||
#else // if TARGET_MIPS
|
#else // if TARGET_MIPS
|
||||||
#ifdef TARGET_WORDS_BIGENDIAN
|
#ifdef TARGET_WORDS_BIGENDIAN
|
||||||
int mips_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
|
int mips_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count)
|
||||||
#else
|
#else
|
||||||
int mipsel_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
|
int mipsel_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@ -187,15 +194,19 @@ DEFAULT_VISIBILITY
|
||||||
DEFAULT_VISIBILITY
|
DEFAULT_VISIBILITY
|
||||||
#ifdef TARGET_MIPS64
|
#ifdef TARGET_MIPS64
|
||||||
#ifdef TARGET_WORDS_BIGENDIAN
|
#ifdef TARGET_WORDS_BIGENDIAN
|
||||||
int mips64_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
|
int mips64_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count)
|
||||||
#else
|
#else
|
||||||
int mips64el_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
|
int mips64el_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count)
|
||||||
#endif
|
#endif
|
||||||
#else // if TARGET_MIPS
|
#else // if TARGET_MIPS
|
||||||
#ifdef TARGET_WORDS_BIGENDIAN
|
#ifdef TARGET_WORDS_BIGENDIAN
|
||||||
int mips_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
|
int mips_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count)
|
||||||
#else
|
#else
|
||||||
int mipsel_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
|
int mipsel_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
@ -226,15 +237,15 @@ static int mips_cpus_init(struct uc_struct *uc, const char *cpu_model)
|
||||||
DEFAULT_VISIBILITY
|
DEFAULT_VISIBILITY
|
||||||
#ifdef TARGET_MIPS64
|
#ifdef TARGET_MIPS64
|
||||||
#ifdef TARGET_WORDS_BIGENDIAN
|
#ifdef TARGET_WORDS_BIGENDIAN
|
||||||
void mips64_uc_init(struct uc_struct* uc)
|
void mips64_uc_init(struct uc_struct *uc)
|
||||||
#else
|
#else
|
||||||
void mips64el_uc_init(struct uc_struct* uc)
|
void mips64el_uc_init(struct uc_struct *uc)
|
||||||
#endif
|
#endif
|
||||||
#else // if TARGET_MIPS
|
#else // if TARGET_MIPS
|
||||||
#ifdef TARGET_WORDS_BIGENDIAN
|
#ifdef TARGET_WORDS_BIGENDIAN
|
||||||
void mips_uc_init(struct uc_struct* uc)
|
void mips_uc_init(struct uc_struct *uc)
|
||||||
#else
|
#else
|
||||||
void mipsel_uc_init(struct uc_struct* uc)
|
void mipsel_uc_init(struct uc_struct *uc)
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,22 +5,32 @@
|
||||||
#define UC_QEMU_TARGET_MIPS_H
|
#define UC_QEMU_TARGET_MIPS_H
|
||||||
|
|
||||||
// functions to read & write registers
|
// functions to read & write registers
|
||||||
int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||||
int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
int count);
|
||||||
|
int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
|
int count);
|
||||||
|
|
||||||
int mips_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
int mips_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
int mips_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
void **vals, int count);
|
||||||
int mipsel_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
int mips_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
int mipsel_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
void *const *vals, int count);
|
||||||
int mips64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
int mipsel_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
int mips64_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
void **vals, int count);
|
||||||
int mips64el_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
int mipsel_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
int mips64el_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
void *const *vals, int count);
|
||||||
|
int mips64_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count);
|
||||||
|
int mips64_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count);
|
||||||
|
int mips64el_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count);
|
||||||
|
int mips64el_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count);
|
||||||
|
|
||||||
void mips_reg_reset(struct uc_struct *uc);
|
void mips_reg_reset(struct uc_struct *uc);
|
||||||
|
|
||||||
void mips_uc_init(struct uc_struct* uc);
|
void mips_uc_init(struct uc_struct *uc);
|
||||||
void mipsel_uc_init(struct uc_struct* uc);
|
void mipsel_uc_init(struct uc_struct *uc);
|
||||||
void mips64_uc_init(struct uc_struct* uc);
|
void mips64_uc_init(struct uc_struct *uc);
|
||||||
void mips64el_uc_init(struct uc_struct* uc);
|
void mips64el_uc_init(struct uc_struct *uc);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -18,7 +18,7 @@ typedef uint32_t ppcreg_t;
|
||||||
|
|
||||||
static uint64_t ppc_mem_redirect(uint64_t address)
|
static uint64_t ppc_mem_redirect(uint64_t address)
|
||||||
{
|
{
|
||||||
/* // kseg0 range masks off high address bit
|
/* // kseg0 range masks off high address bit
|
||||||
if (address >= 0x80000000 && address <= 0x9fffffff)
|
if (address >= 0x80000000 && address <= 0x9fffffff)
|
||||||
return address & 0x7fffffff;
|
return address & 0x7fffffff;
|
||||||
|
|
||||||
|
@ -59,12 +59,12 @@ static void ppc_release(void *ctx)
|
||||||
for (i = 0; i < 32; i++) {
|
for (i = 0; i < 32; i++) {
|
||||||
g_free(tcg_ctx->cpu_gpr[i]);
|
g_free(tcg_ctx->cpu_gpr[i]);
|
||||||
}
|
}
|
||||||
// g_free(tcg_ctx->cpu_PC);
|
// g_free(tcg_ctx->cpu_PC);
|
||||||
g_free(tcg_ctx->btarget);
|
g_free(tcg_ctx->btarget);
|
||||||
g_free(tcg_ctx->bcond);
|
g_free(tcg_ctx->bcond);
|
||||||
g_free(tcg_ctx->cpu_dspctrl);
|
g_free(tcg_ctx->cpu_dspctrl);
|
||||||
|
|
||||||
// g_free(tcg_ctx->tb_ctx.tbs);
|
// g_free(tcg_ctx->tb_ctx.tbs);
|
||||||
|
|
||||||
ppc_cpu_instance_finalize(tcg_ctx->uc->cpu);
|
ppc_cpu_instance_finalize(tcg_ctx->uc->cpu);
|
||||||
ppc_cpu_unrealize(tcg_ctx->uc->cpu);
|
ppc_cpu_unrealize(tcg_ctx->uc->cpu);
|
||||||
|
@ -84,12 +84,13 @@ static void reg_read(CPUPPCState *env, unsigned int regid, void *value)
|
||||||
if (regid >= UC_PPC_REG_0 && regid <= UC_PPC_REG_31)
|
if (regid >= UC_PPC_REG_0 && regid <= UC_PPC_REG_31)
|
||||||
*(ppcreg_t *)value = env->gpr[regid - UC_PPC_REG_0];
|
*(ppcreg_t *)value = env->gpr[regid - UC_PPC_REG_0];
|
||||||
else {
|
else {
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
default: break;
|
default:
|
||||||
|
break;
|
||||||
case UC_PPC_REG_PC:
|
case UC_PPC_REG_PC:
|
||||||
*(ppcreg_t *)value = env->nip;
|
*(ppcreg_t *)value = env->nip;
|
||||||
break;
|
break;
|
||||||
/* case UC_PPC_REG_CP0_CONFIG3:
|
/* case UC_PPC_REG_CP0_CONFIG3:
|
||||||
*(mipsreg_t *)value = env->CP0_Config3;
|
*(mipsreg_t *)value = env->CP0_Config3;
|
||||||
break;
|
break;
|
||||||
case UC_MIPS_REG_CP0_USERLOCAL:
|
case UC_MIPS_REG_CP0_USERLOCAL:
|
||||||
|
@ -106,12 +107,13 @@ static void reg_write(CPUPPCState *env, unsigned int regid, const void *value)
|
||||||
if (regid >= UC_PPC_REG_0 && regid <= UC_PPC_REG_31)
|
if (regid >= UC_PPC_REG_0 && regid <= UC_PPC_REG_31)
|
||||||
env->gpr[regid - UC_PPC_REG_0] = *(ppcreg_t *)value;
|
env->gpr[regid - UC_PPC_REG_0] = *(ppcreg_t *)value;
|
||||||
else {
|
else {
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
default: break;
|
default:
|
||||||
|
break;
|
||||||
case UC_PPC_REG_PC:
|
case UC_PPC_REG_PC:
|
||||||
env->nip = *(ppcreg_t *)value;
|
env->nip = *(ppcreg_t *)value;
|
||||||
break;
|
break;
|
||||||
/* case UC_MIPS_REG_CP0_CONFIG3:
|
/* case UC_MIPS_REG_CP0_CONFIG3:
|
||||||
env->CP0_Config3 = *(mipsreg_t *)value;
|
env->CP0_Config3 = *(mipsreg_t *)value;
|
||||||
break;
|
break;
|
||||||
case UC_MIPS_REG_CP0_USERLOCAL:
|
case UC_MIPS_REG_CP0_USERLOCAL:
|
||||||
|
@ -123,7 +125,8 @@ static void reg_write(CPUPPCState *env, unsigned int regid, const void *value)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ppc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
|
int ppc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||||
|
int count)
|
||||||
{
|
{
|
||||||
CPUPPCState *env = &(POWERPC_CPU(uc->cpu)->env);
|
CPUPPCState *env = &(POWERPC_CPU(uc->cpu)->env);
|
||||||
int i;
|
int i;
|
||||||
|
@ -137,7 +140,8 @@ int ppc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int coun
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ppc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count)
|
int ppc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
|
int count)
|
||||||
{
|
{
|
||||||
CPUPPCState *env = &(POWERPC_CPU(uc->cpu)->env);
|
CPUPPCState *env = &(POWERPC_CPU(uc->cpu)->env);
|
||||||
int i;
|
int i;
|
||||||
|
@ -158,9 +162,11 @@ int ppc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, i
|
||||||
|
|
||||||
DEFAULT_VISIBILITY
|
DEFAULT_VISIBILITY
|
||||||
#ifdef TARGET_PPC64
|
#ifdef TARGET_PPC64
|
||||||
int ppc64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
|
int ppc64_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count)
|
||||||
#else
|
#else
|
||||||
int ppc_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
|
int ppc_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
CPUPPCState *env = (CPUPPCState *)ctx->data;
|
CPUPPCState *env = (CPUPPCState *)ctx->data;
|
||||||
|
@ -177,9 +183,11 @@ int ppc_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals
|
||||||
|
|
||||||
DEFAULT_VISIBILITY
|
DEFAULT_VISIBILITY
|
||||||
#ifdef TARGET_PPC64
|
#ifdef TARGET_PPC64
|
||||||
int ppc64_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
|
int ppc64_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count)
|
||||||
#else
|
#else
|
||||||
int ppc_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
|
int ppc_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
CPUPPCState *env = (CPUPPCState *)ctx->data;
|
CPUPPCState *env = (CPUPPCState *)ctx->data;
|
||||||
|
@ -208,9 +216,9 @@ static int ppc_cpus_init(struct uc_struct *uc, const char *cpu_model)
|
||||||
|
|
||||||
DEFAULT_VISIBILITY
|
DEFAULT_VISIBILITY
|
||||||
#ifdef TARGET_PPC64
|
#ifdef TARGET_PPC64
|
||||||
void ppc64_uc_init(struct uc_struct* uc)
|
void ppc64_uc_init(struct uc_struct *uc)
|
||||||
#else
|
#else
|
||||||
void ppc_uc_init(struct uc_struct* uc)
|
void ppc_uc_init(struct uc_struct *uc)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
uc->reg_read = ppc_reg_read;
|
uc->reg_read = ppc_reg_read;
|
||||||
|
|
|
@ -5,16 +5,22 @@
|
||||||
#define UC_QEMU_TARGET_PPC_H
|
#define UC_QEMU_TARGET_PPC_H
|
||||||
|
|
||||||
// functions to read & write registers
|
// functions to read & write registers
|
||||||
int ppc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
int ppc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||||
int ppc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
int count);
|
||||||
|
int ppc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
|
int count);
|
||||||
|
|
||||||
int ppc_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
int ppc_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
int ppc_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
void **vals, int count);
|
||||||
int ppc64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
int ppc_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
int ppc64_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
void *const *vals, int count);
|
||||||
|
int ppc64_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count);
|
||||||
|
int ppc64_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count);
|
||||||
|
|
||||||
void ppc_reg_reset(struct uc_struct *uc);
|
void ppc_reg_reset(struct uc_struct *uc);
|
||||||
|
|
||||||
void ppc_uc_init(struct uc_struct* uc);
|
void ppc_uc_init(struct uc_struct *uc);
|
||||||
void ppc64_uc_init(struct uc_struct* uc);
|
void ppc64_uc_init(struct uc_struct *uc);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -36,13 +36,11 @@ static void riscv_release(void *ctx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void riscv_reg_reset(struct uc_struct *uc)
|
void riscv_reg_reset(struct uc_struct *uc) {}
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
static void reg_read(CPURISCVState *env, unsigned int regid, void *value)
|
static void reg_read(CPURISCVState *env, unsigned int regid, void *value)
|
||||||
{
|
{
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
case UC_RISCV_REG_X0:
|
case UC_RISCV_REG_X0:
|
||||||
case UC_RISCV_REG_X1:
|
case UC_RISCV_REG_X1:
|
||||||
case UC_RISCV_REG_X2:
|
case UC_RISCV_REG_X2:
|
||||||
|
@ -136,7 +134,7 @@ static void reg_read(CPURISCVState *env, unsigned int regid, void *value)
|
||||||
|
|
||||||
static void reg_write(CPURISCVState *env, unsigned int regid, const void *value)
|
static void reg_write(CPURISCVState *env, unsigned int regid, const void *value)
|
||||||
{
|
{
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
case UC_RISCV_REG_X0:
|
case UC_RISCV_REG_X0:
|
||||||
case UC_RISCV_REG_X1:
|
case UC_RISCV_REG_X1:
|
||||||
case UC_RISCV_REG_X2:
|
case UC_RISCV_REG_X2:
|
||||||
|
@ -225,7 +223,8 @@ static void reg_write(CPURISCVState *env, unsigned int regid, const void *value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int riscv_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
|
int riscv_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||||
|
int count)
|
||||||
{
|
{
|
||||||
CPURISCVState *env = &(RISCV_CPU(uc->cpu)->env);
|
CPURISCVState *env = &(RISCV_CPU(uc->cpu)->env);
|
||||||
int i;
|
int i;
|
||||||
|
@ -239,7 +238,8 @@ int riscv_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int co
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count)
|
int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
|
int count)
|
||||||
{
|
{
|
||||||
CPURISCVState *env = &(RISCV_CPU(uc->cpu)->env);
|
CPURISCVState *env = &(RISCV_CPU(uc->cpu)->env);
|
||||||
int i;
|
int i;
|
||||||
|
@ -248,7 +248,7 @@ int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
unsigned int regid = regs[i];
|
unsigned int regid = regs[i];
|
||||||
const void *value = vals[i];
|
const void *value = vals[i];
|
||||||
reg_write(env, regid, value);
|
reg_write(env, regid, value);
|
||||||
if(regid == UC_RISCV_REG_PC){
|
if (regid == UC_RISCV_REG_PC) {
|
||||||
// force to quit execution and flush TB
|
// force to quit execution and flush TB
|
||||||
uc->quit_request = true;
|
uc->quit_request = true;
|
||||||
uc_emu_stop(uc);
|
uc_emu_stop(uc);
|
||||||
|
@ -260,10 +260,12 @@ int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
|
|
||||||
DEFAULT_VISIBILITY
|
DEFAULT_VISIBILITY
|
||||||
#ifdef TARGET_RISCV32
|
#ifdef TARGET_RISCV32
|
||||||
int riscv32_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
|
int riscv32_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count)
|
||||||
#else
|
#else
|
||||||
/* TARGET_RISCV64 */
|
/* TARGET_RISCV64 */
|
||||||
int riscv64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
|
int riscv64_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
CPURISCVState *env = (CPURISCVState *)ctx->data;
|
CPURISCVState *env = (CPURISCVState *)ctx->data;
|
||||||
|
@ -280,10 +282,12 @@ int riscv64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **
|
||||||
|
|
||||||
DEFAULT_VISIBILITY
|
DEFAULT_VISIBILITY
|
||||||
#ifdef TARGET_RISCV32
|
#ifdef TARGET_RISCV32
|
||||||
int riscv32_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
|
int riscv32_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count)
|
||||||
#else
|
#else
|
||||||
/* TARGET_RISCV64 */
|
/* TARGET_RISCV64 */
|
||||||
int riscv64_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
|
int riscv64_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
CPURISCVState *env = (CPURISCVState *)ctx->data;
|
CPURISCVState *env = (CPURISCVState *)ctx->data;
|
||||||
|
@ -301,7 +305,7 @@ int riscv64_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *
|
||||||
static bool riscv_stop_interrupt(struct uc_struct *uc, int intno)
|
static bool riscv_stop_interrupt(struct uc_struct *uc, int intno)
|
||||||
{
|
{
|
||||||
// detect stop exception
|
// detect stop exception
|
||||||
switch(intno){
|
switch (intno) {
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
case RISCV_EXCP_UNICORN_END:
|
case RISCV_EXCP_UNICORN_END:
|
||||||
|
@ -332,10 +336,10 @@ static int riscv_cpus_init(struct uc_struct *uc, const char *cpu_model)
|
||||||
|
|
||||||
DEFAULT_VISIBILITY
|
DEFAULT_VISIBILITY
|
||||||
#ifdef TARGET_RISCV32
|
#ifdef TARGET_RISCV32
|
||||||
void riscv32_uc_init(struct uc_struct* uc)
|
void riscv32_uc_init(struct uc_struct *uc)
|
||||||
#else
|
#else
|
||||||
/* TARGET_RISCV64 */
|
/* TARGET_RISCV64 */
|
||||||
void riscv64_uc_init(struct uc_struct* uc)
|
void riscv64_uc_init(struct uc_struct *uc)
|
||||||
#endif
|
#endif
|
||||||
{
|
{
|
||||||
uc->reg_read = riscv_reg_read;
|
uc->reg_read = riscv_reg_read;
|
||||||
|
|
|
@ -6,16 +6,22 @@
|
||||||
#define UC_QEMU_TARGET_RISCV_H
|
#define UC_QEMU_TARGET_RISCV_H
|
||||||
|
|
||||||
// functions to read & write registers
|
// functions to read & write registers
|
||||||
int riscv_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
int riscv_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||||
int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
int count);
|
||||||
|
int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
|
int count);
|
||||||
|
|
||||||
int riscv32_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
int riscv32_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
int riscv32_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
void **vals, int count);
|
||||||
int riscv64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
int riscv32_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
int riscv64_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
void *const *vals, int count);
|
||||||
|
int riscv64_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count);
|
||||||
|
int riscv64_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count);
|
||||||
|
|
||||||
void riscv_reg_reset(struct uc_struct *uc);
|
void riscv_reg_reset(struct uc_struct *uc);
|
||||||
|
|
||||||
void riscv32_uc_init(struct uc_struct* uc);
|
void riscv32_uc_init(struct uc_struct *uc);
|
||||||
void riscv64_uc_init(struct uc_struct* uc);
|
void riscv64_uc_init(struct uc_struct *uc);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
|
|
||||||
static bool sparc_stop_interrupt(struct uc_struct *uc, int intno)
|
static bool sparc_stop_interrupt(struct uc_struct *uc, int intno)
|
||||||
{
|
{
|
||||||
switch(intno) {
|
switch (intno) {
|
||||||
default:
|
default:
|
||||||
return false;
|
return false;
|
||||||
case TT_ILL_INSN:
|
case TT_ILL_INSN:
|
||||||
|
@ -67,8 +67,9 @@ static void reg_read(CPUSPARCState *env, unsigned int regid, void *value)
|
||||||
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
|
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
|
||||||
*(int32_t *)value = env->regwptr[16 + regid - UC_SPARC_REG_I0];
|
*(int32_t *)value = env->regwptr[16 + regid - UC_SPARC_REG_I0];
|
||||||
else {
|
else {
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
default: break;
|
default:
|
||||||
|
break;
|
||||||
case UC_SPARC_REG_PC:
|
case UC_SPARC_REG_PC:
|
||||||
*(int32_t *)value = env->pc;
|
*(int32_t *)value = env->pc;
|
||||||
break;
|
break;
|
||||||
|
@ -89,8 +90,9 @@ static void reg_write(CPUSPARCState *env, unsigned int regid, const void *value)
|
||||||
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
|
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
|
||||||
env->regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint32_t *)value;
|
env->regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint32_t *)value;
|
||||||
else {
|
else {
|
||||||
switch(regid) {
|
switch (regid) {
|
||||||
default: break;
|
default:
|
||||||
|
break;
|
||||||
case UC_SPARC_REG_PC:
|
case UC_SPARC_REG_PC:
|
||||||
env->pc = *(uint32_t *)value;
|
env->pc = *(uint32_t *)value;
|
||||||
env->npc = *(uint32_t *)value + 4;
|
env->npc = *(uint32_t *)value + 4;
|
||||||
|
@ -101,7 +103,8 @@ static void reg_write(CPUSPARCState *env, unsigned int regid, const void *value)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
|
int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||||
|
int count)
|
||||||
{
|
{
|
||||||
CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env);
|
CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env);
|
||||||
int i;
|
int i;
|
||||||
|
@ -115,7 +118,8 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int co
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count)
|
int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
|
int count)
|
||||||
{
|
{
|
||||||
CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env);
|
CPUSPARCState *env = &(SPARC_CPU(uc->cpu)->env);
|
||||||
int i;
|
int i;
|
||||||
|
@ -124,7 +128,7 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
unsigned int regid = regs[i];
|
unsigned int regid = regs[i];
|
||||||
const void *value = vals[i];
|
const void *value = vals[i];
|
||||||
reg_write(env, regid, value);
|
reg_write(env, regid, value);
|
||||||
if( regid == UC_SPARC_REG_PC){
|
if (regid == UC_SPARC_REG_PC) {
|
||||||
// force to quit execution and flush TB
|
// force to quit execution and flush TB
|
||||||
uc->quit_request = true;
|
uc->quit_request = true;
|
||||||
uc_emu_stop(uc);
|
uc_emu_stop(uc);
|
||||||
|
@ -136,7 +140,8 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_VISIBILITY
|
DEFAULT_VISIBILITY
|
||||||
int sparc_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
|
int sparc_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count)
|
||||||
{
|
{
|
||||||
CPUSPARCState *env = (CPUSPARCState *)ctx->data;
|
CPUSPARCState *env = (CPUSPARCState *)ctx->data;
|
||||||
int i;
|
int i;
|
||||||
|
@ -151,7 +156,8 @@ int sparc_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **va
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_VISIBILITY
|
DEFAULT_VISIBILITY
|
||||||
int sparc_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
|
int sparc_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count)
|
||||||
{
|
{
|
||||||
CPUSPARCState *env = (CPUSPARCState *)ctx->data;
|
CPUSPARCState *env = (CPUSPARCState *)ctx->data;
|
||||||
int i;
|
int i;
|
||||||
|
@ -177,7 +183,7 @@ static int sparc_cpus_init(struct uc_struct *uc, const char *cpu_model)
|
||||||
}
|
}
|
||||||
|
|
||||||
DEFAULT_VISIBILITY
|
DEFAULT_VISIBILITY
|
||||||
void sparc_uc_init(struct uc_struct* uc)
|
void sparc_uc_init(struct uc_struct *uc)
|
||||||
{
|
{
|
||||||
uc->release = sparc_release;
|
uc->release = sparc_release;
|
||||||
uc->reg_read = sparc_reg_read;
|
uc->reg_read = sparc_reg_read;
|
||||||
|
|
|
@ -5,16 +5,22 @@
|
||||||
#define UC_QEMU_TARGET_SPARC_H
|
#define UC_QEMU_TARGET_SPARC_H
|
||||||
|
|
||||||
// functions to read & write registers
|
// functions to read & write registers
|
||||||
int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||||
int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
int count);
|
||||||
|
int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||||
|
int count);
|
||||||
|
|
||||||
int sparc_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
int sparc_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
int sparc_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
void **vals, int count);
|
||||||
int sparc64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
int sparc_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
int sparc64_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count);
|
void *const *vals, int count);
|
||||||
|
int sparc64_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void **vals, int count);
|
||||||
|
int sparc64_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||||
|
void *const *vals, int count);
|
||||||
|
|
||||||
void sparc_reg_reset(struct uc_struct *uc);
|
void sparc_reg_reset(struct uc_struct *uc);
|
||||||
|
|
||||||
void sparc_uc_init(struct uc_struct* uc);
|
void sparc_uc_init(struct uc_struct *uc);
|
||||||
void sparc64_uc_init(struct uc_struct* uc);
|
void sparc64_uc_init(struct uc_struct *uc);
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,24 +14,24 @@
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||||
|
USA.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define __STDC_FORMAT_MACROS
|
#define __STDC_FORMAT_MACROS
|
||||||
|
|
||||||
|
|
||||||
#include <unicorn/unicorn.h>
|
#include <unicorn/unicorn.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
|
|
||||||
static int insts_executed;
|
static int insts_executed;
|
||||||
|
|
||||||
// callback for tracing instructions, detect HLT and terminate emulation
|
// callback for tracing instructions, detect HLT and terminate emulation
|
||||||
static void hook_code(uc_engine *uc, uint64_t addr, uint32_t size, void *user_data)
|
static void hook_code(uc_engine *uc, uint64_t addr, uint32_t size,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
uint8_t opcode;
|
uint8_t opcode;
|
||||||
unsigned char buf[256];
|
unsigned char buf[256];
|
||||||
|
@ -39,9 +39,13 @@ static void hook_code(uc_engine *uc, uint64_t addr, uint32_t size, void *user_da
|
||||||
insts_executed++;
|
insts_executed++;
|
||||||
|
|
||||||
if (uc_mem_read(uc, addr, buf, size) != UC_ERR_OK) {
|
if (uc_mem_read(uc, addr, buf, size) != UC_ERR_OK) {
|
||||||
printf("not ok - uc_mem_read fail during hook_code callback, addr: 0x%" PRIx64 "\n", addr);
|
printf("not ok - uc_mem_read fail during hook_code callback, addr: "
|
||||||
|
"0x%" PRIx64 "\n",
|
||||||
|
addr);
|
||||||
if (uc_emu_stop(uc) != UC_ERR_OK) {
|
if (uc_emu_stop(uc) != UC_ERR_OK) {
|
||||||
printf("not ok - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", addr);
|
printf("not ok - uc_emu_stop fail during hook_code callback, addr: "
|
||||||
|
"0x%" PRIx64 "\n",
|
||||||
|
addr);
|
||||||
_exit(-1);
|
_exit(-1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -50,19 +54,25 @@ static void hook_code(uc_engine *uc, uint64_t addr, uint32_t size, void *user_da
|
||||||
switch (opcode) {
|
switch (opcode) {
|
||||||
case 0x41: // inc ecx
|
case 0x41: // inc ecx
|
||||||
if (uc_mem_protect(uc, 0x101000, 0x1000, UC_PROT_READ) != UC_ERR_OK) {
|
if (uc_mem_protect(uc, 0x101000, 0x1000, UC_PROT_READ) != UC_ERR_OK) {
|
||||||
printf("not ok - uc_mem_protect fail during hook_code callback, addr: 0x%" PRIx64 "\n", addr);
|
printf("not ok - uc_mem_protect fail during hook_code callback, "
|
||||||
|
"addr: 0x%" PRIx64 "\n",
|
||||||
|
addr);
|
||||||
_exit(-1);
|
_exit(-1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0x42: // inc edx
|
case 0x42: // inc edx
|
||||||
if (uc_mem_unmap(uc, 0x101000, 0x1000) != UC_ERR_OK) {
|
if (uc_mem_unmap(uc, 0x101000, 0x1000) != UC_ERR_OK) {
|
||||||
printf("not ok - uc_mem_unmap fail during hook_code callback, addr: 0x%" PRIx64 "\n", addr);
|
printf("not ok - uc_mem_unmap fail during hook_code callback, "
|
||||||
|
"addr: 0x%" PRIx64 "\n",
|
||||||
|
addr);
|
||||||
_exit(-1);
|
_exit(-1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case 0xf4: // hlt
|
case 0xf4: // hlt
|
||||||
if (uc_emu_stop(uc) != UC_ERR_OK) {
|
if (uc_emu_stop(uc) != UC_ERR_OK) {
|
||||||
printf("not ok - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", addr);
|
printf("not ok - uc_emu_stop fail during hook_code callback, addr: "
|
||||||
|
"0x%" PRIx64 "\n",
|
||||||
|
addr);
|
||||||
_exit(-1);
|
_exit(-1);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -72,27 +82,37 @@ static void hook_code(uc_engine *uc, uint64_t addr, uint32_t size, void *user_da
|
||||||
}
|
}
|
||||||
|
|
||||||
// callback for tracing invalid memory access (READ/WRITE/EXEC)
|
// callback for tracing invalid memory access (READ/WRITE/EXEC)
|
||||||
static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
|
static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type, uint64_t addr,
|
||||||
uint64_t addr, int size, int64_t value, void *user_data)
|
int size, int64_t value, void *user_data)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch (type) {
|
||||||
default:
|
default:
|
||||||
printf("not ok - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", type, addr);
|
printf("not ok - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", type,
|
||||||
|
addr);
|
||||||
return false;
|
return false;
|
||||||
case UC_MEM_READ_UNMAPPED:
|
case UC_MEM_READ_UNMAPPED:
|
||||||
printf("not ok - Read from invalid memory at 0x%"PRIx64 ", data size = %u\n", addr, size);
|
printf("not ok - Read from invalid memory at 0x%" PRIx64
|
||||||
|
", data size = %u\n",
|
||||||
|
addr, size);
|
||||||
return false;
|
return false;
|
||||||
case UC_MEM_WRITE_UNMAPPED:
|
case UC_MEM_WRITE_UNMAPPED:
|
||||||
printf("not ok - Write to invalid memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value);
|
printf("not ok - Write to invalid memory at 0x%" PRIx64
|
||||||
|
", data size = %u, data value = 0x%" PRIx64 "\n",
|
||||||
|
addr, size, value);
|
||||||
return false;
|
return false;
|
||||||
case UC_MEM_FETCH_PROT:
|
case UC_MEM_FETCH_PROT:
|
||||||
printf("not ok - Fetch from non-executable memory at 0x%"PRIx64 "\n", addr);
|
printf("not ok - Fetch from non-executable memory at 0x%" PRIx64 "\n",
|
||||||
|
addr);
|
||||||
return false;
|
return false;
|
||||||
case UC_MEM_WRITE_PROT:
|
case UC_MEM_WRITE_PROT:
|
||||||
printf("not ok - Write to non-writeable memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value);
|
printf("not ok - Write to non-writeable memory at 0x%" PRIx64
|
||||||
|
", data size = %u, data value = 0x%" PRIx64 "\n",
|
||||||
|
addr, size, value);
|
||||||
return false;
|
return false;
|
||||||
case UC_MEM_READ_PROT:
|
case UC_MEM_READ_PROT:
|
||||||
printf("not ok - Read from non-readable memory at 0x%"PRIx64 ", data size = %u\n", addr, size);
|
printf("not ok - Read from non-readable memory at 0x%" PRIx64
|
||||||
|
", data size = %u\n",
|
||||||
|
addr, size);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -107,7 +127,8 @@ static void do_nx_demo(bool cause_fault)
|
||||||
insts_executed = 0;
|
insts_executed = 0;
|
||||||
|
|
||||||
printf("===================================\n");
|
printf("===================================\n");
|
||||||
printf("# Example of marking memory NX (%s)\n", cause_fault ? "faulting" : "non-faulting");
|
printf("# Example of marking memory NX (%s)\n",
|
||||||
|
cause_fault ? "faulting" : "non-faulting");
|
||||||
|
|
||||||
// Initialize emulator in X86-32bit mode
|
// Initialize emulator in X86-32bit mode
|
||||||
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
||||||
|
@ -130,12 +151,14 @@ static void do_nx_demo(bool cause_fault)
|
||||||
jmp page1
|
jmp page1
|
||||||
*/
|
*/
|
||||||
memset(code_buf, 0x40, sizeof(code_buf)); // fill with inc eax
|
memset(code_buf, 0x40, sizeof(code_buf)); // fill with inc eax
|
||||||
memcpy(code_buf + 0x1000 - 5, "\xe9\x00\x10\x00\x00", 5); // jump to 0x102000
|
memcpy(code_buf + 0x1000 - 5, "\xe9\x00\x10\x00\x00",
|
||||||
|
5); // jump to 0x102000
|
||||||
memcpy(code_buf + 0x2000, "\xe9\xfb\xef\xff\xff", 5); // jump to 0x101000
|
memcpy(code_buf + 0x2000, "\xe9\xfb\xef\xff\xff", 5); // jump to 0x101000
|
||||||
code_buf[0x1fff] = 0xf4; //hlt
|
code_buf[0x1fff] = 0xf4; // hlt
|
||||||
|
|
||||||
if (cause_fault) {
|
if (cause_fault) {
|
||||||
// insert instruction to trigger U_PROT_EXEC change (see hook_code function)
|
// insert instruction to trigger U_PROT_EXEC change (see hook_code
|
||||||
|
// function)
|
||||||
code_buf[0x1000] = 0x41; // inc ecx at page1
|
code_buf[0x1000] = 0x41; // inc ecx at page1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -146,9 +169,10 @@ static void do_nx_demo(bool cause_fault)
|
||||||
}
|
}
|
||||||
|
|
||||||
// intercept code and invalid memory events
|
// intercept code and invalid memory events
|
||||||
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK ||
|
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) !=
|
||||||
uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID,
|
UC_ERR_OK ||
|
||||||
hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) {
|
uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL, 1,
|
||||||
|
0) != UC_ERR_OK) {
|
||||||
printf("not ok - Failed to install hooks\n");
|
printf("not ok - Failed to install hooks\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -157,7 +181,8 @@ static void do_nx_demo(bool cause_fault)
|
||||||
printf("BEGINNING EXECUTION\n");
|
printf("BEGINNING EXECUTION\n");
|
||||||
err = uc_emu_start(uc, 0x100000, 0x103000, 0, 0);
|
err = uc_emu_start(uc, 0x100000, 0x103000, 0, 0);
|
||||||
if (err != UC_ERR_OK) {
|
if (err != UC_ERR_OK) {
|
||||||
printf("not ok - Failure on uc_emu_start() with error %u: %s\n", err, uc_strerror(err));
|
printf("not ok - Failure on uc_emu_start() with error %u: %s\n", err,
|
||||||
|
uc_strerror(err));
|
||||||
printf("FAILED EXECUTION\n");
|
printf("FAILED EXECUTION\n");
|
||||||
} else {
|
} else {
|
||||||
printf("SUCCESSFUL EXECUTION\n");
|
printf("SUCCESSFUL EXECUTION\n");
|
||||||
|
@ -215,7 +240,8 @@ static void do_perms_demo(bool change_perms)
|
||||||
code_buf[sizeof(WRITE_DEMO) - 1 + 1000] = 0xf4; // hlt
|
code_buf[sizeof(WRITE_DEMO) - 1 + 1000] = 0xf4; // hlt
|
||||||
|
|
||||||
if (change_perms) {
|
if (change_perms) {
|
||||||
// write protect memory area [0x101000, 0x101fff]. see hook_code function
|
// write protect memory area [0x101000, 0x101fff]. see hook_code
|
||||||
|
// function
|
||||||
code_buf[0] = 0x41; // inc ecx
|
code_buf[0] = 0x41; // inc ecx
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,10 +252,10 @@ static void do_perms_demo(bool change_perms)
|
||||||
}
|
}
|
||||||
|
|
||||||
// intercept code and invalid memory events
|
// intercept code and invalid memory events
|
||||||
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK ||
|
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) !=
|
||||||
uc_hook_add(uc, &trace1,
|
UC_ERR_OK ||
|
||||||
UC_HOOK_MEM_INVALID,
|
uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL, 1,
|
||||||
hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) {
|
0) != UC_ERR_OK) {
|
||||||
printf("not ok - Failed to install hooks\n");
|
printf("not ok - Failed to install hooks\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -239,7 +265,8 @@ static void do_perms_demo(bool change_perms)
|
||||||
err = uc_emu_start(uc, 0x100000, 0x103000, 0, 0);
|
err = uc_emu_start(uc, 0x100000, 0x103000, 0, 0);
|
||||||
if (err != UC_ERR_OK) {
|
if (err != UC_ERR_OK) {
|
||||||
printf("FAILED EXECUTION\n");
|
printf("FAILED EXECUTION\n");
|
||||||
printf("not ok - Failure on uc_emu_start() with error %u: %s\n", err, uc_strerror(err));
|
printf("not ok - Failure on uc_emu_start() with error %u: %s\n", err,
|
||||||
|
uc_strerror(err));
|
||||||
} else {
|
} else {
|
||||||
printf("SUCCESSFUL EXECUTION\n");
|
printf("SUCCESSFUL EXECUTION\n");
|
||||||
}
|
}
|
||||||
|
@ -253,11 +280,11 @@ static void perms_test()
|
||||||
{
|
{
|
||||||
printf("Permissions demo - step 1: show that area is writeable\n");
|
printf("Permissions demo - step 1: show that area is writeable\n");
|
||||||
do_perms_demo(false);
|
do_perms_demo(false);
|
||||||
printf("Permissions demo - step 2: show that code fails when memory marked unwriteable\n");
|
printf("Permissions demo - step 2: show that code fails when memory marked "
|
||||||
|
"unwriteable\n");
|
||||||
do_perms_demo(true);
|
do_perms_demo(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void do_unmap_demo(bool do_unmap)
|
static void do_unmap_demo(bool do_unmap)
|
||||||
{
|
{
|
||||||
uc_engine *uc;
|
uc_engine *uc;
|
||||||
|
@ -304,10 +331,10 @@ static void do_unmap_demo(bool do_unmap)
|
||||||
}
|
}
|
||||||
|
|
||||||
// intercept code and invalid memory events
|
// intercept code and invalid memory events
|
||||||
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK ||
|
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) !=
|
||||||
uc_hook_add(uc, &trace1,
|
UC_ERR_OK ||
|
||||||
UC_HOOK_MEM_INVALID,
|
uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL, 1,
|
||||||
hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) {
|
0) != UC_ERR_OK) {
|
||||||
printf("not ok - Failed to install hooks\n");
|
printf("not ok - Failed to install hooks\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -317,7 +344,8 @@ static void do_unmap_demo(bool do_unmap)
|
||||||
err = uc_emu_start(uc, 0x100000, 0x103000, 0, 0);
|
err = uc_emu_start(uc, 0x100000, 0x103000, 0, 0);
|
||||||
if (err != UC_ERR_OK) {
|
if (err != UC_ERR_OK) {
|
||||||
printf("FAILED EXECUTION\n");
|
printf("FAILED EXECUTION\n");
|
||||||
printf("not ok - Failure on uc_emu_start() with error %u: %s\n", err, uc_strerror(err));
|
printf("not ok - Failure on uc_emu_start() with error %u: %s\n", err,
|
||||||
|
uc_strerror(err));
|
||||||
} else {
|
} else {
|
||||||
printf("SUCCESSFUL EXECUTION\n");
|
printf("SUCCESSFUL EXECUTION\n");
|
||||||
}
|
}
|
||||||
|
@ -331,7 +359,8 @@ static void unmap_test()
|
||||||
{
|
{
|
||||||
printf("Unmap demo - step 1: show that area is writeable\n");
|
printf("Unmap demo - step 1: show that area is writeable\n");
|
||||||
do_unmap_demo(false);
|
do_unmap_demo(false);
|
||||||
printf("Unmap demo - step 2: show that code fails when memory is unmapped\n");
|
printf(
|
||||||
|
"Unmap demo - step 2: show that code fails when memory is unmapped\n");
|
||||||
do_unmap_demo(true);
|
do_unmap_demo(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -6,29 +6,37 @@
|
||||||
#include <unicorn/unicorn.h>
|
#include <unicorn/unicorn.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
// code to be emulated
|
// code to be emulated
|
||||||
// #define ARM_CODE "\x37\x00\xa0\xe3" // mov r0, #0x37
|
// #define ARM_CODE "\x37\x00\xa0\xe3" // mov r0, #0x37
|
||||||
#define ARM_CODE "\x00\xf0\x20\xe3" // nop
|
#define ARM_CODE "\x00\xf0\x20\xe3" // nop
|
||||||
// #define ARM_CODE "\x37\x00\xa0\xe3\x03\x10\x42\xe0" // mov r0, #0x37; sub r1, r2, r3
|
// #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
|
#define THUMB_CODE "\x83\xb0" // sub sp, #0xc
|
||||||
|
|
||||||
#define ARM_THUM_COND_CODE "\x9a\x42\x14\xbf\x68\x22\x4d\x22" // 'cmp r2, r3\nit ne\nmov r2, #0x68\nmov r2, #0x4d'
|
#define ARM_THUM_COND_CODE \
|
||||||
|
"\x9a\x42\x14\xbf\x68\x22\x4d\x22" // 'cmp r2, r3\nit ne\nmov r2, #0x68\nmov
|
||||||
|
// r2, #0x4d'
|
||||||
|
|
||||||
// code to be emulated
|
// code to be emulated
|
||||||
#define ARM_CODE_EB "\xe3\xa0\x00\x37\xe0\x42\x10\x03" // mov r0, #0x37; sub r1, r2, r3
|
#define ARM_CODE_EB \
|
||||||
|
"\xe3\xa0\x00\x37\xe0\x42\x10\x03" // mov r0, #0x37; sub r1, r2, r3
|
||||||
#define THUMB_CODE_EB "\xb0\x83" // sub sp, #0xc
|
#define THUMB_CODE_EB "\xb0\x83" // sub sp, #0xc
|
||||||
// memory address where emulation starts
|
// memory address where emulation starts
|
||||||
#define ADDRESS 0x10000
|
#define ADDRESS 0x10000
|
||||||
|
|
||||||
static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
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);
|
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)
|
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);
|
printf(">>> Tracing instruction at 0x%" PRIx64
|
||||||
|
", instruction size = 0x%x\n",
|
||||||
|
address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_arm(void)
|
static void test_arm(void)
|
||||||
|
@ -47,8 +55,8 @@ static void test_arm(void)
|
||||||
// Initialize emulator in ARM mode
|
// Initialize emulator in ARM mode
|
||||||
err = uc_open(UC_ARCH_ARM, UC_MODE_ARM, &uc);
|
err = uc_open(UC_ARCH_ARM, UC_MODE_ARM, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +79,7 @@ static void test_arm(void)
|
||||||
|
|
||||||
// emulate machine code in infinite time (last param = 0), or when
|
// emulate machine code in infinite time (last param = 0), or when
|
||||||
// finishing all the code.
|
// finishing all the code.
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM_CODE) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||||
}
|
}
|
||||||
|
@ -100,8 +108,8 @@ static void test_thumb(void)
|
||||||
// Initialize emulator in ARM mode
|
// Initialize emulator in ARM mode
|
||||||
err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB, &uc);
|
err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,7 +131,7 @@ static void test_thumb(void)
|
||||||
// emulate machine code in infinite time (last param = 0), or when
|
// emulate machine code in infinite time (last param = 0), or when
|
||||||
// finishing all the code.
|
// finishing all the code.
|
||||||
// Note we start at ADDRESS | 1 to indicate THUMB mode.
|
// Note we start at ADDRESS | 1 to indicate THUMB mode.
|
||||||
err = uc_emu_start(uc, ADDRESS | 1, ADDRESS + sizeof(THUMB_CODE) -1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS | 1, ADDRESS + sizeof(THUMB_CODE) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||||
}
|
}
|
||||||
|
@ -153,8 +161,8 @@ static void test_armeb(void)
|
||||||
// Initialize emulator in ARM mode
|
// Initialize emulator in ARM mode
|
||||||
err = uc_open(UC_ARCH_ARM, UC_MODE_ARM + UC_MODE_BIG_ENDIAN, &uc);
|
err = uc_open(UC_ARCH_ARM, UC_MODE_ARM + UC_MODE_BIG_ENDIAN, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -177,7 +185,7 @@ static void test_armeb(void)
|
||||||
|
|
||||||
// emulate machine code in infinite time (last param = 0), or when
|
// emulate machine code in infinite time (last param = 0), or when
|
||||||
// finishing all the code.
|
// finishing all the code.
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM_CODE_EB) -1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM_CODE_EB) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||||
}
|
}
|
||||||
|
@ -206,8 +214,8 @@ static void test_thumbeb(void)
|
||||||
// Initialize emulator in ARM mode
|
// Initialize emulator in ARM mode
|
||||||
err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB + UC_MODE_BIG_ENDIAN, &uc);
|
err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB + UC_MODE_BIG_ENDIAN, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,7 +237,8 @@ static void test_thumbeb(void)
|
||||||
// emulate machine code in infinite time (last param = 0), or when
|
// emulate machine code in infinite time (last param = 0), or when
|
||||||
// finishing all the code.
|
// finishing all the code.
|
||||||
// Note we start at ADDRESS | 1 to indicate THUMB mode.
|
// Note we start at ADDRESS | 1 to indicate THUMB mode.
|
||||||
err = uc_emu_start(uc, ADDRESS | 1, ADDRESS + sizeof(THUMB_CODE_EB) -1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS | 1, ADDRESS + sizeof(THUMB_CODE_EB) - 1, 0,
|
||||||
|
0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||||
}
|
}
|
||||||
|
@ -257,8 +266,8 @@ static void test_thumb_mrs(void)
|
||||||
// Initialize emulator in ARM mode
|
// Initialize emulator in ARM mode
|
||||||
err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB | UC_MODE_MCLASS, &uc);
|
err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB | UC_MODE_MCLASS, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -288,14 +297,15 @@ static void test_thumb_mrs(void)
|
||||||
|
|
||||||
uc_reg_read(uc, UC_ARM_REG_PC, &pc);
|
uc_reg_read(uc, UC_ARM_REG_PC, &pc);
|
||||||
printf(">>> PC = 0x%x\n", pc);
|
printf(">>> PC = 0x%x\n", pc);
|
||||||
if (pc != ADDRESS + 4){
|
if (pc != ADDRESS + 4) {
|
||||||
printf("Error, PC was 0x%x, expected was 0x%x.\n", pc, ADDRESS + 4);
|
printf("Error, PC was 0x%x, expected was 0x%x.\n", pc, ADDRESS + 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
uc_close(uc);
|
uc_close(uc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_thumb_ite_internal(bool step, uint32_t *r2_out, uint32_t *r3_out)
|
static void test_thumb_ite_internal(bool step, uint32_t *r2_out,
|
||||||
|
uint32_t *r3_out)
|
||||||
{
|
{
|
||||||
uc_engine *uc;
|
uc_engine *uc;
|
||||||
uc_err err;
|
uc_err err;
|
||||||
|
@ -305,14 +315,15 @@ static void test_thumb_ite_internal(bool step, uint32_t *r2_out, uint32_t *r3_ou
|
||||||
|
|
||||||
err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB, &uc);
|
err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||||
|
|
||||||
uc_mem_write(uc, ADDRESS, ARM_THUM_COND_CODE, sizeof(ARM_THUM_COND_CODE) - 1);
|
uc_mem_write(uc, ADDRESS, ARM_THUM_COND_CODE,
|
||||||
|
sizeof(ARM_THUM_COND_CODE) - 1);
|
||||||
|
|
||||||
uc_reg_write(uc, UC_ARM_REG_SP, &sp);
|
uc_reg_write(uc, UC_ARM_REG_SP, &sp);
|
||||||
|
|
||||||
|
@ -320,16 +331,19 @@ static void test_thumb_ite_internal(bool step, uint32_t *r2_out, uint32_t *r3_ou
|
||||||
uc_reg_write(uc, UC_ARM_REG_R3, &r3);
|
uc_reg_write(uc, UC_ARM_REG_R3, &r3);
|
||||||
|
|
||||||
if (!step) {
|
if (!step) {
|
||||||
err = uc_emu_start(uc, ADDRESS | 1, ADDRESS + sizeof(ARM_THUM_COND_CODE) - 1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS | 1,
|
||||||
|
ADDRESS + sizeof(ARM_THUM_COND_CODE) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
int i, addr = ADDRESS;
|
int i, addr = ADDRESS;
|
||||||
for (i = 0; i < sizeof(ARM_THUM_COND_CODE) / 2; i++) {
|
for (i = 0; i < sizeof(ARM_THUM_COND_CODE) / 2; i++) {
|
||||||
err = uc_emu_start(uc, addr | 1, ADDRESS + sizeof(ARM_THUM_COND_CODE) - 1, 0, 1);
|
err = uc_emu_start(uc, addr | 1,
|
||||||
|
ADDRESS + sizeof(ARM_THUM_COND_CODE) - 1, 0, 1);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
printf("Failed on uc_emu_start() with error returned: %u\n",
|
||||||
|
err);
|
||||||
}
|
}
|
||||||
uc_reg_read(uc, UC_ARM_REG_PC, &addr);
|
uc_reg_read(uc, UC_ARM_REG_PC, &addr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,48 +6,53 @@
|
||||||
#include <unicorn/unicorn.h>
|
#include <unicorn/unicorn.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
// code to be emulated
|
// code to be emulated
|
||||||
#define ARM64_CODE "\xab\x05\x00\xb8\xaf\x05\x40\x38" // str w11, [x13], #0; ldrb w15, [x13], #0
|
#define ARM64_CODE \
|
||||||
//#define ARM64_CODE_EB "\xb8\x00\x05\xab\x38\x40\x05\xaf" // str w11, [x13]; ldrb w15, [x13]
|
"\xab\x05\x00\xb8\xaf\x05\x40\x38" // str w11, [x13], #0; ldrb w15, [x13],
|
||||||
|
// #0
|
||||||
|
//#define ARM64_CODE_EB "\xb8\x00\x05\xab\x38\x40\x05\xaf" // str w11, [x13];
|
||||||
|
//ldrb w15, [x13]
|
||||||
#define ARM64_CODE_EB ARM64_CODE
|
#define ARM64_CODE_EB ARM64_CODE
|
||||||
|
|
||||||
// memory address where emulation starts
|
// memory address where emulation starts
|
||||||
#define ADDRESS 0x10000
|
#define ADDRESS 0x10000
|
||||||
|
|
||||||
static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
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);
|
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)
|
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);
|
printf(">>> Tracing instruction at 0x%" PRIx64
|
||||||
|
", instruction size = 0x%x\n",
|
||||||
|
address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_arm64_mem_fetch(void)
|
static void test_arm64_mem_fetch(void)
|
||||||
{
|
{
|
||||||
uc_engine* uc;
|
uc_engine *uc;
|
||||||
uc_err err;
|
uc_err err;
|
||||||
uint64_t x1, sp, x0;
|
uint64_t x1, sp, x0;
|
||||||
// msr x0, CurrentEL
|
// msr x0, CurrentEL
|
||||||
unsigned char shellcode0[4] = {
|
unsigned char shellcode0[4] = {64, 66, 56, 213};
|
||||||
64, 66, 56, 213
|
|
||||||
};
|
|
||||||
// .text:00000000004002C0 LDR X1, [SP,#arg_0]
|
// .text:00000000004002C0 LDR X1, [SP,#arg_0]
|
||||||
unsigned char shellcode[4] = {
|
unsigned char shellcode[4] = {0xE1, 0x03, 0x40, 0xF9};
|
||||||
0xE1, 0x03, 0x40, 0xF9
|
|
||||||
};
|
|
||||||
unsigned shellcode_address = 0x4002C0;
|
unsigned shellcode_address = 0x4002C0;
|
||||||
uint64_t data_address = 0x10000000000000;
|
uint64_t data_address = 0x10000000000000;
|
||||||
|
|
||||||
printf(">>> Emulate ARM64 fetching stack data from high address %"PRIx64"\n", data_address);
|
printf(">>> Emulate ARM64 fetching stack data from high address %" PRIx64
|
||||||
|
"\n",
|
||||||
|
data_address);
|
||||||
|
|
||||||
// Initialize emulator in ARM mode
|
// Initialize emulator in ARM mode
|
||||||
err = uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc);
|
err = uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,16 +65,16 @@ static void test_arm64_mem_fetch(void)
|
||||||
uc_mem_write(uc, shellcode_address, shellcode0, 4);
|
uc_mem_write(uc, shellcode_address, shellcode0, 4);
|
||||||
uc_mem_write(uc, shellcode_address + 4, shellcode, 4);
|
uc_mem_write(uc, shellcode_address + 4, shellcode, 4);
|
||||||
|
|
||||||
err = uc_emu_start(uc, shellcode_address, shellcode_address+4, 0, 0);
|
err = uc_emu_start(uc, shellcode_address, shellcode_address + 4, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
x0 = 0;
|
x0 = 0;
|
||||||
uc_reg_read(uc, UC_ARM64_REG_X0, &x0);
|
uc_reg_read(uc, UC_ARM64_REG_X0, &x0);
|
||||||
printf(">>> x0(Exception Level)=%"PRIx64"\n", x0>>2);
|
printf(">>> x0(Exception Level)=%" PRIx64 "\n", x0 >> 2);
|
||||||
|
|
||||||
err = uc_emu_start(uc, shellcode_address+4, shellcode_address+8, 0, 0);
|
err = uc_emu_start(uc, shellcode_address + 4, shellcode_address + 8, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||||
}
|
}
|
||||||
|
@ -96,8 +101,8 @@ static void test_arm64(void)
|
||||||
// Initialize emulator in ARM mode
|
// Initialize emulator in ARM mode
|
||||||
err = uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc);
|
err = uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -120,7 +125,7 @@ static void test_arm64(void)
|
||||||
|
|
||||||
// emulate machine code in infinite time (last param = 0), or when
|
// emulate machine code in infinite time (last param = 0), or when
|
||||||
// finishing all the code.
|
// finishing all the code.
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM64_CODE) -1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM64_CODE) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||||
}
|
}
|
||||||
|
@ -150,8 +155,8 @@ static void test_arm64eb(void)
|
||||||
// Initialize emulator in ARM mode
|
// Initialize emulator in ARM mode
|
||||||
err = uc_open(UC_ARCH_ARM64, UC_MODE_ARM + UC_MODE_BIG_ENDIAN, &uc);
|
err = uc_open(UC_ARCH_ARM64, UC_MODE_ARM + UC_MODE_BIG_ENDIAN, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +179,7 @@ static void test_arm64eb(void)
|
||||||
|
|
||||||
// emulate machine code in infinite time (last param = 0), or when
|
// emulate machine code in infinite time (last param = 0), or when
|
||||||
// finishing all the code.
|
// finishing all the code.
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM64_CODE_EB) -1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM64_CODE_EB) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,17 +2,15 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int syscall_abi[] = {UC_X86_REG_RAX, UC_X86_REG_RDI, UC_X86_REG_RSI,
|
||||||
|
UC_X86_REG_RDX, UC_X86_REG_R10, UC_X86_REG_R8,
|
||||||
|
UC_X86_REG_R9};
|
||||||
|
|
||||||
int syscall_abi[] = {
|
uint64_t vals[7] = {200, 10, 11, 12, 13, 14, 15};
|
||||||
UC_X86_REG_RAX, UC_X86_REG_RDI, UC_X86_REG_RSI, UC_X86_REG_RDX,
|
|
||||||
UC_X86_REG_R10, UC_X86_REG_R8, UC_X86_REG_R9
|
|
||||||
};
|
|
||||||
|
|
||||||
uint64_t vals[7] = { 200, 10, 11, 12, 13, 14, 15 };
|
// This part of the API is less... clean... because Unicorn supports arbitrary
|
||||||
|
// register types. So the least intrusive solution is passing individual
|
||||||
// This part of the API is less... clean... because Unicorn supports arbitrary register types.
|
// pointers. On the plus side, you only need to make this pointer array once.
|
||||||
// So the least intrusive solution is passing individual pointers.
|
|
||||||
// On the plus side, you only need to make this pointer array once.
|
|
||||||
void *ptrs[7];
|
void *ptrs[7];
|
||||||
|
|
||||||
void uc_perror(const char *func, uc_err err)
|
void uc_perror(const char *func, uc_err err)
|
||||||
|
@ -22,8 +20,12 @@ void uc_perror(const char *func, uc_err err)
|
||||||
|
|
||||||
#define BASE 0x10000
|
#define BASE 0x10000
|
||||||
|
|
||||||
// mov rax, 100; mov rdi, 1; mov rsi, 2; mov rdx, 3; mov r10, 4; mov r8, 5; mov r9, 6; syscall
|
// mov rax, 100; mov rdi, 1; mov rsi, 2; mov rdx, 3; mov r10, 4; mov r8, 5; mov
|
||||||
#define CODE "\x48\xc7\xc0\x64\x00\x00\x00\x48\xc7\xc7\x01\x00\x00\x00\x48\xc7\xc6\x02\x00\x00\x00\x48\xc7\xc2\x03\x00\x00\x00\x49\xc7\xc2\x04\x00\x00\x00\x49\xc7\xc0\x05\x00\x00\x00\x49\xc7\xc1\x06\x00\x00\x00\x0f\x05"
|
// r9, 6; syscall
|
||||||
|
#define CODE \
|
||||||
|
"\x48\xc7\xc0\x64\x00\x00\x00\x48\xc7\xc7\x01\x00\x00\x00\x48\xc7\xc6\x02" \
|
||||||
|
"\x00\x00\x00\x48\xc7\xc2\x03\x00\x00\x00\x49\xc7\xc2\x04\x00\x00\x00\x49" \
|
||||||
|
"\xc7\xc0\x05\x00\x00\x00\x49\xc7\xc1\x06\x00\x00\x00\x0f\x05"
|
||||||
|
|
||||||
void hook_syscall(uc_engine *uc, void *user_data)
|
void hook_syscall(uc_engine *uc, void *user_data)
|
||||||
{
|
{
|
||||||
|
@ -34,7 +36,8 @@ void hook_syscall(uc_engine *uc, void *user_data)
|
||||||
printf("syscall: {");
|
printf("syscall: {");
|
||||||
|
|
||||||
for (i = 0; i < 7; i++) {
|
for (i = 0; i < 7; i++) {
|
||||||
if (i != 0) printf(", ");
|
if (i != 0)
|
||||||
|
printf(", ");
|
||||||
printf("%" PRIu64, vals[i]);
|
printf("%" PRIu64, vals[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +83,8 @@ int main()
|
||||||
printf("reg_read_batch = {");
|
printf("reg_read_batch = {");
|
||||||
|
|
||||||
for (i = 0; i < 7; i++) {
|
for (i = 0; i < 7; i++) {
|
||||||
if (i != 0) printf(", ");
|
if (i != 0)
|
||||||
|
printf(", ");
|
||||||
printf("%" PRIu64, vals[i]);
|
printf("%" PRIu64, vals[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,7 +94,8 @@ int main()
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("running syscall shellcode\n");
|
printf("running syscall shellcode\n");
|
||||||
|
|
||||||
if ((err = uc_hook_add(uc, &sys_hook, UC_HOOK_INSN, hook_syscall, NULL, 1, 0, UC_X86_INS_SYSCALL))) {
|
if ((err = uc_hook_add(uc, &sys_hook, UC_HOOK_INSN, hook_syscall, NULL, 1,
|
||||||
|
0, UC_X86_INS_SYSCALL))) {
|
||||||
uc_perror("uc_hook_add", err);
|
uc_perror("uc_hook_add", err);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,21 +6,25 @@
|
||||||
#include <unicorn/unicorn.h>
|
#include <unicorn/unicorn.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
// code to be emulated
|
// code to be emulated
|
||||||
#define M68K_CODE "\x76\xed" // movq #-19, %d3
|
#define M68K_CODE "\x76\xed" // movq #-19, %d3
|
||||||
|
|
||||||
// memory address where emulation starts
|
// memory address where emulation starts
|
||||||
#define ADDRESS 0x10000
|
#define ADDRESS 0x10000
|
||||||
|
|
||||||
static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
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);
|
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)
|
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);
|
printf(">>> Tracing instruction at 0x%" PRIx64
|
||||||
|
", instruction size = 0x%x\n",
|
||||||
|
address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_m68k(void)
|
static void test_m68k(void)
|
||||||
|
@ -55,8 +59,8 @@ static void test_m68k(void)
|
||||||
// Initialize emulator in M68K mode
|
// Initialize emulator in M68K mode
|
||||||
err = uc_open(UC_ARCH_M68K, UC_MODE_BIG_ENDIAN, &uc);
|
err = uc_open(UC_ARCH_M68K, UC_MODE_BIG_ENDIAN, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -96,7 +100,7 @@ static void test_m68k(void)
|
||||||
|
|
||||||
// emulate machine code in infinite time (last param = 0), or when
|
// emulate machine code in infinite time (last param = 0), or when
|
||||||
// finishing all the code.
|
// finishing all the code.
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(M68K_CODE)-1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(M68K_CODE) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include <unicorn/unicorn.h>
|
#include <unicorn/unicorn.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
// code to be emulated
|
// code to be emulated
|
||||||
#define MIPS_CODE_EB "\x34\x21\x34\x56" // ori $at, $at, 0x3456;
|
#define MIPS_CODE_EB "\x34\x21\x34\x56" // ori $at, $at, 0x3456;
|
||||||
#define MIPS_CODE_EL "\x56\x34\x21\x34" // ori $at, $at, 0x3456;
|
#define MIPS_CODE_EL "\x56\x34\x21\x34" // ori $at, $at, 0x3456;
|
||||||
|
@ -14,14 +13,19 @@
|
||||||
// memory address where emulation starts
|
// memory address where emulation starts
|
||||||
#define ADDRESS 0x10000
|
#define ADDRESS 0x10000
|
||||||
|
|
||||||
static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
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);
|
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)
|
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);
|
printf(">>> Tracing instruction at 0x%" PRIx64
|
||||||
|
", instruction size = 0x%x\n",
|
||||||
|
address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_mips_eb(void)
|
static void test_mips_eb(void)
|
||||||
|
@ -37,8 +41,8 @@ static void test_mips_eb(void)
|
||||||
// Initialize emulator in MIPS mode
|
// Initialize emulator in MIPS mode
|
||||||
err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN, &uc);
|
err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,7 +65,8 @@ static void test_mips_eb(void)
|
||||||
// finishing all the code.
|
// finishing all the code.
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(MIPS_CODE_EB) - 1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(MIPS_CODE_EB) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err, uc_strerror(err));
|
printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err,
|
||||||
|
uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now print out some registers
|
// now print out some registers
|
||||||
|
@ -87,8 +92,8 @@ static void test_mips_el(void)
|
||||||
// Initialize emulator in MIPS mode
|
// Initialize emulator in MIPS mode
|
||||||
err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN, &uc);
|
err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +116,8 @@ static void test_mips_el(void)
|
||||||
// finishing all the code.
|
// finishing all the code.
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(MIPS_CODE_EL) - 1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(MIPS_CODE_EL) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err, uc_strerror(err));
|
printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err,
|
||||||
|
uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now print out some registers
|
// now print out some registers
|
||||||
|
|
|
@ -6,22 +6,25 @@
|
||||||
#include <unicorn/unicorn.h>
|
#include <unicorn/unicorn.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
// code to be emulated
|
// code to be emulated
|
||||||
#define PPC_CODE "\x7F\x46\x1A\x14" // add r26, r6, r3
|
#define PPC_CODE "\x7F\x46\x1A\x14" // add r26, r6, r3
|
||||||
|
|
||||||
// memory address where emulation starts
|
// memory address where emulation starts
|
||||||
#define ADDRESS 0x10000
|
#define ADDRESS 0x10000
|
||||||
|
|
||||||
|
static void hook_block(uc_engine *uc, uint64_t address, uint32_t size,
|
||||||
static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
void *user_data)
|
||||||
{
|
{
|
||||||
printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size);
|
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)
|
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);
|
printf(">>> Tracing instruction at 0x%" PRIx64
|
||||||
|
", instruction size = 0x%x\n",
|
||||||
|
address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_ppc(void)
|
static void test_ppc(void)
|
||||||
|
@ -37,10 +40,10 @@ static void test_ppc(void)
|
||||||
printf("Emulate PPC code\n");
|
printf("Emulate PPC code\n");
|
||||||
|
|
||||||
// Initialize emulator in PPC mode
|
// Initialize emulator in PPC mode
|
||||||
err = uc_open(UC_ARCH_PPC, UC_MODE_PPC32 | UC_MODE_BIG_ENDIAN , &uc);
|
err = uc_open(UC_ARCH_PPC, UC_MODE_PPC32 | UC_MODE_BIG_ENDIAN, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,7 +66,7 @@ static void test_ppc(void)
|
||||||
|
|
||||||
// emulate machine code in infinite time (last param = 0), or when
|
// emulate machine code in infinite time (last param = 0), or when
|
||||||
// finishing all the code.
|
// finishing all the code.
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(PPC_CODE) -1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(PPC_CODE) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||||
return;
|
return;
|
||||||
|
@ -79,7 +82,6 @@ static void test_ppc(void)
|
||||||
uc_close(uc);
|
uc_close(uc);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
int main(int argc, char **argv, char **envp)
|
int main(int argc, char **argv, char **envp)
|
||||||
{
|
{
|
||||||
test_ppc();
|
test_ppc();
|
||||||
|
|
|
@ -5,7 +5,6 @@
|
||||||
#include <unicorn/unicorn.h>
|
#include <unicorn/unicorn.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
// code to be emulated
|
// code to be emulated
|
||||||
#if 0
|
#if 0
|
||||||
$ cstool riscv64 1305100093850502
|
$ cstool riscv64 1305100093850502
|
||||||
|
@ -15,23 +14,30 @@ $ cstool riscv64 1305100093850502
|
||||||
//#define RISCV_CODE "\x13\x05\x10\x00\x93\x85\x05\x02\x93\x85\x05\x02"
|
//#define RISCV_CODE "\x13\x05\x10\x00\x93\x85\x05\x02\x93\x85\x05\x02"
|
||||||
#define RISCV_CODE "\x13\x05\x10\x00\x93\x85\x05\x02"
|
#define RISCV_CODE "\x13\x05\x10\x00\x93\x85\x05\x02"
|
||||||
|
|
||||||
|
|
||||||
// memory address where emulation starts
|
// memory address where emulation starts
|
||||||
#define ADDRESS 0x10000
|
#define ADDRESS 0x10000
|
||||||
|
|
||||||
static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
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);
|
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)
|
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);
|
printf(">>> Tracing instruction at 0x%" PRIx64
|
||||||
|
", instruction size = 0x%x\n",
|
||||||
|
address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hook_code3(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
static void hook_code3(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);
|
printf(">>> Tracing instruction at 0x%" PRIx64
|
||||||
|
", instruction size = 0x%x\n",
|
||||||
|
address, size);
|
||||||
if (address == ADDRESS) {
|
if (address == ADDRESS) {
|
||||||
printf("stop emulation\n");
|
printf("stop emulation\n");
|
||||||
uc_emu_stop(uc);
|
uc_emu_stop(uc);
|
||||||
|
@ -52,8 +58,8 @@ static void test_riscv(void)
|
||||||
// Initialize emulator in RISCV64 mode
|
// Initialize emulator in RISCV64 mode
|
||||||
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -106,8 +112,8 @@ static void test_riscv2(void)
|
||||||
// Initialize emulator in RISCV64 mode
|
// Initialize emulator in RISCV64 mode
|
||||||
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,8 +177,8 @@ static void test_riscv3(void)
|
||||||
// Initialize emulator in RISCV64 mode
|
// Initialize emulator in RISCV64 mode
|
||||||
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -226,8 +232,8 @@ static void test_riscv_step(void)
|
||||||
// Initialize emulator in RISCV64 mode
|
// Initialize emulator in RISCV64 mode
|
||||||
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -297,8 +303,8 @@ static void test_riscv_timeout(void)
|
||||||
// Initialize emulator in RISCV64 mode
|
// Initialize emulator in RISCV64 mode
|
||||||
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -365,8 +371,8 @@ static void test_riscv_sd64(void)
|
||||||
// Initialize emulator in RISCV64 mode
|
// Initialize emulator in RISCV64 mode
|
||||||
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV64, &uc);
|
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV64, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,7 +412,8 @@ static bool hook_memalloc(uc_engine *uc, uc_mem_type type, uint64_t address,
|
||||||
uint64_t algined_address = address & 0xFFFFFFFFFFFFF000ULL;
|
uint64_t algined_address = address & 0xFFFFFFFFFFFFF000ULL;
|
||||||
int aligned_size = ((int)(size / 0x1000) + 1) * 0x1000;
|
int aligned_size = ((int)(size / 0x1000) + 1) * 0x1000;
|
||||||
|
|
||||||
printf(">>> Allocating block at 0x%" PRIx64 " (0x%" PRIx64 "), block size = 0x%x (0x%x)\n",
|
printf(">>> Allocating block at 0x%" PRIx64 " (0x%" PRIx64
|
||||||
|
"), block size = 0x%x (0x%x)\n",
|
||||||
address, algined_address, size, aligned_size);
|
address, algined_address, size, aligned_size);
|
||||||
|
|
||||||
uc_mem_map(uc, algined_address, aligned_size, UC_PROT_ALL);
|
uc_mem_map(uc, algined_address, aligned_size, UC_PROT_ALL);
|
||||||
|
@ -439,7 +446,8 @@ static void test_recover_from_illegal(void)
|
||||||
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||||
|
|
||||||
// auto-allocate memory on access
|
// auto-allocate memory on access
|
||||||
uc_hook_add(uc, &mem_alloc, UC_HOOK_MEM_UNMAPPED, hook_memalloc, NULL, 1, 0);
|
uc_hook_add(uc, &mem_alloc, UC_HOOK_MEM_UNMAPPED, hook_memalloc, NULL, 1,
|
||||||
|
0);
|
||||||
|
|
||||||
// tracing all basic blocks with customized callback
|
// tracing all basic blocks with customized callback
|
||||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
||||||
|
@ -469,8 +477,8 @@ static void test_recover_from_illegal(void)
|
||||||
uc_reg_read(uc, UC_RISCV_REG_A0, &a0);
|
uc_reg_read(uc, UC_RISCV_REG_A0, &a0);
|
||||||
uc_reg_read(uc, UC_RISCV_REG_A1, &a1);
|
uc_reg_read(uc, UC_RISCV_REG_A1, &a1);
|
||||||
|
|
||||||
printf(">>> A0 = 0x%"PRIx64 "\n", a0);
|
printf(">>> A0 = 0x%" PRIx64 "\n", a0);
|
||||||
printf(">>> A1 = 0x%"PRIx64 "\n", a1);
|
printf(">>> A1 = 0x%" PRIx64 "\n", a1);
|
||||||
|
|
||||||
uc_close(uc);
|
uc_close(uc);
|
||||||
}
|
}
|
||||||
|
@ -495,8 +503,8 @@ static void test_riscv_func_return(void)
|
||||||
// Initialize emulator in RISCV64 mode
|
// Initialize emulator in RISCV64 mode
|
||||||
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV64, &uc);
|
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV64, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -527,7 +535,9 @@ static void test_riscv_func_return(void)
|
||||||
|
|
||||||
uc_reg_read(uc, UC_RISCV_REG_PC, &pc);
|
uc_reg_read(uc, UC_RISCV_REG_PC, &pc);
|
||||||
if (pc != ra) {
|
if (pc != ra) {
|
||||||
printf("Error after execution: PC is: 0x%"PRIx64 ", expected was 0x%"PRIx64 "\n", pc, ra);
|
printf("Error after execution: PC is: 0x%" PRIx64
|
||||||
|
", expected was 0x%" PRIx64 "\n",
|
||||||
|
pc, ra);
|
||||||
if (pc == 0x10000) {
|
if (pc == 0x10000) {
|
||||||
printf(" PC did not change during execution\n");
|
printf(" PC did not change during execution\n");
|
||||||
}
|
}
|
||||||
|
@ -551,7 +561,9 @@ static void test_riscv_func_return(void)
|
||||||
|
|
||||||
uc_reg_read(uc, UC_RISCV_REG_PC, &pc);
|
uc_reg_read(uc, UC_RISCV_REG_PC, &pc);
|
||||||
if (pc != ra) {
|
if (pc != ra) {
|
||||||
printf("Error after execution: PC is: 0x%"PRIx64 ", expected was 0x%"PRIx64 "\n", pc, ra);
|
printf("Error after execution: PC is: 0x%" PRIx64
|
||||||
|
", expected was 0x%" PRIx64 "\n",
|
||||||
|
pc, ra);
|
||||||
if (pc == 0x10004) {
|
if (pc == 0x10004) {
|
||||||
printf(" PC did not change during execution\n");
|
printf(" PC did not change during execution\n");
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
#include <unicorn/unicorn.h>
|
#include <unicorn/unicorn.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
// code to be emulated
|
// code to be emulated
|
||||||
#define SPARC_CODE "\x86\x00\x40\x02" // add %g1, %g2, %g3;
|
#define SPARC_CODE "\x86\x00\x40\x02" // add %g1, %g2, %g3;
|
||||||
//#define SPARC_CODE "\xbb\x70\x00\x00" // illegal code
|
//#define SPARC_CODE "\xbb\x70\x00\x00" // illegal code
|
||||||
|
@ -14,14 +13,19 @@
|
||||||
// memory address where emulation starts
|
// memory address where emulation starts
|
||||||
#define ADDRESS 0x10000
|
#define ADDRESS 0x10000
|
||||||
|
|
||||||
static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
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);
|
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)
|
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);
|
printf(">>> Tracing instruction at 0x%" PRIx64
|
||||||
|
", instruction size = 0x%x\n",
|
||||||
|
address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_sparc(void)
|
static void test_sparc(void)
|
||||||
|
@ -37,10 +41,10 @@ static void test_sparc(void)
|
||||||
printf("Emulate SPARC code\n");
|
printf("Emulate SPARC code\n");
|
||||||
|
|
||||||
// Initialize emulator in Sparc mode
|
// Initialize emulator in Sparc mode
|
||||||
err = uc_open(UC_ARCH_SPARC, UC_MODE_SPARC32|UC_MODE_BIG_ENDIAN, &uc);
|
err = uc_open(UC_ARCH_SPARC, UC_MODE_SPARC32 | UC_MODE_BIG_ENDIAN, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -65,8 +69,8 @@ static void test_sparc(void)
|
||||||
// finishing all the code.
|
// finishing all the code.
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(SPARC_CODE) - 1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(SPARC_CODE) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned: %u (%s)\n",
|
printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now print out some registers
|
// now print out some registers
|
||||||
|
|
|
@ -6,27 +6,45 @@
|
||||||
#include <unicorn/unicorn.h>
|
#include <unicorn/unicorn.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
// code to be emulated
|
// code to be emulated
|
||||||
#define X86_CODE32 "\x41\x4a\x66\x0f\xef\xc1" // INC ecx; DEC edx; PXOR xmm0, xmm1
|
#define X86_CODE32 \
|
||||||
#define X86_CODE32_JUMP "\xeb\x02\x90\x90\x90\x90\x90\x90" // jmp 4; nop; nop; nop; nop; nop; nop
|
"\x41\x4a\x66\x0f\xef\xc1" // INC ecx; DEC edx; PXOR xmm0, xmm1
|
||||||
// #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_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 "\x51\x51\x51\x51" // PUSH ecx;
|
||||||
#define X86_CODE32_LOOP "\x41\x4a\xeb\xfe" // INC ecx; DEC edx; JMP self-loop
|
#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_WRITE \
|
||||||
#define X86_CODE32_MEM_READ "\x8B\x0D\xAA\xAA\xAA\xAA\x41\x4a" // mov ecx,[0xaaaaaaaa]; INC ecx; DEC edx
|
"\x89\x0D\xAA\xAA\xAA\xAA\x41\x4a" // mov [0xaaaaaaaa], ecx; INC ecx; DEC
|
||||||
#define X86_CODE32_MEM_READ_IN_TB "\x40\x8b\x1d\x00\x00\x10\x00\x42" // inc eax; mov ebx, [0x100000]; inc edx
|
// edx
|
||||||
|
#define X86_CODE32_MEM_READ \
|
||||||
|
"\x8B\x0D\xAA\xAA\xAA\xAA\x41\x4a" // mov ecx,[0xaaaaaaaa]; INC ecx; DEC edx
|
||||||
|
#define X86_CODE32_MEM_READ_IN_TB \
|
||||||
|
"\x40\x8b\x1d\x00\x00\x10\x00\x42" // inc eax; mov ebx, [0x100000]; inc edx
|
||||||
|
|
||||||
#define X86_CODE32_JMP_INVALID "\xe9\xe9\xee\xee\xee\x41\x4a" // JMP outside; INC ecx; DEC edx
|
#define X86_CODE32_JMP_INVALID \
|
||||||
#define X86_CODE32_INOUT "\x41\xE4\x3F\x4a\xE6\x46\x43" // INC ecx; IN AL, 0x3f; DEC edx; OUT 0x46, AL; INC ebx
|
"\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_CODE32_INC "\x40" // INC eax
|
#define X86_CODE32_INC "\x40" // INC eax
|
||||||
|
|
||||||
//#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
|
||||||
//#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\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"
|
//<== 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_CODE16 "\x00\x00" // add byte ptr [bx + si], al
|
||||||
#define X86_CODE64_SYSCALL "\x0f\x05" // SYSCALL
|
#define X86_CODE64_SYSCALL "\x0f\x05" // SYSCALL
|
||||||
#define X86_MMIO_CODE "\x89\x0d\x04\x00\x02\x00\x8b\x0d\x04\x00\x02\x00" // mov [0x20004], ecx; mov ecx, [0x20004]
|
#define X86_MMIO_CODE \
|
||||||
|
"\x89\x0d\x04\x00\x02\x00\x8b\x0d\x04\x00\x02\x00" // mov [0x20004], ecx;
|
||||||
|
// mov ecx, [0x20004]
|
||||||
/*
|
/*
|
||||||
* 0x1000 xor dword ptr [edi+0x3], eax ; edi=0x1000, eax=0xbc4177e6
|
* 0x1000 xor dword ptr [edi+0x3], eax ; edi=0x1000, eax=0xbc4177e6
|
||||||
* 0x1003 dw 0x3ea98b13
|
* 0x1003 dw 0x3ea98b13
|
||||||
|
@ -37,16 +55,21 @@
|
||||||
#define ADDRESS 0x1000000
|
#define ADDRESS 0x1000000
|
||||||
|
|
||||||
// callback for tracing basic blocks
|
// callback for tracing basic blocks
|
||||||
static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
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);
|
printf(">>> Tracing basic block at 0x%" PRIx64 ", block size = 0x%x\n",
|
||||||
|
address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// callback for tracing instruction
|
// callback for tracing instruction
|
||||||
static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
static void hook_code(uc_engine *uc, uint64_t address, uint32_t size,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
int eflags;
|
int eflags;
|
||||||
printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size);
|
printf(">>> Tracing instruction at 0x%" PRIx64
|
||||||
|
", instruction size = 0x%x\n",
|
||||||
|
address, size);
|
||||||
|
|
||||||
uc_reg_read(uc, UC_X86_REG_EFLAGS, &eflags);
|
uc_reg_read(uc, UC_X86_REG_EFLAGS, &eflags);
|
||||||
printf(">>> --- EFLAGS is 0x%x\n", eflags);
|
printf(">>> --- EFLAGS is 0x%x\n", eflags);
|
||||||
|
@ -57,13 +80,16 @@ static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user
|
||||||
}
|
}
|
||||||
|
|
||||||
// callback for tracing instruction
|
// callback for tracing instruction
|
||||||
static void hook_code64(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
static void hook_code64(uc_engine *uc, uint64_t address, uint32_t size,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
uint64_t rip;
|
uint64_t rip;
|
||||||
|
|
||||||
uc_reg_read(uc, UC_X86_REG_RIP, &rip);
|
uc_reg_read(uc, UC_X86_REG_RIP, &rip);
|
||||||
printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size);
|
printf(">>> Tracing instruction at 0x%" PRIx64
|
||||||
printf(">>> RIP is 0x%"PRIx64 "\n", rip);
|
", 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()
|
// Uncomment below code to stop the emulation using uc_emu_stop()
|
||||||
// if (address == 0x1000009)
|
// if (address == 0x1000009)
|
||||||
|
@ -71,18 +97,19 @@ static void hook_code64(uc_engine *uc, uint64_t address, uint32_t size, void *us
|
||||||
}
|
}
|
||||||
|
|
||||||
// callback for tracing memory access (READ or WRITE)
|
// callback for tracing memory access (READ or WRITE)
|
||||||
static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
|
static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type, uint64_t address,
|
||||||
uint64_t address, int size, int64_t value, void *user_data)
|
int size, int64_t value, void *user_data)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch (type) {
|
||||||
default:
|
default:
|
||||||
// return false to indicate we want to stop emulation
|
// return false to indicate we want to stop emulation
|
||||||
return false;
|
return false;
|
||||||
case UC_MEM_WRITE_UNMAPPED:
|
case UC_MEM_WRITE_UNMAPPED:
|
||||||
printf(">>> Missing memory is being WRITE at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n",
|
printf(">>> Missing memory is being WRITE at 0x%" PRIx64
|
||||||
|
", data size = %u, data value = 0x%" PRIx64 "\n",
|
||||||
address, size, value);
|
address, size, value);
|
||||||
// map this memory in with 2MB in size
|
// map this memory in with 2MB in size
|
||||||
uc_mem_map(uc, 0xaaaa0000, 2 * 1024*1024, UC_PROT_ALL);
|
uc_mem_map(uc, 0xaaaa0000, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||||
// return true to indicate we want to continue
|
// return true to indicate we want to continue
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -90,23 +117,26 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
|
||||||
|
|
||||||
// dummy callback
|
// dummy callback
|
||||||
static bool hook_mem_invalid_dummy(uc_engine *uc, uc_mem_type type,
|
static bool hook_mem_invalid_dummy(uc_engine *uc, uc_mem_type type,
|
||||||
uint64_t address, int size, int64_t value, void *user_data)
|
uint64_t address, int size, int64_t value,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
// stop emulation
|
// stop emulation
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hook_mem64(uc_engine *uc, uc_mem_type type,
|
static void hook_mem64(uc_engine *uc, uc_mem_type type, uint64_t address,
|
||||||
uint64_t address, int size, int64_t value, void *user_data)
|
int size, int64_t value, void *user_data)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch (type) {
|
||||||
default: break;
|
default:
|
||||||
|
break;
|
||||||
case UC_MEM_READ:
|
case UC_MEM_READ:
|
||||||
printf(">>> Memory is being READ at 0x%"PRIx64 ", data size = %u\n",
|
printf(">>> Memory is being READ at 0x%" PRIx64 ", data size = %u\n",
|
||||||
address, size);
|
address, size);
|
||||||
break;
|
break;
|
||||||
case UC_MEM_WRITE:
|
case UC_MEM_WRITE:
|
||||||
printf(">>> Memory is being WRITE at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n",
|
printf(">>> Memory is being WRITE at 0x%" PRIx64
|
||||||
|
", data size = %u, data value = 0x%" PRIx64 "\n",
|
||||||
address, size, value);
|
address, size, value);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -120,9 +150,10 @@ static uint32_t hook_in(uc_engine *uc, uint32_t port, int size, void *user_data)
|
||||||
|
|
||||||
uc_reg_read(uc, UC_X86_REG_EIP, &eip);
|
uc_reg_read(uc, UC_X86_REG_EIP, &eip);
|
||||||
|
|
||||||
printf("--- reading from port 0x%x, size: %u, address: 0x%x\n", port, size, eip);
|
printf("--- reading from port 0x%x, size: %u, address: 0x%x\n", port, size,
|
||||||
|
eip);
|
||||||
|
|
||||||
switch(size) {
|
switch (size) {
|
||||||
default:
|
default:
|
||||||
return 0; // should never reach this
|
return 0; // should never reach this
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -139,17 +170,19 @@ static uint32_t hook_in(uc_engine *uc, uint32_t port, int size, void *user_data)
|
||||||
}
|
}
|
||||||
|
|
||||||
// callback for OUT instruction (X86).
|
// callback for OUT instruction (X86).
|
||||||
static void hook_out(uc_engine *uc, uint32_t port, int size, uint32_t value, void *user_data)
|
static void hook_out(uc_engine *uc, uint32_t port, int size, uint32_t value,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
uint32_t tmp = 0;
|
uint32_t tmp = 0;
|
||||||
uint32_t eip;
|
uint32_t eip;
|
||||||
|
|
||||||
uc_reg_read(uc, UC_X86_REG_EIP, &eip);
|
uc_reg_read(uc, UC_X86_REG_EIP, &eip);
|
||||||
|
|
||||||
printf("--- writing to port 0x%x, size: %u, value: 0x%x, address: 0x%x\n", port, size, value, eip);
|
printf("--- writing to port 0x%x, size: %u, value: 0x%x, address: 0x%x\n",
|
||||||
|
port, size, value, eip);
|
||||||
|
|
||||||
// confirm that value is indeed the value of AL/AX/EAX
|
// confirm that value is indeed the value of AL/AX/EAX
|
||||||
switch(size) {
|
switch (size) {
|
||||||
default:
|
default:
|
||||||
return; // should never reach this
|
return; // should never reach this
|
||||||
case 1:
|
case 1:
|
||||||
|
@ -176,7 +209,7 @@ static void hook_syscall(uc_engine *uc, void *user_data)
|
||||||
rax = 0x200;
|
rax = 0x200;
|
||||||
uc_reg_write(uc, UC_X86_REG_RAX, &rax);
|
uc_reg_write(uc, UC_X86_REG_RAX, &rax);
|
||||||
} else
|
} else
|
||||||
printf("ERROR: was not expecting rax=0x%"PRIx64 " in syscall\n", rax);
|
printf("ERROR: was not expecting rax=0x%" PRIx64 " in syscall\n", rax);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool hook_memalloc(uc_engine *uc, uc_mem_type type, uint64_t address,
|
static bool hook_memalloc(uc_engine *uc, uc_mem_type type, uint64_t address,
|
||||||
|
@ -185,7 +218,8 @@ static bool hook_memalloc(uc_engine *uc, uc_mem_type type, uint64_t address,
|
||||||
uint64_t algined_address = address & 0xFFFFFFFFFFFFF000ULL;
|
uint64_t algined_address = address & 0xFFFFFFFFFFFFF000ULL;
|
||||||
int aligned_size = ((int)(size / 0x1000) + 1) * 0x1000;
|
int aligned_size = ((int)(size / 0x1000) + 1) * 0x1000;
|
||||||
|
|
||||||
printf(">>> Allocating block at 0x%" PRIx64 " (0x%" PRIx64 "), block size = 0x%x (0x%x)\n",
|
printf(">>> Allocating block at 0x%" PRIx64 " (0x%" PRIx64
|
||||||
|
"), block size = 0x%x (0x%x)\n",
|
||||||
address, algined_address, size, aligned_size);
|
address, algined_address, size, aligned_size);
|
||||||
|
|
||||||
uc_mem_map(uc, algined_address, aligned_size, UC_PROT_ALL);
|
uc_mem_map(uc, algined_address, aligned_size, UC_PROT_ALL);
|
||||||
|
@ -231,8 +265,8 @@ static void test_miss_code(void)
|
||||||
// emulate machine code, without having the code in yet
|
// emulate machine code, without having the code in yet
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now print out some registers
|
// now print out some registers
|
||||||
|
@ -292,8 +326,8 @@ static void test_i386(void)
|
||||||
// emulate machine code in infinite time
|
// emulate machine code in infinite time
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now print out some registers
|
// now print out some registers
|
||||||
|
@ -304,7 +338,7 @@ static void test_i386(void)
|
||||||
uc_reg_read(uc, UC_X86_REG_XMM0, &r_xmm0);
|
uc_reg_read(uc, UC_X86_REG_XMM0, &r_xmm0);
|
||||||
printf(">>> ECX = 0x%x\n", r_ecx);
|
printf(">>> ECX = 0x%x\n", r_ecx);
|
||||||
printf(">>> EDX = 0x%x\n", r_edx);
|
printf(">>> EDX = 0x%x\n", r_edx);
|
||||||
printf(">>> XMM0 = 0x%.16"PRIx64"%.16"PRIx64"\n", r_xmm0[1], r_xmm0[0]);
|
printf(">>> XMM0 = 0x%.16" PRIx64 "%.16" PRIx64 "\n", r_xmm0[1], r_xmm0[0]);
|
||||||
|
|
||||||
// read from memory
|
// read from memory
|
||||||
if (!uc_mem_read(uc, ADDRESS, &tmp, sizeof(tmp)))
|
if (!uc_mem_read(uc, ADDRESS, &tmp, sizeof(tmp)))
|
||||||
|
@ -364,8 +398,8 @@ static void test_i386_map_ptr(void)
|
||||||
// emulate machine code in infinite time
|
// emulate machine code in infinite time
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now print out some registers
|
// now print out some registers
|
||||||
|
@ -419,10 +453,11 @@ static void test_i386_jump(void)
|
||||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS);
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS);
|
||||||
|
|
||||||
// emulate machine code in infinite time
|
// emulate machine code in infinite time
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_JUMP) - 1, 0, 0);
|
err =
|
||||||
|
uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_JUMP) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(">>> Emulation done. Below is the CPU context\n");
|
printf(">>> Emulation done. Below is the CPU context\n");
|
||||||
|
@ -453,7 +488,8 @@ static void test_i386_loop(void)
|
||||||
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||||
|
|
||||||
// write machine code to be emulated to memory
|
// write machine code to be emulated to memory
|
||||||
if (uc_mem_write(uc, ADDRESS, X86_CODE32_LOOP, sizeof(X86_CODE32_LOOP) - 1)) {
|
if (uc_mem_write(uc, ADDRESS, X86_CODE32_LOOP,
|
||||||
|
sizeof(X86_CODE32_LOOP) - 1)) {
|
||||||
printf("Failed to write emulation code to memory, quit!\n");
|
printf("Failed to write emulation code to memory, quit!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -464,10 +500,11 @@ static void test_i386_loop(void)
|
||||||
|
|
||||||
// emulate machine code in 2 seconds, so we can quit even
|
// emulate machine code in 2 seconds, so we can quit even
|
||||||
// if the code loops
|
// if the code loops
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_LOOP) - 1, 2 * UC_SECOND_SCALE, 0);
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_LOOP) - 1,
|
||||||
|
2 * UC_SECOND_SCALE, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now print out some registers
|
// now print out some registers
|
||||||
|
@ -505,7 +542,8 @@ static void test_i386_invalid_mem_read(void)
|
||||||
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||||
|
|
||||||
// write machine code to be emulated to memory
|
// write machine code to be emulated to memory
|
||||||
if (uc_mem_write(uc, ADDRESS, X86_CODE32_MEM_READ, sizeof(X86_CODE32_MEM_READ) - 1)) {
|
if (uc_mem_write(uc, ADDRESS, X86_CODE32_MEM_READ,
|
||||||
|
sizeof(X86_CODE32_MEM_READ) - 1)) {
|
||||||
printf("Failed to write emulation code to memory, quit!\n");
|
printf("Failed to write emulation code to memory, quit!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -521,10 +559,11 @@ static void test_i386_invalid_mem_read(void)
|
||||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
||||||
|
|
||||||
// emulate machine code in infinite time
|
// emulate machine code in infinite time
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_READ) - 1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_READ) - 1,
|
||||||
|
0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now print out some registers
|
// now print out some registers
|
||||||
|
@ -563,7 +602,8 @@ static void test_i386_invalid_mem_write(void)
|
||||||
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||||
|
|
||||||
// write machine code to be emulated to memory
|
// write machine code to be emulated to memory
|
||||||
if (uc_mem_write(uc, ADDRESS, X86_CODE32_MEM_WRITE, sizeof(X86_CODE32_MEM_WRITE) - 1)) {
|
if (uc_mem_write(uc, ADDRESS, X86_CODE32_MEM_WRITE,
|
||||||
|
sizeof(X86_CODE32_MEM_WRITE) - 1)) {
|
||||||
printf("Failed to write emulation code to memory, quit!\n");
|
printf("Failed to write emulation code to memory, quit!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -579,13 +619,16 @@ static void test_i386_invalid_mem_write(void)
|
||||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
||||||
|
|
||||||
// intercept invalid memory events
|
// intercept invalid memory events
|
||||||
uc_hook_add(uc, &trace3, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_invalid, NULL, 1, 0);
|
uc_hook_add(uc, &trace3,
|
||||||
|
UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED,
|
||||||
|
hook_mem_invalid, NULL, 1, 0);
|
||||||
|
|
||||||
// emulate machine code in infinite time
|
// emulate machine code in infinite time
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_WRITE) - 1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_WRITE) - 1,
|
||||||
|
0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now print out some registers
|
// now print out some registers
|
||||||
|
@ -634,7 +677,8 @@ static void test_i386_jump_invalid(void)
|
||||||
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||||
|
|
||||||
// write machine code to be emulated to memory
|
// write machine code to be emulated to memory
|
||||||
if (uc_mem_write(uc, ADDRESS, X86_CODE32_JMP_INVALID, sizeof(X86_CODE32_JMP_INVALID) - 1)) {
|
if (uc_mem_write(uc, ADDRESS, X86_CODE32_JMP_INVALID,
|
||||||
|
sizeof(X86_CODE32_JMP_INVALID) - 1)) {
|
||||||
printf("Failed to write emulation code to memory, quit!\n");
|
printf("Failed to write emulation code to memory, quit!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -650,10 +694,11 @@ static void test_i386_jump_invalid(void)
|
||||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
||||||
|
|
||||||
// emulate machine code in infinite time
|
// emulate machine code in infinite time
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_JMP_INVALID) - 1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS,
|
||||||
|
ADDRESS + sizeof(X86_CODE32_JMP_INVALID) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now print out some registers
|
// now print out some registers
|
||||||
|
@ -673,7 +718,6 @@ static void test_i386_inout(void)
|
||||||
uc_err err;
|
uc_err err;
|
||||||
uc_hook trace1, trace2, trace3, trace4;
|
uc_hook trace1, trace2, trace3, trace4;
|
||||||
|
|
||||||
|
|
||||||
int r_eax = 0x1234; // EAX register
|
int r_eax = 0x1234; // EAX register
|
||||||
int r_ecx = 0x6789; // ECX register
|
int r_ecx = 0x6789; // ECX register
|
||||||
|
|
||||||
|
@ -691,7 +735,8 @@ static void test_i386_inout(void)
|
||||||
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||||
|
|
||||||
// write machine code to be emulated to memory
|
// write machine code to be emulated to memory
|
||||||
if (uc_mem_write(uc, ADDRESS, X86_CODE32_INOUT, sizeof(X86_CODE32_INOUT) - 1)) {
|
if (uc_mem_write(uc, ADDRESS, X86_CODE32_INOUT,
|
||||||
|
sizeof(X86_CODE32_INOUT) - 1)) {
|
||||||
printf("Failed to write emulation code to memory, quit!\n");
|
printf("Failed to write emulation code to memory, quit!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -709,13 +754,15 @@ static void test_i386_inout(void)
|
||||||
// uc IN instruction
|
// uc IN instruction
|
||||||
uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_in, NULL, 1, 0, UC_X86_INS_IN);
|
uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_in, NULL, 1, 0, UC_X86_INS_IN);
|
||||||
// uc OUT instruction
|
// uc OUT instruction
|
||||||
uc_hook_add(uc, &trace4, UC_HOOK_INSN, hook_out, NULL, 1, 0, UC_X86_INS_OUT);
|
uc_hook_add(uc, &trace4, UC_HOOK_INSN, hook_out, NULL, 1, 0,
|
||||||
|
UC_X86_INS_OUT);
|
||||||
|
|
||||||
// emulate machine code in infinite time
|
// emulate machine code in infinite time
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_INOUT) - 1, 0, 0);
|
err =
|
||||||
|
uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_INOUT) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now print out some registers
|
// now print out some registers
|
||||||
|
@ -765,8 +812,8 @@ static void test_i386_context_save(void)
|
||||||
|
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_INC) - 1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_INC) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now print out some registers
|
// now print out some registers
|
||||||
|
@ -795,8 +842,8 @@ static void test_i386_context_save(void)
|
||||||
|
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_INC) - 1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_INC) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now print out some registers
|
// now print out some registers
|
||||||
|
@ -830,7 +877,8 @@ static void test_i386_context_save(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
// now print out some registers
|
// now print out some registers
|
||||||
printf(">>> CPU context restored with modification. Below is the CPU context\n");
|
printf(">>> CPU context restored with modification. Below is the CPU "
|
||||||
|
"context\n");
|
||||||
|
|
||||||
uc_reg_read(uc, UC_X86_REG_EAX, &r_eax);
|
uc_reg_read(uc, UC_X86_REG_EAX, &r_eax);
|
||||||
printf(">>> EAX = 0x%x\n", r_eax);
|
printf(">>> EAX = 0x%x\n", r_eax);
|
||||||
|
@ -928,7 +976,6 @@ static void test_x86_64(void)
|
||||||
|
|
||||||
int64_t rsp = ADDRESS + 0x200000;
|
int64_t rsp = ADDRESS + 0x200000;
|
||||||
|
|
||||||
|
|
||||||
printf("Emulate x86_64 code\n");
|
printf("Emulate x86_64 code\n");
|
||||||
|
|
||||||
// Initialize emulator in X86-64bit mode
|
// Initialize emulator in X86-64bit mode
|
||||||
|
@ -969,7 +1016,8 @@ static void test_x86_64(void)
|
||||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
||||||
|
|
||||||
// tracing all instructions in the range [ADDRESS, ADDRESS+20]
|
// tracing all instructions in the range [ADDRESS, ADDRESS+20]
|
||||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code64, NULL, ADDRESS, ADDRESS+20);
|
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code64, NULL, ADDRESS,
|
||||||
|
ADDRESS + 20);
|
||||||
|
|
||||||
// tracing all memory WRITE access (with @begin > @end)
|
// tracing all memory WRITE access (with @begin > @end)
|
||||||
uc_hook_add(uc, &trace3, UC_HOOK_MEM_WRITE, hook_mem64, NULL, 1, 0);
|
uc_hook_add(uc, &trace3, UC_HOOK_MEM_WRITE, hook_mem64, NULL, 1, 0);
|
||||||
|
@ -981,8 +1029,8 @@ static void test_x86_64(void)
|
||||||
// finishing all the code.
|
// finishing all the code.
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE64) - 1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE64) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now print out some registers
|
// now print out some registers
|
||||||
|
@ -1043,23 +1091,26 @@ static void test_x86_64_syscall(void)
|
||||||
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||||
|
|
||||||
// write machine code to be emulated to memory
|
// write machine code to be emulated to memory
|
||||||
if (uc_mem_write(uc, ADDRESS, X86_CODE64_SYSCALL, sizeof(X86_CODE64_SYSCALL) - 1)) {
|
if (uc_mem_write(uc, ADDRESS, X86_CODE64_SYSCALL,
|
||||||
|
sizeof(X86_CODE64_SYSCALL) - 1)) {
|
||||||
printf("Failed to write emulation code to memory, quit!\n");
|
printf("Failed to write emulation code to memory, quit!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// hook interrupts for syscall
|
// hook interrupts for syscall
|
||||||
uc_hook_add(uc, &trace1, UC_HOOK_INSN, hook_syscall, NULL, 1, 0, UC_X86_INS_SYSCALL);
|
uc_hook_add(uc, &trace1, UC_HOOK_INSN, hook_syscall, NULL, 1, 0,
|
||||||
|
UC_X86_INS_SYSCALL);
|
||||||
|
|
||||||
// initialize machine registers
|
// initialize machine registers
|
||||||
uc_reg_write(uc, UC_X86_REG_RAX, &rax);
|
uc_reg_write(uc, UC_X86_REG_RAX, &rax);
|
||||||
|
|
||||||
// emulate machine code in infinite time (last param = 0), or when
|
// emulate machine code in infinite time (last param = 0), or when
|
||||||
// finishing all the code.
|
// finishing all the code.
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE64_SYSCALL) - 1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE64_SYSCALL) - 1, 0,
|
||||||
|
0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now print out some registers
|
// now print out some registers
|
||||||
|
@ -1109,8 +1160,8 @@ static void test_x86_16(void)
|
||||||
// finishing all the code.
|
// finishing all the code.
|
||||||
err = uc_emu_start(uc, 0, sizeof(X86_CODE16) - 1, 0, 0);
|
err = uc_emu_start(uc, 0, sizeof(X86_CODE16) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
// now print out some registers
|
// now print out some registers
|
||||||
|
@ -1136,7 +1187,8 @@ static void test_i386_invalid_mem_read_in_tb(void)
|
||||||
int r_eip = 0;
|
int r_eip = 0;
|
||||||
|
|
||||||
printf("===================================\n");
|
printf("===================================\n");
|
||||||
printf("Emulate i386 code that read invalid memory in the middle of a TB\n");
|
printf(
|
||||||
|
"Emulate i386 code that read invalid memory in the middle of a TB\n");
|
||||||
|
|
||||||
// Initialize emulator in X86-32bit mode
|
// Initialize emulator in X86-32bit mode
|
||||||
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
||||||
|
@ -1149,7 +1201,8 @@ static void test_i386_invalid_mem_read_in_tb(void)
|
||||||
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||||
|
|
||||||
// write machine code to be emulated to memory
|
// write machine code to be emulated to memory
|
||||||
if (uc_mem_write(uc, ADDRESS, X86_CODE32_MEM_READ_IN_TB, sizeof(X86_CODE32_MEM_READ_IN_TB) - 1)) {
|
if (uc_mem_write(uc, ADDRESS, X86_CODE32_MEM_READ_IN_TB,
|
||||||
|
sizeof(X86_CODE32_MEM_READ_IN_TB) - 1)) {
|
||||||
printf("Failed to write emulation code to memory, quit!\n");
|
printf("Failed to write emulation code to memory, quit!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1159,10 +1212,12 @@ static void test_i386_invalid_mem_read_in_tb(void)
|
||||||
uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
|
uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
|
||||||
|
|
||||||
// Add a dummy callback.
|
// Add a dummy callback.
|
||||||
uc_hook_add(uc, &trace1, UC_HOOK_MEM_READ, hook_mem_invalid_dummy, NULL, 1, 0);
|
uc_hook_add(uc, &trace1, UC_HOOK_MEM_READ, hook_mem_invalid_dummy, NULL, 1,
|
||||||
|
0);
|
||||||
|
|
||||||
// Let it crash by design.
|
// Let it crash by design.
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_READ_IN_TB) - 1, 0, 0);
|
err = uc_emu_start(uc, ADDRESS,
|
||||||
|
ADDRESS + sizeof(X86_CODE32_MEM_READ_IN_TB) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("uc_emu_start() failed BY DESIGN with error returned %u: %s\n",
|
printf("uc_emu_start() failed BY DESIGN with error returned %u: %s\n",
|
||||||
err, uc_strerror(err));
|
err, uc_strerror(err));
|
||||||
|
@ -1174,9 +1229,12 @@ static void test_i386_invalid_mem_read_in_tb(void)
|
||||||
printf(">>> EIP = 0x%x\n", r_eip);
|
printf(">>> EIP = 0x%x\n", r_eip);
|
||||||
|
|
||||||
if (r_eip != ADDRESS + 1) {
|
if (r_eip != ADDRESS + 1) {
|
||||||
printf(">>> ERROR: Wrong PC 0x%x when reading unmapped memory in the middle of TB!\n", r_eip);
|
printf(">>> ERROR: Wrong PC 0x%x when reading unmapped memory in the "
|
||||||
|
"middle of TB!\n",
|
||||||
|
r_eip);
|
||||||
} else {
|
} else {
|
||||||
printf(">>> The PC is correct after reading unmapped memory in the middle of TB.\n");
|
printf(">>> The PC is correct after reading unmapped memory in the "
|
||||||
|
"middle of TB.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
uc_close(uc);
|
uc_close(uc);
|
||||||
|
@ -1217,14 +1275,14 @@ static void test_i386_smc_xor()
|
||||||
// **Important Note**
|
// **Important Note**
|
||||||
//
|
//
|
||||||
// Since SMC code will cause TB regeneration, the XOR in fact would executed
|
// Since SMC code will cause TB regeneration, the XOR in fact would executed
|
||||||
// twice (the first execution won't take effect.). Thus, if you would like to
|
// twice (the first execution won't take effect.). Thus, if you would like
|
||||||
// use count to control the emulation, the count should be set to 2.
|
// to use count to control the emulation, the count should be set to 2.
|
||||||
//
|
//
|
||||||
// err = uc_emu_start(uc, ADDRESS, ADDRESS + 3, 0, 0);
|
// err = uc_emu_start(uc, ADDRESS, ADDRESS + 3, 0, 0);
|
||||||
err = uc_emu_start(uc, ADDRESS, 0, 0, 2);
|
err = uc_emu_start(uc, ADDRESS, 0, 0, 2);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
printf(">>> Emulation done. Below is the result.\n");
|
printf(">>> Emulation done. Below is the result.\n");
|
||||||
|
@ -1232,30 +1290,38 @@ static void test_i386_smc_xor()
|
||||||
uc_mem_read(uc, ADDRESS + 3, (void *)&result, 4);
|
uc_mem_read(uc, ADDRESS + 3, (void *)&result, 4);
|
||||||
|
|
||||||
if (result == (0x3ea98b13 ^ 0xbc4177e6)) {
|
if (result == (0x3ea98b13 ^ 0xbc4177e6)) {
|
||||||
printf(">>> SMC emulation is correct. 0x3ea98b13 ^ 0xbc4177e6 = 0x%x\n", result);
|
printf(">>> SMC emulation is correct. 0x3ea98b13 ^ 0xbc4177e6 = 0x%x\n",
|
||||||
|
result);
|
||||||
} else {
|
} else {
|
||||||
printf(">>> SMC emulation is wrong. 0x3ea98b13 ^ 0xbc4177e6 = 0x%x\n", result);
|
printf(">>> SMC emulation is wrong. 0x3ea98b13 ^ 0xbc4177e6 = 0x%x\n",
|
||||||
|
result);
|
||||||
}
|
}
|
||||||
|
|
||||||
uc_close(uc);
|
uc_close(uc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t mmio_read_callback(uc_engine* uc, uint64_t offset, unsigned size, void* user_data)
|
static uint64_t mmio_read_callback(uc_engine *uc, uint64_t offset,
|
||||||
|
unsigned size, void *user_data)
|
||||||
{
|
{
|
||||||
printf(">>> Read IO memory at offset 0x%"PRIu64" with 0x%"PRIu32" bytes and return 0x19260817\n", offset, size);
|
printf(">>> Read IO memory at offset 0x%" PRIu64 " with 0x%" PRIu32
|
||||||
|
" bytes and return 0x19260817\n",
|
||||||
|
offset, size);
|
||||||
// The value returned here would be written to ecx.
|
// The value returned here would be written to ecx.
|
||||||
return 0x19260817;
|
return 0x19260817;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void mmio_write_callback(uc_engine* uc, uint64_t offset, unsigned size, uint64_t value, void* user_data)
|
static void mmio_write_callback(uc_engine *uc, uint64_t offset, unsigned size,
|
||||||
|
uint64_t value, void *user_data)
|
||||||
{
|
{
|
||||||
printf(">>> Write value 0x%"PRIu64" to IO memory at offset 0x%"PRIu64" with 0x%"PRIu32" bytes\n", value, offset, size);
|
printf(">>> Write value 0x%" PRIu64 " to IO memory at offset 0x%" PRIu64
|
||||||
|
" with 0x%" PRIu32 " bytes\n",
|
||||||
|
value, offset, size);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_i386_mmio()
|
static void test_i386_mmio()
|
||||||
{
|
{
|
||||||
uc_engine* uc;
|
uc_engine *uc;
|
||||||
int r_ecx = 0xdeadbeef;
|
int r_ecx = 0xdeadbeef;
|
||||||
uc_err err;
|
uc_err err;
|
||||||
|
|
||||||
|
@ -1283,7 +1349,8 @@ static void test_i386_mmio()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = uc_mmio_map(uc, 0x20000, 0x4000, mmio_read_callback, NULL, mmio_write_callback, NULL);
|
err = uc_mmio_map(uc, 0x20000, 0x4000, mmio_read_callback, NULL,
|
||||||
|
mmio_write_callback, NULL);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_mmio_map() with error returned: %u\n", err);
|
printf("Failed on uc_mmio_map() with error returned: %u\n", err);
|
||||||
return;
|
return;
|
||||||
|
@ -1314,8 +1381,7 @@ int main(int argc, char **argv, char **envp)
|
||||||
if (argc == 2) {
|
if (argc == 2) {
|
||||||
if (!strcmp(argv[1], "-16")) {
|
if (!strcmp(argv[1], "-16")) {
|
||||||
test_x86_16();
|
test_x86_16();
|
||||||
}
|
} else if (!strcmp(argv[1], "-32")) {
|
||||||
else if (!strcmp(argv[1], "-32")) {
|
|
||||||
test_miss_code();
|
test_miss_code();
|
||||||
test_i386();
|
test_i386();
|
||||||
test_i386_map_ptr();
|
test_i386_map_ptr();
|
||||||
|
@ -1326,17 +1392,14 @@ int main(int argc, char **argv, char **envp)
|
||||||
test_i386_invalid_mem_read();
|
test_i386_invalid_mem_read();
|
||||||
test_i386_invalid_mem_write();
|
test_i386_invalid_mem_write();
|
||||||
test_i386_jump_invalid();
|
test_i386_jump_invalid();
|
||||||
//test_i386_invalid_c6c7();
|
// test_i386_invalid_c6c7();
|
||||||
}
|
} else if (!strcmp(argv[1], "-64")) {
|
||||||
else if (!strcmp(argv[1], "-64")) {
|
|
||||||
test_x86_64();
|
test_x86_64();
|
||||||
test_x86_64_syscall();
|
test_x86_64_syscall();
|
||||||
}
|
} else if (!strcmp(argv[1], "-h")) {
|
||||||
else if (!strcmp(argv[1], "-h")) {
|
|
||||||
printf("Syntax: %s <-16|-32|-64>\n", argv[0]);
|
printf("Syntax: %s <-16|-32|-64>\n", argv[0]);
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
test_x86_16();
|
test_x86_16();
|
||||||
test_miss_code();
|
test_miss_code();
|
||||||
test_i386();
|
test_i386();
|
||||||
|
@ -1348,7 +1411,7 @@ int main(int argc, char **argv, char **envp)
|
||||||
test_i386_invalid_mem_read();
|
test_i386_invalid_mem_read();
|
||||||
test_i386_invalid_mem_write();
|
test_i386_invalid_mem_write();
|
||||||
test_i386_jump_invalid();
|
test_i386_jump_invalid();
|
||||||
//test_i386_invalid_c6c7();
|
// test_i386_invalid_c6c7();
|
||||||
test_x86_64();
|
test_x86_64();
|
||||||
test_x86_64_syscall();
|
test_x86_64_syscall();
|
||||||
test_i386_invalid_mem_read_in_tb();
|
test_i386_invalid_mem_read_in_tb();
|
||||||
|
|
|
@ -32,27 +32,27 @@ struct SegmentDescriptor {
|
||||||
unsigned short limit0;
|
unsigned short limit0;
|
||||||
unsigned short base0;
|
unsigned short base0;
|
||||||
unsigned char base1;
|
unsigned char base1;
|
||||||
unsigned char type:4;
|
unsigned char type : 4;
|
||||||
unsigned char system:1; /* S flag */
|
unsigned char system : 1; /* S flag */
|
||||||
unsigned char dpl:2;
|
unsigned char dpl : 2;
|
||||||
unsigned char present:1; /* P flag */
|
unsigned char present : 1; /* P flag */
|
||||||
unsigned char limit1:4;
|
unsigned char limit1 : 4;
|
||||||
unsigned char avail:1;
|
unsigned char avail : 1;
|
||||||
unsigned char is_64_code:1; /* L flag */
|
unsigned char is_64_code : 1; /* L flag */
|
||||||
unsigned char db:1; /* DB flag */
|
unsigned char db : 1; /* DB flag */
|
||||||
unsigned char granularity:1; /* G flag */
|
unsigned char granularity : 1; /* G flag */
|
||||||
unsigned char base2;
|
unsigned char base2;
|
||||||
#else
|
#else
|
||||||
unsigned char base2;
|
unsigned char base2;
|
||||||
unsigned char granularity:1; /* G flag */
|
unsigned char granularity : 1; /* G flag */
|
||||||
unsigned char db:1; /* DB flag */
|
unsigned char db : 1; /* DB flag */
|
||||||
unsigned char is_64_code:1; /* L flag */
|
unsigned char is_64_code : 1; /* L flag */
|
||||||
unsigned char avail:1;
|
unsigned char avail : 1;
|
||||||
unsigned char limit1:4;
|
unsigned char limit1 : 4;
|
||||||
unsigned char present:1; /* P flag */
|
unsigned char present : 1; /* P flag */
|
||||||
unsigned char dpl:2;
|
unsigned char dpl : 2;
|
||||||
unsigned char system:1; /* S flag */
|
unsigned char system : 1; /* S flag */
|
||||||
unsigned char type:4;
|
unsigned char type : 4;
|
||||||
unsigned char base1;
|
unsigned char base1;
|
||||||
unsigned short base0;
|
unsigned short base0;
|
||||||
unsigned short limit0;
|
unsigned short limit0;
|
||||||
|
@ -63,20 +63,22 @@ struct SegmentDescriptor {
|
||||||
};
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
#define SEGBASE(d) ((uint32_t)((((d).desc >> 16) & 0xffffff) | (((d).desc >> 32) & 0xff000000)))
|
#define SEGBASE(d) \
|
||||||
|
((uint32_t)((((d).desc >> 16) & 0xffffff) | \
|
||||||
|
(((d).desc >> 32) & 0xff000000)))
|
||||||
#define SEGLIMIT(d) ((d).limit0 | (((unsigned int)(d).limit1) << 16))
|
#define SEGLIMIT(d) ((d).limit0 | (((unsigned int)(d).limit1) << 16))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assert that err matches expect
|
* Assert that err matches expect
|
||||||
*/
|
*/
|
||||||
#define uc_assert_err(expect, err) \
|
#define uc_assert_err(expect, err) \
|
||||||
do { \
|
do { \
|
||||||
uc_err __err = err; \
|
uc_err __err = err; \
|
||||||
if (__err != expect) { \
|
if (__err != expect) { \
|
||||||
fprintf(stderr, "%s", uc_strerror(__err)); \
|
fprintf(stderr, "%s", uc_strerror(__err)); \
|
||||||
exit(1); \
|
exit(1); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assert that err is UC_ERR_OK
|
* Assert that err is UC_ERR_OK
|
||||||
|
@ -91,54 +93,60 @@ do { \
|
||||||
* in various scenarios.
|
* in various scenarios.
|
||||||
*/
|
*/
|
||||||
#define uc_assert_fail(err) \
|
#define uc_assert_fail(err) \
|
||||||
do { \
|
do { \
|
||||||
uc_err __err = err; \
|
uc_err __err = err; \
|
||||||
if (__err == UC_ERR_OK) { \
|
if (__err == UC_ERR_OK) { \
|
||||||
fprintf(stderr, "%s", uc_strerror(__err)); \
|
fprintf(stderr, "%s", uc_strerror(__err)); \
|
||||||
exit(1); \
|
exit(1); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
#define OK(x) uc_assert_success(x)
|
#define OK(x) uc_assert_success(x)
|
||||||
|
|
||||||
/******************************************************************************/
|
/******************************************************************************/
|
||||||
|
|
||||||
static void hook_mem(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data)
|
static void hook_mem(uc_engine *uc, uc_mem_type type, uint64_t address,
|
||||||
|
int size, int64_t value, void *user_data)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch (type) {
|
||||||
case UC_MEM_WRITE:
|
case UC_MEM_WRITE:
|
||||||
printf("mem write at 0x%"PRIx64 ", size = %u, value = 0x%"PRIx64 "\n", address, size, value);
|
printf("mem write at 0x%" PRIx64 ", size = %u, value = 0x%" PRIx64 "\n",
|
||||||
|
address, size, value);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
break;
|
break;
|
||||||
default: break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
static void hook_code(uc_engine *uc, uint64_t address, uint32_t size,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
printf("Executing at 0x%"PRIx64 ", ilen = 0x%x\n", address, size);
|
printf("Executing at 0x%" PRIx64 ", ilen = 0x%x\n", address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
//VERY basic descriptor init function, sets many fields to user space sane defaults
|
// VERY basic descriptor init function, sets many fields to user space sane
|
||||||
static void init_descriptor(struct SegmentDescriptor *desc, uint32_t base, uint32_t limit, uint8_t is_code)
|
// defaults
|
||||||
|
static void init_descriptor(struct SegmentDescriptor *desc, uint32_t base,
|
||||||
|
uint32_t limit, uint8_t is_code)
|
||||||
{
|
{
|
||||||
desc->desc = 0; //clear the descriptor
|
desc->desc = 0; // clear the descriptor
|
||||||
desc->base0 = base & 0xffff;
|
desc->base0 = base & 0xffff;
|
||||||
desc->base1 = (base >> 16) & 0xff;
|
desc->base1 = (base >> 16) & 0xff;
|
||||||
desc->base2 = base >> 24;
|
desc->base2 = base >> 24;
|
||||||
if (limit > 0xfffff) {
|
if (limit > 0xfffff) {
|
||||||
//need Giant granularity
|
// need Giant granularity
|
||||||
limit >>= 12;
|
limit >>= 12;
|
||||||
desc->granularity = 1;
|
desc->granularity = 1;
|
||||||
}
|
}
|
||||||
desc->limit0 = limit & 0xffff;
|
desc->limit0 = limit & 0xffff;
|
||||||
desc->limit1 = limit >> 16;
|
desc->limit1 = limit >> 16;
|
||||||
|
|
||||||
//some sane defaults
|
// some sane defaults
|
||||||
desc->dpl = 3;
|
desc->dpl = 3;
|
||||||
desc->present = 1;
|
desc->present = 1;
|
||||||
desc->db = 1; //32 bit
|
desc->db = 1; // 32 bit
|
||||||
desc->type = is_code ? 0xb : 3;
|
desc->type = is_code ? 0xb : 3;
|
||||||
desc->system = 1; //code or data
|
desc->system = 1; // code or data
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -174,17 +182,20 @@ static void gdt_demo()
|
||||||
mov dword [fs:4], 0x89abcdef
|
mov dword [fs:4], 0x89abcdef
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const uint8_t code[] = "\x68\x67\x45\x23\x01\x68\xef\xcd\xab\x89\x64\xc7\x05\x00\x00\x00\x00\x67\x45\x23\x01\x64\xc7\x05\x04\x00\x00\x00\xef\xcd\xab\x89";
|
const uint8_t code[] =
|
||||||
|
"\x68\x67\x45\x23\x01\x68\xef\xcd\xab\x89\x64\xc7\x05\x00\x00\x00\x00"
|
||||||
|
"\x67\x45\x23\x01\x64\xc7\x05\x04\x00\x00\x00\xef\xcd\xab\x89";
|
||||||
const uint64_t code_address = 0x1000000;
|
const uint64_t code_address = 0x1000000;
|
||||||
const uint64_t stack_address = 0x120000;
|
const uint64_t stack_address = 0x120000;
|
||||||
const uint64_t gdt_address = 0xc0000000;
|
const uint64_t gdt_address = 0xc0000000;
|
||||||
const uint64_t fs_address = 0x7efdd000;
|
const uint64_t fs_address = 0x7efdd000;
|
||||||
|
|
||||||
struct SegmentDescriptor *gdt = (struct SegmentDescriptor*)calloc(31, sizeof(struct SegmentDescriptor));
|
struct SegmentDescriptor *gdt = (struct SegmentDescriptor *)calloc(
|
||||||
|
31, sizeof(struct SegmentDescriptor));
|
||||||
|
|
||||||
int r_esp = (int)stack_address + 0x1000; // initial esp
|
int r_esp = (int)stack_address + 0x1000; // initial esp
|
||||||
int r_cs = 0x73;
|
int r_cs = 0x73;
|
||||||
int r_ss = 0x88; //ring 0
|
int r_ss = 0x88; // ring 0
|
||||||
int r_ds = 0x7b;
|
int r_ds = 0x7b;
|
||||||
int r_es = 0x7b;
|
int r_es = 0x7b;
|
||||||
int r_fs = 0x83;
|
int r_fs = 0x83;
|
||||||
|
@ -192,11 +203,12 @@ static void gdt_demo()
|
||||||
gdtr.base = gdt_address;
|
gdtr.base = gdt_address;
|
||||||
gdtr.limit = 31 * sizeof(struct SegmentDescriptor) - 1;
|
gdtr.limit = 31 * sizeof(struct SegmentDescriptor) - 1;
|
||||||
|
|
||||||
init_descriptor(&gdt[14], 0, 0xfffff000, 1); //code segment
|
init_descriptor(&gdt[14], 0, 0xfffff000, 1); // code segment
|
||||||
init_descriptor(&gdt[15], 0, 0xfffff000, 0); //data segment
|
init_descriptor(&gdt[15], 0, 0xfffff000, 0); // data segment
|
||||||
init_descriptor(&gdt[16], 0x7efdd000, 0xfff, 0); //one page data segment simulate fs
|
init_descriptor(&gdt[16], 0x7efdd000, 0xfff,
|
||||||
init_descriptor(&gdt[17], 0, 0xfffff000, 0); //ring 0 data
|
0); // one page data segment simulate fs
|
||||||
gdt[17].dpl = 0; //set descriptor privilege level
|
init_descriptor(&gdt[17], 0, 0xfffff000, 0); // ring 0 data
|
||||||
|
gdt[17].dpl = 0; // set descriptor privilege level
|
||||||
|
|
||||||
/*
|
/*
|
||||||
fprintf(stderr, "GDT: \n");
|
fprintf(stderr, "GDT: \n");
|
||||||
|
@ -207,9 +219,11 @@ static void gdt_demo()
|
||||||
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
||||||
uc_assert_success(err);
|
uc_assert_success(err);
|
||||||
|
|
||||||
uc_hook_add(uc, &hook1, UC_HOOK_CODE, hook_code, NULL, code_address, code_address + sizeof(code) - 1);
|
uc_hook_add(uc, &hook1, UC_HOOK_CODE, hook_code, NULL, code_address,
|
||||||
|
code_address + sizeof(code) - 1);
|
||||||
|
|
||||||
err = uc_hook_add(uc, &hook2, UC_HOOK_MEM_WRITE, hook_mem, NULL, (uint64_t)1, (uint64_t)0);
|
err = uc_hook_add(uc, &hook2, UC_HOOK_MEM_WRITE, hook_mem, NULL,
|
||||||
|
(uint64_t)1, (uint64_t)0);
|
||||||
uc_assert_success(err);
|
uc_assert_success(err);
|
||||||
|
|
||||||
// map 1 page of code for this emulation
|
// map 1 page of code for this emulation
|
||||||
|
@ -224,12 +238,13 @@ static void gdt_demo()
|
||||||
err = uc_mem_map(uc, gdt_address, 0x10000, UC_PROT_WRITE | UC_PROT_READ);
|
err = uc_mem_map(uc, gdt_address, 0x10000, UC_PROT_WRITE | UC_PROT_READ);
|
||||||
uc_assert_success(err);
|
uc_assert_success(err);
|
||||||
|
|
||||||
//set up a GDT BEFORE you manipulate any segment registers
|
// set up a GDT BEFORE you manipulate any segment registers
|
||||||
err = uc_reg_write(uc, UC_X86_REG_GDTR, &gdtr);
|
err = uc_reg_write(uc, UC_X86_REG_GDTR, &gdtr);
|
||||||
uc_assert_success(err);
|
uc_assert_success(err);
|
||||||
|
|
||||||
// write gdt to be emulated to memory
|
// write gdt to be emulated to memory
|
||||||
err = uc_mem_write(uc, gdt_address, gdt, 31 * sizeof(struct SegmentDescriptor));
|
err = uc_mem_write(uc, gdt_address, gdt,
|
||||||
|
31 * sizeof(struct SegmentDescriptor));
|
||||||
uc_assert_success(err);
|
uc_assert_success(err);
|
||||||
|
|
||||||
// map 1 page for FS
|
// map 1 page for FS
|
||||||
|
@ -237,7 +252,7 @@ static void gdt_demo()
|
||||||
uc_assert_success(err);
|
uc_assert_success(err);
|
||||||
|
|
||||||
// write machine code to be emulated to memory
|
// write machine code to be emulated to memory
|
||||||
err = uc_mem_write(uc, code_address, code, sizeof(code)-1);
|
err = uc_mem_write(uc, code_address, code, sizeof(code) - 1);
|
||||||
uc_assert_success(err);
|
uc_assert_success(err);
|
||||||
|
|
||||||
// initialize machine registers
|
// initialize machine registers
|
||||||
|
@ -245,7 +260,8 @@ static void gdt_demo()
|
||||||
uc_assert_success(err);
|
uc_assert_success(err);
|
||||||
|
|
||||||
// when setting SS, need rpl == cpl && dpl == cpl
|
// when setting SS, need rpl == cpl && dpl == cpl
|
||||||
// emulator starts with cpl == 0, so we need a dpl 0 descriptor and rpl 0 selector
|
// emulator starts with cpl == 0, so we need a dpl 0 descriptor and rpl 0
|
||||||
|
// selector
|
||||||
err = uc_reg_write(uc, UC_X86_REG_SS, &r_ss);
|
err = uc_reg_write(uc, UC_X86_REG_SS, &r_ss);
|
||||||
uc_assert_success(err);
|
uc_assert_success(err);
|
||||||
|
|
||||||
|
@ -259,7 +275,7 @@ static void gdt_demo()
|
||||||
uc_assert_success(err);
|
uc_assert_success(err);
|
||||||
|
|
||||||
// emulate machine code in infinite time
|
// emulate machine code in infinite time
|
||||||
err = uc_emu_start(uc, code_address, code_address+sizeof(code)-1, 0, 0);
|
err = uc_emu_start(uc, code_address, code_address + sizeof(code) - 1, 0, 0);
|
||||||
uc_assert_success(err);
|
uc_assert_success(err);
|
||||||
|
|
||||||
// read from memory
|
// read from memory
|
||||||
|
|
|
@ -6,23 +6,31 @@
|
||||||
#include <unicorn/unicorn.h>
|
#include <unicorn/unicorn.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
// code to be emulated
|
// code to be emulated
|
||||||
#define X86_CODE32 "\xeb\x19\x31\xc0\x31\xdb\x31\xd2\x31\xc9\xb0\x04\xb3\x01\x59\xb2\x05\xcd\x80\x31\xc0\xb0\x01\x31\xdb\xcd\x80\xe8\xe2\xff\xff\xff\x68\x65\x6c\x6c\x6f"
|
#define X86_CODE32 \
|
||||||
|
"\xeb\x19\x31\xc0\x31\xdb\x31\xd2\x31\xc9\xb0\x04\xb3\x01\x59\xb2\x05\xcd" \
|
||||||
|
"\x80\x31\xc0\xb0\x01\x31\xdb\xcd\x80\xe8\xe2\xff\xff\xff\x68\x65\x6c\x6c" \
|
||||||
|
"\x6f"
|
||||||
|
|
||||||
#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\x41\x41\x41\x41"
|
#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\x41\x41\x41\x41"
|
||||||
|
|
||||||
// memory address where emulation starts
|
// memory address where emulation starts
|
||||||
#define ADDRESS 0x1000000
|
#define ADDRESS 0x1000000
|
||||||
|
|
||||||
#define MIN(a, b) (a < b? a : b)
|
#define MIN(a, b) (a < b ? a : b)
|
||||||
// callback for tracing instruction
|
// callback for tracing instruction
|
||||||
static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
static void hook_code(uc_engine *uc, uint64_t address, uint32_t size,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
int r_eip;
|
int r_eip;
|
||||||
uint8_t tmp[16];
|
uint8_t tmp[16];
|
||||||
|
|
||||||
printf("Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size);
|
printf("Tracing instruction at 0x%" PRIx64 ", instruction size = 0x%x\n",
|
||||||
|
address, size);
|
||||||
|
|
||||||
uc_reg_read(uc, UC_X86_REG_EIP, &r_eip);
|
uc_reg_read(uc, UC_X86_REG_EIP, &r_eip);
|
||||||
printf("*** EIP = %x ***: ", r_eip);
|
printf("*** EIP = %x ***: ", r_eip);
|
||||||
|
@ -30,7 +38,7 @@ static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user
|
||||||
size = MIN(sizeof(tmp), size);
|
size = MIN(sizeof(tmp), size);
|
||||||
if (!uc_mem_read(uc, address, tmp, size)) {
|
if (!uc_mem_read(uc, address, tmp, size)) {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
for (i=0; i<size; i++) {
|
for (i = 0; i < size; i++) {
|
||||||
printf("%x ", tmp[i]);
|
printf("%x ", tmp[i]);
|
||||||
}
|
}
|
||||||
printf("\n");
|
printf("\n");
|
||||||
|
@ -52,7 +60,7 @@ static void hook_intr(uc_engine *uc, uint32_t intno, void *user_data)
|
||||||
uc_reg_read(uc, UC_X86_REG_EAX, &r_eax);
|
uc_reg_read(uc, UC_X86_REG_EAX, &r_eax);
|
||||||
uc_reg_read(uc, UC_X86_REG_EIP, &r_eip);
|
uc_reg_read(uc, UC_X86_REG_EIP, &r_eip);
|
||||||
|
|
||||||
switch(r_eax) {
|
switch (r_eax) {
|
||||||
default:
|
default:
|
||||||
printf(">>> 0x%x: interrupt 0x%x, EAX = 0x%x\n", r_eip, intno, r_eax);
|
printf(">>> 0x%x: interrupt 0x%x, EAX = 0x%x\n", r_eip, intno, r_eax);
|
||||||
break;
|
break;
|
||||||
|
@ -68,14 +76,16 @@ static void hook_intr(uc_engine *uc, uint32_t intno, void *user_data)
|
||||||
uc_reg_read(uc, UC_X86_REG_EDX, &r_edx);
|
uc_reg_read(uc, UC_X86_REG_EDX, &r_edx);
|
||||||
|
|
||||||
// read the buffer in
|
// read the buffer in
|
||||||
size = MIN(sizeof(buffer)-1, r_edx);
|
size = MIN(sizeof(buffer) - 1, r_edx);
|
||||||
|
|
||||||
if (!uc_mem_read(uc, r_ecx, buffer, size)) {
|
if (!uc_mem_read(uc, r_ecx, buffer, size)) {
|
||||||
buffer[size] = '\0';
|
buffer[size] = '\0';
|
||||||
printf(">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = %u, content = '%s'\n",
|
printf(">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = "
|
||||||
|
"%u, content = '%s'\n",
|
||||||
r_eip, intno, r_ecx, r_edx, buffer);
|
r_eip, intno, r_ecx, r_edx, buffer);
|
||||||
} else {
|
} else {
|
||||||
printf(">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = %u (cannot get content)\n",
|
printf(">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = "
|
||||||
|
"%u (cannot get content)\n",
|
||||||
r_eip, intno, r_ecx, r_edx);
|
r_eip, intno, r_ecx, r_edx);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -103,7 +113,8 @@ static void test_i386(void)
|
||||||
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||||
|
|
||||||
// write machine code to be emulated to memory
|
// write machine code to be emulated to memory
|
||||||
if (uc_mem_write(uc, ADDRESS, X86_CODE32_SELF, sizeof(X86_CODE32_SELF) - 1)) {
|
if (uc_mem_write(uc, ADDRESS, X86_CODE32_SELF,
|
||||||
|
sizeof(X86_CODE32_SELF) - 1)) {
|
||||||
printf("Failed to write emulation code to memory, quit!\n");
|
printf("Failed to write emulation code to memory, quit!\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -120,11 +131,13 @@ static void test_i386(void)
|
||||||
printf("\n>>> Start tracing this Linux code\n");
|
printf("\n>>> Start tracing this Linux code\n");
|
||||||
|
|
||||||
// emulate machine code in infinite time
|
// emulate machine code in infinite time
|
||||||
// err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_SELF), 0, 12); <--- emulate only 12 instructions
|
// err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_SELF), 0,
|
||||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_SELF) - 1, 0, 0);
|
// 12); <--- emulate only 12 instructions
|
||||||
|
err =
|
||||||
|
uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_SELF) - 1, 0, 0);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||||
err, uc_strerror(err));
|
uc_strerror(err));
|
||||||
}
|
}
|
||||||
|
|
||||||
printf("\n>>> Emulation done.\n");
|
printf("\n>>> Emulation done.\n");
|
||||||
|
@ -137,8 +150,7 @@ int main(int argc, char **argv, char **envp)
|
||||||
if (argc == 2) {
|
if (argc == 2) {
|
||||||
if (!strcmp(argv[1], "-32")) {
|
if (!strcmp(argv[1], "-32")) {
|
||||||
test_i386();
|
test_i386();
|
||||||
}
|
} else if (!strcmp(argv[1], "-h")) {
|
||||||
else if (!strcmp(argv[1], "-h")) {
|
|
||||||
printf("Syntax: %s <-32|-64>\n", argv[0]);
|
printf("Syntax: %s <-32|-64>\n", argv[0]);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
1107
tests/unit/acutest.h
1107
tests/unit/acutest.h
File diff suppressed because it is too large
Load Diff
|
@ -3,14 +3,17 @@
|
||||||
const uint64_t code_start = 0x1000;
|
const uint64_t code_start = 0x1000;
|
||||||
const uint64_t code_len = 0x4000;
|
const uint64_t code_len = 0x4000;
|
||||||
|
|
||||||
static void uc_common_setup(uc_engine** uc, uc_arch arch, uc_mode mode, const char* code, uint64_t size) {
|
static void uc_common_setup(uc_engine **uc, uc_arch arch, uc_mode mode,
|
||||||
|
const char *code, uint64_t size)
|
||||||
|
{
|
||||||
OK(uc_open(arch, mode, uc));
|
OK(uc_open(arch, mode, uc));
|
||||||
OK(uc_mem_map(*uc, code_start, code_len, UC_PROT_ALL));
|
OK(uc_mem_map(*uc, code_start, code_len, UC_PROT_ALL));
|
||||||
OK(uc_mem_write(*uc, code_start, code, size));
|
OK(uc_mem_write(*uc, code_start, code, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_arm_nop() {
|
static void test_arm_nop()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
char code[] = "\x00\xf0\x20\xe3"; // nop
|
char code[] = "\x00\xf0\x20\xe3"; // nop
|
||||||
int r_r0 = 0x1234;
|
int r_r0 = 0x1234;
|
||||||
int r_r2 = 0x6789;
|
int r_r2 = 0x6789;
|
||||||
|
@ -29,8 +32,9 @@ static void test_arm_nop() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_arm_thumb_sub() {
|
static void test_arm_thumb_sub()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
char code[] = "\x83\xb0"; // sub sp, #0xc
|
char code[] = "\x83\xb0"; // sub sp, #0xc
|
||||||
int r_sp = 0x1234;
|
int r_sp = 0x1234;
|
||||||
|
|
||||||
|
@ -45,15 +49,18 @@ static void test_arm_thumb_sub() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_armeb_sub() {
|
static void test_armeb_sub()
|
||||||
uc_engine* uc;
|
{
|
||||||
char code[] = "\xe3\xa0\x00\x37\xe0\x42\x10\x03"; // mov r0, #0x37; sub r1, r2, r3
|
uc_engine *uc;
|
||||||
|
char code[] =
|
||||||
|
"\xe3\xa0\x00\x37\xe0\x42\x10\x03"; // mov r0, #0x37; sub r1, r2, r3
|
||||||
int r_r0 = 0x1234;
|
int r_r0 = 0x1234;
|
||||||
int r_r2 = 0x6789;
|
int r_r2 = 0x6789;
|
||||||
int r_r3 = 0x3333;
|
int r_r3 = 0x3333;
|
||||||
int r_r1;
|
int r_r1;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_ARM | UC_MODE_BIG_ENDIAN, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_ARM | UC_MODE_BIG_ENDIAN, code,
|
||||||
|
sizeof(code) - 1);
|
||||||
OK(uc_reg_write(uc, UC_ARM_REG_R0, &r_r0));
|
OK(uc_reg_write(uc, UC_ARM_REG_R0, &r_r0));
|
||||||
OK(uc_reg_write(uc, UC_ARM_REG_R2, &r_r2));
|
OK(uc_reg_write(uc, UC_ARM_REG_R2, &r_r2));
|
||||||
OK(uc_reg_write(uc, UC_ARM_REG_R3, &r_r3));
|
OK(uc_reg_write(uc, UC_ARM_REG_R3, &r_r3));
|
||||||
|
@ -73,12 +80,14 @@ static void test_armeb_sub() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_arm_thumbeb_sub() {
|
static void test_arm_thumbeb_sub()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
char code[] = "\xb0\x83"; // sub sp, #0xc
|
char code[] = "\xb0\x83"; // sub sp, #0xc
|
||||||
int r_sp = 0x1234;
|
int r_sp = 0x1234;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_THUMB | UC_MODE_BIG_ENDIAN, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_THUMB | UC_MODE_BIG_ENDIAN, code,
|
||||||
|
sizeof(code) - 1);
|
||||||
OK(uc_reg_write(uc, UC_ARM_REG_SP, &r_sp));
|
OK(uc_reg_write(uc, UC_ARM_REG_SP, &r_sp));
|
||||||
|
|
||||||
OK(uc_emu_start(uc, code_start | 1, code_start + sizeof(code) - 1, 0, 0));
|
OK(uc_emu_start(uc, code_start | 1, code_start + sizeof(code) - 1, 0, 0));
|
||||||
|
@ -89,16 +98,25 @@ static void test_arm_thumbeb_sub() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_arm_thumb_ite_count_callback(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) {
|
static void test_arm_thumb_ite_count_callback(uc_engine *uc, uint64_t address,
|
||||||
uint64_t* count = (uint64_t*)user_data;
|
uint32_t size, void *user_data)
|
||||||
|
{
|
||||||
|
uint64_t *count = (uint64_t *)user_data;
|
||||||
|
|
||||||
(*count) += 1;
|
(*count) += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_arm_thumb_ite() {
|
static void test_arm_thumb_ite()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
uc_hook hook;
|
uc_hook hook;
|
||||||
char code[] = "\x9a\x42\x15\xbf\x00\x9a\x01\x9a\x78\x23\x15\x23"; // cmp r2, r3; itete ne; ldrne r2, [sp]; ldreq r2, [sp,#4]; movne r3, #0x78; moveq r3, #0x15
|
char code[] =
|
||||||
|
"\x9a\x42\x15\xbf\x00\x9a\x01\x9a\x78\x23\x15\x23"; // cmp r2, r3; itete
|
||||||
|
// ne; ldrne r2,
|
||||||
|
// [sp]; ldreq r2,
|
||||||
|
// [sp,#4]; movne
|
||||||
|
// r3, #0x78; moveq
|
||||||
|
// r3, #0x15
|
||||||
int r_sp = 0x8000;
|
int r_sp = 0x8000;
|
||||||
int r_r2 = 0;
|
int r_r2 = 0;
|
||||||
int r_r3 = 1;
|
int r_r3 = 1;
|
||||||
|
@ -116,7 +134,8 @@ static void test_arm_thumb_ite() {
|
||||||
r_r2 = 0x4d;
|
r_r2 = 0x4d;
|
||||||
OK(uc_mem_write(uc, r_sp + 4, &r_r2, 4));
|
OK(uc_mem_write(uc, r_sp + 4, &r_r2, 4));
|
||||||
|
|
||||||
OK(uc_hook_add(uc, &hook, UC_HOOK_CODE, test_arm_thumb_ite_count_callback, &count, 1, 0));
|
OK(uc_hook_add(uc, &hook, UC_HOOK_CODE, test_arm_thumb_ite_count_callback,
|
||||||
|
&count, 1, 0));
|
||||||
|
|
||||||
// Execute four instructions at a time.
|
// Execute four instructions at a time.
|
||||||
OK(uc_emu_start(uc, code_start | 1, code_start + sizeof(code) - 1, 0, 0));
|
OK(uc_emu_start(uc, code_start | 1, code_start + sizeof(code) - 1, 0, 0));
|
||||||
|
@ -146,14 +165,17 @@ static void test_arm_thumb_ite() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_arm_m_thumb_mrs() {
|
static void test_arm_m_thumb_mrs()
|
||||||
uc_engine* uc;
|
{
|
||||||
char code[] = "\xef\xf3\x14\x80\xef\xf3\x00\x81"; // mrs r0, control; mrs r1, apsr
|
uc_engine *uc;
|
||||||
|
char code[] =
|
||||||
|
"\xef\xf3\x14\x80\xef\xf3\x00\x81"; // mrs r0, control; mrs r1, apsr
|
||||||
uint32_t r_control = 0b10;
|
uint32_t r_control = 0b10;
|
||||||
uint32_t r_apsr = (0b10101 << 27);
|
uint32_t r_apsr = (0b10101 << 27);
|
||||||
uint32_t r_r0, r_r1;
|
uint32_t r_r0, r_r1;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_THUMB | UC_MODE_MCLASS, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_THUMB | UC_MODE_MCLASS, code,
|
||||||
|
sizeof(code) - 1);
|
||||||
|
|
||||||
OK(uc_reg_write(uc, UC_ARM_REG_CONTROL, &r_control));
|
OK(uc_reg_write(uc, UC_ARM_REG_CONTROL, &r_control));
|
||||||
OK(uc_reg_write(uc, UC_ARM_REG_APSR_NZCVQ, &r_apsr));
|
OK(uc_reg_write(uc, UC_ARM_REG_APSR_NZCVQ, &r_apsr));
|
||||||
|
@ -168,8 +190,9 @@ static void test_arm_m_thumb_mrs() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_arm_m_control() {
|
static void test_arm_m_control()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
int r_control, r_msp, r_psp;
|
int r_control, r_msp, r_psp;
|
||||||
|
|
||||||
OK(uc_open(UC_ARCH_ARM, UC_MODE_THUMB | UC_MODE_MCLASS, &uc));
|
OK(uc_open(UC_ARCH_ARM, UC_MODE_THUMB | UC_MODE_MCLASS, &uc));
|
||||||
|
@ -201,10 +224,13 @@ static void test_arm_m_control() {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Some notes:
|
// Some notes:
|
||||||
// Qemu raise a special exception EXCP_EXCEPTION_EXIT to handle the EXC_RETURN. We can't
|
// Qemu raise a special exception EXCP_EXCEPTION_EXIT to handle the
|
||||||
// help user handle EXC_RETURN since unicorn is designed not to handle any CPU exception.
|
// EXC_RETURN. We can't help user handle EXC_RETURN since unicorn is designed
|
||||||
|
// not to handle any CPU exception.
|
||||||
//
|
//
|
||||||
static void test_arm_m_exc_return_hook_interrupt(uc_engine* uc, int intno, void* data) {
|
static void test_arm_m_exc_return_hook_interrupt(uc_engine *uc, int intno,
|
||||||
|
void *data)
|
||||||
|
{
|
||||||
int r_pc;
|
int r_pc;
|
||||||
|
|
||||||
OK(uc_reg_read(uc, UC_ARM_REG_PC, &r_pc));
|
OK(uc_reg_read(uc, UC_ARM_REG_PC, &r_pc));
|
||||||
|
@ -213,16 +239,19 @@ static void test_arm_m_exc_return_hook_interrupt(uc_engine* uc, int intno, void*
|
||||||
OK(uc_emu_stop(uc));
|
OK(uc_emu_stop(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_arm_m_exc_return() {
|
static void test_arm_m_exc_return()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
char code[] = "\x6f\xf0\x02\x00\x00\x47"; // mov r0, #0xFFFFFFFD; bx r0;
|
char code[] = "\x6f\xf0\x02\x00\x00\x47"; // mov r0, #0xFFFFFFFD; bx r0;
|
||||||
int r_ipsr;
|
int r_ipsr;
|
||||||
int r_sp = 0x8000;
|
int r_sp = 0x8000;
|
||||||
uc_hook hook;
|
uc_hook hook;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_THUMB | UC_MODE_MCLASS, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_THUMB | UC_MODE_MCLASS, code,
|
||||||
|
sizeof(code) - 1);
|
||||||
OK(uc_mem_map(uc, r_sp - 0x1000, 0x1000, UC_PROT_ALL));
|
OK(uc_mem_map(uc, r_sp - 0x1000, 0x1000, UC_PROT_ALL));
|
||||||
OK(uc_hook_add(uc, &hook, UC_HOOK_INTR, test_arm_m_exc_return_hook_interrupt, NULL, 0, 0));
|
OK(uc_hook_add(uc, &hook, UC_HOOK_INTR,
|
||||||
|
test_arm_m_exc_return_hook_interrupt, NULL, 0, 0));
|
||||||
|
|
||||||
r_sp -= 0x1c;
|
r_sp -= 0x1c;
|
||||||
OK(uc_reg_write(uc, UC_ARM_REG_SP, &r_sp));
|
OK(uc_reg_write(uc, UC_ARM_REG_SP, &r_sp));
|
||||||
|
@ -230,20 +259,19 @@ static void test_arm_m_exc_return() {
|
||||||
r_ipsr = 16; // We are in whatever exception.
|
r_ipsr = 16; // We are in whatever exception.
|
||||||
OK(uc_reg_write(uc, UC_ARM_REG_IPSR, &r_ipsr));
|
OK(uc_reg_write(uc, UC_ARM_REG_IPSR, &r_ipsr));
|
||||||
|
|
||||||
OK(uc_emu_start(uc, code_start | 1, code_start + sizeof(code) - 1, 0, 2)); // Just execute 2 instructions.
|
OK(uc_emu_start(uc, code_start | 1, code_start + sizeof(code) - 1, 0,
|
||||||
|
2)); // Just execute 2 instructions.
|
||||||
|
|
||||||
OK(uc_hook_del(uc, hook));
|
OK(uc_hook_del(uc, hook));
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_LIST = {
|
TEST_LIST = {{"test_arm_nop", test_arm_nop},
|
||||||
{ "test_arm_nop", test_arm_nop },
|
{"test_arm_thumb_sub", test_arm_thumb_sub},
|
||||||
{ "test_arm_thumb_sub", test_arm_thumb_sub },
|
{"test_armeb_sub", test_armeb_sub},
|
||||||
{ "test_armeb_sub", test_armeb_sub },
|
{"test_arm_thumbeb_sub", test_arm_thumbeb_sub},
|
||||||
{ "test_arm_thumbeb_sub", test_arm_thumbeb_sub },
|
{"test_arm_thumb_ite", test_arm_thumb_ite},
|
||||||
{ "test_arm_thumb_ite", test_arm_thumb_ite },
|
{"test_arm_m_thumb_mrs", test_arm_m_thumb_mrs},
|
||||||
{ "test_arm_m_thumb_mrs", test_arm_m_thumb_mrs },
|
{"test_arm_m_control", test_arm_m_control},
|
||||||
{ "test_arm_m_control", test_arm_m_control },
|
{"test_arm_m_exc_return", test_arm_m_exc_return},
|
||||||
{ "test_arm_m_exc_return", test_arm_m_exc_return },
|
{NULL, NULL}};
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
|
@ -3,13 +3,16 @@
|
||||||
const uint64_t code_start = 0x1000;
|
const uint64_t code_start = 0x1000;
|
||||||
const uint64_t code_len = 0x4000;
|
const uint64_t code_len = 0x4000;
|
||||||
|
|
||||||
static void uc_common_setup(uc_engine** uc, uc_arch arch, uc_mode mode, const char* code, uint64_t size) {
|
static void uc_common_setup(uc_engine **uc, uc_arch arch, uc_mode mode,
|
||||||
|
const char *code, uint64_t size)
|
||||||
|
{
|
||||||
OK(uc_open(arch, mode, uc));
|
OK(uc_open(arch, mode, uc));
|
||||||
OK(uc_mem_map(*uc, code_start, code_len, UC_PROT_ALL));
|
OK(uc_mem_map(*uc, code_start, code_len, UC_PROT_ALL));
|
||||||
OK(uc_mem_write(*uc, code_start, code, size));
|
OK(uc_mem_write(*uc, code_start, code, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_arm64_until() {
|
static void test_arm64_until()
|
||||||
|
{
|
||||||
uc_engine *uc;
|
uc_engine *uc;
|
||||||
char code[] = "\x30\x00\x80\xd2\x11\x04\x80\xd2\x9c\x23\x00\x91";
|
char code[] = "\x30\x00\x80\xd2\x11\x04\x80\xd2\x9c\x23\x00\x91";
|
||||||
|
|
||||||
|
@ -47,8 +50,4 @@ static void test_arm64_until() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_LIST = {{"test_arm64_until", test_arm64_until}, {NULL, NULL}};
|
||||||
TEST_LIST = {
|
|
||||||
{ "test_arm64_until", test_arm64_until },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
|
@ -3,6 +3,4 @@
|
||||||
const uint64_t code_start = 0x1000;
|
const uint64_t code_start = 0x1000;
|
||||||
const uint64_t code_len = 0x4000;
|
const uint64_t code_len = 0x4000;
|
||||||
|
|
||||||
TEST_LIST = {
|
TEST_LIST = {{NULL, NULL}};
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
|
@ -1,34 +1,40 @@
|
||||||
#include "unicorn_test.h"
|
#include "unicorn_test.h"
|
||||||
|
|
||||||
static void test_map_correct() {
|
static void test_map_correct()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
|
|
||||||
OK(uc_open (UC_ARCH_X86, UC_MODE_64, &uc));
|
OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc));
|
||||||
OK(uc_mem_map (uc, 0x40000, 0x1000 * 16, UC_PROT_ALL)); // [0x40000, 0x50000]
|
OK(uc_mem_map(uc, 0x40000, 0x1000 * 16, UC_PROT_ALL)); // [0x40000, 0x50000]
|
||||||
OK(uc_mem_map (uc, 0x60000, 0x1000 * 16, UC_PROT_ALL)); // [0x60000, 0x70000]
|
OK(uc_mem_map(uc, 0x60000, 0x1000 * 16, UC_PROT_ALL)); // [0x60000, 0x70000]
|
||||||
OK(uc_mem_map (uc, 0x20000, 0x1000 * 16, UC_PROT_ALL)); // [0x20000, 0x30000]
|
OK(uc_mem_map(uc, 0x20000, 0x1000 * 16, UC_PROT_ALL)); // [0x20000, 0x30000]
|
||||||
uc_assert_err(UC_ERR_MAP, uc_mem_map(uc, 0x10000, 0x2000 * 16, UC_PROT_ALL));
|
uc_assert_err(UC_ERR_MAP,
|
||||||
uc_assert_err(UC_ERR_MAP, uc_mem_map(uc, 0x25000, 0x1000 * 16, UC_PROT_ALL));
|
uc_mem_map(uc, 0x10000, 0x2000 * 16, UC_PROT_ALL));
|
||||||
uc_assert_err(UC_ERR_MAP, uc_mem_map(uc, 0x35000, 0x1000 * 16, UC_PROT_ALL));
|
uc_assert_err(UC_ERR_MAP,
|
||||||
uc_assert_err(UC_ERR_MAP, uc_mem_map(uc, 0x45000, 0x1000 * 16, UC_PROT_ALL));
|
uc_mem_map(uc, 0x25000, 0x1000 * 16, UC_PROT_ALL));
|
||||||
uc_assert_err(UC_ERR_MAP, uc_mem_map(uc, 0x55000, 0x2000 * 16, UC_PROT_ALL));
|
uc_assert_err(UC_ERR_MAP,
|
||||||
|
uc_mem_map(uc, 0x35000, 0x1000 * 16, UC_PROT_ALL));
|
||||||
|
uc_assert_err(UC_ERR_MAP,
|
||||||
|
uc_mem_map(uc, 0x45000, 0x1000 * 16, UC_PROT_ALL));
|
||||||
|
uc_assert_err(UC_ERR_MAP,
|
||||||
|
uc_mem_map(uc, 0x55000, 0x2000 * 16, UC_PROT_ALL));
|
||||||
OK(uc_mem_map(uc, 0x35000, 0x5000, UC_PROT_ALL));
|
OK(uc_mem_map(uc, 0x35000, 0x5000, UC_PROT_ALL));
|
||||||
OK(uc_mem_map(uc, 0x50000, 0x5000, UC_PROT_ALL));
|
OK(uc_mem_map(uc, 0x50000, 0x5000, UC_PROT_ALL));
|
||||||
|
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_map_wrapping() {
|
static void test_map_wrapping()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
|
|
||||||
OK(uc_open (UC_ARCH_X86, UC_MODE_64, &uc));
|
OK(uc_open(UC_ARCH_X86, UC_MODE_64, &uc));
|
||||||
uc_assert_err(UC_ERR_ARG, uc_mem_map (uc, (~0ll - 0x4000) & ~0xfff, 0x8000, UC_PROT_ALL));
|
uc_assert_err(UC_ERR_ARG, uc_mem_map(uc, (~0ll - 0x4000) & ~0xfff, 0x8000,
|
||||||
|
UC_PROT_ALL));
|
||||||
|
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_LIST = {
|
TEST_LIST = {{"test_map_correct", test_map_correct},
|
||||||
{ "test_map_correct", test_map_correct },
|
{"test_map_wrapping", test_map_wrapping},
|
||||||
{ "test_map_wrapping", test_map_wrapping },
|
{NULL, NULL}};
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
|
@ -3,18 +3,22 @@
|
||||||
const uint64_t code_start = 0x10000000;
|
const uint64_t code_start = 0x10000000;
|
||||||
const uint64_t code_len = 0x4000;
|
const uint64_t code_len = 0x4000;
|
||||||
|
|
||||||
static void uc_common_setup(uc_engine** uc, uc_arch arch, uc_mode mode, const char* code, uint64_t size) {
|
static void uc_common_setup(uc_engine **uc, uc_arch arch, uc_mode mode,
|
||||||
|
const char *code, uint64_t size)
|
||||||
|
{
|
||||||
OK(uc_open(arch, mode, uc));
|
OK(uc_open(arch, mode, uc));
|
||||||
OK(uc_mem_map(*uc, code_start, code_len, UC_PROT_ALL));
|
OK(uc_mem_map(*uc, code_start, code_len, UC_PROT_ALL));
|
||||||
OK(uc_mem_write(*uc, code_start, code, size));
|
OK(uc_mem_write(*uc, code_start, code, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_mips_el_ori() {
|
static void test_mips_el_ori()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
char code[] = "\x56\x34\x21\x34"; // ori $at, $at, 0x3456;
|
char code[] = "\x56\x34\x21\x34"; // ori $at, $at, 0x3456;
|
||||||
int r_r1 = 0x6789;
|
int r_r1 = 0x6789;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_32 | UC_MODE_LITTLE_ENDIAN, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_32 | UC_MODE_LITTLE_ENDIAN, code,
|
||||||
|
sizeof(code) - 1);
|
||||||
OK(uc_reg_write(uc, UC_MIPS_REG_1, &r_r1));
|
OK(uc_reg_write(uc, UC_MIPS_REG_1, &r_r1));
|
||||||
|
|
||||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||||
|
@ -26,12 +30,14 @@ static void test_mips_el_ori() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_mips_eb_ori() {
|
static void test_mips_eb_ori()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
char code[] = "\x34\x21\x34\x56"; // ori $at, $at, 0x3456;
|
char code[] = "\x34\x21\x34\x56"; // ori $at, $at, 0x3456;
|
||||||
int r_r1 = 0x6789;
|
int r_r1 = 0x6789;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_32 | UC_MODE_BIG_ENDIAN, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_32 | UC_MODE_BIG_ENDIAN, code,
|
||||||
|
sizeof(code) - 1);
|
||||||
OK(uc_reg_write(uc, UC_MIPS_REG_1, &r_r1));
|
OK(uc_reg_write(uc, UC_MIPS_REG_1, &r_r1));
|
||||||
|
|
||||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||||
|
@ -43,12 +49,15 @@ static void test_mips_eb_ori() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_mips_stop_at_branch() {
|
static void test_mips_stop_at_branch()
|
||||||
uc_engine* uc;
|
{
|
||||||
char code[] = "\x02\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00"; // j 0x8; nop;
|
uc_engine *uc;
|
||||||
|
char code[] =
|
||||||
|
"\x02\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00"; // j 0x8; nop;
|
||||||
int r_pc = 0x0;
|
int r_pc = 0x0;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_32 | UC_MODE_LITTLE_ENDIAN, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_32 | UC_MODE_LITTLE_ENDIAN, code,
|
||||||
|
sizeof(code) - 1);
|
||||||
|
|
||||||
// Execute one instruction with branch delay slot.
|
// Execute one instruction with branch delay slot.
|
||||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 1));
|
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 1));
|
||||||
|
@ -62,12 +71,15 @@ static void test_mips_stop_at_branch() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_mips_stop_at_delay_slot() {
|
static void test_mips_stop_at_delay_slot()
|
||||||
uc_engine* uc;
|
{
|
||||||
char code[] = "\x02\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00"; // j 0x8; nop;
|
uc_engine *uc;
|
||||||
|
char code[] =
|
||||||
|
"\x02\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00"; // j 0x8; nop;
|
||||||
int r_pc = 0x0;
|
int r_pc = 0x0;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_32 | UC_MODE_LITTLE_ENDIAN, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_32 | UC_MODE_LITTLE_ENDIAN, code,
|
||||||
|
sizeof(code) - 1);
|
||||||
|
|
||||||
// Stop at the delay slot by design.
|
// Stop at the delay slot by design.
|
||||||
OK(uc_emu_start(uc, code_start, code_start + 4, 0, 0));
|
OK(uc_emu_start(uc, code_start, code_start + 4, 0, 0));
|
||||||
|
@ -81,12 +93,14 @@ static void test_mips_stop_at_delay_slot() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_mips_lwx_exception_issue_1314() {
|
static void test_mips_lwx_exception_issue_1314()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
char code[] = "\x0a\xc8\x79\x7e"; // lwx $t9, $t9($s3)
|
char code[] = "\x0a\xc8\x79\x7e"; // lwx $t9, $t9($s3)
|
||||||
int reg;
|
int reg;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_32 | UC_MODE_LITTLE_ENDIAN, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_MIPS, UC_MODE_32 | UC_MODE_LITTLE_ENDIAN, code,
|
||||||
|
sizeof(code) - 1);
|
||||||
OK(uc_mem_map(uc, 0x10000, 0x4000, UC_PROT_ALL));
|
OK(uc_mem_map(uc, 0x10000, 0x4000, UC_PROT_ALL));
|
||||||
|
|
||||||
// Enable DSP
|
// Enable DSP
|
||||||
|
@ -113,10 +127,9 @@ static void test_mips_lwx_exception_issue_1314() {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_LIST = {
|
TEST_LIST = {
|
||||||
{ "test_mips_stop_at_branch", test_mips_stop_at_branch },
|
{"test_mips_stop_at_branch", test_mips_stop_at_branch},
|
||||||
{ "test_mips_stop_at_delay_slot", test_mips_stop_at_delay_slot},
|
{"test_mips_stop_at_delay_slot", test_mips_stop_at_delay_slot},
|
||||||
{ "test_mips_el_ori", test_mips_el_ori},
|
{"test_mips_el_ori", test_mips_el_ori},
|
||||||
{ "test_mips_eb_ori", test_mips_eb_ori},
|
{"test_mips_eb_ori", test_mips_eb_ori},
|
||||||
{ "test_mips_lwx_exception_issue_1314", test_mips_lwx_exception_issue_1314},
|
{"test_mips_lwx_exception_issue_1314", test_mips_lwx_exception_issue_1314},
|
||||||
{ NULL, NULL }
|
{NULL, NULL}};
|
||||||
};
|
|
|
@ -3,18 +3,22 @@
|
||||||
const uint64_t code_start = 0x1000;
|
const uint64_t code_start = 0x1000;
|
||||||
const uint64_t code_len = 0x4000;
|
const uint64_t code_len = 0x4000;
|
||||||
|
|
||||||
static void uc_common_setup(uc_engine** uc, uc_arch arch, uc_mode mode, const char* code, uint64_t size) {
|
static void uc_common_setup(uc_engine **uc, uc_arch arch, uc_mode mode,
|
||||||
|
const char *code, uint64_t size)
|
||||||
|
{
|
||||||
OK(uc_open(arch, mode, uc));
|
OK(uc_open(arch, mode, uc));
|
||||||
OK(uc_mem_map(*uc, code_start, code_len, UC_PROT_ALL));
|
OK(uc_mem_map(*uc, code_start, code_len, UC_PROT_ALL));
|
||||||
OK(uc_mem_write(*uc, code_start, code, size));
|
OK(uc_mem_write(*uc, code_start, code, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_ppc32_add() {
|
static void test_ppc32_add()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
char code[] = "\x7f\x46\x1a\x14"; // ADD 26, 6, 3
|
char code[] = "\x7f\x46\x1a\x14"; // ADD 26, 6, 3
|
||||||
int reg;
|
int reg;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_PPC, UC_MODE_32 | UC_MODE_BIG_ENDIAN, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_PPC, UC_MODE_32 | UC_MODE_BIG_ENDIAN, code,
|
||||||
|
sizeof(code) - 1);
|
||||||
|
|
||||||
reg = 42;
|
reg = 42;
|
||||||
OK(uc_reg_write(uc, UC_PPC_REG_3, ®));
|
OK(uc_reg_write(uc, UC_PPC_REG_3, ®));
|
||||||
|
@ -30,7 +34,4 @@ static void test_ppc32_add() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_LIST = {
|
TEST_LIST = {{"test_ppc32_add", test_ppc32_add}, {NULL, NULL}};
|
||||||
{ "test_ppc32_add", test_ppc32_add },
|
|
||||||
{ NULL, NULL}
|
|
||||||
};
|
|
|
@ -3,19 +3,23 @@
|
||||||
const uint64_t code_start = 0x1000;
|
const uint64_t code_start = 0x1000;
|
||||||
const uint64_t code_len = 0x4000;
|
const uint64_t code_len = 0x4000;
|
||||||
|
|
||||||
static void uc_common_setup(uc_engine** uc, uc_arch arch, uc_mode mode, const char* code, uint64_t size) {
|
static void uc_common_setup(uc_engine **uc, uc_arch arch, uc_mode mode,
|
||||||
|
const char *code, uint64_t size)
|
||||||
|
{
|
||||||
OK(uc_open(arch, mode, uc));
|
OK(uc_open(arch, mode, uc));
|
||||||
OK(uc_mem_map(*uc, code_start, code_len, UC_PROT_ALL));
|
OK(uc_mem_map(*uc, code_start, code_len, UC_PROT_ALL));
|
||||||
OK(uc_mem_write(*uc, code_start, code, size));
|
OK(uc_mem_write(*uc, code_start, code, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_riscv32_nop() {
|
static void test_riscv32_nop()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
char code[] = "\x13\x00\x00\x00"; // nop
|
char code[] = "\x13\x00\x00\x00"; // nop
|
||||||
uint32_t r_t0 = 0x1234;
|
uint32_t r_t0 = 0x1234;
|
||||||
uint32_t r_t1 = 0x5678;
|
uint32_t r_t1 = 0x5678;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_RISCV, UC_MODE_RISCV32, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_RISCV, UC_MODE_RISCV32, code,
|
||||||
|
sizeof(code) - 1);
|
||||||
OK(uc_reg_write(uc, UC_RISCV_REG_T0, &r_t0));
|
OK(uc_reg_write(uc, UC_RISCV_REG_T0, &r_t0));
|
||||||
OK(uc_reg_write(uc, UC_RISCV_REG_T1, &r_t1));
|
OK(uc_reg_write(uc, UC_RISCV_REG_T1, &r_t1));
|
||||||
|
|
||||||
|
@ -29,13 +33,15 @@ static void test_riscv32_nop() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_riscv64_nop() {
|
static void test_riscv64_nop()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
char code[] = "\x13\x00\x00\x00"; // nop
|
char code[] = "\x13\x00\x00\x00"; // nop
|
||||||
uint64_t r_t0 = 0x1234;
|
uint64_t r_t0 = 0x1234;
|
||||||
uint64_t r_t1 = 0x5678;
|
uint64_t r_t1 = 0x5678;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_RISCV, UC_MODE_RISCV64, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_RISCV, UC_MODE_RISCV64, code,
|
||||||
|
sizeof(code) - 1);
|
||||||
OK(uc_reg_write(uc, UC_RISCV_REG_T0, &r_t0));
|
OK(uc_reg_write(uc, UC_RISCV_REG_T0, &r_t0));
|
||||||
OK(uc_reg_write(uc, UC_RISCV_REG_T1, &r_t1));
|
OK(uc_reg_write(uc, UC_RISCV_REG_T1, &r_t1));
|
||||||
|
|
||||||
|
@ -49,7 +55,8 @@ static void test_riscv64_nop() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_riscv32_until_pc_update() {
|
static void test_riscv32_until_pc_update()
|
||||||
|
{
|
||||||
uc_engine *uc;
|
uc_engine *uc;
|
||||||
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
|
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
|
||||||
|
|
||||||
|
@ -64,7 +71,8 @@ static void test_riscv32_until_pc_update() {
|
||||||
uint32_t r_pc = 0x0000;
|
uint32_t r_pc = 0x0000;
|
||||||
uint32_t r_sp = 0x1234;
|
uint32_t r_sp = 0x1234;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_RISCV, UC_MODE_RISCV32, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_RISCV, UC_MODE_RISCV32, code,
|
||||||
|
sizeof(code) - 1);
|
||||||
|
|
||||||
// initialize machine registers
|
// initialize machine registers
|
||||||
OK(uc_reg_write(uc, UC_RISCV_REG_T0, &r_t0));
|
OK(uc_reg_write(uc, UC_RISCV_REG_T0, &r_t0));
|
||||||
|
@ -88,7 +96,8 @@ static void test_riscv32_until_pc_update() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_riscv64_until_pc_update() {
|
static void test_riscv64_until_pc_update()
|
||||||
|
{
|
||||||
uc_engine *uc;
|
uc_engine *uc;
|
||||||
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
|
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
|
||||||
|
|
||||||
|
@ -103,7 +112,8 @@ static void test_riscv64_until_pc_update() {
|
||||||
uint64_t r_pc = 0x0000;
|
uint64_t r_pc = 0x0000;
|
||||||
uint64_t r_sp = 0x1234;
|
uint64_t r_sp = 0x1234;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_RISCV, UC_MODE_RISCV64, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_RISCV, UC_MODE_RISCV64, code,
|
||||||
|
sizeof(code) - 1);
|
||||||
|
|
||||||
// initialize machine registers
|
// initialize machine registers
|
||||||
OK(uc_reg_write(uc, UC_RISCV_REG_T0, &r_t0));
|
OK(uc_reg_write(uc, UC_RISCV_REG_T0, &r_t0));
|
||||||
|
@ -126,7 +136,8 @@ static void test_riscv64_until_pc_update() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_riscv32_3steps_pc_update() {
|
static void test_riscv32_3steps_pc_update()
|
||||||
|
{
|
||||||
uc_engine *uc;
|
uc_engine *uc;
|
||||||
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
|
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
|
||||||
|
|
||||||
|
@ -141,7 +152,8 @@ static void test_riscv32_3steps_pc_update() {
|
||||||
uint32_t r_pc = 0x0000;
|
uint32_t r_pc = 0x0000;
|
||||||
uint32_t r_sp = 0x1234;
|
uint32_t r_sp = 0x1234;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_RISCV, UC_MODE_RISCV32, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_RISCV, UC_MODE_RISCV32, code,
|
||||||
|
sizeof(code) - 1);
|
||||||
|
|
||||||
// initialize machine registers
|
// initialize machine registers
|
||||||
OK(uc_reg_write(uc, UC_RISCV_REG_T0, &r_t0));
|
OK(uc_reg_write(uc, UC_RISCV_REG_T0, &r_t0));
|
||||||
|
@ -165,7 +177,8 @@ static void test_riscv32_3steps_pc_update() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_riscv64_3steps_pc_update() {
|
static void test_riscv64_3steps_pc_update()
|
||||||
|
{
|
||||||
uc_engine *uc;
|
uc_engine *uc;
|
||||||
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
|
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
|
||||||
|
|
||||||
|
@ -180,7 +193,8 @@ static void test_riscv64_3steps_pc_update() {
|
||||||
uint64_t r_pc = 0x0000;
|
uint64_t r_pc = 0x0000;
|
||||||
uint64_t r_sp = 0x1234;
|
uint64_t r_sp = 0x1234;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_RISCV, UC_MODE_RISCV64, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_RISCV, UC_MODE_RISCV64, code,
|
||||||
|
sizeof(code) - 1);
|
||||||
|
|
||||||
// initialize machine registers
|
// initialize machine registers
|
||||||
OK(uc_reg_write(uc, UC_RISCV_REG_T0, &r_t0));
|
OK(uc_reg_write(uc, UC_RISCV_REG_T0, &r_t0));
|
||||||
|
@ -203,13 +217,10 @@ static void test_riscv64_3steps_pc_update() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_LIST = {{"test_riscv32_nop", test_riscv32_nop},
|
||||||
TEST_LIST = {
|
{"test_riscv64_nop", test_riscv64_nop},
|
||||||
{ "test_riscv32_nop", test_riscv32_nop },
|
{"test_riscv32_3steps_pc_update", test_riscv32_3steps_pc_update},
|
||||||
{ "test_riscv64_nop", test_riscv64_nop },
|
{"test_riscv64_3steps_pc_update", test_riscv64_3steps_pc_update},
|
||||||
{ "test_riscv32_3steps_pc_update", test_riscv32_3steps_pc_update },
|
{"test_riscv32_until_pc_update", test_riscv32_until_pc_update},
|
||||||
{ "test_riscv64_3steps_pc_update", test_riscv64_3steps_pc_update },
|
{"test_riscv64_until_pc_update", test_riscv64_until_pc_update},
|
||||||
{ "test_riscv32_until_pc_update", test_riscv32_until_pc_update },
|
{NULL, NULL}};
|
||||||
{ "test_riscv64_until_pc_update", test_riscv64_until_pc_update },
|
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
||||||
|
|
|
@ -3,6 +3,4 @@
|
||||||
const uint64_t code_start = 0x1000;
|
const uint64_t code_start = 0x1000;
|
||||||
const uint64_t code_len = 0x4000;
|
const uint64_t code_len = 0x4000;
|
||||||
|
|
||||||
TEST_LIST = {
|
TEST_LIST = {{NULL, NULL}};
|
||||||
{ NULL, NULL }
|
|
||||||
};
|
|
|
@ -3,7 +3,9 @@
|
||||||
const uint64_t code_start = 0x1000;
|
const uint64_t code_start = 0x1000;
|
||||||
const uint64_t code_len = 0x4000;
|
const uint64_t code_len = 0x4000;
|
||||||
|
|
||||||
static void uc_common_setup(uc_engine** uc, uc_arch arch, uc_mode mode, const char* code, uint64_t size) {
|
static void uc_common_setup(uc_engine **uc, uc_arch arch, uc_mode mode,
|
||||||
|
const char *code, uint64_t size)
|
||||||
|
{
|
||||||
OK(uc_open(arch, mode, uc));
|
OK(uc_open(arch, mode, uc));
|
||||||
OK(uc_mem_map(*uc, code_start, code_len, UC_PROT_ALL));
|
OK(uc_mem_map(*uc, code_start, code_len, UC_PROT_ALL));
|
||||||
OK(uc_mem_write(*uc, code_start, code, size));
|
OK(uc_mem_write(*uc, code_start, code, size));
|
||||||
|
@ -14,21 +16,25 @@ typedef struct _INSN_IN_RESULT {
|
||||||
int size;
|
int size;
|
||||||
} INSN_IN_RESULT;
|
} INSN_IN_RESULT;
|
||||||
|
|
||||||
static void test_x86_in_callback(uc_engine* uc, uint32_t port, int size, void* user_data) {
|
static void test_x86_in_callback(uc_engine *uc, uint32_t port, int size,
|
||||||
INSN_IN_RESULT* result = (INSN_IN_RESULT*)user_data;
|
void *user_data)
|
||||||
|
{
|
||||||
|
INSN_IN_RESULT *result = (INSN_IN_RESULT *)user_data;
|
||||||
|
|
||||||
result->port = port;
|
result->port = port;
|
||||||
result->size = size;
|
result->size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_in() {
|
static void test_x86_in()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
uc_hook hook;
|
uc_hook hook;
|
||||||
char code[] = "\xe5\x10"; // IN eax, 0x10
|
char code[] = "\xe5\x10"; // IN eax, 0x10
|
||||||
INSN_IN_RESULT result;
|
INSN_IN_RESULT result;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
||||||
OK(uc_hook_add(uc, &hook, UC_HOOK_INSN, test_x86_in_callback, &result, 1, 0, UC_X86_INS_IN));
|
OK(uc_hook_add(uc, &hook, UC_HOOK_INSN, test_x86_in_callback, &result, 1, 0,
|
||||||
|
UC_X86_INS_IN));
|
||||||
|
|
||||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||||
TEST_CHECK(result.port == 0x10);
|
TEST_CHECK(result.port == 0x10);
|
||||||
|
@ -44,22 +50,26 @@ typedef struct _INSN_OUT_RESULT {
|
||||||
uint32_t value;
|
uint32_t value;
|
||||||
} INSN_OUT_RESULT;
|
} INSN_OUT_RESULT;
|
||||||
|
|
||||||
static void test_x86_out_callback(uc_engine* uc, uint32_t port, int size, uint32_t value, void* user_data) {
|
static void test_x86_out_callback(uc_engine *uc, uint32_t port, int size,
|
||||||
INSN_OUT_RESULT* result = (INSN_OUT_RESULT*)user_data;
|
uint32_t value, void *user_data)
|
||||||
|
{
|
||||||
|
INSN_OUT_RESULT *result = (INSN_OUT_RESULT *)user_data;
|
||||||
|
|
||||||
result->port = port;
|
result->port = port;
|
||||||
result->size = size;
|
result->size = size;
|
||||||
result->value = value;
|
result->value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_out() {
|
static void test_x86_out()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
uc_hook hook;
|
uc_hook hook;
|
||||||
char code[] = "\xb0\x32\xe6\x46"; // MOV al, 0x32; OUT 0x46, al;
|
char code[] = "\xb0\x32\xe6\x46"; // MOV al, 0x32; OUT 0x46, al;
|
||||||
INSN_OUT_RESULT result;
|
INSN_OUT_RESULT result;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
||||||
OK(uc_hook_add(uc, &hook, UC_HOOK_INSN, test_x86_out_callback, &result, 1, 0, UC_X86_INS_OUT));
|
OK(uc_hook_add(uc, &hook, UC_HOOK_INSN, test_x86_out_callback, &result, 1,
|
||||||
|
0, UC_X86_INS_OUT));
|
||||||
|
|
||||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||||
TEST_CHECK(result.port == 0x46);
|
TEST_CHECK(result.port == 0x46);
|
||||||
|
@ -82,8 +92,11 @@ typedef struct _MEM_HOOK_RESULTS {
|
||||||
MEM_HOOK_RESULT results[16];
|
MEM_HOOK_RESULT results[16];
|
||||||
} MEM_HOOK_RESULTS;
|
} MEM_HOOK_RESULTS;
|
||||||
|
|
||||||
static bool test_x86_mem_hook_all_callback(uc_engine* uc, uc_mem_type type, uint64_t address, int size, uint64_t value, void* user_data) {
|
static bool test_x86_mem_hook_all_callback(uc_engine *uc, uc_mem_type type,
|
||||||
MEM_HOOK_RESULTS* r = (MEM_HOOK_RESULTS*)user_data;
|
uint64_t address, int size,
|
||||||
|
uint64_t value, void *user_data)
|
||||||
|
{
|
||||||
|
MEM_HOOK_RESULTS *r = (MEM_HOOK_RESULTS *)user_data;
|
||||||
uint64_t count = r->count;
|
uint64_t count = r->count;
|
||||||
|
|
||||||
if (count >= 16) {
|
if (count >= 16) {
|
||||||
|
@ -103,27 +116,28 @@ static bool test_x86_mem_hook_all_callback(uc_engine* uc, uc_mem_type type, uint
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_mem_hook_all() {
|
static void test_x86_mem_hook_all()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
uc_hook hook;
|
uc_hook hook;
|
||||||
// mov eax, 0xdeadbeef;
|
// mov eax, 0xdeadbeef;
|
||||||
// mov [0x8000], eax;
|
// mov [0x8000], eax;
|
||||||
// mov eax, [0x10000];
|
// mov eax, [0x10000];
|
||||||
char code[] = "\xb8\xef\xbe\xad\xde\xa3\x00\x80\x00\x00\xa1\x00\x00\x01\x00";
|
char code[] =
|
||||||
MEM_HOOK_RESULTS r = { 0 };
|
"\xb8\xef\xbe\xad\xde\xa3\x00\x80\x00\x00\xa1\x00\x00\x01\x00";
|
||||||
MEM_HOOK_RESULT expects[3] = {
|
MEM_HOOK_RESULTS r = {0};
|
||||||
{UC_MEM_WRITE, 0x8000, 4, 0xdeadbeef},
|
MEM_HOOK_RESULT expects[3] = {{UC_MEM_WRITE, 0x8000, 4, 0xdeadbeef},
|
||||||
{UC_MEM_READ_UNMAPPED, 0x10000, 4, 0},
|
{UC_MEM_READ_UNMAPPED, 0x10000, 4, 0},
|
||||||
{UC_MEM_READ, 0x10000, 4, 0}
|
{UC_MEM_READ, 0x10000, 4, 0}};
|
||||||
};
|
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
||||||
OK(uc_mem_map(uc, 0x8000, 0x1000, UC_PROT_ALL));
|
OK(uc_mem_map(uc, 0x8000, 0x1000, UC_PROT_ALL));
|
||||||
OK(uc_hook_add(uc, &hook, UC_HOOK_MEM_VALID | UC_HOOK_MEM_INVALID, test_x86_mem_hook_all_callback, &r, 1, 0));
|
OK(uc_hook_add(uc, &hook, UC_HOOK_MEM_VALID | UC_HOOK_MEM_INVALID,
|
||||||
|
test_x86_mem_hook_all_callback, &r, 1, 0));
|
||||||
|
|
||||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||||
TEST_CHECK(r.count == 3);
|
TEST_CHECK(r.count == 3);
|
||||||
for (int i = 0; i < r.count; i ++) {
|
for (int i = 0; i < r.count; i++) {
|
||||||
TEST_CHECK(expects[i].type == r.results[i].type);
|
TEST_CHECK(expects[i].type == r.results[i].type);
|
||||||
TEST_CHECK(expects[i].address == r.results[i].address);
|
TEST_CHECK(expects[i].address == r.results[i].address);
|
||||||
TEST_CHECK(expects[i].size == r.results[i].size);
|
TEST_CHECK(expects[i].size == r.results[i].size);
|
||||||
|
@ -134,9 +148,11 @@ static void test_x86_mem_hook_all() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_inc_dec_pxor() {
|
static void test_x86_inc_dec_pxor()
|
||||||
uc_engine* uc;
|
{
|
||||||
char code[] = "\x41\x4a\x66\x0f\xef\xc1"; // INC ecx; DEC edx; PXOR xmm0, xmm1
|
uc_engine *uc;
|
||||||
|
char code[] =
|
||||||
|
"\x41\x4a\x66\x0f\xef\xc1"; // INC ecx; DEC edx; PXOR xmm0, xmm1
|
||||||
int r_ecx = 0x1234;
|
int r_ecx = 0x1234;
|
||||||
int r_edx = 0x7890;
|
int r_edx = 0x7890;
|
||||||
uint64_t r_xmm0[2] = {0x08090a0b0c0d0e0f, 0x0001020304050607};
|
uint64_t r_xmm0[2] = {0x08090a0b0c0d0e0f, 0x0001020304050607};
|
||||||
|
@ -162,9 +178,11 @@ static void test_x86_inc_dec_pxor() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_relative_jump() {
|
static void test_x86_relative_jump()
|
||||||
uc_engine* uc;
|
{
|
||||||
char code[] = "\xeb\x02\x90\x90\x90\x90\x90\x90"; // jmp 4; nop; nop; nop; nop; nop; nop
|
uc_engine *uc;
|
||||||
|
char code[] = "\xeb\x02\x90\x90\x90\x90\x90\x90"; // jmp 4; nop; nop; nop;
|
||||||
|
// nop; nop; nop
|
||||||
int r_eip;
|
int r_eip;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
||||||
|
@ -178,8 +196,9 @@ static void test_x86_relative_jump() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_loop() {
|
static void test_x86_loop()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
char code[] = "\x41\x4a\xeb\xfe"; // inc ecx; dec edx; jmp $;
|
char code[] = "\x41\x4a\xeb\xfe"; // inc ecx; dec edx; jmp $;
|
||||||
int r_ecx = 0x1234;
|
int r_ecx = 0x1234;
|
||||||
int r_edx = 0x7890;
|
int r_edx = 0x7890;
|
||||||
|
@ -188,7 +207,8 @@ static void test_x86_loop() {
|
||||||
OK(uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx));
|
OK(uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx));
|
||||||
OK(uc_reg_write(uc, UC_X86_REG_EDX, &r_edx));
|
OK(uc_reg_write(uc, UC_X86_REG_EDX, &r_edx));
|
||||||
|
|
||||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 1 * 1000000, 0));
|
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 1 * 1000000,
|
||||||
|
0));
|
||||||
|
|
||||||
OK(uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx));
|
OK(uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx));
|
||||||
OK(uc_reg_read(uc, UC_X86_REG_EDX, &r_edx));
|
OK(uc_reg_read(uc, UC_X86_REG_EDX, &r_edx));
|
||||||
|
@ -199,40 +219,50 @@ static void test_x86_loop() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_invalid_mem_read() {
|
static void test_x86_invalid_mem_read()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
char code[] = "\x8b\x0d\xaa\xaa\xaa\xaa"; // mov ecx, [0xAAAAAAAA]
|
char code[] = "\x8b\x0d\xaa\xaa\xaa\xaa"; // mov ecx, [0xAAAAAAAA]
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
||||||
|
|
||||||
uc_assert_err(UC_ERR_READ_UNMAPPED, uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
uc_assert_err(
|
||||||
|
UC_ERR_READ_UNMAPPED,
|
||||||
|
uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||||
|
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_invalid_mem_write() {
|
static void test_x86_invalid_mem_write()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
char code[] = "\x89\x0d\xaa\xaa\xaa\xaa"; // mov ecx, [0xAAAAAAAA]
|
char code[] = "\x89\x0d\xaa\xaa\xaa\xaa"; // mov ecx, [0xAAAAAAAA]
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
||||||
|
|
||||||
uc_assert_err(UC_ERR_WRITE_UNMAPPED, uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
uc_assert_err(
|
||||||
|
UC_ERR_WRITE_UNMAPPED,
|
||||||
|
uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||||
|
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_invalid_jump() {
|
static void test_x86_invalid_jump()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
char code[] = "\xe9\xe9\xee\xee\xee"; // jmp 0xEEEEEEEE
|
char code[] = "\xe9\xe9\xee\xee\xee"; // jmp 0xEEEEEEEE
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
||||||
|
|
||||||
uc_assert_err(UC_ERR_FETCH_UNMAPPED, uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
uc_assert_err(
|
||||||
|
UC_ERR_FETCH_UNMAPPED,
|
||||||
|
uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||||
|
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_64_syscall_callback(uc_engine* uc, void* user_data) {
|
static void test_x86_64_syscall_callback(uc_engine *uc, void *user_data)
|
||||||
|
{
|
||||||
uint64_t rax;
|
uint64_t rax;
|
||||||
|
|
||||||
OK(uc_reg_read(uc, UC_X86_REG_RAX, &rax));
|
OK(uc_reg_read(uc, UC_X86_REG_RAX, &rax));
|
||||||
|
@ -240,15 +270,17 @@ static void test_x86_64_syscall_callback(uc_engine* uc, void* user_data) {
|
||||||
TEST_CHECK(rax == 0x100);
|
TEST_CHECK(rax == 0x100);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_64_syscall() {
|
static void test_x86_64_syscall()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
uc_hook hook;
|
uc_hook hook;
|
||||||
char code[] = "\x0f\x05"; // syscall
|
char code[] = "\x0f\x05"; // syscall
|
||||||
uint64_t r_rax = 0x100;
|
uint64_t r_rax = 0x100;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_64, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_64, code, sizeof(code) - 1);
|
||||||
OK(uc_reg_write(uc, UC_X86_REG_RAX, &r_rax));
|
OK(uc_reg_write(uc, UC_X86_REG_RAX, &r_rax));
|
||||||
OK(uc_hook_add(uc, &hook, UC_HOOK_INSN, test_x86_64_syscall_callback, NULL, 1, 0, UC_X86_INS_SYSCALL));
|
OK(uc_hook_add(uc, &hook, UC_HOOK_INSN, test_x86_64_syscall_callback, NULL,
|
||||||
|
1, 0, UC_X86_INS_SYSCALL));
|
||||||
|
|
||||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||||
|
|
||||||
|
@ -256,8 +288,9 @@ static void test_x86_64_syscall() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_16_add() {
|
static void test_x86_16_add()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
char code[] = "\x00\x00"; // add byte ptr [bx + si], al
|
char code[] = "\x00\x00"; // add byte ptr [bx + si], al
|
||||||
uint16_t r_ax = 7;
|
uint16_t r_ax = 7;
|
||||||
uint16_t r_bx = 5;
|
uint16_t r_bx = 5;
|
||||||
|
@ -277,9 +310,10 @@ static void test_x86_16_add() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_reg_save() {
|
static void test_x86_reg_save()
|
||||||
uc_engine* uc;
|
{
|
||||||
uc_context* ctx;
|
uc_engine *uc;
|
||||||
|
uc_context *ctx;
|
||||||
char code[] = "\x40"; // inc eax
|
char code[] = "\x40"; // inc eax
|
||||||
int r_eax = 1;
|
int r_eax = 1;
|
||||||
|
|
||||||
|
@ -302,27 +336,38 @@ static void test_x86_reg_save() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool test_x86_invalid_mem_read_stop_in_cb_callback(uc_engine* uc, uc_mem_type type, uint64_t address, int size, uint64_t value, void* user_data) {
|
static bool
|
||||||
// False indicates that we fail to handle this ERROR and let the emulation stop.
|
test_x86_invalid_mem_read_stop_in_cb_callback(uc_engine *uc, uc_mem_type type,
|
||||||
|
uint64_t address, int size,
|
||||||
|
uint64_t value, void *user_data)
|
||||||
|
{
|
||||||
|
// False indicates that we fail to handle this ERROR and let the emulation
|
||||||
|
// stop.
|
||||||
//
|
//
|
||||||
// Note that the memory must be mapped properly if we return true! Check test_x86_mem_hook_all for example.
|
// Note that the memory must be mapped properly if we return true! Check
|
||||||
|
// test_x86_mem_hook_all for example.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_invalid_mem_read_stop_in_cb() {
|
static void test_x86_invalid_mem_read_stop_in_cb()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
uc_hook hook;
|
uc_hook hook;
|
||||||
char code[] = "\x40\x8b\x1d\x00\x00\x10\x00\x42"; // inc eax; mov ebx, [0x100000]; inc edx
|
char code[] = "\x40\x8b\x1d\x00\x00\x10\x00\x42"; // inc eax; mov ebx,
|
||||||
|
// [0x100000]; inc edx
|
||||||
int r_eax = 0x1234;
|
int r_eax = 0x1234;
|
||||||
int r_edx = 0x5678;
|
int r_edx = 0x5678;
|
||||||
int r_eip = 0;
|
int r_eip = 0;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
||||||
OK(uc_hook_add(uc, &hook, UC_HOOK_MEM_READ, test_x86_invalid_mem_read_stop_in_cb_callback, NULL, 1, 0));
|
OK(uc_hook_add(uc, &hook, UC_HOOK_MEM_READ,
|
||||||
|
test_x86_invalid_mem_read_stop_in_cb_callback, NULL, 1, 0));
|
||||||
OK(uc_reg_write(uc, UC_X86_REG_EAX, &r_eax));
|
OK(uc_reg_write(uc, UC_X86_REG_EAX, &r_eax));
|
||||||
OK(uc_reg_write(uc, UC_X86_REG_EDX, &r_edx));
|
OK(uc_reg_write(uc, UC_X86_REG_EDX, &r_edx));
|
||||||
|
|
||||||
uc_assert_err(UC_ERR_READ_UNMAPPED, uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
uc_assert_err(
|
||||||
|
UC_ERR_READ_UNMAPPED,
|
||||||
|
uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||||
|
|
||||||
// The state of Unicorn should be correct at this time.
|
// The state of Unicorn should be correct at this time.
|
||||||
OK(uc_reg_read(uc, UC_X86_REG_EIP, &r_eip));
|
OK(uc_reg_read(uc, UC_X86_REG_EIP, &r_eip));
|
||||||
|
@ -336,8 +381,9 @@ static void test_x86_invalid_mem_read_stop_in_cb() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_x86_x87_fnstenv_callback(uc_engine *uc, uint64_t address,
|
||||||
static void test_x86_x87_fnstenv_callback(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) {
|
uint32_t size, void *user_data)
|
||||||
|
{
|
||||||
uint32_t r_eip;
|
uint32_t r_eip;
|
||||||
uint32_t r_eax;
|
uint32_t r_eax;
|
||||||
uint32_t fnstenv[7];
|
uint32_t fnstenv[7];
|
||||||
|
@ -345,7 +391,7 @@ static void test_x86_x87_fnstenv_callback(uc_engine* uc, uint64_t address, uint3
|
||||||
if (address == code_start + 4) { // The first fnstenv executed
|
if (address == code_start + 4) { // The first fnstenv executed
|
||||||
// Save the address of the fld.
|
// Save the address of the fld.
|
||||||
OK(uc_reg_read(uc, UC_X86_REG_EIP, &r_eip));
|
OK(uc_reg_read(uc, UC_X86_REG_EIP, &r_eip));
|
||||||
*((uint32_t*)user_data) = r_eip;
|
*((uint32_t *)user_data) = r_eip;
|
||||||
|
|
||||||
OK(uc_reg_read(uc, UC_X86_REG_EAX, &r_eax));
|
OK(uc_reg_read(uc, UC_X86_REG_EAX, &r_eax));
|
||||||
OK(uc_mem_read(uc, r_eax, fnstenv, sizeof(fnstenv)));
|
OK(uc_mem_read(uc, r_eax, fnstenv, sizeof(fnstenv)));
|
||||||
|
@ -354,10 +400,13 @@ static void test_x86_x87_fnstenv_callback(uc_engine* uc, uint64_t address, uint3
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_x87_fnstenv() {
|
static void test_x86_x87_fnstenv()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
uc_hook hook;
|
uc_hook hook;
|
||||||
char code[] = "\xd9\xd0\xd9\x30\xd9\x00\xd9\x30"; // fnop;fnstenv [eax];fld dword ptr [eax];fnstenv [eax]
|
char code[] =
|
||||||
|
"\xd9\xd0\xd9\x30\xd9\x00\xd9\x30"; // fnop;fnstenv [eax];fld dword ptr
|
||||||
|
// [eax];fnstenv [eax]
|
||||||
uint32_t base = code_start + 3 * code_len;
|
uint32_t base = code_start + 3 * code_len;
|
||||||
uint32_t last_eip;
|
uint32_t last_eip;
|
||||||
uint32_t fnstenv[7];
|
uint32_t fnstenv[7];
|
||||||
|
@ -366,25 +415,31 @@ static void test_x86_x87_fnstenv() {
|
||||||
OK(uc_mem_map(uc, base, code_len, UC_PROT_ALL));
|
OK(uc_mem_map(uc, base, code_len, UC_PROT_ALL));
|
||||||
OK(uc_reg_write(uc, UC_X86_REG_EAX, &base));
|
OK(uc_reg_write(uc, UC_X86_REG_EAX, &base));
|
||||||
|
|
||||||
OK(uc_hook_add(uc, &hook, UC_HOOK_CODE, test_x86_x87_fnstenv_callback, &last_eip, 1, 0));
|
OK(uc_hook_add(uc, &hook, UC_HOOK_CODE, test_x86_x87_fnstenv_callback,
|
||||||
|
&last_eip, 1, 0));
|
||||||
|
|
||||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||||
|
|
||||||
OK(uc_mem_read(uc, base, fnstenv, sizeof(fnstenv)));
|
OK(uc_mem_read(uc, base, fnstenv, sizeof(fnstenv)));
|
||||||
//But update FCS:FIP for fld.
|
// But update FCS:FIP for fld.
|
||||||
TEST_CHECK(fnstenv[3] == last_eip);
|
TEST_CHECK(fnstenv[3] == last_eip);
|
||||||
|
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t test_x86_mmio_read_callback(uc_engine* uc, uint64_t offset, unsigned size, void* user_data) {
|
static uint64_t test_x86_mmio_read_callback(uc_engine *uc, uint64_t offset,
|
||||||
|
unsigned size, void *user_data)
|
||||||
|
{
|
||||||
TEST_CHECK(offset == 4);
|
TEST_CHECK(offset == 4);
|
||||||
TEST_CHECK(size == 4);
|
TEST_CHECK(size == 4);
|
||||||
|
|
||||||
return 0x19260817;
|
return 0x19260817;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_mmio_write_callback(uc_engine* uc, uint64_t offset, unsigned size, uint64_t value, void* user_data) {
|
static void test_x86_mmio_write_callback(uc_engine *uc, uint64_t offset,
|
||||||
|
unsigned size, uint64_t value,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
TEST_CHECK(offset == 4);
|
TEST_CHECK(offset == 4);
|
||||||
TEST_CHECK(size == 4);
|
TEST_CHECK(size == 4);
|
||||||
TEST_CHECK(value == 0xdeadbeef);
|
TEST_CHECK(value == 0xdeadbeef);
|
||||||
|
@ -392,14 +447,19 @@ static void test_x86_mmio_write_callback(uc_engine* uc, uint64_t offset, unsigne
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_mmio() {
|
static void test_x86_mmio()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
int r_ecx = 0xdeadbeef;
|
int r_ecx = 0xdeadbeef;
|
||||||
char code[] = "\x89\x0d\x04\x00\x02\x00\x8b\x0d\x04\x00\x02\x00"; // mov [0x20004], ecx; mov ecx, [0x20004]
|
char code[] =
|
||||||
|
"\x89\x0d\x04\x00\x02\x00\x8b\x0d\x04\x00\x02\x00"; // mov [0x20004],
|
||||||
|
// ecx; mov ecx,
|
||||||
|
// [0x20004]
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
||||||
OK(uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx));
|
OK(uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx));
|
||||||
OK(uc_mmio_map(uc, 0x20000, 0x1000, test_x86_mmio_read_callback, NULL, test_x86_mmio_write_callback, NULL));
|
OK(uc_mmio_map(uc, 0x20000, 0x1000, test_x86_mmio_read_callback, NULL,
|
||||||
|
test_x86_mmio_write_callback, NULL));
|
||||||
|
|
||||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||||
|
|
||||||
|
@ -410,7 +470,10 @@ static void test_x86_mmio() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool test_x86_missing_code_callback(uc_engine* uc, uc_mem_type type, uint64_t address, int size, uint64_t value, void* user_data) {
|
static bool test_x86_missing_code_callback(uc_engine *uc, uc_mem_type type,
|
||||||
|
uint64_t address, int size,
|
||||||
|
uint64_t value, void *user_data)
|
||||||
|
{
|
||||||
char code[] = "\x41\x4a"; // inc ecx; dec edx;
|
char code[] = "\x41\x4a"; // inc ecx; dec edx;
|
||||||
uint64_t algined_address = address & 0xFFFFFFFFFFFFF000ULL;
|
uint64_t algined_address = address & 0xFFFFFFFFFFFFF000ULL;
|
||||||
int aligned_size = ((int)(size / 0x1000) + 1) * 0x1000;
|
int aligned_size = ((int)(size / 0x1000) + 1) * 0x1000;
|
||||||
|
@ -422,8 +485,9 @@ static bool test_x86_missing_code_callback(uc_engine* uc, uc_mem_type type, uint
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_missing_code() {
|
static void test_x86_missing_code()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
uc_hook hook;
|
uc_hook hook;
|
||||||
int r_ecx = 0x1234;
|
int r_ecx = 0x1234;
|
||||||
int r_edx = 0x7890;
|
int r_edx = 0x7890;
|
||||||
|
@ -432,7 +496,8 @@ static void test_x86_missing_code() {
|
||||||
OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc));
|
OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc));
|
||||||
OK(uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx));
|
OK(uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx));
|
||||||
OK(uc_reg_write(uc, UC_X86_REG_EDX, &r_edx));
|
OK(uc_reg_write(uc, UC_X86_REG_EDX, &r_edx));
|
||||||
OK(uc_hook_add(uc, &hook, UC_HOOK_MEM_UNMAPPED, test_x86_missing_code_callback, NULL, 1, 0));
|
OK(uc_hook_add(uc, &hook, UC_HOOK_MEM_UNMAPPED,
|
||||||
|
test_x86_missing_code_callback, NULL, 1, 0));
|
||||||
|
|
||||||
OK(uc_emu_start(uc, code_start, code_start + 2, 0, 0));
|
OK(uc_emu_start(uc, code_start, code_start + 2, 0, 0));
|
||||||
|
|
||||||
|
@ -445,8 +510,9 @@ static void test_x86_missing_code() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_smc_xor() {
|
static void test_x86_smc_xor()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
/*
|
/*
|
||||||
* 0x1000 xor dword ptr [edi+0x3], eax ; edi=0x1000, eax=0xbc4177e6
|
* 0x1000 xor dword ptr [edi+0x3], eax ; edi=0x1000, eax=0xbc4177e6
|
||||||
* 0x1003 dw 0x3ea98b13
|
* 0x1003 dw 0x3ea98b13
|
||||||
|
@ -469,14 +535,23 @@ static void test_x86_smc_xor() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint64_t test_x86_mmio_uc_mem_rw_read_callback(uc_engine* uc, uint64_t offset, unsigned size, void* user_data) {
|
static uint64_t test_x86_mmio_uc_mem_rw_read_callback(uc_engine *uc,
|
||||||
|
uint64_t offset,
|
||||||
|
unsigned size,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
TEST_CHECK(offset == 8);
|
TEST_CHECK(offset == 8);
|
||||||
TEST_CHECK(size == 4);
|
TEST_CHECK(size == 4);
|
||||||
|
|
||||||
return 0x19260817;
|
return 0x19260817;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_mmio_uc_mem_rw_write_callback(uc_engine* uc, uint64_t offset, unsigned size, uint64_t value, void* user_data) {
|
static void test_x86_mmio_uc_mem_rw_write_callback(uc_engine *uc,
|
||||||
|
uint64_t offset,
|
||||||
|
unsigned size,
|
||||||
|
uint64_t value,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
TEST_CHECK(offset == 4);
|
TEST_CHECK(offset == 4);
|
||||||
TEST_CHECK(size == 4);
|
TEST_CHECK(size == 4);
|
||||||
TEST_CHECK(value == 0xdeadbeef);
|
TEST_CHECK(value == 0xdeadbeef);
|
||||||
|
@ -484,39 +559,40 @@ static void test_x86_mmio_uc_mem_rw_write_callback(uc_engine* uc, uint64_t offse
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void test_x86_mmio_uc_mem_rw()
|
||||||
static void test_x86_mmio_uc_mem_rw() {
|
{
|
||||||
uc_engine* uc;
|
uc_engine *uc;
|
||||||
int data = 0xdeadbeef;
|
int data = 0xdeadbeef;
|
||||||
|
|
||||||
OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc));
|
OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc));
|
||||||
|
|
||||||
OK(uc_mmio_map(uc,
|
OK(uc_mmio_map(uc, 0x20000, 0x1000, test_x86_mmio_uc_mem_rw_read_callback,
|
||||||
0x20000, 0x1000,
|
NULL, test_x86_mmio_uc_mem_rw_write_callback, NULL));
|
||||||
test_x86_mmio_uc_mem_rw_read_callback, NULL,
|
|
||||||
test_x86_mmio_uc_mem_rw_write_callback, NULL));
|
|
||||||
|
|
||||||
OK(uc_mem_write(uc, 0x20004, (void*)&data, 4));
|
OK(uc_mem_write(uc, 0x20004, (void *)&data, 4));
|
||||||
OK(uc_mem_read(uc, 0x20008, (void*)&data, 4));
|
OK(uc_mem_read(uc, 0x20008, (void *)&data, 4));
|
||||||
|
|
||||||
TEST_CHECK(data == 0x19260817);
|
TEST_CHECK(data == 0x19260817);
|
||||||
|
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_sysenter_hook(uc_engine* uc, void* user) {
|
static void test_x86_sysenter_hook(uc_engine *uc, void *user)
|
||||||
*(int*)user = 1;
|
{
|
||||||
|
*(int *)user = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_sysenter() {
|
static void test_x86_sysenter()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
char code[] = "\x0F\x34"; // sysenter
|
char code[] = "\x0F\x34"; // sysenter
|
||||||
uc_hook h;
|
uc_hook h;
|
||||||
int called = 0;
|
int called = 0;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
||||||
|
|
||||||
OK(uc_hook_add(uc, &h, UC_HOOK_INSN, test_x86_sysenter_hook, &called, 1, 0, UC_X86_INS_SYSENTER));
|
OK(uc_hook_add(uc, &h, UC_HOOK_INSN, test_x86_sysenter_hook, &called, 1, 0,
|
||||||
|
UC_X86_INS_SYSENTER));
|
||||||
|
|
||||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||||
|
|
||||||
|
@ -525,21 +601,24 @@ static void test_x86_sysenter() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_hook_cpuid_callback(uc_engine* uc, void* data) {
|
static void test_x86_hook_cpuid_callback(uc_engine *uc, void *data)
|
||||||
|
{
|
||||||
int reg = 7;
|
int reg = 7;
|
||||||
|
|
||||||
OK(uc_reg_write(uc, UC_X86_REG_EAX, ®));
|
OK(uc_reg_write(uc, UC_X86_REG_EAX, ®));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void test_x86_hook_cpuid() {
|
static void test_x86_hook_cpuid()
|
||||||
uc_engine* uc;
|
{
|
||||||
|
uc_engine *uc;
|
||||||
char code[] = "\x40\x0F\xA2"; // INC EAX; CPUID
|
char code[] = "\x40\x0F\xA2"; // INC EAX; CPUID
|
||||||
uc_hook h;
|
uc_hook h;
|
||||||
int reg;
|
int reg;
|
||||||
|
|
||||||
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
uc_common_setup(&uc, UC_ARCH_X86, UC_MODE_32, code, sizeof(code) - 1);
|
||||||
|
|
||||||
OK(uc_hook_add(uc, &h, UC_HOOK_INSN, test_x86_hook_cpuid_callback, NULL, 1, 0, UC_X86_INS_CPUID));
|
OK(uc_hook_add(uc, &h, UC_HOOK_INSN, test_x86_hook_cpuid_callback, NULL, 1,
|
||||||
|
0, UC_X86_INS_CPUID));
|
||||||
|
|
||||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||||
|
|
||||||
|
@ -550,26 +629,25 @@ static void test_x86_hook_cpuid() {
|
||||||
OK(uc_close(uc));
|
OK(uc_close(uc));
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_LIST = {
|
TEST_LIST = {{"test_x86_in", test_x86_in},
|
||||||
{ "test_x86_in", test_x86_in },
|
{"test_x86_out", test_x86_out},
|
||||||
{ "test_x86_out", test_x86_out },
|
{"test_x86_mem_hook_all", test_x86_mem_hook_all},
|
||||||
{ "test_x86_mem_hook_all", test_x86_mem_hook_all },
|
{"test_x86_inc_dec_pxor", test_x86_inc_dec_pxor},
|
||||||
{ "test_x86_inc_dec_pxor", test_x86_inc_dec_pxor },
|
{"test_x86_relative_jump", test_x86_relative_jump},
|
||||||
{ "test_x86_relative_jump", test_x86_relative_jump },
|
{"test_x86_loop", test_x86_loop},
|
||||||
{ "test_x86_loop", test_x86_loop },
|
{"test_x86_invalid_mem_read", test_x86_invalid_mem_read},
|
||||||
{ "test_x86_invalid_mem_read", test_x86_invalid_mem_read },
|
{"test_x86_invalid_mem_write", test_x86_invalid_mem_write},
|
||||||
{ "test_x86_invalid_mem_write", test_x86_invalid_mem_write },
|
{"test_x86_invalid_jump", test_x86_invalid_jump},
|
||||||
{ "test_x86_invalid_jump", test_x86_invalid_jump},
|
{"test_x86_64_syscall", test_x86_64_syscall},
|
||||||
{ "test_x86_64_syscall", test_x86_64_syscall },
|
{"test_x86_16_add", test_x86_16_add},
|
||||||
{ "test_x86_16_add", test_x86_16_add },
|
{"test_x86_reg_save", test_x86_reg_save},
|
||||||
{ "test_x86_reg_save", test_x86_reg_save },
|
{"test_x86_invalid_mem_read_stop_in_cb",
|
||||||
{ "test_x86_invalid_mem_read_stop_in_cb", test_x86_invalid_mem_read_stop_in_cb },
|
test_x86_invalid_mem_read_stop_in_cb},
|
||||||
{ "test_x86_x87_fnstenv", test_x86_x87_fnstenv},
|
{"test_x86_x87_fnstenv", test_x86_x87_fnstenv},
|
||||||
{ "test_x86_mmio", test_x86_mmio},
|
{"test_x86_mmio", test_x86_mmio},
|
||||||
{ "test_x86_missing_code", test_x86_missing_code},
|
{"test_x86_missing_code", test_x86_missing_code},
|
||||||
{ "test_x86_smc_xor", test_x86_smc_xor},
|
{"test_x86_smc_xor", test_x86_smc_xor},
|
||||||
{ "test_x86_mmio_uc_mem_rw", test_x86_mmio_uc_mem_rw},
|
{"test_x86_mmio_uc_mem_rw", test_x86_mmio_uc_mem_rw},
|
||||||
{ "test_x86_sysenter", test_x86_sysenter},
|
{"test_x86_sysenter", test_x86_sysenter},
|
||||||
{ "test_x86_hook_cpuid", test_x86_hook_cpuid},
|
{"test_x86_hook_cpuid", test_x86_hook_cpuid},
|
||||||
{ NULL, NULL }
|
{NULL, NULL}};
|
||||||
};
|
|
|
@ -9,12 +9,12 @@
|
||||||
* Assert that err matches expect
|
* Assert that err matches expect
|
||||||
*/
|
*/
|
||||||
#define uc_assert_err(expect, err) \
|
#define uc_assert_err(expect, err) \
|
||||||
do { \
|
do { \
|
||||||
uc_err __err = err; \
|
uc_err __err = err; \
|
||||||
if (!TEST_CHECK(__err == expect)) { \
|
if (!TEST_CHECK(__err == expect)) { \
|
||||||
TEST_MSG("%s", uc_strerror(__err)); \
|
TEST_MSG("%s", uc_strerror(__err)); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assert that err is UC_ERR_OK
|
* Assert that err is UC_ERR_OK
|
||||||
|
|
291
uc.c
291
uc.c
|
@ -37,18 +37,16 @@ unsigned int uc_version(unsigned int *major, unsigned int *minor)
|
||||||
return (UC_API_MAJOR << 8) + UC_API_MINOR;
|
return (UC_API_MAJOR << 8) + UC_API_MINOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_errno(uc_engine *uc)
|
uc_err uc_errno(uc_engine *uc)
|
||||||
{
|
{
|
||||||
return uc->errnum;
|
return uc->errnum;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
const char *uc_strerror(uc_err code)
|
const char *uc_strerror(uc_err code)
|
||||||
{
|
{
|
||||||
switch(code) {
|
switch (code) {
|
||||||
default:
|
default:
|
||||||
return "Unknown error code";
|
return "Unknown error code";
|
||||||
case UC_ERR_OK:
|
case UC_ERR_OK:
|
||||||
|
@ -96,41 +94,48 @@ const char *uc_strerror(uc_err code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
bool uc_arch_supported(uc_arch arch)
|
bool uc_arch_supported(uc_arch arch)
|
||||||
{
|
{
|
||||||
switch (arch) {
|
switch (arch) {
|
||||||
#ifdef UNICORN_HAS_ARM
|
#ifdef UNICORN_HAS_ARM
|
||||||
case UC_ARCH_ARM: return true;
|
case UC_ARCH_ARM:
|
||||||
|
return true;
|
||||||
#endif
|
#endif
|
||||||
#ifdef UNICORN_HAS_ARM64
|
#ifdef UNICORN_HAS_ARM64
|
||||||
case UC_ARCH_ARM64: return true;
|
case UC_ARCH_ARM64:
|
||||||
|
return true;
|
||||||
#endif
|
#endif
|
||||||
#ifdef UNICORN_HAS_M68K
|
#ifdef UNICORN_HAS_M68K
|
||||||
case UC_ARCH_M68K: return true;
|
case UC_ARCH_M68K:
|
||||||
|
return true;
|
||||||
#endif
|
#endif
|
||||||
#ifdef UNICORN_HAS_MIPS
|
#ifdef UNICORN_HAS_MIPS
|
||||||
case UC_ARCH_MIPS: return true;
|
case UC_ARCH_MIPS:
|
||||||
|
return true;
|
||||||
#endif
|
#endif
|
||||||
#ifdef UNICORN_HAS_PPC
|
#ifdef UNICORN_HAS_PPC
|
||||||
case UC_ARCH_PPC: return true;
|
case UC_ARCH_PPC:
|
||||||
|
return true;
|
||||||
#endif
|
#endif
|
||||||
#ifdef UNICORN_HAS_SPARC
|
#ifdef UNICORN_HAS_SPARC
|
||||||
case UC_ARCH_SPARC: return true;
|
case UC_ARCH_SPARC:
|
||||||
|
return true;
|
||||||
#endif
|
#endif
|
||||||
#ifdef UNICORN_HAS_X86
|
#ifdef UNICORN_HAS_X86
|
||||||
case UC_ARCH_X86: return true;
|
case UC_ARCH_X86:
|
||||||
|
return true;
|
||||||
#endif
|
#endif
|
||||||
#ifdef UNICORN_HAS_RISCV
|
#ifdef UNICORN_HAS_RISCV
|
||||||
case UC_ARCH_RISCV: return true;
|
case UC_ARCH_RISCV:
|
||||||
|
return true;
|
||||||
#endif
|
#endif
|
||||||
/* Invalid or disabled arch */
|
/* Invalid or disabled arch */
|
||||||
default: return false;
|
default:
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
|
uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
|
||||||
{
|
{
|
||||||
|
@ -156,13 +161,12 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
|
||||||
|
|
||||||
QTAILQ_INIT(&uc->address_spaces);
|
QTAILQ_INIT(&uc->address_spaces);
|
||||||
|
|
||||||
switch(arch) {
|
switch (arch) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
#ifdef UNICORN_HAS_M68K
|
#ifdef UNICORN_HAS_M68K
|
||||||
case UC_ARCH_M68K:
|
case UC_ARCH_M68K:
|
||||||
if ((mode & ~UC_MODE_M68K_MASK) ||
|
if ((mode & ~UC_MODE_M68K_MASK) || !(mode & UC_MODE_BIG_ENDIAN)) {
|
||||||
!(mode & UC_MODE_BIG_ENDIAN)) {
|
|
||||||
free(uc);
|
free(uc);
|
||||||
return UC_ERR_MODE;
|
return UC_ERR_MODE;
|
||||||
}
|
}
|
||||||
|
@ -171,9 +175,8 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
|
||||||
#endif
|
#endif
|
||||||
#ifdef UNICORN_HAS_X86
|
#ifdef UNICORN_HAS_X86
|
||||||
case UC_ARCH_X86:
|
case UC_ARCH_X86:
|
||||||
if ((mode & ~UC_MODE_X86_MASK) ||
|
if ((mode & ~UC_MODE_X86_MASK) || (mode & UC_MODE_BIG_ENDIAN) ||
|
||||||
(mode & UC_MODE_BIG_ENDIAN) ||
|
!(mode & (UC_MODE_16 | UC_MODE_32 | UC_MODE_64))) {
|
||||||
!(mode & (UC_MODE_16|UC_MODE_32|UC_MODE_64))) {
|
|
||||||
free(uc);
|
free(uc);
|
||||||
return UC_ERR_MODE;
|
return UC_ERR_MODE;
|
||||||
}
|
}
|
||||||
|
@ -211,10 +214,11 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(UNICORN_HAS_MIPS) || defined(UNICORN_HAS_MIPSEL) || defined(UNICORN_HAS_MIPS64) || defined(UNICORN_HAS_MIPS64EL)
|
#if defined(UNICORN_HAS_MIPS) || defined(UNICORN_HAS_MIPSEL) || \
|
||||||
|
defined(UNICORN_HAS_MIPS64) || defined(UNICORN_HAS_MIPS64EL)
|
||||||
case UC_ARCH_MIPS:
|
case UC_ARCH_MIPS:
|
||||||
if ((mode & ~UC_MODE_MIPS_MASK) ||
|
if ((mode & ~UC_MODE_MIPS_MASK) ||
|
||||||
!(mode & (UC_MODE_MIPS32|UC_MODE_MIPS64))) {
|
!(mode & (UC_MODE_MIPS32 | UC_MODE_MIPS64))) {
|
||||||
free(uc);
|
free(uc);
|
||||||
return UC_ERR_MODE;
|
return UC_ERR_MODE;
|
||||||
}
|
}
|
||||||
|
@ -246,9 +250,8 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
|
||||||
|
|
||||||
#ifdef UNICORN_HAS_SPARC
|
#ifdef UNICORN_HAS_SPARC
|
||||||
case UC_ARCH_SPARC:
|
case UC_ARCH_SPARC:
|
||||||
if ((mode & ~UC_MODE_SPARC_MASK) ||
|
if ((mode & ~UC_MODE_SPARC_MASK) || !(mode & UC_MODE_BIG_ENDIAN) ||
|
||||||
!(mode & UC_MODE_BIG_ENDIAN) ||
|
!(mode & (UC_MODE_SPARC32 | UC_MODE_SPARC64))) {
|
||||||
!(mode & (UC_MODE_SPARC32|UC_MODE_SPARC64))) {
|
|
||||||
free(uc);
|
free(uc);
|
||||||
return UC_ERR_MODE;
|
return UC_ERR_MODE;
|
||||||
}
|
}
|
||||||
|
@ -261,9 +264,8 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
|
||||||
#endif
|
#endif
|
||||||
#ifdef UNICORN_HAS_PPC
|
#ifdef UNICORN_HAS_PPC
|
||||||
case UC_ARCH_PPC:
|
case UC_ARCH_PPC:
|
||||||
if ((mode & ~UC_MODE_PPC_MASK) ||
|
if ((mode & ~UC_MODE_PPC_MASK) || !(mode & UC_MODE_BIG_ENDIAN) ||
|
||||||
!(mode & UC_MODE_BIG_ENDIAN) ||
|
!(mode & (UC_MODE_PPC32 | UC_MODE_PPC64))) {
|
||||||
!(mode & (UC_MODE_PPC32|UC_MODE_PPC64))) {
|
|
||||||
free(uc);
|
free(uc);
|
||||||
return UC_ERR_MODE;
|
return UC_ERR_MODE;
|
||||||
}
|
}
|
||||||
|
@ -277,21 +279,20 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
|
||||||
#ifdef UNICORN_HAS_RISCV
|
#ifdef UNICORN_HAS_RISCV
|
||||||
case UC_ARCH_RISCV:
|
case UC_ARCH_RISCV:
|
||||||
if ((mode & ~UC_MODE_RISCV_MASK) ||
|
if ((mode & ~UC_MODE_RISCV_MASK) ||
|
||||||
!(mode & (UC_MODE_RISCV32|UC_MODE_RISCV64))) {
|
!(mode & (UC_MODE_RISCV32 | UC_MODE_RISCV64))) {
|
||||||
free(uc);
|
free(uc);
|
||||||
return UC_ERR_MODE;
|
return UC_ERR_MODE;
|
||||||
}
|
}
|
||||||
if (mode & UC_MODE_RISCV32) {
|
if (mode & UC_MODE_RISCV32) {
|
||||||
uc->init_arch = riscv32_uc_init;
|
uc->init_arch = riscv32_uc_init;
|
||||||
} else if (mode & UC_MODE_RISCV64) {
|
} else if (mode & UC_MODE_RISCV64) {
|
||||||
uc->init_arch =riscv64_uc_init;
|
uc->init_arch = riscv64_uc_init;
|
||||||
} else {
|
} else {
|
||||||
free(uc);
|
free(uc);
|
||||||
return UC_ERR_MODE;
|
return UC_ERR_MODE;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uc->init_arch == NULL) {
|
if (uc->init_arch == NULL) {
|
||||||
|
@ -317,7 +318,6 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_close(uc_engine *uc)
|
uc_err uc_close(uc_engine *uc)
|
||||||
{
|
{
|
||||||
|
@ -390,7 +390,7 @@ uc_err uc_close(uc_engine *uc)
|
||||||
cur = uc->saved_contexts.head;
|
cur = uc->saved_contexts.head;
|
||||||
while (cur != NULL) {
|
while (cur != NULL) {
|
||||||
struct list_item *next = cur->next;
|
struct list_item *next = cur->next;
|
||||||
struct uc_context *context = (struct uc_context*)cur->data;
|
struct uc_context *context = (struct uc_context *)cur->data;
|
||||||
context->uc = NULL;
|
context->uc = NULL;
|
||||||
cur = next;
|
cur = next;
|
||||||
}
|
}
|
||||||
|
@ -403,7 +403,6 @@ uc_err uc_close(uc_engine *uc)
|
||||||
return UC_ERR_OK;
|
return UC_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_reg_read_batch(uc_engine *uc, int *ids, void **vals, int count)
|
uc_err uc_reg_read_batch(uc_engine *uc, int *ids, void **vals, int count)
|
||||||
{
|
{
|
||||||
|
@ -417,7 +416,6 @@ uc_err uc_reg_read_batch(uc_engine *uc, int *ids, void **vals, int count)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_reg_write_batch(uc_engine *uc, int *ids, void *const *vals, int count)
|
uc_err uc_reg_write_batch(uc_engine *uc, int *ids, void *const *vals, int count)
|
||||||
{
|
{
|
||||||
|
@ -431,7 +429,6 @@ uc_err uc_reg_write_batch(uc_engine *uc, int *ids, void *const *vals, int count)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_reg_read(uc_engine *uc, int regid, void *value)
|
uc_err uc_reg_read(uc_engine *uc, int regid, void *value)
|
||||||
{
|
{
|
||||||
|
@ -450,13 +447,13 @@ static bool check_mem_area(uc_engine *uc, uint64_t address, size_t size)
|
||||||
{
|
{
|
||||||
size_t count = 0, len;
|
size_t count = 0, len;
|
||||||
|
|
||||||
while(count < size) {
|
while (count < size) {
|
||||||
MemoryRegion *mr = memory_mapping(uc, address);
|
MemoryRegion *mr = memory_mapping(uc, address);
|
||||||
if (mr) {
|
if (mr) {
|
||||||
len = (size_t)MIN(size - count, mr->end - address);
|
len = (size_t)MIN(size - count, mr->end - address);
|
||||||
count += len;
|
count += len;
|
||||||
address += len;
|
address += len;
|
||||||
} else {// this address is not mapped in yet
|
} else { // this address is not mapped in yet
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -464,7 +461,6 @@ static bool check_mem_area(uc_engine *uc, uint64_t address, size_t size)
|
||||||
return (count == size);
|
return (count == size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *_bytes, size_t size)
|
uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *_bytes, size_t size)
|
||||||
{
|
{
|
||||||
|
@ -484,11 +480,12 @@ uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *_bytes, size_t size)
|
||||||
}
|
}
|
||||||
|
|
||||||
// memory area can overlap adjacent memory blocks
|
// memory area can overlap adjacent memory blocks
|
||||||
while(count < size) {
|
while (count < size) {
|
||||||
MemoryRegion *mr = memory_mapping(uc, address);
|
MemoryRegion *mr = memory_mapping(uc, address);
|
||||||
if (mr) {
|
if (mr) {
|
||||||
len = (size_t)MIN(size - count, mr->end - address);
|
len = (size_t)MIN(size - count, mr->end - address);
|
||||||
if (uc->read_mem(&uc->address_space_memory, address, bytes, len) == false) {
|
if (uc->read_mem(&uc->address_space_memory, address, bytes, len) ==
|
||||||
|
false) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
count += len;
|
count += len;
|
||||||
|
@ -507,7 +504,8 @@ uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *_bytes, size_t size)
|
||||||
}
|
}
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *_bytes, size_t size)
|
uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *_bytes,
|
||||||
|
size_t size)
|
||||||
{
|
{
|
||||||
size_t count = 0, len;
|
size_t count = 0, len;
|
||||||
const uint8_t *bytes = _bytes;
|
const uint8_t *bytes = _bytes;
|
||||||
|
@ -525,21 +523,23 @@ uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *_bytes, size_t
|
||||||
}
|
}
|
||||||
|
|
||||||
// memory area can overlap adjacent memory blocks
|
// memory area can overlap adjacent memory blocks
|
||||||
while(count < size) {
|
while (count < size) {
|
||||||
MemoryRegion *mr = memory_mapping(uc, address);
|
MemoryRegion *mr = memory_mapping(uc, address);
|
||||||
if (mr) {
|
if (mr) {
|
||||||
uint32_t operms = mr->perms;
|
uint32_t operms = mr->perms;
|
||||||
if (!(operms & UC_PROT_WRITE)) {// write protected
|
if (!(operms & UC_PROT_WRITE)) { // write protected
|
||||||
// but this is not the program accessing memory, so temporarily mark writable
|
// but this is not the program accessing memory, so temporarily
|
||||||
|
// mark writable
|
||||||
uc->readonly_mem(mr, false);
|
uc->readonly_mem(mr, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
len = (size_t)MIN(size - count, mr->end - address);
|
len = (size_t)MIN(size - count, mr->end - address);
|
||||||
if (uc->write_mem(&uc->address_space_memory, address, bytes, len) == false) {
|
if (uc->write_mem(&uc->address_space_memory, address, bytes, len) ==
|
||||||
|
false) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(operms & UC_PROT_WRITE)) {// write protected
|
if (!(operms & UC_PROT_WRITE)) { // write protected
|
||||||
// now write protect it again
|
// now write protect it again
|
||||||
uc->readonly_mem(mr, true);
|
uc->readonly_mem(mr, true);
|
||||||
}
|
}
|
||||||
|
@ -547,7 +547,7 @@ uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *_bytes, size_t
|
||||||
count += len;
|
count += len;
|
||||||
address += len;
|
address += len;
|
||||||
bytes += len;
|
bytes += len;
|
||||||
} else {// this address is not mapped in yet
|
} else { // this address is not mapped in yet
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -571,7 +571,7 @@ static void *_timeout_fn(void *arg)
|
||||||
if (uc->emulation_done) {
|
if (uc->emulation_done) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} while((uint64_t)(get_clock() - current_time) < uc->timeout);
|
} while ((uint64_t)(get_clock() - current_time) < uc->timeout);
|
||||||
|
|
||||||
// timeout before emulation is done?
|
// timeout before emulation is done?
|
||||||
if (!uc->emulation_done) {
|
if (!uc->emulation_done) {
|
||||||
|
@ -586,11 +586,12 @@ static void *_timeout_fn(void *arg)
|
||||||
static void enable_emu_timer(uc_engine *uc, uint64_t timeout)
|
static void enable_emu_timer(uc_engine *uc, uint64_t timeout)
|
||||||
{
|
{
|
||||||
uc->timeout = timeout;
|
uc->timeout = timeout;
|
||||||
qemu_thread_create(uc, &uc->timer, "timeout", _timeout_fn,
|
qemu_thread_create(uc, &uc->timer, "timeout", _timeout_fn, uc,
|
||||||
uc, QEMU_THREAD_JOINABLE);
|
QEMU_THREAD_JOINABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void hook_count_cb(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data)
|
static void hook_count_cb(struct uc_struct *uc, uint64_t address, uint32_t size,
|
||||||
|
void *user_data)
|
||||||
{
|
{
|
||||||
// count this instruction. ah ah ah.
|
// count this instruction. ah ah ah.
|
||||||
uc->emu_counter++;
|
uc->emu_counter++;
|
||||||
|
@ -604,11 +605,12 @@ static void hook_count_cb(struct uc_struct *uc, uint64_t address, uint32_t size,
|
||||||
|
|
||||||
static void clear_deleted_hooks(uc_engine *uc)
|
static void clear_deleted_hooks(uc_engine *uc)
|
||||||
{
|
{
|
||||||
struct list_item * cur;
|
struct list_item *cur;
|
||||||
struct hook * hook;
|
struct hook *hook;
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for (cur = uc->hooks_to_del.head; cur != NULL && (hook = (struct hook *)cur->data); cur = cur->next) {
|
for (cur = uc->hooks_to_del.head;
|
||||||
|
cur != NULL && (hook = (struct hook *)cur->data); cur = cur->next) {
|
||||||
assert(hook->to_delete);
|
assert(hook->to_delete);
|
||||||
for (i = 0; i < UC_HOOK_MAX; i++) {
|
for (i = 0; i < UC_HOOK_MAX; i++) {
|
||||||
if (list_remove(&uc->hook[i], (void *)hook)) {
|
if (list_remove(&uc->hook[i], (void *)hook)) {
|
||||||
|
@ -626,7 +628,8 @@ static void clear_deleted_hooks(uc_engine *uc)
|
||||||
}
|
}
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count)
|
uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until,
|
||||||
|
uint64_t timeout, size_t count)
|
||||||
{
|
{
|
||||||
// reset the counter
|
// reset the counter
|
||||||
uc->emu_counter = 0;
|
uc->emu_counter = 0;
|
||||||
|
@ -636,7 +639,7 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time
|
||||||
uc->timed_out = false;
|
uc->timed_out = false;
|
||||||
uc->first_tb = true;
|
uc->first_tb = true;
|
||||||
|
|
||||||
switch(uc->arch) {
|
switch (uc->arch) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
#ifdef UNICORN_HAS_M68K
|
#ifdef UNICORN_HAS_M68K
|
||||||
|
@ -646,7 +649,7 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time
|
||||||
#endif
|
#endif
|
||||||
#ifdef UNICORN_HAS_X86
|
#ifdef UNICORN_HAS_X86
|
||||||
case UC_ARCH_X86:
|
case UC_ARCH_X86:
|
||||||
switch(uc->mode) {
|
switch (uc->mode) {
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
case UC_MODE_16: {
|
case UC_MODE_16: {
|
||||||
|
@ -655,7 +658,7 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time
|
||||||
|
|
||||||
uc_reg_read(uc, UC_X86_REG_CS, &cs);
|
uc_reg_read(uc, UC_X86_REG_CS, &cs);
|
||||||
// compensate for later adding up IP & CS
|
// compensate for later adding up IP & CS
|
||||||
ip = begin - cs*16;
|
ip = begin - cs * 16;
|
||||||
uc_reg_write(uc, UC_X86_REG_IP, &ip);
|
uc_reg_write(uc, UC_X86_REG_IP, &ip);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -717,7 +720,8 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time
|
||||||
// so instead of appending, we must insert the hook at the begin
|
// so instead of appending, we must insert the hook at the begin
|
||||||
// of the hook list
|
// of the hook list
|
||||||
uc->hook_insert = 1;
|
uc->hook_insert = 1;
|
||||||
err = uc_hook_add(uc, &uc->count_hook, UC_HOOK_CODE, hook_count_cb, NULL, 1, 0);
|
err = uc_hook_add(uc, &uc->count_hook, UC_HOOK_CODE, hook_count_cb,
|
||||||
|
NULL, 1, 0);
|
||||||
// restore to append mode for uc_hook_add()
|
// restore to append mode for uc_hook_add()
|
||||||
uc->hook_insert = 0;
|
uc->hook_insert = 0;
|
||||||
if (err != UC_ERR_OK) {
|
if (err != UC_ERR_OK) {
|
||||||
|
@ -747,7 +751,6 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time
|
||||||
return uc->invalid_error;
|
return uc->invalid_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_emu_stop(uc_engine *uc)
|
uc_err uc_emu_stop(uc_engine *uc)
|
||||||
{
|
{
|
||||||
|
@ -765,14 +768,16 @@ uc_err uc_emu_stop(uc_engine *uc)
|
||||||
return UC_ERR_OK;
|
return UC_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return target index where a memory region at the address exists, or could be inserted
|
// return target index where a memory region at the address exists, or could be
|
||||||
|
// inserted
|
||||||
//
|
//
|
||||||
// address either is inside the mapping at the returned index, or is in free space before
|
// address either is inside the mapping at the returned index, or is in free
|
||||||
// the next mapping.
|
// space before the next mapping.
|
||||||
//
|
//
|
||||||
// if there is overlap, between regions, ending address will be higher than the starting
|
// if there is overlap, between regions, ending address will be higher than the
|
||||||
// address of the mapping at returned index
|
// starting address of the mapping at returned index
|
||||||
static int bsearch_mapped_blocks(const uc_engine *uc, uint64_t address) {
|
static int bsearch_mapped_blocks(const uc_engine *uc, uint64_t address)
|
||||||
|
{
|
||||||
int left, right, mid;
|
int left, right, mid;
|
||||||
MemoryRegion *mapping;
|
MemoryRegion *mapping;
|
||||||
|
|
||||||
|
@ -817,7 +822,8 @@ static bool memory_overlap(struct uc_struct *uc, uint64_t begin, size_t size)
|
||||||
}
|
}
|
||||||
|
|
||||||
// common setup/error checking shared between uc_mem_map and uc_mem_map_ptr
|
// common setup/error checking shared between uc_mem_map and uc_mem_map_ptr
|
||||||
static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, MemoryRegion *block)
|
static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size,
|
||||||
|
uint32_t perms, MemoryRegion *block)
|
||||||
{
|
{
|
||||||
MemoryRegion **regions;
|
MemoryRegion **regions;
|
||||||
int pos;
|
int pos;
|
||||||
|
@ -826,9 +832,10 @@ static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t per
|
||||||
return UC_ERR_NOMEM;
|
return UC_ERR_NOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((uc->mapped_block_count & (MEM_BLOCK_INCR - 1)) == 0) { //time to grow
|
if ((uc->mapped_block_count & (MEM_BLOCK_INCR - 1)) == 0) { // time to grow
|
||||||
regions = (MemoryRegion**)g_realloc(uc->mapped_blocks,
|
regions = (MemoryRegion **)g_realloc(
|
||||||
sizeof(MemoryRegion*) * (uc->mapped_block_count + MEM_BLOCK_INCR));
|
uc->mapped_blocks,
|
||||||
|
sizeof(MemoryRegion *) * (uc->mapped_block_count + MEM_BLOCK_INCR));
|
||||||
if (regions == NULL) {
|
if (regions == NULL) {
|
||||||
return UC_ERR_NOMEM;
|
return UC_ERR_NOMEM;
|
||||||
}
|
}
|
||||||
|
@ -838,7 +845,8 @@ static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t per
|
||||||
pos = bsearch_mapped_blocks(uc, block->addr);
|
pos = bsearch_mapped_blocks(uc, block->addr);
|
||||||
|
|
||||||
// shift the array right to give space for the new pointer
|
// shift the array right to give space for the new pointer
|
||||||
memmove(&uc->mapped_blocks[pos + 1], &uc->mapped_blocks[pos], sizeof(MemoryRegion*) * (uc->mapped_block_count - pos));
|
memmove(&uc->mapped_blocks[pos + 1], &uc->mapped_blocks[pos],
|
||||||
|
sizeof(MemoryRegion *) * (uc->mapped_block_count - pos));
|
||||||
|
|
||||||
uc->mapped_blocks[pos] = block;
|
uc->mapped_blocks[pos] = block;
|
||||||
uc->mapped_block_count++;
|
uc->mapped_block_count++;
|
||||||
|
@ -846,7 +854,8 @@ static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t per
|
||||||
return UC_ERR_OK;
|
return UC_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uc_err mem_map_check(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
|
static uc_err mem_map_check(uc_engine *uc, uint64_t address, size_t size,
|
||||||
|
uint32_t perms)
|
||||||
{
|
{
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
// invalid memory mapping
|
// invalid memory mapping
|
||||||
|
@ -895,11 +904,13 @@ uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mem_map(uc, address, size, perms, uc->memory_map(uc, address, size, perms));
|
return mem_map(uc, address, size, perms,
|
||||||
|
uc->memory_map(uc, address, size, perms));
|
||||||
}
|
}
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr)
|
uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size,
|
||||||
|
uint32_t perms, void *ptr)
|
||||||
{
|
{
|
||||||
uc_err res;
|
uc_err res;
|
||||||
|
|
||||||
|
@ -916,7 +927,8 @@ uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t per
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mem_map(uc, address, size, UC_PROT_ALL, uc->memory_map_ptr(uc, address, size, perms, ptr));
|
return mem_map(uc, address, size, UC_PROT_ALL,
|
||||||
|
uc->memory_map_ptr(uc, address, size, perms, ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
|
@ -937,7 +949,8 @@ uc_err uc_mmio_map(uc_engine *uc, uint64_t address, size_t size,
|
||||||
// The callbacks do not need to be checked for NULL here, as their presence
|
// The callbacks do not need to be checked for NULL here, as their presence
|
||||||
// (or lack thereof) will determine the permissions used.
|
// (or lack thereof) will determine the permissions used.
|
||||||
return mem_map(uc, address, size, UC_PROT_NONE,
|
return mem_map(uc, address, size, UC_PROT_NONE,
|
||||||
uc->memory_map_io(uc, address, size, read_cb, write_cb, user_data_read, user_data_write));
|
uc->memory_map_io(uc, address, size, read_cb, write_cb,
|
||||||
|
user_data_read, user_data_write));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a backup copy of the indicated MemoryRegion.
|
// Create a backup copy of the indicated MemoryRegion.
|
||||||
|
@ -946,7 +959,8 @@ static uint8_t *copy_region(struct uc_struct *uc, MemoryRegion *mr)
|
||||||
{
|
{
|
||||||
uint8_t *block = (uint8_t *)g_malloc0((size_t)int128_get64(mr->size));
|
uint8_t *block = (uint8_t *)g_malloc0((size_t)int128_get64(mr->size));
|
||||||
if (block != NULL) {
|
if (block != NULL) {
|
||||||
uc_err err = uc_mem_read(uc, mr->addr, block, (size_t)int128_get64(mr->size));
|
uc_err err =
|
||||||
|
uc_mem_read(uc, mr->addr, block, (size_t)int128_get64(mr->size));
|
||||||
if (err != UC_ERR_OK) {
|
if (err != UC_ERR_OK) {
|
||||||
free(block);
|
free(block);
|
||||||
block = NULL;
|
block = NULL;
|
||||||
|
@ -971,8 +985,8 @@ static uint8_t *copy_region(struct uc_struct *uc, MemoryRegion *mr)
|
||||||
*/
|
*/
|
||||||
// TODO: investigate whether qemu region manipulation functions already offered
|
// TODO: investigate whether qemu region manipulation functions already offered
|
||||||
// this capability
|
// this capability
|
||||||
static bool split_region(struct uc_struct *uc, MemoryRegion *mr, uint64_t address,
|
static bool split_region(struct uc_struct *uc, MemoryRegion *mr,
|
||||||
size_t size, bool do_delete)
|
uint64_t address, size_t size, bool do_delete)
|
||||||
{
|
{
|
||||||
uint8_t *backup;
|
uint8_t *backup;
|
||||||
uint32_t perms;
|
uint32_t perms;
|
||||||
|
@ -999,8 +1013,10 @@ static bool split_region(struct uc_struct *uc, MemoryRegion *mr, uint64_t addres
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
QLIST_FOREACH(block, &uc->ram_list.blocks, next) {
|
QLIST_FOREACH(block, &uc->ram_list.blocks, next)
|
||||||
if (block->offset <= mr->addr && block->used_length >= (mr->end - mr->addr)) {
|
{
|
||||||
|
if (block->offset <= mr->addr &&
|
||||||
|
block->used_length >= (mr->end - mr->addr)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1022,13 +1038,15 @@ static bool split_region(struct uc_struct *uc, MemoryRegion *mr, uint64_t addres
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// save the essential information required for the split before mr gets deleted
|
// save the essential information required for the split before mr gets
|
||||||
|
// deleted
|
||||||
perms = mr->perms;
|
perms = mr->perms;
|
||||||
begin = mr->addr;
|
begin = mr->addr;
|
||||||
end = mr->end;
|
end = mr->end;
|
||||||
|
|
||||||
// unmap this region first, then do split it later
|
// unmap this region first, then do split it later
|
||||||
if (uc_mem_unmap(uc, mr->addr, (size_t)int128_get64(mr->size)) != UC_ERR_OK) {
|
if (uc_mem_unmap(uc, mr->addr, (size_t)int128_get64(mr->size)) !=
|
||||||
|
UC_ERR_OK) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1052,10 +1070,10 @@ static bool split_region(struct uc_struct *uc, MemoryRegion *mr, uint64_t addres
|
||||||
r_size = (size_t)(end - chunk_end);
|
r_size = (size_t)(end - chunk_end);
|
||||||
m_size = (size_t)(chunk_end - address);
|
m_size = (size_t)(chunk_end - address);
|
||||||
|
|
||||||
// If there are error in any of the below operations, things are too far gone
|
// If there are error in any of the below operations, things are too far
|
||||||
// at that point to recover. Could try to remap orignal region, but these smaller
|
// gone at that point to recover. Could try to remap orignal region, but
|
||||||
// allocation just failed so no guarantee that we can recover the original
|
// these smaller allocation just failed so no guarantee that we can recover
|
||||||
// allocation at this point
|
// the original allocation at this point
|
||||||
if (l_size > 0) {
|
if (l_size > 0) {
|
||||||
if (!prealloc) {
|
if (!prealloc) {
|
||||||
if (uc_mem_map(uc, begin, l_size, perms) != UC_ERR_OK) {
|
if (uc_mem_map(uc, begin, l_size, perms) != UC_ERR_OK) {
|
||||||
|
@ -1076,11 +1094,13 @@ static bool split_region(struct uc_struct *uc, MemoryRegion *mr, uint64_t addres
|
||||||
if (uc_mem_map(uc, address, m_size, perms) != UC_ERR_OK) {
|
if (uc_mem_map(uc, address, m_size, perms) != UC_ERR_OK) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (uc_mem_write(uc, address, backup + l_size, m_size) != UC_ERR_OK) {
|
if (uc_mem_write(uc, address, backup + l_size, m_size) !=
|
||||||
|
UC_ERR_OK) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (uc_mem_map_ptr(uc, address, m_size, perms, backup + l_size) != UC_ERR_OK) {
|
if (uc_mem_map_ptr(uc, address, m_size, perms, backup + l_size) !=
|
||||||
|
UC_ERR_OK) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1091,11 +1111,13 @@ static bool split_region(struct uc_struct *uc, MemoryRegion *mr, uint64_t addres
|
||||||
if (uc_mem_map(uc, chunk_end, r_size, perms) != UC_ERR_OK) {
|
if (uc_mem_map(uc, chunk_end, r_size, perms) != UC_ERR_OK) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
if (uc_mem_write(uc, chunk_end, backup + l_size + m_size, r_size) != UC_ERR_OK) {
|
if (uc_mem_write(uc, chunk_end, backup + l_size + m_size, r_size) !=
|
||||||
|
UC_ERR_OK) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (uc_mem_map_ptr(uc, chunk_end, r_size, perms, backup + l_size + m_size) != UC_ERR_OK) {
|
if (uc_mem_map_ptr(uc, chunk_end, r_size, perms,
|
||||||
|
backup + l_size + m_size) != UC_ERR_OK) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1114,7 +1136,8 @@ error:
|
||||||
}
|
}
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, uint32_t perms)
|
uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size,
|
||||||
|
uint32_t perms)
|
||||||
{
|
{
|
||||||
MemoryRegion *mr;
|
MemoryRegion *mr;
|
||||||
uint64_t addr = address;
|
uint64_t addr = address;
|
||||||
|
@ -1154,7 +1177,7 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, uint3
|
||||||
// We may need to split regions if this area spans adjacent regions
|
// We may need to split regions if this area spans adjacent regions
|
||||||
addr = address;
|
addr = address;
|
||||||
count = 0;
|
count = 0;
|
||||||
while(count < size) {
|
while (count < size) {
|
||||||
mr = memory_mapping(uc, addr);
|
mr = memory_mapping(uc, addr);
|
||||||
len = (size_t)MIN(size - count, mr->end - addr);
|
len = (size_t)MIN(size - count, mr->end - addr);
|
||||||
if (!split_region(uc, mr, addr, len, false)) {
|
if (!split_region(uc, mr, addr, len, false)) {
|
||||||
|
@ -1163,7 +1186,8 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, uint3
|
||||||
|
|
||||||
mr = memory_mapping(uc, addr);
|
mr = memory_mapping(uc, addr);
|
||||||
// will this remove EXEC permission?
|
// will this remove EXEC permission?
|
||||||
if (((mr->perms & UC_PROT_EXEC) != 0) && ((perms & UC_PROT_EXEC) == 0)) {
|
if (((mr->perms & UC_PROT_EXEC) != 0) &&
|
||||||
|
((perms & UC_PROT_EXEC) == 0)) {
|
||||||
remove_exec = true;
|
remove_exec = true;
|
||||||
}
|
}
|
||||||
mr->perms = perms;
|
mr->perms = perms;
|
||||||
|
@ -1173,7 +1197,8 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, uint3
|
||||||
addr += len;
|
addr += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if EXEC permission is removed, then quit TB and continue at the same place
|
// if EXEC permission is removed, then quit TB and continue at the same
|
||||||
|
// place
|
||||||
if (remove_exec) {
|
if (remove_exec) {
|
||||||
uc->quit_request = true;
|
uc->quit_request = true;
|
||||||
uc_emu_stop(uc);
|
uc_emu_stop(uc);
|
||||||
|
@ -1217,7 +1242,7 @@ uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size)
|
||||||
// We may need to split regions if this area spans adjacent regions
|
// We may need to split regions if this area spans adjacent regions
|
||||||
addr = address;
|
addr = address;
|
||||||
count = 0;
|
count = 0;
|
||||||
while(count < size) {
|
while (count < size) {
|
||||||
mr = memory_mapping(uc, addr);
|
mr = memory_mapping(uc, addr);
|
||||||
len = (size_t)MIN(size - count, mr->end - addr);
|
len = (size_t)MIN(size - count, mr->end - addr);
|
||||||
if (!split_region(uc, mr, addr, len, true)) {
|
if (!split_region(uc, mr, addr, len, true)) {
|
||||||
|
@ -1238,7 +1263,7 @@ uc_err uc_mem_unmap(struct uc_struct *uc, uint64_t address, size_t size)
|
||||||
}
|
}
|
||||||
|
|
||||||
// find the memory region of this address
|
// find the memory region of this address
|
||||||
MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address)
|
MemoryRegion *memory_mapping(struct uc_struct *uc, uint64_t address)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i;
|
||||||
|
|
||||||
|
@ -1253,13 +1278,15 @@ MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address)
|
||||||
// try with the cache index first
|
// try with the cache index first
|
||||||
i = uc->mapped_block_cache_index;
|
i = uc->mapped_block_cache_index;
|
||||||
|
|
||||||
if (i < uc->mapped_block_count && address >= uc->mapped_blocks[i]->addr && address < uc->mapped_blocks[i]->end) {
|
if (i < uc->mapped_block_count && address >= uc->mapped_blocks[i]->addr &&
|
||||||
|
address < uc->mapped_blocks[i]->end) {
|
||||||
return uc->mapped_blocks[i];
|
return uc->mapped_blocks[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
i = bsearch_mapped_blocks(uc, address);
|
i = bsearch_mapped_blocks(uc, address);
|
||||||
|
|
||||||
if (i < uc->mapped_block_count && address >= uc->mapped_blocks[i]->addr && address <= uc->mapped_blocks[i]->end - 1)
|
if (i < uc->mapped_block_count && address >= uc->mapped_blocks[i]->addr &&
|
||||||
|
address <= uc->mapped_blocks[i]->end - 1)
|
||||||
return uc->mapped_blocks[i];
|
return uc->mapped_blocks[i];
|
||||||
|
|
||||||
// not found
|
// not found
|
||||||
|
@ -1296,7 +1323,7 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
|
||||||
va_end(valist);
|
va_end(valist);
|
||||||
|
|
||||||
if (uc->insn_hook_validate) {
|
if (uc->insn_hook_validate) {
|
||||||
if (! uc->insn_hook_validate(hook->insn)) {
|
if (!uc->insn_hook_validate(hook->insn)) {
|
||||||
free(hook);
|
free(hook);
|
||||||
return UC_ERR_HOOK;
|
return UC_ERR_HOOK;
|
||||||
}
|
}
|
||||||
|
@ -1352,7 +1379,6 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_hook_del(uc_engine *uc, uc_hook hh)
|
uc_err uc_hook_del(uc_engine *uc, uc_hook hh)
|
||||||
{
|
{
|
||||||
|
@ -1365,7 +1391,7 @@ uc_err uc_hook_del(uc_engine *uc, uc_hook hh)
|
||||||
// an optimization would be to align the hook pointer
|
// an optimization would be to align the hook pointer
|
||||||
// and store the type mask in the hook pointer.
|
// and store the type mask in the hook pointer.
|
||||||
for (i = 0; i < UC_HOOK_MAX; i++) {
|
for (i = 0; i < UC_HOOK_MAX; i++) {
|
||||||
if (list_exists(&uc->hook[i], (void *) hook)) {
|
if (list_exists(&uc->hook[i], (void *)hook)) {
|
||||||
hook->to_delete = true;
|
hook->to_delete = true;
|
||||||
list_append(&uc->hooks_to_del, hook);
|
list_append(&uc->hooks_to_del, hook);
|
||||||
}
|
}
|
||||||
|
@ -1375,13 +1401,18 @@ uc_err uc_hook_del(uc_engine *uc, uc_hook hh)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TCG helper
|
// TCG helper
|
||||||
void helper_uc_tracecode(int32_t size, uc_hook_idx index, void *handle, int64_t address);
|
void helper_uc_tracecode(int32_t size, uc_hook_idx index, void *handle,
|
||||||
void helper_uc_tracecode(int32_t size, uc_hook_idx index, void *handle, int64_t address)
|
int64_t address);
|
||||||
|
void helper_uc_tracecode(int32_t size, uc_hook_idx index, void *handle,
|
||||||
|
int64_t address)
|
||||||
{
|
{
|
||||||
struct uc_struct *uc = handle;
|
struct uc_struct *uc = handle;
|
||||||
struct list_item *cur;
|
struct list_item *cur;
|
||||||
struct hook *hook;
|
struct hook *hook;
|
||||||
int hook_flags = index & UC_HOOK_FLAG_MASK; // The index here may contain additional flags. See the comments of uc_hook_idx for details.
|
int hook_flags =
|
||||||
|
index &
|
||||||
|
UC_HOOK_FLAG_MASK; // The index here may contain additional flags. See
|
||||||
|
// the comments of uc_hook_idx for details.
|
||||||
|
|
||||||
index = index & UC_HOOK_IDX_MASK;
|
index = index & UC_HOOK_IDX_MASK;
|
||||||
|
|
||||||
|
@ -1395,30 +1426,35 @@ void helper_uc_tracecode(int32_t size, uc_hook_idx index, void *handle, int64_t
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (cur = uc->hook[index].head; cur != NULL && (hook = (struct hook *)cur->data); cur = cur->next) {
|
for (cur = uc->hook[index].head;
|
||||||
|
cur != NULL && (hook = (struct hook *)cur->data); cur = cur->next) {
|
||||||
if (hook->to_delete) {
|
if (hook->to_delete) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// on invalid block/instruction, call instruction counter (if enable), then quit
|
// on invalid block/instruction, call instruction counter (if enable),
|
||||||
|
// then quit
|
||||||
if (size == 0) {
|
if (size == 0) {
|
||||||
if (index == UC_HOOK_CODE_IDX && uc->count_hook) {
|
if (index == UC_HOOK_CODE_IDX && uc->count_hook) {
|
||||||
// this is the instruction counter (first hook in the list)
|
// this is the instruction counter (first hook in the list)
|
||||||
((uc_cb_hookcode_t)hook->callback)(uc, address, size, hook->user_data);
|
((uc_cb_hookcode_t)hook->callback)(uc, address, size,
|
||||||
|
hook->user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (HOOK_BOUND_CHECK(hook, (uint64_t)address)) {
|
if (HOOK_BOUND_CHECK(hook, (uint64_t)address)) {
|
||||||
((uc_cb_hookcode_t)hook->callback)(uc, address, size, hook->user_data);
|
((uc_cb_hookcode_t)hook->callback)(uc, address, size,
|
||||||
|
hook->user_data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// the last callback may already asked to stop emulation
|
// the last callback may already asked to stop emulation
|
||||||
// Unicorn:
|
// Unicorn:
|
||||||
// In an ARM IT block, we behave like the emulation continues normally. No check_exit_request
|
// In an ARM IT block, we behave like the emulation continues
|
||||||
// is generated and the hooks are triggered normally. In other words, the whole IT block is
|
// normally. No check_exit_request is generated and the hooks are
|
||||||
// treated as a single instruction.
|
// triggered normally. In other words, the whole IT block is treated
|
||||||
|
// as a single instruction.
|
||||||
if (uc->stop_request && !(hook_flags & UC_HOOK_FLAG_NO_STOP)) {
|
if (uc->stop_request && !(hook_flags & UC_HOOK_FLAG_NO_STOP)) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1455,7 +1491,7 @@ uc_err uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count)
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result)
|
uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result)
|
||||||
{
|
{
|
||||||
switch(type) {
|
switch (type) {
|
||||||
default:
|
default:
|
||||||
return UC_ERR_ARG;
|
return UC_ERR_ARG;
|
||||||
|
|
||||||
|
@ -1517,20 +1553,20 @@ UNICORN_EXPORT
|
||||||
size_t uc_context_size(uc_engine *uc)
|
size_t uc_context_size(uc_engine *uc)
|
||||||
{
|
{
|
||||||
// return the total size of struct uc_context
|
// return the total size of struct uc_context
|
||||||
return sizeof(uc_context) + uc->cpu_context_size + sizeof(*uc->cpu->jmp_env);
|
return sizeof(uc_context) + uc->cpu_context_size +
|
||||||
|
sizeof(*uc->cpu->jmp_env);
|
||||||
}
|
}
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_context_save(uc_engine *uc, uc_context *context)
|
uc_err uc_context_save(uc_engine *uc, uc_context *context)
|
||||||
{
|
{
|
||||||
memcpy(context->data, uc->cpu->env_ptr, context->context_size);
|
memcpy(context->data, uc->cpu->env_ptr, context->context_size);
|
||||||
memcpy(context->data + context->context_size, uc->cpu->jmp_env, context->jmp_env_size);
|
memcpy(context->data + context->context_size, uc->cpu->jmp_env,
|
||||||
|
context->jmp_env_size);
|
||||||
|
|
||||||
return UC_ERR_OK;
|
return UC_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_context_reg_write(uc_context *ctx, int regid, const void *value)
|
uc_err uc_context_reg_write(uc_context *ctx, int regid, const void *value)
|
||||||
{
|
{
|
||||||
|
@ -1544,10 +1580,11 @@ uc_err uc_context_reg_read(uc_context *ctx, int regid, void *value)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keep in mind that we don't a uc_engine when r/w the registers of a context.
|
// Keep in mind that we don't a uc_engine when r/w the registers of a context.
|
||||||
static void find_context_reg_rw_function(uc_arch arch, uc_mode mode, context_reg_rw_t *rw)
|
static void find_context_reg_rw_function(uc_arch arch, uc_mode mode,
|
||||||
|
context_reg_rw_t *rw)
|
||||||
{
|
{
|
||||||
// We believe that the arch/mode pair is correct.
|
// We believe that the arch/mode pair is correct.
|
||||||
switch(arch) {
|
switch (arch) {
|
||||||
default:
|
default:
|
||||||
rw->context_reg_read = NULL;
|
rw->context_reg_read = NULL;
|
||||||
rw->context_reg_write = NULL;
|
rw->context_reg_write = NULL;
|
||||||
|
@ -1586,7 +1623,8 @@ static void find_context_reg_rw_function(uc_arch arch, uc_mode mode, context_reg
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(UNICORN_HAS_MIPS) || defined(UNICORN_HAS_MIPSEL) || defined(UNICORN_HAS_MIPS64) || defined(UNICORN_HAS_MIPS64EL)
|
#if defined(UNICORN_HAS_MIPS) || defined(UNICORN_HAS_MIPSEL) || \
|
||||||
|
defined(UNICORN_HAS_MIPS64) || defined(UNICORN_HAS_MIPS64EL)
|
||||||
case UC_ARCH_MIPS:
|
case UC_ARCH_MIPS:
|
||||||
if (mode & UC_MODE_BIG_ENDIAN) {
|
if (mode & UC_MODE_BIG_ENDIAN) {
|
||||||
#ifdef UNICORN_HAS_MIPS
|
#ifdef UNICORN_HAS_MIPS
|
||||||
|
@ -1657,7 +1695,8 @@ static void find_context_reg_rw_function(uc_arch arch, uc_mode mode, context_reg
|
||||||
}
|
}
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_context_reg_write_batch(uc_context *ctx, int *ids, void *const *vals, int count)
|
uc_err uc_context_reg_write_batch(uc_context *ctx, int *ids, void *const *vals,
|
||||||
|
int count)
|
||||||
{
|
{
|
||||||
int ret = UC_ERR_OK;
|
int ret = UC_ERR_OK;
|
||||||
context_reg_rw_t rw;
|
context_reg_rw_t rw;
|
||||||
|
@ -1673,7 +1712,8 @@ uc_err uc_context_reg_write_batch(uc_context *ctx, int *ids, void *const *vals,
|
||||||
}
|
}
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_context_reg_read_batch(uc_context *ctx, int *ids, void **vals, int count)
|
uc_err uc_context_reg_read_batch(uc_context *ctx, int *ids, void **vals,
|
||||||
|
int count)
|
||||||
{
|
{
|
||||||
int ret = UC_ERR_OK;
|
int ret = UC_ERR_OK;
|
||||||
context_reg_rw_t rw;
|
context_reg_rw_t rw;
|
||||||
|
@ -1693,7 +1733,8 @@ uc_err uc_context_restore(uc_engine *uc, uc_context *context)
|
||||||
{
|
{
|
||||||
memcpy(uc->cpu->env_ptr, context->data, context->context_size);
|
memcpy(uc->cpu->env_ptr, context->data, context->context_size);
|
||||||
if (list_exists(&uc->saved_contexts, context)) {
|
if (list_exists(&uc->saved_contexts, context)) {
|
||||||
memcpy(uc->cpu->jmp_env, context->data + context->context_size, context->jmp_env_size);
|
memcpy(uc->cpu->jmp_env, context->data + context->context_size,
|
||||||
|
context->jmp_env_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return UC_ERR_OK;
|
return UC_ERR_OK;
|
||||||
|
@ -1702,7 +1743,7 @@ uc_err uc_context_restore(uc_engine *uc, uc_context *context)
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_context_free(uc_context *context)
|
uc_err uc_context_free(uc_context *context)
|
||||||
{
|
{
|
||||||
uc_engine* uc = context->uc;
|
uc_engine *uc = context->uc;
|
||||||
// if uc is NULL, it means that uc_engine has been free-ed.
|
// if uc is NULL, it means that uc_engine has been free-ed.
|
||||||
if (uc) {
|
if (uc) {
|
||||||
list_remove(&uc->saved_contexts, context);
|
list_remove(&uc->saved_contexts, context);
|
||||||
|
|
Loading…
Reference in New Issue