Add clang-format and format code to qemu code style
This commit is contained in:
parent
9e1443013b
commit
e62b0ef255
16
.clang-format
Normal file
16
.clang-format
Normal file
@ -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
|
@ -2,7 +2,6 @@
|
||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
||||
/* Modified for Unicorn Engine by Chen Huitao<chenhuitao@hfmrit.com>, 2020 */
|
||||
|
||||
|
||||
#ifndef UC_PRIV_H
|
||||
#define UC_PRIV_H
|
||||
|
||||
@ -15,16 +14,22 @@
|
||||
|
||||
// These are masks of supported modes for each cpu/arch.
|
||||
// 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 \
|
||||
|UC_MODE_ARM926|UC_MODE_ARM946|UC_MODE_ARM1176|UC_MODE_BIG_ENDIAN)
|
||||
#define UC_MODE_MIPS_MASK (UC_MODE_MIPS32|UC_MODE_MIPS64|UC_MODE_LITTLE_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_RISCV_MASK (UC_MODE_RISCV32|UC_MODE_RISCV64|UC_MODE_LITTLE_ENDIAN)
|
||||
#define UC_MODE_ARM_MASK \
|
||||
(UC_MODE_ARM | UC_MODE_THUMB | UC_MODE_LITTLE_ENDIAN | UC_MODE_MCLASS | \
|
||||
UC_MODE_ARM926 | UC_MODE_ARM946 | UC_MODE_ARM1176 | UC_MODE_BIG_ENDIAN)
|
||||
#define UC_MODE_MIPS_MASK \
|
||||
(UC_MODE_MIPS32 | UC_MODE_MIPS64 | UC_MODE_LITTLE_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_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_DWORD(x) (x & 0xffffffff)
|
||||
@ -36,15 +41,19 @@
|
||||
#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8))
|
||||
#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff))
|
||||
|
||||
|
||||
typedef uc_err (*query_t)(struct uc_struct *uc, uc_query_type type, size_t *result);
|
||||
typedef uc_err (*query_t)(struct uc_struct *uc, uc_query_type type,
|
||||
size_t *result);
|
||||
|
||||
// return 0 on success, -1 on failure
|
||||
typedef int (*reg_read_t)(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
||||
typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
||||
typedef int (*reg_read_t)(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||
int count);
|
||||
typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int *regs,
|
||||
void *const *vals, int count);
|
||||
|
||||
typedef int (*context_reg_read_t)(struct uc_context *ctx, unsigned int *regs, void **vals, int count);
|
||||
typedef int (*context_reg_write_t)(struct uc_context *ctx, 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_write_t)(struct uc_context *ctx, unsigned int *regs,
|
||||
void *const *vals, int count);
|
||||
typedef struct {
|
||||
context_reg_read_t context_reg_read;
|
||||
context_reg_write_t context_reg_write;
|
||||
@ -52,30 +61,40 @@ typedef struct {
|
||||
|
||||
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_int_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_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 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 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?
|
||||
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);
|
||||
|
||||
// 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
|
||||
typedef void (*uc_target_page_init)(struct uc_struct *);
|
||||
@ -96,11 +115,13 @@ typedef void (*uc_softfloat_initialize)(void);
|
||||
typedef void (*uc_tcg_flush_tlb)(struct uc_struct *uc);
|
||||
|
||||
struct hook {
|
||||
int type; // UC_HOOK_*
|
||||
int insn; // instruction for HOOK_INSN
|
||||
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.
|
||||
uint64_t begin, end; // only trigger if PC or memory access is in this address (depends on hook type)
|
||||
int type; // UC_HOOK_*
|
||||
int insn; // instruction for HOOK_INSN
|
||||
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.
|
||||
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 *user_data;
|
||||
};
|
||||
@ -132,31 +153,31 @@ typedef enum uc_hook_idx {
|
||||
} uc_hook_idx;
|
||||
|
||||
// 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
|
||||
#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.
|
||||
#define UC_HOOK_FLAG_MASK (~(UC_HOOK_IDX_MASK))
|
||||
|
||||
#define HOOK_FOREACH_VAR_DECLARE \
|
||||
struct list_item *cur
|
||||
#define HOOK_FOREACH_VAR_DECLARE struct list_item *cur
|
||||
|
||||
// for loop macro to loop over hook lists
|
||||
#define HOOK_FOREACH(uc, hh, idx) \
|
||||
for ( \
|
||||
cur = (uc)->hook[idx##_IDX].head; \
|
||||
cur != NULL && ((hh) = (struct hook *)cur->data); \
|
||||
cur = cur->next)
|
||||
#define HOOK_FOREACH(uc, hh, idx) \
|
||||
for (cur = (uc)->hook[idx##_IDX].head; \
|
||||
cur != NULL && ((hh) = (struct hook *)cur->data); cur = cur->next)
|
||||
|
||||
// if statement to check hook bounds
|
||||
#define HOOK_BOUND_CHECK(hh, addr) \
|
||||
((((addr) >= (hh)->begin && (addr) <= (hh)->end) \
|
||||
|| (hh)->begin > (hh)->end) && !((hh)->to_delete))
|
||||
#define HOOK_BOUND_CHECK(hh, addr) \
|
||||
((((addr) >= (hh)->begin && (addr) <= (hh)->end) || \
|
||||
(hh)->begin > (hh)->end) && \
|
||||
!((hh)->to_delete))
|
||||
|
||||
#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)
|
||||
{
|
||||
@ -168,7 +189,7 @@ static inline bool _hook_exists_bounded(struct list_item *cur, uint64_t addr)
|
||||
return false;
|
||||
}
|
||||
|
||||
//relloc increment, KEEP THIS A POWER OF 2!
|
||||
// relloc increment, KEEP THIS A POWER OF 2!
|
||||
#define MEM_BLOCK_INCR 32
|
||||
|
||||
typedef struct TargetPageBits TargetPageBits;
|
||||
@ -177,7 +198,7 @@ typedef struct TCGContext TCGContext;
|
||||
struct uc_struct {
|
||||
uc_arch arch;
|
||||
uc_mode mode;
|
||||
uc_err errnum; // qemu/cpu-exec.c
|
||||
uc_err errnum; // qemu/cpu-exec.c
|
||||
AddressSpace address_space_memory;
|
||||
AddressSpace address_space_io;
|
||||
query_t query;
|
||||
@ -187,9 +208,10 @@ struct uc_struct {
|
||||
|
||||
uc_write_mem_t write_mem;
|
||||
uc_read_mem_t read_mem;
|
||||
uc_args_void_t release; // release resource when uc_close()
|
||||
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_void_t release; // release resource when uc_close()
|
||||
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_memory_map_io_t memory_map_io;
|
||||
|
||||
uc_args_uc_t init_arch, cpu_exec_init_all;
|
||||
@ -212,21 +234,21 @@ struct uc_struct {
|
||||
uc_insn_hook_validate insn_hook_validate;
|
||||
|
||||
MemoryRegion *system_memory; // qemu/exec.c
|
||||
MemoryRegion *system_io; // qemu/exec.c
|
||||
MemoryRegion *system_io; // qemu/exec.c
|
||||
MemoryRegion io_mem_unassigned; // qemu/exec.c
|
||||
RAMList ram_list; // qemu/exec.c
|
||||
RAMList ram_list; // qemu/exec.c
|
||||
/* qemu/exec.c */
|
||||
unsigned int alloc_hint;
|
||||
/* qemu/exec-vary.c */
|
||||
TargetPageBits *init_target_page;
|
||||
BounceBuffer bounce; // qemu/cpu-exec.c
|
||||
BounceBuffer bounce; // qemu/cpu-exec.c
|
||||
volatile sig_atomic_t exit_request; // qemu/cpu-exec.c
|
||||
/* qemu/accel/tcg/cpu-exec-common.c */
|
||||
/* always be true after call tcg_exec_init(). */
|
||||
bool tcg_allowed;
|
||||
/* This is a multi-level map on the virtual address space.
|
||||
The bottom level has pointers to PageDesc. */
|
||||
void **l1_map; // qemu/accel/tcg/translate-all.c
|
||||
void **l1_map; // qemu/accel/tcg/translate-all.c
|
||||
size_t l1_map_size;
|
||||
/* qemu/accel/tcg/translate-all.c */
|
||||
int v_l1_size;
|
||||
@ -248,28 +270,33 @@ struct uc_struct {
|
||||
uc_hook count_hook;
|
||||
|
||||
size_t emu_counter; // current counter of uc_emu_start()
|
||||
size_t emu_count; // save counter of uc_emu_start()
|
||||
size_t emu_count; // save counter of uc_emu_start()
|
||||
|
||||
int size_recur_mem; // size for mem access when in a recursive call
|
||||
|
||||
bool init_tcg; // already initialized local TCGv variables?
|
||||
bool stop_request; // request to immediately stop emulation - for 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 timed_out; // emulation timed out, that can retrieve via uc_query(UC_QUERY_TIMEOUT)
|
||||
QemuThread timer; // timer for emulation timeout
|
||||
uint64_t timeout; // timeout for uc_emu_start()
|
||||
bool init_tcg; // already initialized local TCGv variables?
|
||||
bool stop_request; // request to immediately stop emulation - for
|
||||
// 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 timed_out; // emulation timed out, that can retrieve via
|
||||
// uc_query(UC_QUERY_TIMEOUT)
|
||||
QemuThread timer; // timer for emulation timeout
|
||||
uint64_t timeout; // timeout for uc_emu_start()
|
||||
|
||||
uint64_t invalid_addr; // invalid address to be accessed
|
||||
int invalid_error; // invalid memory code: 1 = READ, 2 = WRITE, 3 = CODE
|
||||
uint64_t invalid_addr; // invalid address to be accessed
|
||||
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;
|
||||
uint32_t mapped_block_count;
|
||||
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_align;
|
||||
uint64_t qemu_host_page_size;
|
||||
@ -277,26 +304,29 @@ struct uc_struct {
|
||||
int qemu_icache_linesize;
|
||||
/* ARCH_REGS_STORAGE_SIZE */
|
||||
int cpu_context_size;
|
||||
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 first_tb; // is this the first Translation-Block ever generated since uc_emu_start()?
|
||||
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 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.
|
||||
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_*()
|
||||
// We also save cpu->jmp_env, so emulation can be reentrant
|
||||
struct uc_context {
|
||||
size_t context_size; // size of the real internal context structure
|
||||
size_t jmp_env_size; // size of cpu->jmp_env
|
||||
uc_mode mode; // the mode of this context (uc may be free-ed already)
|
||||
uc_arch arch; // the arch of this context (uc may be free-ed already)
|
||||
struct uc_struct *uc; // the uc_struct which creates this context
|
||||
char data[0]; // context + cpu->jmp_env
|
||||
size_t context_size; // size of the real internal context structure
|
||||
size_t jmp_env_size; // size of cpu->jmp_env
|
||||
uc_mode mode; // the mode of this context (uc may be free-ed already)
|
||||
uc_arch arch; // the arch of this context (uc may be free-ed already)
|
||||
struct uc_struct *uc; // the uc_struct which creates this context
|
||||
char data[0]; // context + cpu->jmp_env
|
||||
};
|
||||
|
||||
// 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
|
||||
/* vim: set ts=4 noet: */
|
||||
|
@ -12,7 +12,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4201)
|
||||
#pragma warning(disable : 4201)
|
||||
#endif
|
||||
|
||||
//> ARM registers
|
||||
@ -158,7 +158,7 @@ typedef enum uc_arm_reg {
|
||||
UC_ARM_REG_XPSR_NZCVQ,
|
||||
UC_ARM_REG_XPSR_G,
|
||||
UC_ARM_REG_XPSR_NZCVQG,
|
||||
UC_ARM_REG_ENDING, // <-- mark the end of the list or registers
|
||||
UC_ARM_REG_ENDING, // <-- mark the end of the list or registers
|
||||
|
||||
//> alias registers
|
||||
UC_ARM_REG_R13 = UC_ARM_REG_SP,
|
||||
|
@ -12,7 +12,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4201)
|
||||
#pragma warning(disable : 4201)
|
||||
#endif
|
||||
|
||||
//> ARM64 registers
|
||||
@ -281,7 +281,7 @@ typedef enum uc_arm64_reg {
|
||||
UC_ARM64_REG_V31,
|
||||
|
||||
//> pseudo registers
|
||||
UC_ARM64_REG_PC, // program counter register
|
||||
UC_ARM64_REG_PC, // program counter register
|
||||
|
||||
UC_ARM64_REG_CPACR_EL1,
|
||||
|
||||
@ -327,7 +327,7 @@ typedef enum uc_arm64_reg {
|
||||
UC_ARM64_REG_VBAR_EL2,
|
||||
UC_ARM64_REG_VBAR_EL3,
|
||||
|
||||
UC_ARM64_REG_ENDING, // <-- mark the end of the list of registers
|
||||
UC_ARM64_REG_ENDING, // <-- mark the end of the list of registers
|
||||
|
||||
//> alias registers
|
||||
|
||||
|
@ -12,7 +12,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4201)
|
||||
#pragma warning(disable : 4201)
|
||||
#endif
|
||||
|
||||
//> M68K registers
|
||||
@ -40,7 +40,7 @@ typedef enum uc_m68k_reg {
|
||||
UC_M68K_REG_SR,
|
||||
UC_M68K_REG_PC,
|
||||
|
||||
UC_M68K_REG_ENDING, // <-- mark the end of the list of registers
|
||||
UC_M68K_REG_ENDING, // <-- mark the end of the list of registers
|
||||
} uc_m68k_reg;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -16,7 +16,7 @@ extern "C" {
|
||||
#undef mips
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4201)
|
||||
#pragma warning(disable : 4201)
|
||||
#endif
|
||||
|
||||
//> MIPS registers
|
||||
@ -179,7 +179,7 @@ typedef enum UC_MIPS_REG {
|
||||
UC_MIPS_REG_CP0_USERLOCAL,
|
||||
UC_MIPS_REG_CP0_STATUS,
|
||||
|
||||
UC_MIPS_REG_ENDING, // <-- mark the end of the list or registers
|
||||
UC_MIPS_REG_ENDING, // <-- mark the end of the list or registers
|
||||
|
||||
// alias registers
|
||||
UC_MIPS_REG_ZERO = UC_MIPS_REG_0,
|
||||
@ -212,7 +212,8 @@ typedef enum UC_MIPS_REG {
|
||||
UC_MIPS_REG_K1 = UC_MIPS_REG_27,
|
||||
UC_MIPS_REG_GP = UC_MIPS_REG_28,
|
||||
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_HI0 = UC_MIPS_REG_AC0,
|
||||
|
@ -22,16 +22,17 @@ MSVC++ 7.0 _MSC_VER == 1300
|
||||
MSVC++ 6.0 _MSC_VER == 1200
|
||||
MSVC++ 5.0 _MSC_VER == 1100
|
||||
*/
|
||||
#define MSC_VER_VS2003 1310
|
||||
#define MSC_VER_VS2005 1400
|
||||
#define MSC_VER_VS2008 1500
|
||||
#define MSC_VER_VS2010 1600
|
||||
#define MSC_VER_VS2012 1700
|
||||
#define MSC_VER_VS2013 1800
|
||||
#define MSC_VER_VS2015 1900
|
||||
#define MSC_VER_VS2003 1310
|
||||
#define MSC_VER_VS2005 1400
|
||||
#define MSC_VER_VS2008 1500
|
||||
#define MSC_VER_VS2010 1600
|
||||
#define MSC_VER_VS2012 1700
|
||||
#define MSC_VER_VS2013 1800
|
||||
#define MSC_VER_VS2015 1900
|
||||
|
||||
// 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
|
||||
|
||||
// stdbool.h
|
||||
@ -41,62 +42,65 @@ MSVC++ 5.0 _MSC_VER == 1100
|
||||
typedef unsigned char bool;
|
||||
#define false 0
|
||||
#define true 1
|
||||
#endif // __cplusplus
|
||||
#endif // __cplusplus
|
||||
|
||||
#else
|
||||
// VisualStudio 2013+ -> C99 is supported
|
||||
#include <stdbool.h>
|
||||
#endif // (_MSC_VER < MSC_VER_VS2013) || defined(_KERNEL_MODE)
|
||||
#endif // (_MSC_VER < MSC_VER_VS2013) || defined(_KERNEL_MODE)
|
||||
|
||||
#else
|
||||
// not MSVC -> C99 is supported
|
||||
#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)
|
||||
// this system does not have stdint.h
|
||||
typedef signed char int8_t;
|
||||
typedef signed char int8_t;
|
||||
typedef signed short int16_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef signed int int32_t;
|
||||
typedef unsigned char uint8_t;
|
||||
typedef unsigned short uint16_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef signed long long int64_t;
|
||||
typedef unsigned int uint32_t;
|
||||
typedef signed long long int64_t;
|
||||
typedef unsigned long long uint64_t;
|
||||
|
||||
#ifndef _INTPTR_T_DEFINED
|
||||
#define _INTPTR_T_DEFINED
|
||||
#ifdef _WIN64
|
||||
typedef long long intptr_t;
|
||||
#else /* _WIN64 */
|
||||
typedef _W64 int intptr_t;
|
||||
#endif /* _WIN64 */
|
||||
#define _INTPTR_T_DEFINED
|
||||
#ifdef _WIN64
|
||||
typedef long long intptr_t;
|
||||
#else /* _WIN64 */
|
||||
typedef _W64 int intptr_t;
|
||||
#endif /* _WIN64 */
|
||||
#endif /* _INTPTR_T_DEFINED */
|
||||
|
||||
#ifndef _UINTPTR_T_DEFINED
|
||||
#define _UINTPTR_T_DEFINED
|
||||
#ifdef _WIN64
|
||||
#define _UINTPTR_T_DEFINED
|
||||
#ifdef _WIN64
|
||||
typedef unsigned long long uintptr_t;
|
||||
#else /* _WIN64 */
|
||||
typedef _W64 unsigned int uintptr_t;
|
||||
#endif /* _WIN64 */
|
||||
#else /* _WIN64 */
|
||||
typedef _W64 unsigned int uintptr_t;
|
||||
#endif /* _WIN64 */
|
||||
#endif /* _UINTPTR_T_DEFINED */
|
||||
|
||||
#define INT8_MIN (-127i8 - 1)
|
||||
#define INT16_MIN (-32767i16 - 1)
|
||||
#define INT32_MIN (-2147483647i32 - 1)
|
||||
#define INT64_MIN (-9223372036854775807i64 - 1)
|
||||
#define INT8_MAX 127i8
|
||||
#define INT16_MAX 32767i16
|
||||
#define INT32_MAX 2147483647i32
|
||||
#define INT64_MAX 9223372036854775807i64
|
||||
#define UINT8_MAX 0xffui8
|
||||
#define UINT16_MAX 0xffffui16
|
||||
#define UINT32_MAX 0xffffffffui32
|
||||
#define UINT64_MAX 0xffffffffffffffffui64
|
||||
#define INT8_MIN (-127i8 - 1)
|
||||
#define INT16_MIN (-32767i16 - 1)
|
||||
#define INT32_MIN (-2147483647i32 - 1)
|
||||
#define INT64_MIN (-9223372036854775807i64 - 1)
|
||||
#define INT8_MAX 127i8
|
||||
#define INT16_MAX 32767i16
|
||||
#define INT32_MAX 2147483647i32
|
||||
#define INT64_MAX 9223372036854775807i64
|
||||
#define UINT8_MAX 0xffui8
|
||||
#define UINT16_MAX 0xffffui16
|
||||
#define UINT32_MAX 0xffffffffui32
|
||||
#define UINT64_MAX 0xffffffffffffffffui64
|
||||
#else // this system has 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
|
||||
#if (defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2013)) || defined(_KERNEL_MODE)
|
||||
@ -105,52 +109,53 @@ typedef _W64 unsigned int uintptr_t;
|
||||
#define __PRI_8_LENGTH_MODIFIER__ "hh"
|
||||
#define __PRI_64_LENGTH_MODIFIER__ "ll"
|
||||
|
||||
#define PRId8 __PRI_8_LENGTH_MODIFIER__ "d"
|
||||
#define PRIi8 __PRI_8_LENGTH_MODIFIER__ "i"
|
||||
#define PRIo8 __PRI_8_LENGTH_MODIFIER__ "o"
|
||||
#define PRIu8 __PRI_8_LENGTH_MODIFIER__ "u"
|
||||
#define PRIx8 __PRI_8_LENGTH_MODIFIER__ "x"
|
||||
#define PRIX8 __PRI_8_LENGTH_MODIFIER__ "X"
|
||||
#define PRId8 __PRI_8_LENGTH_MODIFIER__ "d"
|
||||
#define PRIi8 __PRI_8_LENGTH_MODIFIER__ "i"
|
||||
#define PRIo8 __PRI_8_LENGTH_MODIFIER__ "o"
|
||||
#define PRIu8 __PRI_8_LENGTH_MODIFIER__ "u"
|
||||
#define PRIx8 __PRI_8_LENGTH_MODIFIER__ "x"
|
||||
#define PRIX8 __PRI_8_LENGTH_MODIFIER__ "X"
|
||||
|
||||
#define PRId16 "hd"
|
||||
#define PRIi16 "hi"
|
||||
#define PRIo16 "ho"
|
||||
#define PRIu16 "hu"
|
||||
#define PRIx16 "hx"
|
||||
#define PRIX16 "hX"
|
||||
#define PRId16 "hd"
|
||||
#define PRIi16 "hi"
|
||||
#define PRIo16 "ho"
|
||||
#define PRIu16 "hu"
|
||||
#define PRIx16 "hx"
|
||||
#define PRIX16 "hX"
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER <= MSC_VER_VS2012)
|
||||
#define PRId32 "ld"
|
||||
#define PRIi32 "li"
|
||||
#define PRIo32 "lo"
|
||||
#define PRIu32 "lu"
|
||||
#define PRIx32 "lx"
|
||||
#define PRIX32 "lX"
|
||||
#else // OSX
|
||||
#define PRId32 "d"
|
||||
#define PRIi32 "i"
|
||||
#define PRIo32 "o"
|
||||
#define PRIu32 "u"
|
||||
#define PRIx32 "x"
|
||||
#define PRIX32 "X"
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER <= MSC_VER_VS2012)
|
||||
#define PRId32 "ld"
|
||||
#define PRIi32 "li"
|
||||
#define PRIo32 "lo"
|
||||
#define PRIu32 "lu"
|
||||
#define PRIx32 "lx"
|
||||
#define PRIX32 "lX"
|
||||
#else // OSX
|
||||
#define PRId32 "d"
|
||||
#define PRIi32 "i"
|
||||
#define PRIo32 "o"
|
||||
#define PRIu32 "u"
|
||||
#define PRIx32 "x"
|
||||
#define PRIX32 "X"
|
||||
#endif // defined(_MSC_VER) && (_MSC_VER <= MSC_VER_VS2012)
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER <= MSC_VER_VS2012)
|
||||
// redefine functions from inttypes.h used in cstool
|
||||
#define strtoull _strtoui64
|
||||
#endif
|
||||
|
||||
#define PRId64 __PRI_64_LENGTH_MODIFIER__ "d"
|
||||
#define PRIi64 __PRI_64_LENGTH_MODIFIER__ "i"
|
||||
#define PRIo64 __PRI_64_LENGTH_MODIFIER__ "o"
|
||||
#define PRIu64 __PRI_64_LENGTH_MODIFIER__ "u"
|
||||
#define PRIx64 __PRI_64_LENGTH_MODIFIER__ "x"
|
||||
#define PRIX64 __PRI_64_LENGTH_MODIFIER__ "X"
|
||||
#define PRId64 __PRI_64_LENGTH_MODIFIER__ "d"
|
||||
#define PRIi64 __PRI_64_LENGTH_MODIFIER__ "i"
|
||||
#define PRIo64 __PRI_64_LENGTH_MODIFIER__ "o"
|
||||
#define PRIu64 __PRI_64_LENGTH_MODIFIER__ "u"
|
||||
#define PRIx64 __PRI_64_LENGTH_MODIFIER__ "x"
|
||||
#define PRIX64 __PRI_64_LENGTH_MODIFIER__ "X"
|
||||
|
||||
#else
|
||||
// this system has inttypes.h by default
|
||||
#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
|
||||
#if defined(_MSC_VER)
|
||||
@ -174,7 +179,7 @@ static int usleep(uint32_t usec)
|
||||
if (!timer)
|
||||
return -1;
|
||||
|
||||
due.QuadPart = (-((int64_t) usec)) * 10LL;
|
||||
due.QuadPart = (-((int64_t)usec)) * 10LL;
|
||||
if (!SetWaitableTimer(timer, &due, 0, NULL, NULL, 0)) {
|
||||
CloseHandle(timer);
|
||||
return -1;
|
||||
@ -191,23 +196,22 @@ static int usleep(uint32_t usec)
|
||||
|
||||
// misc support
|
||||
#if defined(_MSC_VER)
|
||||
#ifdef _WIN64
|
||||
typedef signed __int64 ssize_t;
|
||||
#ifdef _WIN64
|
||||
typedef signed __int64 ssize_t;
|
||||
#else
|
||||
typedef _W64 signed int ssize_t;
|
||||
typedef _W64 signed int ssize_t;
|
||||
#endif
|
||||
|
||||
#ifndef va_copy
|
||||
#define va_copy(d,s) ((d) = (s))
|
||||
#define va_copy(d, s) ((d) = (s))
|
||||
#endif
|
||||
#define strcasecmp _stricmp
|
||||
#define strcasecmp _stricmp
|
||||
#if (_MSC_VER < MSC_VER_VS2015)
|
||||
#define snprintf _snprintf
|
||||
#define snprintf _snprintf
|
||||
#endif
|
||||
#if (_MSC_VER <= MSC_VER_VS2013)
|
||||
#define strtoll _strtoi64
|
||||
#define strtoll _strtoi64
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
#endif // UNICORN_PLATFORM_H
|
||||
|
@ -12,7 +12,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4201)
|
||||
#pragma warning(disable : 4201)
|
||||
#endif
|
||||
|
||||
//> PPC registers
|
||||
|
@ -12,7 +12,7 @@ extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4201)
|
||||
#pragma warning(disable : 4201)
|
||||
#endif
|
||||
|
||||
//> RISCV registers
|
||||
@ -53,111 +53,111 @@ typedef enum uc_riscv_reg {
|
||||
UC_RISCV_REG_X31,
|
||||
|
||||
//> Floating-point registers
|
||||
UC_RISCV_REG_F0, // "ft0"
|
||||
UC_RISCV_REG_F1, // "ft1"
|
||||
UC_RISCV_REG_F2, // "ft2"
|
||||
UC_RISCV_REG_F3, // "ft3"
|
||||
UC_RISCV_REG_F4, // "ft4"
|
||||
UC_RISCV_REG_F5, // "ft5"
|
||||
UC_RISCV_REG_F6, // "ft6"
|
||||
UC_RISCV_REG_F7, // "ft7"
|
||||
UC_RISCV_REG_F8, // "fs0"
|
||||
UC_RISCV_REG_F9, // "fs1"
|
||||
UC_RISCV_REG_F10, // "fa0"
|
||||
UC_RISCV_REG_F11, // "fa1"
|
||||
UC_RISCV_REG_F12, // "fa2"
|
||||
UC_RISCV_REG_F13, // "fa3"
|
||||
UC_RISCV_REG_F14, // "fa4"
|
||||
UC_RISCV_REG_F15, // "fa5"
|
||||
UC_RISCV_REG_F16, // "fa6"
|
||||
UC_RISCV_REG_F17, // "fa7"
|
||||
UC_RISCV_REG_F18, // "fs2"
|
||||
UC_RISCV_REG_F19, // "fs3"
|
||||
UC_RISCV_REG_F20, // "fs4"
|
||||
UC_RISCV_REG_F21, // "fs5"
|
||||
UC_RISCV_REG_F22, // "fs6"
|
||||
UC_RISCV_REG_F23, // "fs7"
|
||||
UC_RISCV_REG_F24, // "fs8"
|
||||
UC_RISCV_REG_F25, // "fs9"
|
||||
UC_RISCV_REG_F26, // "fs10"
|
||||
UC_RISCV_REG_F27, // "fs11"
|
||||
UC_RISCV_REG_F28, // "ft8"
|
||||
UC_RISCV_REG_F29, // "ft9"
|
||||
UC_RISCV_REG_F30, // "ft10"
|
||||
UC_RISCV_REG_F31, // "ft11"
|
||||
UC_RISCV_REG_F0, // "ft0"
|
||||
UC_RISCV_REG_F1, // "ft1"
|
||||
UC_RISCV_REG_F2, // "ft2"
|
||||
UC_RISCV_REG_F3, // "ft3"
|
||||
UC_RISCV_REG_F4, // "ft4"
|
||||
UC_RISCV_REG_F5, // "ft5"
|
||||
UC_RISCV_REG_F6, // "ft6"
|
||||
UC_RISCV_REG_F7, // "ft7"
|
||||
UC_RISCV_REG_F8, // "fs0"
|
||||
UC_RISCV_REG_F9, // "fs1"
|
||||
UC_RISCV_REG_F10, // "fa0"
|
||||
UC_RISCV_REG_F11, // "fa1"
|
||||
UC_RISCV_REG_F12, // "fa2"
|
||||
UC_RISCV_REG_F13, // "fa3"
|
||||
UC_RISCV_REG_F14, // "fa4"
|
||||
UC_RISCV_REG_F15, // "fa5"
|
||||
UC_RISCV_REG_F16, // "fa6"
|
||||
UC_RISCV_REG_F17, // "fa7"
|
||||
UC_RISCV_REG_F18, // "fs2"
|
||||
UC_RISCV_REG_F19, // "fs3"
|
||||
UC_RISCV_REG_F20, // "fs4"
|
||||
UC_RISCV_REG_F21, // "fs5"
|
||||
UC_RISCV_REG_F22, // "fs6"
|
||||
UC_RISCV_REG_F23, // "fs7"
|
||||
UC_RISCV_REG_F24, // "fs8"
|
||||
UC_RISCV_REG_F25, // "fs9"
|
||||
UC_RISCV_REG_F26, // "fs10"
|
||||
UC_RISCV_REG_F27, // "fs11"
|
||||
UC_RISCV_REG_F28, // "ft8"
|
||||
UC_RISCV_REG_F29, // "ft9"
|
||||
UC_RISCV_REG_F30, // "ft10"
|
||||
UC_RISCV_REG_F31, // "ft11"
|
||||
|
||||
UC_RISCV_REG_PC, // PC register
|
||||
UC_RISCV_REG_PC, // PC register
|
||||
|
||||
UC_RISCV_REG_ENDING, // <-- mark the end of the list or registers
|
||||
UC_RISCV_REG_ENDING, // <-- mark the end of the list or registers
|
||||
|
||||
//> Alias registers
|
||||
UC_RISCV_REG_ZERO = UC_RISCV_REG_X0, // "zero"
|
||||
UC_RISCV_REG_RA = UC_RISCV_REG_X1, // "ra"
|
||||
UC_RISCV_REG_SP = UC_RISCV_REG_X2, // "sp"
|
||||
UC_RISCV_REG_GP = UC_RISCV_REG_X3, // "gp"
|
||||
UC_RISCV_REG_TP = UC_RISCV_REG_X4, // "tp"
|
||||
UC_RISCV_REG_T0 = UC_RISCV_REG_X5, // "t0"
|
||||
UC_RISCV_REG_T1 = UC_RISCV_REG_X6, // "t1"
|
||||
UC_RISCV_REG_T2 = UC_RISCV_REG_X7, // "t2"
|
||||
UC_RISCV_REG_S0 = UC_RISCV_REG_X8, // "s0"
|
||||
UC_RISCV_REG_FP = UC_RISCV_REG_X8, // "fp"
|
||||
UC_RISCV_REG_S1 = UC_RISCV_REG_X9, // "s1"
|
||||
UC_RISCV_REG_A0 = UC_RISCV_REG_X10, // "a0"
|
||||
UC_RISCV_REG_A1 = UC_RISCV_REG_X11, // "a1"
|
||||
UC_RISCV_REG_A2 = UC_RISCV_REG_X12, // "a2"
|
||||
UC_RISCV_REG_A3 = UC_RISCV_REG_X13, // "a3"
|
||||
UC_RISCV_REG_A4 = UC_RISCV_REG_X14, // "a4"
|
||||
UC_RISCV_REG_A5 = UC_RISCV_REG_X15, // "a5"
|
||||
UC_RISCV_REG_A6 = UC_RISCV_REG_X16, // "a6"
|
||||
UC_RISCV_REG_A7 = UC_RISCV_REG_X17, // "a7"
|
||||
UC_RISCV_REG_S2 = UC_RISCV_REG_X18, // "s2"
|
||||
UC_RISCV_REG_S3 = UC_RISCV_REG_X19, // "s3"
|
||||
UC_RISCV_REG_S4 = UC_RISCV_REG_X20, // "s4"
|
||||
UC_RISCV_REG_S5 = UC_RISCV_REG_X21, // "s5"
|
||||
UC_RISCV_REG_S6 = UC_RISCV_REG_X22, // "s6"
|
||||
UC_RISCV_REG_S7 = UC_RISCV_REG_X23, // "s7"
|
||||
UC_RISCV_REG_S8 = UC_RISCV_REG_X24, // "s8"
|
||||
UC_RISCV_REG_S9 = UC_RISCV_REG_X25, // "s9"
|
||||
UC_RISCV_REG_S10 = UC_RISCV_REG_X26, // "s10"
|
||||
UC_RISCV_REG_S11 = UC_RISCV_REG_X27, // "s11"
|
||||
UC_RISCV_REG_T3 = UC_RISCV_REG_X28, // "t3"
|
||||
UC_RISCV_REG_T4 = UC_RISCV_REG_X29, // "t4"
|
||||
UC_RISCV_REG_T5 = UC_RISCV_REG_X30, // "t5"
|
||||
UC_RISCV_REG_T6 = UC_RISCV_REG_X31, // "t6"
|
||||
UC_RISCV_REG_ZERO = UC_RISCV_REG_X0, // "zero"
|
||||
UC_RISCV_REG_RA = UC_RISCV_REG_X1, // "ra"
|
||||
UC_RISCV_REG_SP = UC_RISCV_REG_X2, // "sp"
|
||||
UC_RISCV_REG_GP = UC_RISCV_REG_X3, // "gp"
|
||||
UC_RISCV_REG_TP = UC_RISCV_REG_X4, // "tp"
|
||||
UC_RISCV_REG_T0 = UC_RISCV_REG_X5, // "t0"
|
||||
UC_RISCV_REG_T1 = UC_RISCV_REG_X6, // "t1"
|
||||
UC_RISCV_REG_T2 = UC_RISCV_REG_X7, // "t2"
|
||||
UC_RISCV_REG_S0 = UC_RISCV_REG_X8, // "s0"
|
||||
UC_RISCV_REG_FP = UC_RISCV_REG_X8, // "fp"
|
||||
UC_RISCV_REG_S1 = UC_RISCV_REG_X9, // "s1"
|
||||
UC_RISCV_REG_A0 = UC_RISCV_REG_X10, // "a0"
|
||||
UC_RISCV_REG_A1 = UC_RISCV_REG_X11, // "a1"
|
||||
UC_RISCV_REG_A2 = UC_RISCV_REG_X12, // "a2"
|
||||
UC_RISCV_REG_A3 = UC_RISCV_REG_X13, // "a3"
|
||||
UC_RISCV_REG_A4 = UC_RISCV_REG_X14, // "a4"
|
||||
UC_RISCV_REG_A5 = UC_RISCV_REG_X15, // "a5"
|
||||
UC_RISCV_REG_A6 = UC_RISCV_REG_X16, // "a6"
|
||||
UC_RISCV_REG_A7 = UC_RISCV_REG_X17, // "a7"
|
||||
UC_RISCV_REG_S2 = UC_RISCV_REG_X18, // "s2"
|
||||
UC_RISCV_REG_S3 = UC_RISCV_REG_X19, // "s3"
|
||||
UC_RISCV_REG_S4 = UC_RISCV_REG_X20, // "s4"
|
||||
UC_RISCV_REG_S5 = UC_RISCV_REG_X21, // "s5"
|
||||
UC_RISCV_REG_S6 = UC_RISCV_REG_X22, // "s6"
|
||||
UC_RISCV_REG_S7 = UC_RISCV_REG_X23, // "s7"
|
||||
UC_RISCV_REG_S8 = UC_RISCV_REG_X24, // "s8"
|
||||
UC_RISCV_REG_S9 = UC_RISCV_REG_X25, // "s9"
|
||||
UC_RISCV_REG_S10 = UC_RISCV_REG_X26, // "s10"
|
||||
UC_RISCV_REG_S11 = UC_RISCV_REG_X27, // "s11"
|
||||
UC_RISCV_REG_T3 = UC_RISCV_REG_X28, // "t3"
|
||||
UC_RISCV_REG_T4 = UC_RISCV_REG_X29, // "t4"
|
||||
UC_RISCV_REG_T5 = UC_RISCV_REG_X30, // "t5"
|
||||
UC_RISCV_REG_T6 = UC_RISCV_REG_X31, // "t6"
|
||||
|
||||
UC_RISCV_REG_FT0 = UC_RISCV_REG_F0, // "ft0"
|
||||
UC_RISCV_REG_FT1 = UC_RISCV_REG_F1, // "ft1"
|
||||
UC_RISCV_REG_FT2 = UC_RISCV_REG_F2, // "ft2"
|
||||
UC_RISCV_REG_FT3 = UC_RISCV_REG_F3, // "ft3"
|
||||
UC_RISCV_REG_FT4 = UC_RISCV_REG_F4, // "ft4"
|
||||
UC_RISCV_REG_FT5 = UC_RISCV_REG_F5, // "ft5"
|
||||
UC_RISCV_REG_FT6 = UC_RISCV_REG_F6, // "ft6"
|
||||
UC_RISCV_REG_FT7 = UC_RISCV_REG_F7, // "ft7"
|
||||
UC_RISCV_REG_FS0 = UC_RISCV_REG_F8, // "fs0"
|
||||
UC_RISCV_REG_FS1 = UC_RISCV_REG_F9, // "fs1"
|
||||
UC_RISCV_REG_FT0 = UC_RISCV_REG_F0, // "ft0"
|
||||
UC_RISCV_REG_FT1 = UC_RISCV_REG_F1, // "ft1"
|
||||
UC_RISCV_REG_FT2 = UC_RISCV_REG_F2, // "ft2"
|
||||
UC_RISCV_REG_FT3 = UC_RISCV_REG_F3, // "ft3"
|
||||
UC_RISCV_REG_FT4 = UC_RISCV_REG_F4, // "ft4"
|
||||
UC_RISCV_REG_FT5 = UC_RISCV_REG_F5, // "ft5"
|
||||
UC_RISCV_REG_FT6 = UC_RISCV_REG_F6, // "ft6"
|
||||
UC_RISCV_REG_FT7 = UC_RISCV_REG_F7, // "ft7"
|
||||
UC_RISCV_REG_FS0 = UC_RISCV_REG_F8, // "fs0"
|
||||
UC_RISCV_REG_FS1 = UC_RISCV_REG_F9, // "fs1"
|
||||
|
||||
UC_RISCV_REG_FA0 = UC_RISCV_REG_F10, // "fa0"
|
||||
UC_RISCV_REG_FA1 = UC_RISCV_REG_F11, // "fa1"
|
||||
UC_RISCV_REG_FA2 = UC_RISCV_REG_F12, // "fa2"
|
||||
UC_RISCV_REG_FA3 = UC_RISCV_REG_F13, // "fa3"
|
||||
UC_RISCV_REG_FA4 = UC_RISCV_REG_F14, // "fa4"
|
||||
UC_RISCV_REG_FA5 = UC_RISCV_REG_F15, // "fa5"
|
||||
UC_RISCV_REG_FA6 = UC_RISCV_REG_F16, // "fa6"
|
||||
UC_RISCV_REG_FA7 = UC_RISCV_REG_F17, // "fa7"
|
||||
UC_RISCV_REG_FS2 = UC_RISCV_REG_F18, // "fs2"
|
||||
UC_RISCV_REG_FS3 = UC_RISCV_REG_F19, // "fs3"
|
||||
UC_RISCV_REG_FS4 = UC_RISCV_REG_F20, // "fs4"
|
||||
UC_RISCV_REG_FS5 = UC_RISCV_REG_F21, // "fs5"
|
||||
UC_RISCV_REG_FS6 = UC_RISCV_REG_F22, // "fs6"
|
||||
UC_RISCV_REG_FS7 = UC_RISCV_REG_F23, // "fs7"
|
||||
UC_RISCV_REG_FS8 = UC_RISCV_REG_F24, // "fs8"
|
||||
UC_RISCV_REG_FS9 = UC_RISCV_REG_F25, // "fs9"
|
||||
UC_RISCV_REG_FS10 = UC_RISCV_REG_F26, // "fs10"
|
||||
UC_RISCV_REG_FS11 = UC_RISCV_REG_F27, // "fs11"
|
||||
UC_RISCV_REG_FT8 = UC_RISCV_REG_F28, // "ft8"
|
||||
UC_RISCV_REG_FT9 = UC_RISCV_REG_F29, // "ft9"
|
||||
UC_RISCV_REG_FT10 = UC_RISCV_REG_F30, // "ft10"
|
||||
UC_RISCV_REG_FT11 = UC_RISCV_REG_F31, // "ft11"
|
||||
UC_RISCV_REG_FA0 = UC_RISCV_REG_F10, // "fa0"
|
||||
UC_RISCV_REG_FA1 = UC_RISCV_REG_F11, // "fa1"
|
||||
UC_RISCV_REG_FA2 = UC_RISCV_REG_F12, // "fa2"
|
||||
UC_RISCV_REG_FA3 = UC_RISCV_REG_F13, // "fa3"
|
||||
UC_RISCV_REG_FA4 = UC_RISCV_REG_F14, // "fa4"
|
||||
UC_RISCV_REG_FA5 = UC_RISCV_REG_F15, // "fa5"
|
||||
UC_RISCV_REG_FA6 = UC_RISCV_REG_F16, // "fa6"
|
||||
UC_RISCV_REG_FA7 = UC_RISCV_REG_F17, // "fa7"
|
||||
UC_RISCV_REG_FS2 = UC_RISCV_REG_F18, // "fs2"
|
||||
UC_RISCV_REG_FS3 = UC_RISCV_REG_F19, // "fs3"
|
||||
UC_RISCV_REG_FS4 = UC_RISCV_REG_F20, // "fs4"
|
||||
UC_RISCV_REG_FS5 = UC_RISCV_REG_F21, // "fs5"
|
||||
UC_RISCV_REG_FS6 = UC_RISCV_REG_F22, // "fs6"
|
||||
UC_RISCV_REG_FS7 = UC_RISCV_REG_F23, // "fs7"
|
||||
UC_RISCV_REG_FS8 = UC_RISCV_REG_F24, // "fs8"
|
||||
UC_RISCV_REG_FS9 = UC_RISCV_REG_F25, // "fs9"
|
||||
UC_RISCV_REG_FS10 = UC_RISCV_REG_F26, // "fs10"
|
||||
UC_RISCV_REG_FS11 = UC_RISCV_REG_F27, // "fs11"
|
||||
UC_RISCV_REG_FT8 = UC_RISCV_REG_F28, // "ft8"
|
||||
UC_RISCV_REG_FT9 = UC_RISCV_REG_F29, // "ft9"
|
||||
UC_RISCV_REG_FT10 = UC_RISCV_REG_F30, // "ft10"
|
||||
UC_RISCV_REG_FT11 = UC_RISCV_REG_F31, // "ft11"
|
||||
} uc_riscv_reg;
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
@ -16,7 +16,7 @@ extern "C" {
|
||||
#undef sparc
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4201)
|
||||
#pragma warning(disable : 4201)
|
||||
#endif
|
||||
|
||||
//> SPARC registers
|
||||
@ -71,7 +71,7 @@ typedef enum uc_sparc_reg {
|
||||
UC_SPARC_REG_F58,
|
||||
UC_SPARC_REG_F60,
|
||||
UC_SPARC_REG_F62,
|
||||
UC_SPARC_REG_FCC0, // Floating condition codes
|
||||
UC_SPARC_REG_FCC0, // Floating condition codes
|
||||
UC_SPARC_REG_FCC1,
|
||||
UC_SPARC_REG_FCC2,
|
||||
UC_SPARC_REG_FCC3,
|
||||
@ -91,7 +91,7 @@ typedef enum uc_sparc_reg {
|
||||
UC_SPARC_REG_I5,
|
||||
UC_SPARC_REG_FP,
|
||||
UC_SPARC_REG_I7,
|
||||
UC_SPARC_REG_ICC, // Integer condition codes
|
||||
UC_SPARC_REG_ICC, // Integer condition codes
|
||||
UC_SPARC_REG_L0,
|
||||
UC_SPARC_REG_L1,
|
||||
UC_SPARC_REG_L2,
|
||||
@ -114,9 +114,9 @@ typedef enum uc_sparc_reg {
|
||||
UC_SPARC_REG_XCC,
|
||||
|
||||
// pseudo register
|
||||
UC_SPARC_REG_PC, // program counter register
|
||||
UC_SPARC_REG_PC, // program counter register
|
||||
|
||||
UC_SPARC_REG_ENDING, // <-- mark the end of the list of registers
|
||||
UC_SPARC_REG_ENDING, // <-- mark the end of the list of registers
|
||||
|
||||
// extras
|
||||
UC_SPARC_REG_O6 = UC_SPARC_REG_SP,
|
||||
|
@ -42,11 +42,11 @@ typedef size_t uc_hook;
|
||||
#endif
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(disable:4201)
|
||||
#pragma warning(disable:4100)
|
||||
#pragma warning(disable : 4201)
|
||||
#pragma warning(disable : 4100)
|
||||
#ifdef UNICORN_SHARED
|
||||
#define UNICORN_EXPORT __declspec(dllexport)
|
||||
#else // defined(UNICORN_STATIC)
|
||||
#else // defined(UNICORN_STATIC)
|
||||
#define UNICORN_EXPORT
|
||||
#endif
|
||||
#else
|
||||
@ -62,7 +62,8 @@ typedef size_t uc_hook;
|
||||
#elif defined(_MSC_VER)
|
||||
#define UNICORN_DEPRECATED __declspec(deprecated)
|
||||
#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
|
||||
#endif
|
||||
|
||||
@ -75,7 +76,6 @@ typedef size_t uc_hook;
|
||||
#define UC_VERSION_MINOR UC_API_MINOR
|
||||
#define UC_VERSION_EXTRA 0
|
||||
|
||||
|
||||
/*
|
||||
Macro to create combined version which can be compared to
|
||||
result of uc_version() API.
|
||||
@ -90,14 +90,14 @@ typedef size_t uc_hook;
|
||||
|
||||
// Architecture type
|
||||
typedef enum uc_arch {
|
||||
UC_ARCH_ARM = 1, // ARM architecture (including Thumb, Thumb-2)
|
||||
UC_ARCH_ARM64, // ARM-64, also called AArch64
|
||||
UC_ARCH_MIPS, // Mips architecture
|
||||
UC_ARCH_X86, // X86 architecture (including x86 & x86-64)
|
||||
UC_ARCH_PPC, // PowerPC architecture
|
||||
UC_ARCH_SPARC, // Sparc architecture
|
||||
UC_ARCH_M68K, // M68K architecture
|
||||
UC_ARCH_RISCV, // RISCV architecture
|
||||
UC_ARCH_ARM = 1, // ARM architecture (including Thumb, Thumb-2)
|
||||
UC_ARCH_ARM64, // ARM-64, also called AArch64
|
||||
UC_ARCH_MIPS, // Mips architecture
|
||||
UC_ARCH_X86, // X86 architecture (including x86 & x86-64)
|
||||
UC_ARCH_PPC, // PowerPC architecture
|
||||
UC_ARCH_SPARC, // Sparc architecture
|
||||
UC_ARCH_M68K, // M68K architecture
|
||||
UC_ARCH_RISCV, // RISCV architecture
|
||||
UC_ARCH_MAX,
|
||||
} uc_arch;
|
||||
|
||||
@ -107,41 +107,42 @@ typedef enum uc_mode {
|
||||
UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode
|
||||
|
||||
// arm / arm64
|
||||
UC_MODE_ARM = 0, // ARM mode
|
||||
UC_MODE_THUMB = 1 << 4, // THUMB mode (including Thumb-2)
|
||||
UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series
|
||||
UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM (currently unsupported)
|
||||
UC_MODE_ARM = 0, // ARM mode
|
||||
UC_MODE_THUMB = 1 << 4, // THUMB mode (including Thumb-2)
|
||||
UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series
|
||||
UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM (currently unsupported)
|
||||
|
||||
// arm (32bit) cpu types
|
||||
UC_MODE_ARM926 = 1 << 7, // ARM926 CPU type
|
||||
UC_MODE_ARM946 = 1 << 8, // ARM946 CPU type
|
||||
UC_MODE_ARM1176 = 1 << 9, // ARM1176 CPU type
|
||||
UC_MODE_ARM926 = 1 << 7, // ARM926 CPU type
|
||||
UC_MODE_ARM946 = 1 << 8, // ARM946 CPU type
|
||||
UC_MODE_ARM1176 = 1 << 9, // ARM1176 CPU type
|
||||
|
||||
// mips
|
||||
UC_MODE_MICRO = 1 << 4, // MicroMips mode (currently unsupported)
|
||||
UC_MODE_MIPS3 = 1 << 5, // Mips III ISA (currently unsupported)
|
||||
UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA (currently unsupported)
|
||||
UC_MODE_MIPS32 = 1 << 2, // Mips32 ISA
|
||||
UC_MODE_MIPS64 = 1 << 3, // Mips64 ISA
|
||||
UC_MODE_MICRO = 1 << 4, // MicroMips mode (currently unsupported)
|
||||
UC_MODE_MIPS3 = 1 << 5, // Mips III ISA (currently unsupported)
|
||||
UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA (currently unsupported)
|
||||
UC_MODE_MIPS32 = 1 << 2, // Mips32 ISA
|
||||
UC_MODE_MIPS64 = 1 << 3, // Mips64 ISA
|
||||
|
||||
// x86 / x64
|
||||
UC_MODE_16 = 1 << 1, // 16-bit mode
|
||||
UC_MODE_32 = 1 << 2, // 32-bit mode
|
||||
UC_MODE_64 = 1 << 3, // 64-bit mode
|
||||
UC_MODE_16 = 1 << 1, // 16-bit mode
|
||||
UC_MODE_32 = 1 << 2, // 32-bit mode
|
||||
UC_MODE_64 = 1 << 3, // 64-bit mode
|
||||
|
||||
// ppc
|
||||
UC_MODE_PPC32 = 1 << 2, // 32-bit mode
|
||||
UC_MODE_PPC64 = 1 << 3, // 64-bit mode (currently unsupported)
|
||||
UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (currently unsupported)
|
||||
// ppc
|
||||
UC_MODE_PPC32 = 1 << 2, // 32-bit mode
|
||||
UC_MODE_PPC64 = 1 << 3, // 64-bit mode (currently unsupported)
|
||||
UC_MODE_QPX =
|
||||
1 << 4, // Quad Processing eXtensions mode (currently unsupported)
|
||||
|
||||
// sparc
|
||||
UC_MODE_SPARC32 = 1 << 2, // 32-bit mode
|
||||
UC_MODE_SPARC64 = 1 << 3, // 64-bit mode
|
||||
UC_MODE_V9 = 1 << 4, // SparcV9 mode (currently unsupported)
|
||||
UC_MODE_SPARC32 = 1 << 2, // 32-bit mode
|
||||
UC_MODE_SPARC64 = 1 << 3, // 64-bit mode
|
||||
UC_MODE_V9 = 1 << 4, // SparcV9 mode (currently unsupported)
|
||||
|
||||
// riscv
|
||||
UC_MODE_RISCV32 = 1 << 2, // 32-bit mode
|
||||
UC_MODE_RISCV64 = 1 << 3, // 64-bit mode
|
||||
UC_MODE_RISCV32 = 1 << 2, // 32-bit mode
|
||||
UC_MODE_RISCV64 = 1 << 3, // 64-bit mode
|
||||
|
||||
// m68k
|
||||
} uc_mode;
|
||||
@ -149,39 +150,48 @@ typedef enum uc_mode {
|
||||
// All type of errors encountered by Unicorn API.
|
||||
// These are values returned by uc_errno()
|
||||
typedef enum uc_err {
|
||||
UC_ERR_OK = 0, // No error: everything was fine
|
||||
UC_ERR_NOMEM, // Out-Of-Memory error: uc_open(), uc_emulate()
|
||||
UC_ERR_ARCH, // Unsupported architecture: uc_open()
|
||||
UC_ERR_HANDLE, // Invalid handle
|
||||
UC_ERR_MODE, // Invalid/unsupported mode: uc_open()
|
||||
UC_ERR_VERSION, // Unsupported version (bindings)
|
||||
UC_ERR_READ_UNMAPPED, // Quit emulation due to READ 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_INSN_INVALID, // Quit emulation due to invalid instruction: uc_emu_start()
|
||||
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_READ_PROT, // Quit emulation due to UC_MEM_READ_PROT violation: 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_OK = 0, // No error: everything was fine
|
||||
UC_ERR_NOMEM, // Out-Of-Memory error: uc_open(), uc_emulate()
|
||||
UC_ERR_ARCH, // Unsupported architecture: uc_open()
|
||||
UC_ERR_HANDLE, // Invalid handle
|
||||
UC_ERR_MODE, // Invalid/unsupported mode: uc_open()
|
||||
UC_ERR_VERSION, // Unsupported version (bindings)
|
||||
UC_ERR_READ_UNMAPPED, // Quit emulation due to READ 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_INSN_INVALID, // Quit emulation due to invalid instruction:
|
||||
// uc_emu_start()
|
||||
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_READ_PROT, // Quit emulation due to UC_MEM_READ_PROT violation:
|
||||
// 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_WRITE_UNALIGNED, // Unaligned write
|
||||
UC_ERR_FETCH_UNALIGNED, // Unaligned fetch
|
||||
UC_ERR_HOOK_EXIST, // hook for this event already existed
|
||||
UC_ERR_RESOURCE, // Insufficient resource: uc_emu_start()
|
||||
UC_ERR_EXCEPTION, // Unhandled CPU exception
|
||||
UC_ERR_WRITE_UNALIGNED, // Unaligned write
|
||||
UC_ERR_FETCH_UNALIGNED, // Unaligned fetch
|
||||
UC_ERR_HOOK_EXIST, // hook for this event already existed
|
||||
UC_ERR_RESOURCE, // Insufficient resource: uc_emu_start()
|
||||
UC_ERR_EXCEPTION, // Unhandled CPU exception
|
||||
} uc_err;
|
||||
|
||||
|
||||
/*
|
||||
Callback function for tracing code (UC_HOOK_CODE & UC_HOOK_BLOCK)
|
||||
|
||||
@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.
|
||||
*/
|
||||
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())
|
||||
@ -189,14 +199,16 @@ typedef void (*uc_cb_hookcode_t)(uc_engine *uc, uint64_t address, uint32_t size,
|
||||
@intno: interrupt number
|
||||
@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
|
||||
|
||||
@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);
|
||||
|
||||
@ -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
|
||||
@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
|
||||
@ -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
|
||||
@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
|
||||
@ -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
|
||||
@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
|
||||
@ -235,28 +250,30 @@ typedef uint64_t (*uc_cb_mmio_read_t)(uc_engine *uc, uint64_t offset, unsigned s
|
||||
@value: data value to be written
|
||||
@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_*
|
||||
typedef enum uc_mem_type {
|
||||
UC_MEM_READ = 16, // Memory is read from
|
||||
UC_MEM_WRITE, // Memory is written to
|
||||
UC_MEM_FETCH, // Memory is fetched
|
||||
UC_MEM_READ_UNMAPPED, // Unmapped memory is read from
|
||||
UC_MEM_WRITE_UNMAPPED, // Unmapped memory is written to
|
||||
UC_MEM_FETCH_UNMAPPED, // Unmapped memory is fetched
|
||||
UC_MEM_WRITE_PROT, // Write to write protected, but mapped, memory
|
||||
UC_MEM_READ_PROT, // Read from read protected, but mapped, memory
|
||||
UC_MEM_FETCH_PROT, // Fetch from non-executable, but mapped, memory
|
||||
UC_MEM_READ_AFTER, // Memory is read from (successful access)
|
||||
UC_MEM_READ = 16, // Memory is read from
|
||||
UC_MEM_WRITE, // Memory is written to
|
||||
UC_MEM_FETCH, // Memory is fetched
|
||||
UC_MEM_READ_UNMAPPED, // Unmapped memory is read from
|
||||
UC_MEM_WRITE_UNMAPPED, // Unmapped memory is written to
|
||||
UC_MEM_FETCH_UNMAPPED, // Unmapped memory is fetched
|
||||
UC_MEM_WRITE_PROT, // Write to write protected, but mapped, memory
|
||||
UC_MEM_READ_PROT, // Read from read protected, but mapped, memory
|
||||
UC_MEM_FETCH_PROT, // Fetch from non-executable, but mapped, memory
|
||||
UC_MEM_READ_AFTER, // Memory is read from (successful access)
|
||||
} uc_mem_type;
|
||||
|
||||
// All type of hooks for uc_hook_add() API.
|
||||
typedef enum uc_hook_type {
|
||||
// Hook all interrupt/syscall events
|
||||
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,
|
||||
// Hook a range of code
|
||||
UC_HOOK_CODE = 1 << 2,
|
||||
@ -288,21 +305,29 @@ typedef enum uc_hook_type {
|
||||
} uc_hook_type;
|
||||
|
||||
// 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
|
||||
#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
|
||||
#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
|
||||
#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
|
||||
#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
|
||||
#define UC_HOOK_MEM_INVALID (UC_HOOK_MEM_UNMAPPED + UC_HOOK_MEM_PROT)
|
||||
// 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
|
||||
// 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)
|
||||
// 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.
|
||||
#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)
|
||||
@ -314,7 +339,8 @@ typedef enum uc_hook_type {
|
||||
@user_data: user data passed to tracing APIs
|
||||
*/
|
||||
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
|
||||
@ -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.
|
||||
@user_data: user data passed to tracing APIs
|
||||
|
||||
@return: return true to continue, or false to stop program (due to invalid memory).
|
||||
NOTE: returning true to continue execution will only work if if the accessed
|
||||
memory is made accessible with the correct permissions during the hook.
|
||||
@return: return true to continue, or false to stop program (due to invalid
|
||||
memory). NOTE: returning true to continue execution will only work if if the
|
||||
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,
|
||||
the memory should be uc_mem_map()-ed with the correct permissions, and the
|
||||
instruction will then read or write to the address as it was supposed to.
|
||||
In the event of a UC_MEM_READ_UNMAPPED or UC_MEM_WRITE_UNMAPPED
|
||||
callback, the memory should be uc_mem_map()-ed with the correct permissions,
|
||||
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 as executable, in which case execution will resume from the fetched address.
|
||||
The instruction pointer may be written to in order to change where execution resumes,
|
||||
but the fetch must succeed if execution is to resume.
|
||||
In the event of a UC_MEM_FETCH_UNMAPPED callback, the memory can be
|
||||
mapped in as executable, in which case execution will resume from the fetched
|
||||
address. The instruction pointer may be written to in order to change where
|
||||
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,
|
||||
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()
|
||||
@ -357,8 +386,9 @@ typedef enum uc_query_type {
|
||||
// Dynamically query current hardware mode.
|
||||
UC_QUERY_MODE = 1,
|
||||
UC_QUERY_PAGE_SIZE, // query pagesize of engine
|
||||
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_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_type;
|
||||
|
||||
// Opaque storage for CPU context, used with uc_context_*()
|
||||
@ -385,7 +415,6 @@ typedef struct uc_context uc_context;
|
||||
UNICORN_EXPORT
|
||||
unsigned int uc_version(unsigned int *major, unsigned int *minor);
|
||||
|
||||
|
||||
/*
|
||||
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
|
||||
bool uc_arch_supported(uc_arch arch);
|
||||
|
||||
|
||||
/*
|
||||
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).
|
||||
*/
|
||||
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.
|
||||
@ -529,7 +558,8 @@ uc_err uc_reg_read_batch(uc_engine *uc, int *regs, void **vals, int count);
|
||||
for detailed error).
|
||||
*/
|
||||
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.
|
||||
@ -566,7 +596,8 @@ uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t size);
|
||||
for detailed error).
|
||||
*/
|
||||
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.
|
||||
@ -585,15 +616,17 @@ uc_err uc_emu_stop(uc_engine *uc);
|
||||
The callback will be run when the hook event is hit.
|
||||
|
||||
@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
|
||||
@callback: callback to be run when instruction is hit
|
||||
@user_data: user-defined data. This will be passed to callback function in its
|
||||
last argument @user_data
|
||||
@begin: start address of the area where the callback is effect (inclusive)
|
||||
@end: end address of the area where the callback is effect (inclusive)
|
||||
NOTE 1: the callback is called only if related address is in range [@begin, @end]
|
||||
NOTE 2: if @begin > @end, callback is called whenever this hook type is triggered
|
||||
NOTE 1: the callback is called only if related address is in range [@begin,
|
||||
@end] NOTE 2: if @begin > @end, callback is called whenever this hook type is
|
||||
triggered
|
||||
@...: variable arguments (depending on @type)
|
||||
NOTE: if @type = UC_HOOK_INSN, this is the instruction ID.
|
||||
currently, only x86 in, out, syscall, sysenter, cpuid are supported.
|
||||
@ -603,7 +636,7 @@ uc_err uc_emu_stop(uc_engine *uc);
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
|
||||
void *user_data, uint64_t begin, uint64_t end, ...);
|
||||
void *user_data, uint64_t begin, uint64_t end, ...);
|
||||
|
||||
/*
|
||||
Unregister (remove) a hook callback.
|
||||
@ -621,11 +654,11 @@ UNICORN_EXPORT
|
||||
uc_err uc_hook_del(uc_engine *uc, uc_hook hh);
|
||||
|
||||
typedef enum uc_prot {
|
||||
UC_PROT_NONE = 0,
|
||||
UC_PROT_READ = 1,
|
||||
UC_PROT_WRITE = 2,
|
||||
UC_PROT_EXEC = 4,
|
||||
UC_PROT_ALL = 7,
|
||||
UC_PROT_NONE = 0,
|
||||
UC_PROT_READ = 1,
|
||||
UC_PROT_WRITE = 2,
|
||||
UC_PROT_EXEC = 4,
|
||||
UC_PROT_ALL = 7,
|
||||
} uc_prot;
|
||||
|
||||
/*
|
||||
@ -634,12 +667,14 @@ typedef enum uc_prot {
|
||||
|
||||
@uc: handle returned by uc_open()
|
||||
@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.
|
||||
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.
|
||||
This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC,
|
||||
or this will return with UC_ERR_ARG error.
|
||||
This must be some combination of UC_PROT_READ | UC_PROT_WRITE |
|
||||
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
|
||||
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()
|
||||
@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.
|
||||
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.
|
||||
This must be some combination of UC_PROT_READ | UC_PROT_WRITE | 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
|
||||
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.
|
||||
This must be some combination of UC_PROT_READ | UC_PROT_WRITE |
|
||||
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 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.
|
||||
|
||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||
for detailed error).
|
||||
*/
|
||||
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.
|
||||
@ -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()
|
||||
@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.
|
||||
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.
|
||||
@user_data_read: user-defined data. This will be passed to @read_cb function in its
|
||||
last argument @user_data
|
||||
@user_data_read: user-defined data. This will be passed to @read_cb function in
|
||||
its last argument @user_data
|
||||
@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
|
||||
last argument @user_data
|
||||
@user_data_write: user-defined data. This will be passed to @write_cb function
|
||||
in its last argument @user_data
|
||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||
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()
|
||||
@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.
|
||||
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
|
||||
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()
|
||||
@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.
|
||||
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.
|
||||
This must be some combination of UC_PROT_READ | UC_PROT_WRITE | UC_PROT_EXEC,
|
||||
or this will return with UC_ERR_ARG error.
|
||||
This must be some combination of UC_PROT_READ | UC_PROT_WRITE |
|
||||
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
|
||||
for detailed error).
|
||||
*/
|
||||
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()
|
||||
@ -763,9 +808,9 @@ uc_err uc_context_alloc(uc_engine *uc, uc_context **context);
|
||||
|
||||
/*
|
||||
Free the memory allocated by uc_mem_regions.
|
||||
WARNING: After Unicorn 1.0.1rc5, the memory allocated by uc_context_alloc should
|
||||
be free-ed by uc_context_free(). Calling uc_free() may still work, but the result
|
||||
is **undefined**.
|
||||
WARNING: After Unicorn 1.0.1rc5, the memory allocated by uc_context_alloc
|
||||
should be free-ed by uc_context_free(). Calling uc_free() may still work, but
|
||||
the result is **undefined**.
|
||||
|
||||
@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).
|
||||
*/
|
||||
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.
|
||||
@ -841,7 +887,8 @@ uc_err uc_context_reg_write_batch(uc_context *ctx, int *regs, void *const *vals,
|
||||
for detailed error).
|
||||
*/
|
||||
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.
|
||||
@ -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().
|
||||
|
||||
@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
|
||||
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
|
||||
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
|
||||
to contain the cpu context and directly call uc_context_save.
|
||||
Return the size needed to store the cpu context. Can be used to allocate a
|
||||
buffer to contain the cpu context and directly call uc_context_save.
|
||||
|
||||
@uc: handle returned by uc_open()
|
||||
|
||||
@ -869,7 +916,6 @@ uc_err uc_context_restore(uc_engine *uc, uc_context *context);
|
||||
UNICORN_EXPORT
|
||||
size_t uc_context_size(uc_engine *uc);
|
||||
|
||||
|
||||
/*
|
||||
Free the context allocated by uc_context_alloc().
|
||||
|
||||
|
@ -16,14 +16,14 @@ extern "C" {
|
||||
// Memory-Management Register for instructions IDTR, GDTR, LDTR, TR.
|
||||
// Borrow from SegmentCache in qemu/target-i386/cpu.h
|
||||
typedef struct uc_x86_mmr {
|
||||
uint16_t selector; /* not used by GDTR and IDTR */
|
||||
uint64_t base; /* handle 32 or 64 bit CPUs */
|
||||
uint16_t selector; /* not used by GDTR and IDTR */
|
||||
uint64_t base; /* handle 32 or 64 bit CPUs */
|
||||
uint32_t limit;
|
||||
uint32_t flags; /* not used by GDTR and IDTR */
|
||||
uint32_t flags; /* not used by GDTR and IDTR */
|
||||
} uc_x86_mmr;
|
||||
|
||||
// Model-Specific Register structure, use this with UC_X86_REG_MSR (as the register ID) in
|
||||
// call to uc_reg_write/uc_reg_read() to manipulate MSRs.
|
||||
// Model-Specific Register structure, use this with UC_X86_REG_MSR (as the
|
||||
// register ID) in call to uc_reg_write/uc_reg_read() to manipulate MSRs.
|
||||
typedef struct uc_x86_msr {
|
||||
uint32_t rid; // MSR id
|
||||
uint64_t value; // MSR value
|
||||
@ -35,62 +35,241 @@ typedef void (*uc_cb_insn_syscall_t)(struct uc_struct *uc, void *user_data);
|
||||
|
||||
//> X86 registers
|
||||
typedef enum uc_x86_reg {
|
||||
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_BP, UC_X86_REG_BPL, UC_X86_REG_BX, UC_X86_REG_CH, UC_X86_REG_CL,
|
||||
UC_X86_REG_CS, UC_X86_REG_CX, UC_X86_REG_DH, UC_X86_REG_DI, UC_X86_REG_DIL,
|
||||
UC_X86_REG_DL, UC_X86_REG_DS, UC_X86_REG_DX, UC_X86_REG_EAX, UC_X86_REG_EBP,
|
||||
UC_X86_REG_EBX, UC_X86_REG_ECX, UC_X86_REG_EDI, UC_X86_REG_EDX, UC_X86_REG_EFLAGS,
|
||||
UC_X86_REG_EIP, UC_X86_REG_ES, UC_X86_REG_ESI, UC_X86_REG_ESP,
|
||||
UC_X86_REG_FPSW, UC_X86_REG_FS, UC_X86_REG_GS, UC_X86_REG_IP, UC_X86_REG_RAX,
|
||||
UC_X86_REG_RBP, UC_X86_REG_RBX, UC_X86_REG_RCX, UC_X86_REG_RDI, UC_X86_REG_RDX,
|
||||
UC_X86_REG_RIP, UC_X86_REG_RSI, UC_X86_REG_RSP, UC_X86_REG_SI,
|
||||
UC_X86_REG_SIL, UC_X86_REG_SP, UC_X86_REG_SPL, 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_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_BP,
|
||||
UC_X86_REG_BPL,
|
||||
UC_X86_REG_BX,
|
||||
UC_X86_REG_CH,
|
||||
UC_X86_REG_CL,
|
||||
UC_X86_REG_CS,
|
||||
UC_X86_REG_CX,
|
||||
UC_X86_REG_DH,
|
||||
UC_X86_REG_DI,
|
||||
UC_X86_REG_DIL,
|
||||
UC_X86_REG_DL,
|
||||
UC_X86_REG_DS,
|
||||
UC_X86_REG_DX,
|
||||
UC_X86_REG_EAX,
|
||||
UC_X86_REG_EBP,
|
||||
UC_X86_REG_EBX,
|
||||
UC_X86_REG_ECX,
|
||||
UC_X86_REG_EDI,
|
||||
UC_X86_REG_EDX,
|
||||
UC_X86_REG_EFLAGS,
|
||||
UC_X86_REG_EIP,
|
||||
UC_X86_REG_ES,
|
||||
UC_X86_REG_ESI,
|
||||
UC_X86_REG_ESP,
|
||||
UC_X86_REG_FPSW,
|
||||
UC_X86_REG_FS,
|
||||
UC_X86_REG_GS,
|
||||
UC_X86_REG_IP,
|
||||
UC_X86_REG_RAX,
|
||||
UC_X86_REG_RBP,
|
||||
UC_X86_REG_RBX,
|
||||
UC_X86_REG_RCX,
|
||||
UC_X86_REG_RDI,
|
||||
UC_X86_REG_RDX,
|
||||
UC_X86_REG_RIP,
|
||||
UC_X86_REG_RSI,
|
||||
UC_X86_REG_RSP,
|
||||
UC_X86_REG_SI,
|
||||
UC_X86_REG_SIL,
|
||||
UC_X86_REG_SP,
|
||||
UC_X86_REG_SPL,
|
||||
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_MSR, // Model-Specific Register
|
||||
UC_X86_REG_MXCSR,
|
||||
UC_X86_REG_FS_BASE, // Base regs for x86_64
|
||||
UC_X86_REG_GS_BASE,
|
||||
UC_X86_REG_FLAGS,
|
||||
UC_X86_REG_RFLAGS,
|
||||
UC_X86_REG_ENDING // <-- mark the end of the list of registers
|
||||
UC_X86_REG_ENDING // <-- mark the end of the list of registers
|
||||
} uc_x86_reg;
|
||||
|
||||
//> X86 instructions
|
||||
|
@ -5,26 +5,38 @@
|
||||
#define UC_QEMU_TARGET_ARM_H
|
||||
|
||||
// functions to read & write registers
|
||||
int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
||||
int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
||||
int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
||||
int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
||||
int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||
int count);
|
||||
int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||
int count);
|
||||
int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||
int count);
|
||||
int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||
int count);
|
||||
|
||||
int arm_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, void *const *vals, int count);
|
||||
int armeb_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, 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);
|
||||
int arm_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,
|
||||
void *const *vals, int count);
|
||||
int armeb_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,
|
||||
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 arm64_reg_reset(struct uc_struct *uc);
|
||||
|
||||
void arm_uc_init(struct uc_struct* uc);
|
||||
void armeb_uc_init(struct uc_struct* uc);
|
||||
void arm_uc_init(struct uc_struct *uc);
|
||||
void armeb_uc_init(struct uc_struct *uc);
|
||||
|
||||
void arm64_uc_init(struct uc_struct* uc);
|
||||
void arm64eb_uc_init(struct uc_struct* uc);
|
||||
void arm64_uc_init(struct uc_struct *uc);
|
||||
void arm64eb_uc_init(struct uc_struct *uc);
|
||||
#endif
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -6,12 +6,16 @@
|
||||
#define UC_QEMU_TARGET_I386_H
|
||||
|
||||
// functions to read & write registers
|
||||
int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
||||
int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
||||
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);
|
||||
int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||
int count);
|
||||
int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||
int count);
|
||||
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_uc_init(struct uc_struct* uc);
|
||||
void x86_uc_init(struct uc_struct *uc);
|
||||
#endif
|
||||
|
@ -15,7 +15,7 @@ static void m68k_set_pc(struct uc_struct *uc, uint64_t address)
|
||||
((CPUM68KState *)uc->cpu->env_ptr)->pc = address;
|
||||
}
|
||||
|
||||
static void m68k_release(void* ctx)
|
||||
static void m68k_release(void *ctx)
|
||||
{
|
||||
int i;
|
||||
TCGContext *tcg_ctx = (TCGContext *)ctx;
|
||||
@ -51,11 +51,12 @@ static void reg_read(CPUM68KState *env, unsigned int regid, void *value)
|
||||
else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7)
|
||||
*(int32_t *)value = env->dregs[regid - UC_M68K_REG_D0];
|
||||
else {
|
||||
switch(regid) {
|
||||
default: break;
|
||||
case UC_M68K_REG_PC:
|
||||
*(int32_t *)value = env->pc;
|
||||
break;
|
||||
switch (regid) {
|
||||
default:
|
||||
break;
|
||||
case UC_M68K_REG_PC:
|
||||
*(int32_t *)value = env->pc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -69,18 +70,20 @@ static void reg_write(CPUM68KState *env, unsigned int regid, const void *value)
|
||||
else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7)
|
||||
env->dregs[regid - UC_M68K_REG_D0] = *(uint32_t *)value;
|
||||
else {
|
||||
switch(regid) {
|
||||
default: break;
|
||||
case UC_M68K_REG_PC:
|
||||
env->pc = *(uint32_t *)value;
|
||||
break;
|
||||
switch (regid) {
|
||||
default:
|
||||
break;
|
||||
case UC_M68K_REG_PC:
|
||||
env->pc = *(uint32_t *)value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
unsigned int regid = regs[i];
|
||||
const void *value = vals[i];
|
||||
reg_write(env, regid, value);
|
||||
if (regid == UC_M68K_REG_PC){
|
||||
if (regid == UC_M68K_REG_PC) {
|
||||
// force to quit execution and flush TB
|
||||
uc->quit_request = true;
|
||||
uc_emu_stop(uc);
|
||||
@ -112,9 +116,10 @@ int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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
|
||||
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;
|
||||
|
||||
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
|
||||
void m68k_uc_init(struct uc_struct* uc)
|
||||
void m68k_uc_init(struct uc_struct *uc)
|
||||
{
|
||||
uc->release = m68k_release;
|
||||
uc->reg_read = m68k_reg_read;
|
||||
|
@ -5,12 +5,16 @@
|
||||
#define UC_QEMU_TARGET_M68K_H
|
||||
|
||||
// functions to read & write registers
|
||||
int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
||||
int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
||||
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);
|
||||
int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||
int count);
|
||||
int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||
int count);
|
||||
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_uc_init(struct uc_struct* uc);
|
||||
void m68k_uc_init(struct uc_struct *uc);
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
static void mips_release(void *ctx)
|
||||
{
|
||||
int i;
|
||||
@ -75,20 +74,21 @@ static void reg_read(CPUMIPSState *env, unsigned int regid, void *value)
|
||||
if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31)
|
||||
*(mipsreg_t *)value = env->active_tc.gpr[regid - UC_MIPS_REG_0];
|
||||
else {
|
||||
switch(regid) {
|
||||
default: break;
|
||||
case UC_MIPS_REG_PC:
|
||||
*(mipsreg_t *)value = env->active_tc.PC;
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_CONFIG3:
|
||||
*(mipsreg_t *)value = env->CP0_Config3;
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_STATUS:
|
||||
*(mipsreg_t *)value = env->CP0_Status;
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_USERLOCAL:
|
||||
*(mipsreg_t *)value = env->active_tc.CP0_UserLocal;
|
||||
break;
|
||||
switch (regid) {
|
||||
default:
|
||||
break;
|
||||
case UC_MIPS_REG_PC:
|
||||
*(mipsreg_t *)value = env->active_tc.PC;
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_CONFIG3:
|
||||
*(mipsreg_t *)value = env->CP0_Config3;
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_STATUS:
|
||||
*(mipsreg_t *)value = env->CP0_Status;
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_USERLOCAL:
|
||||
*(mipsreg_t *)value = env->active_tc.CP0_UserLocal;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,31 +100,33 @@ static void reg_write(CPUMIPSState *env, unsigned int regid, const void *value)
|
||||
if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31)
|
||||
env->active_tc.gpr[regid - UC_MIPS_REG_0] = *(mipsreg_t *)value;
|
||||
else {
|
||||
switch(regid) {
|
||||
default: break;
|
||||
case UC_MIPS_REG_PC:
|
||||
env->active_tc.PC = *(mipsreg_t *)value;
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_CONFIG3:
|
||||
env->CP0_Config3 = *(mipsreg_t *)value;
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_STATUS:
|
||||
// TODO: ALL CP0 REGS
|
||||
// https://s3-eu-west-1.amazonaws.com/downloads-mips/documents/MD00090-2B-MIPS32PRA-AFP-06.02.pdf
|
||||
// https://s3-eu-west-1.amazonaws.com/downloads-mips/documents/MD00582-2B-microMIPS32-AFP-05.04.pdf
|
||||
env->CP0_Status = *(mipsreg_t *)value;
|
||||
compute_hflags(env);
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_USERLOCAL:
|
||||
env->active_tc.CP0_UserLocal = *(mipsreg_t *)value;
|
||||
break;
|
||||
switch (regid) {
|
||||
default:
|
||||
break;
|
||||
case UC_MIPS_REG_PC:
|
||||
env->active_tc.PC = *(mipsreg_t *)value;
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_CONFIG3:
|
||||
env->CP0_Config3 = *(mipsreg_t *)value;
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_STATUS:
|
||||
// TODO: ALL CP0 REGS
|
||||
// https://s3-eu-west-1.amazonaws.com/downloads-mips/documents/MD00090-2B-MIPS32PRA-AFP-06.02.pdf
|
||||
// https://s3-eu-west-1.amazonaws.com/downloads-mips/documents/MD00582-2B-microMIPS32-AFP-05.04.pdf
|
||||
env->CP0_Status = *(mipsreg_t *)value;
|
||||
compute_hflags(env);
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_USERLOCAL:
|
||||
env->active_tc.CP0_UserLocal = *(mipsreg_t *)value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
int i;
|
||||
@ -138,7 +140,8 @@ int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int cou
|
||||
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);
|
||||
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];
|
||||
const void *value = vals[i];
|
||||
reg_write(env, regid, value);
|
||||
if(regid == UC_MIPS_REG_PC){
|
||||
if (regid == UC_MIPS_REG_PC) {
|
||||
// force to quit execution and flush TB
|
||||
uc->quit_request = true;
|
||||
uc_emu_stop(uc);
|
||||
@ -160,15 +163,19 @@ int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||
DEFAULT_VISIBILITY
|
||||
#ifdef TARGET_MIPS64
|
||||
#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
|
||||
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
|
||||
#else // if TARGET_MIPS
|
||||
#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
|
||||
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
|
||||
{
|
||||
@ -187,15 +194,19 @@ DEFAULT_VISIBILITY
|
||||
DEFAULT_VISIBILITY
|
||||
#ifdef TARGET_MIPS64
|
||||
#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
|
||||
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
|
||||
#else // if TARGET_MIPS
|
||||
#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
|
||||
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
|
||||
{
|
||||
@ -226,15 +237,15 @@ static int mips_cpus_init(struct uc_struct *uc, const char *cpu_model)
|
||||
DEFAULT_VISIBILITY
|
||||
#ifdef TARGET_MIPS64
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
void mips64_uc_init(struct uc_struct* uc)
|
||||
void mips64_uc_init(struct uc_struct *uc)
|
||||
#else
|
||||
void mips64el_uc_init(struct uc_struct* uc)
|
||||
void mips64el_uc_init(struct uc_struct *uc)
|
||||
#endif
|
||||
#else // if TARGET_MIPS
|
||||
#ifdef TARGET_WORDS_BIGENDIAN
|
||||
void mips_uc_init(struct uc_struct* uc)
|
||||
void mips_uc_init(struct uc_struct *uc)
|
||||
#else
|
||||
void mipsel_uc_init(struct uc_struct* uc)
|
||||
void mipsel_uc_init(struct uc_struct *uc)
|
||||
#endif
|
||||
#endif
|
||||
{
|
||||
|
@ -5,22 +5,32 @@
|
||||
#define UC_QEMU_TARGET_MIPS_H
|
||||
|
||||
// functions to read & write registers
|
||||
int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
||||
int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
||||
int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||
int count);
|
||||
int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||
int count);
|
||||
|
||||
int mips_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, void *const *vals, int count);
|
||||
int mipsel_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, 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);
|
||||
int mips_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,
|
||||
void *const *vals, int count);
|
||||
int mipsel_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,
|
||||
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_uc_init(struct uc_struct* uc);
|
||||
void mipsel_uc_init(struct uc_struct* uc);
|
||||
void mips64_uc_init(struct uc_struct* uc);
|
||||
void mips64el_uc_init(struct uc_struct* uc);
|
||||
void mips_uc_init(struct uc_struct *uc);
|
||||
void mipsel_uc_init(struct uc_struct *uc);
|
||||
void mips64_uc_init(struct uc_struct *uc);
|
||||
void mips64el_uc_init(struct uc_struct *uc);
|
||||
#endif
|
||||
|
@ -18,14 +18,14 @@ typedef uint32_t ppcreg_t;
|
||||
|
||||
static uint64_t ppc_mem_redirect(uint64_t address)
|
||||
{
|
||||
/* // kseg0 range masks off high address bit
|
||||
if (address >= 0x80000000 && address <= 0x9fffffff)
|
||||
return address & 0x7fffffff;
|
||||
/* // kseg0 range masks off high address bit
|
||||
if (address >= 0x80000000 && address <= 0x9fffffff)
|
||||
return address & 0x7fffffff;
|
||||
|
||||
// kseg1 range masks off top 3 address bits
|
||||
if (address >= 0xa0000000 && address <= 0xbfffffff) {
|
||||
return address & 0x1fffffff;
|
||||
}*/
|
||||
// kseg1 range masks off top 3 address bits
|
||||
if (address >= 0xa0000000 && address <= 0xbfffffff) {
|
||||
return address & 0x1fffffff;
|
||||
}*/
|
||||
|
||||
// no redirect
|
||||
return address;
|
||||
@ -59,12 +59,12 @@ static void ppc_release(void *ctx)
|
||||
for (i = 0; i < 32; 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->bcond);
|
||||
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_unrealize(tcg_ctx->uc->cpu);
|
||||
@ -84,17 +84,18 @@ static void reg_read(CPUPPCState *env, unsigned int regid, void *value)
|
||||
if (regid >= UC_PPC_REG_0 && regid <= UC_PPC_REG_31)
|
||||
*(ppcreg_t *)value = env->gpr[regid - UC_PPC_REG_0];
|
||||
else {
|
||||
switch(regid) {
|
||||
default: break;
|
||||
case UC_PPC_REG_PC:
|
||||
*(ppcreg_t *)value = env->nip;
|
||||
break;
|
||||
/* case UC_PPC_REG_CP0_CONFIG3:
|
||||
*(mipsreg_t *)value = env->CP0_Config3;
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_USERLOCAL:
|
||||
*(mipsreg_t *)value = env->active_tc.CP0_UserLocal;
|
||||
break; */
|
||||
switch (regid) {
|
||||
default:
|
||||
break;
|
||||
case UC_PPC_REG_PC:
|
||||
*(ppcreg_t *)value = env->nip;
|
||||
break;
|
||||
/* case UC_PPC_REG_CP0_CONFIG3:
|
||||
*(mipsreg_t *)value = env->CP0_Config3;
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_USERLOCAL:
|
||||
*(mipsreg_t *)value = env->active_tc.CP0_UserLocal;
|
||||
break; */
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,24 +107,26 @@ static void reg_write(CPUPPCState *env, unsigned int regid, const void *value)
|
||||
if (regid >= UC_PPC_REG_0 && regid <= UC_PPC_REG_31)
|
||||
env->gpr[regid - UC_PPC_REG_0] = *(ppcreg_t *)value;
|
||||
else {
|
||||
switch(regid) {
|
||||
default: break;
|
||||
case UC_PPC_REG_PC:
|
||||
env->nip = *(ppcreg_t *)value;
|
||||
break;
|
||||
/* case UC_MIPS_REG_CP0_CONFIG3:
|
||||
env->CP0_Config3 = *(mipsreg_t *)value;
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_USERLOCAL:
|
||||
env->active_tc.CP0_UserLocal = *(mipsreg_t *)value;
|
||||
break; */
|
||||
switch (regid) {
|
||||
default:
|
||||
break;
|
||||
case UC_PPC_REG_PC:
|
||||
env->nip = *(ppcreg_t *)value;
|
||||
break;
|
||||
/* case UC_MIPS_REG_CP0_CONFIG3:
|
||||
env->CP0_Config3 = *(mipsreg_t *)value;
|
||||
break;
|
||||
case UC_MIPS_REG_CP0_USERLOCAL:
|
||||
env->active_tc.CP0_UserLocal = *(mipsreg_t *)value;
|
||||
break; */
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
int i;
|
||||
@ -137,7 +140,8 @@ int ppc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int coun
|
||||
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);
|
||||
int i;
|
||||
@ -158,9 +162,11 @@ int ppc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, i
|
||||
|
||||
DEFAULT_VISIBILITY
|
||||
#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
|
||||
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
|
||||
{
|
||||
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
|
||||
#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
|
||||
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
|
||||
{
|
||||
CPUPPCState *env = (CPUPPCState *)ctx->data;
|
||||
@ -208,9 +216,9 @@ static int ppc_cpus_init(struct uc_struct *uc, const char *cpu_model)
|
||||
|
||||
DEFAULT_VISIBILITY
|
||||
#ifdef TARGET_PPC64
|
||||
void ppc64_uc_init(struct uc_struct* uc)
|
||||
void ppc64_uc_init(struct uc_struct *uc)
|
||||
#else
|
||||
void ppc_uc_init(struct uc_struct* uc)
|
||||
void ppc_uc_init(struct uc_struct *uc)
|
||||
#endif
|
||||
{
|
||||
uc->reg_read = ppc_reg_read;
|
||||
|
@ -5,16 +5,22 @@
|
||||
#define UC_QEMU_TARGET_PPC_H
|
||||
|
||||
// functions to read & write registers
|
||||
int ppc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
||||
int ppc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
||||
int ppc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||
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_write(struct uc_context *ctx, unsigned int *regs, 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);
|
||||
int ppc_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,
|
||||
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_uc_init(struct uc_struct* uc);
|
||||
void ppc64_uc_init(struct uc_struct* uc);
|
||||
void ppc_uc_init(struct uc_struct *uc);
|
||||
void ppc64_uc_init(struct uc_struct *uc);
|
||||
#endif
|
||||
|
@ -36,99 +36,97 @@ 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)
|
||||
{
|
||||
switch(regid) {
|
||||
case UC_RISCV_REG_X0:
|
||||
case UC_RISCV_REG_X1:
|
||||
case UC_RISCV_REG_X2:
|
||||
case UC_RISCV_REG_X3:
|
||||
case UC_RISCV_REG_X4:
|
||||
case UC_RISCV_REG_X5:
|
||||
case UC_RISCV_REG_X6:
|
||||
case UC_RISCV_REG_X7:
|
||||
case UC_RISCV_REG_X8:
|
||||
case UC_RISCV_REG_X9:
|
||||
case UC_RISCV_REG_X10:
|
||||
case UC_RISCV_REG_X11:
|
||||
case UC_RISCV_REG_X12:
|
||||
case UC_RISCV_REG_X13:
|
||||
case UC_RISCV_REG_X14:
|
||||
case UC_RISCV_REG_X15:
|
||||
case UC_RISCV_REG_X16:
|
||||
case UC_RISCV_REG_X17:
|
||||
case UC_RISCV_REG_X18:
|
||||
case UC_RISCV_REG_X19:
|
||||
case UC_RISCV_REG_X20:
|
||||
case UC_RISCV_REG_X21:
|
||||
case UC_RISCV_REG_X22:
|
||||
case UC_RISCV_REG_X23:
|
||||
case UC_RISCV_REG_X24:
|
||||
case UC_RISCV_REG_X25:
|
||||
case UC_RISCV_REG_X26:
|
||||
case UC_RISCV_REG_X27:
|
||||
case UC_RISCV_REG_X28:
|
||||
case UC_RISCV_REG_X29:
|
||||
case UC_RISCV_REG_X30:
|
||||
case UC_RISCV_REG_X31:
|
||||
switch (regid) {
|
||||
case UC_RISCV_REG_X0:
|
||||
case UC_RISCV_REG_X1:
|
||||
case UC_RISCV_REG_X2:
|
||||
case UC_RISCV_REG_X3:
|
||||
case UC_RISCV_REG_X4:
|
||||
case UC_RISCV_REG_X5:
|
||||
case UC_RISCV_REG_X6:
|
||||
case UC_RISCV_REG_X7:
|
||||
case UC_RISCV_REG_X8:
|
||||
case UC_RISCV_REG_X9:
|
||||
case UC_RISCV_REG_X10:
|
||||
case UC_RISCV_REG_X11:
|
||||
case UC_RISCV_REG_X12:
|
||||
case UC_RISCV_REG_X13:
|
||||
case UC_RISCV_REG_X14:
|
||||
case UC_RISCV_REG_X15:
|
||||
case UC_RISCV_REG_X16:
|
||||
case UC_RISCV_REG_X17:
|
||||
case UC_RISCV_REG_X18:
|
||||
case UC_RISCV_REG_X19:
|
||||
case UC_RISCV_REG_X20:
|
||||
case UC_RISCV_REG_X21:
|
||||
case UC_RISCV_REG_X22:
|
||||
case UC_RISCV_REG_X23:
|
||||
case UC_RISCV_REG_X24:
|
||||
case UC_RISCV_REG_X25:
|
||||
case UC_RISCV_REG_X26:
|
||||
case UC_RISCV_REG_X27:
|
||||
case UC_RISCV_REG_X28:
|
||||
case UC_RISCV_REG_X29:
|
||||
case UC_RISCV_REG_X30:
|
||||
case UC_RISCV_REG_X31:
|
||||
#ifdef TARGET_RISCV64
|
||||
*(int64_t *)value = env->gpr[regid - UC_RISCV_REG_X0];
|
||||
*(int64_t *)value = env->gpr[regid - UC_RISCV_REG_X0];
|
||||
#else
|
||||
*(int32_t *)value = env->gpr[regid - UC_RISCV_REG_X0];
|
||||
*(int32_t *)value = env->gpr[regid - UC_RISCV_REG_X0];
|
||||
#endif
|
||||
break;
|
||||
case UC_RISCV_REG_PC:
|
||||
break;
|
||||
case UC_RISCV_REG_PC:
|
||||
#ifdef TARGET_RISCV64
|
||||
*(int64_t *)value = env->pc;
|
||||
*(int64_t *)value = env->pc;
|
||||
#else
|
||||
*(int32_t *)value = env->pc;
|
||||
*(int32_t *)value = env->pc;
|
||||
#endif
|
||||
break;
|
||||
break;
|
||||
|
||||
case UC_RISCV_REG_F0: // "ft0"
|
||||
case UC_RISCV_REG_F1: // "ft1"
|
||||
case UC_RISCV_REG_F2: // "ft2"
|
||||
case UC_RISCV_REG_F3: // "ft3"
|
||||
case UC_RISCV_REG_F4: // "ft4"
|
||||
case UC_RISCV_REG_F5: // "ft5"
|
||||
case UC_RISCV_REG_F6: // "ft6"
|
||||
case UC_RISCV_REG_F7: // "ft7"
|
||||
case UC_RISCV_REG_F8: // "fs0"
|
||||
case UC_RISCV_REG_F9: // "fs1"
|
||||
case UC_RISCV_REG_F10: // "fa0"
|
||||
case UC_RISCV_REG_F11: // "fa1"
|
||||
case UC_RISCV_REG_F12: // "fa2"
|
||||
case UC_RISCV_REG_F13: // "fa3"
|
||||
case UC_RISCV_REG_F14: // "fa4"
|
||||
case UC_RISCV_REG_F15: // "fa5"
|
||||
case UC_RISCV_REG_F16: // "fa6"
|
||||
case UC_RISCV_REG_F17: // "fa7"
|
||||
case UC_RISCV_REG_F18: // "fs2"
|
||||
case UC_RISCV_REG_F19: // "fs3"
|
||||
case UC_RISCV_REG_F20: // "fs4"
|
||||
case UC_RISCV_REG_F21: // "fs5"
|
||||
case UC_RISCV_REG_F22: // "fs6"
|
||||
case UC_RISCV_REG_F23: // "fs7"
|
||||
case UC_RISCV_REG_F24: // "fs8"
|
||||
case UC_RISCV_REG_F25: // "fs9"
|
||||
case UC_RISCV_REG_F26: // "fs10"
|
||||
case UC_RISCV_REG_F27: // "fs11"
|
||||
case UC_RISCV_REG_F28: // "ft8"
|
||||
case UC_RISCV_REG_F29: // "ft9"
|
||||
case UC_RISCV_REG_F30: // "ft10"
|
||||
case UC_RISCV_REG_F31: // "ft11"
|
||||
case UC_RISCV_REG_F0: // "ft0"
|
||||
case UC_RISCV_REG_F1: // "ft1"
|
||||
case UC_RISCV_REG_F2: // "ft2"
|
||||
case UC_RISCV_REG_F3: // "ft3"
|
||||
case UC_RISCV_REG_F4: // "ft4"
|
||||
case UC_RISCV_REG_F5: // "ft5"
|
||||
case UC_RISCV_REG_F6: // "ft6"
|
||||
case UC_RISCV_REG_F7: // "ft7"
|
||||
case UC_RISCV_REG_F8: // "fs0"
|
||||
case UC_RISCV_REG_F9: // "fs1"
|
||||
case UC_RISCV_REG_F10: // "fa0"
|
||||
case UC_RISCV_REG_F11: // "fa1"
|
||||
case UC_RISCV_REG_F12: // "fa2"
|
||||
case UC_RISCV_REG_F13: // "fa3"
|
||||
case UC_RISCV_REG_F14: // "fa4"
|
||||
case UC_RISCV_REG_F15: // "fa5"
|
||||
case UC_RISCV_REG_F16: // "fa6"
|
||||
case UC_RISCV_REG_F17: // "fa7"
|
||||
case UC_RISCV_REG_F18: // "fs2"
|
||||
case UC_RISCV_REG_F19: // "fs3"
|
||||
case UC_RISCV_REG_F20: // "fs4"
|
||||
case UC_RISCV_REG_F21: // "fs5"
|
||||
case UC_RISCV_REG_F22: // "fs6"
|
||||
case UC_RISCV_REG_F23: // "fs7"
|
||||
case UC_RISCV_REG_F24: // "fs8"
|
||||
case UC_RISCV_REG_F25: // "fs9"
|
||||
case UC_RISCV_REG_F26: // "fs10"
|
||||
case UC_RISCV_REG_F27: // "fs11"
|
||||
case UC_RISCV_REG_F28: // "ft8"
|
||||
case UC_RISCV_REG_F29: // "ft9"
|
||||
case UC_RISCV_REG_F30: // "ft10"
|
||||
case UC_RISCV_REG_F31: // "ft11"
|
||||
#ifdef TARGET_RISCV64
|
||||
*(int64_t *)value = env->fpr[regid - UC_RISCV_REG_F0];
|
||||
*(int64_t *)value = env->fpr[regid - UC_RISCV_REG_F0];
|
||||
#else
|
||||
*(int32_t *)value = env->fpr[regid - UC_RISCV_REG_F0];
|
||||
*(int32_t *)value = env->fpr[regid - UC_RISCV_REG_F0];
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return;
|
||||
@ -136,96 +134,97 @@ static void reg_read(CPURISCVState *env, unsigned int regid, void *value)
|
||||
|
||||
static void reg_write(CPURISCVState *env, unsigned int regid, const void *value)
|
||||
{
|
||||
switch(regid) {
|
||||
case UC_RISCV_REG_X0:
|
||||
case UC_RISCV_REG_X1:
|
||||
case UC_RISCV_REG_X2:
|
||||
case UC_RISCV_REG_X3:
|
||||
case UC_RISCV_REG_X4:
|
||||
case UC_RISCV_REG_X5:
|
||||
case UC_RISCV_REG_X6:
|
||||
case UC_RISCV_REG_X7:
|
||||
case UC_RISCV_REG_X8:
|
||||
case UC_RISCV_REG_X9:
|
||||
case UC_RISCV_REG_X10:
|
||||
case UC_RISCV_REG_X11:
|
||||
case UC_RISCV_REG_X12:
|
||||
case UC_RISCV_REG_X13:
|
||||
case UC_RISCV_REG_X14:
|
||||
case UC_RISCV_REG_X15:
|
||||
case UC_RISCV_REG_X16:
|
||||
case UC_RISCV_REG_X17:
|
||||
case UC_RISCV_REG_X18:
|
||||
case UC_RISCV_REG_X19:
|
||||
case UC_RISCV_REG_X20:
|
||||
case UC_RISCV_REG_X21:
|
||||
case UC_RISCV_REG_X22:
|
||||
case UC_RISCV_REG_X23:
|
||||
case UC_RISCV_REG_X24:
|
||||
case UC_RISCV_REG_X25:
|
||||
case UC_RISCV_REG_X26:
|
||||
case UC_RISCV_REG_X27:
|
||||
case UC_RISCV_REG_X28:
|
||||
case UC_RISCV_REG_X29:
|
||||
case UC_RISCV_REG_X30:
|
||||
case UC_RISCV_REG_X31:
|
||||
switch (regid) {
|
||||
case UC_RISCV_REG_X0:
|
||||
case UC_RISCV_REG_X1:
|
||||
case UC_RISCV_REG_X2:
|
||||
case UC_RISCV_REG_X3:
|
||||
case UC_RISCV_REG_X4:
|
||||
case UC_RISCV_REG_X5:
|
||||
case UC_RISCV_REG_X6:
|
||||
case UC_RISCV_REG_X7:
|
||||
case UC_RISCV_REG_X8:
|
||||
case UC_RISCV_REG_X9:
|
||||
case UC_RISCV_REG_X10:
|
||||
case UC_RISCV_REG_X11:
|
||||
case UC_RISCV_REG_X12:
|
||||
case UC_RISCV_REG_X13:
|
||||
case UC_RISCV_REG_X14:
|
||||
case UC_RISCV_REG_X15:
|
||||
case UC_RISCV_REG_X16:
|
||||
case UC_RISCV_REG_X17:
|
||||
case UC_RISCV_REG_X18:
|
||||
case UC_RISCV_REG_X19:
|
||||
case UC_RISCV_REG_X20:
|
||||
case UC_RISCV_REG_X21:
|
||||
case UC_RISCV_REG_X22:
|
||||
case UC_RISCV_REG_X23:
|
||||
case UC_RISCV_REG_X24:
|
||||
case UC_RISCV_REG_X25:
|
||||
case UC_RISCV_REG_X26:
|
||||
case UC_RISCV_REG_X27:
|
||||
case UC_RISCV_REG_X28:
|
||||
case UC_RISCV_REG_X29:
|
||||
case UC_RISCV_REG_X30:
|
||||
case UC_RISCV_REG_X31:
|
||||
#ifdef TARGET_RISCV64
|
||||
env->gpr[regid - UC_RISCV_REG_X0] = *(uint64_t *)value;
|
||||
env->gpr[regid - UC_RISCV_REG_X0] = *(uint64_t *)value;
|
||||
#else
|
||||
env->gpr[regid - UC_RISCV_REG_X0] = *(uint32_t *)value;
|
||||
env->gpr[regid - UC_RISCV_REG_X0] = *(uint32_t *)value;
|
||||
#endif
|
||||
break;
|
||||
case UC_RISCV_REG_PC:
|
||||
break;
|
||||
case UC_RISCV_REG_PC:
|
||||
#ifdef TARGET_RISCV64
|
||||
env->pc = *(uint64_t *)value;
|
||||
env->pc = *(uint64_t *)value;
|
||||
#else
|
||||
env->pc = *(uint32_t *)value;
|
||||
env->pc = *(uint32_t *)value;
|
||||
#endif
|
||||
break;
|
||||
case UC_RISCV_REG_F0: // "ft0"
|
||||
case UC_RISCV_REG_F1: // "ft1"
|
||||
case UC_RISCV_REG_F2: // "ft2"
|
||||
case UC_RISCV_REG_F3: // "ft3"
|
||||
case UC_RISCV_REG_F4: // "ft4"
|
||||
case UC_RISCV_REG_F5: // "ft5"
|
||||
case UC_RISCV_REG_F6: // "ft6"
|
||||
case UC_RISCV_REG_F7: // "ft7"
|
||||
case UC_RISCV_REG_F8: // "fs0"
|
||||
case UC_RISCV_REG_F9: // "fs1"
|
||||
case UC_RISCV_REG_F10: // "fa0"
|
||||
case UC_RISCV_REG_F11: // "fa1"
|
||||
case UC_RISCV_REG_F12: // "fa2"
|
||||
case UC_RISCV_REG_F13: // "fa3"
|
||||
case UC_RISCV_REG_F14: // "fa4"
|
||||
case UC_RISCV_REG_F15: // "fa5"
|
||||
case UC_RISCV_REG_F16: // "fa6"
|
||||
case UC_RISCV_REG_F17: // "fa7"
|
||||
case UC_RISCV_REG_F18: // "fs2"
|
||||
case UC_RISCV_REG_F19: // "fs3"
|
||||
case UC_RISCV_REG_F20: // "fs4"
|
||||
case UC_RISCV_REG_F21: // "fs5"
|
||||
case UC_RISCV_REG_F22: // "fs6"
|
||||
case UC_RISCV_REG_F23: // "fs7"
|
||||
case UC_RISCV_REG_F24: // "fs8"
|
||||
case UC_RISCV_REG_F25: // "fs9"
|
||||
case UC_RISCV_REG_F26: // "fs10"
|
||||
case UC_RISCV_REG_F27: // "fs11"
|
||||
case UC_RISCV_REG_F28: // "ft8"
|
||||
case UC_RISCV_REG_F29: // "ft9"
|
||||
case UC_RISCV_REG_F30: // "ft10"
|
||||
case UC_RISCV_REG_F31: // "ft11"
|
||||
break;
|
||||
case UC_RISCV_REG_F0: // "ft0"
|
||||
case UC_RISCV_REG_F1: // "ft1"
|
||||
case UC_RISCV_REG_F2: // "ft2"
|
||||
case UC_RISCV_REG_F3: // "ft3"
|
||||
case UC_RISCV_REG_F4: // "ft4"
|
||||
case UC_RISCV_REG_F5: // "ft5"
|
||||
case UC_RISCV_REG_F6: // "ft6"
|
||||
case UC_RISCV_REG_F7: // "ft7"
|
||||
case UC_RISCV_REG_F8: // "fs0"
|
||||
case UC_RISCV_REG_F9: // "fs1"
|
||||
case UC_RISCV_REG_F10: // "fa0"
|
||||
case UC_RISCV_REG_F11: // "fa1"
|
||||
case UC_RISCV_REG_F12: // "fa2"
|
||||
case UC_RISCV_REG_F13: // "fa3"
|
||||
case UC_RISCV_REG_F14: // "fa4"
|
||||
case UC_RISCV_REG_F15: // "fa5"
|
||||
case UC_RISCV_REG_F16: // "fa6"
|
||||
case UC_RISCV_REG_F17: // "fa7"
|
||||
case UC_RISCV_REG_F18: // "fs2"
|
||||
case UC_RISCV_REG_F19: // "fs3"
|
||||
case UC_RISCV_REG_F20: // "fs4"
|
||||
case UC_RISCV_REG_F21: // "fs5"
|
||||
case UC_RISCV_REG_F22: // "fs6"
|
||||
case UC_RISCV_REG_F23: // "fs7"
|
||||
case UC_RISCV_REG_F24: // "fs8"
|
||||
case UC_RISCV_REG_F25: // "fs9"
|
||||
case UC_RISCV_REG_F26: // "fs10"
|
||||
case UC_RISCV_REG_F27: // "fs11"
|
||||
case UC_RISCV_REG_F28: // "ft8"
|
||||
case UC_RISCV_REG_F29: // "ft9"
|
||||
case UC_RISCV_REG_F30: // "ft10"
|
||||
case UC_RISCV_REG_F31: // "ft11"
|
||||
#ifdef TARGET_RISCV64
|
||||
env->fpr[regid - UC_RISCV_REG_F0] = *(uint64_t *)value;
|
||||
env->fpr[regid - UC_RISCV_REG_F0] = *(uint64_t *)value;
|
||||
#else
|
||||
env->fpr[regid - UC_RISCV_REG_F0] = *(uint32_t *)value;
|
||||
env->fpr[regid - UC_RISCV_REG_F0] = *(uint32_t *)value;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
int i;
|
||||
@ -239,7 +238,8 @@ int riscv_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int co
|
||||
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);
|
||||
int i;
|
||||
@ -248,11 +248,11 @@ int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||
unsigned int regid = regs[i];
|
||||
const void *value = vals[i];
|
||||
reg_write(env, regid, value);
|
||||
if(regid == UC_RISCV_REG_PC){
|
||||
if (regid == UC_RISCV_REG_PC) {
|
||||
// force to quit execution and flush TB
|
||||
uc->quit_request = true;
|
||||
uc_emu_stop(uc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -260,10 +260,12 @@ int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||
|
||||
DEFAULT_VISIBILITY
|
||||
#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
|
||||
/* TARGET_RISCV64 */
|
||||
int riscv64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
|
||||
/* TARGET_RISCV64 */
|
||||
int riscv64_context_reg_read(struct uc_context *ctx, unsigned int *regs,
|
||||
void **vals, int count)
|
||||
#endif
|
||||
{
|
||||
CPURISCVState *env = (CPURISCVState *)ctx->data;
|
||||
@ -280,10 +282,12 @@ int riscv64_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **
|
||||
|
||||
DEFAULT_VISIBILITY
|
||||
#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
|
||||
/* TARGET_RISCV64 */
|
||||
int riscv64_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
|
||||
/* TARGET_RISCV64 */
|
||||
int riscv64_context_reg_write(struct uc_context *ctx, unsigned int *regs,
|
||||
void *const *vals, int count)
|
||||
#endif
|
||||
{
|
||||
CPURISCVState *env = (CPURISCVState *)ctx->data;
|
||||
@ -301,14 +305,14 @@ int riscv64_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *
|
||||
static bool riscv_stop_interrupt(struct uc_struct *uc, int intno)
|
||||
{
|
||||
// detect stop exception
|
||||
switch(intno){
|
||||
default:
|
||||
return false;
|
||||
case RISCV_EXCP_UNICORN_END:
|
||||
return true;
|
||||
case RISCV_EXCP_BREAKPOINT:
|
||||
uc->invalid_error = UC_ERR_EXCEPTION;
|
||||
return true;
|
||||
switch (intno) {
|
||||
default:
|
||||
return false;
|
||||
case RISCV_EXCP_UNICORN_END:
|
||||
return true;
|
||||
case RISCV_EXCP_BREAKPOINT:
|
||||
uc->invalid_error = UC_ERR_EXCEPTION;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -332,10 +336,10 @@ static int riscv_cpus_init(struct uc_struct *uc, const char *cpu_model)
|
||||
|
||||
DEFAULT_VISIBILITY
|
||||
#ifdef TARGET_RISCV32
|
||||
void riscv32_uc_init(struct uc_struct* uc)
|
||||
void riscv32_uc_init(struct uc_struct *uc)
|
||||
#else
|
||||
/* TARGET_RISCV64 */
|
||||
void riscv64_uc_init(struct uc_struct* uc)
|
||||
/* TARGET_RISCV64 */
|
||||
void riscv64_uc_init(struct uc_struct *uc)
|
||||
#endif
|
||||
{
|
||||
uc->reg_read = riscv_reg_read;
|
||||
|
@ -6,16 +6,22 @@
|
||||
#define UC_QEMU_TARGET_RISCV_H
|
||||
|
||||
// functions to read & write registers
|
||||
int riscv_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
||||
int riscv_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
||||
int riscv_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||
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_write(struct uc_context *ctx, unsigned int *regs, 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);
|
||||
int riscv32_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,
|
||||
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 riscv32_uc_init(struct uc_struct* uc);
|
||||
void riscv64_uc_init(struct uc_struct* uc);
|
||||
void riscv32_uc_init(struct uc_struct *uc);
|
||||
void riscv64_uc_init(struct uc_struct *uc);
|
||||
#endif
|
||||
|
@ -10,11 +10,11 @@
|
||||
|
||||
static bool sparc_stop_interrupt(struct uc_struct *uc, int intno)
|
||||
{
|
||||
switch(intno) {
|
||||
default:
|
||||
return false;
|
||||
case TT_ILL_INSN:
|
||||
return true;
|
||||
switch (intno) {
|
||||
default:
|
||||
return false;
|
||||
case TT_ILL_INSN:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,15 +63,16 @@ static void reg_read(CPUSPARCState *env, unsigned int regid, void *value)
|
||||
else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7)
|
||||
*(int32_t *)value = env->regwptr[regid - UC_SPARC_REG_O0];
|
||||
else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7)
|
||||
*(int32_t *)value = env->regwptr[8 + regid - UC_SPARC_REG_L0];
|
||||
*(int32_t *)value = env->regwptr[8 + regid - UC_SPARC_REG_L0];
|
||||
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 {
|
||||
switch(regid) {
|
||||
default: break;
|
||||
case UC_SPARC_REG_PC:
|
||||
*(int32_t *)value = env->pc;
|
||||
break;
|
||||
switch (regid) {
|
||||
default:
|
||||
break;
|
||||
case UC_SPARC_REG_PC:
|
||||
*(int32_t *)value = env->pc;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -87,21 +88,23 @@ static void reg_write(CPUSPARCState *env, unsigned int regid, const void *value)
|
||||
else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7)
|
||||
env->regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint32_t *)value;
|
||||
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 {
|
||||
switch(regid) {
|
||||
default: break;
|
||||
case UC_SPARC_REG_PC:
|
||||
env->pc = *(uint32_t *)value;
|
||||
env->npc = *(uint32_t *)value + 4;
|
||||
break;
|
||||
switch (regid) {
|
||||
default:
|
||||
break;
|
||||
case UC_SPARC_REG_PC:
|
||||
env->pc = *(uint32_t *)value;
|
||||
env->npc = *(uint32_t *)value + 4;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
int i;
|
||||
@ -115,7 +118,8 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int co
|
||||
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);
|
||||
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];
|
||||
const void *value = vals[i];
|
||||
reg_write(env, regid, value);
|
||||
if( regid == UC_SPARC_REG_PC){
|
||||
if (regid == UC_SPARC_REG_PC) {
|
||||
// force to quit execution and flush TB
|
||||
uc->quit_request = true;
|
||||
uc_emu_stop(uc);
|
||||
@ -136,7 +140,8 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||
}
|
||||
|
||||
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;
|
||||
int i;
|
||||
@ -151,7 +156,8 @@ int sparc_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **va
|
||||
}
|
||||
|
||||
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;
|
||||
int i;
|
||||
@ -177,7 +183,7 @@ static int sparc_cpus_init(struct uc_struct *uc, const char *cpu_model)
|
||||
}
|
||||
|
||||
DEFAULT_VISIBILITY
|
||||
void sparc_uc_init(struct uc_struct* uc)
|
||||
void sparc_uc_init(struct uc_struct *uc)
|
||||
{
|
||||
uc->release = sparc_release;
|
||||
uc->reg_read = sparc_reg_read;
|
||||
|
@ -5,16 +5,22 @@
|
||||
#define UC_QEMU_TARGET_SPARC_H
|
||||
|
||||
// functions to read & write registers
|
||||
int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count);
|
||||
int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count);
|
||||
int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
|
||||
int count);
|
||||
int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
|
||||
int count);
|
||||
|
||||
int sparc_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, 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);
|
||||
int sparc_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,
|
||||
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_uc_init(struct uc_struct* uc);
|
||||
void sparc64_uc_init(struct uc_struct* uc);
|
||||
void sparc_uc_init(struct uc_struct *uc);
|
||||
void sparc64_uc_init(struct uc_struct *uc);
|
||||
#endif
|
||||
|
@ -14,24 +14,24 @@
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
|
||||
USA.
|
||||
|
||||
*/
|
||||
|
||||
#define __STDC_FORMAT_MACROS
|
||||
|
||||
|
||||
#include <unicorn/unicorn.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
|
||||
|
||||
static int insts_executed;
|
||||
|
||||
// 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;
|
||||
unsigned char buf[256];
|
||||
@ -39,61 +39,81 @@ static void hook_code(uc_engine *uc, uint64_t addr, uint32_t size, void *user_da
|
||||
insts_executed++;
|
||||
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
opcode = buf[0];
|
||||
switch (opcode) {
|
||||
case 0x41: // inc ecx
|
||||
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);
|
||||
_exit(-1);
|
||||
}
|
||||
break;
|
||||
case 0x42: // inc edx
|
||||
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);
|
||||
_exit(-1);
|
||||
}
|
||||
break;
|
||||
case 0xf4: // hlt
|
||||
if (uc_emu_stop(uc) != UC_ERR_OK) {
|
||||
printf("not ok - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", addr);
|
||||
_exit(-1);
|
||||
}
|
||||
break;
|
||||
default: // all others
|
||||
break;
|
||||
case 0x41: // inc ecx
|
||||
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);
|
||||
_exit(-1);
|
||||
}
|
||||
break;
|
||||
case 0x42: // inc edx
|
||||
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);
|
||||
_exit(-1);
|
||||
}
|
||||
break;
|
||||
case 0xf4: // hlt
|
||||
if (uc_emu_stop(uc) != UC_ERR_OK) {
|
||||
printf("not ok - uc_emu_stop fail during hook_code callback, addr: "
|
||||
"0x%" PRIx64 "\n",
|
||||
addr);
|
||||
_exit(-1);
|
||||
}
|
||||
break;
|
||||
default: // all others
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// callback for tracing invalid memory access (READ/WRITE/EXEC)
|
||||
static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
|
||||
uint64_t addr, int size, int64_t value, void *user_data)
|
||||
static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type, uint64_t addr,
|
||||
int size, int64_t value, void *user_data)
|
||||
{
|
||||
switch(type) {
|
||||
default:
|
||||
printf("not ok - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", type, addr);
|
||||
return false;
|
||||
case UC_MEM_READ_UNMAPPED:
|
||||
printf("not ok - Read from invalid memory at 0x%"PRIx64 ", data size = %u\n", addr, size);
|
||||
return false;
|
||||
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);
|
||||
return false;
|
||||
case UC_MEM_FETCH_PROT:
|
||||
printf("not ok - Fetch from non-executable memory at 0x%"PRIx64 "\n", addr);
|
||||
return false;
|
||||
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);
|
||||
return false;
|
||||
case UC_MEM_READ_PROT:
|
||||
printf("not ok - Read from non-readable memory at 0x%"PRIx64 ", data size = %u\n", addr, size);
|
||||
return false;
|
||||
switch (type) {
|
||||
default:
|
||||
printf("not ok - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", type,
|
||||
addr);
|
||||
return false;
|
||||
case UC_MEM_READ_UNMAPPED:
|
||||
printf("not ok - Read from invalid memory at 0x%" PRIx64
|
||||
", data size = %u\n",
|
||||
addr, size);
|
||||
return false;
|
||||
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);
|
||||
return false;
|
||||
case UC_MEM_FETCH_PROT:
|
||||
printf("not ok - Fetch from non-executable memory at 0x%" PRIx64 "\n",
|
||||
addr);
|
||||
return false;
|
||||
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);
|
||||
return false;
|
||||
case UC_MEM_READ_PROT:
|
||||
printf("not ok - Read from non-readable memory at 0x%" PRIx64
|
||||
", data size = %u\n",
|
||||
addr, size);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,7 +127,8 @@ static void do_nx_demo(bool cause_fault)
|
||||
insts_executed = 0;
|
||||
|
||||
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
|
||||
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
||||
@ -129,14 +150,16 @@ static void do_nx_demo(bool cause_fault)
|
||||
page2: @2000
|
||||
jmp page1
|
||||
*/
|
||||
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
|
||||
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 + 0x2000, "\xe9\xfb\xef\xff\xff", 5); // jump to 0x101000
|
||||
code_buf[0x1fff] = 0xf4; //hlt
|
||||
code_buf[0x1fff] = 0xf4; // hlt
|
||||
|
||||
if (cause_fault) {
|
||||
// insert instruction to trigger U_PROT_EXEC change (see hook_code function)
|
||||
code_buf[0x1000] = 0x41; // inc ecx at page1
|
||||
// insert instruction to trigger U_PROT_EXEC change (see hook_code
|
||||
// function)
|
||||
code_buf[0x1000] = 0x41; // inc ecx at page1
|
||||
}
|
||||
|
||||
// write machine code to be emulated to memory
|
||||
@ -146,9 +169,10 @@ static void do_nx_demo(bool cause_fault)
|
||||
}
|
||||
|
||||
// intercept code and invalid memory events
|
||||
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK ||
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID,
|
||||
hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) {
|
||||
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, 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");
|
||||
return;
|
||||
}
|
||||
@ -157,7 +181,8 @@ static void do_nx_demo(bool cause_fault)
|
||||
printf("BEGINNING EXECUTION\n");
|
||||
err = uc_emu_start(uc, 0x100000, 0x103000, 0, 0);
|
||||
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");
|
||||
} else {
|
||||
printf("SUCCESSFUL EXECUTION\n");
|
||||
@ -212,11 +237,12 @@ static void do_perms_demo(bool change_perms)
|
||||
*/
|
||||
memcpy(code_buf, WRITE_DEMO, sizeof(WRITE_DEMO) - 1);
|
||||
memset(code_buf + sizeof(WRITE_DEMO) - 1, 0x90, 1000);
|
||||
code_buf[sizeof(WRITE_DEMO) - 1 + 1000] = 0xf4; // hlt
|
||||
code_buf[sizeof(WRITE_DEMO) - 1 + 1000] = 0xf4; // hlt
|
||||
|
||||
if (change_perms) {
|
||||
// write protect memory area [0x101000, 0x101fff]. see hook_code function
|
||||
code_buf[0] = 0x41; // inc ecx
|
||||
// write protect memory area [0x101000, 0x101fff]. see hook_code
|
||||
// function
|
||||
code_buf[0] = 0x41; // inc ecx
|
||||
}
|
||||
|
||||
// write machine code to be emulated to memory
|
||||
@ -226,10 +252,10 @@ static void do_perms_demo(bool change_perms)
|
||||
}
|
||||
|
||||
// intercept code and invalid memory events
|
||||
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK ||
|
||||
uc_hook_add(uc, &trace1,
|
||||
UC_HOOK_MEM_INVALID,
|
||||
hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) {
|
||||
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, 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");
|
||||
return;
|
||||
}
|
||||
@ -239,7 +265,8 @@ static void do_perms_demo(bool change_perms)
|
||||
err = uc_emu_start(uc, 0x100000, 0x103000, 0, 0);
|
||||
if (err != UC_ERR_OK) {
|
||||
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 {
|
||||
printf("SUCCESSFUL EXECUTION\n");
|
||||
}
|
||||
@ -253,11 +280,11 @@ static void perms_test()
|
||||
{
|
||||
printf("Permissions demo - step 1: show that area is writeable\n");
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
static void do_unmap_demo(bool do_unmap)
|
||||
{
|
||||
uc_engine *uc;
|
||||
@ -290,11 +317,11 @@ static void do_unmap_demo(bool do_unmap)
|
||||
*/
|
||||
memcpy(code_buf, WRITE_DEMO, sizeof(WRITE_DEMO) - 1);
|
||||
memset(code_buf + sizeof(WRITE_DEMO) - 1, 0x90, 1000);
|
||||
code_buf[sizeof(WRITE_DEMO) - 1 + 1000] = 0xf4; // hlt
|
||||
code_buf[sizeof(WRITE_DEMO) - 1 + 1000] = 0xf4; // hlt
|
||||
|
||||
if (do_unmap) {
|
||||
// unmap memory area [0x101000, 0x101fff]. see hook_code function
|
||||
code_buf[0] = 0x42; // inc edx (see hook_code function)
|
||||
code_buf[0] = 0x42; // inc edx (see hook_code function)
|
||||
}
|
||||
|
||||
// write machine code to be emulated to memory
|
||||
@ -304,10 +331,10 @@ static void do_unmap_demo(bool do_unmap)
|
||||
}
|
||||
|
||||
// intercept code and invalid memory events
|
||||
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK ||
|
||||
uc_hook_add(uc, &trace1,
|
||||
UC_HOOK_MEM_INVALID,
|
||||
hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) {
|
||||
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, 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");
|
||||
return;
|
||||
}
|
||||
@ -317,7 +344,8 @@ static void do_unmap_demo(bool do_unmap)
|
||||
err = uc_emu_start(uc, 0x100000, 0x103000, 0, 0);
|
||||
if (err != UC_ERR_OK) {
|
||||
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 {
|
||||
printf("SUCCESSFUL EXECUTION\n");
|
||||
}
|
||||
@ -331,7 +359,8 @@ static void unmap_test()
|
||||
{
|
||||
printf("Unmap demo - step 1: show that area is writeable\n");
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -6,29 +6,37 @@
|
||||
#include <unicorn/unicorn.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// code to be emulated
|
||||
// #define ARM_CODE "\x37\x00\xa0\xe3" // mov r0, #0x37
|
||||
#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 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
|
||||
#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 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
|
||||
// memory address where emulation starts
|
||||
#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)
|
||||
@ -37,18 +45,18 @@ static void test_arm(void)
|
||||
uc_err err;
|
||||
uc_hook trace1, trace2;
|
||||
|
||||
int r0 = 0x1234; // R0 register
|
||||
int r2 = 0x6789; // R1 register
|
||||
int r3 = 0x3333; // R2 register
|
||||
int r1; // R1 register
|
||||
int r0 = 0x1234; // R0 register
|
||||
int r2 = 0x6789; // R1 register
|
||||
int r3 = 0x3333; // R2 register
|
||||
int r1; // R1 register
|
||||
|
||||
printf("Emulate ARM code\n");
|
||||
|
||||
// Initialize emulator in ARM mode
|
||||
err = uc_open(UC_ARCH_ARM, UC_MODE_ARM, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -71,7 +79,7 @@ static void test_arm(void)
|
||||
|
||||
// emulate machine code in infinite time (last param = 0), or when
|
||||
// finishing all the code.
|
||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, 0, 0);
|
||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM_CODE) - 1, 0, 0);
|
||||
if (err) {
|
||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||
}
|
||||
@ -93,15 +101,15 @@ static void test_thumb(void)
|
||||
uc_err err;
|
||||
uc_hook trace1, trace2;
|
||||
|
||||
int sp = 0x1234; // R0 register
|
||||
int sp = 0x1234; // R0 register
|
||||
|
||||
printf("Emulate THUMB code\n");
|
||||
|
||||
// Initialize emulator in ARM mode
|
||||
err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -123,7 +131,7 @@ static void test_thumb(void)
|
||||
// emulate machine code in infinite time (last param = 0), or when
|
||||
// finishing all the code.
|
||||
// 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) {
|
||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||
}
|
||||
@ -143,18 +151,18 @@ static void test_armeb(void)
|
||||
uc_err err;
|
||||
uc_hook trace1, trace2;
|
||||
|
||||
int r0 = 0x1234; // R0 register
|
||||
int r2 = 0x6789; // R1 register
|
||||
int r3 = 0x3333; // R2 register
|
||||
int r1; // R1 register
|
||||
int r0 = 0x1234; // R0 register
|
||||
int r2 = 0x6789; // R1 register
|
||||
int r3 = 0x3333; // R2 register
|
||||
int r1; // R1 register
|
||||
|
||||
printf("Emulate ARM Big-Endian code\n");
|
||||
|
||||
// Initialize emulator in ARM mode
|
||||
err = uc_open(UC_ARCH_ARM, UC_MODE_ARM + UC_MODE_BIG_ENDIAN, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -177,7 +185,7 @@ static void test_armeb(void)
|
||||
|
||||
// emulate machine code in infinite time (last param = 0), or when
|
||||
// finishing all the code.
|
||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM_CODE_EB) -1, 0, 0);
|
||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM_CODE_EB) - 1, 0, 0);
|
||||
if (err) {
|
||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||
}
|
||||
@ -199,15 +207,15 @@ static void test_thumbeb(void)
|
||||
uc_err err;
|
||||
uc_hook trace1, trace2;
|
||||
|
||||
int sp = 0x1234; // R0 register
|
||||
int sp = 0x1234; // R0 register
|
||||
|
||||
printf("Emulate THUMB Big-Endian code\n");
|
||||
|
||||
// Initialize emulator in ARM mode
|
||||
err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB + UC_MODE_BIG_ENDIAN, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -229,7 +237,8 @@ static void test_thumbeb(void)
|
||||
// emulate machine code in infinite time (last param = 0), or when
|
||||
// finishing all the code.
|
||||
// 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) {
|
||||
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
|
||||
err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB | UC_MODE_MCLASS, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -288,14 +297,15 @@ static void test_thumb_mrs(void)
|
||||
|
||||
uc_reg_read(uc, UC_ARM_REG_PC, &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);
|
||||
}
|
||||
|
||||
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_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);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
@ -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);
|
||||
|
||||
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) {
|
||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||
}
|
||||
} else {
|
||||
int i, addr = ADDRESS;
|
||||
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) {
|
||||
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);
|
||||
}
|
||||
@ -344,13 +358,13 @@ static void test_thumb_ite_internal(bool step, uint32_t *r2_out, uint32_t *r3_ou
|
||||
*r3_out = r3;
|
||||
}
|
||||
|
||||
static void test_thumb_ite()
|
||||
static void test_thumb_ite()
|
||||
{
|
||||
uint32_t r2, r3;
|
||||
uint32_t step_r2, step_r3;
|
||||
|
||||
printf("Emulate a THUMB ITE block as a whole or per instruction.\n");
|
||||
|
||||
|
||||
// Run once.
|
||||
printf("Running the entire binary.\n");
|
||||
test_thumb_ite_internal(false, &r2, &r3);
|
||||
|
@ -6,48 +6,53 @@
|
||||
#include <unicorn/unicorn.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// 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_EB "\xb8\x00\x05\xab\x38\x40\x05\xaf" // str w11, [x13]; ldrb w15, [x13]
|
||||
#define ARM64_CODE \
|
||||
"\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
|
||||
|
||||
// memory address where emulation starts
|
||||
#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)
|
||||
{
|
||||
uc_engine* uc;
|
||||
uc_engine *uc;
|
||||
uc_err err;
|
||||
uint64_t x1, sp, x0;
|
||||
// msr x0, CurrentEL
|
||||
unsigned char shellcode0[4] = {
|
||||
64, 66, 56, 213
|
||||
};
|
||||
unsigned char shellcode0[4] = {64, 66, 56, 213};
|
||||
// .text:00000000004002C0 LDR X1, [SP,#arg_0]
|
||||
unsigned char shellcode[4] = {
|
||||
0xE1, 0x03, 0x40, 0xF9
|
||||
};
|
||||
unsigned char shellcode[4] = {0xE1, 0x03, 0x40, 0xF9};
|
||||
unsigned shellcode_address = 0x4002C0;
|
||||
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
|
||||
err = uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
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 + 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) {
|
||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||
}
|
||||
|
||||
x0 = 0;
|
||||
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) {
|
||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||
}
|
||||
@ -87,17 +92,17 @@ static void test_arm64(void)
|
||||
uc_err err;
|
||||
uc_hook trace1, trace2;
|
||||
|
||||
int64_t x11 = 0x12345678; // X11 register
|
||||
int64_t x13 = 0x10000 + 0x8; // X13 register
|
||||
int64_t x15 = 0x33; // X15 register
|
||||
int64_t x11 = 0x12345678; // X11 register
|
||||
int64_t x13 = 0x10000 + 0x8; // X13 register
|
||||
int64_t x15 = 0x33; // X15 register
|
||||
|
||||
printf("Emulate ARM64 code\n");
|
||||
|
||||
// Initialize emulator in ARM mode
|
||||
err = uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -120,7 +125,7 @@ static void test_arm64(void)
|
||||
|
||||
// emulate machine code in infinite time (last param = 0), or when
|
||||
// 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) {
|
||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||
}
|
||||
@ -141,17 +146,17 @@ static void test_arm64eb(void)
|
||||
uc_err err;
|
||||
uc_hook trace1, trace2;
|
||||
|
||||
int64_t x11 = 0x12345678; // X11 register
|
||||
int64_t x13 = 0x10000 + 0x8; // X13 register
|
||||
int64_t x15 = 0x33; // X15 register
|
||||
int64_t x11 = 0x12345678; // X11 register
|
||||
int64_t x13 = 0x10000 + 0x8; // X13 register
|
||||
int64_t x15 = 0x33; // X15 register
|
||||
|
||||
printf("Emulate ARM64 Big-Endian code\n");
|
||||
|
||||
// Initialize emulator in ARM mode
|
||||
err = uc_open(UC_ARCH_ARM64, UC_MODE_ARM + UC_MODE_BIG_ENDIAN, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -174,7 +179,7 @@ static void test_arm64eb(void)
|
||||
|
||||
// emulate machine code in infinite time (last param = 0), or when
|
||||
// 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) {
|
||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||
}
|
||||
@ -190,7 +195,7 @@ static void test_arm64eb(void)
|
||||
}
|
||||
|
||||
int main(int argc, char **argv, char **envp)
|
||||
{
|
||||
{
|
||||
test_arm64_mem_fetch();
|
||||
test_arm64();
|
||||
|
||||
|
@ -2,17 +2,15 @@
|
||||
#include <string.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[] = {
|
||||
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};
|
||||
|
||||
uint64_t vals[7] = { 200, 10, 11, 12, 13, 14, 15 };
|
||||
|
||||
// This part of the API is less... clean... because Unicorn supports arbitrary register types.
|
||||
// So the least intrusive solution is passing individual pointers.
|
||||
// On the plus side, you only need to make this pointer array once.
|
||||
// This part of the API is less... clean... because Unicorn supports arbitrary
|
||||
// register types. So the least intrusive solution is passing individual
|
||||
// pointers. On the plus side, you only need to make this pointer array once.
|
||||
void *ptrs[7];
|
||||
|
||||
void uc_perror(const char *func, uc_err err)
|
||||
@ -22,8 +20,12 @@ void uc_perror(const char *func, uc_err err)
|
||||
|
||||
#define BASE 0x10000
|
||||
|
||||
// mov rax, 100; mov rdi, 1; mov rsi, 2; mov rdx, 3; mov r10, 4; mov r8, 5; mov r9, 6; syscall
|
||||
#define CODE "\x48\xc7\xc0\x64\x00\x00\x00\x48\xc7\xc7\x01\x00\x00\x00\x48\xc7\xc6\x02\x00\x00\x00\x48\xc7\xc2\x03\x00\x00\x00\x49\xc7\xc2\x04\x00\x00\x00\x49\xc7\xc0\x05\x00\x00\x00\x49\xc7\xc1\x06\x00\x00\x00\x0f\x05"
|
||||
// mov rax, 100; mov rdi, 1; mov rsi, 2; mov rdx, 3; mov r10, 4; mov r8, 5; mov
|
||||
// r9, 6; syscall
|
||||
#define CODE \
|
||||
"\x48\xc7\xc0\x64\x00\x00\x00\x48\xc7\xc7\x01\x00\x00\x00\x48\xc7\xc6\x02" \
|
||||
"\x00\x00\x00\x48\xc7\xc2\x03\x00\x00\x00\x49\xc7\xc2\x04\x00\x00\x00\x49" \
|
||||
"\xc7\xc0\x05\x00\x00\x00\x49\xc7\xc1\x06\x00\x00\x00\x0f\x05"
|
||||
|
||||
void hook_syscall(uc_engine *uc, void *user_data)
|
||||
{
|
||||
@ -34,7 +36,8 @@ void hook_syscall(uc_engine *uc, void *user_data)
|
||||
printf("syscall: {");
|
||||
|
||||
for (i = 0; i < 7; i++) {
|
||||
if (i != 0) printf(", ");
|
||||
if (i != 0)
|
||||
printf(", ");
|
||||
printf("%" PRIu64, vals[i]);
|
||||
}
|
||||
|
||||
@ -80,7 +83,8 @@ int main()
|
||||
printf("reg_read_batch = {");
|
||||
|
||||
for (i = 0; i < 7; i++) {
|
||||
if (i != 0) printf(", ");
|
||||
if (i != 0)
|
||||
printf(", ");
|
||||
printf("%" PRIu64, vals[i]);
|
||||
}
|
||||
|
||||
@ -90,7 +94,8 @@ int main()
|
||||
printf("\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);
|
||||
return 1;
|
||||
}
|
||||
|
@ -6,21 +6,25 @@
|
||||
#include <unicorn/unicorn.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// code to be emulated
|
||||
#define M68K_CODE "\x76\xed" // movq #-19, %d3
|
||||
|
||||
// memory address where emulation starts
|
||||
#define ADDRESS 0x10000
|
||||
|
||||
static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
||||
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)
|
||||
@ -29,34 +33,34 @@ static void test_m68k(void)
|
||||
uc_hook trace1, trace2;
|
||||
uc_err err;
|
||||
|
||||
int d0 = 0x0000; // d0 data register
|
||||
int d1 = 0x0000; // d1 data register
|
||||
int d2 = 0x0000; // d2 data register
|
||||
int d3 = 0x0000; // d3 data register
|
||||
int d4 = 0x0000; // d4 data register
|
||||
int d5 = 0x0000; // d5 data register
|
||||
int d6 = 0x0000; // d6 data register
|
||||
int d7 = 0x0000; // d7 data register
|
||||
int d0 = 0x0000; // d0 data register
|
||||
int d1 = 0x0000; // d1 data register
|
||||
int d2 = 0x0000; // d2 data register
|
||||
int d3 = 0x0000; // d3 data register
|
||||
int d4 = 0x0000; // d4 data register
|
||||
int d5 = 0x0000; // d5 data register
|
||||
int d6 = 0x0000; // d6 data register
|
||||
int d7 = 0x0000; // d7 data register
|
||||
|
||||
int a0 = 0x0000; // a0 address register
|
||||
int a1 = 0x0000; // a1 address register
|
||||
int a2 = 0x0000; // a2 address register
|
||||
int a3 = 0x0000; // a3 address register
|
||||
int a4 = 0x0000; // a4 address register
|
||||
int a5 = 0x0000; // a5 address register
|
||||
int a6 = 0x0000; // a6 address register
|
||||
int a7 = 0x0000; // a6 address register
|
||||
int a0 = 0x0000; // a0 address register
|
||||
int a1 = 0x0000; // a1 address register
|
||||
int a2 = 0x0000; // a2 address register
|
||||
int a3 = 0x0000; // a3 address register
|
||||
int a4 = 0x0000; // a4 address register
|
||||
int a5 = 0x0000; // a5 address register
|
||||
int a6 = 0x0000; // a6 address register
|
||||
int a7 = 0x0000; // a6 address register
|
||||
|
||||
int pc = 0x0000; // program counter
|
||||
int sr = 0x0000; // status register
|
||||
int pc = 0x0000; // program counter
|
||||
int sr = 0x0000; // status register
|
||||
|
||||
printf("Emulate M68K code\n");
|
||||
|
||||
// Initialize emulator in M68K mode
|
||||
err = uc_open(UC_ARCH_M68K, UC_MODE_BIG_ENDIAN, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -96,7 +100,7 @@ static void test_m68k(void)
|
||||
|
||||
// emulate machine code in infinite time (last param = 0), or when
|
||||
// finishing all the code.
|
||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(M68K_CODE)-1, 0, 0);
|
||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(M68K_CODE) - 1, 0, 0);
|
||||
if (err) {
|
||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||
}
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include <unicorn/unicorn.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// code to be emulated
|
||||
#define MIPS_CODE_EB "\x34\x21\x34\x56" // ori $at, $at, 0x3456;
|
||||
#define MIPS_CODE_EL "\x56\x34\x21\x34" // ori $at, $at, 0x3456;
|
||||
@ -14,14 +13,19 @@
|
||||
// memory address where emulation starts
|
||||
#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)
|
||||
@ -30,15 +34,15 @@ static void test_mips_eb(void)
|
||||
uc_err err;
|
||||
uc_hook trace1, trace2;
|
||||
|
||||
int r1 = 0x6789; // R1 register
|
||||
int r1 = 0x6789; // R1 register
|
||||
|
||||
printf("Emulate MIPS code (big-endian)\n");
|
||||
|
||||
// Initialize emulator in MIPS mode
|
||||
err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -61,7 +65,8 @@ static void test_mips_eb(void)
|
||||
// finishing all the code.
|
||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(MIPS_CODE_EB) - 1, 0, 0);
|
||||
if (err) {
|
||||
printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err, uc_strerror(err));
|
||||
printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
}
|
||||
|
||||
// now print out some registers
|
||||
@ -79,7 +84,7 @@ static void test_mips_el(void)
|
||||
uc_err err;
|
||||
uc_hook trace1, trace2;
|
||||
|
||||
int r1 = 0x6789; // R1 register
|
||||
int r1 = 0x6789; // R1 register
|
||||
|
||||
printf("===========================\n");
|
||||
printf("Emulate MIPS code (little-endian)\n");
|
||||
@ -87,8 +92,8 @@ static void test_mips_el(void)
|
||||
// Initialize emulator in MIPS mode
|
||||
err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -111,7 +116,8 @@ static void test_mips_el(void)
|
||||
// finishing all the code.
|
||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(MIPS_CODE_EL) - 1, 0, 0);
|
||||
if (err) {
|
||||
printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err, uc_strerror(err));
|
||||
printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
}
|
||||
|
||||
// now print out some registers
|
||||
|
@ -6,22 +6,25 @@
|
||||
#include <unicorn/unicorn.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// code to be emulated
|
||||
#define PPC_CODE "\x7F\x46\x1A\x14" // add r26, r6, r3
|
||||
|
||||
// memory address where emulation starts
|
||||
#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_ppc(void)
|
||||
@ -30,17 +33,17 @@ static void test_ppc(void)
|
||||
uc_err err;
|
||||
uc_hook trace1, trace2;
|
||||
|
||||
int r3 = 0x1234; // R3 register
|
||||
int r6 = 0x6789; // R6 register
|
||||
int r26 = 0x8877; // R26 register (result)
|
||||
int r3 = 0x1234; // R3 register
|
||||
int r6 = 0x6789; // R6 register
|
||||
int r26 = 0x8877; // R26 register (result)
|
||||
|
||||
printf("Emulate PPC code\n");
|
||||
|
||||
// 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) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -63,7 +66,7 @@ static void test_ppc(void)
|
||||
|
||||
// emulate machine code in infinite time (last param = 0), or when
|
||||
// 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) {
|
||||
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||
return;
|
||||
@ -79,7 +82,6 @@ static void test_ppc(void)
|
||||
uc_close(uc);
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv, char **envp)
|
||||
{
|
||||
test_ppc();
|
||||
|
@ -5,7 +5,6 @@
|
||||
#include <unicorn/unicorn.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// code to be emulated
|
||||
#if 0
|
||||
$ 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"
|
||||
|
||||
|
||||
// memory address where emulation starts
|
||||
#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) {
|
||||
printf("stop emulation\n");
|
||||
uc_emu_stop(uc);
|
||||
@ -52,8 +58,8 @@ static void test_riscv(void)
|
||||
// Initialize emulator in RISCV64 mode
|
||||
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -106,8 +112,8 @@ static void test_riscv2(void)
|
||||
// Initialize emulator in RISCV64 mode
|
||||
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -171,8 +177,8 @@ static void test_riscv3(void)
|
||||
// Initialize emulator in RISCV64 mode
|
||||
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -226,8 +232,8 @@ static void test_riscv_step(void)
|
||||
// Initialize emulator in RISCV64 mode
|
||||
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -297,8 +303,8 @@ static void test_riscv_timeout(void)
|
||||
// Initialize emulator in RISCV64 mode
|
||||
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV32, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -365,8 +371,8 @@ static void test_riscv_sd64(void)
|
||||
// Initialize emulator in RISCV64 mode
|
||||
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV64, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -401,13 +407,14 @@ static void test_riscv_sd64(void)
|
||||
}
|
||||
|
||||
static bool hook_memalloc(uc_engine *uc, uc_mem_type type, uint64_t address,
|
||||
int size, int64_t value, void *user_data)
|
||||
int size, int64_t value, void *user_data)
|
||||
{
|
||||
uint64_t algined_address = address & 0xFFFFFFFFFFFFF000ULL;
|
||||
int aligned_size = ((int)(size / 0x1000) + 1) * 0x1000;
|
||||
|
||||
printf(">>> Allocating block at 0x%" PRIx64 " (0x%" PRIx64 "), block size = 0x%x (0x%x)\n",
|
||||
address, algined_address, size, aligned_size);
|
||||
printf(">>> Allocating block at 0x%" PRIx64 " (0x%" PRIx64
|
||||
"), block size = 0x%x (0x%x)\n",
|
||||
address, algined_address, size, aligned_size);
|
||||
|
||||
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);
|
||||
|
||||
// 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
|
||||
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_A1, &a1);
|
||||
|
||||
printf(">>> A0 = 0x%"PRIx64 "\n", a0);
|
||||
printf(">>> A1 = 0x%"PRIx64 "\n", a1);
|
||||
printf(">>> A0 = 0x%" PRIx64 "\n", a0);
|
||||
printf(">>> A1 = 0x%" PRIx64 "\n", a1);
|
||||
|
||||
uc_close(uc);
|
||||
}
|
||||
@ -495,8 +503,8 @@ static void test_riscv_func_return(void)
|
||||
// Initialize emulator in RISCV64 mode
|
||||
err = uc_open(UC_ARCH_RISCV, UC_MODE_RISCV64, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -527,7 +535,9 @@ static void test_riscv_func_return(void)
|
||||
|
||||
uc_reg_read(uc, UC_RISCV_REG_PC, &pc);
|
||||
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) {
|
||||
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);
|
||||
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) {
|
||||
printf(" PC did not change during execution\n");
|
||||
}
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include <unicorn/unicorn.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// code to be emulated
|
||||
#define SPARC_CODE "\x86\x00\x40\x02" // add %g1, %g2, %g3;
|
||||
//#define SPARC_CODE "\xbb\x70\x00\x00" // illegal code
|
||||
@ -14,14 +13,19 @@
|
||||
// memory address where emulation starts
|
||||
#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)
|
||||
@ -30,17 +34,17 @@ static void test_sparc(void)
|
||||
uc_err err;
|
||||
uc_hook trace1, trace2;
|
||||
|
||||
int g1 = 0x1230; // G1 register
|
||||
int g2 = 0x6789; // G2 register
|
||||
int g3 = 0x5555; // G3 register
|
||||
int g1 = 0x1230; // G1 register
|
||||
int g2 = 0x6789; // G2 register
|
||||
int g3 = 0x5555; // G3 register
|
||||
|
||||
printf("Emulate SPARC code\n");
|
||||
|
||||
// Initialize emulator in Sparc mode
|
||||
err = uc_open(UC_ARCH_SPARC, UC_MODE_SPARC32|UC_MODE_BIG_ENDIAN, &uc);
|
||||
err = uc_open(UC_ARCH_SPARC, UC_MODE_SPARC32 | UC_MODE_BIG_ENDIAN, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
return;
|
||||
}
|
||||
|
||||
@ -65,8 +69,8 @@ static void test_sparc(void)
|
||||
// finishing all the code.
|
||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(SPARC_CODE) - 1, 0, 0);
|
||||
if (err) {
|
||||
printf("Failed on uc_emu_start() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err,
|
||||
uc_strerror(err));
|
||||
}
|
||||
|
||||
// now print out some registers
|
||||
|
@ -6,27 +6,45 @@
|
||||
#include <unicorn/unicorn.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// code to be emulated
|
||||
#define X86_CODE32 "\x41\x4a\x66\x0f\xef\xc1" // INC ecx; DEC edx; PXOR xmm0, xmm1
|
||||
#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 \
|
||||
"\x41\x4a\x66\x0f\xef\xc1" // INC ecx; DEC edx; PXOR xmm0, xmm1
|
||||
#define X86_CODE32_JUMP \
|
||||
"\xeb\x02\x90\x90\x90\x90\x90\x90" // jmp 4; nop; nop; nop; nop; nop; nop
|
||||
// #define X86_CODE32_SELF
|
||||
// "\xeb\x1c\x5a\x89\xd6\x8b\x02\x66\x3d\xca\x7d\x75\x06\x66\x05\x03\x03\x89\x02\xfe\xc2\x3d\x41\x41\x41\x41\x75\xe9\xff\xe6\xe8\xdf\xff\xff\xff\x31\xd2\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xca\x7d\x41\x41\x41\x41"
|
||||
//#define X86_CODE32 "\x51\x51\x51\x51" // PUSH ecx;
|
||||
#define X86_CODE32_LOOP "\x41\x4a\xeb\xfe" // INC ecx; DEC edx; JMP self-loop
|
||||
#define X86_CODE32_MEM_WRITE "\x89\x0D\xAA\xAA\xAA\xAA\x41\x4a" // mov [0xaaaaaaaa], ecx; INC ecx; DEC edx
|
||||
#define X86_CODE32_MEM_READ "\x8B\x0D\xAA\xAA\xAA\xAA\x41\x4a" // mov ecx,[0xaaaaaaaa]; INC ecx; DEC edx
|
||||
#define X86_CODE32_MEM_READ_IN_TB "\x40\x8b\x1d\x00\x00\x10\x00\x42" // inc eax; mov ebx, [0x100000]; inc edx
|
||||
#define X86_CODE32_MEM_WRITE \
|
||||
"\x89\x0D\xAA\xAA\xAA\xAA\x41\x4a" // mov [0xaaaaaaaa], ecx; INC ecx; DEC
|
||||
// edx
|
||||
#define X86_CODE32_MEM_READ \
|
||||
"\x8B\x0D\xAA\xAA\xAA\xAA\x41\x4a" // mov ecx,[0xaaaaaaaa]; INC ecx; DEC edx
|
||||
#define X86_CODE32_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_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_JMP_INVALID \
|
||||
"\xe9\xe9\xee\xee\xee\x41\x4a" // JMP outside; INC ecx; DEC edx
|
||||
#define X86_CODE32_INOUT \
|
||||
"\x41\xE4\x3F\x4a\xE6\x46\x43" // INC ecx; IN AL, 0x3f; DEC edx; OUT 0x46,
|
||||
// AL; INC ebx
|
||||
#define X86_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\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9"
|
||||
#define X86_CODE64 "\x41\xBC\x3B\xB0\x28\x2A\x49\x0F\xC9\x90\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9\x4D\x29\xF4\x49\x81\xC9\xF6\x8A\xC6\x53\x4D\x87\xED\x48\x0F\xAD\xD2\x49\xF7\xD4\x48\xF7\xE1\x4D\x19\xC5\x4D\x89\xC5\x48\xF7\xD6\x41\xB8\x4F\x8D\x6B\x59\x4D\x87\xD0\x68\x6A\x1E\x09\x3C\x59"
|
||||
#define X86_CODE16 "\x00\x00" // add byte ptr [bx + si], al
|
||||
//#define X86_CODE64 "\x41\xBC\x3B\xB0\x28\x2A \x49\x0F\xC9 \x90
|
||||
//\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9" //
|
||||
//<== still crash #define X86_CODE64
|
||||
//"\x41\xBC\x3B\xB0\x28\x2A\x49\x0F\xC9\x90\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9"
|
||||
#define X86_CODE64 \
|
||||
"\x41\xBC\x3B\xB0\x28\x2A\x49\x0F\xC9\x90\x4D\x0F\xAD\xCF\x49\x87\xFD\x90" \
|
||||
"\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9\x4D\x29\xF4\x49\x81\xC9\xF6\x8A" \
|
||||
"\xC6\x53\x4D\x87\xED\x48\x0F\xAD\xD2\x49\xF7\xD4\x48\xF7\xE1\x4D\x19\xC5" \
|
||||
"\x4D\x89\xC5\x48\xF7\xD6\x41\xB8\x4F\x8D\x6B\x59\x4D\x87\xD0\x68\x6A\x1E" \
|
||||
"\x09\x3C\x59"
|
||||
#define X86_CODE16 "\x00\x00" // add byte ptr [bx + si], al
|
||||
#define X86_CODE64_SYSCALL "\x0f\x05" // SYSCALL
|
||||
#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
|
||||
* 0x1003 dw 0x3ea98b13
|
||||
@ -37,16 +55,21 @@
|
||||
#define ADDRESS 0x1000000
|
||||
|
||||
// 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
|
||||
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;
|
||||
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);
|
||||
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
|
||||
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;
|
||||
|
||||
uc_reg_read(uc, UC_X86_REG_RIP, &rip);
|
||||
printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size);
|
||||
printf(">>> RIP is 0x%"PRIx64 "\n", rip);
|
||||
printf(">>> Tracing instruction at 0x%" PRIx64
|
||||
", instruction size = 0x%x\n",
|
||||
address, size);
|
||||
printf(">>> RIP is 0x%" PRIx64 "\n", rip);
|
||||
|
||||
// Uncomment below code to stop the emulation using uc_emu_stop()
|
||||
// if (address == 0x1000009)
|
||||
@ -71,44 +97,48 @@ static void hook_code64(uc_engine *uc, uint64_t address, uint32_t size, void *us
|
||||
}
|
||||
|
||||
// callback for tracing memory access (READ or WRITE)
|
||||
static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
|
||||
uint64_t address, int size, int64_t value, void *user_data)
|
||||
static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type, uint64_t address,
|
||||
int size, int64_t value, void *user_data)
|
||||
{
|
||||
switch(type) {
|
||||
default:
|
||||
// return false to indicate we want to stop emulation
|
||||
return false;
|
||||
case UC_MEM_WRITE_UNMAPPED:
|
||||
printf(">>> Missing memory is being WRITE at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n",
|
||||
address, size, value);
|
||||
// map this memory in with 2MB in size
|
||||
uc_mem_map(uc, 0xaaaa0000, 2 * 1024*1024, UC_PROT_ALL);
|
||||
// return true to indicate we want to continue
|
||||
return true;
|
||||
switch (type) {
|
||||
default:
|
||||
// return false to indicate we want to stop emulation
|
||||
return false;
|
||||
case UC_MEM_WRITE_UNMAPPED:
|
||||
printf(">>> Missing memory is being WRITE at 0x%" PRIx64
|
||||
", data size = %u, data value = 0x%" PRIx64 "\n",
|
||||
address, size, value);
|
||||
// map this memory in with 2MB in size
|
||||
uc_mem_map(uc, 0xaaaa0000, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||
// return true to indicate we want to continue
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// dummy callback
|
||||
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
|
||||
return false;
|
||||
}
|
||||
|
||||
static void hook_mem64(uc_engine *uc, uc_mem_type type,
|
||||
uint64_t address, int size, int64_t value, void *user_data)
|
||||
static void hook_mem64(uc_engine *uc, uc_mem_type type, uint64_t address,
|
||||
int size, int64_t value, void *user_data)
|
||||
{
|
||||
switch(type) {
|
||||
default: break;
|
||||
case UC_MEM_READ:
|
||||
printf(">>> Memory is being READ at 0x%"PRIx64 ", data size = %u\n",
|
||||
address, size);
|
||||
break;
|
||||
case UC_MEM_WRITE:
|
||||
printf(">>> Memory is being WRITE at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n",
|
||||
address, size, value);
|
||||
break;
|
||||
switch (type) {
|
||||
default:
|
||||
break;
|
||||
case UC_MEM_READ:
|
||||
printf(">>> Memory is being READ at 0x%" PRIx64 ", data size = %u\n",
|
||||
address, size);
|
||||
break;
|
||||
case UC_MEM_WRITE:
|
||||
printf(">>> Memory is being WRITE at 0x%" PRIx64
|
||||
", data size = %u, data value = 0x%" PRIx64 "\n",
|
||||
address, size, value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -120,47 +150,50 @@ 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);
|
||||
|
||||
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) {
|
||||
default:
|
||||
return 0; // should never reach this
|
||||
case 1:
|
||||
// read 1 byte to AL
|
||||
return 0xf1;
|
||||
case 2:
|
||||
// read 2 byte to AX
|
||||
return 0xf2;
|
||||
break;
|
||||
case 4:
|
||||
// read 4 byte to EAX
|
||||
return 0xf4;
|
||||
switch (size) {
|
||||
default:
|
||||
return 0; // should never reach this
|
||||
case 1:
|
||||
// read 1 byte to AL
|
||||
return 0xf1;
|
||||
case 2:
|
||||
// read 2 byte to AX
|
||||
return 0xf2;
|
||||
break;
|
||||
case 4:
|
||||
// read 4 byte to EAX
|
||||
return 0xf4;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 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
|
||||
switch(size) {
|
||||
default:
|
||||
return; // should never reach this
|
||||
case 1:
|
||||
uc_reg_read(uc, UC_X86_REG_AL, &tmp);
|
||||
break;
|
||||
case 2:
|
||||
uc_reg_read(uc, UC_X86_REG_AX, &tmp);
|
||||
break;
|
||||
case 4:
|
||||
uc_reg_read(uc, UC_X86_REG_EAX, &tmp);
|
||||
break;
|
||||
switch (size) {
|
||||
default:
|
||||
return; // should never reach this
|
||||
case 1:
|
||||
uc_reg_read(uc, UC_X86_REG_AL, &tmp);
|
||||
break;
|
||||
case 2:
|
||||
uc_reg_read(uc, UC_X86_REG_AX, &tmp);
|
||||
break;
|
||||
case 4:
|
||||
uc_reg_read(uc, UC_X86_REG_EAX, &tmp);
|
||||
break;
|
||||
}
|
||||
|
||||
printf("--- register value = 0x%x\n", tmp);
|
||||
@ -176,17 +209,18 @@ static void hook_syscall(uc_engine *uc, void *user_data)
|
||||
rax = 0x200;
|
||||
uc_reg_write(uc, UC_X86_REG_RAX, &rax);
|
||||
} 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,
|
||||
int size, int64_t value, void *user_data)
|
||||
int size, int64_t value, void *user_data)
|
||||
{
|
||||
uint64_t algined_address = address & 0xFFFFFFFFFFFFF000ULL;
|
||||
int aligned_size = ((int)(size / 0x1000) + 1) * 0x1000;
|
||||
|
||||
printf(">>> Allocating block at 0x%" PRIx64 " (0x%" PRIx64 "), block size = 0x%x (0x%x)\n",
|
||||
address, algined_address, size, aligned_size);
|
||||
printf(">>> Allocating block at 0x%" PRIx64 " (0x%" PRIx64
|
||||
"), block size = 0x%x (0x%x)\n",
|
||||
address, algined_address, size, aligned_size);
|
||||
|
||||
uc_mem_map(uc, algined_address, aligned_size, UC_PROT_ALL);
|
||||
|
||||
@ -206,8 +240,8 @@ static void test_miss_code(void)
|
||||
uc_err err;
|
||||
uc_hook trace1, trace2;
|
||||
|
||||
int r_ecx = 0x1234; // ECX register
|
||||
int r_edx = 0x7890; // EDX register
|
||||
int r_ecx = 0x1234; // ECX register
|
||||
int r_edx = 0x7890; // EDX register
|
||||
|
||||
printf("Emulate i386 code - missing code\n");
|
||||
|
||||
@ -231,8 +265,8 @@ static void test_miss_code(void)
|
||||
// emulate machine code, without having the code in yet
|
||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0);
|
||||
if (err) {
|
||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||
uc_strerror(err));
|
||||
}
|
||||
|
||||
// now print out some registers
|
||||
@ -253,8 +287,8 @@ static void test_i386(void)
|
||||
uint32_t tmp;
|
||||
uc_hook trace1, trace2;
|
||||
|
||||
int r_ecx = 0x1234; // ECX register
|
||||
int r_edx = 0x7890; // EDX register
|
||||
int r_ecx = 0x1234; // ECX register
|
||||
int r_edx = 0x7890; // EDX register
|
||||
// XMM0 and XMM1 registers, low qword then high qword
|
||||
uint64_t r_xmm0[2] = {0x08090a0b0c0d0e0f, 0x0001020304050607};
|
||||
uint64_t r_xmm1[2] = {0x8090a0b0c0d0e0f0, 0x0010203040506070};
|
||||
@ -292,8 +326,8 @@ static void test_i386(void)
|
||||
// emulate machine code in infinite time
|
||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0);
|
||||
if (err) {
|
||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||
uc_strerror(err));
|
||||
}
|
||||
|
||||
// now print out some registers
|
||||
@ -304,7 +338,7 @@ static void test_i386(void)
|
||||
uc_reg_read(uc, UC_X86_REG_XMM0, &r_xmm0);
|
||||
printf(">>> ECX = 0x%x\n", r_ecx);
|
||||
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
|
||||
if (!uc_mem_read(uc, ADDRESS, &tmp, sizeof(tmp)))
|
||||
@ -323,8 +357,8 @@ static void test_i386_map_ptr(void)
|
||||
uc_hook trace1, trace2;
|
||||
void *mem;
|
||||
|
||||
int r_ecx = 0x1234; // ECX register
|
||||
int r_edx = 0x7890; // EDX register
|
||||
int r_ecx = 0x1234; // ECX register
|
||||
int r_edx = 0x7890; // EDX register
|
||||
|
||||
printf("===================================\n");
|
||||
printf("Emulate i386 code - use uc_mem_map_ptr()\n");
|
||||
@ -364,8 +398,8 @@ static void test_i386_map_ptr(void)
|
||||
// emulate machine code in infinite time
|
||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0);
|
||||
if (err) {
|
||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||
uc_strerror(err));
|
||||
}
|
||||
|
||||
// now print out some registers
|
||||
@ -407,7 +441,7 @@ static void test_i386_jump(void)
|
||||
|
||||
// write machine code to be emulated to memory
|
||||
if (uc_mem_write(uc, ADDRESS, X86_CODE32_JUMP,
|
||||
sizeof(X86_CODE32_JUMP) - 1)) {
|
||||
sizeof(X86_CODE32_JUMP) - 1)) {
|
||||
printf("Failed to write emulation code to memory, quit!\n");
|
||||
return;
|
||||
}
|
||||
@ -419,10 +453,11 @@ static void test_i386_jump(void)
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS);
|
||||
|
||||
// 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) {
|
||||
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));
|
||||
}
|
||||
|
||||
printf(">>> Emulation done. Below is the CPU context\n");
|
||||
@ -436,8 +471,8 @@ static void test_i386_loop(void)
|
||||
uc_engine *uc;
|
||||
uc_err err;
|
||||
|
||||
int r_ecx = 0x1234; // ECX register
|
||||
int r_edx = 0x7890; // EDX register
|
||||
int r_ecx = 0x1234; // ECX register
|
||||
int r_edx = 0x7890; // EDX register
|
||||
|
||||
printf("===================================\n");
|
||||
printf("Emulate i386 code that loop forever\n");
|
||||
@ -453,7 +488,8 @@ static void test_i386_loop(void)
|
||||
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||
|
||||
// write machine code to be emulated to memory
|
||||
if (uc_mem_write(uc, ADDRESS, X86_CODE32_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");
|
||||
return;
|
||||
}
|
||||
@ -464,10 +500,11 @@ static void test_i386_loop(void)
|
||||
|
||||
// emulate machine code in 2 seconds, so we can quit even
|
||||
// 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) {
|
||||
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
|
||||
@ -488,8 +525,8 @@ static void test_i386_invalid_mem_read(void)
|
||||
uc_err err;
|
||||
uc_hook trace1, trace2;
|
||||
|
||||
int r_ecx = 0x1234; // ECX register
|
||||
int r_edx = 0x7890; // EDX register
|
||||
int r_ecx = 0x1234; // ECX register
|
||||
int r_edx = 0x7890; // EDX register
|
||||
|
||||
printf("===================================\n");
|
||||
printf("Emulate i386 code that read from invalid memory\n");
|
||||
@ -505,7 +542,8 @@ static void test_i386_invalid_mem_read(void)
|
||||
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||
|
||||
// write machine code to be emulated to memory
|
||||
if (uc_mem_write(uc, ADDRESS, X86_CODE32_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");
|
||||
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);
|
||||
|
||||
// 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) {
|
||||
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
|
||||
@ -546,8 +585,8 @@ static void test_i386_invalid_mem_write(void)
|
||||
uc_hook trace1, trace2, trace3;
|
||||
uint32_t tmp;
|
||||
|
||||
int r_ecx = 0x1234; // ECX register
|
||||
int r_edx = 0x7890; // EDX register
|
||||
int r_ecx = 0x1234; // ECX register
|
||||
int r_edx = 0x7890; // EDX register
|
||||
|
||||
printf("===================================\n");
|
||||
printf("Emulate i386 code that write to invalid memory\n");
|
||||
@ -563,7 +602,8 @@ static void test_i386_invalid_mem_write(void)
|
||||
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||
|
||||
// write machine code to be emulated to memory
|
||||
if (uc_mem_write(uc, ADDRESS, X86_CODE32_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");
|
||||
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);
|
||||
|
||||
// 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
|
||||
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) {
|
||||
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
|
||||
@ -617,8 +660,8 @@ static void test_i386_jump_invalid(void)
|
||||
uc_err err;
|
||||
uc_hook trace1, trace2;
|
||||
|
||||
int r_ecx = 0x1234; // ECX register
|
||||
int r_edx = 0x7890; // EDX register
|
||||
int r_ecx = 0x1234; // ECX register
|
||||
int r_edx = 0x7890; // EDX register
|
||||
|
||||
printf("===================================\n");
|
||||
printf("Emulate i386 code that jumps to invalid memory\n");
|
||||
@ -634,7 +677,8 @@ static void test_i386_jump_invalid(void)
|
||||
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||
|
||||
// write machine code to be emulated to memory
|
||||
if (uc_mem_write(uc, ADDRESS, X86_CODE32_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");
|
||||
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);
|
||||
|
||||
// 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) {
|
||||
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
|
||||
@ -673,9 +718,8 @@ static void test_i386_inout(void)
|
||||
uc_err err;
|
||||
uc_hook trace1, trace2, trace3, trace4;
|
||||
|
||||
|
||||
int r_eax = 0x1234; // EAX register
|
||||
int r_ecx = 0x6789; // ECX register
|
||||
int r_eax = 0x1234; // EAX register
|
||||
int r_ecx = 0x6789; // ECX register
|
||||
|
||||
printf("===================================\n");
|
||||
printf("Emulate i386 code with IN/OUT instructions\n");
|
||||
@ -691,7 +735,8 @@ static void test_i386_inout(void)
|
||||
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||
|
||||
// write machine code to be emulated to memory
|
||||
if (uc_mem_write(uc, ADDRESS, X86_CODE32_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");
|
||||
return;
|
||||
}
|
||||
@ -709,13 +754,15 @@ static void test_i386_inout(void)
|
||||
// uc IN instruction
|
||||
uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_in, NULL, 1, 0, UC_X86_INS_IN);
|
||||
// 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
|
||||
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) {
|
||||
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
|
||||
@ -736,7 +783,7 @@ static void test_i386_context_save(void)
|
||||
uc_context *context;
|
||||
uc_err err;
|
||||
|
||||
int r_eax = 0x1; // EAX register
|
||||
int r_eax = 0x1; // EAX register
|
||||
|
||||
printf("===================================\n");
|
||||
printf("Save/restore CPU context in opaque blob\n");
|
||||
@ -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);
|
||||
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
|
||||
@ -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);
|
||||
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
|
||||
@ -830,7 +877,8 @@ static void test_i386_context_save(void)
|
||||
}
|
||||
|
||||
// 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);
|
||||
printf(">>> EAX = 0x%x\n", r_eax);
|
||||
@ -928,7 +976,6 @@ static void test_x86_64(void)
|
||||
|
||||
int64_t rsp = ADDRESS + 0x200000;
|
||||
|
||||
|
||||
printf("Emulate x86_64 code\n");
|
||||
|
||||
// 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);
|
||||
|
||||
// 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)
|
||||
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.
|
||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE64) - 1, 0, 0);
|
||||
if (err) {
|
||||
printf("Failed on uc_emu_start() with error returned %u: %s\n",
|
||||
err, uc_strerror(err));
|
||||
printf("Failed on uc_emu_start() with error returned %u: %s\n", err,
|
||||
uc_strerror(err));
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
// 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");
|
||||
return;
|
||||
}
|
||||
|
||||
// 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
|
||||
uc_reg_write(uc, UC_X86_REG_RAX, &rax);
|
||||
|
||||
// emulate machine code in infinite time (last param = 0), or when
|
||||
// finishing all the code.
|
||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE64_SYSCALL) - 1, 0, 0);
|
||||
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE64_SYSCALL) - 1, 0,
|
||||
0);
|
||||
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
|
||||
@ -1109,8 +1160,8 @@ static void test_x86_16(void)
|
||||
// finishing all the code.
|
||||
err = uc_emu_start(uc, 0, sizeof(X86_CODE16) - 1, 0, 0);
|
||||
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
|
||||
@ -1131,12 +1182,13 @@ static void test_i386_invalid_mem_read_in_tb(void)
|
||||
uc_err err;
|
||||
uc_hook trace1;
|
||||
|
||||
int r_eax = 0x1234; // EAX register
|
||||
int r_edx = 0x7890; // EDX register
|
||||
int r_eax = 0x1234; // EAX register
|
||||
int r_edx = 0x7890; // EDX register
|
||||
int r_eip = 0;
|
||||
|
||||
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
|
||||
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);
|
||||
|
||||
// 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");
|
||||
return;
|
||||
}
|
||||
@ -1159,13 +1212,15 @@ static void test_i386_invalid_mem_read_in_tb(void)
|
||||
uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
|
||||
|
||||
// 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.
|
||||
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) {
|
||||
printf("uc_emu_start() failed BY DESIGN with error returned %u: %s\n",
|
||||
err, uc_strerror(err));
|
||||
err, uc_strerror(err));
|
||||
}
|
||||
|
||||
printf(">>> Emulation done. Below is the CPU context\n");
|
||||
@ -1174,21 +1229,24 @@ static void test_i386_invalid_mem_read_in_tb(void)
|
||||
printf(">>> EIP = 0x%x\n", r_eip);
|
||||
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
|
||||
static void test_i386_smc_xor()
|
||||
static void test_i386_smc_xor()
|
||||
{
|
||||
uc_engine *uc;
|
||||
uc_err err;
|
||||
|
||||
uint32_t r_edi = ADDRESS; // ECX register
|
||||
uint32_t r_eax = 0xbc4177e6; // EDX register
|
||||
uint32_t r_edi = ADDRESS; // ECX register
|
||||
uint32_t r_eax = 0xbc4177e6; // EDX register
|
||||
uint32_t result;
|
||||
|
||||
printf("===================================\n");
|
||||
@ -1216,15 +1274,15 @@ static void test_i386_smc_xor()
|
||||
|
||||
// **Important Note**
|
||||
//
|
||||
// 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
|
||||
// use count to control the emulation, the count should be set to 2.
|
||||
// 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 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, 0, 0, 2);
|
||||
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));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
|
||||
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.
|
||||
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;
|
||||
}
|
||||
|
||||
static void test_i386_mmio()
|
||||
{
|
||||
uc_engine* uc;
|
||||
uc_engine *uc;
|
||||
int r_ecx = 0xdeadbeef;
|
||||
uc_err err;
|
||||
|
||||
@ -1283,7 +1349,8 @@ static void test_i386_mmio()
|
||||
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) {
|
||||
printf("Failed on uc_mmio_map() with error returned: %u\n", err);
|
||||
return;
|
||||
@ -1314,8 +1381,7 @@ int main(int argc, char **argv, char **envp)
|
||||
if (argc == 2) {
|
||||
if (!strcmp(argv[1], "-16")) {
|
||||
test_x86_16();
|
||||
}
|
||||
else if (!strcmp(argv[1], "-32")) {
|
||||
} else if (!strcmp(argv[1], "-32")) {
|
||||
test_miss_code();
|
||||
test_i386();
|
||||
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_write();
|
||||
test_i386_jump_invalid();
|
||||
//test_i386_invalid_c6c7();
|
||||
}
|
||||
else if (!strcmp(argv[1], "-64")) {
|
||||
// test_i386_invalid_c6c7();
|
||||
} else if (!strcmp(argv[1], "-64")) {
|
||||
test_x86_64();
|
||||
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]);
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
test_x86_16();
|
||||
test_miss_code();
|
||||
test_i386();
|
||||
@ -1348,7 +1411,7 @@ int main(int argc, char **argv, char **envp)
|
||||
test_i386_invalid_mem_read();
|
||||
test_i386_invalid_mem_write();
|
||||
test_i386_jump_invalid();
|
||||
//test_i386_invalid_c6c7();
|
||||
// test_i386_invalid_c6c7();
|
||||
test_x86_64();
|
||||
test_x86_64_syscall();
|
||||
test_i386_invalid_mem_read_in_tb();
|
||||
|
@ -26,62 +26,64 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
#pragma pack(push, 1)
|
||||
struct SegmentDescriptor {
|
||||
union {
|
||||
struct {
|
||||
union {
|
||||
struct {
|
||||
#if __BYTE_ORDER == __LITTLE_ENDIAN
|
||||
unsigned short limit0;
|
||||
unsigned short base0;
|
||||
unsigned char base1;
|
||||
unsigned char type:4;
|
||||
unsigned char system:1; /* S flag */
|
||||
unsigned char dpl:2;
|
||||
unsigned char present:1; /* P flag */
|
||||
unsigned char limit1:4;
|
||||
unsigned char avail:1;
|
||||
unsigned char is_64_code:1; /* L flag */
|
||||
unsigned char db:1; /* DB flag */
|
||||
unsigned char granularity:1; /* G flag */
|
||||
unsigned char base2;
|
||||
unsigned short limit0;
|
||||
unsigned short base0;
|
||||
unsigned char base1;
|
||||
unsigned char type : 4;
|
||||
unsigned char system : 1; /* S flag */
|
||||
unsigned char dpl : 2;
|
||||
unsigned char present : 1; /* P flag */
|
||||
unsigned char limit1 : 4;
|
||||
unsigned char avail : 1;
|
||||
unsigned char is_64_code : 1; /* L flag */
|
||||
unsigned char db : 1; /* DB flag */
|
||||
unsigned char granularity : 1; /* G flag */
|
||||
unsigned char base2;
|
||||
#else
|
||||
unsigned char base2;
|
||||
unsigned char granularity:1; /* G flag */
|
||||
unsigned char db:1; /* DB flag */
|
||||
unsigned char is_64_code:1; /* L flag */
|
||||
unsigned char avail:1;
|
||||
unsigned char limit1:4;
|
||||
unsigned char present:1; /* P flag */
|
||||
unsigned char dpl:2;
|
||||
unsigned char system:1; /* S flag */
|
||||
unsigned char type:4;
|
||||
unsigned char base1;
|
||||
unsigned short base0;
|
||||
unsigned short limit0;
|
||||
unsigned char base2;
|
||||
unsigned char granularity : 1; /* G flag */
|
||||
unsigned char db : 1; /* DB flag */
|
||||
unsigned char is_64_code : 1; /* L flag */
|
||||
unsigned char avail : 1;
|
||||
unsigned char limit1 : 4;
|
||||
unsigned char present : 1; /* P flag */
|
||||
unsigned char dpl : 2;
|
||||
unsigned char system : 1; /* S flag */
|
||||
unsigned char type : 4;
|
||||
unsigned char base1;
|
||||
unsigned short base0;
|
||||
unsigned short limit0;
|
||||
#endif
|
||||
};
|
||||
uint64_t desc;
|
||||
};
|
||||
};
|
||||
uint64_t desc;
|
||||
};
|
||||
};
|
||||
#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))
|
||||
|
||||
/**
|
||||
* Assert that err matches expect
|
||||
*/
|
||||
#define uc_assert_err(expect, err) \
|
||||
do { \
|
||||
uc_err __err = err; \
|
||||
if (__err != expect) { \
|
||||
fprintf(stderr, "%s", uc_strerror(__err)); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
#define uc_assert_err(expect, err) \
|
||||
do { \
|
||||
uc_err __err = err; \
|
||||
if (__err != expect) { \
|
||||
fprintf(stderr, "%s", uc_strerror(__err)); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Assert that err is UC_ERR_OK
|
||||
*/
|
||||
#define uc_assert_success(err) uc_assert_err(UC_ERR_OK, err)
|
||||
#define uc_assert_success(err) uc_assert_err(UC_ERR_OK, err)
|
||||
|
||||
/**
|
||||
* Assert that err is anything but UC_ERR_OK
|
||||
@ -90,55 +92,61 @@ do { \
|
||||
* as this serves to document which errors a function will return
|
||||
* in various scenarios.
|
||||
*/
|
||||
#define uc_assert_fail(err) \
|
||||
do { \
|
||||
uc_err __err = err; \
|
||||
if (__err == UC_ERR_OK) { \
|
||||
fprintf(stderr, "%s", uc_strerror(__err)); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
#define uc_assert_fail(err) \
|
||||
do { \
|
||||
uc_err __err = err; \
|
||||
if (__err == UC_ERR_OK) { \
|
||||
fprintf(stderr, "%s", uc_strerror(__err)); \
|
||||
exit(1); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
#define OK(x) uc_assert_success(x)
|
||||
#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) {
|
||||
case UC_MEM_WRITE:
|
||||
printf("mem write at 0x%"PRIx64 ", size = %u, value = 0x%"PRIx64 "\n", address, size, value);
|
||||
break;
|
||||
default: break;
|
||||
switch (type) {
|
||||
case UC_MEM_WRITE:
|
||||
printf("mem write at 0x%" PRIx64 ", size = %u, value = 0x%" PRIx64 "\n",
|
||||
address, size, value);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void hook_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
|
||||
static void init_descriptor(struct SegmentDescriptor *desc, uint32_t base, uint32_t limit, uint8_t is_code)
|
||||
// VERY basic descriptor init function, sets many fields to user space sane
|
||||
// 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->base1 = (base >> 16) & 0xff;
|
||||
desc->base2 = base >> 24;
|
||||
if (limit > 0xfffff) {
|
||||
//need Giant granularity
|
||||
// need Giant granularity
|
||||
limit >>= 12;
|
||||
desc->granularity = 1;
|
||||
}
|
||||
desc->limit0 = limit & 0xffff;
|
||||
desc->limit1 = limit >> 16;
|
||||
|
||||
//some sane defaults
|
||||
// some sane defaults
|
||||
desc->dpl = 3;
|
||||
desc->present = 1;
|
||||
desc->db = 1; //32 bit
|
||||
desc->db = 1; // 32 bit
|
||||
desc->type = is_code ? 0xb : 3;
|
||||
desc->system = 1; //code or data
|
||||
desc->system = 1; // code or data
|
||||
}
|
||||
|
||||
/*
|
||||
@ -149,7 +157,7 @@ static void hex_dump(unsigned char *ptr, unsigned int len)
|
||||
if (i != 0 && (i & 0xf) == 0) {
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
fprintf(stderr, "%02hhx", ptr[i]);
|
||||
fprintf(stderr, "%02hhx", ptr[i]);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
@ -163,7 +171,7 @@ static void gdt_demo()
|
||||
uint8_t buf[128];
|
||||
uc_x86_mmr gdtr;
|
||||
int i;
|
||||
|
||||
|
||||
/*
|
||||
bits 32
|
||||
|
||||
@ -174,29 +182,33 @@ static void gdt_demo()
|
||||
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 stack_address = 0x120000;
|
||||
const uint64_t gdt_address = 0xc0000000;
|
||||
const uint64_t fs_address = 0x7efdd000;
|
||||
|
||||
struct SegmentDescriptor *gdt = (struct SegmentDescriptor*)calloc(31, sizeof(struct SegmentDescriptor));
|
||||
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_ss = 0x88; //ring 0
|
||||
int r_ss = 0x88; // ring 0
|
||||
int r_ds = 0x7b;
|
||||
int r_es = 0x7b;
|
||||
int r_fs = 0x83;
|
||||
|
||||
gdtr.base = gdt_address;
|
||||
gdtr.base = gdt_address;
|
||||
gdtr.limit = 31 * sizeof(struct SegmentDescriptor) - 1;
|
||||
|
||||
init_descriptor(&gdt[14], 0, 0xfffff000, 1); //code segment
|
||||
init_descriptor(&gdt[15], 0, 0xfffff000, 0); //data segment
|
||||
init_descriptor(&gdt[16], 0x7efdd000, 0xfff, 0); //one page data segment simulate fs
|
||||
init_descriptor(&gdt[17], 0, 0xfffff000, 0); //ring 0 data
|
||||
gdt[17].dpl = 0; //set descriptor privilege level
|
||||
init_descriptor(&gdt[14], 0, 0xfffff000, 1); // code segment
|
||||
init_descriptor(&gdt[15], 0, 0xfffff000, 0); // data segment
|
||||
init_descriptor(&gdt[16], 0x7efdd000, 0xfff,
|
||||
0); // one page data segment simulate fs
|
||||
init_descriptor(&gdt[17], 0, 0xfffff000, 0); // ring 0 data
|
||||
gdt[17].dpl = 0; // set descriptor privilege level
|
||||
|
||||
/*
|
||||
fprintf(stderr, "GDT: \n");
|
||||
@ -207,9 +219,11 @@ static void gdt_demo()
|
||||
err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
||||
uc_assert_success(err);
|
||||
|
||||
uc_hook_add(uc, &hook1, UC_HOOK_CODE, hook_code, NULL, code_address, code_address + sizeof(code) - 1);
|
||||
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);
|
||||
|
||||
// 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);
|
||||
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);
|
||||
uc_assert_success(err);
|
||||
|
||||
// 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);
|
||||
|
||||
// map 1 page for FS
|
||||
@ -237,7 +252,7 @@ static void gdt_demo()
|
||||
uc_assert_success(err);
|
||||
|
||||
// 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);
|
||||
|
||||
// initialize machine registers
|
||||
@ -245,7 +260,8 @@ static void gdt_demo()
|
||||
uc_assert_success(err);
|
||||
|
||||
// when setting SS, need rpl == cpl && dpl == cpl
|
||||
// emulator starts with cpl == 0, so we need a dpl 0 descriptor and rpl 0 selector
|
||||
// emulator starts with cpl == 0, so we need a dpl 0 descriptor and rpl 0
|
||||
// selector
|
||||
err = uc_reg_write(uc, UC_X86_REG_SS, &r_ss);
|
||||
uc_assert_success(err);
|
||||
|
||||
@ -259,7 +275,7 @@ static void gdt_demo()
|
||||
uc_assert_success(err);
|
||||
|
||||
// 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);
|
||||
|
||||
// read from memory
|
||||
|
@ -6,23 +6,31 @@
|
||||
#include <unicorn/unicorn.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
// 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
|
||||
#define ADDRESS 0x1000000
|
||||
|
||||
#define MIN(a, b) (a < b? a : b)
|
||||
#define MIN(a, b) (a < b ? a : b)
|
||||
// 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;
|
||||
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);
|
||||
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);
|
||||
if (!uc_mem_read(uc, address, tmp, size)) {
|
||||
uint32_t i;
|
||||
for (i=0; i<size; i++) {
|
||||
for (i = 0; i < size; i++) {
|
||||
printf("%x ", tmp[i]);
|
||||
}
|
||||
printf("\n");
|
||||
@ -52,33 +60,35 @@ 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_EIP, &r_eip);
|
||||
|
||||
switch(r_eax) {
|
||||
default:
|
||||
printf(">>> 0x%x: interrupt 0x%x, EAX = 0x%x\n", r_eip, intno, r_eax);
|
||||
break;
|
||||
case 1: // sys_exit
|
||||
printf(">>> 0x%x: interrupt 0x%x, SYS_EXIT. quit!\n\n", r_eip, intno);
|
||||
uc_emu_stop(uc);
|
||||
break;
|
||||
case 4: // sys_write
|
||||
// ECX = buffer address
|
||||
uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx);
|
||||
switch (r_eax) {
|
||||
default:
|
||||
printf(">>> 0x%x: interrupt 0x%x, EAX = 0x%x\n", r_eip, intno, r_eax);
|
||||
break;
|
||||
case 1: // sys_exit
|
||||
printf(">>> 0x%x: interrupt 0x%x, SYS_EXIT. quit!\n\n", r_eip, intno);
|
||||
uc_emu_stop(uc);
|
||||
break;
|
||||
case 4: // sys_write
|
||||
// ECX = buffer address
|
||||
uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx);
|
||||
|
||||
// EDX = buffer size
|
||||
uc_reg_read(uc, UC_X86_REG_EDX, &r_edx);
|
||||
// EDX = buffer size
|
||||
uc_reg_read(uc, UC_X86_REG_EDX, &r_edx);
|
||||
|
||||
// read the buffer in
|
||||
size = MIN(sizeof(buffer)-1, r_edx);
|
||||
// read the buffer in
|
||||
size = MIN(sizeof(buffer) - 1, r_edx);
|
||||
|
||||
if (!uc_mem_read(uc, r_ecx, buffer, size)) {
|
||||
buffer[size] = '\0';
|
||||
printf(">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = %u, content = '%s'\n",
|
||||
r_eip, intno, r_ecx, r_edx, buffer);
|
||||
} else {
|
||||
printf(">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = %u (cannot get content)\n",
|
||||
r_eip, intno, r_ecx, r_edx);
|
||||
}
|
||||
break;
|
||||
if (!uc_mem_read(uc, r_ecx, buffer, size)) {
|
||||
buffer[size] = '\0';
|
||||
printf(">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = "
|
||||
"%u, content = '%s'\n",
|
||||
r_eip, intno, r_ecx, r_edx, buffer);
|
||||
} else {
|
||||
printf(">>> 0x%x: interrupt 0x%x, SYS_WRITE. buffer = 0x%x, size = "
|
||||
"%u (cannot get content)\n",
|
||||
r_eip, intno, r_ecx, r_edx);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -88,7 +98,7 @@ static void test_i386(void)
|
||||
uc_err err;
|
||||
uc_hook trace1, trace2;
|
||||
|
||||
int r_esp = ADDRESS + 0x200000; // ESP register
|
||||
int r_esp = ADDRESS + 0x200000; // ESP register
|
||||
|
||||
printf("Emulate i386 code\n");
|
||||
|
||||
@ -103,7 +113,8 @@ static void test_i386(void)
|
||||
uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||
|
||||
// write machine code to be emulated to memory
|
||||
if (uc_mem_write(uc, ADDRESS, X86_CODE32_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");
|
||||
return;
|
||||
}
|
||||
@ -120,11 +131,13 @@ static void test_i386(void)
|
||||
printf("\n>>> Start tracing this Linux code\n");
|
||||
|
||||
// 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) - 1, 0, 0);
|
||||
// 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) - 1, 0, 0);
|
||||
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));
|
||||
}
|
||||
|
||||
printf("\n>>> Emulation done.\n");
|
||||
@ -137,8 +150,7 @@ int main(int argc, char **argv, char **envp)
|
||||
if (argc == 2) {
|
||||
if (!strcmp(argv[1], "-32")) {
|
||||
test_i386();
|
||||
}
|
||||
else if (!strcmp(argv[1], "-h")) {
|
||||
} else if (!strcmp(argv[1], "-h")) {
|
||||
printf("Syntax: %s <-32|-64>\n", argv[0]);
|
||||
}
|
||||
} else {
|
||||
|
1369
tests/unit/acutest.h
1369
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_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_mem_map(*uc, code_start, code_len, UC_PROT_ALL));
|
||||
OK(uc_mem_write(*uc, code_start, code, size));
|
||||
}
|
||||
|
||||
static void test_arm_nop() {
|
||||
uc_engine* uc;
|
||||
static void test_arm_nop()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\x00\xf0\x20\xe3"; // nop
|
||||
int r_r0 = 0x1234;
|
||||
int r_r2 = 0x6789;
|
||||
@ -29,8 +32,9 @@ static void test_arm_nop() {
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_arm_thumb_sub() {
|
||||
uc_engine* uc;
|
||||
static void test_arm_thumb_sub()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\x83\xb0"; // sub sp, #0xc
|
||||
int r_sp = 0x1234;
|
||||
|
||||
@ -45,15 +49,18 @@ static void test_arm_thumb_sub() {
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
int r_r0 = 0x1234;
|
||||
int r_r2 = 0x6789;
|
||||
int r_r3 = 0x3333;
|
||||
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_R2, &r_r2));
|
||||
OK(uc_reg_write(uc, UC_ARM_REG_R3, &r_r3));
|
||||
@ -73,12 +80,14 @@ static void test_armeb_sub() {
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_arm_thumbeb_sub() {
|
||||
uc_engine* uc;
|
||||
static void test_arm_thumbeb_sub()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\xb0\x83"; // sub sp, #0xc
|
||||
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_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));
|
||||
}
|
||||
|
||||
static void test_arm_thumb_ite_count_callback(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) {
|
||||
uint64_t* count = (uint64_t*)user_data;
|
||||
static void test_arm_thumb_ite_count_callback(uc_engine *uc, uint64_t address,
|
||||
uint32_t size, void *user_data)
|
||||
{
|
||||
uint64_t *count = (uint64_t *)user_data;
|
||||
|
||||
(*count) += 1;
|
||||
}
|
||||
|
||||
static void test_arm_thumb_ite() {
|
||||
uc_engine* uc;
|
||||
static void test_arm_thumb_ite()
|
||||
{
|
||||
uc_engine *uc;
|
||||
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_r2 = 0;
|
||||
int r_r3 = 1;
|
||||
@ -116,7 +134,8 @@ static void test_arm_thumb_ite() {
|
||||
r_r2 = 0x4d;
|
||||
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.
|
||||
OK(uc_emu_start(uc, code_start | 1, code_start + sizeof(code) - 1, 0, 0));
|
||||
@ -146,19 +165,22 @@ static void test_arm_thumb_ite() {
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
uint32_t r_control = 0b10;
|
||||
uint32_t r_apsr = (0b10101 << 27);
|
||||
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_APSR_NZCVQ, &r_apsr));
|
||||
OK(uc_emu_start(uc, code_start | 1, code_start + sizeof(code) - 1, 0, 0));
|
||||
|
||||
|
||||
OK(uc_reg_read(uc, UC_ARM_REG_R0, &r_r0));
|
||||
OK(uc_reg_read(uc, UC_ARM_REG_R1, &r_r1));
|
||||
|
||||
@ -168,8 +190,9 @@ static void test_arm_m_thumb_mrs() {
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_arm_m_control() {
|
||||
uc_engine* uc;
|
||||
static void test_arm_m_control()
|
||||
{
|
||||
uc_engine *uc;
|
||||
int r_control, r_msp, r_psp;
|
||||
|
||||
OK(uc_open(UC_ARCH_ARM, UC_MODE_THUMB | UC_MODE_MCLASS, &uc));
|
||||
@ -195,16 +218,19 @@ static void test_arm_m_control() {
|
||||
OK(uc_reg_read(uc, UC_ARM_REG_R13, &r_msp));
|
||||
TEST_CHECK(r_psp != r_msp);
|
||||
TEST_CHECK(r_msp == 0x1000);
|
||||
|
||||
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
//
|
||||
// Some notes:
|
||||
// Qemu raise a special exception EXCP_EXCEPTION_EXIT to handle the EXC_RETURN. We can't
|
||||
// help user handle EXC_RETURN since unicorn is designed not to handle any CPU exception.
|
||||
// Qemu raise a special exception EXCP_EXCEPTION_EXIT to handle the
|
||||
// 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;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
static void test_arm_m_exc_return() {
|
||||
uc_engine* uc;
|
||||
static void test_arm_m_exc_return()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\x6f\xf0\x02\x00\x00\x47"; // mov r0, #0xFFFFFFFD; bx r0;
|
||||
int r_ipsr;
|
||||
int r_sp = 0x8000;
|
||||
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_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;
|
||||
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.
|
||||
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_close(uc));
|
||||
}
|
||||
|
||||
TEST_LIST = {
|
||||
{ "test_arm_nop", test_arm_nop },
|
||||
{ "test_arm_thumb_sub", test_arm_thumb_sub },
|
||||
{ "test_armeb_sub", test_armeb_sub },
|
||||
{ "test_arm_thumbeb_sub", test_arm_thumbeb_sub },
|
||||
{ "test_arm_thumb_ite", test_arm_thumb_ite },
|
||||
{ "test_arm_m_thumb_mrs", test_arm_m_thumb_mrs },
|
||||
{ "test_arm_m_control", test_arm_m_control },
|
||||
{ "test_arm_m_exc_return", test_arm_m_exc_return },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
TEST_LIST = {{"test_arm_nop", test_arm_nop},
|
||||
{"test_arm_thumb_sub", test_arm_thumb_sub},
|
||||
{"test_armeb_sub", test_armeb_sub},
|
||||
{"test_arm_thumbeb_sub", test_arm_thumbeb_sub},
|
||||
{"test_arm_thumb_ite", test_arm_thumb_ite},
|
||||
{"test_arm_m_thumb_mrs", test_arm_m_thumb_mrs},
|
||||
{"test_arm_m_control", test_arm_m_control},
|
||||
{"test_arm_m_exc_return", test_arm_m_exc_return},
|
||||
{NULL, NULL}};
|
@ -3,52 +3,51 @@
|
||||
const uint64_t code_start = 0x1000;
|
||||
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_mem_map(*uc, code_start, code_len, UC_PROT_ALL));
|
||||
OK(uc_mem_write(*uc, code_start, code, size));
|
||||
}
|
||||
|
||||
static void test_arm64_until() {
|
||||
uc_engine *uc;
|
||||
char code[] = "\x30\x00\x80\xd2\x11\x04\x80\xd2\x9c\x23\x00\x91";
|
||||
static void test_arm64_until()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\x30\x00\x80\xd2\x11\x04\x80\xd2\x9c\x23\x00\x91";
|
||||
|
||||
/*
|
||||
mov x16, #1
|
||||
mov x17, #0x20
|
||||
add x28, x28, 8
|
||||
*/
|
||||
/*
|
||||
mov x16, #1
|
||||
mov x17, #0x20
|
||||
add x28, x28, 8
|
||||
*/
|
||||
|
||||
uint64_t r_x16 = 0x12341234;
|
||||
uint64_t r_x17 = 0x78907890;
|
||||
uint64_t r_pc = 0x00000000;
|
||||
uint64_t r_x28 = 0x12341234;
|
||||
uint64_t r_x16 = 0x12341234;
|
||||
uint64_t r_x17 = 0x78907890;
|
||||
uint64_t r_pc = 0x00000000;
|
||||
uint64_t r_x28 = 0x12341234;
|
||||
|
||||
uc_common_setup(&uc, UC_ARCH_ARM64, UC_MODE_ARM, code, sizeof(code) - 1);
|
||||
uc_common_setup(&uc, UC_ARCH_ARM64, UC_MODE_ARM, code, sizeof(code) - 1);
|
||||
|
||||
// initialize machine registers
|
||||
OK(uc_reg_write(uc, UC_ARM64_REG_X16, &r_x16));
|
||||
OK(uc_reg_write(uc, UC_ARM64_REG_X17, &r_x17));
|
||||
OK(uc_reg_write(uc, UC_ARM64_REG_X28, &r_x28));
|
||||
// initialize machine registers
|
||||
OK(uc_reg_write(uc, UC_ARM64_REG_X16, &r_x16));
|
||||
OK(uc_reg_write(uc, UC_ARM64_REG_X17, &r_x17));
|
||||
OK(uc_reg_write(uc, UC_ARM64_REG_X28, &r_x28));
|
||||
|
||||
// emulate the three instructions
|
||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 3));
|
||||
// emulate the three instructions
|
||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 3));
|
||||
|
||||
OK(uc_reg_read(uc, UC_ARM64_REG_X16, &r_x16));
|
||||
OK(uc_reg_read(uc, UC_ARM64_REG_X17, &r_x17));
|
||||
OK(uc_reg_read(uc, UC_ARM64_REG_X28, &r_x28));
|
||||
OK(uc_reg_read(uc, UC_ARM64_REG_PC, &r_pc));
|
||||
OK(uc_reg_read(uc, UC_ARM64_REG_X16, &r_x16));
|
||||
OK(uc_reg_read(uc, UC_ARM64_REG_X17, &r_x17));
|
||||
OK(uc_reg_read(uc, UC_ARM64_REG_X28, &r_x28));
|
||||
OK(uc_reg_read(uc, UC_ARM64_REG_PC, &r_pc));
|
||||
|
||||
TEST_CHECK(r_x16 == 0x1);
|
||||
TEST_CHECK(r_x17 == 0x20);
|
||||
TEST_CHECK(r_x28 == 0x1234123c);
|
||||
TEST_CHECK(r_pc == (code_start + sizeof(code) - 1));
|
||||
TEST_CHECK(r_x16 == 0x1);
|
||||
TEST_CHECK(r_x17 == 0x20);
|
||||
TEST_CHECK(r_x28 == 0x1234123c);
|
||||
TEST_CHECK(r_pc == (code_start + sizeof(code) - 1));
|
||||
|
||||
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_len = 0x4000;
|
||||
|
||||
TEST_LIST = {
|
||||
{ NULL, NULL }
|
||||
};
|
||||
TEST_LIST = {{NULL, NULL}};
|
@ -1,34 +1,40 @@
|
||||
#include "unicorn_test.h"
|
||||
|
||||
static void test_map_correct() {
|
||||
uc_engine* uc;
|
||||
static void test_map_correct()
|
||||
{
|
||||
uc_engine *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, 0x60000, 0x1000 * 16, UC_PROT_ALL)); // [0x60000, 0x70000]
|
||||
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_mem_map(uc, 0x25000, 0x1000 * 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_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, 0x60000, 0x1000 * 16, UC_PROT_ALL)); // [0x60000, 0x70000]
|
||||
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_mem_map(uc, 0x25000, 0x1000 * 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, 0x50000, 0x5000, UC_PROT_ALL));
|
||||
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_map_wrapping() {
|
||||
uc_engine* uc;
|
||||
static void test_map_wrapping()
|
||||
{
|
||||
uc_engine *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));
|
||||
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));
|
||||
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
TEST_LIST = {
|
||||
{ "test_map_correct", test_map_correct },
|
||||
{ "test_map_wrapping", test_map_wrapping },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
TEST_LIST = {{"test_map_correct", test_map_correct},
|
||||
{"test_map_wrapping", test_map_wrapping},
|
||||
{NULL, NULL}};
|
||||
|
@ -3,18 +3,22 @@
|
||||
const uint64_t code_start = 0x10000000;
|
||||
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_mem_map(*uc, code_start, code_len, UC_PROT_ALL));
|
||||
OK(uc_mem_write(*uc, code_start, code, size));
|
||||
}
|
||||
|
||||
static void test_mips_el_ori() {
|
||||
uc_engine* uc;
|
||||
static void test_mips_el_ori()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\x56\x34\x21\x34"; // ori $at, $at, 0x3456;
|
||||
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_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));
|
||||
}
|
||||
|
||||
static void test_mips_eb_ori() {
|
||||
uc_engine* uc;
|
||||
static void test_mips_eb_ori()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\x34\x21\x34\x56"; // ori $at, $at, 0x3456;
|
||||
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_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||
@ -43,37 +49,43 @@ static void test_mips_eb_ori() {
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
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.
|
||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 1));
|
||||
|
||||
OK(uc_reg_read(uc, UC_MIPS_REG_PC, &r_pc));
|
||||
|
||||
// Even if we just execute one instruction, the instruction in the
|
||||
// Even if we just execute one instruction, the instruction in the
|
||||
// delay slot would also be executed.
|
||||
TEST_CHECK(r_pc == code_start + 0x8);
|
||||
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
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;
|
||||
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;
|
||||
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.
|
||||
OK(uc_emu_start(uc, code_start, code_start + 4, 0, 0));
|
||||
|
||||
OK(uc_reg_read(uc, UC_MIPS_REG_PC, &r_pc));
|
||||
|
||||
|
||||
// The branch instruction isn't committed and the PC is not updated.
|
||||
// Users is responsible to restart emulation at the branch instruction.
|
||||
TEST_CHECK(r_pc == code_start);
|
||||
@ -81,12 +93,14 @@ static void test_mips_stop_at_delay_slot() {
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_mips_lwx_exception_issue_1314() {
|
||||
uc_engine* uc;
|
||||
static void test_mips_lwx_exception_issue_1314()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\x0a\xc8\x79\x7e"; // lwx $t9, $t9($s3)
|
||||
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));
|
||||
|
||||
// Enable DSP
|
||||
@ -113,10 +127,9 @@ static void test_mips_lwx_exception_issue_1314() {
|
||||
}
|
||||
|
||||
TEST_LIST = {
|
||||
{ "test_mips_stop_at_branch", test_mips_stop_at_branch },
|
||||
{ "test_mips_stop_at_delay_slot", test_mips_stop_at_delay_slot},
|
||||
{ "test_mips_el_ori", test_mips_el_ori},
|
||||
{ "test_mips_eb_ori", test_mips_eb_ori},
|
||||
{ "test_mips_lwx_exception_issue_1314", test_mips_lwx_exception_issue_1314},
|
||||
{ NULL, NULL }
|
||||
};
|
||||
{"test_mips_stop_at_branch", test_mips_stop_at_branch},
|
||||
{"test_mips_stop_at_delay_slot", test_mips_stop_at_delay_slot},
|
||||
{"test_mips_el_ori", test_mips_el_ori},
|
||||
{"test_mips_eb_ori", test_mips_eb_ori},
|
||||
{"test_mips_lwx_exception_issue_1314", test_mips_lwx_exception_issue_1314},
|
||||
{NULL, NULL}};
|
@ -3,18 +3,22 @@
|
||||
const uint64_t code_start = 0x1000;
|
||||
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_mem_map(*uc, code_start, code_len, UC_PROT_ALL));
|
||||
OK(uc_mem_write(*uc, code_start, code, size));
|
||||
}
|
||||
|
||||
static void test_ppc32_add() {
|
||||
uc_engine* uc;
|
||||
static void test_ppc32_add()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\x7f\x46\x1a\x14"; // ADD 26, 6, 3
|
||||
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;
|
||||
OK(uc_reg_write(uc, UC_PPC_REG_3, ®));
|
||||
@ -30,7 +34,4 @@ static void test_ppc32_add() {
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
TEST_LIST = {
|
||||
{ "test_ppc32_add", test_ppc32_add },
|
||||
{ NULL, NULL}
|
||||
};
|
||||
TEST_LIST = {{"test_ppc32_add", test_ppc32_add}, {NULL, NULL}};
|
@ -3,19 +3,23 @@
|
||||
const uint64_t code_start = 0x1000;
|
||||
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_mem_map(*uc, code_start, code_len, UC_PROT_ALL));
|
||||
OK(uc_mem_write(*uc, code_start, code, size));
|
||||
}
|
||||
|
||||
static void test_riscv32_nop() {
|
||||
uc_engine* uc;
|
||||
static void test_riscv32_nop()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\x13\x00\x00\x00"; // nop
|
||||
uint32_t r_t0 = 0x1234;
|
||||
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_T1, &r_t1));
|
||||
|
||||
@ -29,13 +33,15 @@ static void test_riscv32_nop() {
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_riscv64_nop() {
|
||||
uc_engine* uc;
|
||||
static void test_riscv64_nop()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\x13\x00\x00\x00"; // nop
|
||||
uint64_t r_t0 = 0x1234;
|
||||
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_T1, &r_t1));
|
||||
|
||||
@ -49,167 +55,172 @@ static void test_riscv64_nop() {
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_riscv32_until_pc_update() {
|
||||
uc_engine *uc;
|
||||
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
|
||||
static void test_riscv32_until_pc_update()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
|
||||
|
||||
/*
|
||||
addi t0, zero, 1
|
||||
addi t1, zero, 0x20
|
||||
addi sp, sp, 8
|
||||
*/
|
||||
/*
|
||||
addi t0, zero, 1
|
||||
addi t1, zero, 0x20
|
||||
addi sp, sp, 8
|
||||
*/
|
||||
|
||||
uint32_t r_t0 = 0x1234;
|
||||
uint32_t r_t1 = 0x7890;
|
||||
uint32_t r_pc = 0x0000;
|
||||
uint32_t r_sp = 0x1234;
|
||||
uint32_t r_t0 = 0x1234;
|
||||
uint32_t r_t1 = 0x7890;
|
||||
uint32_t r_pc = 0x0000;
|
||||
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
|
||||
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_SP, &r_sp));
|
||||
// initialize machine registers
|
||||
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_SP, &r_sp));
|
||||
|
||||
// emulate the three instructions
|
||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||
// emulate the three instructions
|
||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_T0, &r_t0));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_T1, &r_t1));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_SP, &r_sp));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_PC, &r_pc));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_T0, &r_t0));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_T1, &r_t1));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_SP, &r_sp));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_PC, &r_pc));
|
||||
|
||||
TEST_CHECK(r_t0 == 0x1);
|
||||
TEST_CHECK(r_t1 == 0x20);
|
||||
TEST_CHECK(r_sp == 0x123c);
|
||||
TEST_CHECK(r_t0 == 0x1);
|
||||
TEST_CHECK(r_t1 == 0x20);
|
||||
TEST_CHECK(r_sp == 0x123c);
|
||||
|
||||
TEST_CHECK(r_pc == (code_start + sizeof(code) - 1));
|
||||
TEST_CHECK(r_pc == (code_start + sizeof(code) - 1));
|
||||
|
||||
OK(uc_close(uc));
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_riscv64_until_pc_update() {
|
||||
uc_engine *uc;
|
||||
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
|
||||
static void test_riscv64_until_pc_update()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
|
||||
|
||||
/*
|
||||
addi t0, zero, 1
|
||||
addi t1, zero, 0x20
|
||||
addi sp, sp, 8
|
||||
*/
|
||||
/*
|
||||
addi t0, zero, 1
|
||||
addi t1, zero, 0x20
|
||||
addi sp, sp, 8
|
||||
*/
|
||||
|
||||
uint64_t r_t0 = 0x1234;
|
||||
uint64_t r_t1 = 0x7890;
|
||||
uint64_t r_pc = 0x0000;
|
||||
uint64_t r_sp = 0x1234;
|
||||
uint64_t r_t0 = 0x1234;
|
||||
uint64_t r_t1 = 0x7890;
|
||||
uint64_t r_pc = 0x0000;
|
||||
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
|
||||
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_SP, &r_sp));
|
||||
// initialize machine registers
|
||||
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_SP, &r_sp));
|
||||
|
||||
// emulate the three instructions
|
||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||
// emulate the three instructions
|
||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_T0, &r_t0));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_T1, &r_t1));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_SP, &r_sp));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_PC, &r_pc));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_T0, &r_t0));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_T1, &r_t1));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_SP, &r_sp));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_PC, &r_pc));
|
||||
|
||||
TEST_CHECK(r_t0 == 0x1);
|
||||
TEST_CHECK(r_t1 == 0x20);
|
||||
TEST_CHECK(r_sp == 0x123c);
|
||||
TEST_CHECK(r_pc == (code_start + sizeof(code) - 1));
|
||||
TEST_CHECK(r_t0 == 0x1);
|
||||
TEST_CHECK(r_t1 == 0x20);
|
||||
TEST_CHECK(r_sp == 0x123c);
|
||||
TEST_CHECK(r_pc == (code_start + sizeof(code) - 1));
|
||||
|
||||
OK(uc_close(uc));
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_riscv32_3steps_pc_update() {
|
||||
uc_engine *uc;
|
||||
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
|
||||
static void test_riscv32_3steps_pc_update()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
|
||||
|
||||
/*
|
||||
addi t0, zero, 1
|
||||
addi t1, zero, 0x20
|
||||
addi sp, sp, 8
|
||||
*/
|
||||
/*
|
||||
addi t0, zero, 1
|
||||
addi t1, zero, 0x20
|
||||
addi sp, sp, 8
|
||||
*/
|
||||
|
||||
uint32_t r_t0 = 0x1234;
|
||||
uint32_t r_t1 = 0x7890;
|
||||
uint32_t r_pc = 0x0000;
|
||||
uint32_t r_sp = 0x1234;
|
||||
uint32_t r_t0 = 0x1234;
|
||||
uint32_t r_t1 = 0x7890;
|
||||
uint32_t r_pc = 0x0000;
|
||||
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
|
||||
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_SP, &r_sp));
|
||||
// initialize machine registers
|
||||
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_SP, &r_sp));
|
||||
|
||||
// emulate the three instructions
|
||||
OK(uc_emu_start(uc, code_start, -1, 0, 3));
|
||||
// emulate the three instructions
|
||||
OK(uc_emu_start(uc, code_start, -1, 0, 3));
|
||||
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_T0, &r_t0));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_T1, &r_t1));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_SP, &r_sp));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_PC, &r_pc));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_T0, &r_t0));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_T1, &r_t1));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_SP, &r_sp));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_PC, &r_pc));
|
||||
|
||||
TEST_CHECK(r_t0 == 0x1);
|
||||
TEST_CHECK(r_t1 == 0x20);
|
||||
TEST_CHECK(r_sp == 0x123c);
|
||||
TEST_CHECK(r_t0 == 0x1);
|
||||
TEST_CHECK(r_t1 == 0x20);
|
||||
TEST_CHECK(r_sp == 0x123c);
|
||||
|
||||
TEST_CHECK(r_pc == (code_start + sizeof(code) - 1));
|
||||
TEST_CHECK(r_pc == (code_start + sizeof(code) - 1));
|
||||
|
||||
OK(uc_close(uc));
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_riscv64_3steps_pc_update() {
|
||||
uc_engine *uc;
|
||||
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
|
||||
static void test_riscv64_3steps_pc_update()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
|
||||
|
||||
/*
|
||||
addi t0, zero, 1
|
||||
addi t1, zero, 0x20
|
||||
addi sp, sp, 8
|
||||
*/
|
||||
/*
|
||||
addi t0, zero, 1
|
||||
addi t1, zero, 0x20
|
||||
addi sp, sp, 8
|
||||
*/
|
||||
|
||||
uint64_t r_t0 = 0x1234;
|
||||
uint64_t r_t1 = 0x7890;
|
||||
uint64_t r_pc = 0x0000;
|
||||
uint64_t r_sp = 0x1234;
|
||||
uint64_t r_t0 = 0x1234;
|
||||
uint64_t r_t1 = 0x7890;
|
||||
uint64_t r_pc = 0x0000;
|
||||
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
|
||||
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_SP, &r_sp));
|
||||
// initialize machine registers
|
||||
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_SP, &r_sp));
|
||||
|
||||
// emulate the three instructions
|
||||
OK(uc_emu_start(uc, code_start, -1, 0, 3));
|
||||
// emulate the three instructions
|
||||
OK(uc_emu_start(uc, code_start, -1, 0, 3));
|
||||
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_T0, &r_t0));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_T1, &r_t1));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_SP, &r_sp));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_PC, &r_pc));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_T0, &r_t0));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_T1, &r_t1));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_SP, &r_sp));
|
||||
OK(uc_reg_read(uc, UC_RISCV_REG_PC, &r_pc));
|
||||
|
||||
TEST_CHECK(r_t0 == 0x1);
|
||||
TEST_CHECK(r_t1 == 0x20);
|
||||
TEST_CHECK(r_sp == 0x123c);
|
||||
TEST_CHECK(r_pc == (code_start + sizeof(code) - 1));
|
||||
TEST_CHECK(r_t0 == 0x1);
|
||||
TEST_CHECK(r_t1 == 0x20);
|
||||
TEST_CHECK(r_sp == 0x123c);
|
||||
TEST_CHECK(r_pc == (code_start + sizeof(code) - 1));
|
||||
|
||||
OK(uc_close(uc));
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
|
||||
TEST_LIST = {
|
||||
{ "test_riscv32_nop", test_riscv32_nop },
|
||||
{ "test_riscv64_nop", test_riscv64_nop },
|
||||
{ "test_riscv32_3steps_pc_update", test_riscv32_3steps_pc_update },
|
||||
{ "test_riscv64_3steps_pc_update", test_riscv64_3steps_pc_update },
|
||||
{ "test_riscv32_until_pc_update", test_riscv32_until_pc_update },
|
||||
{ "test_riscv64_until_pc_update", test_riscv64_until_pc_update },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
TEST_LIST = {{"test_riscv32_nop", test_riscv32_nop},
|
||||
{"test_riscv64_nop", test_riscv64_nop},
|
||||
{"test_riscv32_3steps_pc_update", test_riscv32_3steps_pc_update},
|
||||
{"test_riscv64_3steps_pc_update", test_riscv64_3steps_pc_update},
|
||||
{"test_riscv32_until_pc_update", test_riscv32_until_pc_update},
|
||||
{"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_len = 0x4000;
|
||||
|
||||
TEST_LIST = {
|
||||
{ NULL, NULL }
|
||||
};
|
||||
TEST_LIST = {{NULL, NULL}};
|
@ -3,7 +3,9 @@
|
||||
const uint64_t code_start = 0x1000;
|
||||
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_mem_map(*uc, code_start, code_len, UC_PROT_ALL));
|
||||
OK(uc_mem_write(*uc, code_start, code, size));
|
||||
@ -14,22 +16,26 @@ typedef struct _INSN_IN_RESULT {
|
||||
int size;
|
||||
} INSN_IN_RESULT;
|
||||
|
||||
static void test_x86_in_callback(uc_engine* uc, uint32_t port, int size, void* user_data) {
|
||||
INSN_IN_RESULT* result = (INSN_IN_RESULT*)user_data;
|
||||
static void test_x86_in_callback(uc_engine *uc, uint32_t port, int size,
|
||||
void *user_data)
|
||||
{
|
||||
INSN_IN_RESULT *result = (INSN_IN_RESULT *)user_data;
|
||||
|
||||
result->port = port;
|
||||
result->size = size;
|
||||
}
|
||||
|
||||
static void test_x86_in() {
|
||||
uc_engine* uc;
|
||||
static void test_x86_in()
|
||||
{
|
||||
uc_engine *uc;
|
||||
uc_hook hook;
|
||||
char code[] = "\xe5\x10"; // IN eax, 0x10
|
||||
INSN_IN_RESULT result;
|
||||
|
||||
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));
|
||||
TEST_CHECK(result.port == 0x10);
|
||||
TEST_CHECK(result.size == 4);
|
||||
@ -44,23 +50,27 @@ typedef struct _INSN_OUT_RESULT {
|
||||
uint32_t value;
|
||||
} INSN_OUT_RESULT;
|
||||
|
||||
static void test_x86_out_callback(uc_engine* uc, uint32_t port, int size, uint32_t value, void* user_data) {
|
||||
INSN_OUT_RESULT* result = (INSN_OUT_RESULT*)user_data;
|
||||
static void test_x86_out_callback(uc_engine *uc, uint32_t port, int size,
|
||||
uint32_t value, void *user_data)
|
||||
{
|
||||
INSN_OUT_RESULT *result = (INSN_OUT_RESULT *)user_data;
|
||||
|
||||
result->port = port;
|
||||
result->size = size;
|
||||
result->value = value;
|
||||
}
|
||||
|
||||
static void test_x86_out() {
|
||||
uc_engine* uc;
|
||||
static void test_x86_out()
|
||||
{
|
||||
uc_engine *uc;
|
||||
uc_hook hook;
|
||||
char code[] = "\xb0\x32\xe6\x46"; // MOV al, 0x32; OUT 0x46, al;
|
||||
INSN_OUT_RESULT result;
|
||||
|
||||
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));
|
||||
TEST_CHECK(result.port == 0x46);
|
||||
TEST_CHECK(result.size == 1);
|
||||
@ -82,8 +92,11 @@ typedef struct _MEM_HOOK_RESULTS {
|
||||
MEM_HOOK_RESULT results[16];
|
||||
} 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) {
|
||||
MEM_HOOK_RESULTS* r = (MEM_HOOK_RESULTS*)user_data;
|
||||
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)
|
||||
{
|
||||
MEM_HOOK_RESULTS *r = (MEM_HOOK_RESULTS *)user_data;
|
||||
uint64_t count = r->count;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static void test_x86_mem_hook_all() {
|
||||
uc_engine* uc;
|
||||
static void test_x86_mem_hook_all()
|
||||
{
|
||||
uc_engine *uc;
|
||||
uc_hook hook;
|
||||
// mov eax, 0xdeadbeef;
|
||||
// mov [0x8000], eax;
|
||||
// mov eax, [0x10000];
|
||||
char code[] = "\xb8\xef\xbe\xad\xde\xa3\x00\x80\x00\x00\xa1\x00\x00\x01\x00";
|
||||
MEM_HOOK_RESULTS r = { 0 };
|
||||
MEM_HOOK_RESULT expects[3] = {
|
||||
{UC_MEM_WRITE, 0x8000, 4, 0xdeadbeef},
|
||||
{UC_MEM_READ_UNMAPPED, 0x10000, 4, 0},
|
||||
{UC_MEM_READ, 0x10000, 4, 0}
|
||||
};
|
||||
char code[] =
|
||||
"\xb8\xef\xbe\xad\xde\xa3\x00\x80\x00\x00\xa1\x00\x00\x01\x00";
|
||||
MEM_HOOK_RESULTS r = {0};
|
||||
MEM_HOOK_RESULT expects[3] = {{UC_MEM_WRITE, 0x8000, 4, 0xdeadbeef},
|
||||
{UC_MEM_READ_UNMAPPED, 0x10000, 4, 0},
|
||||
{UC_MEM_READ, 0x10000, 4, 0}};
|
||||
|
||||
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_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));
|
||||
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].address == r.results[i].address);
|
||||
TEST_CHECK(expects[i].size == r.results[i].size);
|
||||
@ -134,9 +148,11 @@ static void test_x86_mem_hook_all() {
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
int r_ecx = 0x1234;
|
||||
int r_edx = 0x7890;
|
||||
uint64_t r_xmm0[2] = {0x08090a0b0c0d0e0f, 0x0001020304050607};
|
||||
@ -162,9 +178,11 @@ static void test_x86_inc_dec_pxor() {
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
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
|
||||
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
|
||||
int r_eip;
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
static void test_x86_loop() {
|
||||
uc_engine* uc;
|
||||
static void test_x86_loop()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\x41\x4a\xeb\xfe"; // inc ecx; dec edx; jmp $;
|
||||
int r_ecx = 0x1234;
|
||||
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_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_EDX, &r_edx));
|
||||
@ -199,40 +219,50 @@ static void test_x86_loop() {
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_x86_invalid_mem_read() {
|
||||
uc_engine* uc;
|
||||
static void test_x86_invalid_mem_read()
|
||||
{
|
||||
uc_engine *uc;
|
||||
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_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));
|
||||
}
|
||||
|
||||
static void test_x86_invalid_mem_write() {
|
||||
uc_engine* uc;
|
||||
static void test_x86_invalid_mem_write()
|
||||
{
|
||||
uc_engine *uc;
|
||||
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_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));
|
||||
}
|
||||
|
||||
static void test_x86_invalid_jump() {
|
||||
uc_engine* uc;
|
||||
static void test_x86_invalid_jump()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\xe9\xe9\xee\xee\xee"; // jmp 0xEEEEEEEE
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static void test_x86_64_syscall() {
|
||||
uc_engine* uc;
|
||||
static void test_x86_64_syscall()
|
||||
{
|
||||
uc_engine *uc;
|
||||
uc_hook hook;
|
||||
char code[] = "\x0f\x05"; // syscall
|
||||
uint64_t r_rax = 0x100;
|
||||
|
||||
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_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));
|
||||
|
||||
@ -256,8 +288,9 @@ static void test_x86_64_syscall() {
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_x86_16_add() {
|
||||
uc_engine* uc;
|
||||
static void test_x86_16_add()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\x00\x00"; // add byte ptr [bx + si], al
|
||||
uint16_t r_ax = 7;
|
||||
uint16_t r_bx = 5;
|
||||
@ -277,9 +310,10 @@ static void test_x86_16_add() {
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_x86_reg_save() {
|
||||
uc_engine* uc;
|
||||
uc_context* ctx;
|
||||
static void test_x86_reg_save()
|
||||
{
|
||||
uc_engine *uc;
|
||||
uc_context *ctx;
|
||||
char code[] = "\x40"; // inc eax
|
||||
int r_eax = 1;
|
||||
|
||||
@ -289,7 +323,7 @@ static void test_x86_reg_save() {
|
||||
OK(uc_context_alloc(uc, &ctx));
|
||||
OK(uc_context_save(uc, ctx));
|
||||
OK(uc_emu_start(uc, code_start, code_start + sizeof(code) - 1, 0, 0));
|
||||
|
||||
|
||||
OK(uc_reg_read(uc, UC_X86_REG_EAX, &r_eax));
|
||||
TEST_CHECK(r_eax == 2);
|
||||
|
||||
@ -302,27 +336,38 @@ static void test_x86_reg_save() {
|
||||
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) {
|
||||
// False indicates that we fail to handle this ERROR and let the emulation stop.
|
||||
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)
|
||||
{
|
||||
// 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;
|
||||
}
|
||||
|
||||
static void test_x86_invalid_mem_read_stop_in_cb() {
|
||||
uc_engine* uc;
|
||||
static void test_x86_invalid_mem_read_stop_in_cb()
|
||||
{
|
||||
uc_engine *uc;
|
||||
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_edx = 0x5678;
|
||||
int r_eip = 0;
|
||||
|
||||
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_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.
|
||||
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));
|
||||
}
|
||||
|
||||
|
||||
static void test_x86_x87_fnstenv_callback(uc_engine* uc, uint64_t address, uint32_t size, void* user_data) {
|
||||
static void test_x86_x87_fnstenv_callback(uc_engine *uc, uint64_t address,
|
||||
uint32_t size, void *user_data)
|
||||
{
|
||||
uint32_t r_eip;
|
||||
uint32_t r_eax;
|
||||
uint32_t fnstenv[7];
|
||||
@ -345,8 +391,8 @@ static void test_x86_x87_fnstenv_callback(uc_engine* uc, uint64_t address, uint3
|
||||
if (address == code_start + 4) { // The first fnstenv executed
|
||||
// Save the address of the fld.
|
||||
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_mem_read(uc, r_eax, fnstenv, sizeof(fnstenv)));
|
||||
// Don't update FCS:FIP for fnop.
|
||||
@ -354,10 +400,13 @@ static void test_x86_x87_fnstenv_callback(uc_engine* uc, uint64_t address, uint3
|
||||
}
|
||||
}
|
||||
|
||||
static void test_x86_x87_fnstenv() {
|
||||
uc_engine* uc;
|
||||
static void test_x86_x87_fnstenv()
|
||||
{
|
||||
uc_engine *uc;
|
||||
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 last_eip;
|
||||
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_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_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);
|
||||
|
||||
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(size == 4);
|
||||
|
||||
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(size == 4);
|
||||
TEST_CHECK(value == 0xdeadbeef);
|
||||
@ -392,14 +447,19 @@ static void test_x86_mmio_write_callback(uc_engine* uc, uint64_t offset, unsigne
|
||||
return;
|
||||
}
|
||||
|
||||
static void test_x86_mmio() {
|
||||
uc_engine* uc;
|
||||
static void test_x86_mmio()
|
||||
{
|
||||
uc_engine *uc;
|
||||
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);
|
||||
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));
|
||||
|
||||
@ -410,7 +470,10 @@ static void test_x86_mmio() {
|
||||
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;
|
||||
uint64_t algined_address = address & 0xFFFFFFFFFFFFF000ULL;
|
||||
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;
|
||||
}
|
||||
|
||||
static void test_x86_missing_code() {
|
||||
uc_engine* uc;
|
||||
static void test_x86_missing_code()
|
||||
{
|
||||
uc_engine *uc;
|
||||
uc_hook hook;
|
||||
int r_ecx = 0x1234;
|
||||
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_reg_write(uc, UC_X86_REG_ECX, &r_ecx));
|
||||
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));
|
||||
|
||||
@ -445,13 +510,14 @@ static void test_x86_missing_code() {
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_x86_smc_xor() {
|
||||
uc_engine* uc;
|
||||
static void test_x86_smc_xor()
|
||||
{
|
||||
uc_engine *uc;
|
||||
/*
|
||||
* 0x1000 xor dword ptr [edi+0x3], eax ; edi=0x1000, eax=0xbc4177e6
|
||||
* 0x1003 dw 0x3ea98b13
|
||||
*/
|
||||
char code[] = "\x31\x47\x03\x13\x8b\xa9\x3e";
|
||||
* 0x1000 xor dword ptr [edi+0x3], eax ; edi=0x1000, eax=0xbc4177e6
|
||||
* 0x1003 dw 0x3ea98b13
|
||||
*/
|
||||
char code[] = "\x31\x47\x03\x13\x8b\xa9\x3e";
|
||||
int r_edi = code_start;
|
||||
int r_eax = 0xbc4177e6;
|
||||
uint32_t result;
|
||||
@ -469,14 +535,23 @@ static void test_x86_smc_xor() {
|
||||
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(size == 4);
|
||||
|
||||
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(size == 4);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
static void test_x86_mmio_uc_mem_rw() {
|
||||
uc_engine* uc;
|
||||
static void test_x86_mmio_uc_mem_rw()
|
||||
{
|
||||
uc_engine *uc;
|
||||
int data = 0xdeadbeef;
|
||||
|
||||
OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc));
|
||||
|
||||
OK(uc_mmio_map(uc,
|
||||
0x20000, 0x1000,
|
||||
test_x86_mmio_uc_mem_rw_read_callback, NULL,
|
||||
test_x86_mmio_uc_mem_rw_write_callback, NULL));
|
||||
OK(uc_mmio_map(uc, 0x20000, 0x1000, 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_read(uc, 0x20008, (void*)&data, 4));
|
||||
OK(uc_mem_write(uc, 0x20004, (void *)&data, 4));
|
||||
OK(uc_mem_read(uc, 0x20008, (void *)&data, 4));
|
||||
|
||||
TEST_CHECK(data == 0x19260817);
|
||||
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
static void test_x86_sysenter_hook(uc_engine* uc, void* user) {
|
||||
*(int*)user = 1;
|
||||
static void test_x86_sysenter_hook(uc_engine *uc, void *user)
|
||||
{
|
||||
*(int *)user = 1;
|
||||
}
|
||||
|
||||
static void test_x86_sysenter() {
|
||||
uc_engine* uc;
|
||||
static void test_x86_sysenter()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\x0F\x34"; // sysenter
|
||||
uc_hook h;
|
||||
int called = 0;
|
||||
|
||||
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));
|
||||
|
||||
@ -525,21 +601,24 @@ static void test_x86_sysenter() {
|
||||
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;
|
||||
|
||||
OK(uc_reg_write(uc, UC_X86_REG_EAX, ®));
|
||||
}
|
||||
|
||||
static void test_x86_hook_cpuid() {
|
||||
uc_engine* uc;
|
||||
static void test_x86_hook_cpuid()
|
||||
{
|
||||
uc_engine *uc;
|
||||
char code[] = "\x40\x0F\xA2"; // INC EAX; CPUID
|
||||
uc_hook h;
|
||||
int reg;
|
||||
|
||||
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));
|
||||
|
||||
@ -550,26 +629,25 @@ static void test_x86_hook_cpuid() {
|
||||
OK(uc_close(uc));
|
||||
}
|
||||
|
||||
TEST_LIST = {
|
||||
{ "test_x86_in", test_x86_in },
|
||||
{ "test_x86_out", test_x86_out },
|
||||
{ "test_x86_mem_hook_all", test_x86_mem_hook_all },
|
||||
{ "test_x86_inc_dec_pxor", test_x86_inc_dec_pxor },
|
||||
{ "test_x86_relative_jump", test_x86_relative_jump },
|
||||
{ "test_x86_loop", test_x86_loop },
|
||||
{ "test_x86_invalid_mem_read", test_x86_invalid_mem_read },
|
||||
{ "test_x86_invalid_mem_write", test_x86_invalid_mem_write },
|
||||
{ "test_x86_invalid_jump", test_x86_invalid_jump},
|
||||
{ "test_x86_64_syscall", test_x86_64_syscall },
|
||||
{ "test_x86_16_add", test_x86_16_add },
|
||||
{ "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_x87_fnstenv", test_x86_x87_fnstenv},
|
||||
{ "test_x86_mmio", test_x86_mmio},
|
||||
{ "test_x86_missing_code", test_x86_missing_code},
|
||||
{ "test_x86_smc_xor", test_x86_smc_xor},
|
||||
{ "test_x86_mmio_uc_mem_rw", test_x86_mmio_uc_mem_rw},
|
||||
{ "test_x86_sysenter", test_x86_sysenter},
|
||||
{ "test_x86_hook_cpuid", test_x86_hook_cpuid},
|
||||
{ NULL, NULL }
|
||||
};
|
||||
TEST_LIST = {{"test_x86_in", test_x86_in},
|
||||
{"test_x86_out", test_x86_out},
|
||||
{"test_x86_mem_hook_all", test_x86_mem_hook_all},
|
||||
{"test_x86_inc_dec_pxor", test_x86_inc_dec_pxor},
|
||||
{"test_x86_relative_jump", test_x86_relative_jump},
|
||||
{"test_x86_loop", test_x86_loop},
|
||||
{"test_x86_invalid_mem_read", test_x86_invalid_mem_read},
|
||||
{"test_x86_invalid_mem_write", test_x86_invalid_mem_write},
|
||||
{"test_x86_invalid_jump", test_x86_invalid_jump},
|
||||
{"test_x86_64_syscall", test_x86_64_syscall},
|
||||
{"test_x86_16_add", test_x86_16_add},
|
||||
{"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_x87_fnstenv", test_x86_x87_fnstenv},
|
||||
{"test_x86_mmio", test_x86_mmio},
|
||||
{"test_x86_missing_code", test_x86_missing_code},
|
||||
{"test_x86_smc_xor", test_x86_smc_xor},
|
||||
{"test_x86_mmio_uc_mem_rw", test_x86_mmio_uc_mem_rw},
|
||||
{"test_x86_sysenter", test_x86_sysenter},
|
||||
{"test_x86_hook_cpuid", test_x86_hook_cpuid},
|
||||
{NULL, NULL}};
|
@ -8,17 +8,17 @@
|
||||
/**
|
||||
* Assert that err matches expect
|
||||
*/
|
||||
#define uc_assert_err(expect, err) \
|
||||
do { \
|
||||
uc_err __err = err; \
|
||||
if (!TEST_CHECK(__err == expect)) { \
|
||||
TEST_MSG("%s", uc_strerror(__err)); \
|
||||
} \
|
||||
} while (0)
|
||||
#define uc_assert_err(expect, err) \
|
||||
do { \
|
||||
uc_err __err = err; \
|
||||
if (!TEST_CHECK(__err == expect)) { \
|
||||
TEST_MSG("%s", uc_strerror(__err)); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
/**
|
||||
* Assert that err is UC_ERR_OK
|
||||
*/
|
||||
#define OK(stat) uc_assert_err(UC_ERR_OK, stat)
|
||||
#define OK(stat) uc_assert_err(UC_ERR_OK, stat)
|
||||
|
||||
#endif /* UNICORN_TEST_H */
|
||||
|
Loading…
Reference in New Issue
Block a user