Merge branch 'master' into mem_map_ex_cse
This commit is contained in:
commit
4a680b9277
|
@ -9,8 +9,8 @@ void hookCode_cgo(uch handle, uint64_t addr, uint32_t size, void *user) {
|
||||||
hookCode(handle, addr, size, user);
|
hookCode(handle, addr, size, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool hookMemInvalid_cgo(uch handle, uc_mem_type type, uint64_t addr, int64_t value, void *user) {
|
bool hookMemInvalid_cgo(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user) {
|
||||||
return hookMemInvalid(handle, type, addr, value, user);
|
return hookMemInvalid(handle, type, addr, size, value, user);
|
||||||
}
|
}
|
||||||
|
|
||||||
void hookMemAccess_cgo(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user) {
|
void hookMemAccess_cgo(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user) {
|
||||||
|
|
|
@ -23,15 +23,15 @@ func hookCode(handle C.uch, addr C.uint64_t, size C.uint32_t, user unsafe.Pointe
|
||||||
}
|
}
|
||||||
|
|
||||||
//export hookMemInvalid
|
//export hookMemInvalid
|
||||||
func hookMemInvalid(handle C.uch, typ C.uc_mem_type, addr C.uint64_t, value C.int64_t, user unsafe.Pointer) C.bool {
|
func hookMemInvalid(handle C.uch, typ C.uc_mem_type, addr C.uint64_t, size int, value C.int64_t, user unsafe.Pointer) C.bool {
|
||||||
hook := (*HookData)(user)
|
hook := (*HookData)(user)
|
||||||
return C.bool(hook.Callback.(func(*Uc, int, uint64, int64) bool)(hook.Uc, int(typ), uint64(addr), int64(value)))
|
return C.bool(hook.Callback.(func(*Uc, int, uint64, int, int64) bool)(hook.Uc, int(typ), uint64(addr), size, int64(value)))
|
||||||
}
|
}
|
||||||
|
|
||||||
//export hookMemAccess
|
//export hookMemAccess
|
||||||
func hookMemAccess(handle C.uch, typ C.uc_mem_type, addr C.uint64_t, size int, value C.int64_t, user unsafe.Pointer) {
|
func hookMemAccess(handle C.uch, typ C.uc_mem_type, addr C.uint64_t, size int, value C.int64_t, user unsafe.Pointer) {
|
||||||
hook := (*HookData)(user)
|
hook := (*HookData)(user)
|
||||||
hook.Callback.(func(*Uc, int, uint64, uint32, int64))(hook.Uc, int(typ), uint64(addr), uint32(size), int64(value))
|
hook.Callback.(func(*Uc, int, uint64, int, int64))(hook.Uc, int(typ), uint64(addr), size, int64(value))
|
||||||
}
|
}
|
||||||
|
|
||||||
//export hookX86In
|
//export hookX86In
|
||||||
|
@ -52,6 +52,8 @@ func hookX86Syscall(handle C.uch, user unsafe.Pointer) {
|
||||||
hook.Callback.(func(*Uc))(hook.Uc)
|
hook.Callback.(func(*Uc))(hook.Uc)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var hookRetain = make(map[C.uch]*HookData)
|
||||||
|
|
||||||
func (u *Uc) HookAdd(htype int, cb interface{}, insn ...int) (C.uch, error) {
|
func (u *Uc) HookAdd(htype int, cb interface{}, insn ...int) (C.uch, error) {
|
||||||
var callback unsafe.Pointer
|
var callback unsafe.Pointer
|
||||||
var extra C.int
|
var extra C.int
|
||||||
|
@ -78,10 +80,13 @@ func (u *Uc) HookAdd(htype int, cb interface{}, insn ...int) (C.uch, error) {
|
||||||
return 0, errors.New("Unknown hook type.")
|
return 0, errors.New("Unknown hook type.")
|
||||||
}
|
}
|
||||||
var h2 C.uch
|
var h2 C.uch
|
||||||
C.uc_hook_add2(u.Handle, &h2, C.uc_hook_t(htype), callback, unsafe.Pointer(&HookData{u, cb}), extra)
|
data := &HookData{u, cb}
|
||||||
|
C.uc_hook_add2(u.Handle, &h2, C.uc_hook_t(htype), callback, unsafe.Pointer(data), extra)
|
||||||
|
hookRetain[h2] = data
|
||||||
return h2, nil
|
return h2, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Uc) HookDel(hook *C.uch) error {
|
func (u *Uc) HookDel(hook *C.uch) error {
|
||||||
|
delete(hookRetain, *hook)
|
||||||
return errReturn(C.uc_hook_del(u.Handle, hook))
|
return errReturn(C.uc_hook_del(u.Handle, hook))
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
uc_err uc_hook_add2(uch handle, uch *h2, uc_hook_t type, void *callback, void *user_data, int extra);
|
uc_err uc_hook_add2(uch handle, uch *h2, uc_hook_t type, void *callback, void *user_data, int extra);
|
||||||
void hookCode_cgo(uch handle, uint64_t addr, uint32_t size, void *user);
|
void hookCode_cgo(uch handle, uint64_t addr, uint32_t size, void *user);
|
||||||
bool hookMemInvalid_cgo(uch handle, uc_mem_type type, uint64_t addr, int64_t value, void *user);
|
bool hookMemInvalid_cgo(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user);
|
||||||
void hookMemAccess_cgo(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user);
|
void hookMemAccess_cgo(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user);
|
||||||
uint32_t hookX86In_cgo(uch handle, uint32_t port, uint32_t size, void *user);
|
uint32_t hookX86In_cgo(uch handle, uint32_t port, uint32_t size, void *user);
|
||||||
void hookX86Out_cgo(uch handle, uint32_t port, uint32_t size, uint32_t value, void *user);
|
void hookX86Out_cgo(uch handle, uint32_t port, uint32_t size, uint32_t value, void *user);
|
||||||
|
|
|
@ -72,10 +72,16 @@ func (u *Uc) RegRead(reg int) (uint64, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Uc) MemWrite(addr uint64, data []byte) error {
|
func (u *Uc) MemWrite(addr uint64, data []byte) error {
|
||||||
|
if len(data) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return errReturn(C.uc_mem_write(u.Handle, C.uint64_t(addr), (*C.uint8_t)(unsafe.Pointer(&data[0])), C.size_t(len(data))))
|
return errReturn(C.uc_mem_write(u.Handle, C.uint64_t(addr), (*C.uint8_t)(unsafe.Pointer(&data[0])), C.size_t(len(data))))
|
||||||
}
|
}
|
||||||
|
|
||||||
func (u *Uc) MemReadInto(dst []byte, addr uint64) error {
|
func (u *Uc) MemReadInto(dst []byte, addr uint64) error {
|
||||||
|
if len(dst) == 0 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
return errReturn(C.uc_mem_read(u.Handle, C.uint64_t(addr), (*C.uint8_t)(unsafe.Pointer(&dst[0])), C.size_t(len(dst))))
|
return errReturn(C.uc_mem_read(u.Handle, C.uint64_t(addr), (*C.uint8_t)(unsafe.Pointer(&dst[0])), C.size_t(len(dst))))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -98,7 +98,6 @@ struct uc_struct {
|
||||||
void* cpu;
|
void* cpu;
|
||||||
|
|
||||||
MemoryRegion *system_memory; // qemu/exec.c
|
MemoryRegion *system_memory; // qemu/exec.c
|
||||||
MemoryRegion *ram;
|
|
||||||
MemoryRegion io_mem_rom; // qemu/exec.c
|
MemoryRegion io_mem_rom; // qemu/exec.c
|
||||||
MemoryRegion io_mem_notdirty; // qemu/exec.c
|
MemoryRegion io_mem_notdirty; // qemu/exec.c
|
||||||
MemoryRegion io_mem_unassigned; // qemu/exec.c
|
MemoryRegion io_mem_unassigned; // qemu/exec.c
|
||||||
|
|
4
make.sh
4
make.sh
|
@ -38,8 +38,8 @@ build_cross() {
|
||||||
[ "$UNAME" = Darwin ] && LIBARCHS="i386 x86_64"
|
[ "$UNAME" = Darwin ] && LIBARCHS="i386 x86_64"
|
||||||
CROSS=$1
|
CROSS=$1
|
||||||
CC=$CROSS-gcc \
|
CC=$CROSS-gcc \
|
||||||
AR=$CROSS-ar \
|
AR=$CROSS-gcc-ar \
|
||||||
RANLIB=$CROSS-ranlib \
|
RANLIB=$CROSS-gcc-ranlib \
|
||||||
GLIB="-L/usr/$CROSS/lib/ -lglib-2.0" \
|
GLIB="-L/usr/$CROSS/lib/ -lglib-2.0" \
|
||||||
${MAKE}
|
${MAKE}
|
||||||
}
|
}
|
||||||
|
|
|
@ -33,16 +33,16 @@
|
||||||
// Unicorn engine
|
// Unicorn engine
|
||||||
MemoryRegion *memory_map(struct uc_struct *uc, ram_addr_t begin, size_t size, uint32_t perms)
|
MemoryRegion *memory_map(struct uc_struct *uc, ram_addr_t begin, size_t size, uint32_t perms)
|
||||||
{
|
{
|
||||||
uc->ram = g_new(MemoryRegion, 1);
|
MemoryRegion *ram = g_new(MemoryRegion, 1);
|
||||||
|
|
||||||
memory_region_init_ram(uc, uc->ram, NULL, "pc.ram", size, perms, &error_abort);
|
memory_region_init_ram(uc, ram, NULL, "pc.ram", size, perms, &error_abort);
|
||||||
|
|
||||||
memory_region_add_subregion(get_system_memory(uc), begin, uc->ram);
|
memory_region_add_subregion(get_system_memory(uc), begin, ram);
|
||||||
|
|
||||||
if (uc->current_cpu)
|
if (uc->current_cpu)
|
||||||
tlb_flush(uc->current_cpu, 1);
|
tlb_flush(uc->current_cpu, 1);
|
||||||
|
|
||||||
return uc->ram;
|
return ram;
|
||||||
}
|
}
|
||||||
|
|
||||||
void memory_unmap(struct uc_struct *uc, MemoryRegion *mr)
|
void memory_unmap(struct uc_struct *uc, MemoryRegion *mr)
|
||||||
|
|
|
@ -5,6 +5,7 @@ TESTS = map_crash map_write
|
||||||
TESTS += sigill sigill2
|
TESTS += sigill sigill2
|
||||||
TESTS += block_test
|
TESTS += block_test
|
||||||
TESTS += ro_mem_test nr_mem_test
|
TESTS += ro_mem_test nr_mem_test
|
||||||
|
TESTS += timeout_segfault
|
||||||
|
|
||||||
all: $(TESTS)
|
all: $(TESTS)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,149 @@
|
||||||
|
/*
|
||||||
|
timeout_segfault.c
|
||||||
|
|
||||||
|
This program shows a case where the emulation timer keeps running after
|
||||||
|
emulation has ended. It triggers an intermittent segfault when _timeout_fn()
|
||||||
|
tries to call uc_emu_stop() after emulation has already been cleaned up. This
|
||||||
|
code is the same as samples/sample_arm.c, except that it adds a timeout on each
|
||||||
|
call to uc_emu_start(). See issue #78 for more details:
|
||||||
|
https://github.com/unicorn-engine/unicorn/issues/78
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include <unicorn/unicorn.h>
|
||||||
|
|
||||||
|
|
||||||
|
// code to be emulated
|
||||||
|
#define ARM_CODE "\x37\x00\xa0\xe3\x03\x10\x42\xe0" // mov r0, #0x37; sub r1, r2, r3
|
||||||
|
#define THUMB_CODE "\x83\xb0" // sub sp, #0xc
|
||||||
|
|
||||||
|
// memory address where emulation starts
|
||||||
|
#define ADDRESS 0x10000
|
||||||
|
|
||||||
|
// number of seconds to wait before timeout
|
||||||
|
#define TIMEOUT 5
|
||||||
|
|
||||||
|
static void hook_block(uch handle, uint64_t address, uint32_t size, void *user_data)
|
||||||
|
{
|
||||||
|
printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hook_code(uch handle, uint64_t address, uint32_t size, void *user_data)
|
||||||
|
{
|
||||||
|
printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_arm(void)
|
||||||
|
{
|
||||||
|
uch handle;
|
||||||
|
uc_err err;
|
||||||
|
uch trace1, trace2;
|
||||||
|
|
||||||
|
int r0 = 0x1234; // R0 register
|
||||||
|
int r2 = 0x6789; // R1 register
|
||||||
|
int r3 = 0x3333; // R2 register
|
||||||
|
int r1; // R1 register
|
||||||
|
|
||||||
|
printf("Emulate ARM code\n");
|
||||||
|
|
||||||
|
// Initialize emulator in ARM mode
|
||||||
|
err = uc_open(UC_ARCH_ARM, UC_MODE_ARM, &handle);
|
||||||
|
if (err) {
|
||||||
|
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||||
|
err, uc_strerror(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// map 2MB memory for this emulation
|
||||||
|
uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||||
|
|
||||||
|
// write machine code to be emulated to memory
|
||||||
|
uc_mem_write(handle, ADDRESS, (uint8_t *)ARM_CODE, sizeof(ARM_CODE) - 1);
|
||||||
|
|
||||||
|
// initialize machine registers
|
||||||
|
uc_reg_write(handle, UC_ARM_REG_R0, &r0);
|
||||||
|
uc_reg_write(handle, UC_ARM_REG_R2, &r2);
|
||||||
|
uc_reg_write(handle, UC_ARM_REG_R3, &r3);
|
||||||
|
|
||||||
|
// tracing all basic blocks with customized callback
|
||||||
|
uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
|
||||||
|
|
||||||
|
// tracing one instruction at ADDRESS with customized callback
|
||||||
|
uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS);
|
||||||
|
|
||||||
|
// emulate machine code in infinite time (last param = 0), or when
|
||||||
|
// finishing all the code.
|
||||||
|
err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, UC_SECOND_SCALE * TIMEOUT, 0);
|
||||||
|
if (err) {
|
||||||
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now print out some registers
|
||||||
|
printf(">>> Emulation done. Below is the CPU context\n");
|
||||||
|
|
||||||
|
uc_reg_read(handle, UC_ARM_REG_R0, &r0);
|
||||||
|
uc_reg_read(handle, UC_ARM_REG_R1, &r1);
|
||||||
|
printf(">>> R0 = 0x%x\n", r0);
|
||||||
|
printf(">>> R1 = 0x%x\n", r1);
|
||||||
|
|
||||||
|
uc_close(&handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_thumb(void)
|
||||||
|
{
|
||||||
|
uch handle;
|
||||||
|
uc_err err;
|
||||||
|
uch trace1, trace2;
|
||||||
|
|
||||||
|
int sp = 0x1234; // R0 register
|
||||||
|
|
||||||
|
printf("Emulate THUMB code\n");
|
||||||
|
|
||||||
|
// Initialize emulator in ARM mode
|
||||||
|
err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB, &handle);
|
||||||
|
if (err) {
|
||||||
|
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||||
|
err, uc_strerror(err));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// map 2MB memory for this emulation
|
||||||
|
uc_mem_map(handle, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL);
|
||||||
|
|
||||||
|
// write machine code to be emulated to memory
|
||||||
|
uc_mem_write(handle, ADDRESS, (uint8_t *)THUMB_CODE, sizeof(THUMB_CODE) - 1);
|
||||||
|
|
||||||
|
// initialize machine registers
|
||||||
|
uc_reg_write(handle, UC_ARM_REG_SP, &sp);
|
||||||
|
|
||||||
|
// tracing all basic blocks with customized callback
|
||||||
|
uc_hook_add(handle, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
|
||||||
|
|
||||||
|
// tracing one instruction at ADDRESS with customized callback
|
||||||
|
uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS);
|
||||||
|
|
||||||
|
// emulate machine code in infinite time (last param = 0), or when
|
||||||
|
// finishing all the code.
|
||||||
|
err = uc_emu_start(handle, ADDRESS, ADDRESS + sizeof(THUMB_CODE) -1, UC_SECOND_SCALE * TIMEOUT, 0);
|
||||||
|
if (err) {
|
||||||
|
printf("Failed on uc_emu_start() with error returned: %u\n", err);
|
||||||
|
}
|
||||||
|
|
||||||
|
// now print out some registers
|
||||||
|
printf(">>> Emulation done. Below is the CPU context\n");
|
||||||
|
|
||||||
|
uc_reg_read(handle, UC_ARM_REG_SP, &sp);
|
||||||
|
printf(">>> SP = 0x%x\n", sp);
|
||||||
|
|
||||||
|
uc_close(&handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv, char **envp)
|
||||||
|
{
|
||||||
|
test_arm();
|
||||||
|
printf("==========================\n");
|
||||||
|
test_thumb();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
5
uc.c
5
uc.c
|
@ -549,6 +549,11 @@ uc_err uc_emu_start(uch handle, uint64_t begin, uint64_t until, uint64_t timeout
|
||||||
// emulation is done
|
// emulation is done
|
||||||
uc->emulation_done = true;
|
uc->emulation_done = true;
|
||||||
|
|
||||||
|
if (timeout) {
|
||||||
|
// wait for the timer to finish
|
||||||
|
qemu_thread_join(&uc->timer);
|
||||||
|
}
|
||||||
|
|
||||||
return uc->invalid_error;
|
return uc->invalid_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue