Add clang-format and format code to qemu code style

This commit is contained in:
lazymio 2021-10-29 12:44:49 +02:00
parent 9e1443013b
commit e62b0ef255
No known key found for this signature in database
GPG Key ID: DFF27E34A47CB873
49 changed files with 4967 additions and 4190 deletions

16
.clang-format Normal file
View 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

View File

@ -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,14 +14,20 @@
// 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_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_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_RISCV_MASK \
(UC_MODE_RISCV32 | UC_MODE_RISCV64 | UC_MODE_LITTLE_ENDIAN)
#define ARR_SIZE(a) (sizeof(a) / sizeof(a[0]))
@ -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,9 +61,11 @@ 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 *);
@ -65,9 +76,12 @@ 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);
@ -75,7 +89,12 @@ 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);
@ -99,8 +118,10 @@ 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)
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;
};
@ -135,28 +156,28 @@ typedef enum uc_hook_idx {
#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)
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))
((((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)
{
@ -189,7 +210,8 @@ struct uc_struct {
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_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;
@ -253,23 +275,28 @@ struct uc_struct {
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 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)
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 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
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;
@ -278,10 +305,13 @@ struct uc_struct {
/* 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()?
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_*()

View File

@ -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,

View File

@ -31,7 +31,8 @@ MSVC++ 5.0 _MSC_VER == 1100
#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
@ -51,7 +52,9 @@ typedef unsigned char bool;
#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
@ -96,7 +99,8 @@ typedef _W64 unsigned int uintptr_t;
#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)
@ -150,7 +154,8 @@ typedef _W64 unsigned int uintptr_t;
#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)
@ -209,5 +214,4 @@ typedef _W64 signed int ssize_t;
#endif
#endif
#endif // UNICORN_PLATFORM_H

View File

@ -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.
@ -132,7 +132,8 @@ typedef enum uc_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)
UC_MODE_QPX =
1 << 4, // Quad Processing eXtensions mode (currently unsupported)
// sparc
UC_MODE_SPARC32 = 1 << 2, // 32-bit mode
@ -155,16 +156,24 @@ typedef enum uc_err {
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_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_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_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
@ -173,15 +182,16 @@ typedef enum uc_err {
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,8 +250,9 @@ typedef uint64_t (*uc_cb_mmio_read_t)(uc_engine *uc, uint64_t offset, unsigned s
@value: data value to be written
@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 {
@ -256,7 +272,8 @@ typedef enum uc_mem_type {
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
// 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)
#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()
@ -358,7 +387,8 @@ typedef enum uc_query_type {
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_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.
@ -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().

View File

@ -22,8 +22,8 @@ typedef struct uc_x86_mmr {
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
@ -36,53 +36,232 @@ 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_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,

View File

@ -5,19 +5,31 @@
#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);

View File

@ -14,10 +14,10 @@
#define X86_NON_CS_FLAGS (DESC_P_MASK | DESC_S_MASK | DESC_W_MASK | DESC_A_MASK)
static void load_seg_16_helper(CPUX86State *env, int seg, uint32_t selector)
{
cpu_x86_load_seg_cache(env, seg, selector, (selector << 4), 0xffff, X86_NON_CS_FLAGS);
cpu_x86_load_seg_cache(env, seg, selector, (selector << 4), 0xffff,
X86_NON_CS_FLAGS);
}
void cpu_get_fp80(uint64_t *pmant, uint16_t *pexp, floatx80 f);
floatx80 cpu_set_fp80(uint64_t mant, uint16_t upper);
@ -59,11 +59,16 @@ void x86_reg_reset(struct uc_struct *uc)
{
CPUArchState *env = uc->cpu->env_ptr;
env->features[FEAT_1_EDX] = CPUID_CX8 | CPUID_CMOV | CPUID_SSE2 | CPUID_FXSR | CPUID_SSE | CPUID_CLFLUSH;
env->features[FEAT_1_ECX] = CPUID_EXT_SSSE3 | CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_AES | CPUID_EXT_CX16;
env->features[FEAT_1_EDX] = CPUID_CX8 | CPUID_CMOV | CPUID_SSE2 |
CPUID_FXSR | CPUID_SSE | CPUID_CLFLUSH;
env->features[FEAT_1_ECX] = CPUID_EXT_SSSE3 | CPUID_EXT_SSE41 |
CPUID_EXT_SSE42 | CPUID_EXT_AES |
CPUID_EXT_CX16;
env->features[FEAT_8000_0001_EDX] = CPUID_EXT2_3DNOW | CPUID_EXT2_RDTSCP;
env->features[FEAT_8000_0001_ECX] = CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | CPUID_EXT3_SKINIT | CPUID_EXT3_CR8LEG;
env->features[FEAT_7_0_EBX] = CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP;
env->features[FEAT_8000_0001_ECX] = CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM |
CPUID_EXT3_SKINIT | CPUID_EXT3_CR8LEG;
env->features[FEAT_7_0_EBX] = CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 |
CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP;
memset(env->regs, 0, sizeof(env->regs));
memset(env->segs, 0, sizeof(env->segs));
@ -153,7 +158,8 @@ void x86_reg_reset(struct uc_struct *uc)
cpu_x86_update_cr0(env, CR0_PE_MASK); // protected mode
break;
case UC_MODE_64:
env->hflags |= HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK | HF_LMA_MASK | HF_OSFXSR_MASK;
env->hflags |= HF_CS32_MASK | HF_SS32_MASK | HF_CS64_MASK |
HF_LMA_MASK | HF_OSFXSR_MASK;
env->hflags &= ~(HF_ADDSEG_MASK);
env->efer |= MSR_EFER_LMA | MSR_EFER_LME; // extended mode activated
cpu_x86_update_cr0(env, CR0_PE_MASK); // protected mode
@ -181,8 +187,8 @@ static int x86_msr_read(CPUX86State *env, uc_x86_msr *msr)
env->regs[R_ECX] = ecx;
env->regs[R_EDX] = edx;
/* The implementation doesn't throw exception or return an error if there is one, so
* we will return 0. */
/* The implementation doesn't throw exception or return an error if there is
* one, so we will return 0. */
return 0;
}
@ -201,12 +207,13 @@ static int x86_msr_write(CPUX86State *env, uc_x86_msr *msr)
env->regs[R_EAX] = eax;
env->regs[R_EDX] = edx;
/* The implementation doesn't throw exception or return an error if there is one, so
* we will return 0. */
/* The implementation doesn't throw exception or return an error if there is
* one, so we will return 0. */
return 0;
}
static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode mode)
static void reg_read(CPUX86State *env, unsigned int regid, void *value,
uc_mode mode)
{
switch (regid) {
default:
@ -218,14 +225,13 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode
case UC_X86_REG_FP4:
case UC_X86_REG_FP5:
case UC_X86_REG_FP6:
case UC_X86_REG_FP7:
{
case UC_X86_REG_FP7: {
floatx80 reg = env->fpregs[regid - UC_X86_REG_FP0].d;
cpu_get_fp80(value, (uint16_t*)((char*)value+sizeof(uint64_t)), reg);
cpu_get_fp80(value, (uint16_t *)((char *)value + sizeof(uint64_t)),
reg);
}
return;
case UC_X86_REG_FPSW:
{
case UC_X86_REG_FPSW: {
uint16_t fpus = env->fpus;
fpus = fpus & ~0x3800;
fpus |= (env->fpstt & 0x7) << 11;
@ -235,8 +241,7 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode
case UC_X86_REG_FPCW:
*(uint16_t *)value = env->fpuc;
return;
case UC_X86_REG_FPTAG:
{
case UC_X86_REG_FPTAG: {
#define EXPD(fp) (fp.l.upper & 0x7fff)
#define MANTD(fp) (fp.l.lower)
#define MAXEXPD 0x7fff
@ -255,8 +260,8 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode
if (exp == 0 && mant == 0) {
/* zero */
fptag |= 1;
} else if (exp == 0 || exp == MAXEXPD
|| (mant & (1LL << 63)) == 0) {
} else if (exp == 0 || exp == MAXEXPD ||
(mant & (1LL << 63)) == 0) {
/* NaNs, infinity, denormal */
fptag |= 2;
}
@ -272,8 +277,7 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode
case UC_X86_REG_XMM4:
case UC_X86_REG_XMM5:
case UC_X86_REG_XMM6:
case UC_X86_REG_XMM7:
{
case UC_X86_REG_XMM7: {
float64 *dst = (float64 *)value;
XMMReg *reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
dst[0] = reg->_d[0];
@ -287,8 +291,7 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode
case UC_X86_REG_ST4:
case UC_X86_REG_ST5:
case UC_X86_REG_ST6:
case UC_X86_REG_ST7:
{
case UC_X86_REG_ST7: {
// value must be big enough to keep 80 bits (10 bytes)
memcpy(value, &FPST(regid - UC_X86_REG_ST0), 10);
return;
@ -308,8 +311,7 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode
case UC_X86_REG_YMM12:
case UC_X86_REG_YMM13:
case UC_X86_REG_YMM14:
case UC_X86_REG_YMM15:
{
case UC_X86_REG_YMM15: {
float64 *dst = (float64 *)value;
XMMReg *lo_reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_YMM0];
XMMReg *hi_reg = &env->ymmh_regs[regid - UC_X86_REG_YMM0];
@ -326,7 +328,8 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode
break;
case UC_MODE_16:
switch (regid) {
default: break;
default:
break;
case UC_X86_REG_ES:
*(int16_t *)value = env->segs[R_ES].selector;
return;
@ -797,8 +800,7 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode
case UC_X86_REG_XMM12:
case UC_X86_REG_XMM13:
case UC_X86_REG_XMM14:
case UC_X86_REG_XMM15:
{
case UC_X86_REG_XMM15: {
float64 *dst = (float64 *)value;
XMMReg *reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
dst[0] = reg->_d[0];
@ -819,7 +821,8 @@ static void reg_read(CPUX86State *env, unsigned int regid, void *value, uc_mode
return;
}
static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc_mode mode)
static int reg_write(CPUX86State *env, unsigned int regid, const void *value,
uc_mode mode)
{
int ret;
@ -833,15 +836,13 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
case UC_X86_REG_FP4:
case UC_X86_REG_FP5:
case UC_X86_REG_FP6:
case UC_X86_REG_FP7:
{
case UC_X86_REG_FP7: {
uint64_t mant = *(uint64_t *)value;
uint16_t upper = *(uint16_t *)((char *)value + sizeof(uint64_t));
env->fpregs[regid - UC_X86_REG_FP0].d = cpu_set_fp80(mant, upper);
}
return 0;
case UC_X86_REG_FPSW:
{
case UC_X86_REG_FPSW: {
uint16_t fpus = *(uint16_t *)value;
env->fpus = fpus & ~0x3800;
env->fpstt = (fpus >> 11) & 0x7;
@ -850,8 +851,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
case UC_X86_REG_FPCW:
cpu_set_fpuc(env, *(uint16_t *)value);
return 0;
case UC_X86_REG_FPTAG:
{
case UC_X86_REG_FPTAG: {
int i;
uint16_t fptag = *(uint16_t *)value;
for (i = 0; i < 8; i++) {
@ -860,8 +860,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
}
return 0;
}
break;
} break;
case UC_X86_REG_XMM0:
case UC_X86_REG_XMM1:
case UC_X86_REG_XMM2:
@ -869,8 +868,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
case UC_X86_REG_XMM4:
case UC_X86_REG_XMM5:
case UC_X86_REG_XMM6:
case UC_X86_REG_XMM7:
{
case UC_X86_REG_XMM7: {
float64 *src = (float64 *)value;
XMMReg *reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
reg->_d[0] = src[0];
@ -884,8 +882,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
case UC_X86_REG_ST4:
case UC_X86_REG_ST5:
case UC_X86_REG_ST6:
case UC_X86_REG_ST7:
{
case UC_X86_REG_ST7: {
// value must be big enough to keep 80 bits (10 bytes)
memcpy(&FPST(regid - UC_X86_REG_ST0), value, 10);
return 0;
@ -905,8 +902,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
case UC_X86_REG_YMM12:
case UC_X86_REG_YMM13:
case UC_X86_REG_YMM14:
case UC_X86_REG_YMM15:
{
case UC_X86_REG_YMM15: {
float64 *src = (float64 *)value;
XMMReg *lo_reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_YMM0];
XMMReg *hi_reg = &env->ymmh_regs[regid - UC_X86_REG_YMM0];
@ -924,7 +920,8 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
case UC_MODE_16:
switch (regid) {
default: break;
default:
break;
case UC_X86_REG_ES:
load_seg_16_helper(env, R_ES, *(uint16_t *)value);
return 0;
@ -1430,8 +1427,7 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
case UC_X86_REG_XMM12:
case UC_X86_REG_XMM13:
case UC_X86_REG_XMM14:
case UC_X86_REG_XMM15:
{
case UC_X86_REG_XMM15: {
float64 *src = (float64 *)value;
XMMReg *reg = (XMMReg *)&env->xmm_regs[regid - UC_X86_REG_XMM0];
reg->_d[0] = src[0];
@ -1452,7 +1448,8 @@ static int reg_write(CPUX86State *env, unsigned int regid, const void *value, uc
return 0;
}
int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
int count)
{
CPUX86State *env = &(X86_CPU(uc->cpu)->env);
int i;
@ -1466,7 +1463,8 @@ int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int coun
return 0;
}
int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count)
int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals,
int count)
{
CPUX86State *env = &(X86_CPU(uc->cpu)->env);
int i;
@ -1515,7 +1513,8 @@ int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, i
}
DEFAULT_VISIBILITY
int x86_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals, int count)
int x86_context_reg_read(struct uc_context *ctx, unsigned int *regs,
void **vals, int count)
{
CPUX86State *env = (CPUX86State *)ctx->data;
int i;
@ -1530,7 +1529,8 @@ int x86_context_reg_read(struct uc_context *ctx, unsigned int *regs, void **vals
}
DEFAULT_VISIBILITY
int x86_context_reg_write(struct uc_context *ctx, unsigned int *regs, void *const *vals, int count)
int x86_context_reg_write(struct uc_context *ctx, unsigned int *regs,
void *const *vals, int count)
{
CPUX86State *env = (CPUX86State *)ctx->data;
int i;
@ -1561,11 +1561,9 @@ static bool x86_stop_interrupt(struct uc_struct *uc, int intno)
static bool x86_insn_hook_validate(uint32_t insn_enum)
{
// for x86 we can only hook IN, OUT, and SYSCALL
if (insn_enum != UC_X86_INS_IN
&& insn_enum != UC_X86_INS_OUT
&& insn_enum != UC_X86_INS_SYSCALL
&& insn_enum != UC_X86_INS_SYSENTER
&& insn_enum != UC_X86_INS_CPUID) {
if (insn_enum != UC_X86_INS_IN && insn_enum != UC_X86_INS_OUT &&
insn_enum != UC_X86_INS_SYSCALL && insn_enum != UC_X86_INS_SYSENTER &&
insn_enum != UC_X86_INS_CPUID) {
return false;
}
return true;

View File

@ -6,10 +6,14 @@
#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);

View File

@ -52,7 +52,8 @@ static void reg_read(CPUM68KState *env, unsigned int regid, void *value)
*(int32_t *)value = env->dregs[regid - UC_M68K_REG_D0];
else {
switch (regid) {
default: break;
default:
break;
case UC_M68K_REG_PC:
*(int32_t *)value = env->pc;
break;
@ -70,7 +71,8 @@ static void reg_write(CPUM68KState *env, unsigned int regid, const void *value)
env->dregs[regid - UC_M68K_REG_D0] = *(uint32_t *)value;
else {
switch (regid) {
default: break;
default:
break;
case UC_M68K_REG_PC:
env->pc = *(uint32_t *)value;
break;
@ -78,7 +80,8 @@ static void reg_write(CPUM68KState *env, unsigned int regid, const void *value)
}
}
int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
int count)
{
CPUM68KState *env = &(M68K_CPU(uc->cpu)->env);
int i;
@ -92,7 +95,8 @@ 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);
int i;
@ -112,7 +116,8 @@ 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;
int i;
@ -127,7 +132,8 @@ 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;
int i;

View File

@ -5,10 +5,14 @@
#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);

View File

@ -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;
@ -76,7 +75,8 @@ static void reg_read(CPUMIPSState *env, unsigned int regid, void *value)
*(mipsreg_t *)value = env->active_tc.gpr[regid - UC_MIPS_REG_0];
else {
switch (regid) {
default: break;
default:
break;
case UC_MIPS_REG_PC:
*(mipsreg_t *)value = env->active_tc.PC;
break;
@ -101,7 +101,8 @@ static void reg_write(CPUMIPSState *env, unsigned int regid, const void *value)
env->active_tc.gpr[regid - UC_MIPS_REG_0] = *(mipsreg_t *)value;
else {
switch (regid) {
default: break;
default:
break;
case UC_MIPS_REG_PC:
env->active_tc.PC = *(mipsreg_t *)value;
break;
@ -124,7 +125,8 @@ static void reg_write(CPUMIPSState *env, unsigned int regid, const void *value)
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;
@ -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
{

View File

@ -5,17 +5,27 @@
#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);

View File

@ -85,7 +85,8 @@ static void reg_read(CPUPPCState *env, unsigned int regid, void *value)
*(ppcreg_t *)value = env->gpr[regid - UC_PPC_REG_0];
else {
switch (regid) {
default: break;
default:
break;
case UC_PPC_REG_PC:
*(ppcreg_t *)value = env->nip;
break;
@ -107,7 +108,8 @@ static void reg_write(CPUPPCState *env, unsigned int regid, const void *value)
env->gpr[regid - UC_PPC_REG_0] = *(ppcreg_t *)value;
else {
switch (regid) {
default: break;
default:
break;
case UC_PPC_REG_PC:
env->nip = *(ppcreg_t *)value;
break;
@ -123,7 +125,8 @@ static void reg_write(CPUPPCState *env, unsigned int regid, const void *value)
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;

View File

@ -5,13 +5,19 @@
#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);

View File

@ -36,9 +36,7 @@ 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)
{
@ -225,7 +223,8 @@ static void reg_write(CPURISCVState *env, unsigned int regid, const void *value)
}
}
int riscv_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count)
int riscv_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals,
int count)
{
CPURISCVState *env = &(RISCV_CPU(uc->cpu)->env);
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;
@ -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)
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)
int riscv64_context_reg_write(struct uc_context *ctx, unsigned int *regs,
void *const *vals, int count)
#endif
{
CPURISCVState *env = (CPURISCVState *)ctx->data;

View File

@ -6,13 +6,19 @@
#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);

View File

@ -68,7 +68,8 @@ static void reg_read(CPUSPARCState *env, unsigned int regid, void *value)
*(int32_t *)value = env->regwptr[16 + regid - UC_SPARC_REG_I0];
else {
switch (regid) {
default: break;
default:
break;
case UC_SPARC_REG_PC:
*(int32_t *)value = env->pc;
break;
@ -90,7 +91,8 @@ static void reg_write(CPUSPARCState *env, unsigned int regid, const void *value)
env->regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint32_t *)value;
else {
switch (regid) {
default: break;
default:
break;
case UC_SPARC_REG_PC:
env->pc = *(uint32_t *)value;
env->npc = *(uint32_t *)value + 4;
@ -101,7 +103,8 @@ static void reg_write(CPUSPARCState *env, unsigned int regid, const void *value)
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;
@ -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;

View File

@ -5,13 +5,19 @@
#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);

View File

@ -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,9 +39,13 @@ 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);
}
}
@ -50,19 +54,25 @@ static void hook_code(uc_engine *uc, uint64_t addr, uint32_t size, void *user_da
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);
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);
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);
printf("not ok - uc_emu_stop fail during hook_code callback, addr: "
"0x%" PRIx64 "\n",
addr);
_exit(-1);
}
break;
@ -72,27 +82,37 @@ static void hook_code(uc_engine *uc, uint64_t addr, uint32_t size, void *user_da
}
// callback for tracing invalid memory access (READ/WRITE/EXEC)
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);
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);
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);
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);
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);
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);
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);
@ -130,12 +151,14 @@ static void do_nx_demo(bool cause_fault)
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
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
if (cause_fault) {
// insert instruction to trigger U_PROT_EXEC change (see hook_code function)
// insert instruction to trigger U_PROT_EXEC change (see hook_code
// function)
code_buf[0x1000] = 0x41; // inc ecx at page1
}
@ -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");
@ -215,7 +240,8 @@ static void do_perms_demo(bool change_perms)
code_buf[sizeof(WRITE_DEMO) - 1 + 1000] = 0xf4; // hlt
if (change_perms) {
// write protect memory area [0x101000, 0x101fff]. see hook_code function
// write protect memory area [0x101000, 0x101fff]. see hook_code
// function
code_buf[0] = 0x41; // inc ecx
}
@ -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;
@ -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);
}

View File

@ -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 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)
@ -47,8 +55,8 @@ static void test_arm(void)
// 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;
}
@ -100,8 +108,8 @@ static void test_thumb(void)
// 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;
}
@ -153,8 +161,8 @@ static void test_armeb(void)
// 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;
}
@ -206,8 +214,8 @@ static void test_thumbeb(void)
// 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;
}
@ -295,7 +304,8 @@ static void test_thumb_mrs(void)
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);
}

View File

@ -6,23 +6,30 @@
#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)
@ -31,23 +38,21 @@ static void test_arm64_mem_fetch(void)
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;
}
@ -96,8 +101,8 @@ static void test_arm64(void)
// 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;
}
@ -150,8 +155,8 @@ static void test_arm64eb(void)
// 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;
}

View File

@ -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};
// 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;
}

View File

@ -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)
@ -55,8 +59,8 @@ static void test_m68k(void)
// 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;
}

View File

@ -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)
@ -37,8 +41,8 @@ static void test_mips_eb(void)
// 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
@ -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

View File

@ -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)
@ -39,8 +42,8 @@ static void test_ppc(void)
// Initialize emulator in PPC mode
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;
}
@ -79,7 +82,6 @@ static void test_ppc(void)
uc_close(uc);
}
int main(int argc, char **argv, char **envp)
{
test_ppc();

View File

@ -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;
}
@ -406,7 +412,8 @@ static bool hook_memalloc(uc_engine *uc, uc_mem_type type, uint64_t address,
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",
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);
@ -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");
}

View File

@ -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)
@ -39,8 +43,8 @@ static void test_sparc(void)
// Initialize emulator in Sparc mode
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

View File

@ -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_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_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,12 +80,15 @@ 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(">>> 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()
@ -71,15 +97,16 @@ 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",
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);
@ -90,23 +117,26 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
// 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;
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",
printf(">>> Memory is being WRITE at 0x%" PRIx64
", data size = %u, data value = 0x%" PRIx64 "\n",
address, size, value);
break;
}
@ -120,7 +150,8 @@ 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:
@ -139,14 +170,16 @@ static uint32_t hook_in(uc_engine *uc, uint32_t port, int size, void *user_data)
}
// callback for OUT instruction (X86).
static void hook_out(uc_engine *uc, uint32_t port, int size, uint32_t value, void *user_data)
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) {
@ -185,7 +218,8 @@ static bool hook_memalloc(uc_engine *uc, uc_mem_type type, uint64_t address,
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",
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);
@ -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
@ -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
@ -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
@ -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");
@ -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
@ -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
@ -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
@ -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,7 +718,6 @@ 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
@ -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
@ -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
@ -1136,7 +1187,8 @@ static void test_i386_invalid_mem_read_in_tb(void)
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,10 +1212,12 @@ 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));
@ -1174,9 +1229,12 @@ 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);
@ -1217,14 +1275,14 @@ 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.
// 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,24 +1290,32 @@ 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;
}
@ -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();
@ -1327,16 +1393,13 @@ int main(int argc, char **argv, char **envp)
test_i386_invalid_mem_write();
test_i386_jump_invalid();
// test_i386_invalid_c6c7();
}
else if (!strcmp(argv[1], "-64")) {
} 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();

View File

@ -63,7 +63,9 @@ struct SegmentDescriptor {
};
#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))
/**
@ -103,23 +105,29 @@ do { \
/******************************************************************************/
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);
printf("mem write at 0x%" PRIx64 ", size = %u, value = 0x%" PRIx64 "\n",
address, size, value);
break;
default:
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);
}
//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->base0 = base & 0xffff;
@ -174,13 +182,16 @@ 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_cs = 0x73;
@ -194,7 +205,8 @@ static void gdt_demo()
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[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
@ -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
@ -229,7 +243,8 @@ static void gdt_demo()
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
@ -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);

View File

@ -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)
// 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);
@ -72,10 +80,12 @@ static void hook_intr(uc_engine *uc, uint32_t intno, void *user_data)
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",
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",
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;
@ -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 {

File diff suppressed because it is too large Load Diff

View File

@ -3,13 +3,16 @@
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() {
static void test_arm_nop()
{
uc_engine *uc;
char code[] = "\x00\xf0\x20\xe3"; // nop
int r_r0 = 0x1234;
@ -29,7 +32,8 @@ static void test_arm_nop() {
OK(uc_close(uc));
}
static void test_arm_thumb_sub() {
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() {
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
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() {
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) {
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() {
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,14 +165,17 @@ static void test_arm_thumb_ite() {
OK(uc_close(uc));
}
static void test_arm_m_thumb_mrs() {
static void test_arm_m_thumb_mrs()
{
uc_engine *uc;
char code[] = "\xef\xf3\x14\x80\xef\xf3\x00\x81"; // mrs r0, control; mrs r1, apsr
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));
@ -168,7 +190,8 @@ static void test_arm_m_thumb_mrs() {
OK(uc_close(uc));
}
static void test_arm_m_control() {
static void test_arm_m_control()
{
uc_engine *uc;
int r_control, r_msp, r_psp;
@ -201,10 +224,13 @@ static void test_arm_m_control() {
//
// 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() {
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,14 +259,14 @@ 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_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},
@ -245,5 +274,4 @@ TEST_LIST = {
{"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 }
};
{NULL, NULL}};

View File

@ -3,13 +3,16 @@
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() {
static void test_arm64_until()
{
uc_engine *uc;
char code[] = "\x30\x00\x80\xd2\x11\x04\x80\xd2\x9c\x23\x00\x91";
@ -47,8 +50,4 @@ static void test_arm64_until() {
OK(uc_close(uc));
}
TEST_LIST = {
{ "test_arm64_until", test_arm64_until },
{ NULL, NULL }
};
TEST_LIST = {{"test_arm64_until", test_arm64_until}, {NULL, NULL}};

View File

@ -3,6 +3,4 @@
const uint64_t code_start = 0x1000;
const uint64_t code_len = 0x4000;
TEST_LIST = {
{ NULL, NULL }
};
TEST_LIST = {{NULL, NULL}};

View File

@ -1,34 +1,40 @@
#include "unicorn_test.h"
static void test_map_correct() {
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));
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() {
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));
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_LIST = {{"test_map_correct", test_map_correct},
{"test_map_wrapping", test_map_wrapping},
{ NULL, NULL }
};
{NULL, NULL}};

View File

@ -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() {
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() {
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,12 +49,15 @@ static void test_mips_eb_ori() {
OK(uc_close(uc));
}
static void test_mips_stop_at_branch() {
static void test_mips_stop_at_branch()
{
uc_engine *uc;
char code[] = "\x02\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00"; // j 0x8; nop;
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));
@ -62,12 +71,15 @@ static void test_mips_stop_at_branch() {
OK(uc_close(uc));
}
static void test_mips_stop_at_delay_slot() {
static void test_mips_stop_at_delay_slot()
{
uc_engine *uc;
char code[] = "\x02\x00\x00\x08\x00\x00\x00\x00\x00\x00\x00\x00"; // j 0x8; nop;
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));
@ -81,12 +93,14 @@ static void test_mips_stop_at_delay_slot() {
OK(uc_close(uc));
}
static void test_mips_lwx_exception_issue_1314() {
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
@ -118,5 +132,4 @@ TEST_LIST = {
{"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 }
};
{NULL, NULL}};

View File

@ -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() {
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, &reg));
@ -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}};

View File

@ -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() {
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() {
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,7 +55,8 @@ static void test_riscv64_nop() {
OK(uc_close(uc));
}
static void test_riscv32_until_pc_update() {
static void test_riscv32_until_pc_update()
{
uc_engine *uc;
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
@ -64,7 +71,8 @@ static void test_riscv32_until_pc_update() {
uint32_t r_pc = 0x0000;
uint32_t r_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));
@ -88,7 +96,8 @@ static void test_riscv32_until_pc_update() {
OK(uc_close(uc));
}
static void test_riscv64_until_pc_update() {
static void test_riscv64_until_pc_update()
{
uc_engine *uc;
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
@ -103,7 +112,8 @@ static void test_riscv64_until_pc_update() {
uint64_t r_pc = 0x0000;
uint64_t r_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));
@ -126,7 +136,8 @@ static void test_riscv64_until_pc_update() {
OK(uc_close(uc));
}
static void test_riscv32_3steps_pc_update() {
static void test_riscv32_3steps_pc_update()
{
uc_engine *uc;
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
@ -141,7 +152,8 @@ static void test_riscv32_3steps_pc_update() {
uint32_t r_pc = 0x0000;
uint32_t r_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));
@ -165,7 +177,8 @@ static void test_riscv32_3steps_pc_update() {
OK(uc_close(uc));
}
static void test_riscv64_3steps_pc_update() {
static void test_riscv64_3steps_pc_update()
{
uc_engine *uc;
char code[] = "\x93\x02\x10\x00\x13\x03\x00\x02\x13\x01\x81\x00";
@ -180,7 +193,8 @@ static void test_riscv64_3steps_pc_update() {
uint64_t r_pc = 0x0000;
uint64_t r_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));
@ -203,13 +217,10 @@ static void test_riscv64_3steps_pc_update() {
OK(uc_close(uc));
}
TEST_LIST = {
{ "test_riscv32_nop", test_riscv32_nop },
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 }
};
{NULL, NULL}};

View File

@ -3,6 +3,4 @@
const uint64_t code_start = 0x1000;
const uint64_t code_len = 0x4000;
TEST_LIST = {
{ NULL, NULL }
};
TEST_LIST = {{NULL, NULL}};

View File

@ -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,21 +16,25 @@ 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) {
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() {
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);
@ -44,7 +50,9 @@ 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) {
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;
@ -52,14 +60,16 @@ static void test_x86_out_callback(uc_engine* uc, uint32_t port, int size, uint32
result->value = value;
}
static void test_x86_out() {
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);
@ -82,7 +92,10 @@ 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) {
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;
@ -103,23 +116,24 @@ 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() {
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";
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},
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_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);
@ -134,9 +148,11 @@ static void test_x86_mem_hook_all() {
OK(uc_close(uc));
}
static void test_x86_inc_dec_pxor() {
static void test_x86_inc_dec_pxor()
{
uc_engine *uc;
char code[] = "\x41\x4a\x66\x0f\xef\xc1"; // INC ecx; DEC edx; PXOR xmm0, xmm1
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() {
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
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,7 +196,8 @@ static void test_x86_relative_jump() {
OK(uc_close(uc));
}
static void test_x86_loop() {
static void test_x86_loop()
{
uc_engine *uc;
char code[] = "\x41\x4a\xeb\xfe"; // inc ecx; dec edx; jmp $;
int r_ecx = 0x1234;
@ -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() {
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() {
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() {
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,7 +270,8 @@ static void test_x86_64_syscall_callback(uc_engine* uc, void* user_data) {
TEST_CHECK(rax == 0x100);
}
static void test_x86_64_syscall() {
static void test_x86_64_syscall()
{
uc_engine *uc;
uc_hook hook;
char code[] = "\x0f\x05"; // syscall
@ -248,7 +279,8 @@ static void test_x86_64_syscall() {
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,7 +288,8 @@ static void test_x86_64_syscall() {
OK(uc_close(uc));
}
static void test_x86_16_add() {
static void test_x86_16_add()
{
uc_engine *uc;
char code[] = "\x00\x00"; // add byte ptr [bx + si], al
uint16_t r_ax = 7;
@ -277,7 +310,8 @@ static void test_x86_16_add() {
OK(uc_close(uc));
}
static void test_x86_reg_save() {
static void test_x86_reg_save()
{
uc_engine *uc;
uc_context *ctx;
char code[] = "\x40"; // inc eax
@ -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() {
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];
@ -354,10 +400,13 @@ static void test_x86_x87_fnstenv_callback(uc_engine* uc, uint64_t address, uint3
}
}
static void test_x86_x87_fnstenv() {
static void test_x86_x87_fnstenv()
{
uc_engine *uc;
uc_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,7 +415,8 @@ 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));
@ -377,14 +427,19 @@ static void test_x86_x87_fnstenv() {
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() {
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,7 +485,8 @@ static bool test_x86_missing_code_callback(uc_engine* uc, uc_mem_type type, uint
return true;
}
static void test_x86_missing_code() {
static void test_x86_missing_code()
{
uc_engine *uc;
uc_hook hook;
int r_ecx = 0x1234;
@ -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,7 +510,8 @@ static void test_x86_missing_code() {
OK(uc_close(uc));
}
static void test_x86_smc_xor() {
static void test_x86_smc_xor()
{
uc_engine *uc;
/*
* 0x1000 xor dword ptr [edi+0x3], eax ; edi=0x1000, eax=0xbc4177e6
@ -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,17 +559,15 @@ 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() {
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));
@ -504,11 +577,13 @@ static void test_x86_mmio_uc_mem_rw() {
OK(uc_close(uc));
}
static void test_x86_sysenter_hook(uc_engine* uc, void* user) {
static void test_x86_sysenter_hook(uc_engine *uc, void *user)
{
*(int *)user = 1;
}
static void test_x86_sysenter() {
static void test_x86_sysenter()
{
uc_engine *uc;
char code[] = "\x0F\x34"; // sysenter
uc_hook h;
@ -516,7 +591,8 @@ static void test_x86_sysenter() {
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,13 +601,15 @@ 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, &reg));
}
static void test_x86_hook_cpuid() {
static void test_x86_hook_cpuid()
{
uc_engine *uc;
char code[] = "\x40\x0F\xA2"; // INC EAX; CPUID
uc_hook h;
@ -539,7 +617,8 @@ static void test_x86_hook_cpuid() {
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,8 +629,7 @@ static void test_x86_hook_cpuid() {
OK(uc_close(uc));
}
TEST_LIST = {
{ "test_x86_in", test_x86_in },
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},
@ -563,7 +641,8 @@ TEST_LIST = {
{"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_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},
@ -571,5 +650,4 @@ TEST_LIST = {
{"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 }
};
{NULL, NULL}};

227
uc.c
View File

@ -37,14 +37,12 @@ unsigned int uc_version(unsigned int *major, unsigned int *minor)
return (UC_API_MAJOR << 8) + UC_API_MINOR;
}
UNICORN_EXPORT
uc_err uc_errno(uc_engine *uc)
{
return uc->errnum;
}
UNICORN_EXPORT
const char *uc_strerror(uc_err code)
{
@ -96,41 +94,48 @@ const char *uc_strerror(uc_err code)
}
}
UNICORN_EXPORT
bool uc_arch_supported(uc_arch arch)
{
switch (arch) {
#ifdef UNICORN_HAS_ARM
case UC_ARCH_ARM: return true;
case UC_ARCH_ARM:
return true;
#endif
#ifdef UNICORN_HAS_ARM64
case UC_ARCH_ARM64: return true;
case UC_ARCH_ARM64:
return true;
#endif
#ifdef UNICORN_HAS_M68K
case UC_ARCH_M68K: return true;
case UC_ARCH_M68K:
return true;
#endif
#ifdef UNICORN_HAS_MIPS
case UC_ARCH_MIPS: return true;
case UC_ARCH_MIPS:
return true;
#endif
#ifdef UNICORN_HAS_PPC
case UC_ARCH_PPC: return true;
case UC_ARCH_PPC:
return true;
#endif
#ifdef UNICORN_HAS_SPARC
case UC_ARCH_SPARC: return true;
case UC_ARCH_SPARC:
return true;
#endif
#ifdef UNICORN_HAS_X86
case UC_ARCH_X86: return true;
case UC_ARCH_X86:
return true;
#endif
#ifdef UNICORN_HAS_RISCV
case UC_ARCH_RISCV: return true;
case UC_ARCH_RISCV:
return true;
#endif
/* Invalid or disabled arch */
default: return false;
default:
return false;
}
}
UNICORN_EXPORT
uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
{
@ -161,8 +166,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
break;
#ifdef UNICORN_HAS_M68K
case UC_ARCH_M68K:
if ((mode & ~UC_MODE_M68K_MASK) ||
!(mode & UC_MODE_BIG_ENDIAN)) {
if ((mode & ~UC_MODE_M68K_MASK) || !(mode & UC_MODE_BIG_ENDIAN)) {
free(uc);
return UC_ERR_MODE;
}
@ -171,8 +175,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
#endif
#ifdef UNICORN_HAS_X86
case UC_ARCH_X86:
if ((mode & ~UC_MODE_X86_MASK) ||
(mode & UC_MODE_BIG_ENDIAN) ||
if ((mode & ~UC_MODE_X86_MASK) || (mode & UC_MODE_BIG_ENDIAN) ||
!(mode & (UC_MODE_16 | UC_MODE_32 | UC_MODE_64))) {
free(uc);
return UC_ERR_MODE;
@ -211,7 +214,8 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
break;
#endif
#if defined(UNICORN_HAS_MIPS) || defined(UNICORN_HAS_MIPSEL) || defined(UNICORN_HAS_MIPS64) || defined(UNICORN_HAS_MIPS64EL)
#if defined(UNICORN_HAS_MIPS) || defined(UNICORN_HAS_MIPSEL) || \
defined(UNICORN_HAS_MIPS64) || defined(UNICORN_HAS_MIPS64EL)
case UC_ARCH_MIPS:
if ((mode & ~UC_MODE_MIPS_MASK) ||
!(mode & (UC_MODE_MIPS32 | UC_MODE_MIPS64))) {
@ -246,8 +250,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
#ifdef UNICORN_HAS_SPARC
case UC_ARCH_SPARC:
if ((mode & ~UC_MODE_SPARC_MASK) ||
!(mode & UC_MODE_BIG_ENDIAN) ||
if ((mode & ~UC_MODE_SPARC_MASK) || !(mode & UC_MODE_BIG_ENDIAN) ||
!(mode & (UC_MODE_SPARC32 | UC_MODE_SPARC64))) {
free(uc);
return UC_ERR_MODE;
@ -261,8 +264,7 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
#endif
#ifdef UNICORN_HAS_PPC
case UC_ARCH_PPC:
if ((mode & ~UC_MODE_PPC_MASK) ||
!(mode & UC_MODE_BIG_ENDIAN) ||
if ((mode & ~UC_MODE_PPC_MASK) || !(mode & UC_MODE_BIG_ENDIAN) ||
!(mode & (UC_MODE_PPC32 | UC_MODE_PPC64))) {
free(uc);
return UC_ERR_MODE;
@ -291,7 +293,6 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
}
break;
#endif
}
if (uc->init_arch == NULL) {
@ -317,7 +318,6 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
}
}
UNICORN_EXPORT
uc_err uc_close(uc_engine *uc)
{
@ -403,7 +403,6 @@ uc_err uc_close(uc_engine *uc)
return UC_ERR_OK;
}
UNICORN_EXPORT
uc_err uc_reg_read_batch(uc_engine *uc, int *ids, void **vals, int count)
{
@ -417,7 +416,6 @@ uc_err uc_reg_read_batch(uc_engine *uc, int *ids, void **vals, int count)
return ret;
}
UNICORN_EXPORT
uc_err uc_reg_write_batch(uc_engine *uc, int *ids, void *const *vals, int count)
{
@ -431,7 +429,6 @@ uc_err uc_reg_write_batch(uc_engine *uc, int *ids, void *const *vals, int count)
return ret;
}
UNICORN_EXPORT
uc_err uc_reg_read(uc_engine *uc, int regid, void *value)
{
@ -464,7 +461,6 @@ static bool check_mem_area(uc_engine *uc, uint64_t address, size_t size)
return (count == size);
}
UNICORN_EXPORT
uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *_bytes, size_t size)
{
@ -488,7 +484,8 @@ uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *_bytes, size_t size)
MemoryRegion *mr = memory_mapping(uc, address);
if (mr) {
len = (size_t)MIN(size - count, mr->end - address);
if (uc->read_mem(&uc->address_space_memory, address, bytes, len) == false) {
if (uc->read_mem(&uc->address_space_memory, address, bytes, len) ==
false) {
break;
}
count += len;
@ -507,7 +504,8 @@ uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *_bytes, size_t size)
}
UNICORN_EXPORT
uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *_bytes, size_t size)
uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *_bytes,
size_t size)
{
size_t count = 0, len;
const uint8_t *bytes = _bytes;
@ -530,12 +528,14 @@ uc_err uc_mem_write(uc_engine *uc, uint64_t address, const void *_bytes, size_t
if (mr) {
uint32_t operms = mr->perms;
if (!(operms & UC_PROT_WRITE)) { // write protected
// but this is not the program accessing memory, so temporarily mark writable
// but this is not the program accessing memory, so temporarily
// mark writable
uc->readonly_mem(mr, false);
}
len = (size_t)MIN(size - count, mr->end - address);
if (uc->write_mem(&uc->address_space_memory, address, bytes, len) == false) {
if (uc->write_mem(&uc->address_space_memory, address, bytes, len) ==
false) {
break;
}
@ -586,11 +586,12 @@ static void *_timeout_fn(void *arg)
static void enable_emu_timer(uc_engine *uc, uint64_t timeout)
{
uc->timeout = timeout;
qemu_thread_create(uc, &uc->timer, "timeout", _timeout_fn,
uc, QEMU_THREAD_JOINABLE);
qemu_thread_create(uc, &uc->timer, "timeout", _timeout_fn, uc,
QEMU_THREAD_JOINABLE);
}
static void hook_count_cb(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data)
static void hook_count_cb(struct uc_struct *uc, uint64_t address, uint32_t size,
void *user_data)
{
// count this instruction. ah ah ah.
uc->emu_counter++;
@ -608,7 +609,8 @@ static void clear_deleted_hooks(uc_engine *uc)
struct hook *hook;
int i;
for (cur = uc->hooks_to_del.head; cur != NULL && (hook = (struct hook *)cur->data); cur = cur->next) {
for (cur = uc->hooks_to_del.head;
cur != NULL && (hook = (struct hook *)cur->data); cur = cur->next) {
assert(hook->to_delete);
for (i = 0; i < UC_HOOK_MAX; i++) {
if (list_remove(&uc->hook[i], (void *)hook)) {
@ -626,7 +628,8 @@ static void clear_deleted_hooks(uc_engine *uc)
}
UNICORN_EXPORT
uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count)
uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until,
uint64_t timeout, size_t count)
{
// reset the counter
uc->emu_counter = 0;
@ -717,7 +720,8 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time
// so instead of appending, we must insert the hook at the begin
// of the hook list
uc->hook_insert = 1;
err = uc_hook_add(uc, &uc->count_hook, UC_HOOK_CODE, hook_count_cb, NULL, 1, 0);
err = uc_hook_add(uc, &uc->count_hook, UC_HOOK_CODE, hook_count_cb,
NULL, 1, 0);
// restore to append mode for uc_hook_add()
uc->hook_insert = 0;
if (err != UC_ERR_OK) {
@ -747,7 +751,6 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time
return uc->invalid_error;
}
UNICORN_EXPORT
uc_err uc_emu_stop(uc_engine *uc)
{
@ -765,14 +768,16 @@ uc_err uc_emu_stop(uc_engine *uc)
return UC_ERR_OK;
}
// return target index where a memory region at the address exists, or could be inserted
// return target index where a memory region at the address exists, or could be
// inserted
//
// address either is inside the mapping at the returned index, or is in free space before
// the next mapping.
// address either is inside the mapping at the returned index, or is in free
// space before the next mapping.
//
// if there is overlap, between regions, ending address will be higher than the starting
// address of the mapping at returned index
static int bsearch_mapped_blocks(const uc_engine *uc, uint64_t address) {
// if there is overlap, between regions, ending address will be higher than the
// starting address of the mapping at returned index
static int bsearch_mapped_blocks(const uc_engine *uc, uint64_t address)
{
int left, right, mid;
MemoryRegion *mapping;
@ -817,7 +822,8 @@ static bool memory_overlap(struct uc_struct *uc, uint64_t begin, size_t size)
}
// common setup/error checking shared between uc_mem_map and uc_mem_map_ptr
static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, MemoryRegion *block)
static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size,
uint32_t perms, MemoryRegion *block)
{
MemoryRegion **regions;
int pos;
@ -827,7 +833,8 @@ static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t per
}
if ((uc->mapped_block_count & (MEM_BLOCK_INCR - 1)) == 0) { // time to grow
regions = (MemoryRegion**)g_realloc(uc->mapped_blocks,
regions = (MemoryRegion **)g_realloc(
uc->mapped_blocks,
sizeof(MemoryRegion *) * (uc->mapped_block_count + MEM_BLOCK_INCR));
if (regions == NULL) {
return UC_ERR_NOMEM;
@ -838,7 +845,8 @@ static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t per
pos = bsearch_mapped_blocks(uc, block->addr);
// shift the array right to give space for the new pointer
memmove(&uc->mapped_blocks[pos + 1], &uc->mapped_blocks[pos], sizeof(MemoryRegion*) * (uc->mapped_block_count - pos));
memmove(&uc->mapped_blocks[pos + 1], &uc->mapped_blocks[pos],
sizeof(MemoryRegion *) * (uc->mapped_block_count - pos));
uc->mapped_blocks[pos] = block;
uc->mapped_block_count++;
@ -846,7 +854,8 @@ static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t per
return UC_ERR_OK;
}
static uc_err mem_map_check(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
static uc_err mem_map_check(uc_engine *uc, uint64_t address, size_t size,
uint32_t perms)
{
if (size == 0) {
// invalid memory mapping
@ -895,11 +904,13 @@ uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
return res;
}
return mem_map(uc, address, size, perms, uc->memory_map(uc, address, size, perms));
return mem_map(uc, address, size, perms,
uc->memory_map(uc, address, size, perms));
}
UNICORN_EXPORT
uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr)
uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size,
uint32_t perms, void *ptr)
{
uc_err res;
@ -916,7 +927,8 @@ uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t per
return res;
}
return mem_map(uc, address, size, UC_PROT_ALL, uc->memory_map_ptr(uc, address, size, perms, ptr));
return mem_map(uc, address, size, UC_PROT_ALL,
uc->memory_map_ptr(uc, address, size, perms, ptr));
}
UNICORN_EXPORT
@ -937,7 +949,8 @@ uc_err uc_mmio_map(uc_engine *uc, uint64_t address, size_t size,
// The callbacks do not need to be checked for NULL here, as their presence
// (or lack thereof) will determine the permissions used.
return mem_map(uc, address, size, UC_PROT_NONE,
uc->memory_map_io(uc, address, size, read_cb, write_cb, user_data_read, user_data_write));
uc->memory_map_io(uc, address, size, read_cb, write_cb,
user_data_read, user_data_write));
}
// Create a backup copy of the indicated MemoryRegion.
@ -946,7 +959,8 @@ static uint8_t *copy_region(struct uc_struct *uc, MemoryRegion *mr)
{
uint8_t *block = (uint8_t *)g_malloc0((size_t)int128_get64(mr->size));
if (block != NULL) {
uc_err err = uc_mem_read(uc, mr->addr, block, (size_t)int128_get64(mr->size));
uc_err err =
uc_mem_read(uc, mr->addr, block, (size_t)int128_get64(mr->size));
if (err != UC_ERR_OK) {
free(block);
block = NULL;
@ -971,8 +985,8 @@ static uint8_t *copy_region(struct uc_struct *uc, MemoryRegion *mr)
*/
// TODO: investigate whether qemu region manipulation functions already offered
// this capability
static bool split_region(struct uc_struct *uc, MemoryRegion *mr, uint64_t address,
size_t size, bool do_delete)
static bool split_region(struct uc_struct *uc, MemoryRegion *mr,
uint64_t address, size_t size, bool do_delete)
{
uint8_t *backup;
uint32_t perms;
@ -999,8 +1013,10 @@ static bool split_region(struct uc_struct *uc, MemoryRegion *mr, uint64_t addres
return false;
}
QLIST_FOREACH(block, &uc->ram_list.blocks, next) {
if (block->offset <= mr->addr && block->used_length >= (mr->end - mr->addr)) {
QLIST_FOREACH(block, &uc->ram_list.blocks, next)
{
if (block->offset <= mr->addr &&
block->used_length >= (mr->end - mr->addr)) {
break;
}
}
@ -1022,13 +1038,15 @@ static bool split_region(struct uc_struct *uc, MemoryRegion *mr, uint64_t addres
}
}
// save the essential information required for the split before mr gets deleted
// save the essential information required for the split before mr gets
// deleted
perms = mr->perms;
begin = mr->addr;
end = mr->end;
// unmap this region first, then do split it later
if (uc_mem_unmap(uc, mr->addr, (size_t)int128_get64(mr->size)) != UC_ERR_OK) {
if (uc_mem_unmap(uc, mr->addr, (size_t)int128_get64(mr->size)) !=
UC_ERR_OK) {
goto error;
}
@ -1052,10 +1070,10 @@ static bool split_region(struct uc_struct *uc, MemoryRegion *mr, uint64_t addres
r_size = (size_t)(end - chunk_end);
m_size = (size_t)(chunk_end - address);
// If there are error in any of the below operations, things are too far gone
// at that point to recover. Could try to remap orignal region, but these smaller
// allocation just failed so no guarantee that we can recover the original
// allocation at this point
// If there are error in any of the below operations, things are too far
// gone at that point to recover. Could try to remap orignal region, but
// these smaller allocation just failed so no guarantee that we can recover
// the original allocation at this point
if (l_size > 0) {
if (!prealloc) {
if (uc_mem_map(uc, begin, l_size, perms) != UC_ERR_OK) {
@ -1076,11 +1094,13 @@ static bool split_region(struct uc_struct *uc, MemoryRegion *mr, uint64_t addres
if (uc_mem_map(uc, address, m_size, perms) != UC_ERR_OK) {
goto error;
}
if (uc_mem_write(uc, address, backup + l_size, m_size) != UC_ERR_OK) {
if (uc_mem_write(uc, address, backup + l_size, m_size) !=
UC_ERR_OK) {
goto error;
}
} else {
if (uc_mem_map_ptr(uc, address, m_size, perms, backup + l_size) != UC_ERR_OK) {
if (uc_mem_map_ptr(uc, address, m_size, perms, backup + l_size) !=
UC_ERR_OK) {
goto error;
}
}
@ -1091,11 +1111,13 @@ static bool split_region(struct uc_struct *uc, MemoryRegion *mr, uint64_t addres
if (uc_mem_map(uc, chunk_end, r_size, perms) != UC_ERR_OK) {
goto error;
}
if (uc_mem_write(uc, chunk_end, backup + l_size + m_size, r_size) != UC_ERR_OK) {
if (uc_mem_write(uc, chunk_end, backup + l_size + m_size, r_size) !=
UC_ERR_OK) {
goto error;
}
} else {
if (uc_mem_map_ptr(uc, chunk_end, r_size, perms, backup + l_size + m_size) != UC_ERR_OK) {
if (uc_mem_map_ptr(uc, chunk_end, r_size, perms,
backup + l_size + m_size) != UC_ERR_OK) {
goto error;
}
}
@ -1114,7 +1136,8 @@ error:
}
UNICORN_EXPORT
uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, uint32_t perms)
uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size,
uint32_t perms)
{
MemoryRegion *mr;
uint64_t addr = address;
@ -1163,7 +1186,8 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, uint3
mr = memory_mapping(uc, addr);
// will this remove EXEC permission?
if (((mr->perms & UC_PROT_EXEC) != 0) && ((perms & UC_PROT_EXEC) == 0)) {
if (((mr->perms & UC_PROT_EXEC) != 0) &&
((perms & UC_PROT_EXEC) == 0)) {
remove_exec = true;
}
mr->perms = perms;
@ -1173,7 +1197,8 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, uint3
addr += len;
}
// if EXEC permission is removed, then quit TB and continue at the same place
// if EXEC permission is removed, then quit TB and continue at the same
// place
if (remove_exec) {
uc->quit_request = true;
uc_emu_stop(uc);
@ -1253,13 +1278,15 @@ MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address)
// try with the cache index first
i = uc->mapped_block_cache_index;
if (i < uc->mapped_block_count && address >= uc->mapped_blocks[i]->addr && address < uc->mapped_blocks[i]->end) {
if (i < uc->mapped_block_count && address >= uc->mapped_blocks[i]->addr &&
address < uc->mapped_blocks[i]->end) {
return uc->mapped_blocks[i];
}
i = bsearch_mapped_blocks(uc, address);
if (i < uc->mapped_block_count && address >= uc->mapped_blocks[i]->addr && address <= uc->mapped_blocks[i]->end - 1)
if (i < uc->mapped_block_count && address >= uc->mapped_blocks[i]->addr &&
address <= uc->mapped_blocks[i]->end - 1)
return uc->mapped_blocks[i];
// not found
@ -1352,7 +1379,6 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
return ret;
}
UNICORN_EXPORT
uc_err uc_hook_del(uc_engine *uc, uc_hook hh)
{
@ -1375,13 +1401,18 @@ uc_err uc_hook_del(uc_engine *uc, uc_hook hh)
}
// TCG helper
void helper_uc_tracecode(int32_t size, uc_hook_idx index, void *handle, int64_t address);
void helper_uc_tracecode(int32_t size, uc_hook_idx index, void *handle, int64_t address)
void helper_uc_tracecode(int32_t size, uc_hook_idx index, void *handle,
int64_t address);
void helper_uc_tracecode(int32_t size, uc_hook_idx index, void *handle,
int64_t address)
{
struct uc_struct *uc = handle;
struct list_item *cur;
struct hook *hook;
int hook_flags = index & UC_HOOK_FLAG_MASK; // The index here may contain additional flags. See the comments of uc_hook_idx for details.
int hook_flags =
index &
UC_HOOK_FLAG_MASK; // The index here may contain additional flags. See
// the comments of uc_hook_idx for details.
index = index & UC_HOOK_IDX_MASK;
@ -1395,30 +1426,35 @@ void helper_uc_tracecode(int32_t size, uc_hook_idx index, void *handle, int64_t
return;
}
for (cur = uc->hook[index].head; cur != NULL && (hook = (struct hook *)cur->data); cur = cur->next) {
for (cur = uc->hook[index].head;
cur != NULL && (hook = (struct hook *)cur->data); cur = cur->next) {
if (hook->to_delete) {
continue;
}
// on invalid block/instruction, call instruction counter (if enable), then quit
// on invalid block/instruction, call instruction counter (if enable),
// then quit
if (size == 0) {
if (index == UC_HOOK_CODE_IDX && uc->count_hook) {
// this is the instruction counter (first hook in the list)
((uc_cb_hookcode_t)hook->callback)(uc, address, size, hook->user_data);
((uc_cb_hookcode_t)hook->callback)(uc, address, size,
hook->user_data);
}
return;
}
if (HOOK_BOUND_CHECK(hook, (uint64_t)address)) {
((uc_cb_hookcode_t)hook->callback)(uc, address, size, hook->user_data);
((uc_cb_hookcode_t)hook->callback)(uc, address, size,
hook->user_data);
}
// the last callback may already asked to stop emulation
// Unicorn:
// In an ARM IT block, we behave like the emulation continues normally. No check_exit_request
// is generated and the hooks are triggered normally. In other words, the whole IT block is
// treated as a single instruction.
// In an ARM IT block, we behave like the emulation continues
// normally. No check_exit_request is generated and the hooks are
// triggered normally. In other words, the whole IT block is treated
// as a single instruction.
if (uc->stop_request && !(hook_flags & UC_HOOK_FLAG_NO_STOP)) {
break;
}
@ -1517,20 +1553,20 @@ UNICORN_EXPORT
size_t uc_context_size(uc_engine *uc)
{
// return the total size of struct uc_context
return sizeof(uc_context) + uc->cpu_context_size + sizeof(*uc->cpu->jmp_env);
return sizeof(uc_context) + uc->cpu_context_size +
sizeof(*uc->cpu->jmp_env);
}
UNICORN_EXPORT
uc_err uc_context_save(uc_engine *uc, uc_context *context)
{
memcpy(context->data, uc->cpu->env_ptr, context->context_size);
memcpy(context->data + context->context_size, uc->cpu->jmp_env, context->jmp_env_size);
memcpy(context->data + context->context_size, uc->cpu->jmp_env,
context->jmp_env_size);
return UC_ERR_OK;
}
UNICORN_EXPORT
uc_err uc_context_reg_write(uc_context *ctx, int regid, const void *value)
{
@ -1544,7 +1580,8 @@ uc_err uc_context_reg_read(uc_context *ctx, int regid, void *value)
}
// Keep in mind that we don't a uc_engine when r/w the registers of a context.
static void find_context_reg_rw_function(uc_arch arch, uc_mode mode, context_reg_rw_t *rw)
static void find_context_reg_rw_function(uc_arch arch, uc_mode mode,
context_reg_rw_t *rw)
{
// We believe that the arch/mode pair is correct.
switch (arch) {
@ -1586,7 +1623,8 @@ static void find_context_reg_rw_function(uc_arch arch, uc_mode mode, context_reg
break;
#endif
#if defined(UNICORN_HAS_MIPS) || defined(UNICORN_HAS_MIPSEL) || defined(UNICORN_HAS_MIPS64) || defined(UNICORN_HAS_MIPS64EL)
#if defined(UNICORN_HAS_MIPS) || defined(UNICORN_HAS_MIPSEL) || \
defined(UNICORN_HAS_MIPS64) || defined(UNICORN_HAS_MIPS64EL)
case UC_ARCH_MIPS:
if (mode & UC_MODE_BIG_ENDIAN) {
#ifdef UNICORN_HAS_MIPS
@ -1657,7 +1695,8 @@ static void find_context_reg_rw_function(uc_arch arch, uc_mode mode, context_reg
}
UNICORN_EXPORT
uc_err uc_context_reg_write_batch(uc_context *ctx, int *ids, void *const *vals, int count)
uc_err uc_context_reg_write_batch(uc_context *ctx, int *ids, void *const *vals,
int count)
{
int ret = UC_ERR_OK;
context_reg_rw_t rw;
@ -1673,7 +1712,8 @@ uc_err uc_context_reg_write_batch(uc_context *ctx, int *ids, void *const *vals,
}
UNICORN_EXPORT
uc_err uc_context_reg_read_batch(uc_context *ctx, int *ids, void **vals, int count)
uc_err uc_context_reg_read_batch(uc_context *ctx, int *ids, void **vals,
int count)
{
int ret = UC_ERR_OK;
context_reg_rw_t rw;
@ -1693,7 +1733,8 @@ uc_err uc_context_restore(uc_engine *uc, uc_context *context)
{
memcpy(uc->cpu->env_ptr, context->data, context->context_size);
if (list_exists(&uc->saved_contexts, context)) {
memcpy(uc->cpu->jmp_env, context->data + context->context_size, context->jmp_env_size);
memcpy(uc->cpu->jmp_env, context->data + context->context_size,
context->jmp_env_size);
}
return UC_ERR_OK;