mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-01-24 01:21:10 +00:00
Merge pull request #2 from unicorn-engine/master
Pulling in from unicorn-engine to my private repo
This commit is contained in:
commit
7cb8e889ad
16
.appveyor.yml
Normal file
16
.appveyor.yml
Normal file
|
@ -0,0 +1,16 @@
|
|||
version: 1.0-{build}
|
||||
|
||||
platform:
|
||||
- x64
|
||||
|
||||
environment:
|
||||
global:
|
||||
MSYS2_ARCH: x86_64
|
||||
matrix:
|
||||
- HOST_ARCH_ARG: --host=x86_64-w64-mingw32
|
||||
ADD_PATH: /mingw64/bin
|
||||
- HOST_ARCH_ARG: --host=i686-w64-mingw32
|
||||
ADD_PATH: /mingw32/bin
|
||||
|
||||
build_script:
|
||||
- make.sh cross-win64
|
5
.gitignore
vendored
5
.gitignore
vendored
|
@ -134,6 +134,11 @@ test_mem_high
|
|||
rw_hookstack
|
||||
hook_extrainvoke
|
||||
sysenter_hook_x86
|
||||
test_tb_x86
|
||||
test_multihook
|
||||
test_pc_change
|
||||
mem_fuzz
|
||||
test_x86_soft_paging
|
||||
|
||||
|
||||
#################
|
||||
|
|
15
.travis.yml
Normal file
15
.travis.yml
Normal file
|
@ -0,0 +1,15 @@
|
|||
language: c
|
||||
sudo: false
|
||||
before_install:
|
||||
- export LD_LIBRARY_PATH=`pwd`/samples/:$LD_LIBRARY_PATH
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi
|
||||
- if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install glib; fi
|
||||
|
||||
script:
|
||||
- ./make.sh
|
||||
compiler:
|
||||
- clang
|
||||
- gcc
|
||||
os:
|
||||
- linux
|
||||
- osx
|
|
@ -54,3 +54,8 @@ Nguyen Tan Cong
|
|||
Loi Anh Tuan
|
||||
Shaun Wheelhouse: Homebrew package
|
||||
Kamil Rytarowski: Pkgsrc package
|
||||
Zak Escano: MSVC binding
|
||||
Chris Eagle: Java binding
|
||||
Ryan Hileman: Go binding
|
||||
Antonio Parata: .NET binding
|
||||
Jonathon Reinhart: C unit test
|
||||
|
|
4
Makefile
4
Makefile
|
@ -228,7 +228,7 @@ compile_lib: config qemu/config-host.h-timestamp
|
|||
|
||||
unicorn: $(LIBRARY) $(ARCHIVE)
|
||||
|
||||
$(LIBRARY): $(UC_TARGET_OBJ) uc.o hook.o
|
||||
$(LIBRARY): $(UC_TARGET_OBJ) uc.o list.o
|
||||
ifeq ($(UNICORN_SHARED),yes)
|
||||
ifeq ($(V),0)
|
||||
$(call log,GEN,$(LIBRARY))
|
||||
|
@ -241,7 +241,7 @@ ifneq (,$(LIBRARY_SYMLINK))
|
|||
endif
|
||||
endif
|
||||
|
||||
$(ARCHIVE): $(UC_TARGET_OBJ) uc.o hook.o
|
||||
$(ARCHIVE): $(UC_TARGET_OBJ) uc.o list.o
|
||||
ifeq ($(UNICORN_STATIC),yes)
|
||||
ifeq ($(V),0)
|
||||
$(call log,GEN,$(ARCHIVE))
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
Unicorn Engine
|
||||
==============
|
||||
|
||||
[![Build Status](https://travis-ci.org/unicorn-engine/unicorn.svg?branch=master)](https://travis-ci.org/unicorn-engine/unicorn)
|
||||
[![Build status](https://ci.appveyor.com/api/projects/status/kojr7bald748ba2x/branch/master?svg=true)](https://ci.appveyor.com/project/aquynh/unicorn/branch/master)
|
||||
|
||||
Unicorn is a lightweight, multi-platform, multi-architecture CPU emulator framework
|
||||
based on [QEMU](http://qemu.org).
|
||||
|
||||
|
|
|
@ -116,7 +116,8 @@ def gen(lang):
|
|||
|
||||
if f[0].startswith("UC_" + prefix.upper()):
|
||||
if len(f) > 1 and f[1] not in ('//', '='):
|
||||
print("Error: Unable to convert %s" % f)
|
||||
print("WARNING: Unable to convert %s" % f)
|
||||
print(" Line =", line)
|
||||
continue
|
||||
elif len(f) > 1 and f[1] == '=':
|
||||
rhs = ''.join(f[2:])
|
||||
|
|
|
@ -6,9 +6,9 @@ open System
|
|||
|
||||
[<AutoOpen>]
|
||||
module Common =
|
||||
let UC_API_MAJOR = 1
|
||||
|
||||
let UC_API_MAJOR = 0
|
||||
let UC_API_MINOR = 9
|
||||
let UC_API_MINOR = 0
|
||||
let UC_SECOND_SCALE = 1000000
|
||||
let UC_MILISECOND_SCALE = 1000
|
||||
let UC_ARCH_ARM = 1
|
||||
|
@ -21,22 +21,26 @@ module Common =
|
|||
let UC_ARCH_MAX = 8
|
||||
|
||||
let UC_MODE_LITTLE_ENDIAN = 0
|
||||
let UC_MODE_BIG_ENDIAN = 1073741824
|
||||
|
||||
let UC_MODE_ARM = 0
|
||||
let UC_MODE_16 = 2
|
||||
let UC_MODE_32 = 4
|
||||
let UC_MODE_64 = 8
|
||||
let UC_MODE_THUMB = 16
|
||||
let UC_MODE_MCLASS = 32
|
||||
let UC_MODE_V8 = 64
|
||||
let UC_MODE_MICRO = 16
|
||||
let UC_MODE_MIPS3 = 32
|
||||
let UC_MODE_MIPS32R6 = 64
|
||||
let UC_MODE_V9 = 16
|
||||
let UC_MODE_QPX = 16
|
||||
let UC_MODE_BIG_ENDIAN = 1073741824
|
||||
let UC_MODE_MIPS32 = 4
|
||||
let UC_MODE_MIPS64 = 8
|
||||
let UC_MODE_16 = 2
|
||||
let UC_MODE_32 = 4
|
||||
let UC_MODE_64 = 8
|
||||
let UC_MODE_PPC32 = 4
|
||||
let UC_MODE_PPC64 = 8
|
||||
let UC_MODE_QPX = 16
|
||||
let UC_MODE_SPARC32 = 4
|
||||
let UC_MODE_SPARC64 = 8
|
||||
let UC_MODE_V9 = 16
|
||||
|
||||
let UC_ERR_OK = 0
|
||||
let UC_ERR_NOMEM = 1
|
||||
|
@ -87,6 +91,9 @@ module Common =
|
|||
let UC_HOOK_MEM_WRITE_INVALID = 288
|
||||
let UC_HOOK_MEM_FETCH_INVALID = 576
|
||||
let UC_HOOK_MEM_INVALID = 1008
|
||||
let UC_HOOK_MEM_VALID = 7168
|
||||
let UC_QUERY_MODE = 1
|
||||
let UC_QUERY_PAGE_SIZE = 2
|
||||
|
||||
let UC_PROT_NONE = 0
|
||||
let UC_PROT_READ = 1
|
||||
|
|
|
@ -251,7 +251,13 @@ module X86 =
|
|||
let UC_X86_REG_R13W = 239
|
||||
let UC_X86_REG_R14W = 240
|
||||
let UC_X86_REG_R15W = 241
|
||||
let UC_X86_REG_ENDING = 242
|
||||
let UC_X86_REG_IDTR = 242
|
||||
let UC_X86_REG_GDTR = 243
|
||||
let UC_X86_REG_LDTR = 244
|
||||
let UC_X86_REG_TR = 245
|
||||
let UC_X86_REG_FPCW = 246
|
||||
let UC_X86_REG_FPTAG = 247
|
||||
let UC_X86_REG_ENDING = 248
|
||||
|
||||
// X86 instructions
|
||||
|
||||
|
|
|
@ -1,12 +1,16 @@
|
|||
#include <unicorn/unicorn.h>
|
||||
#include "_cgo_export.h"
|
||||
|
||||
uc_err uc_hook_add_i1(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, int arg1) {
|
||||
return uc_hook_add(handle, h2, type, callback, (void *)user, arg1);
|
||||
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
|
||||
void *user_data, uint64_t begin, uint64_t end, ...);
|
||||
|
||||
|
||||
uc_err uc_hook_add_wrap(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t begin, uint64_t end) {
|
||||
return uc_hook_add(handle, h2, type, callback, (void *)user, begin, end);
|
||||
}
|
||||
|
||||
uc_err uc_hook_add_u2(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t arg1, uint64_t arg2) {
|
||||
return uc_hook_add(handle, h2, type, callback, (void *)user, arg1, arg2);
|
||||
uc_err uc_hook_add_insn(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t begin, uint64_t end, int insn) {
|
||||
return uc_hook_add(handle, h2, type, callback, (void *)user, begin, end, insn);
|
||||
}
|
||||
|
||||
void hookCode_cgo(uc_engine *handle, uint64_t addr, uint32_t size, uintptr_t user) {
|
||||
|
|
|
@ -63,23 +63,21 @@ func hookX86Syscall(handle unsafe.Pointer, user unsafe.Pointer) {
|
|||
hook.Callback.(func(Unicorn))(hook.Uc)
|
||||
}
|
||||
|
||||
func (u *uc) HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) {
|
||||
func (u *uc) HookAdd(htype int, cb interface{}, begin, end uint64, extra ...int) (Hook, error) {
|
||||
var callback unsafe.Pointer
|
||||
var iarg1 C.int
|
||||
var uarg1, uarg2 C.uint64_t
|
||||
rangeMode := false
|
||||
var insn C.int
|
||||
var insnMode bool
|
||||
switch htype {
|
||||
case HOOK_BLOCK, HOOK_CODE:
|
||||
rangeMode = true
|
||||
callback = C.hookCode_cgo
|
||||
case HOOK_MEM_READ, HOOK_MEM_WRITE, HOOK_MEM_READ | HOOK_MEM_WRITE:
|
||||
rangeMode = true
|
||||
callback = C.hookMemAccess_cgo
|
||||
case HOOK_INTR:
|
||||
callback = C.hookInterrupt_cgo
|
||||
case HOOK_INSN:
|
||||
iarg1 = C.int(extra[0])
|
||||
switch iarg1 {
|
||||
insn = C.int(extra[0])
|
||||
insnMode = true
|
||||
switch insn {
|
||||
case X86_INS_IN:
|
||||
callback = C.hookX86In_cgo
|
||||
case X86_INS_OUT:
|
||||
|
@ -93,7 +91,6 @@ func (u *uc) HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) {
|
|||
// special case for mask
|
||||
if htype&(HOOK_MEM_READ_UNMAPPED|HOOK_MEM_WRITE_UNMAPPED|HOOK_MEM_FETCH_UNMAPPED|
|
||||
HOOK_MEM_READ_PROT|HOOK_MEM_WRITE_PROT|HOOK_MEM_FETCH_PROT) != 0 {
|
||||
rangeMode = true
|
||||
callback = C.hookMemInvalid_cgo
|
||||
} else {
|
||||
return 0, errors.New("Unknown hook type.")
|
||||
|
@ -102,16 +99,10 @@ func (u *uc) HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) {
|
|||
var h2 C.uc_hook
|
||||
data := &HookData{u, cb}
|
||||
uptr := uintptr(unsafe.Pointer(data))
|
||||
if rangeMode {
|
||||
if len(extra) == 2 {
|
||||
uarg1 = C.uint64_t(extra[0])
|
||||
uarg2 = C.uint64_t(extra[1])
|
||||
} else {
|
||||
uarg1, uarg2 = 1, 0
|
||||
}
|
||||
C.uc_hook_add_u2(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), uarg1, uarg2)
|
||||
if insnMode {
|
||||
C.uc_hook_add_insn(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), C.uint64_t(begin), C.uint64_t(end), insn)
|
||||
} else {
|
||||
C.uc_hook_add_i1(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), iarg1)
|
||||
C.uc_hook_add_wrap(u.handle, &h2, C.uc_hook_type(htype), callback, C.uintptr_t(uptr), C.uint64_t(begin), C.uint64_t(end))
|
||||
}
|
||||
hookDataMap[uptr] = data
|
||||
hookToUintptr[Hook(h2)] = uptr
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
uc_err uc_hook_add_i1(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, int arg1);
|
||||
uc_err uc_hook_add_u2(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t arg1, uint64_t arg2);
|
||||
uc_err uc_hook_add_wrap(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t begin, uint64_t end);
|
||||
uc_err uc_hook_add_insn(uc_engine *handle, uc_hook *h2, uc_hook_type type, void *callback, uintptr_t user, uint64_t begin, uint64_t end, int insn);
|
||||
void hookCode_cgo(uc_engine *handle, uint64_t addr, uint32_t size, uintptr_t user);
|
||||
bool hookMemInvalid_cgo(uc_engine *handle, uc_mem_type type, uint64_t addr, int size, int64_t value, uintptr_t user);
|
||||
void hookMemAccess_cgo(uc_engine *handle, uc_mem_type type, uint64_t addr, int size, int64_t value, uintptr_t user);
|
||||
|
|
|
@ -25,22 +25,31 @@ func errReturn(err C.uc_err) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
type MemRegion struct {
|
||||
Begin, End uint64
|
||||
Prot int
|
||||
}
|
||||
|
||||
type Unicorn interface {
|
||||
MemMap(addr, size uint64) error
|
||||
MemMapProt(addr, size uint64, prot int) error
|
||||
MemMapPtr(addr, size uint64, prot int, ptr unsafe.Pointer) error
|
||||
MemProtect(addr, size uint64, prot int) error
|
||||
MemUnmap(addr, size uint64) error
|
||||
MemRegions() ([]*MemRegion, error)
|
||||
MemRead(addr, size uint64) ([]byte, error)
|
||||
MemReadInto(dst []byte, addr uint64) error
|
||||
MemWrite(addr uint64, data []byte) error
|
||||
RegRead(reg int) (uint64, error)
|
||||
RegWrite(reg int, value uint64) error
|
||||
RegReadMmr(reg int) (*X86Mmr, error)
|
||||
RegWriteMmr(reg int, value *X86Mmr) error
|
||||
Start(begin, until uint64) error
|
||||
StartWithOptions(begin, until uint64, options *UcOptions) error
|
||||
Stop() error
|
||||
HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error)
|
||||
HookAdd(htype int, cb interface{}, begin, end uint64, extra ...int) (Hook, error)
|
||||
HookDel(hook Hook) error
|
||||
Query(queryType int) (uint64, error)
|
||||
Close() error
|
||||
}
|
||||
|
||||
|
@ -103,6 +112,25 @@ func (u *uc) RegRead(reg int) (uint64, error) {
|
|||
return uint64(val), errReturn(ucerr)
|
||||
}
|
||||
|
||||
func (u *uc) MemRegions() ([]*MemRegion, error) {
|
||||
var regions *C.struct_uc_mem_region
|
||||
var count C.uint32_t
|
||||
ucerr := C.uc_mem_regions(u.handle, ®ions, &count)
|
||||
if ucerr != C.UC_ERR_OK {
|
||||
return nil, errReturn(ucerr)
|
||||
}
|
||||
ret := make([]*MemRegion, count)
|
||||
tmp := (*[1 << 24]C.struct_uc_mem_region)(unsafe.Pointer(regions))[:count]
|
||||
for i, v := range tmp {
|
||||
ret[i] = &MemRegion{
|
||||
Begin: uint64(v.begin),
|
||||
End: uint64(v.end),
|
||||
Prot: int(v.perms),
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (u *uc) MemWrite(addr uint64, data []byte) error {
|
||||
if len(data) == 0 {
|
||||
return nil
|
||||
|
@ -141,3 +169,9 @@ func (u *uc) MemProtect(addr, size uint64, prot int) error {
|
|||
func (u *uc) MemUnmap(addr, size uint64) error {
|
||||
return errReturn(C.uc_mem_unmap(u.handle, C.uint64_t(addr), C.size_t(size)))
|
||||
}
|
||||
|
||||
func (u *uc) Query(queryType int) (uint64, error) {
|
||||
var ret C.size_t
|
||||
ucerr := C.uc_query(u.handle, C.uc_query_type(queryType), &ret)
|
||||
return uint64(ret), errReturn(ucerr)
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
package unicorn
|
||||
// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [unicorn_const.go]
|
||||
const (
|
||||
API_MAJOR = 1
|
||||
|
||||
API_MAJOR = 0
|
||||
API_MINOR = 9
|
||||
API_MINOR = 0
|
||||
SECOND_SCALE = 1000000
|
||||
MILISECOND_SCALE = 1000
|
||||
ARCH_ARM = 1
|
||||
|
@ -16,22 +16,26 @@ const (
|
|||
ARCH_MAX = 8
|
||||
|
||||
MODE_LITTLE_ENDIAN = 0
|
||||
MODE_BIG_ENDIAN = 1073741824
|
||||
|
||||
MODE_ARM = 0
|
||||
MODE_16 = 2
|
||||
MODE_32 = 4
|
||||
MODE_64 = 8
|
||||
MODE_THUMB = 16
|
||||
MODE_MCLASS = 32
|
||||
MODE_V8 = 64
|
||||
MODE_MICRO = 16
|
||||
MODE_MIPS3 = 32
|
||||
MODE_MIPS32R6 = 64
|
||||
MODE_V9 = 16
|
||||
MODE_QPX = 16
|
||||
MODE_BIG_ENDIAN = 1073741824
|
||||
MODE_MIPS32 = 4
|
||||
MODE_MIPS64 = 8
|
||||
MODE_16 = 2
|
||||
MODE_32 = 4
|
||||
MODE_64 = 8
|
||||
MODE_PPC32 = 4
|
||||
MODE_PPC64 = 8
|
||||
MODE_QPX = 16
|
||||
MODE_SPARC32 = 4
|
||||
MODE_SPARC64 = 8
|
||||
MODE_V9 = 16
|
||||
|
||||
ERR_OK = 0
|
||||
ERR_NOMEM = 1
|
||||
|
@ -82,6 +86,9 @@ const (
|
|||
HOOK_MEM_WRITE_INVALID = 288
|
||||
HOOK_MEM_FETCH_INVALID = 576
|
||||
HOOK_MEM_INVALID = 1008
|
||||
HOOK_MEM_VALID = 7168
|
||||
QUERY_MODE = 1
|
||||
QUERY_PAGE_SIZE = 2
|
||||
|
||||
PROT_NONE = 0
|
||||
PROT_READ = 1
|
||||
|
|
|
@ -37,3 +37,39 @@ func TestDoubleClose(t *testing.T) {
|
|||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMemRegions(t *testing.T) {
|
||||
mu, err := NewUnicorn(ARCH_X86, MODE_32)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = mu.MemMap(0x1000, 0x1000)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
regions, err := mu.MemRegions()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(regions) != 1 {
|
||||
t.Fatalf("returned wrong number of regions: %d != 1", len(regions))
|
||||
}
|
||||
r := regions[0]
|
||||
if r.Begin != 0x1000 || r.End != 0x1fff || r.Prot != 7 {
|
||||
t.Fatalf("incorrect region: %#v", r)
|
||||
}
|
||||
}
|
||||
|
||||
func TestQuery(t *testing.T) {
|
||||
mu, err := NewUnicorn(ARCH_ARM, MODE_THUMB)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mode, err := mu.Query(QUERY_MODE)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if mode != MODE_THUMB {
|
||||
t.Fatal("query returned invalid mode: %d != %d", mode, MODE_THUMB)
|
||||
}
|
||||
}
|
||||
|
|
38
bindings/go/unicorn/x86.go
Normal file
38
bindings/go/unicorn/x86.go
Normal file
|
@ -0,0 +1,38 @@
|
|||
package unicorn
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// #include <unicorn/unicorn.h>
|
||||
// #include <unicorn/x86.h>
|
||||
import "C"
|
||||
|
||||
type X86Mmr struct {
|
||||
Selector uint16
|
||||
Base uint64
|
||||
Limit uint32
|
||||
Flags uint32
|
||||
}
|
||||
|
||||
func (u *uc) RegWriteMmr(reg int, value *X86Mmr) error {
|
||||
var val C.uc_x86_mmr
|
||||
val.selector = C.uint16_t(value.Selector)
|
||||
val.base = C.uint64_t(value.Base)
|
||||
val.limit = C.uint32_t(value.Limit)
|
||||
val.flags = C.uint32_t(value.Flags)
|
||||
ucerr := C.uc_reg_write(u.handle, C.int(reg), unsafe.Pointer(&val))
|
||||
return errReturn(ucerr)
|
||||
}
|
||||
|
||||
func (u *uc) RegReadMmr(reg int) (*X86Mmr, error) {
|
||||
var val C.uc_x86_mmr
|
||||
ucerr := C.uc_reg_read(u.handle, C.int(reg), unsafe.Pointer(&val))
|
||||
ret := &X86Mmr{
|
||||
Selector: uint16(val.selector),
|
||||
Base: uint64(val.base),
|
||||
Limit: uint32(val.limit),
|
||||
Flags: uint32(val.flags),
|
||||
}
|
||||
return ret, errReturn(ucerr)
|
||||
}
|
|
@ -246,7 +246,13 @@ const (
|
|||
X86_REG_R13W = 239
|
||||
X86_REG_R14W = 240
|
||||
X86_REG_R15W = 241
|
||||
X86_REG_ENDING = 242
|
||||
X86_REG_IDTR = 242
|
||||
X86_REG_GDTR = 243
|
||||
X86_REG_LDTR = 244
|
||||
X86_REG_TR = 245
|
||||
X86_REG_FPCW = 246
|
||||
X86_REG_FPTAG = 247
|
||||
X86_REG_ENDING = 248
|
||||
|
||||
// X86 instructions
|
||||
|
||||
|
|
|
@ -96,7 +96,7 @@ func TestX86InOut(t *testing.T) {
|
|||
default:
|
||||
return 0
|
||||
}
|
||||
}, X86_INS_IN)
|
||||
}, 1, 0, X86_INS_IN)
|
||||
mu.HookAdd(HOOK_INSN, func(_ Unicorn, port, size, value uint32) {
|
||||
outCalled = true
|
||||
var err error
|
||||
|
@ -111,7 +111,7 @@ func TestX86InOut(t *testing.T) {
|
|||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}, X86_INS_OUT)
|
||||
}, 1, 0, X86_INS_OUT)
|
||||
if err := mu.Start(ADDRESS, ADDRESS+uint64(len(code))); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ func TestX86Syscall(t *testing.T) {
|
|||
mu.HookAdd(HOOK_INSN, func(_ Unicorn) {
|
||||
rax, _ := mu.RegRead(X86_REG_RAX)
|
||||
mu.RegWrite(X86_REG_RAX, rax+1)
|
||||
}, X86_INS_SYSCALL)
|
||||
}, 1, 0, X86_INS_SYSCALL)
|
||||
mu.RegWrite(X86_REG_RAX, 0x100)
|
||||
err = mu.Start(ADDRESS, ADDRESS+uint64(len(code)))
|
||||
if err != nil {
|
||||
|
@ -143,3 +143,18 @@ func TestX86Syscall(t *testing.T) {
|
|||
t.Fatal("Incorrect syscall return value.")
|
||||
}
|
||||
}
|
||||
|
||||
func TestX86Mmr(t *testing.T) {
|
||||
mu, err := MakeUc(MODE_64, "")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
err = mu.RegWriteMmr(X86_REG_GDTR, &X86Mmr{Selector: 0, Base: 0x1000, Limit: 0x1fff, Flags: 0})
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
mmr, err := mu.RegReadMmr(X86_REG_GDTR)
|
||||
if mmr.Selector != 0 || mmr.Base != 0x1000 || mmr.Limit != 0x1fff || mmr.Flags != 0 {
|
||||
t.Fatalf("mmr read failed: %#v", mmr)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -113,7 +113,7 @@ public class Sample_mips {
|
|||
System.out.print("Emulate MIPS code (little-endian)\n");
|
||||
|
||||
// Initialize emulator in MIPS mode
|
||||
Unicorn u = new Unicorn(Unicorn.UC_ARCH_MIPS, Unicorn.UC_MODE_MIPS32);
|
||||
Unicorn u = new Unicorn(Unicorn.UC_ARCH_MIPS, Unicorn.UC_MODE_MIPS32 + Unicorn.UC_MODE_LITTLE_ENDIAN);
|
||||
|
||||
// map 2MB memory for this emulation
|
||||
u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL);
|
||||
|
|
|
@ -76,7 +76,7 @@ public class Sample_sparc {
|
|||
System.out.print("Emulate SPARC code\n");
|
||||
|
||||
// Initialize emulator in Sparc mode
|
||||
Unicorn u = new Unicorn(Unicorn.UC_ARCH_SPARC, Unicorn.UC_MODE_32);
|
||||
Unicorn u = new Unicorn(Unicorn.UC_ARCH_SPARC, Unicorn.UC_MODE_32 + Unicorn.UC_MODE_BIG_ENDIAN);
|
||||
|
||||
// map 2MB memory for this emulation
|
||||
u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL);
|
||||
|
|
77
bindings/java/samples/Sample_x86_mmr.java
Normal file
77
bindings/java/samples/Sample_x86_mmr.java
Normal file
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
|
||||
Java bindings for the Unicorn Emulator Engine
|
||||
|
||||
Copyright(c) 2016 Chris Eagle
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
/* Sample code to demonstrate how to register read/write API */
|
||||
|
||||
import unicorn.*;
|
||||
|
||||
public class Sample_x86_mmr {
|
||||
|
||||
static void test_x86_mmr() {
|
||||
// Initialize emulator in X86-32bit mode
|
||||
Unicorn uc;
|
||||
try {
|
||||
uc = new Unicorn(Unicorn.UC_ARCH_X86, Unicorn.UC_MODE_32);
|
||||
} catch (UnicornException uex) {
|
||||
System.out.println("Failed on uc_open() with error returned: " + uex);
|
||||
return;
|
||||
}
|
||||
|
||||
// map 4k
|
||||
uc.mem_map(ADDRESS, 0x1000, Unicorn.UC_PROT_ALL);
|
||||
|
||||
X86_MMR ldtr1 = new X86_MMR(0x1111111122222222L, 0x33333333, 0x44444444, (short)0x5555);
|
||||
X86_MMR ldtr2;
|
||||
X86_MMR gdtr1 = new X86_MMR(0x6666666677777777L, 0x88888888, 0x99999999, (short)0xaaaa);
|
||||
X86_MMR gdtr2, gdtr3, gdtr4;
|
||||
|
||||
int eax;
|
||||
|
||||
// initialize machine registers
|
||||
|
||||
uc.reg_write(Unicorn.UC_X86_REG_LDTR, ldtr1);
|
||||
uc.reg_write(Unicorn.UC_X86_REG_GDTR, gdtr1);
|
||||
uc.reg_write(Unicorn.UC_X86_REG_EAX, new Long(0xdddddddd));
|
||||
|
||||
// read the registers back out
|
||||
eax = (int)((Long)uc.reg_read(Unicorn.UC_X86_REG_EAX)).longValue();
|
||||
ldtr2 = (X86_MMR)uc.reg_read(Unicorn.UC_X86_REG_LDTR);
|
||||
gdtr2 = (X86_MMR)uc.reg_read(Unicorn.UC_X86_REG_GDTR);
|
||||
|
||||
System.out.printf(">>> EAX = 0x%x\n", eax);
|
||||
|
||||
System.out.printf(">>> LDTR.base = 0x%x\n", ldtr2.base);
|
||||
System.out.printf(">>> LDTR.limit = 0x%x\n", ldtr2.limit);
|
||||
System.out.printf(">>> LDTR.flags = 0x%x\n", ldtr2.flags);
|
||||
System.out.printf(">>> LDTR.selector = 0x%x\n\n", ldtr2.selector);
|
||||
|
||||
System.out.printf(">>> GDTR.base = 0x%x\n", gdtr2.base);
|
||||
System.out.printf(">>> GDTR.limit = 0x%x\n", gdtr2.limit);
|
||||
|
||||
uc.close();
|
||||
}
|
||||
|
||||
public static void main(String args[])
|
||||
{
|
||||
test_x86_mmr();
|
||||
}
|
||||
|
||||
}
|
37
bindings/java/unicorn/MemRegion.java
Normal file
37
bindings/java/unicorn/MemRegion.java
Normal file
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
|
||||
Java bindings for the Unicorn Emulator Engine
|
||||
|
||||
Copyright(c) 2016 Chris Eagle
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
package unicorn;
|
||||
|
||||
public class MemRegion {
|
||||
|
||||
public long begin;
|
||||
public long end;
|
||||
public int perms;
|
||||
|
||||
public MemRegion(long begin, long end, int perms) {
|
||||
this.begin = begin;
|
||||
this.end = end;
|
||||
this.perms = perms;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -26,6 +26,8 @@ import java.util.*;
|
|||
public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, SparcConst, MipsConst, X86Const {
|
||||
|
||||
private long eng;
|
||||
private int arch;
|
||||
private int mode;
|
||||
|
||||
private long blockHandle = 0;
|
||||
private long interruptHandle = 0;
|
||||
|
@ -275,6 +277,38 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to register.
|
||||
*
|
||||
* @param regid Register ID that is to be modified.
|
||||
* @param value Number containing the new register value
|
||||
*/
|
||||
private native void reg_write_num(int regid, Number value) throws UnicornException;
|
||||
|
||||
/**
|
||||
* Write to register.
|
||||
*
|
||||
* @param regid Register ID that is to be modified.
|
||||
* @param value X86 specific memory management register containing the new register value
|
||||
*/
|
||||
private native void reg_write_mmr(int regid, X86_MMR value) throws UnicornException;
|
||||
|
||||
/**
|
||||
* Read register value.
|
||||
*
|
||||
* @param regid Register ID that is to be retrieved.
|
||||
* @return Number containing the requested register value.
|
||||
*/
|
||||
private native Number reg_read_num(int regid) throws UnicornException;
|
||||
|
||||
/**
|
||||
* Read register value.
|
||||
*
|
||||
* @param regid Register ID that is to be retrieved.
|
||||
* @return X86_MMR containing the requested register value.
|
||||
*/
|
||||
private native Number reg_read_mmr(int regid) throws UnicornException;
|
||||
|
||||
/**
|
||||
* Native access to uc_open
|
||||
*
|
||||
|
@ -288,10 +322,13 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S
|
|||
*
|
||||
* @param arch Architecture type (UC_ARCH_*)
|
||||
* @param mode Hardware mode. This is combined of UC_MODE_*
|
||||
* @see unicorn.UnicornArchs, unicorn.UnicornModes
|
||||
* @see unicorn.UnicornConst
|
||||
*
|
||||
*/
|
||||
public Unicorn(int arch, int mode) throws UnicornException {
|
||||
//remember these in case we need arch specific code
|
||||
this.arch = arch;
|
||||
this.mode = mode;
|
||||
eng = open(arch, mode);
|
||||
unicorns.put(eng, this);
|
||||
allLists.add(blockList);
|
||||
|
@ -327,7 +364,7 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S
|
|||
*
|
||||
* @param arch Architecture type (UC_ARCH_*)
|
||||
* @return true if this library supports the given arch.
|
||||
* @see unicorn.UnicornArchs
|
||||
* @see unicorn.UnicornConst
|
||||
*/
|
||||
public native static boolean arch_supported(int arch);
|
||||
|
||||
|
@ -337,12 +374,23 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S
|
|||
*/
|
||||
public native void close() throws UnicornException;
|
||||
|
||||
/**
|
||||
* Query internal status of engine.
|
||||
*
|
||||
* @param type query type. See UC_QUERY_*
|
||||
* @param result save the internal status queried
|
||||
*
|
||||
* @return: error code. see UC_ERR_*
|
||||
* @see unicorn.UnicornConst
|
||||
*/
|
||||
public native int query(int type) throws UnicornException;
|
||||
|
||||
/**
|
||||
* Report the last error number when some API function fail.
|
||||
* Like glibc's errno, uc_errno might not retain its old value once accessed.
|
||||
*
|
||||
* @return Error code of uc_err enum type (UC_ERR_*, see above)
|
||||
* @see unicorn.UnicornErrors
|
||||
* @see unicorn.UnicornConst
|
||||
*/
|
||||
public native int errno();
|
||||
|
||||
|
@ -351,26 +399,67 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S
|
|||
*
|
||||
* @param code Error code (see UC_ERR_* above)
|
||||
* @return Returns a String that describes the error code
|
||||
* @see unicorn.UnicornErrors
|
||||
* @see unicorn.UnicornConst
|
||||
*/
|
||||
public native static String strerror(int code);
|
||||
|
||||
/**
|
||||
* Write to register.
|
||||
*
|
||||
* @deprecated use reg_write(int regid, Object value) instead
|
||||
* @param regid Register ID that is to be modified.
|
||||
* @param value Array containing value that will be written into register @regid
|
||||
*/
|
||||
@Deprecated
|
||||
public native void reg_write(int regid, byte[] value) throws UnicornException;
|
||||
|
||||
/**
|
||||
* Write to register.
|
||||
*
|
||||
* @param regid Register ID that is to be modified.
|
||||
* @param value Object containing the new register value. Long, BigInteger, or
|
||||
* other custom class used to represent register values
|
||||
*/
|
||||
public void reg_write(int regid, Object value) throws UnicornException {
|
||||
if (value instanceof Number) {
|
||||
reg_write_num(regid, (Number)value);
|
||||
}
|
||||
else if (arch == UC_ARCH_X86 && value instanceof X86_MMR) {
|
||||
if (regid >= UC_X86_REG_IDTR && regid <= UC_X86_REG_TR) {
|
||||
reg_write_mmr(regid, (X86_MMR)value);
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw new ClassCastException("Invalid value type");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Read register value.
|
||||
*
|
||||
* @deprecated use Object reg_write(int regid) instead
|
||||
* @param regid Register ID that is to be retrieved.
|
||||
* @param regsz Size of the register being retrieved.
|
||||
* @return Byte array containing the requested register value.
|
||||
*/
|
||||
@Deprecated
|
||||
public native byte[] reg_read(int regid, int regsz) throws UnicornException;
|
||||
|
||||
/**
|
||||
* Read register value.
|
||||
*
|
||||
* @param regid Register ID that is to be retrieved.
|
||||
* @param regsz Size of the register being retrieved.
|
||||
* @return Byte array containing the requested register value.
|
||||
* @return Object containing the requested register value. Long, BigInteger, or
|
||||
* other custom class used to represent register values
|
||||
*/
|
||||
public native byte[] reg_read(int regid, int regsz) throws UnicornException;
|
||||
public Object reg_read(int regid) throws UnicornException {
|
||||
if (arch == UC_ARCH_X86 && regid >= UC_X86_REG_IDTR && regid <= UC_X86_REG_TR) {
|
||||
return reg_read_mmr(regid);
|
||||
}
|
||||
else {
|
||||
return reg_read_num(regid);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Write to memory.
|
||||
|
@ -625,6 +714,19 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S
|
|||
*/
|
||||
public native void mem_map(long address, long size, int perms) throws UnicornException;
|
||||
|
||||
/**
|
||||
* Map existing host memory in for emulation.
|
||||
* This API adds a memory region that can be used by emulation.
|
||||
*
|
||||
* @param address Base address of the memory range
|
||||
* @param size Size of the memory block.
|
||||
* @param perms Permissions on the memory block. A combination of UC_PROT_READ, UC_PROT_WRITE, UC_PROT_EXEC
|
||||
* @param ptr Block of host memory backing the newly mapped memory. This block 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.
|
||||
*/
|
||||
public native void mem_map_ptr(long address, long size, int perms, byte[] block) throws UnicornException;
|
||||
|
||||
/**
|
||||
* Unmap a range of memory.
|
||||
*
|
||||
|
@ -642,5 +744,13 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S
|
|||
*/
|
||||
public native void mem_protect(long address, long size, int perms) throws UnicornException;
|
||||
|
||||
/**
|
||||
* Retrieve all memory regions mapped by mem_map() and mem_map_ptr()
|
||||
* NOTE: memory regions may be split by mem_unmap()
|
||||
*
|
||||
* @return list of mapped regions.
|
||||
*/
|
||||
public native MemRegion[] mem_regions() throws UnicornException;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
package unicorn;
|
||||
|
||||
public interface UnicornConst {
|
||||
public static final int UC_API_MAJOR = 1;
|
||||
|
||||
public static final int UC_API_MAJOR = 0;
|
||||
public static final int UC_API_MINOR = 9;
|
||||
public static final int UC_API_MINOR = 0;
|
||||
public static final int UC_SECOND_SCALE = 1000000;
|
||||
public static final int UC_MILISECOND_SCALE = 1000;
|
||||
public static final int UC_ARCH_ARM = 1;
|
||||
|
@ -18,22 +18,26 @@ public interface UnicornConst {
|
|||
public static final int UC_ARCH_MAX = 8;
|
||||
|
||||
public static final int UC_MODE_LITTLE_ENDIAN = 0;
|
||||
public static final int UC_MODE_BIG_ENDIAN = 1073741824;
|
||||
|
||||
public static final int UC_MODE_ARM = 0;
|
||||
public static final int UC_MODE_16 = 2;
|
||||
public static final int UC_MODE_32 = 4;
|
||||
public static final int UC_MODE_64 = 8;
|
||||
public static final int UC_MODE_THUMB = 16;
|
||||
public static final int UC_MODE_MCLASS = 32;
|
||||
public static final int UC_MODE_V8 = 64;
|
||||
public static final int UC_MODE_MICRO = 16;
|
||||
public static final int UC_MODE_MIPS3 = 32;
|
||||
public static final int UC_MODE_MIPS32R6 = 64;
|
||||
public static final int UC_MODE_V9 = 16;
|
||||
public static final int UC_MODE_QPX = 16;
|
||||
public static final int UC_MODE_BIG_ENDIAN = 1073741824;
|
||||
public static final int UC_MODE_MIPS32 = 4;
|
||||
public static final int UC_MODE_MIPS64 = 8;
|
||||
public static final int UC_MODE_16 = 2;
|
||||
public static final int UC_MODE_32 = 4;
|
||||
public static final int UC_MODE_64 = 8;
|
||||
public static final int UC_MODE_PPC32 = 4;
|
||||
public static final int UC_MODE_PPC64 = 8;
|
||||
public static final int UC_MODE_QPX = 16;
|
||||
public static final int UC_MODE_SPARC32 = 4;
|
||||
public static final int UC_MODE_SPARC64 = 8;
|
||||
public static final int UC_MODE_V9 = 16;
|
||||
|
||||
public static final int UC_ERR_OK = 0;
|
||||
public static final int UC_ERR_NOMEM = 1;
|
||||
|
@ -84,6 +88,9 @@ public interface UnicornConst {
|
|||
public static final int UC_HOOK_MEM_WRITE_INVALID = 288;
|
||||
public static final int UC_HOOK_MEM_FETCH_INVALID = 576;
|
||||
public static final int UC_HOOK_MEM_INVALID = 1008;
|
||||
public static final int UC_HOOK_MEM_VALID = 7168;
|
||||
public static final int UC_QUERY_MODE = 1;
|
||||
public static final int UC_QUERY_PAGE_SIZE = 2;
|
||||
|
||||
public static final int UC_PROT_NONE = 0;
|
||||
public static final int UC_PROT_READ = 1;
|
||||
|
|
|
@ -1,38 +0,0 @@
|
|||
/*
|
||||
|
||||
Java bindings for the Unicorn Emulator Engine
|
||||
|
||||
Copyright(c) 2015 Chris Eagle
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
package unicorn;
|
||||
|
||||
public interface UnicornErrors {
|
||||
public static final int UC_ERR_OK = 0; // No error: everything was fine
|
||||
public static final int UC_ERR_OOM = 1; // Out-Of-Memory error: uc_open(), uc_emulate()
|
||||
public static final int UC_ERR_ARCH = 2; // Unsupported architecture: uc_open()
|
||||
public static final int UC_ERR_HANDLE = 3; // Invalid handle
|
||||
public static final int UC_ERR_UCH = 4; // Invalid handle (uch)
|
||||
public static final int UC_ERR_MODE = 5; // Invalid/unsupported mode: uc_open()
|
||||
public static final int UC_ERR_VERSION = 6; // Unsupported version (bindings)
|
||||
public static final int UC_ERR_MEM_READ = 7; // Quit emulation due to invalid memory READ: uc_emu_start()
|
||||
public static final int UC_ERR_MEM_WRITE = 8; // Quit emulation due to invalid memory WRITE: uc_emu_start()
|
||||
public static final int UC_ERR_HOOK = 9; // Invalid hook type: uc_hook_add()
|
||||
public static final int UC_ERR_INSN_INVALID = 10; // Quit emulation due to invalid instruction: uc_emu_start()
|
||||
public static final int UC_ERR_MAP = 11; // Invalid memory mapping: uc_mem_map()
|
||||
}
|
||||
|
|
@ -248,7 +248,13 @@ public interface X86Const {
|
|||
public static final int UC_X86_REG_R13W = 239;
|
||||
public static final int UC_X86_REG_R14W = 240;
|
||||
public static final int UC_X86_REG_R15W = 241;
|
||||
public static final int UC_X86_REG_ENDING = 242;
|
||||
public static final int UC_X86_REG_IDTR = 242;
|
||||
public static final int UC_X86_REG_GDTR = 243;
|
||||
public static final int UC_X86_REG_LDTR = 244;
|
||||
public static final int UC_X86_REG_TR = 245;
|
||||
public static final int UC_X86_REG_FPCW = 246;
|
||||
public static final int UC_X86_REG_FPTAG = 247;
|
||||
public static final int UC_X86_REG_ENDING = 248;
|
||||
|
||||
// X86 instructions
|
||||
|
||||
|
|
46
bindings/java/unicorn/X86_MMR.java
Normal file
46
bindings/java/unicorn/X86_MMR.java
Normal file
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
|
||||
Java bindings for the Unicorn Emulator Engine
|
||||
|
||||
Copyright(c) 2016 Chris Eagle
|
||||
|
||||
This program is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU General Public License
|
||||
version 2 as published by the Free Software Foundation.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
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.
|
||||
|
||||
*/
|
||||
|
||||
package unicorn;
|
||||
|
||||
public class X86_MMR {
|
||||
|
||||
public long base;
|
||||
public int limit;
|
||||
public int flags;
|
||||
public short selector;
|
||||
|
||||
public X86_MMR(long base, int limit, int flags, short selector) {
|
||||
this.base = base;
|
||||
this.limit = limit;
|
||||
this.flags = flags;
|
||||
this.selector = selector;
|
||||
}
|
||||
|
||||
public X86_MMR(long base, int limit) {
|
||||
this.base = base;
|
||||
this.limit = limit;
|
||||
selector = 0;
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -24,8 +24,8 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#include <unicorn/unicorn.h>
|
||||
#include <unicorn/x86.h>
|
||||
#include "unicorn_Unicorn.h"
|
||||
|
||||
//cache jmethodID values as we look them up
|
||||
|
@ -201,6 +201,117 @@ static uc_engine *getEngine(JNIEnv *env, jobject self) {
|
|||
return (uc_engine *)(*env)->GetLongField(env, self, fid);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: unicorn_Unicorn
|
||||
* Method: reg_write_num
|
||||
* Signature: (ILjava/lang/Number;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_unicorn_Unicorn_reg_1write_1num
|
||||
(JNIEnv *env, jobject self, jint regid, jobject value) {
|
||||
uc_engine *eng = getEngine(env, self);
|
||||
|
||||
jclass clz = (*env)->FindClass(env, "java/lang/Number");
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
return;
|
||||
}
|
||||
|
||||
jmethodID longValue = (*env)->GetMethodID(env, clz, "longValue", "()J");
|
||||
jlong longVal = (*env)->CallLongMethod(env, value, longValue);
|
||||
uc_err err = uc_reg_write(eng, regid, &longVal);
|
||||
if (err != UC_ERR_OK) {
|
||||
throwException(env, err);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: unicorn_Unicorn
|
||||
* Method: reg_write_mmr
|
||||
* Signature: (ILunicorn/X86_MMR;)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_unicorn_Unicorn_reg_1write_1mmr
|
||||
(JNIEnv *env, jobject self, jint regid, jobject value) {
|
||||
uc_engine *eng = getEngine(env, self);
|
||||
uc_x86_mmr mmr;
|
||||
|
||||
jclass clz = (*env)->FindClass(env, "unicorn/X86_MMR");
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
return;
|
||||
}
|
||||
|
||||
jfieldID fid = (*env)->GetFieldID(env, clz, "base", "J");
|
||||
mmr.base = (uint64_t)(*env)->GetLongField(env, value, fid);
|
||||
|
||||
fid = (*env)->GetFieldID(env, clz, "limit", "I");
|
||||
mmr.limit = (uint32_t)(*env)->GetLongField(env, value, fid);
|
||||
|
||||
fid = (*env)->GetFieldID(env, clz, "flags", "I");
|
||||
mmr.flags = (uint32_t)(*env)->GetLongField(env, value, fid);
|
||||
|
||||
fid = (*env)->GetFieldID(env, clz, "selector", "S");
|
||||
mmr.selector = (uint16_t)(*env)->GetLongField(env, value, fid);
|
||||
|
||||
uc_err err = uc_reg_write(eng, regid, &mmr);
|
||||
if (err != UC_ERR_OK) {
|
||||
throwException(env, err);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: unicorn_Unicorn
|
||||
* Method: reg_read_num
|
||||
* Signature: (I)Ljava/lang/Number;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_unicorn_Unicorn_reg_1read_1num
|
||||
(JNIEnv *env, jobject self, jint regid) {
|
||||
uc_engine *eng = getEngine(env, self);
|
||||
|
||||
jclass clz = (*env)->FindClass(env, "java/lang/Long");
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
jlong longVal;
|
||||
uc_err err = uc_reg_read(eng, regid, &longVal);
|
||||
if (err != UC_ERR_OK) {
|
||||
throwException(env, err);
|
||||
}
|
||||
|
||||
jmethodID cons = (*env)->GetMethodID(env, clz, "<init>", "(J)V");
|
||||
jobject result = (*env)->NewObject(env, clz, cons, longVal);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: unicorn_Unicorn
|
||||
* Method: reg_read_mmr
|
||||
* Signature: (I)Ljava/lang/Number;
|
||||
*/
|
||||
JNIEXPORT jobject JNICALL Java_unicorn_Unicorn_reg_1read_1mmr
|
||||
(JNIEnv *env, jobject self, jint regid) {
|
||||
uc_engine *eng = getEngine(env, self);
|
||||
|
||||
jclass clz = (*env)->FindClass(env, "unicorn/X86_MMR");
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uc_x86_mmr mmr;
|
||||
uc_err err = uc_reg_read(eng, regid, &mmr);
|
||||
if (err != UC_ERR_OK) {
|
||||
throwException(env, err);
|
||||
}
|
||||
|
||||
jmethodID cons = (*env)->GetMethodID(env, clz, "<init>", "(JIIS)V");
|
||||
jobject result = (*env)->NewObject(env, clz, cons, mmr.base, mmr.limit, mmr.flags, mmr.selector);
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
return NULL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: unicorn_Unicorn
|
||||
* Method: open
|
||||
|
@ -244,7 +355,28 @@ JNIEXPORT jboolean JNICALL Java_unicorn_Unicorn_arch_1supported
|
|||
JNIEXPORT void JNICALL Java_unicorn_Unicorn_close
|
||||
(JNIEnv *env, jobject self) {
|
||||
uc_engine *eng = getEngine(env, self);
|
||||
uc_close(eng);
|
||||
uc_err err = uc_close(eng);
|
||||
if (err != UC_ERR_OK) {
|
||||
throwException(env, err);
|
||||
}
|
||||
//We also need to ReleaseByteArrayElements for any regions that
|
||||
//were mapped with uc_mem_map_ptr
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: unicorn_Unicorn
|
||||
* Method: query
|
||||
* Signature: (I)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_unicorn_Unicorn_query
|
||||
(JNIEnv *env, jobject self, jint type) {
|
||||
uc_engine *eng = getEngine(env, self);
|
||||
size_t result;
|
||||
uc_err err = uc_query(eng, type, &result);
|
||||
if (err != UC_ERR_OK) {
|
||||
throwException(env, err);
|
||||
}
|
||||
return (jint)result;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -508,6 +640,24 @@ JNIEXPORT void JNICALL Java_unicorn_Unicorn_mem_1map
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: unicorn_Unicorn
|
||||
* Method: mem_map_ptr
|
||||
* Signature: (JJI[B)V
|
||||
*/
|
||||
JNIEXPORT void JNICALL Java_unicorn_Unicorn_mem_1map_1ptr
|
||||
(JNIEnv *env, jobject self, jlong address, jlong size, jint perms, jbyteArray block) {
|
||||
uc_engine *eng = getEngine(env, self);
|
||||
jbyte *array = (*env)->GetByteArrayElements(env, block, NULL);
|
||||
uc_err err = uc_mem_map_ptr(eng, (uint64_t)address, (size_t)size, (uint32_t)perms, (void*)array);
|
||||
if (err != UC_ERR_OK) {
|
||||
throwException(env, err);
|
||||
}
|
||||
//Need to track address/block/array so that we can ReleaseByteArrayElements when the
|
||||
//block gets unmapped or when uc_close gets called
|
||||
//(*env)->ReleaseByteArrayElements(env, block, array, JNI_ABORT);
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: unicorn_Unicorn
|
||||
* Method: mem_unmap
|
||||
|
@ -521,6 +671,9 @@ JNIEXPORT void JNICALL Java_unicorn_Unicorn_mem_1unmap
|
|||
if (err != UC_ERR_OK) {
|
||||
throwException(env, err);
|
||||
}
|
||||
|
||||
//If a region was mapped using uc_mem_map_ptr, we also need to
|
||||
//ReleaseByteArrayElements for that region
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -537,3 +690,35 @@ JNIEXPORT void JNICALL Java_unicorn_Unicorn_mem_1protect
|
|||
throwException(env, err);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Class: unicorn_Unicorn
|
||||
* Method: mem_regions
|
||||
* Signature: ()[Lunicorn/MemRegion;
|
||||
*/
|
||||
JNIEXPORT jobjectArray JNICALL Java_unicorn_Unicorn_mem_1regions
|
||||
(JNIEnv *env, jobject self) {
|
||||
uc_engine *eng = getEngine(env, self);
|
||||
|
||||
uc_mem_region *regions = NULL;
|
||||
uint32_t count = 0;
|
||||
uint32_t i;
|
||||
|
||||
uc_err err = uc_mem_regions(eng, ®ions, &count);
|
||||
if (err != UC_ERR_OK) {
|
||||
throwException(env, err);
|
||||
}
|
||||
jclass clz = (*env)->FindClass(env, "unicorn/MemRegion");
|
||||
if ((*env)->ExceptionCheck(env)) {
|
||||
return NULL;
|
||||
}
|
||||
jobjectArray result = (*env)->NewObjectArray(env, (jsize)count, clz, NULL);
|
||||
jmethodID cons = (*env)->GetMethodID(env, clz, "<init>", "(JJI)V");
|
||||
for (i = 0; i < count; i++) {
|
||||
jobject mr = (*env)->NewObject(env, clz, cons, regions[i].begin, regions[i].end, regions[i].perms);
|
||||
(*env)->SetObjectArrayElement(env, result, (jsize)i, mr);
|
||||
}
|
||||
free(regions);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -75,7 +75,7 @@ int main(int argc, char **argv, char **envp)
|
|||
#endif
|
||||
|
||||
// Initialize emulator in MIPS 32bit little endian mode
|
||||
err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc);
|
||||
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\n", err);
|
||||
|
|
|
@ -3,6 +3,7 @@ uc_version
|
|||
uc_arch_supported
|
||||
uc_open
|
||||
uc_close
|
||||
uc_query
|
||||
uc_errno
|
||||
uc_strerror
|
||||
uc_reg_write
|
||||
|
@ -14,5 +15,7 @@ uc_emu_stop
|
|||
uc_hook_add
|
||||
uc_hook_del
|
||||
uc_mem_map
|
||||
uc_mem_map_ptr
|
||||
uc_mem_unmap
|
||||
uc_mem_protect
|
||||
uc_mem_regions
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// Dynamic loader for unicorn shared library in windows and linux.
|
||||
// This was made for v0.9 of unicorn.
|
||||
// This was made for v1.0 of unicorn.
|
||||
// Newer versions of unicorn may require changes to these files.
|
||||
//
|
||||
// Windows Notes:
|
||||
|
@ -62,6 +62,7 @@ typedef unsigned int (*uc_version_t)(unsigned int *major, unsigned int *minor);
|
|||
typedef bool (*uc_arch_supported_t)(uc_arch arch);
|
||||
typedef uc_err (*uc_open_t)(uc_arch arch, uc_mode mode, uc_engine **uc);
|
||||
typedef uc_err (*uc_close_t)(uc_engine *uc);
|
||||
typedef uc_err (*uc_query_t)(uc_engine *uc, uc_query_type type, size_t *result);
|
||||
typedef uc_err (*uc_errno_t)(uc_engine *uc);
|
||||
typedef const char* (*uc_strerror_t)(uc_err code);
|
||||
typedef uc_err (*uc_reg_write_t)(uc_engine *uc, int regid, const void *value);
|
||||
|
@ -70,17 +71,20 @@ typedef uc_err (*uc_mem_write_t)(uc_engine *uc, uint64_t address, const void *by
|
|||
typedef uc_err (*uc_mem_read_t)(uc_engine *uc, uint64_t address, void *bytes, size_t size);
|
||||
typedef uc_err (*uc_emu_start_t)(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count);
|
||||
typedef uc_err (*uc_emu_stop_t)(uc_engine *uc);
|
||||
typedef uc_err (*uc_hook_add_t)(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...);
|
||||
typedef uc_err (*uc_hook_add_t)(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, uint64_t begin, uint64_t end, ...);
|
||||
typedef uc_err (*uc_hook_del_t)(uc_engine *uc, uc_hook hh);
|
||||
typedef uc_err (*uc_mem_map_t)(uc_engine *uc, uint64_t address, size_t size, uint32_t perms);
|
||||
typedef uc_err (*uc_mem_map_ptr_t)(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr);
|
||||
typedef uc_err (*uc_mem_unmap_t)(uc_engine *uc, uint64_t address, size_t size);
|
||||
typedef uc_err (*uc_mem_protect_t)(uc_engine *uc, uint64_t address, size_t size, uint32_t perms);
|
||||
typedef uc_err (*uc_mem_regions_t)(uc_engine *uc, uc_mem_region **regions, uint32_t *count);
|
||||
|
||||
|
||||
static uc_version_t gp_uc_version = NULL;
|
||||
static uc_arch_supported_t gp_uc_arch_supported = NULL;
|
||||
static uc_open_t gp_uc_open = NULL;
|
||||
static uc_close_t gp_uc_close = NULL;
|
||||
static uc_query_t gp_uc_query = NULL;
|
||||
static uc_errno_t gp_uc_errno = NULL;
|
||||
static uc_strerror_t gp_uc_strerror = NULL;
|
||||
static uc_reg_write_t gp_uc_reg_write = NULL;
|
||||
|
@ -92,8 +96,10 @@ static uc_emu_stop_t gp_uc_emu_stop = NULL;
|
|||
static uc_hook_add_t gp_uc_hook_add = NULL;
|
||||
static uc_hook_del_t gp_uc_hook_del = NULL;
|
||||
static uc_mem_map_t gp_uc_mem_map = NULL;
|
||||
static uc_mem_map_ptr_t gp_uc_mem_map_ptr = NULL;
|
||||
static uc_mem_unmap_t gp_uc_mem_unmap = NULL;
|
||||
static uc_mem_protect_t gp_uc_mem_protect = NULL;
|
||||
static uc_mem_regions_t gp_uc_mem_regions = NULL;
|
||||
|
||||
|
||||
bool uc_dyn_load(const char* path, int flags)
|
||||
|
@ -118,6 +124,7 @@ bool uc_dyn_load(const char* path, int flags)
|
|||
gp_uc_arch_supported = (uc_arch_supported_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_arch_supported");
|
||||
gp_uc_open = (uc_open_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_open");
|
||||
gp_uc_close = (uc_close_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_close");
|
||||
gp_uc_query = (uc_query_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_query");
|
||||
gp_uc_errno = (uc_errno_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_errno");
|
||||
gp_uc_strerror = (uc_strerror_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_strerror");
|
||||
gp_uc_reg_write = (uc_reg_write_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_reg_write");
|
||||
|
@ -129,8 +136,10 @@ bool uc_dyn_load(const char* path, int flags)
|
|||
gp_uc_hook_add = (uc_hook_add_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_hook_add");
|
||||
gp_uc_hook_del = (uc_hook_del_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_hook_del");
|
||||
gp_uc_mem_map = (uc_mem_map_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_map");
|
||||
gp_uc_mem_map_ptr = (uc_mem_map_ptr_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_map_ptr");
|
||||
gp_uc_mem_unmap = (uc_mem_unmap_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_unmap");
|
||||
gp_uc_mem_protect = (uc_mem_protect_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_protect");
|
||||
gp_uc_mem_regions = (uc_mem_regions_t)DYNLOAD_GETFUNC(g_dyn_handle, "uc_mem_regions");
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -146,6 +155,7 @@ bool uc_dyn_free(void)
|
|||
gp_uc_arch_supported = NULL;
|
||||
gp_uc_open = NULL;
|
||||
gp_uc_close = NULL;
|
||||
gp_uc_query = NULL;
|
||||
gp_uc_errno = NULL;
|
||||
gp_uc_strerror = NULL;
|
||||
gp_uc_reg_write = NULL;
|
||||
|
@ -157,8 +167,10 @@ bool uc_dyn_free(void)
|
|||
gp_uc_hook_add = NULL;
|
||||
gp_uc_hook_del = NULL;
|
||||
gp_uc_mem_map = NULL;
|
||||
gp_uc_mem_map_ptr = NULL;
|
||||
gp_uc_mem_unmap = NULL;
|
||||
gp_uc_mem_protect = NULL;
|
||||
gp_uc_mem_regions = NULL;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -183,6 +195,11 @@ uc_err uc_close(uc_engine *uc)
|
|||
return gp_uc_close(uc);
|
||||
}
|
||||
|
||||
uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result)
|
||||
{
|
||||
return gp_uc_query(uc, type, result);
|
||||
}
|
||||
|
||||
uc_err uc_errno(uc_engine *uc)
|
||||
{
|
||||
return gp_uc_errno(uc);
|
||||
|
@ -223,43 +240,40 @@ uc_err uc_emu_stop(uc_engine *uc)
|
|||
return gp_uc_emu_stop(uc);
|
||||
}
|
||||
|
||||
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...)
|
||||
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, uint64_t begin, uint64_t end, ...)
|
||||
{
|
||||
va_list valist;
|
||||
uc_err ret = UC_ERR_OK;
|
||||
int id;
|
||||
uint64_t begin, end;
|
||||
va_start(valist, user_data);
|
||||
|
||||
switch(type) {
|
||||
// note this default case will capture any combinations of
|
||||
// UC_HOOK_MEM_*_PROT and UC_HOOK_MEM_*_UNMAPPED
|
||||
// as well as any combination of
|
||||
// UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE and UC_HOOK_MEM_FETCH
|
||||
default:
|
||||
case UC_HOOK_INTR:
|
||||
case UC_HOOK_CODE:
|
||||
case UC_HOOK_BLOCK:
|
||||
// all combinations of UC_HOOK_MEM_*_PROT and UC_HOOK_MEM_*_UNMAPPED are caught by 'default'
|
||||
case UC_HOOK_MEM_READ_UNMAPPED:
|
||||
case UC_HOOK_MEM_WRITE_UNMAPPED:
|
||||
case UC_HOOK_MEM_FETCH_UNMAPPED:
|
||||
case UC_HOOK_MEM_READ_PROT:
|
||||
case UC_HOOK_MEM_WRITE_PROT:
|
||||
case UC_HOOK_MEM_FETCH_PROT:
|
||||
// all combinations of read/write/fetch are caught by 'default'
|
||||
case UC_HOOK_MEM_READ:
|
||||
case UC_HOOK_MEM_WRITE:
|
||||
case UC_HOOK_MEM_FETCH:
|
||||
// 0 extra args
|
||||
ret = gp_uc_hook_add(uc, hh, type, callback, user_data);
|
||||
ret = gp_uc_hook_add(uc, hh, type, callback, user_data, begin, end);
|
||||
break;
|
||||
case UC_HOOK_INSN:
|
||||
// 1 extra arg
|
||||
id = va_arg(valist, int);
|
||||
ret = gp_uc_hook_add(uc, hh, type, callback, user_data, id);
|
||||
break;
|
||||
case UC_HOOK_CODE:
|
||||
case UC_HOOK_BLOCK:
|
||||
case UC_HOOK_MEM_READ:
|
||||
case UC_HOOK_MEM_WRITE:
|
||||
case UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE:
|
||||
// 2 extra args
|
||||
begin = va_arg(valist, uint64_t);
|
||||
end = va_arg(valist, uint64_t);
|
||||
ret = gp_uc_hook_add(uc, hh, type, callback, user_data, begin, end);
|
||||
ret = gp_uc_hook_add(uc, hh, type, callback, user_data, begin, end, id);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -277,6 +291,11 @@ uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
|
|||
return gp_uc_mem_map(uc, address, size, perms);
|
||||
}
|
||||
|
||||
uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr)
|
||||
{
|
||||
return gp_uc_mem_map_ptr(uc, address, size, perms, ptr);
|
||||
}
|
||||
|
||||
uc_err uc_mem_unmap(uc_engine *uc, uint64_t address, size_t size)
|
||||
{
|
||||
return gp_uc_mem_unmap(uc, address, size);
|
||||
|
@ -287,4 +306,9 @@ uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size, uint32_t per
|
|||
return gp_uc_mem_protect(uc, address, size, perms);
|
||||
}
|
||||
|
||||
uc_err uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count)
|
||||
{
|
||||
return gp_uc_mem_regions(uc, regions, count);
|
||||
}
|
||||
|
||||
#endif // DYNLOAD
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
//
|
||||
// Dynamic loader for unicorn shared library in windows and linux.
|
||||
// This was made for v0.9 of unicorn.
|
||||
// This was made for v1.0 of unicorn.
|
||||
// Newer versions of unicorn may require changes to these files.
|
||||
//
|
||||
// Windows Notes:
|
||||
|
|
|
@ -7,7 +7,6 @@ from unicorn import *
|
|||
from unicorn.x86_const import *
|
||||
import struct
|
||||
import uuid
|
||||
import random
|
||||
|
||||
SIZE_REG = 4
|
||||
SOCKETCALL_MAX_ARGS = 3
|
||||
|
@ -51,10 +50,11 @@ X86_REVERSE_TCP_2 = b"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66\xb3\x01\x51\x6a\x
|
|||
# memory address where emulation starts
|
||||
ADDRESS = 0x1000000
|
||||
|
||||
|
||||
# supported classes
|
||||
class IdGenerator:
|
||||
def __init__(self):
|
||||
self.__next_id = 3 # exclude sdtin, stdout, stderr
|
||||
self.__next_id = 3 # exclude sdtin, stdout, stderr
|
||||
|
||||
def next(self):
|
||||
next_id = self.__next_id
|
||||
|
@ -63,6 +63,7 @@ class IdGenerator:
|
|||
|
||||
return next_id
|
||||
|
||||
|
||||
class LogChain:
|
||||
def __init__(self):
|
||||
self.__chains = {}
|
||||
|
@ -72,11 +73,11 @@ class LogChain:
|
|||
self.__chains = {}
|
||||
self.__linking_fds = {}
|
||||
|
||||
def create_chain(self, id):
|
||||
if not self.__chains.has_key(id):
|
||||
self.__chains[id] = []
|
||||
def create_chain(self, my_id):
|
||||
if not my_id in self.__chains:
|
||||
self.__chains[my_id] = []
|
||||
else:
|
||||
print("LogChain: id %d existed" % id)
|
||||
print("LogChain: id %d existed" % my_id)
|
||||
|
||||
def add_log(self, id, msg):
|
||||
fd = self.get_original_fd(id)
|
||||
|
@ -87,20 +88,20 @@ class LogChain:
|
|||
print("LogChain: id %d doesn't exist" % id)
|
||||
|
||||
def link_fd(self, from_fd, to_fd):
|
||||
if not self.__linking_fds.has_key(to_fd):
|
||||
if not to_fd in self.__linking_fds:
|
||||
self.__linking_fds[to_fd] = []
|
||||
|
||||
self.__linking_fds[to_fd].append(from_fd)
|
||||
|
||||
def get_original_fd(self, fd):
|
||||
if self.__chains.has_key(fd):
|
||||
if fd in self.__chains:
|
||||
return fd
|
||||
|
||||
for orig_fd, links in self.__linking_fds.iteritems():
|
||||
for orig_fd, links in self.__linking_fds.items():
|
||||
if fd in links:
|
||||
return orig_fd
|
||||
|
||||
return None
|
||||
return None
|
||||
|
||||
def print_report(self):
|
||||
print("""
|
||||
|
@ -108,10 +109,11 @@ class LogChain:
|
|||
| START REPORT |
|
||||
----------------
|
||||
""")
|
||||
for id, logs in self.__chains.iteritems():
|
||||
print("---- START FD(%d) ----" % id)
|
||||
|
||||
for my_id, logs in self.__chains.items():
|
||||
print("---- START FD(%d) ----" % my_id)
|
||||
print("\n".join(logs))
|
||||
print("---- END FD(%d) ----" % id)
|
||||
print("---- END FD(%d) ----" % my_id)
|
||||
|
||||
print("""
|
||||
--------------
|
||||
|
@ -119,10 +121,9 @@ class LogChain:
|
|||
--------------
|
||||
""")
|
||||
|
||||
|
||||
# end supported classes
|
||||
|
||||
id_gen = IdGenerator()
|
||||
fd_chains = LogChain()
|
||||
|
||||
# utilities
|
||||
def bin_to_ipv4(ip):
|
||||
|
@ -132,6 +133,7 @@ def bin_to_ipv4(ip):
|
|||
(ip & 0xff00) >> 8,
|
||||
(ip & 0xff))
|
||||
|
||||
|
||||
def read_string(uc, addr):
|
||||
ret = ""
|
||||
|
||||
|
@ -140,36 +142,43 @@ def read_string(uc, addr):
|
|||
|
||||
while c != 0x0:
|
||||
ret += chr(c)
|
||||
c = uc.mem_read(addr+read_bytes, 1)[0]
|
||||
c = uc.mem_read(addr + read_bytes, 1)[0]
|
||||
read_bytes += 1
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def parse_sock_address(sock_addr):
|
||||
sin_family, = struct.unpack("<h", sock_addr[:2])
|
||||
|
||||
if sin_family == 2: # AF_INET
|
||||
port, host = struct.unpack(">HI", sock_addr[2:8])
|
||||
|
||||
if sin_family == 2: # AF_INET
|
||||
port, host = struct.unpack(">HI", sock_addr[2:8])
|
||||
return "%s:%d" % (bin_to_ipv4(host), port)
|
||||
elif sin_family == 6: # AF_INET6
|
||||
elif sin_family == 6: # AF_INET6
|
||||
return ""
|
||||
|
||||
|
||||
def print_sockcall(msg):
|
||||
print(">>> SOCKCALL %s" % msg)
|
||||
|
||||
|
||||
# end utilities
|
||||
|
||||
# callback for tracing instructions
|
||||
def hook_code(uc, address, size, user_data):
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size))
|
||||
print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" % (address, size))
|
||||
# read this instruction code from memory
|
||||
tmp = uc.mem_read(address, size)
|
||||
print(">>> Instruction code at [0x%x] =" %(address), end="")
|
||||
print(">>> Instruction code at [0x%x] =" % (address), end="")
|
||||
for i in tmp:
|
||||
print(" %x" %i, end="")
|
||||
print(" %x" % i, end="")
|
||||
print("")
|
||||
|
||||
|
||||
# callback for tracing Linux interrupt
|
||||
def hook_intr(uc, intno, user_data):
|
||||
global id_gen
|
||||
|
||||
# only handle Linux syscall
|
||||
if intno != 0x80:
|
||||
return
|
||||
|
@ -182,17 +191,17 @@ def hook_intr(uc, intno, user_data):
|
|||
|
||||
# print(">>> INTERRUPT %d" % eax)
|
||||
|
||||
if eax == 1: # sys_exit
|
||||
if eax == 1: # sys_exit
|
||||
print(">>> SYS_EXIT")
|
||||
uc.emu_stop()
|
||||
elif eax == 3: # sys_read
|
||||
elif eax == 3: # sys_read
|
||||
fd = ebx
|
||||
buf = ecx
|
||||
count = edx
|
||||
|
||||
dummy_content = str(uuid.uuid1())[:32]
|
||||
if len(dummy_content) > count:
|
||||
dummy_content = dummy_content[:count]
|
||||
dummy_content = dummy_content[:count]
|
||||
|
||||
uc.mem_write(buf, dummy_content)
|
||||
|
||||
|
@ -200,7 +209,7 @@ def hook_intr(uc, intno, user_data):
|
|||
|
||||
fd_chains.add_log(fd, msg)
|
||||
print(">>> %s" % msg)
|
||||
elif eax == 4: # sys_write
|
||||
elif eax == 4: # sys_write
|
||||
fd = ebx
|
||||
buf = ecx
|
||||
count = edx
|
||||
|
@ -211,13 +220,13 @@ def hook_intr(uc, intno, user_data):
|
|||
|
||||
print(">>> %s" % msg)
|
||||
fd_chains.add_log(fd, msg)
|
||||
elif eax == 5: # sys_open
|
||||
elif eax == 5: # sys_open
|
||||
filename_addr = ebx
|
||||
flags = ecx
|
||||
mode = edx
|
||||
filename = read_string(uc, filename_addr)
|
||||
|
||||
dummy_fd = id_gen.next()
|
||||
dummy_fd = id_gen.next()
|
||||
uc.reg_write(UC_X86_REG_EAX, dummy_fd)
|
||||
|
||||
msg = "open file (filename=%s flags=%d mode=%d) with fd(%d)" % (filename, flags, mode, dummy_fd)
|
||||
|
@ -225,42 +234,42 @@ def hook_intr(uc, intno, user_data):
|
|||
fd_chains.create_chain(dummy_fd)
|
||||
fd_chains.add_log(dummy_fd, msg)
|
||||
print(">>> %s" % msg)
|
||||
elif eax == 11: # sys_execv
|
||||
elif eax == 11: # sys_execv
|
||||
# print(">>> ebx=0x%x, ecx=0x%x, edx=0x%x" % (ebx, ecx, edx))
|
||||
filename = read_string(uc, ebx)
|
||||
|
||||
print(">>> SYS_EXECV filename=%s" % filename)
|
||||
elif eax == 63: # sys_dup2
|
||||
elif eax == 63: # sys_dup2
|
||||
fd_chains.link_fd(ecx, ebx)
|
||||
print(">>> SYS_DUP2 oldfd=%d newfd=%d" % (ebx, ecx))
|
||||
elif eax == 102: # sys_socketcall
|
||||
elif eax == 102: # sys_socketcall
|
||||
# ref: http://www.skyfree.org/linux/kernel_network/socket.html
|
||||
call = uc.reg_read(UC_X86_REG_EBX)
|
||||
args = uc.reg_read(UC_X86_REG_ECX)
|
||||
|
||||
SOCKETCALL_NUM_ARGS = {
|
||||
1: 3, # sys_socket
|
||||
2: 3, # sys_bind
|
||||
3: 3, # sys_connect
|
||||
4: 2, # sys_listen
|
||||
5: 3, # sys_accept
|
||||
9: 4, # sys_send
|
||||
1: 3, # sys_socket
|
||||
2: 3, # sys_bind
|
||||
3: 3, # sys_connect
|
||||
4: 2, # sys_listen
|
||||
5: 3, # sys_accept
|
||||
9: 4, # sys_send
|
||||
11: 4, # sys_receive
|
||||
13: 2 # sys_shutdown
|
||||
13: 2 # sys_shutdown
|
||||
}
|
||||
|
||||
buf = uc.mem_read(args, SOCKETCALL_NUM_ARGS[call]*SIZE_REG)
|
||||
args = struct.unpack("<" + "I"*SOCKETCALL_NUM_ARGS[call], buf)
|
||||
buf = uc.mem_read(args, SOCKETCALL_NUM_ARGS[call] * SIZE_REG)
|
||||
args = struct.unpack("<" + "I" * SOCKETCALL_NUM_ARGS[call], buf)
|
||||
|
||||
# int sys_socketcall(int call, unsigned long *args)
|
||||
if call == 1: # sys_socket
|
||||
if call == 1: # sys_socket
|
||||
# err = sys_socket(a0,a1,a[2])
|
||||
# int sys_socket(int family, int type, int protocol)
|
||||
family = args[0]
|
||||
sock_type = args[1]
|
||||
protocol = args[2]
|
||||
|
||||
dummy_fd = id_gen.next()
|
||||
dummy_fd = id_gen.next()
|
||||
uc.reg_write(UC_X86_REG_EAX, dummy_fd)
|
||||
|
||||
if family == 2: # AF_INET
|
||||
|
@ -269,10 +278,10 @@ def hook_intr(uc, intno, user_data):
|
|||
fd_chains.create_chain(dummy_fd)
|
||||
fd_chains.add_log(dummy_fd, msg)
|
||||
print_sockcall(msg)
|
||||
elif family == 3: # AF_INET6
|
||||
elif family == 3: # AF_INET6
|
||||
pass
|
||||
|
||||
elif call == 2: # sys_bind
|
||||
elif call == 2: # sys_bind
|
||||
fd = args[0]
|
||||
umyaddr = args[1]
|
||||
addrlen = args[2]
|
||||
|
@ -283,19 +292,19 @@ def hook_intr(uc, intno, user_data):
|
|||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
elif call == 3: # sys_connect
|
||||
elif call == 3: # sys_connect
|
||||
# err = sys_connect(a0, (struct sockaddr *)a1, a[2])
|
||||
# int sys_connect(int fd, struct sockaddr *uservaddr, int addrlen)
|
||||
fd = args[0]
|
||||
uservaddr = args[1]
|
||||
addrlen = args[2]
|
||||
|
||||
sock_addr = uc.mem_read(uservaddr, addrlen)
|
||||
sock_addr = uc.mem_read(uservaddr, addrlen)
|
||||
msg = "fd(%d) connect to %s" % (fd, parse_sock_address(sock_addr))
|
||||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
elif call == 4: # sys_listen
|
||||
elif call == 4: # sys_listen
|
||||
fd = args[0]
|
||||
backlog = args[1]
|
||||
|
||||
|
@ -303,7 +312,7 @@ def hook_intr(uc, intno, user_data):
|
|||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
elif call == 5: # sys_accept
|
||||
elif call == 5: # sys_accept
|
||||
fd = args[0]
|
||||
upeer_sockaddr = args[1]
|
||||
upeer_addrlen = args[2]
|
||||
|
@ -321,7 +330,7 @@ def hook_intr(uc, intno, user_data):
|
|||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
elif call == 9: # sys_send
|
||||
elif call == 9: # sys_send
|
||||
fd = args[0]
|
||||
buff = args[1]
|
||||
length = args[2]
|
||||
|
@ -332,7 +341,7 @@ def hook_intr(uc, intno, user_data):
|
|||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
elif call == 11: # sys_receive
|
||||
elif call == 11: # sys_receive
|
||||
fd = args[0]
|
||||
ubuf = args[1]
|
||||
size = args[2]
|
||||
|
@ -342,7 +351,7 @@ def hook_intr(uc, intno, user_data):
|
|||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
elif call == 13: # sys_shutdown
|
||||
elif call == 13: # sys_shutdown
|
||||
fd = args[0]
|
||||
how = args[1]
|
||||
|
||||
|
@ -350,8 +359,11 @@ def hook_intr(uc, intno, user_data):
|
|||
fd_chains.add_log(fd, msg)
|
||||
print_sockcall(msg)
|
||||
|
||||
|
||||
# Test X86 32 bit
|
||||
def test_i386(code):
|
||||
global fd_chains
|
||||
|
||||
fd_chains.clean()
|
||||
print("Emulate i386 code")
|
||||
try:
|
||||
|
@ -366,7 +378,7 @@ def test_i386(code):
|
|||
|
||||
# initialize stack
|
||||
mu.reg_write(UC_X86_REG_ESP, ADDRESS + 0x200000)
|
||||
|
||||
|
||||
# tracing all instructions with customized callback
|
||||
# mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
|
@ -384,9 +396,13 @@ def test_i386(code):
|
|||
|
||||
fd_chains.print_report()
|
||||
|
||||
|
||||
# Globals
|
||||
fd_chains = LogChain()
|
||||
id_gen = IdGenerator()
|
||||
|
||||
if __name__ == '__main__':
|
||||
test_i386(X86_SEND_ETCPASSWD)
|
||||
test_i386(X86_SEND_ETCPASSWD)
|
||||
test_i386(X86_BIND_TCP)
|
||||
test_i386(X86_REVERSE_TCP)
|
||||
test_i386(X86_REVERSE_TCP_2)
|
||||
|
||||
|
|
|
@ -28,7 +28,7 @@ def test_sparc():
|
|||
print("Emulate SPARC code")
|
||||
try:
|
||||
# Initialize emulator in SPARC EB mode
|
||||
mu = Uc(UC_ARCH_SPARC, UC_MODE_32)
|
||||
mu = Uc(UC_ARCH_SPARC, UC_MODE_SPARC32|UC_MODE_BIG_ENDIAN)
|
||||
|
||||
# map 2MB memory for this emulation
|
||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||
|
|
|
@ -291,8 +291,8 @@ def test_i386_inout():
|
|||
mu.hook_add(UC_HOOK_CODE, hook_code)
|
||||
|
||||
# handle IN & OUT instruction
|
||||
mu.hook_add(UC_HOOK_INSN, hook_in, None, UC_X86_INS_IN)
|
||||
mu.hook_add(UC_HOOK_INSN, hook_out, None, UC_X86_INS_OUT)
|
||||
mu.hook_add(UC_HOOK_INSN, hook_in, None, 1, 0, UC_X86_INS_IN)
|
||||
mu.hook_add(UC_HOOK_INSN, hook_out, None, 1, 0, UC_X86_INS_OUT)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_INOUT))
|
||||
|
@ -417,7 +417,7 @@ def test_x86_64_syscall():
|
|||
print('ERROR: was not expecting rax=%d in syscall' % rax)
|
||||
|
||||
# hook interrupts for syscall
|
||||
mu.hook_add(UC_HOOK_INSN, hook_syscall, None, UC_X86_INS_SYSCALL)
|
||||
mu.hook_add(UC_HOOK_INSN, hook_syscall, None, 1, 0, UC_X86_INS_SYSCALL)
|
||||
|
||||
# syscall handler is expecting rax=0x100
|
||||
mu.reg_write(UC_X86_REG_RAX, 0x100)
|
||||
|
|
|
@ -24,7 +24,7 @@ PKG_NAME = 'unicorn'
|
|||
if os.path.exists(PATH_LIB64) and os.path.exists(PATH_LIB32):
|
||||
PKG_NAME = 'unicorn-windows'
|
||||
|
||||
VERSION = '0.9'
|
||||
VERSION = '1.0'
|
||||
SYSTEM = sys.platform
|
||||
|
||||
# virtualenv breaks import, but get_python_lib() will work.
|
||||
|
@ -63,7 +63,7 @@ def copy_sources():
|
|||
|
||||
src.extend(glob.glob("../../Makefile"))
|
||||
src.extend(glob.glob("../../LICENSE*"))
|
||||
src.extend(glob.glob("../../README"))
|
||||
src.extend(glob.glob("../../README.md"))
|
||||
src.extend(glob.glob("../../*.TXT"))
|
||||
src.extend(glob.glob("../../RELEASE_NOTES"))
|
||||
src.extend(glob.glob("../../make.sh"))
|
||||
|
|
|
@ -97,7 +97,7 @@ def test_i386(mode, code):
|
|||
mu.hook_add(UC_HOOK_INTR, hook_intr)
|
||||
|
||||
# handle SYSCALL
|
||||
mu.hook_add(UC_HOOK_INSN, hook_syscall, None, UC_X86_INS_SYSCALL)
|
||||
mu.hook_add(UC_HOOK_INSN, hook_syscall, None, 1, 0, UC_X86_INS_SYSCALL)
|
||||
|
||||
# emulate machine code in infinite time
|
||||
mu.emu_start(ADDRESS, ADDRESS + len(code))
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
# Unicorn Python bindings, by Nguyen Anh Quynnh <aquynh@gmail.com>
|
||||
from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const
|
||||
from .unicorn_const import *
|
||||
from .unicorn import Uc, uc_version, uc_arch_supported, version_bind, debug, UcError
|
||||
from .unicorn import Uc, uc_version, uc_arch_supported, version_bind, debug, UcError, __version__
|
||||
|
|
|
@ -81,6 +81,8 @@ if _found == False:
|
|||
raise ImportError("ERROR: fail to load the dynamic library.")
|
||||
|
||||
|
||||
__version__ = "%s.%s" %(UC_API_MAJOR, UC_API_MINOR)
|
||||
|
||||
# setup all the function prototype
|
||||
def _setup_prototype(lib, fname, restype, *argtypes):
|
||||
getattr(lib, fname).restype = restype
|
||||
|
@ -107,6 +109,7 @@ _setup_prototype(_uc, "uc_mem_map", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_
|
|||
_setup_prototype(_uc, "uc_mem_map_ptr", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_uint32, ctypes.c_void_p)
|
||||
_setup_prototype(_uc, "uc_mem_unmap", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_size_t)
|
||||
_setup_prototype(_uc, "uc_mem_protect", ucerr, uc_engine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_uint32)
|
||||
_setup_prototype(_uc, "uc_query", ucerr, uc_engine, ctypes.c_uint32, ctypes.POINTER(ctypes.c_size_t))
|
||||
|
||||
# uc_hook_add is special due to variable number of arguments
|
||||
_uc.uc_hook_add = getattr(_uc, "uc_hook_add")
|
||||
|
@ -153,6 +156,24 @@ def uc_arch_supported(query):
|
|||
return _uc.uc_arch_supported(query)
|
||||
|
||||
|
||||
class uc_x86_mmr(ctypes.Structure):
|
||||
'''Memory-Management Register for instructions IDTR, GDTR, LDTR, TR.'''
|
||||
_fields_ = [
|
||||
("selector", ctypes.c_uint16), # not used by GDTR and IDTR
|
||||
("base", ctypes.c_uint64), # handle 32 or 64 bit CPUs
|
||||
("limit", ctypes.c_uint32),
|
||||
("flags", ctypes.c_uint32), # not used by GDTR and IDTR
|
||||
]
|
||||
|
||||
|
||||
class uc_x86_float80(ctypes.Structure):
|
||||
'''Float80'''
|
||||
_fields_ = [
|
||||
("mantissa", ctypes.c_uint64),
|
||||
("exponent", ctypes.c_uint16),
|
||||
]
|
||||
|
||||
|
||||
class Uc(object):
|
||||
def __init__(self, arch, mode):
|
||||
# verify version compatibility with the core before doing anything
|
||||
|
@ -202,6 +223,20 @@ class Uc(object):
|
|||
|
||||
# return the value of a register
|
||||
def reg_read(self, reg_id):
|
||||
if self._arch == UC_ARCH_X86:
|
||||
if reg_id in [ x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]:
|
||||
reg = uc_x86_mmr()
|
||||
status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg))
|
||||
if status != UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return (reg.selector,reg.base, reg.limits, reg.flags)
|
||||
if reg_id in range(x86_const.UC_X86_REG_FP0,x86_const.UC_X86_REG_FP0+8):
|
||||
reg = uc_x86_float80()
|
||||
status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg))
|
||||
if status != UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return (reg.mantissa, reg.exponent)
|
||||
|
||||
# read to 64bit number to be safe
|
||||
reg = ctypes.c_int64(0)
|
||||
status = _uc.uc_reg_read(self._uch, reg_id, ctypes.byref(reg))
|
||||
|
@ -212,8 +247,25 @@ class Uc(object):
|
|||
|
||||
# write to a register
|
||||
def reg_write(self, reg_id, value):
|
||||
# convert to 64bit number to be safe
|
||||
reg = ctypes.c_int64(value)
|
||||
reg = None
|
||||
|
||||
if self._arch == UC_ARCH_X86:
|
||||
if reg_id in [ x86_const.UC_X86_REG_IDTR, x86_const.UC_X86_REG_GDTR, x86_const.UC_X86_REG_LDTR, x86_const.UC_X86_REG_TR]:
|
||||
assert isinstance(value, tuple) and len(value)==4
|
||||
reg = uc_x86_mmr()
|
||||
reg.selector=value[0]
|
||||
reg.base=value[1]
|
||||
reg.limits=value[2]
|
||||
reg.flags=value[3]
|
||||
if reg_id in range(x86_const.UC_X86_REG_FP0, x86_const.UC_X86_REG_FP0+8):
|
||||
reg = uc_x86_float80()
|
||||
reg.mantissa = value[0]
|
||||
reg.exponent = value[1]
|
||||
|
||||
if reg is None:
|
||||
# convert to 64bit number to be safe
|
||||
reg = ctypes.c_int64(value)
|
||||
|
||||
status = _uc.uc_reg_write(self._uch, reg_id, ctypes.byref(reg))
|
||||
if status != UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
|
@ -262,6 +314,14 @@ class Uc(object):
|
|||
if status != UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
|
||||
# return CPU mode at runtime
|
||||
def query(self, query_mode):
|
||||
result = ctypes.c_size_t(0)
|
||||
status = _uc.uc_query(self._uch, query_mode, ctypes.byref(result))
|
||||
if status != UC_ERR_OK:
|
||||
raise UcError(status)
|
||||
return result.value
|
||||
|
||||
|
||||
def _hookcode_cb(self, handle, address, size, user_data):
|
||||
# call user's callback with self object
|
||||
|
@ -306,7 +366,7 @@ class Uc(object):
|
|||
|
||||
|
||||
# add a hook
|
||||
def hook_add(self, htype, callback, user_data=None, arg1=1, arg2=0):
|
||||
def hook_add(self, htype, callback, user_data=None, begin=1, end=0, arg1=0):
|
||||
_h2 = uc_hook_h()
|
||||
|
||||
# save callback & user_data
|
||||
|
@ -314,25 +374,7 @@ class Uc(object):
|
|||
self._callbacks[self._callback_count] = (callback, user_data)
|
||||
cb = None
|
||||
|
||||
if htype in (UC_HOOK_BLOCK, UC_HOOK_CODE):
|
||||
begin = ctypes.c_uint64(arg1)
|
||||
end = ctypes.c_uint64(arg2)
|
||||
# set callback with wrapper, so it can be called
|
||||
# with this object as param
|
||||
cb = ctypes.cast(UC_HOOK_CODE_CB(self._hookcode_cb), UC_HOOK_CODE_CB)
|
||||
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, cb, \
|
||||
ctypes.cast(self._callback_count, ctypes.c_void_p), begin, end)
|
||||
elif htype & UC_HOOK_MEM_READ_UNMAPPED or htype & UC_HOOK_MEM_WRITE_UNMAPPED or \
|
||||
htype & UC_HOOK_MEM_FETCH_UNMAPPED or htype & UC_HOOK_MEM_READ_PROT or \
|
||||
htype & UC_HOOK_MEM_WRITE_PROT or htype & UC_HOOK_MEM_FETCH_PROT:
|
||||
cb = ctypes.cast(UC_HOOK_MEM_INVALID_CB(self._hook_mem_invalid_cb), UC_HOOK_MEM_INVALID_CB)
|
||||
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
|
||||
cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
|
||||
elif htype in (UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE, UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE):
|
||||
cb = ctypes.cast(UC_HOOK_MEM_ACCESS_CB(self._hook_mem_access_cb), UC_HOOK_MEM_ACCESS_CB)
|
||||
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
|
||||
cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
|
||||
elif htype == UC_HOOK_INSN:
|
||||
if htype == UC_HOOK_INSN:
|
||||
insn = ctypes.c_int(arg1)
|
||||
if arg1 == x86_const.UC_X86_INS_IN: # IN instruction
|
||||
cb = ctypes.cast(UC_HOOK_INSN_IN_CB(self._hook_insn_in_cb), UC_HOOK_INSN_IN_CB)
|
||||
|
@ -341,11 +383,28 @@ class Uc(object):
|
|||
if arg1 in (x86_const.UC_X86_INS_SYSCALL, x86_const.UC_X86_INS_SYSENTER): # SYSCALL/SYSENTER instruction
|
||||
cb = ctypes.cast(UC_HOOK_INSN_SYSCALL_CB(self._hook_insn_syscall_cb), UC_HOOK_INSN_SYSCALL_CB)
|
||||
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
|
||||
cb, ctypes.cast(self._callback_count, ctypes.c_void_p), insn)
|
||||
cb, ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end), insn)
|
||||
elif htype == UC_HOOK_INTR:
|
||||
cb = ctypes.cast(UC_HOOK_INTR_CB(self._hook_intr_cb), UC_HOOK_INTR_CB)
|
||||
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
|
||||
cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
|
||||
cb, ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end))
|
||||
else:
|
||||
if htype in (UC_HOOK_BLOCK, UC_HOOK_CODE):
|
||||
# set callback with wrapper, so it can be called
|
||||
# with this object as param
|
||||
cb = ctypes.cast(UC_HOOK_CODE_CB(self._hookcode_cb), UC_HOOK_CODE_CB)
|
||||
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, cb, \
|
||||
ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end))
|
||||
elif htype & UC_HOOK_MEM_READ_UNMAPPED or htype & UC_HOOK_MEM_WRITE_UNMAPPED or \
|
||||
htype & UC_HOOK_MEM_FETCH_UNMAPPED or htype & UC_HOOK_MEM_READ_PROT or \
|
||||
htype & UC_HOOK_MEM_WRITE_PROT or htype & UC_HOOK_MEM_FETCH_PROT:
|
||||
cb = ctypes.cast(UC_HOOK_MEM_INVALID_CB(self._hook_mem_invalid_cb), UC_HOOK_MEM_INVALID_CB)
|
||||
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
|
||||
cb, ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end))
|
||||
else:
|
||||
cb = ctypes.cast(UC_HOOK_MEM_ACCESS_CB(self._hook_mem_access_cb), UC_HOOK_MEM_ACCESS_CB)
|
||||
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
|
||||
cb, ctypes.cast(self._callback_count, ctypes.c_void_p), ctypes.c_uint64(begin), ctypes.c_uint64(end))
|
||||
|
||||
# save the ctype function so gc will leave it alone.
|
||||
self._ctype_cbs[self._callback_count] = cb
|
||||
|
@ -380,3 +439,4 @@ def debug():
|
|||
(major, minor, _combined) = uc_version()
|
||||
|
||||
return "python-%s-c%u.%u-b%u.%u" % (all_archs, major, minor, UC_API_MAJOR, UC_API_MINOR)
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [unicorn_const.py]
|
||||
UC_API_MAJOR = 1
|
||||
|
||||
UC_API_MAJOR = 0
|
||||
UC_API_MINOR = 9
|
||||
UC_API_MINOR = 0
|
||||
UC_SECOND_SCALE = 1000000
|
||||
UC_MILISECOND_SCALE = 1000
|
||||
UC_ARCH_ARM = 1
|
||||
|
@ -14,22 +14,26 @@ UC_ARCH_M68K = 7
|
|||
UC_ARCH_MAX = 8
|
||||
|
||||
UC_MODE_LITTLE_ENDIAN = 0
|
||||
UC_MODE_BIG_ENDIAN = 1073741824
|
||||
|
||||
UC_MODE_ARM = 0
|
||||
UC_MODE_16 = 2
|
||||
UC_MODE_32 = 4
|
||||
UC_MODE_64 = 8
|
||||
UC_MODE_THUMB = 16
|
||||
UC_MODE_MCLASS = 32
|
||||
UC_MODE_V8 = 64
|
||||
UC_MODE_MICRO = 16
|
||||
UC_MODE_MIPS3 = 32
|
||||
UC_MODE_MIPS32R6 = 64
|
||||
UC_MODE_V9 = 16
|
||||
UC_MODE_QPX = 16
|
||||
UC_MODE_BIG_ENDIAN = 1073741824
|
||||
UC_MODE_MIPS32 = 4
|
||||
UC_MODE_MIPS64 = 8
|
||||
UC_MODE_16 = 2
|
||||
UC_MODE_32 = 4
|
||||
UC_MODE_64 = 8
|
||||
UC_MODE_PPC32 = 4
|
||||
UC_MODE_PPC64 = 8
|
||||
UC_MODE_QPX = 16
|
||||
UC_MODE_SPARC32 = 4
|
||||
UC_MODE_SPARC64 = 8
|
||||
UC_MODE_V9 = 16
|
||||
|
||||
UC_ERR_OK = 0
|
||||
UC_ERR_NOMEM = 1
|
||||
|
@ -80,6 +84,9 @@ UC_HOOK_MEM_READ_INVALID = 144
|
|||
UC_HOOK_MEM_WRITE_INVALID = 288
|
||||
UC_HOOK_MEM_FETCH_INVALID = 576
|
||||
UC_HOOK_MEM_INVALID = 1008
|
||||
UC_HOOK_MEM_VALID = 7168
|
||||
UC_QUERY_MODE = 1
|
||||
UC_QUERY_PAGE_SIZE = 2
|
||||
|
||||
UC_PROT_NONE = 0
|
||||
UC_PROT_READ = 1
|
||||
|
|
|
@ -244,7 +244,13 @@ UC_X86_REG_R12W = 238
|
|||
UC_X86_REG_R13W = 239
|
||||
UC_X86_REG_R14W = 240
|
||||
UC_X86_REG_R15W = 241
|
||||
UC_X86_REG_ENDING = 242
|
||||
UC_X86_REG_IDTR = 242
|
||||
UC_X86_REG_GDTR = 243
|
||||
UC_X86_REG_LDTR = 244
|
||||
UC_X86_REG_TR = 245
|
||||
UC_X86_REG_FPCW = 246
|
||||
UC_X86_REG_FPTAG = 247
|
||||
UC_X86_REG_ENDING = 248
|
||||
|
||||
# X86 instructions
|
||||
|
||||
|
|
279
hook.c
279
hook.c
|
@ -1,279 +0,0 @@
|
|||
/* Unicorn Emulator Engine */
|
||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
||||
|
||||
#include "uc_priv.h"
|
||||
#include "hook.h"
|
||||
|
||||
|
||||
// return index for a new hook entry in hook_callbacks[] array.
|
||||
// this realloc memory if needed.
|
||||
size_t hook_find_new(struct uc_struct *uc)
|
||||
{
|
||||
size_t i;
|
||||
struct hook_struct *new;
|
||||
|
||||
// find the first free slot. skip slot 0, so index > 0
|
||||
for(i = 1; i < uc->hook_size; i++) {
|
||||
if (uc->hook_callbacks[i].callback == NULL) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
// not found, so the array is full.
|
||||
// we have to realloc hook_callbacks[] to contain new hooks
|
||||
new = realloc(uc->hook_callbacks,
|
||||
(uc->hook_size + HOOK_SIZE) * sizeof(uc->hook_callbacks[0]));
|
||||
if (!new) // OOM ?
|
||||
return 0;
|
||||
|
||||
// reset the newly added slots
|
||||
memset(new + uc->hook_size, 0, HOOK_SIZE * sizeof(uc->hook_callbacks[0]));
|
||||
|
||||
uc->hook_callbacks = new;
|
||||
uc->hook_size += HOOK_SIZE;
|
||||
|
||||
// return the first newly allocated slot
|
||||
return uc->hook_size - HOOK_SIZE;
|
||||
}
|
||||
|
||||
// return -1 on failure, index to hook_callbacks[] on success.
|
||||
size_t hook_add(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, void *callback, void *user_data)
|
||||
{
|
||||
int i;
|
||||
|
||||
// find the first free slot. skip slot 0, so index > 0
|
||||
i = hook_find_new(uc);
|
||||
if (i) {
|
||||
uc->hook_callbacks[i].hook_type = type;
|
||||
uc->hook_callbacks[i].begin = begin;
|
||||
uc->hook_callbacks[i].end = end;
|
||||
uc->hook_callbacks[i].callback = callback;
|
||||
uc->hook_callbacks[i].user_data = user_data;
|
||||
|
||||
switch(type) {
|
||||
default: break;
|
||||
case UC_HOOK_BLOCK:
|
||||
uc->hook_block = true;
|
||||
if (begin > end)
|
||||
uc->hook_block_idx = i;
|
||||
break;
|
||||
case UC_HOOK_CODE:
|
||||
uc->hook_insn = true;
|
||||
if (begin > end)
|
||||
uc->hook_insn_idx = i;
|
||||
break;
|
||||
case UC_HOOK_MEM_READ:
|
||||
uc->hook_mem_read = true;
|
||||
if (begin > end)
|
||||
uc->hook_read_idx = i;
|
||||
break;
|
||||
case UC_HOOK_MEM_WRITE:
|
||||
uc->hook_mem_write = true;
|
||||
if (begin > end)
|
||||
uc->hook_write_idx = i;
|
||||
break;
|
||||
case UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE:
|
||||
uc->hook_mem_read = true;
|
||||
uc->hook_mem_write = true;
|
||||
if (begin > end) {
|
||||
uc->hook_read_idx = i;
|
||||
uc->hook_write_idx = i;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
// not found
|
||||
return 0;
|
||||
}
|
||||
|
||||
// return 0 on success, -1 on failure
|
||||
uc_err hook_del(struct uc_struct *uc, uc_hook hh)
|
||||
{
|
||||
if (hh == uc->hook_block_idx) {
|
||||
uc->hook_block_idx = 0;
|
||||
}
|
||||
|
||||
if (hh == uc->hook_insn_idx) {
|
||||
uc->hook_insn_idx = 0;
|
||||
}
|
||||
|
||||
if (hh == uc->hook_read_idx) {
|
||||
uc->hook_read_idx = 0;
|
||||
}
|
||||
|
||||
if (hh == uc->hook_write_idx) {
|
||||
uc->hook_write_idx = 0;
|
||||
}
|
||||
|
||||
if (hh == uc->hook_mem_read_idx) {
|
||||
uc->hook_mem_read_idx = 0;
|
||||
}
|
||||
|
||||
if (hh == uc->hook_mem_write_idx) {
|
||||
uc->hook_mem_write_idx = 0;
|
||||
}
|
||||
|
||||
if (hh == uc->hook_mem_fetch_idx) {
|
||||
uc->hook_mem_fetch_idx = 0;
|
||||
}
|
||||
|
||||
if (hh == uc->hook_mem_read_prot_idx) {
|
||||
uc->hook_mem_read_prot_idx = 0;
|
||||
}
|
||||
|
||||
if (hh == uc->hook_mem_write_prot_idx) {
|
||||
uc->hook_mem_write_prot_idx = 0;
|
||||
}
|
||||
|
||||
if (hh == uc->hook_mem_fetch_prot_idx) {
|
||||
uc->hook_mem_fetch_prot_idx = 0;
|
||||
}
|
||||
|
||||
if (hh == uc->hook_intr_idx) {
|
||||
uc->hook_intr_idx = 0;
|
||||
}
|
||||
|
||||
if (hh == uc->hook_out_idx) {
|
||||
uc->hook_out_idx = 0;
|
||||
}
|
||||
|
||||
if (hh == uc->hook_in_idx) {
|
||||
uc->hook_in_idx = 0;
|
||||
}
|
||||
|
||||
if(hh == uc->hook_syscall_idx) {
|
||||
uc->hook_syscall_idx = 0;
|
||||
}
|
||||
|
||||
uc->hook_callbacks[hh].callback = NULL;
|
||||
uc->hook_callbacks[hh].user_data = NULL;
|
||||
uc->hook_callbacks[hh].hook_type = 0;
|
||||
uc->hook_callbacks[hh].begin = 0;
|
||||
uc->hook_callbacks[hh].end = 0;
|
||||
|
||||
return UC_ERR_OK;
|
||||
}
|
||||
|
||||
// return NULL on failure
|
||||
static struct hook_struct *_hook_find(struct uc_struct *uc, int type, uint64_t address)
|
||||
{
|
||||
int i;
|
||||
|
||||
switch(type) {
|
||||
default: break;
|
||||
case UC_HOOK_BLOCK:
|
||||
// already hooked all blocks?
|
||||
if (uc->hook_block_idx)
|
||||
return &uc->hook_callbacks[uc->hook_block_idx];
|
||||
break;
|
||||
case UC_HOOK_CODE:
|
||||
// already hooked all the code?
|
||||
if (uc->hook_insn_idx)
|
||||
return &uc->hook_callbacks[uc->hook_insn_idx];
|
||||
break;
|
||||
case UC_HOOK_MEM_READ:
|
||||
// already hooked all memory read?
|
||||
if (uc->hook_read_idx) {
|
||||
return &uc->hook_callbacks[uc->hook_read_idx];
|
||||
}
|
||||
break;
|
||||
case UC_HOOK_MEM_WRITE:
|
||||
// already hooked all memory write?
|
||||
if (uc->hook_write_idx)
|
||||
return &uc->hook_callbacks[uc->hook_write_idx];
|
||||
break;
|
||||
}
|
||||
|
||||
// no trace-all callback
|
||||
for(i = 1; i < uc->hook_size; i++) {
|
||||
switch(type) {
|
||||
default: break;
|
||||
case UC_HOOK_BLOCK:
|
||||
case UC_HOOK_CODE:
|
||||
if (uc->hook_callbacks[i].hook_type == type) {
|
||||
if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end)
|
||||
return &uc->hook_callbacks[i];
|
||||
}
|
||||
break;
|
||||
case UC_HOOK_MEM_READ:
|
||||
if (uc->hook_callbacks[i].hook_type & UC_HOOK_MEM_READ) {
|
||||
if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end)
|
||||
return &uc->hook_callbacks[i];
|
||||
}
|
||||
break;
|
||||
case UC_HOOK_MEM_WRITE:
|
||||
if (uc->hook_callbacks[i].hook_type & UC_HOOK_MEM_WRITE) {
|
||||
if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end)
|
||||
return &uc->hook_callbacks[i];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// not found
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
static void hook_count_cb(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data)
|
||||
{
|
||||
// count this instruction
|
||||
uc->emu_counter++;
|
||||
|
||||
if (uc->emu_counter > uc->emu_count)
|
||||
uc_emu_stop(uc);
|
||||
else if (uc->hook_count_callback)
|
||||
uc->hook_count_callback(uc, address, size, user_data);
|
||||
}
|
||||
|
||||
struct hook_struct *hook_find(struct uc_struct *uc, int type, uint64_t address)
|
||||
{
|
||||
// stop executing callbacks if we already got stop request
|
||||
if (uc->stop_request)
|
||||
return NULL;
|
||||
|
||||
// UC_HOOK_CODE is special because we may need to count instructions
|
||||
if (type == UC_HOOK_CODE && uc->emu_count > 0) {
|
||||
struct hook_struct *st = _hook_find(uc, type, address);
|
||||
if (st) {
|
||||
// prepare this struct to pass back to caller
|
||||
uc->hook_count.hook_type = UC_HOOK_CODE;
|
||||
uc->hook_count.begin = st->begin;
|
||||
uc->hook_count.end = st->end;
|
||||
uc->hook_count.callback = hook_count_cb;
|
||||
uc->hook_count.user_data = st->user_data;
|
||||
// save this hook callback so we can call it later
|
||||
uc->hook_count_callback = st->callback;
|
||||
} else {
|
||||
// there is no callback, but we still need to
|
||||
// handle instruction count
|
||||
uc->hook_count.hook_type = UC_HOOK_CODE;
|
||||
uc->hook_count.begin = 1;
|
||||
uc->hook_count.end = 0;
|
||||
uc->hook_count.callback = hook_count_cb;
|
||||
uc->hook_count.user_data = NULL;
|
||||
uc->hook_count_callback = NULL; // no callback
|
||||
}
|
||||
|
||||
return &(uc->hook_count);
|
||||
} else
|
||||
return _hook_find(uc, type, address);
|
||||
}
|
||||
|
||||
|
||||
// TCG helper
|
||||
void helper_uc_tracecode(int32_t size, void *callback, void *handle, int64_t address, void *user_data);
|
||||
void helper_uc_tracecode(int32_t size, void *callback, void *handle, int64_t address, void *user_data)
|
||||
{
|
||||
struct uc_struct *uc = handle;
|
||||
|
||||
// sync PC in CPUArchState with address
|
||||
if (uc->set_pc) {
|
||||
uc->set_pc(uc, address);
|
||||
}
|
||||
|
||||
((uc_cb_hookcode_t)callback)(uc, address, size, user_data);
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
/* Unicorn Emulator Engine */
|
||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
||||
|
||||
#ifndef UC_HOOK_H
|
||||
#define UC_HOOK_H
|
||||
|
||||
// return -1 on failure, index to traces[] on success.
|
||||
size_t hook_add(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, void *callback, void *user_data);
|
||||
|
||||
// return 0 on success, -1 on failure
|
||||
uc_err hook_del(struct uc_struct *uc, uc_hook hh);
|
||||
|
||||
// return NULL on failure
|
||||
struct hook_struct *hook_find(struct uc_struct *uc, int type, uint64_t address);
|
||||
|
||||
// return index of an free hook entry in hook_callbacks[] array.
|
||||
// this realloc memory if needed.
|
||||
size_t hook_find_new(struct uc_struct *uc);
|
||||
|
||||
#endif
|
20
include/list.h
Normal file
20
include/list.h
Normal file
|
@ -0,0 +1,20 @@
|
|||
#ifndef UC_LLIST_H
|
||||
#define UC_LLIST_H
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct list_item {
|
||||
struct list_item *next;
|
||||
void *data;
|
||||
};
|
||||
|
||||
struct list {
|
||||
struct list_item *head, *tail;
|
||||
};
|
||||
|
||||
struct list *list_new(void);
|
||||
void list_clear(struct list *list);
|
||||
void *list_append(struct list *list, void *data);
|
||||
bool list_remove(struct list *list, void *data);
|
||||
|
||||
#endif
|
|
@ -9,10 +9,30 @@
|
|||
|
||||
#include "qemu.h"
|
||||
#include "unicorn/unicorn.h"
|
||||
#include "hook.h"
|
||||
#include "list.h"
|
||||
|
||||
// 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)
|
||||
#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_PPC64|UC_MODE_BIG_ENDIAN)
|
||||
#define UC_MODE_SPARC_MASK (UC_MODE_SPARC32|UC_MODE_SPARC64|UC_MODE_BIG_ENDIAN)
|
||||
#define UC_MODE_M68K_MASK (UC_MODE_BIG_ENDIAN)
|
||||
|
||||
#define ARR_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||
|
||||
#define READ_QWORD(x) ((uint64)x)
|
||||
#define READ_DWORD(x) (x & 0xffffffff)
|
||||
#define READ_WORD(x) (x & 0xffff)
|
||||
#define READ_BYTE_H(x) ((x & 0xffff) >> 8)
|
||||
#define READ_BYTE_L(x) (x & 0xff)
|
||||
#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff))
|
||||
#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff))
|
||||
#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | ((b & 0xff) << 8))
|
||||
#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff))
|
||||
|
||||
|
||||
QTAILQ_HEAD(CPUTailQ, CPUState);
|
||||
|
||||
typedef struct ModuleEntry {
|
||||
|
@ -23,6 +43,8 @@ typedef struct ModuleEntry {
|
|||
|
||||
typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
|
||||
|
||||
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 regid, void *value);
|
||||
typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int regid, const void *value);
|
||||
|
@ -60,16 +82,62 @@ typedef bool (*uc_args_int_t)(int intno);
|
|||
// some architecture redirect virtual memory to physical memory like Mips
|
||||
typedef uint64_t (*uc_mem_redirect_t)(uint64_t address);
|
||||
|
||||
|
||||
struct hook_struct {
|
||||
int hook_type; // uc_tracecode_type & uc_tracemem_type
|
||||
uint64_t begin, end; // range of address to be monitored
|
||||
void *callback; // either uc_cb_tracecode_t or uc_cb_tracemem_t
|
||||
struct hook {
|
||||
int type; // UC_HOOK_*
|
||||
int insn; // instruction for HOOK_INSN
|
||||
int refs; // reference count to free hook stored in multiple lists
|
||||
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;
|
||||
};
|
||||
|
||||
// extend memory to keep 32 more hooks each time
|
||||
#define HOOK_SIZE 32
|
||||
// hook list offsets
|
||||
// mirrors the order of uc_hook_type from include/unicorn/unicorn.h
|
||||
enum uc_hook_idx {
|
||||
UC_HOOK_INTR_IDX,
|
||||
UC_HOOK_INSN_IDX,
|
||||
UC_HOOK_CODE_IDX,
|
||||
UC_HOOK_BLOCK_IDX,
|
||||
UC_HOOK_MEM_READ_UNMAPPED_IDX,
|
||||
UC_HOOK_MEM_WRITE_UNMAPPED_IDX,
|
||||
UC_HOOK_MEM_FETCH_UNMAPPED_IDX,
|
||||
UC_HOOK_MEM_READ_PROT_IDX,
|
||||
UC_HOOK_MEM_WRITE_PROT_IDX,
|
||||
UC_HOOK_MEM_FETCH_PROT_IDX,
|
||||
UC_HOOK_MEM_READ_IDX,
|
||||
UC_HOOK_MEM_WRITE_IDX,
|
||||
UC_HOOK_MEM_FETCH_IDX,
|
||||
|
||||
UC_HOOK_MAX,
|
||||
};
|
||||
|
||||
// for loop macro to loop over hook lists
|
||||
#define HOOK_FOREACH(uc, hh, idx) \
|
||||
struct list_item *cur; \
|
||||
for ( \
|
||||
cur = (uc)->hook[idx##_IDX].head; \
|
||||
cur != NULL && ((hh) = (struct hook *)cur->data) \
|
||||
/* stop excuting callbacks on stop request */ \
|
||||
&& !uc->stop_request; \
|
||||
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))
|
||||
|
||||
#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)
|
||||
|
||||
static inline bool _hook_exists_bounded(struct list_item *cur, uint64_t addr)
|
||||
{
|
||||
while (cur != NULL) {
|
||||
if (HOOK_BOUND_CHECK((struct hook *)cur->data, addr))
|
||||
return true;
|
||||
cur = cur->next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//relloc increment, KEEP THIS A POWER OF 2!
|
||||
#define MEM_BLOCK_INCR 32
|
||||
|
@ -84,6 +152,7 @@ struct uc_struct {
|
|||
struct CPUTailQ cpus; // qemu/cpu-exec.c
|
||||
uc_err errnum; // qemu/cpu-exec.c
|
||||
AddressSpace as;
|
||||
query_t query;
|
||||
reg_read_t reg_read;
|
||||
reg_write_t reg_write;
|
||||
reg_reset_t reg_reset;
|
||||
|
@ -144,38 +213,20 @@ struct uc_struct {
|
|||
bool apic_report_tpr_access;
|
||||
CPUState *current_cpu;
|
||||
|
||||
// all the hook callbacks
|
||||
size_t hook_size;
|
||||
struct hook_struct *hook_callbacks;
|
||||
// linked lists containing hooks per type
|
||||
struct list hook[UC_HOOK_MAX];
|
||||
|
||||
// hook to count number of instructions for uc_emu_start()
|
||||
struct hook_struct hook_count;
|
||||
uc_cb_hookcode_t hook_count_callback;
|
||||
uc_hook count_hook;
|
||||
|
||||
size_t emu_counter; // current counter of uc_emu_start()
|
||||
size_t emu_count; // save counter of uc_emu_start()
|
||||
|
||||
// indexes if hooking ALL block/code/read/write events
|
||||
unsigned int hook_block_idx, hook_insn_idx, hook_read_idx, hook_write_idx;
|
||||
// boolean variables for quick check on hooking block, code, memory accesses
|
||||
bool hook_block, hook_insn, hook_mem_read, hook_mem_write;
|
||||
uint64_t block_addr; // save the last block address we hooked
|
||||
// indexes to event callbacks
|
||||
int hook_mem_read_idx; // for handling invalid memory read access on unmapped memory
|
||||
int hook_mem_write_idx; // for handling invalid memory write access on unmapped memory
|
||||
int hook_mem_fetch_idx; // for handling invalid memory fetch access on unmapped memory
|
||||
int hook_mem_read_prot_idx; // for handling invalid memory read access on read-protected memory
|
||||
int hook_mem_write_prot_idx; // for handling invalid memory write access on write-protected memory
|
||||
int hook_mem_fetch_prot_idx; // for handling invalid memory fetch access on non-executable memory
|
||||
|
||||
int hook_intr_idx; // for handling interrupt
|
||||
int hook_out_idx; // for handling OUT instruction (X86)
|
||||
int hook_in_idx; // for handling IN instruction (X86)
|
||||
int hook_syscall_idx; // for handling SYSCALL/SYSENTER (X86)
|
||||
|
||||
|
||||
bool init_tcg; // already initialized local TCGv variables?
|
||||
bool stop_request; // request to immediately stop emulation - for uc_emu_stop()
|
||||
bool quit_request; // request to quit the current TB, but continue to emulate - for uc_mem_protect()
|
||||
bool emulation_done; // emulation is done by uc_emu_start()
|
||||
QemuThread timer; // timer for emulation timeout
|
||||
uint64_t timeout; // timeout for uc_emu_start()
|
||||
|
|
|
@ -57,8 +57,8 @@ typedef size_t uc_hook;
|
|||
#endif
|
||||
|
||||
// Unicorn API version
|
||||
#define UC_API_MAJOR 0
|
||||
#define UC_API_MINOR 9
|
||||
#define UC_API_MAJOR 1
|
||||
#define UC_API_MINOR 0
|
||||
|
||||
/*
|
||||
Macro to create combined version which can be compared to
|
||||
|
@ -78,7 +78,7 @@ typedef enum uc_arch {
|
|||
UC_ARCH_ARM64, // ARM-64, also called AArch64
|
||||
UC_ARCH_MIPS, // Mips architecture
|
||||
UC_ARCH_X86, // X86 architecture (including x86 & x86-64)
|
||||
UC_ARCH_PPC, // PowerPC architecture
|
||||
UC_ARCH_PPC, // PowerPC architecture (currently unsupported)
|
||||
UC_ARCH_SPARC, // Sparc architecture
|
||||
UC_ARCH_M68K, // M68K architecture
|
||||
UC_ARCH_MAX,
|
||||
|
@ -86,22 +86,32 @@ typedef enum uc_arch {
|
|||
|
||||
// Mode type
|
||||
typedef enum uc_mode {
|
||||
UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode)
|
||||
UC_MODE_ARM = 0, // 32-bit ARM
|
||||
UC_MODE_16 = 1 << 1, // 16-bit mode (X86)
|
||||
UC_MODE_32 = 1 << 2, // 32-bit mode (X86)
|
||||
UC_MODE_64 = 1 << 3, // 64-bit mode (X86, PPC)
|
||||
UC_MODE_THUMB = 1 << 4, // ARM's Thumb mode, including Thumb-2
|
||||
UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series
|
||||
UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM
|
||||
UC_MODE_MICRO = 1 << 4, // MicroMips mode (MIPS)
|
||||
UC_MODE_MIPS3 = 1 << 5, // Mips III ISA
|
||||
UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA
|
||||
UC_MODE_V9 = 1 << 4, // SparcV9 mode (Sparc)
|
||||
UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (PPC)
|
||||
UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode
|
||||
UC_MODE_MIPS32 = UC_MODE_32, // Mips32 ISA (Mips)
|
||||
UC_MODE_MIPS64 = UC_MODE_64, // Mips64 ISA (Mips)
|
||||
UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode)
|
||||
UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode
|
||||
// arm / arm64
|
||||
UC_MODE_ARM = 0, // ARM mode
|
||||
UC_MODE_THUMB = 1 << 4, // THUMB mode (including Thumb-2)
|
||||
UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series (currently unsupported)
|
||||
UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM (currently unsupported)
|
||||
// mips
|
||||
UC_MODE_MICRO = 1 << 4, // MicroMips mode (currently unsupported)
|
||||
UC_MODE_MIPS3 = 1 << 5, // Mips III ISA (currently unsupported)
|
||||
UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA (currently unsupported)
|
||||
UC_MODE_MIPS32 = 1 << 2, // Mips32 ISA
|
||||
UC_MODE_MIPS64 = 1 << 3, // Mips64 ISA
|
||||
// x86 / x64
|
||||
UC_MODE_16 = 1 << 1, // 16-bit mode
|
||||
UC_MODE_32 = 1 << 2, // 32-bit mode
|
||||
UC_MODE_64 = 1 << 3, // 64-bit mode
|
||||
// ppc
|
||||
UC_MODE_PPC32 = 1 << 2, // 32-bit mode (currently unsupported)
|
||||
UC_MODE_PPC64 = 1 << 3, // 64-bit mode (currently unsupported)
|
||||
UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (currently unsupported)
|
||||
// sparc
|
||||
UC_MODE_SPARC32 = 1 << 2, // 32-bit mode
|
||||
UC_MODE_SPARC64 = 1 << 3, // 64-bit mode
|
||||
UC_MODE_V9 = 1 << 4, // SparcV9 mode (currently unsupported)
|
||||
// m68k
|
||||
} uc_mode;
|
||||
|
||||
// All type of errors encountered by Unicorn API.
|
||||
|
@ -208,6 +218,8 @@ typedef enum uc_hook_type {
|
|||
#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
|
||||
#define UC_HOOK_MEM_VALID (UC_HOOK_MEM_READ + UC_HOOK_MEM_WRITE + UC_HOOK_MEM_FETCH)
|
||||
|
||||
/*
|
||||
Callback function for hooking memory (UC_MEM_READ, UC_MEM_WRITE & UC_MEM_FETCH)
|
||||
|
@ -246,6 +258,13 @@ typedef struct uc_mem_region {
|
|||
uint32_t perms; // memory permissions of the region
|
||||
} uc_mem_region;
|
||||
|
||||
// All type of queries for uc_query() API.
|
||||
typedef enum uc_query_type {
|
||||
// Dynamically query current hardware mode.
|
||||
UC_QUERY_MODE = 1,
|
||||
UC_QUERY_PAGE_SIZE,
|
||||
} uc_query_type;
|
||||
|
||||
/*
|
||||
Return combined API version & major and minor version numbers.
|
||||
|
||||
|
@ -306,6 +325,19 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc);
|
|||
UNICORN_EXPORT
|
||||
uc_err uc_close(uc_engine *uc);
|
||||
|
||||
/*
|
||||
Query internal status of engine.
|
||||
|
||||
@uc: handle returned by uc_open()
|
||||
@type: query type. See uc_query_type
|
||||
|
||||
@result: save the internal status queried
|
||||
|
||||
@return: error code of uc_err enum type (UC_ERR_*, see above)
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result);
|
||||
|
||||
/*
|
||||
Report the last error number when some API function fail.
|
||||
Like glibc's errno, uc_errno might not retain its old value once accessed.
|
||||
|
@ -426,13 +458,19 @@ uc_err uc_emu_stop(uc_engine *uc);
|
|||
@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
|
||||
@...: variable arguments (depending on @type)
|
||||
NOTE: if @type = UC_HOOK_INSN, this is the instruction ID (ex: UC_X86_INS_OUT)
|
||||
|
||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||
for detailed error).
|
||||
*/
|
||||
UNICORN_EXPORT
|
||||
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...);
|
||||
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
|
||||
void *user_data, uint64_t begin, uint64_t end, ...);
|
||||
|
||||
/*
|
||||
Unregister (remove) a hook callback.
|
||||
|
|
|
@ -8,6 +8,15 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
// Memory-Management Register for instructions IDTR, GDTR, LDTR, TR.
|
||||
// Borrow from SegmentCache in qemu/target-i386/cpu.h
|
||||
typedef struct uc_x86_mmr {
|
||||
uint16_t selector; /* not used by GDTR and IDTR */
|
||||
uint64_t base; /* handle 32 or 64 bit CPUs */
|
||||
uint32_t limit;
|
||||
uint32_t flags; /* not used by GDTR and IDTR */
|
||||
} uc_x86_mmr;
|
||||
|
||||
// Callback function for tracing SYSCALL/SYSENTER (for uc_hook_intr())
|
||||
// @user_data: user data passed to tracing APIs.
|
||||
typedef void (*uc_cb_insn_syscall_t)(struct uc_struct *uc, void *user_data);
|
||||
|
@ -64,6 +73,8 @@ typedef enum uc_x86_reg {
|
|||
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_ENDING // <-- mark the end of the list of registers
|
||||
} uc_x86_reg;
|
||||
|
|
68
list.c
Normal file
68
list.c
Normal file
|
@ -0,0 +1,68 @@
|
|||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include "list.h"
|
||||
|
||||
// simple linked list implementation
|
||||
|
||||
struct list *list_new(void)
|
||||
{
|
||||
return calloc(1, sizeof(struct list));
|
||||
}
|
||||
|
||||
// removed linked list nodes but does not free their content
|
||||
void list_clear(struct list *list)
|
||||
{
|
||||
struct list_item *next, *cur = list->head;
|
||||
while (cur != NULL) {
|
||||
next = cur->next;
|
||||
free(cur);
|
||||
cur = next;
|
||||
}
|
||||
list->head = NULL;
|
||||
list->tail = NULL;
|
||||
}
|
||||
|
||||
// returns generated linked list node, or NULL on failure
|
||||
void *list_append(struct list *list, void *data)
|
||||
{
|
||||
struct list_item *item = malloc(sizeof(struct list_item));
|
||||
if (item == NULL) {
|
||||
return NULL;
|
||||
}
|
||||
item->next = NULL;
|
||||
item->data = data;
|
||||
if (list->head == NULL) {
|
||||
list->head = item;
|
||||
} else {
|
||||
list->tail->next = item;
|
||||
}
|
||||
list->tail = item;
|
||||
return item;
|
||||
}
|
||||
|
||||
// returns true if entry was removed, false otherwise
|
||||
bool list_remove(struct list *list, void *data)
|
||||
{
|
||||
struct list_item *next, *cur, *prev = NULL;
|
||||
// is list empty?
|
||||
if (list->head == NULL) {
|
||||
return false;
|
||||
}
|
||||
cur = list->head;
|
||||
while (cur != NULL) {
|
||||
next = cur->next;
|
||||
if (cur->data == data) {
|
||||
if (cur == list->head) {
|
||||
list->head = next;
|
||||
}
|
||||
if (cur == list->tail) {
|
||||
list->tail = prev;
|
||||
}
|
||||
free(cur);
|
||||
return true;
|
||||
}
|
||||
prev = cur;
|
||||
cur = next;
|
||||
}
|
||||
return false;
|
||||
}
|
|
@ -2,8 +2,8 @@
|
|||
# To be used to generate unicorn.pc for pkg-config
|
||||
|
||||
# version major & minor
|
||||
PKG_MAJOR = 0
|
||||
PKG_MINOR = 9
|
||||
PKG_MAJOR = 1
|
||||
PKG_MINOR = 0
|
||||
|
||||
# version bugfix level. Example: PKG_EXTRA = 1
|
||||
PKG_EXTRA =
|
||||
|
|
|
@ -6,7 +6,7 @@ util-obj-y = util/ qobject/ qapi/ qapi-types.o qapi-visit.o
|
|||
# block-obj-y is code used by both qemu system emulation and qemu-img
|
||||
|
||||
block-obj-y =
|
||||
block-obj-y += ../uc.o ../hook.o
|
||||
block-obj-y += ../uc.o ../list.o
|
||||
#block-obj-$(CONFIG_POSIX) += aio-posix.o
|
||||
#block-obj-$(CONFIG_WIN32) += aio-win32.o
|
||||
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||
#ifndef UNICORN_AUTOGEN_AARCH64_H
|
||||
#define UNICORN_AUTOGEN_AARCH64_H
|
||||
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_aarch64
|
||||
#define use_idiv_instructions_rt use_idiv_instructions_rt_aarch64
|
||||
#define tcg_target_deposit_valid tcg_target_deposit_valid_aarch64
|
||||
#define helper_power_down helper_power_down_aarch64
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||
#ifndef UNICORN_AUTOGEN_ARM_H
|
||||
#define UNICORN_AUTOGEN_ARM_H
|
||||
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_arm
|
||||
#define use_idiv_instructions_rt use_idiv_instructions_rt_arm
|
||||
#define tcg_target_deposit_valid tcg_target_deposit_valid_arm
|
||||
#define helper_power_down helper_power_down_arm
|
||||
|
|
|
@ -64,6 +64,8 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq
|
|||
TranslationBlock *tb;
|
||||
uint8_t *tc_ptr;
|
||||
uintptr_t next_tb;
|
||||
struct hook *hook;
|
||||
|
||||
|
||||
/* This must be volatile so it is not trashed by longjmp() */
|
||||
volatile bool have_tb_lock = false;
|
||||
|
@ -99,6 +101,7 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq
|
|||
if (sigsetjmp(cpu->jmp_env, 0) == 0) {
|
||||
if (uc->stop_request || uc->invalid_error)
|
||||
break;
|
||||
|
||||
/* if an exception is pending, we execute it here */
|
||||
if (cpu->exception_index >= 0) {
|
||||
//printf(">>> GOT INTERRUPT. exception idx = %x\n", cpu->exception_index); // qq
|
||||
|
@ -127,11 +130,10 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq
|
|||
ret = cpu->exception_index;
|
||||
break;
|
||||
#else
|
||||
// Unicorn: call interrupt callback if registered
|
||||
if (uc->hook_intr_idx)
|
||||
((uc_cb_hookintr_t)uc->hook_callbacks[uc->hook_intr_idx].callback)(
|
||||
uc, cpu->exception_index,
|
||||
uc->hook_callbacks[uc->hook_intr_idx].user_data);
|
||||
// Unicorn: call registered interrupt callbacks
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_INTR) {
|
||||
((uc_cb_hookintr_t)hook->callback)(uc, cpu->exception_index, hook->user_data);
|
||||
}
|
||||
cpu->exception_index = -1;
|
||||
#if defined(TARGET_X86_64)
|
||||
// point EIP to the next instruction after INT
|
||||
|
@ -234,6 +236,7 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq
|
|||
tc_ptr = tb->tc_ptr;
|
||||
/* execute the generated code */
|
||||
next_tb = cpu_tb_exec(cpu, tc_ptr); // qq
|
||||
|
||||
switch (next_tb & TB_EXIT_MASK) {
|
||||
case TB_EXIT_REQUESTED:
|
||||
/* Something asked us to stop executing
|
||||
|
@ -300,12 +303,13 @@ static tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr)
|
|||
TranslationBlock *tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
|
||||
if (cc->synchronize_from_tb) {
|
||||
// avoid sync twice when helper_uc_tracecode() already did this.
|
||||
if (env->uc->emu_counter <= env->uc->emu_count && !env->uc->stop_request)
|
||||
if (env->uc->emu_counter <= env->uc->emu_count &&
|
||||
!env->uc->stop_request && !env->uc->quit_request)
|
||||
cc->synchronize_from_tb(cpu, tb);
|
||||
} else {
|
||||
assert(cc->set_pc);
|
||||
// avoid sync twice when helper_uc_tracecode() already did this.
|
||||
if (env->uc->emu_counter <= env->uc->emu_count)
|
||||
if (env->uc->emu_counter <= env->uc->emu_count && !env->uc->quit_request)
|
||||
cc->set_pc(cpu, tb->pc);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -231,8 +231,14 @@ static bool tcg_exec_all(struct uc_struct* uc)
|
|||
//qemu_clock_enable(QEMU_CLOCK_VIRTUAL,
|
||||
// (cpu->singlestep_enabled & SSTEP_NOTIMER) == 0);
|
||||
if (cpu_can_run(cpu)) {
|
||||
uc->quit_request = false;
|
||||
r = tcg_cpu_exec(uc, env);
|
||||
if (uc->stop_request) {
|
||||
|
||||
// quit current TB but continue emulating?
|
||||
if (uc->quit_request) {
|
||||
// reset stop_request
|
||||
uc->stop_request = false;
|
||||
} else if (uc->stop_request) {
|
||||
//printf(">>> got STOP request!!!\n");
|
||||
finish = true;
|
||||
break;
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
import sys
|
||||
|
||||
symbols = (
|
||||
'aarch64_tb_set_jmp_target',
|
||||
'use_idiv_instructions_rt',
|
||||
'tcg_target_deposit_valid',
|
||||
'helper_power_down',
|
||||
|
|
|
@ -66,39 +66,45 @@ const MemoryRegionOps unassigned_io_ops = {
|
|||
void cpu_outb(struct uc_struct *uc, pio_addr_t addr, uint8_t val)
|
||||
{
|
||||
//LOG_IOPORT("outb: %04"FMT_pioaddr" %02"PRIx8"\n", addr, val);
|
||||
// Unicorn: call interrupt callback if registered
|
||||
if (uc->hook_out_idx)
|
||||
((uc_cb_insn_out_t)uc->hook_callbacks[uc->hook_out_idx].callback)(
|
||||
uc, addr, 1, val,
|
||||
uc->hook_callbacks[uc->hook_out_idx].user_data);
|
||||
// Unicorn: call registered OUT callbacks
|
||||
struct hook *hook;
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_INSN) {
|
||||
if (hook->insn == UC_X86_INS_OUT)
|
||||
((uc_cb_insn_out_t)hook->callback)(uc, addr, 1, val, hook->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_outw(struct uc_struct *uc, pio_addr_t addr, uint16_t val)
|
||||
{
|
||||
//LOG_IOPORT("outw: %04"FMT_pioaddr" %04"PRIx16"\n", addr, val);
|
||||
// Unicorn: call interrupt callback if registered
|
||||
if (uc->hook_out_idx)
|
||||
((uc_cb_insn_out_t)uc->hook_callbacks[uc->hook_out_idx].callback)(
|
||||
uc, addr, 2, val,
|
||||
uc->hook_callbacks[uc->hook_out_idx].user_data);
|
||||
// Unicorn: call registered OUT callbacks
|
||||
struct hook *hook;
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_INSN) {
|
||||
if (hook->insn == UC_X86_INS_OUT)
|
||||
((uc_cb_insn_out_t)hook->callback)(uc, addr, 2, val, hook->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
void cpu_outl(struct uc_struct *uc, pio_addr_t addr, uint32_t val)
|
||||
{
|
||||
//LOG_IOPORT("outl: %04"FMT_pioaddr" %08"PRIx32"\n", addr, val);
|
||||
if (uc->hook_out_idx)
|
||||
((uc_cb_insn_out_t)uc->hook_callbacks[uc->hook_out_idx].callback)(
|
||||
uc, addr, 4, val,
|
||||
uc->hook_callbacks[uc->hook_out_idx].user_data);
|
||||
// Unicorn: call registered OUT callbacks
|
||||
struct hook *hook;
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_INSN) {
|
||||
if (hook->insn == UC_X86_INS_OUT)
|
||||
((uc_cb_insn_out_t)hook->callback)(uc, addr, 4, val, hook->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t cpu_inb(struct uc_struct *uc, pio_addr_t addr)
|
||||
{
|
||||
//LOG_IOPORT("inb : %04"FMT_pioaddr" %02"PRIx8"\n", addr, val);
|
||||
if (uc->hook_in_idx)
|
||||
return ((uc_cb_insn_in_t)uc->hook_callbacks[uc->hook_in_idx].callback)(
|
||||
uc, addr, 1,
|
||||
uc->hook_callbacks[uc->hook_in_idx].user_data);
|
||||
// Unicorn: call registered IN callbacks
|
||||
struct hook *hook;
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_INSN) {
|
||||
if (hook->insn == UC_X86_INS_IN)
|
||||
return ((uc_cb_insn_in_t)hook->callback)(uc, addr, 1, hook->user_data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -106,10 +112,12 @@ uint8_t cpu_inb(struct uc_struct *uc, pio_addr_t addr)
|
|||
uint16_t cpu_inw(struct uc_struct *uc, pio_addr_t addr)
|
||||
{
|
||||
//LOG_IOPORT("inw : %04"FMT_pioaddr" %04"PRIx16"\n", addr, val);
|
||||
if (uc->hook_in_idx)
|
||||
return ((uc_cb_insn_in_t)uc->hook_callbacks[uc->hook_in_idx].callback)(
|
||||
uc, addr, 2,
|
||||
uc->hook_callbacks[uc->hook_in_idx].user_data);
|
||||
// Unicorn: call registered IN callbacks
|
||||
struct hook *hook;
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_INSN) {
|
||||
if (hook->insn == UC_X86_INS_IN)
|
||||
return ((uc_cb_insn_in_t)hook->callback)(uc, addr, 2, hook->user_data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -117,10 +125,12 @@ uint16_t cpu_inw(struct uc_struct *uc, pio_addr_t addr)
|
|||
uint32_t cpu_inl(struct uc_struct *uc, pio_addr_t addr)
|
||||
{
|
||||
//LOG_IOPORT("inl : %04"FMT_pioaddr" %08"PRIx32"\n", addr, val);
|
||||
if (uc->hook_in_idx)
|
||||
return ((uc_cb_insn_in_t)uc->hook_callbacks[uc->hook_in_idx].callback)(
|
||||
uc, addr, 4,
|
||||
uc->hook_callbacks[uc->hook_in_idx].user_data);
|
||||
// Unicorn: call registered IN callbacks
|
||||
struct hook *hook;
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_INSN) {
|
||||
if (hook->insn == UC_X86_INS_IN)
|
||||
return ((uc_cb_insn_in_t)hook->callback)(uc, addr, 4, hook->user_data);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||
#ifndef UNICORN_AUTOGEN_M68K_H
|
||||
#define UNICORN_AUTOGEN_M68K_H
|
||||
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_m68k
|
||||
#define use_idiv_instructions_rt use_idiv_instructions_rt_m68k
|
||||
#define tcg_target_deposit_valid tcg_target_deposit_valid_m68k
|
||||
#define helper_power_down helper_power_down_m68k
|
||||
|
|
|
@ -85,7 +85,7 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr)
|
|||
if (uc->mapped_blocks[i] == mr) {
|
||||
uc->mapped_block_count--;
|
||||
//shift remainder of array down over deleted pointer
|
||||
memcpy(&uc->mapped_blocks[i], &uc->mapped_blocks[i + 1], sizeof(MemoryRegion*) * (uc->mapped_block_count - i));
|
||||
memmove(&uc->mapped_blocks[i], &uc->mapped_blocks[i + 1], sizeof(MemoryRegion*) * (uc->mapped_block_count - i));
|
||||
mr->destructor(mr);
|
||||
g_free((char *)mr->name);
|
||||
g_free(mr->ioeventfds);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||
#ifndef UNICORN_AUTOGEN_MIPS_H
|
||||
#define UNICORN_AUTOGEN_MIPS_H
|
||||
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_mips
|
||||
#define use_idiv_instructions_rt use_idiv_instructions_rt_mips
|
||||
#define tcg_target_deposit_valid tcg_target_deposit_valid_mips
|
||||
#define helper_power_down helper_power_down_mips
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||
#ifndef UNICORN_AUTOGEN_MIPS64_H
|
||||
#define UNICORN_AUTOGEN_MIPS64_H
|
||||
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_mips64
|
||||
#define use_idiv_instructions_rt use_idiv_instructions_rt_mips64
|
||||
#define tcg_target_deposit_valid tcg_target_deposit_valid_mips64
|
||||
#define helper_power_down helper_power_down_mips64
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||
#ifndef UNICORN_AUTOGEN_MIPS64EL_H
|
||||
#define UNICORN_AUTOGEN_MIPS64EL_H
|
||||
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_mips64el
|
||||
#define use_idiv_instructions_rt use_idiv_instructions_rt_mips64el
|
||||
#define tcg_target_deposit_valid tcg_target_deposit_valid_mips64el
|
||||
#define helper_power_down helper_power_down_mips64el
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||
#ifndef UNICORN_AUTOGEN_MIPSEL_H
|
||||
#define UNICORN_AUTOGEN_MIPSEL_H
|
||||
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_mipsel
|
||||
#define use_idiv_instructions_rt use_idiv_instructions_rt_mipsel
|
||||
#define tcg_target_deposit_valid tcg_target_deposit_valid_mipsel
|
||||
#define helper_power_down helper_power_down_mipsel
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||
#ifndef UNICORN_AUTOGEN_POWERPC_H
|
||||
#define UNICORN_AUTOGEN_POWERPC_H
|
||||
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_powerpc
|
||||
#define use_idiv_instructions_rt use_idiv_instructions_rt_powerpc
|
||||
#define tcg_target_deposit_valid tcg_target_deposit_valid_powerpc
|
||||
#define helper_power_down helper_power_down_powerpc
|
||||
|
|
|
@ -178,23 +178,33 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
|
|||
uintptr_t haddr;
|
||||
DATA_TYPE res;
|
||||
int error_code;
|
||||
struct hook *hook;
|
||||
bool handled;
|
||||
|
||||
struct uc_struct *uc = env->uc;
|
||||
MemoryRegion *mr = memory_mapping(uc, addr);
|
||||
|
||||
// memory might be still unmapped while reading or fetching
|
||||
if (mr == NULL) {
|
||||
handled = false;
|
||||
#if defined(SOFTMMU_CODE_ACCESS)
|
||||
error_code = UC_ERR_FETCH_UNMAPPED;
|
||||
if (uc->hook_mem_fetch_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_idx].callback)(
|
||||
uc, UC_MEM_FETCH_UNMAPPED, addr, DATA_SIZE, 0,
|
||||
uc->hook_callbacks[uc->hook_mem_fetch_idx].user_data)) {
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_FETCH_UNMAPPED) {
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_UNMAPPED, addr, DATA_SIZE, 0, hook->user_data)))
|
||||
break;
|
||||
}
|
||||
#else
|
||||
error_code = UC_ERR_READ_UNMAPPED;
|
||||
if (uc->hook_mem_read_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_idx].callback)(
|
||||
uc, UC_MEM_READ_UNMAPPED, addr, DATA_SIZE, 0,
|
||||
uc->hook_callbacks[uc->hook_mem_read_idx].user_data)) {
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ_UNMAPPED) {
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_UNMAPPED, addr, DATA_SIZE, 0, hook->user_data)))
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (handled) {
|
||||
env->invalid_error = UC_ERR_OK;
|
||||
mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time?
|
||||
} else {
|
||||
|
@ -209,9 +219,15 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
|
|||
#if defined(SOFTMMU_CODE_ACCESS)
|
||||
// Unicorn: callback on fetch from NX
|
||||
if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable
|
||||
if (uc->hook_mem_fetch_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].callback)(
|
||||
uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0,
|
||||
uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].user_data)) {
|
||||
handled = false;
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_FETCH_PROT) {
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0, hook->user_data)))
|
||||
break;
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
env->invalid_error = UC_ERR_OK;
|
||||
} else {
|
||||
env->invalid_addr = addr;
|
||||
|
@ -224,19 +240,25 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
|
|||
#endif
|
||||
|
||||
// Unicorn: callback on memory read
|
||||
if (READ_ACCESS_TYPE == MMU_DATA_LOAD && env->uc->hook_mem_read) {
|
||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_MEM_READ, addr);
|
||||
if (trace) {
|
||||
((uc_cb_hookmem_t)trace->callback)(env->uc, UC_MEM_READ,
|
||||
(uint64_t)addr, (int)DATA_SIZE, (int64_t)0, trace->user_data);
|
||||
if (READ_ACCESS_TYPE == MMU_DATA_LOAD) {
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ) {
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
((uc_cb_hookmem_t)hook->callback)(env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, hook->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
// Unicorn: callback on non-readable memory
|
||||
if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable
|
||||
if (uc->hook_mem_read_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_prot_idx].callback)(
|
||||
uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0,
|
||||
uc->hook_callbacks[uc->hook_mem_read_prot_idx].user_data)) {
|
||||
handled = false;
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ_PROT) {
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, hook->user_data)))
|
||||
break;
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
env->invalid_error = UC_ERR_OK;
|
||||
} else {
|
||||
env->invalid_addr = addr;
|
||||
|
@ -368,23 +390,33 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
|
|||
uintptr_t haddr;
|
||||
DATA_TYPE res;
|
||||
int error_code;
|
||||
struct hook *hook;
|
||||
bool handled;
|
||||
|
||||
struct uc_struct *uc = env->uc;
|
||||
MemoryRegion *mr = memory_mapping(uc, addr);
|
||||
|
||||
// memory can be unmapped while reading or fetching
|
||||
if (mr == NULL) {
|
||||
handled = false;
|
||||
#if defined(SOFTMMU_CODE_ACCESS)
|
||||
error_code = UC_ERR_FETCH_UNMAPPED;
|
||||
if (uc->hook_mem_fetch_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_idx].callback)(
|
||||
uc, UC_MEM_FETCH_UNMAPPED, addr, DATA_SIZE, 0,
|
||||
uc->hook_callbacks[uc->hook_mem_fetch_idx].user_data)) {
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_FETCH_UNMAPPED) {
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_UNMAPPED, addr, DATA_SIZE, 0, hook->user_data)))
|
||||
break;
|
||||
}
|
||||
#else
|
||||
error_code = UC_ERR_READ_UNMAPPED;
|
||||
if (uc->hook_mem_read_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_idx].callback)(
|
||||
uc, UC_MEM_READ_UNMAPPED, addr, DATA_SIZE, 0,
|
||||
uc->hook_callbacks[uc->hook_mem_read_idx].user_data)) {
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ_UNMAPPED) {
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_UNMAPPED, addr, DATA_SIZE, 0, hook->user_data)))
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
if (handled) {
|
||||
env->invalid_error = UC_ERR_OK;
|
||||
mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time?
|
||||
} else {
|
||||
|
@ -399,9 +431,15 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
|
|||
#if defined(SOFTMMU_CODE_ACCESS)
|
||||
// Unicorn: callback on fetch from NX
|
||||
if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable
|
||||
if (uc->hook_mem_fetch_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].callback)(
|
||||
uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0,
|
||||
uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].user_data)) {
|
||||
handled = false;
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_FETCH_PROT) {
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0, hook->user_data)))
|
||||
break;
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
env->invalid_error = UC_ERR_OK;
|
||||
} else {
|
||||
env->invalid_addr = addr;
|
||||
|
@ -414,19 +452,25 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
|
|||
#endif
|
||||
|
||||
// Unicorn: callback on memory read
|
||||
if (READ_ACCESS_TYPE == MMU_DATA_LOAD && env->uc->hook_mem_read) {
|
||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_MEM_READ, addr);
|
||||
if (trace) {
|
||||
((uc_cb_hookmem_t)trace->callback)(env->uc, UC_MEM_READ,
|
||||
(uint64_t)addr, (int)DATA_SIZE, (int64_t)0, trace->user_data);
|
||||
if (READ_ACCESS_TYPE == MMU_DATA_LOAD) {
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ) {
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
((uc_cb_hookmem_t)hook->callback)(env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, hook->user_data);
|
||||
}
|
||||
}
|
||||
|
||||
// Unicorn: callback on non-readable memory
|
||||
if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable
|
||||
if (uc->hook_mem_read_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_prot_idx].callback)(
|
||||
uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0,
|
||||
uc->hook_callbacks[uc->hook_mem_read_prot_idx].user_data)) {
|
||||
handled = false;
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ_PROT) {
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, hook->user_data)))
|
||||
break;
|
||||
}
|
||||
|
||||
if (handled) {
|
||||
env->invalid_error = UC_ERR_OK;
|
||||
} else {
|
||||
env->invalid_addr = addr;
|
||||
|
@ -595,24 +639,30 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
|
|||
int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
|
||||
uintptr_t haddr;
|
||||
struct hook *hook;
|
||||
bool handled;
|
||||
|
||||
struct uc_struct *uc = env->uc;
|
||||
MemoryRegion *mr = memory_mapping(uc, addr);
|
||||
|
||||
// Unicorn: callback on memory write
|
||||
if (uc->hook_mem_write) {
|
||||
struct hook_struct *trace = hook_find(uc, UC_HOOK_MEM_WRITE, addr);
|
||||
if (trace) {
|
||||
((uc_cb_hookmem_t)trace->callback)(uc, UC_MEM_WRITE,
|
||||
(uint64_t)addr, (int)DATA_SIZE, (int64_t)val, trace->user_data);
|
||||
}
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE) {
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
((uc_cb_hookmem_t)hook->callback)(uc, UC_MEM_WRITE, addr, DATA_SIZE, val, hook->user_data);
|
||||
}
|
||||
|
||||
// Unicorn: callback on invalid memory
|
||||
if (uc->hook_mem_write_idx && mr == NULL) {
|
||||
if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_idx].callback)(
|
||||
uc, UC_MEM_WRITE_UNMAPPED, addr, DATA_SIZE, (int64_t)val,
|
||||
uc->hook_callbacks[uc->hook_mem_write_idx].user_data)) {
|
||||
if (mr == NULL) {
|
||||
handled = false;
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE_UNMAPPED) {
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_UNMAPPED, addr, DATA_SIZE, val, hook->user_data)))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
// save error & quit
|
||||
env->invalid_addr = addr;
|
||||
env->invalid_error = UC_ERR_WRITE_UNMAPPED;
|
||||
|
@ -627,12 +677,17 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
|
|||
|
||||
// Unicorn: callback on non-writable memory
|
||||
if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable
|
||||
if (uc->hook_mem_write_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_prot_idx].callback)(
|
||||
uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val,
|
||||
uc->hook_callbacks[uc->hook_mem_write_prot_idx].user_data)) {
|
||||
env->invalid_error = UC_ERR_OK;
|
||||
handled = false;
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE_PROT) {
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, val, hook->user_data)))
|
||||
break;
|
||||
}
|
||||
else {
|
||||
|
||||
if (handled) {
|
||||
env->invalid_error = UC_ERR_OK;
|
||||
} else {
|
||||
env->invalid_addr = addr;
|
||||
env->invalid_error = UC_ERR_WRITE_PROT;
|
||||
// printf("***** Invalid memory write (ro) at " TARGET_FMT_lx "\n", addr);
|
||||
|
@ -742,24 +797,30 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
|
|||
int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||
target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
|
||||
uintptr_t haddr;
|
||||
struct hook *hook;
|
||||
bool handled;
|
||||
|
||||
struct uc_struct *uc = env->uc;
|
||||
MemoryRegion *mr = memory_mapping(uc, addr);
|
||||
|
||||
// Unicorn: callback on memory write
|
||||
if (uc->hook_mem_write) {
|
||||
struct hook_struct *trace = hook_find(uc, UC_HOOK_MEM_WRITE, addr);
|
||||
if (trace) {
|
||||
((uc_cb_hookmem_t)trace->callback)(uc, UC_MEM_WRITE,
|
||||
(uint64_t)addr, (int)DATA_SIZE, (int64_t)val, trace->user_data);
|
||||
}
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE) {
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
((uc_cb_hookmem_t)hook->callback)(uc, UC_MEM_WRITE, addr, DATA_SIZE, val, hook->user_data);
|
||||
}
|
||||
|
||||
// Unicorn: callback on invalid memory
|
||||
if (uc->hook_mem_write_idx && mr == NULL) {
|
||||
if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_idx].callback)(
|
||||
uc, UC_MEM_WRITE_UNMAPPED, addr, DATA_SIZE, (int64_t)val,
|
||||
uc->hook_callbacks[uc->hook_mem_write_idx].user_data)) {
|
||||
if (mr == NULL) {
|
||||
handled = false;
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE_UNMAPPED) {
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_UNMAPPED, addr, DATA_SIZE, val, hook->user_data)))
|
||||
break;
|
||||
}
|
||||
|
||||
if (!handled) {
|
||||
// save error & quit
|
||||
env->invalid_addr = addr;
|
||||
env->invalid_error = UC_ERR_WRITE_UNMAPPED;
|
||||
|
@ -774,12 +835,17 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
|
|||
|
||||
// Unicorn: callback on non-writable memory
|
||||
if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable
|
||||
if (uc->hook_mem_write_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_prot_idx].callback)(
|
||||
uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val,
|
||||
uc->hook_callbacks[uc->hook_mem_write_prot_idx].user_data)) {
|
||||
env->invalid_error = UC_ERR_OK;
|
||||
handled = false;
|
||||
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE_PROT) {
|
||||
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||
continue;
|
||||
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, val, hook->user_data)))
|
||||
break;
|
||||
}
|
||||
else {
|
||||
|
||||
if (handled) {
|
||||
env->invalid_error = UC_ERR_OK;
|
||||
} else {
|
||||
env->invalid_addr = addr;
|
||||
env->invalid_error = UC_ERR_WRITE_PROT;
|
||||
// printf("***** Invalid memory write (ro) at " TARGET_FMT_lx "\n", addr);
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||
#ifndef UNICORN_AUTOGEN_SPARC_H
|
||||
#define UNICORN_AUTOGEN_SPARC_H
|
||||
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_sparc
|
||||
#define use_idiv_instructions_rt use_idiv_instructions_rt_sparc
|
||||
#define tcg_target_deposit_valid tcg_target_deposit_valid_sparc
|
||||
#define helper_power_down helper_power_down_sparc
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||
#ifndef UNICORN_AUTOGEN_SPARC64_H
|
||||
#define UNICORN_AUTOGEN_SPARC64_H
|
||||
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_sparc64
|
||||
#define use_idiv_instructions_rt use_idiv_instructions_rt_sparc64
|
||||
#define tcg_target_deposit_valid tcg_target_deposit_valid_sparc64
|
||||
#define helper_power_down helper_power_down_sparc64
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr)
|
||||
DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64)
|
||||
|
||||
DEF_HELPER_FLAGS_1(clz_arm, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||
|
||||
|
|
|
@ -10984,10 +10984,8 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
|
|||
s->pc += 4;
|
||||
|
||||
// Unicorn: trace this instruction on request
|
||||
if (env->uc->hook_insn) {
|
||||
struct hook_struct *trace = hook_find(s->uc, UC_HOOK_CODE, s->pc - 4);
|
||||
if (trace)
|
||||
gen_uc_tracecode(tcg_ctx, 4, trace->callback, env->uc, s->pc - 4, trace->user_data);
|
||||
if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, s->pc - 4)) {
|
||||
gen_uc_tracecode(tcg_ctx, 4, UC_HOOK_CODE_IDX, env->uc, s->pc - 4);
|
||||
// the callback might want to stop emulation immediately
|
||||
check_exit_request(tcg_ctx);
|
||||
}
|
||||
|
@ -11114,13 +11112,10 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
|
|||
// Unicorn: trace this block on request
|
||||
// Only hook this block if it is not broken from previous translation due to
|
||||
// full translation cache
|
||||
if (env->uc->hook_block && !env->uc->block_full) {
|
||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start);
|
||||
if (trace) {
|
||||
// save block address to see if we need to patch block size later
|
||||
env->uc->block_addr = pc_start;
|
||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data);
|
||||
}
|
||||
if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) {
|
||||
// save block address to see if we need to patch block size later
|
||||
env->uc->block_addr = pc_start;
|
||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start);
|
||||
}
|
||||
|
||||
gen_tb_start(tcg_ctx);
|
||||
|
|
|
@ -7687,10 +7687,8 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) // qq
|
|||
}
|
||||
|
||||
// Unicorn: trace this instruction on request
|
||||
if (s->uc->hook_insn) {
|
||||
struct hook_struct *trace = hook_find(s->uc, UC_HOOK_CODE, s->pc - 4);
|
||||
if (trace)
|
||||
gen_uc_tracecode(tcg_ctx, 4, trace->callback, s->uc, s->pc - 4, trace->user_data);
|
||||
if (HOOK_EXISTS_BOUNDED(s->uc, UC_HOOK_CODE, s->pc - 4)) {
|
||||
gen_uc_tracecode(tcg_ctx, 4, UC_HOOK_CODE_IDX, s->uc, s->pc - 4);
|
||||
// the callback might want to stop emulation immediately
|
||||
check_exit_request(tcg_ctx);
|
||||
}
|
||||
|
@ -10408,15 +10406,10 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) // qq
|
|||
}
|
||||
|
||||
// Unicorn: trace this instruction on request
|
||||
if (env->uc->hook_insn) {
|
||||
struct hook_struct *trace = hook_find(s->uc, UC_HOOK_CODE, s->pc);
|
||||
if (trace)
|
||||
gen_uc_tracecode(tcg_ctx, 2, trace->callback, env->uc, s->pc, trace->user_data);
|
||||
// if requested to emulate only some instructions, check to see
|
||||
// if we need to exit immediately
|
||||
if (env->uc->emu_count > 0) {
|
||||
check_exit_request(tcg_ctx);
|
||||
}
|
||||
if (HOOK_EXISTS_BOUNDED(s->uc, UC_HOOK_CODE, s->pc)) {
|
||||
gen_uc_tracecode(tcg_ctx, 2, UC_HOOK_CODE_IDX, s->uc, s->pc);
|
||||
// the callback might want to stop emulation immediately
|
||||
check_exit_request(tcg_ctx);
|
||||
}
|
||||
|
||||
insn = arm_lduw_code(env, s->pc, s->bswap_code);
|
||||
|
@ -11237,13 +11230,10 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
|
|||
// Unicorn: trace this block on request
|
||||
// Only hook this block if it is not broken from previous translation due to
|
||||
// full translation cache
|
||||
if (env->uc->hook_block && !env->uc->block_full) {
|
||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start);
|
||||
if (trace) {
|
||||
// save block address to see if we need to patch block size later
|
||||
env->uc->block_addr = pc_start;
|
||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data);
|
||||
}
|
||||
if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) {
|
||||
// save block address to see if we need to patch block size later
|
||||
env->uc->block_addr = pc_start;
|
||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start);
|
||||
}
|
||||
|
||||
gen_tb_start(tcg_ctx);
|
||||
|
|
|
@ -3,21 +3,11 @@
|
|||
|
||||
#include "hw/boards.h"
|
||||
#include "hw/arm/arm.h"
|
||||
|
||||
#include "sysemu/cpus.h"
|
||||
|
||||
#include "unicorn.h"
|
||||
|
||||
#include "cpu.h"
|
||||
|
||||
#include "unicorn_common.h"
|
||||
|
||||
|
||||
#define READ_QWORD(x) ((uint64)x)
|
||||
#define READ_DWORD(x) (x & 0xffffffff)
|
||||
#define READ_WORD(x) (x & 0xffff)
|
||||
#define READ_BYTE_H(x) ((x & 0xffff) >> 8)
|
||||
#define READ_BYTE_L(x) (x & 0xff)
|
||||
#include "uc_priv.h"
|
||||
|
||||
|
||||
static void arm64_set_pc(struct uc_struct *uc, uint64_t address)
|
||||
|
@ -60,11 +50,6 @@ int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
|
|||
return 0;
|
||||
}
|
||||
|
||||
#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff))
|
||||
#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff))
|
||||
#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff))
|
||||
#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff))
|
||||
|
||||
int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
||||
{
|
||||
CPUState *mycpu = first_cpu;
|
||||
|
@ -82,6 +67,9 @@ int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
|||
break;
|
||||
case UC_ARM64_REG_PC:
|
||||
ARM_CPU(uc, mycpu)->env.pc = *(uint64_t *)value;
|
||||
// force to quit execution and flush TB
|
||||
uc->quit_request = true;
|
||||
uc_emu_stop(uc);
|
||||
break;
|
||||
case UC_ARM64_REG_SP:
|
||||
ARM_CPU(uc, mycpu)->env.xregs[31] = *(uint64_t *)value;
|
||||
|
|
|
@ -3,20 +3,11 @@
|
|||
|
||||
#include "hw/boards.h"
|
||||
#include "hw/arm/arm.h"
|
||||
|
||||
#include "sysemu/cpus.h"
|
||||
|
||||
#include "unicorn.h"
|
||||
|
||||
#include "cpu.h"
|
||||
#include "unicorn_common.h"
|
||||
|
||||
|
||||
#define READ_QWORD(x) ((uint64)x)
|
||||
#define READ_DWORD(x) (x & 0xffffffff)
|
||||
#define READ_WORD(x) (x & 0xffff)
|
||||
#define READ_BYTE_H(x) ((x & 0xffff) >> 8)
|
||||
#define READ_BYTE_L(x) (x & 0xff)
|
||||
#include "uc_priv.h"
|
||||
|
||||
|
||||
static void arm_set_pc(struct uc_struct *uc, uint64_t address)
|
||||
|
@ -42,73 +33,57 @@ int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
|
|||
|
||||
mycpu = first_cpu;
|
||||
|
||||
switch(uc->mode) {
|
||||
default:
|
||||
break;
|
||||
case UC_MODE_ARM:
|
||||
case UC_MODE_THUMB:
|
||||
if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12)
|
||||
*(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0];
|
||||
else {
|
||||
switch(regid) {
|
||||
case UC_ARM_REG_CPSR:
|
||||
*(int32_t *)value = cpsr_read(&ARM_CPU(uc, mycpu)->env);
|
||||
break;
|
||||
//case UC_ARM_REG_SP:
|
||||
case UC_ARM_REG_R13:
|
||||
*(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[13];
|
||||
break;
|
||||
//case UC_ARM_REG_LR:
|
||||
case UC_ARM_REG_R14:
|
||||
*(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[14];
|
||||
break;
|
||||
//case UC_ARM_REG_PC:
|
||||
case UC_ARM_REG_R15:
|
||||
*(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[15];
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12)
|
||||
*(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0];
|
||||
else {
|
||||
switch(regid) {
|
||||
case UC_ARM_REG_CPSR:
|
||||
*(int32_t *)value = cpsr_read(&ARM_CPU(uc, mycpu)->env);
|
||||
break;
|
||||
//case UC_ARM_REG_SP:
|
||||
case UC_ARM_REG_R13:
|
||||
*(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[13];
|
||||
break;
|
||||
//case UC_ARM_REG_LR:
|
||||
case UC_ARM_REG_R14:
|
||||
*(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[14];
|
||||
break;
|
||||
//case UC_ARM_REG_PC:
|
||||
case UC_ARM_REG_R15:
|
||||
*(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[15];
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff))
|
||||
#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff))
|
||||
#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff))
|
||||
#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff))
|
||||
|
||||
int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
||||
{
|
||||
CPUState *mycpu = first_cpu;
|
||||
|
||||
switch(uc->mode) {
|
||||
default:
|
||||
break;
|
||||
if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12)
|
||||
ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0] = *(uint32_t *)value;
|
||||
else {
|
||||
switch(regid) {
|
||||
//case UC_ARM_REG_SP:
|
||||
case UC_ARM_REG_R13:
|
||||
ARM_CPU(uc, mycpu)->env.regs[13] = *(uint32_t *)value;
|
||||
break;
|
||||
//case UC_ARM_REG_LR:
|
||||
case UC_ARM_REG_R14:
|
||||
ARM_CPU(uc, mycpu)->env.regs[14] = *(uint32_t *)value;
|
||||
break;
|
||||
//case UC_ARM_REG_PC:
|
||||
case UC_ARM_REG_R15:
|
||||
ARM_CPU(uc, mycpu)->env.pc = *(uint32_t *)value;
|
||||
ARM_CPU(uc, mycpu)->env.regs[15] = *(uint32_t *)value;
|
||||
// force to quit execution and flush TB
|
||||
uc->quit_request = true;
|
||||
uc_emu_stop(uc);
|
||||
|
||||
case UC_MODE_ARM:
|
||||
case UC_MODE_THUMB:
|
||||
if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12)
|
||||
ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0] = *(uint32_t *)value;
|
||||
else {
|
||||
switch(regid) {
|
||||
//case UC_ARM_REG_SP:
|
||||
case UC_ARM_REG_R13:
|
||||
ARM_CPU(uc, mycpu)->env.regs[13] = *(uint32_t *)value;
|
||||
break;
|
||||
//case UC_ARM_REG_LR:
|
||||
case UC_ARM_REG_R14:
|
||||
ARM_CPU(uc, mycpu)->env.regs[14] = *(uint32_t *)value;
|
||||
break;
|
||||
//case UC_ARM_REG_PC:
|
||||
case UC_ARM_REG_R15:
|
||||
ARM_CPU(uc, mycpu)->env.regs[15] = *(uint32_t *)value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -124,6 +99,24 @@ static bool arm_stop_interrupt(int intno)
|
|||
}
|
||||
}
|
||||
|
||||
static uc_err arm_query(struct uc_struct *uc, uc_query_type type, size_t *result)
|
||||
{
|
||||
CPUState *mycpu = first_cpu;
|
||||
uint32_t mode;
|
||||
|
||||
switch(type) {
|
||||
case UC_QUERY_MODE:
|
||||
// zero out ARM/THUMB mode
|
||||
mode = uc->mode & ~(UC_MODE_ARM | UC_MODE_THUMB);
|
||||
// THUMB mode or ARM MOde
|
||||
mode += ((ARM_CPU(uc, mycpu)->env.thumb != 0)? UC_MODE_THUMB : UC_MODE_ARM);
|
||||
*result = mode;
|
||||
return UC_ERR_OK;
|
||||
default:
|
||||
return UC_ERR_ARG;
|
||||
}
|
||||
}
|
||||
|
||||
void arm_uc_init(struct uc_struct* uc)
|
||||
{
|
||||
register_accel_types(uc);
|
||||
|
@ -134,5 +127,6 @@ void arm_uc_init(struct uc_struct* uc)
|
|||
uc->reg_reset = arm_reg_reset;
|
||||
uc->set_pc = arm_set_pc;
|
||||
uc->stop_interrupt = arm_stop_interrupt;
|
||||
uc->query = arm_query;
|
||||
uc_common_init(uc);
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr)
|
||||
DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64)
|
||||
|
||||
DEF_HELPER_FLAGS_4(cc_compute_all, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int)
|
||||
DEF_HELPER_FLAGS_4(cc_compute_c, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int)
|
||||
|
|
|
@ -945,14 +945,16 @@ void helper_syscall(CPUX86State *env, int next_eip_addend)
|
|||
#else
|
||||
void helper_syscall(CPUX86State *env, int next_eip_addend)
|
||||
{
|
||||
// Unicorn: call interrupt callback if registered
|
||||
struct uc_struct *uc = env->uc;
|
||||
if (uc->hook_syscall_idx) {
|
||||
((uc_cb_insn_syscall_t)uc->hook_callbacks[uc->hook_syscall_idx].callback)(
|
||||
uc, uc->hook_callbacks[uc->hook_syscall_idx].user_data);
|
||||
// Unicorn: call registered syscall hooks
|
||||
struct hook *hook;
|
||||
HOOK_FOREACH(env->uc, hook, UC_HOOK_INSN) {
|
||||
if (!HOOK_BOUND_CHECK(hook, env->eip))
|
||||
continue;
|
||||
if (hook->insn == UC_X86_INS_SYSCALL)
|
||||
((uc_cb_insn_syscall_t)hook->callback)(env->uc, hook->user_data);
|
||||
}
|
||||
env->eip += next_eip_addend;
|
||||
|
||||
env->eip += next_eip_addend;
|
||||
return;
|
||||
|
||||
int selector;
|
||||
|
@ -2303,14 +2305,16 @@ void helper_lret_protected(CPUX86State *env, int shift, int addend)
|
|||
|
||||
void helper_sysenter(CPUX86State *env, int next_eip_addend)
|
||||
{
|
||||
// Unicorn: call interrupt callback if registered
|
||||
struct uc_struct *uc = env->uc;
|
||||
if (uc->hook_syscall_idx) {
|
||||
((uc_cb_insn_syscall_t)uc->hook_callbacks[uc->hook_syscall_idx].callback)(
|
||||
uc, uc->hook_callbacks[uc->hook_syscall_idx].user_data);
|
||||
// Unicorn: call registered SYSENTER hooks
|
||||
struct hook *hook;
|
||||
HOOK_FOREACH(env->uc, hook, UC_HOOK_INSN) {
|
||||
if (!HOOK_BOUND_CHECK(hook, env->eip))
|
||||
continue;
|
||||
if (hook->insn == UC_X86_INS_SYSENTER)
|
||||
((uc_cb_insn_syscall_t)hook->callback)(env->uc, hook->user_data);
|
||||
}
|
||||
env->eip += next_eip_addend;
|
||||
|
||||
env->eip += next_eip_addend;
|
||||
return;
|
||||
|
||||
if (env->sysenter_cs == 0) {
|
||||
|
|
|
@ -516,14 +516,14 @@ static inline void gen_op_addq_A0_reg_sN(TCGContext *s, int shift, int reg)
|
|||
|
||||
static inline void gen_op_ld_v(DisasContext *s, int idx, TCGv t0, TCGv a0)
|
||||
{
|
||||
if (s->uc->hook_mem_read)
|
||||
if (HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ))
|
||||
gen_jmp_im(s, s->prev_pc); // Unicorn: sync EIP
|
||||
tcg_gen_qemu_ld_tl(s->uc, t0, a0, s->mem_index, idx | MO_LE);
|
||||
}
|
||||
|
||||
static inline void gen_op_st_v(DisasContext *s, int idx, TCGv t0, TCGv a0)
|
||||
{
|
||||
if (s->uc->hook_mem_write)
|
||||
if (HOOK_EXISTS(s->uc, UC_HOOK_MEM_WRITE))
|
||||
gen_jmp_im(s, s->prev_pc); // Unicorn: sync EIP
|
||||
tcg_gen_qemu_st_tl(s->uc, t0, a0, s->mem_index, idx | MO_LE);
|
||||
}
|
||||
|
@ -4721,6 +4721,17 @@ static void sync_eflags(DisasContext *s, TCGContext *tcg_ctx)
|
|||
tcg_gen_st_tl(tcg_ctx, *cpu_T[0], cpu_env, offsetof(CPUX86State, eflags));
|
||||
}
|
||||
|
||||
static void restore_eflags(DisasContext *s, TCGContext *tcg_ctx)
|
||||
{
|
||||
TCGv **cpu_T = (TCGv **)tcg_ctx->cpu_T;
|
||||
TCGv_ptr cpu_env = tcg_ctx->cpu_env;
|
||||
|
||||
tcg_gen_ld_tl(tcg_ctx, *cpu_T[0], cpu_env, offsetof(CPUX86State, eflags));
|
||||
gen_helper_write_eflags(tcg_ctx, cpu_env, *cpu_T[0],
|
||||
tcg_const_i32(tcg_ctx, (TF_MASK | AC_MASK | ID_MASK | NT_MASK) & 0xffff));
|
||||
set_cc_op(s, CC_OP_EFLAGS);
|
||||
}
|
||||
|
||||
/* convert one instruction. s->is_jmp is set if the translation must
|
||||
be stopped. Return the next pc value */
|
||||
static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
||||
|
@ -4745,12 +4756,10 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
TCGv cpu_tmp4 = *(TCGv *)tcg_ctx->cpu_tmp4;
|
||||
TCGv **cpu_T = (TCGv **)tcg_ctx->cpu_T;
|
||||
TCGv **cpu_regs = (TCGv **)tcg_ctx->cpu_regs;
|
||||
struct hook_struct *trace = NULL;
|
||||
TCGArg *save_opparam_ptr = tcg_ctx->gen_opparam_ptr;
|
||||
bool cc_op_dirty = s->cc_op_dirty;
|
||||
bool changed_cc_op = false;
|
||||
|
||||
|
||||
s->pc = pc_start;
|
||||
|
||||
// end address tells us to stop emulation
|
||||
|
@ -4768,19 +4777,16 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
}
|
||||
|
||||
// Unicorn: trace this instruction on request
|
||||
if (env->uc->hook_insn) {
|
||||
trace = hook_find(env->uc, UC_HOOK_CODE, pc_start);
|
||||
if (trace) {
|
||||
if (s->last_cc_op != s->cc_op) {
|
||||
sync_eflags(s, tcg_ctx);
|
||||
s->last_cc_op = s->cc_op;
|
||||
changed_cc_op = true;
|
||||
}
|
||||
// generate code to call callback
|
||||
gen_uc_tracecode(tcg_ctx, 0xf1f1f1f1, trace->callback, env->uc, pc_start, trace->user_data);
|
||||
// the callback might want to stop emulation immediately
|
||||
check_exit_request(tcg_ctx);
|
||||
if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, pc_start)) {
|
||||
if (s->last_cc_op != s->cc_op) {
|
||||
sync_eflags(s, tcg_ctx);
|
||||
s->last_cc_op = s->cc_op;
|
||||
changed_cc_op = true;
|
||||
}
|
||||
gen_uc_tracecode(tcg_ctx, 0xf1f1f1f1, UC_HOOK_CODE_IDX, env->uc, pc_start);
|
||||
restore_eflags(s, tcg_ctx);
|
||||
// the callback might want to stop emulation immediately
|
||||
check_exit_request(tcg_ctx);
|
||||
}
|
||||
|
||||
prefixes = 0;
|
||||
|
@ -8173,7 +8179,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
|||
gen_helper_unlock(tcg_ctx, cpu_env);
|
||||
|
||||
// Unicorn: patch the callback for the instruction size
|
||||
if (trace) {
|
||||
if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, pc_start)) {
|
||||
// int i;
|
||||
// for(i = 0; i < 20; i++)
|
||||
// printf("=== [%u] = %x\n", i, *(save_opparam_ptr + i));
|
||||
|
@ -8387,12 +8393,9 @@ static inline void gen_intermediate_code_internal(uint8_t *gen_opc_cc_op,
|
|||
// Unicorn: trace this block on request
|
||||
// Only hook this block if it is not broken from previous translation due to
|
||||
// full translation cache
|
||||
if (env->uc->hook_block && !env->uc->block_full) {
|
||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start);
|
||||
if (trace) {
|
||||
env->uc->block_addr = pc_start;
|
||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data);
|
||||
}
|
||||
if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) {
|
||||
env->uc->block_addr = pc_start;
|
||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start);
|
||||
}
|
||||
|
||||
gen_tb_start(tcg_ctx);
|
||||
|
|
|
@ -2,19 +2,14 @@
|
|||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
||||
|
||||
#include "hw/boards.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "hw/i386/pc.h"
|
||||
#include "sysemu/cpus.h"
|
||||
#include "unicorn.h"
|
||||
#include "cpu.h"
|
||||
#include "tcg.h"
|
||||
|
||||
#include "unicorn_common.h"
|
||||
|
||||
#define READ_QWORD(x) ((uint64)x)
|
||||
#define READ_DWORD(x) (x & 0xffffffff)
|
||||
#define READ_WORD(x) (x & 0xffff)
|
||||
#define READ_BYTE_H(x) ((x & 0xffff) >> 8)
|
||||
#define READ_BYTE_L(x) (x & 0xff)
|
||||
#include <unicorn/x86.h> /* needed for uc_x86_mmr */
|
||||
#include "uc_priv.h"
|
||||
|
||||
|
||||
static void x86_set_pc(struct uc_struct *uc, uint64_t address)
|
||||
|
@ -145,6 +140,58 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
|
|||
{
|
||||
CPUState *mycpu = first_cpu;
|
||||
|
||||
switch(regid) {
|
||||
default:
|
||||
break;
|
||||
case UC_X86_REG_FP0 ... UC_X86_REG_FP7:
|
||||
{
|
||||
floatx80 reg = X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d;
|
||||
cpu_get_fp80(value, value+sizeof(uint64_t), reg);
|
||||
}
|
||||
break;
|
||||
case UC_X86_REG_FPSW:
|
||||
{
|
||||
uint16_t fpus = X86_CPU(uc, mycpu)->env.fpus;
|
||||
fpus = fpus & ~0x3800;
|
||||
fpus |= ( X86_CPU(uc, mycpu)->env.fpstt & 0x7 ) << 11;
|
||||
*(uint16_t*) value = fpus;
|
||||
}
|
||||
break;
|
||||
case UC_X86_REG_FPCW:
|
||||
*(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc;
|
||||
break;
|
||||
case UC_X86_REG_FPTAG:
|
||||
{
|
||||
#define EXPD(fp) (fp.l.upper & 0x7fff)
|
||||
#define MANTD(fp) (fp.l.lower)
|
||||
#define MAXEXPD 0x7fff
|
||||
int fptag, exp, i;
|
||||
uint64_t mant;
|
||||
CPU_LDoubleU tmp;
|
||||
fptag = 0;
|
||||
for (i = 7; i >= 0; i--) {
|
||||
fptag <<= 2;
|
||||
if (X86_CPU(uc, mycpu)->env.fptags[i]) {
|
||||
fptag |= 3;
|
||||
} else {
|
||||
tmp.d = X86_CPU(uc, mycpu)->env.fpregs[i].d;
|
||||
exp = EXPD(tmp);
|
||||
mant = MANTD(tmp);
|
||||
if (exp == 0 && mant == 0) {
|
||||
/* zero */
|
||||
fptag |= 1;
|
||||
} else if (exp == 0 || exp == MAXEXPD
|
||||
|| (mant & (1LL << 63)) == 0) {
|
||||
/* NaNs, infinity, denormal */
|
||||
fptag |= 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
*(uint16_t*) value = fptag;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch(uc->mode) {
|
||||
default:
|
||||
break;
|
||||
|
@ -260,22 +307,42 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
|
|||
*(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.eip);
|
||||
break;
|
||||
case UC_X86_REG_CS:
|
||||
*(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_CS].base;
|
||||
*(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_CS].selector;
|
||||
break;
|
||||
case UC_X86_REG_DS:
|
||||
*(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_DS].base;
|
||||
*(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_DS].selector;
|
||||
break;
|
||||
case UC_X86_REG_SS:
|
||||
*(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_SS].base;
|
||||
*(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_SS].selector;
|
||||
break;
|
||||
case UC_X86_REG_ES:
|
||||
*(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_ES].base;
|
||||
*(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_ES].selector;
|
||||
break;
|
||||
case UC_X86_REG_FS:
|
||||
*(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_FS].base;
|
||||
*(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_FS].selector;
|
||||
break;
|
||||
case UC_X86_REG_GS:
|
||||
*(int32_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].base;
|
||||
*(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_GS].selector;
|
||||
break;
|
||||
case UC_X86_REG_IDTR:
|
||||
((uc_x86_mmr *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.idt.limit;
|
||||
((uc_x86_mmr *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.idt.base;
|
||||
break;
|
||||
case UC_X86_REG_GDTR:
|
||||
((uc_x86_mmr *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.gdt.limit;
|
||||
((uc_x86_mmr *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.gdt.base;
|
||||
break;
|
||||
case UC_X86_REG_LDTR:
|
||||
((uc_x86_mmr *)value)->limit = X86_CPU(uc, mycpu)->env.ldt.limit;
|
||||
((uc_x86_mmr *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.ldt.base;
|
||||
((uc_x86_mmr *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.ldt.selector;
|
||||
((uc_x86_mmr *)value)->flags = X86_CPU(uc, mycpu)->env.ldt.flags;
|
||||
break;
|
||||
case UC_X86_REG_TR:
|
||||
((uc_x86_mmr *)value)->limit = X86_CPU(uc, mycpu)->env.tr.limit;
|
||||
((uc_x86_mmr *)value)->base = (uint32_t)X86_CPU(uc, mycpu)->env.tr.base;
|
||||
((uc_x86_mmr *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.tr.selector;
|
||||
((uc_x86_mmr *)value)->flags = X86_CPU(uc, mycpu)->env.tr.flags;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -412,22 +479,22 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
|
|||
*(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.eip);
|
||||
break;
|
||||
case UC_X86_REG_CS:
|
||||
*(int64_t *)value = X86_CPU(uc, mycpu)->env.segs[R_CS].base;
|
||||
*(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_CS].selector;
|
||||
break;
|
||||
case UC_X86_REG_DS:
|
||||
*(int64_t *)value = X86_CPU(uc, mycpu)->env.segs[R_DS].base;
|
||||
*(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_DS].selector;
|
||||
break;
|
||||
case UC_X86_REG_SS:
|
||||
*(int64_t *)value = X86_CPU(uc, mycpu)->env.segs[R_SS].base;
|
||||
*(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_SS].selector;
|
||||
break;
|
||||
case UC_X86_REG_ES:
|
||||
*(int64_t *)value = X86_CPU(uc, mycpu)->env.segs[R_ES].base;
|
||||
*(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_ES].selector;
|
||||
break;
|
||||
case UC_X86_REG_FS:
|
||||
*(int64_t *)value = X86_CPU(uc, mycpu)->env.segs[R_FS].base;
|
||||
*(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_FS].selector;
|
||||
break;
|
||||
case UC_X86_REG_GS:
|
||||
*(int64_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].base;
|
||||
*(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_GS].selector;
|
||||
break;
|
||||
case UC_X86_REG_R8:
|
||||
*(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[8]);
|
||||
|
@ -525,6 +592,26 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
|
|||
case UC_X86_REG_R15B:
|
||||
*(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[15]);
|
||||
break;
|
||||
case UC_X86_REG_IDTR:
|
||||
((uc_x86_mmr *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.idt.limit;
|
||||
((uc_x86_mmr *)value)->base = X86_CPU(uc, mycpu)->env.idt.base;
|
||||
break;
|
||||
case UC_X86_REG_GDTR:
|
||||
((uc_x86_mmr *)value)->limit = (uint16_t)X86_CPU(uc, mycpu)->env.gdt.limit;
|
||||
((uc_x86_mmr *)value)->base = X86_CPU(uc, mycpu)->env.gdt.base;
|
||||
break;
|
||||
case UC_X86_REG_LDTR:
|
||||
((uc_x86_mmr *)value)->limit = X86_CPU(uc, mycpu)->env.ldt.limit;
|
||||
((uc_x86_mmr *)value)->base = X86_CPU(uc, mycpu)->env.ldt.base;
|
||||
((uc_x86_mmr *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.ldt.selector;
|
||||
((uc_x86_mmr *)value)->flags = X86_CPU(uc, mycpu)->env.ldt.flags;
|
||||
break;
|
||||
case UC_X86_REG_TR:
|
||||
((uc_x86_mmr *)value)->limit = X86_CPU(uc, mycpu)->env.tr.limit;
|
||||
((uc_x86_mmr *)value)->base = X86_CPU(uc, mycpu)->env.tr.base;
|
||||
((uc_x86_mmr *)value)->selector = (uint16_t)X86_CPU(uc, mycpu)->env.tr.selector;
|
||||
((uc_x86_mmr *)value)->flags = X86_CPU(uc, mycpu)->env.tr.flags;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
@ -534,16 +621,42 @@ int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff))
|
||||
#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff))
|
||||
#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff))
|
||||
#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff))
|
||||
|
||||
int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
||||
{
|
||||
CPUState *mycpu = first_cpu;
|
||||
|
||||
switch(regid) {
|
||||
default:
|
||||
break;
|
||||
case UC_X86_REG_FP0 ... UC_X86_REG_FP7:
|
||||
{
|
||||
uint64_t mant = *(uint64_t*) value;
|
||||
uint16_t upper = *(uint16_t*) (value + sizeof(uint64_t));
|
||||
X86_CPU(uc, mycpu)->env.fpregs[regid - UC_X86_REG_FP0].d = cpu_set_fp80(mant, upper);
|
||||
}
|
||||
break;
|
||||
case UC_X86_REG_FPSW:
|
||||
{
|
||||
uint16_t fpus = *(uint16_t*) value;
|
||||
X86_CPU(uc, mycpu)->env.fpus = fpus & ~0x3800;
|
||||
X86_CPU(uc, mycpu)->env.fpstt = (fpus >> 11) & 0x7;
|
||||
}
|
||||
break;
|
||||
case UC_X86_REG_FPCW:
|
||||
X86_CPU(uc, mycpu)->env.fpuc = *(uint16_t *)value;
|
||||
break;
|
||||
case UC_X86_REG_FPTAG:
|
||||
{
|
||||
int i;
|
||||
uint16_t fptag = *(uint16_t*) value;
|
||||
for (i = 0; i < 8; i++) {
|
||||
X86_CPU(uc, mycpu)->env.fptags[i] = ((fptag & 3) == 3);
|
||||
fptag >>= 2;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
switch(uc->mode) {
|
||||
default:
|
||||
break;
|
||||
|
@ -656,27 +769,53 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
|||
break;
|
||||
case UC_X86_REG_EIP:
|
||||
X86_CPU(uc, mycpu)->env.eip = *(uint32_t *)value;
|
||||
// force to quit execution and flush TB
|
||||
uc->quit_request = true;
|
||||
uc_emu_stop(uc);
|
||||
break;
|
||||
case UC_X86_REG_IP:
|
||||
WRITE_WORD(X86_CPU(uc, mycpu)->env.eip, *(uint16_t *)value);
|
||||
// force to quit execution and flush TB
|
||||
uc->quit_request = true;
|
||||
uc_emu_stop(uc);
|
||||
break;
|
||||
case UC_X86_REG_CS:
|
||||
X86_CPU(uc, mycpu)->env.segs[R_CS].base = *(uint32_t *)value;
|
||||
X86_CPU(uc, mycpu)->env.segs[R_CS].selector = *(uint16_t *)value;
|
||||
break;
|
||||
case UC_X86_REG_DS:
|
||||
X86_CPU(uc, mycpu)->env.segs[R_DS].base = *(uint32_t *)value;
|
||||
X86_CPU(uc, mycpu)->env.segs[R_DS].selector = *(uint16_t *)value;
|
||||
break;
|
||||
case UC_X86_REG_SS:
|
||||
X86_CPU(uc, mycpu)->env.segs[R_SS].base = *(uint32_t *)value;
|
||||
X86_CPU(uc, mycpu)->env.segs[R_SS].selector = *(uint16_t *)value;
|
||||
break;
|
||||
case UC_X86_REG_ES:
|
||||
X86_CPU(uc, mycpu)->env.segs[R_ES].base = *(uint32_t *)value;
|
||||
X86_CPU(uc, mycpu)->env.segs[R_ES].selector = *(uint16_t *)value;
|
||||
break;
|
||||
case UC_X86_REG_FS:
|
||||
X86_CPU(uc, mycpu)->env.segs[R_FS].base = *(uint32_t *)value;
|
||||
X86_CPU(uc, mycpu)->env.segs[R_FS].selector = *(uint16_t *)value;
|
||||
break;
|
||||
case UC_X86_REG_GS:
|
||||
X86_CPU(uc, mycpu)->env.segs[R_GS].base = *(uint32_t *)value;
|
||||
X86_CPU(uc, mycpu)->env.segs[R_GS].selector = *(uint16_t *)value;
|
||||
break;
|
||||
case UC_X86_REG_IDTR:
|
||||
X86_CPU(uc, mycpu)->env.idt.limit = (uint16_t)((uc_x86_mmr *)value)->limit;
|
||||
X86_CPU(uc, mycpu)->env.idt.base = (uint32_t)((uc_x86_mmr *)value)->base;
|
||||
break;
|
||||
case UC_X86_REG_GDTR:
|
||||
X86_CPU(uc, mycpu)->env.gdt.limit = (uint16_t)((uc_x86_mmr *)value)->limit;
|
||||
X86_CPU(uc, mycpu)->env.gdt.base = (uint32_t)((uc_x86_mmr *)value)->base;
|
||||
break;
|
||||
case UC_X86_REG_LDTR:
|
||||
X86_CPU(uc, mycpu)->env.ldt.limit = ((uc_x86_mmr *)value)->limit;
|
||||
X86_CPU(uc, mycpu)->env.ldt.base = (uint32_t)((uc_x86_mmr *)value)->base;
|
||||
X86_CPU(uc, mycpu)->env.ldt.selector = (uint16_t)((uc_x86_mmr *)value)->selector;
|
||||
X86_CPU(uc, mycpu)->env.ldt.flags = ((uc_x86_mmr *)value)->flags;
|
||||
break;
|
||||
case UC_X86_REG_TR:
|
||||
X86_CPU(uc, mycpu)->env.tr.limit = ((uc_x86_mmr *)value)->limit;
|
||||
X86_CPU(uc, mycpu)->env.tr.base = (uint32_t)((uc_x86_mmr *)value)->base;
|
||||
X86_CPU(uc, mycpu)->env.tr.selector = (uint16_t)((uc_x86_mmr *)value)->selector;
|
||||
X86_CPU(uc, mycpu)->env.tr.flags = ((uc_x86_mmr *)value)->flags;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
@ -806,30 +945,39 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
|||
break;
|
||||
case UC_X86_REG_RIP:
|
||||
X86_CPU(uc, mycpu)->env.eip = *(uint64_t *)value;
|
||||
// force to quit execution and flush TB
|
||||
uc->quit_request = true;
|
||||
uc_emu_stop(uc);
|
||||
break;
|
||||
case UC_X86_REG_EIP:
|
||||
WRITE_DWORD(X86_CPU(uc, mycpu)->env.eip, *(uint32_t *)value);
|
||||
// force to quit execution and flush TB
|
||||
uc->quit_request = true;
|
||||
uc_emu_stop(uc);
|
||||
break;
|
||||
case UC_X86_REG_IP:
|
||||
WRITE_WORD(X86_CPU(uc, mycpu)->env.eip, *(uint16_t *)value);
|
||||
// force to quit execution and flush TB
|
||||
uc->quit_request = true;
|
||||
uc_emu_stop(uc);
|
||||
break;
|
||||
case UC_X86_REG_CS:
|
||||
X86_CPU(uc, mycpu)->env.segs[R_CS].base = *(uint64_t *)value;
|
||||
X86_CPU(uc, mycpu)->env.segs[R_CS].selector = *(uint16_t *)value;
|
||||
break;
|
||||
case UC_X86_REG_DS:
|
||||
X86_CPU(uc, mycpu)->env.segs[R_DS].base = *(uint64_t *)value;
|
||||
X86_CPU(uc, mycpu)->env.segs[R_DS].selector = *(uint16_t *)value;
|
||||
break;
|
||||
case UC_X86_REG_SS:
|
||||
X86_CPU(uc, mycpu)->env.segs[R_SS].base = *(uint64_t *)value;
|
||||
X86_CPU(uc, mycpu)->env.segs[R_SS].selector = *(uint16_t *)value;
|
||||
break;
|
||||
case UC_X86_REG_ES:
|
||||
X86_CPU(uc, mycpu)->env.segs[R_ES].base = *(uint64_t *)value;
|
||||
X86_CPU(uc, mycpu)->env.segs[R_ES].selector = *(uint16_t *)value;
|
||||
break;
|
||||
case UC_X86_REG_FS:
|
||||
X86_CPU(uc, mycpu)->env.segs[R_FS].base = *(uint64_t *)value;
|
||||
X86_CPU(uc, mycpu)->env.segs[R_FS].selector = *(uint16_t *)value;
|
||||
break;
|
||||
case UC_X86_REG_GS:
|
||||
X86_CPU(uc, mycpu)->env.segs[R_GS].base = *(uint64_t *)value;
|
||||
X86_CPU(uc, mycpu)->env.segs[R_GS].selector = *(uint16_t *)value;
|
||||
break;
|
||||
case UC_X86_REG_R8:
|
||||
X86_CPU(uc, mycpu)->env.regs[8] = *(uint64_t *)value;
|
||||
|
@ -927,6 +1075,26 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
|||
case UC_X86_REG_R15B:
|
||||
WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[15], *(uint8_t *)value);
|
||||
break;
|
||||
case UC_X86_REG_IDTR:
|
||||
X86_CPU(uc, mycpu)->env.idt.limit = (uint16_t)((uc_x86_mmr *)value)->limit;
|
||||
X86_CPU(uc, mycpu)->env.idt.base = ((uc_x86_mmr *)value)->base;
|
||||
break;
|
||||
case UC_X86_REG_GDTR:
|
||||
X86_CPU(uc, mycpu)->env.gdt.limit = (uint16_t)((uc_x86_mmr *)value)->limit;
|
||||
X86_CPU(uc, mycpu)->env.gdt.base = ((uc_x86_mmr *)value)->base;
|
||||
break;
|
||||
case UC_X86_REG_LDTR:
|
||||
X86_CPU(uc, mycpu)->env.ldt.limit = ((uc_x86_mmr *)value)->limit;
|
||||
X86_CPU(uc, mycpu)->env.ldt.base = ((uc_x86_mmr *)value)->base;
|
||||
X86_CPU(uc, mycpu)->env.ldt.selector = (uint16_t)((uc_x86_mmr *)value)->selector;
|
||||
X86_CPU(uc, mycpu)->env.ldt.flags = ((uc_x86_mmr *)value)->flags;
|
||||
break;
|
||||
case UC_X86_REG_TR:
|
||||
X86_CPU(uc, mycpu)->env.tr.limit = ((uc_x86_mmr *)value)->limit;
|
||||
X86_CPU(uc, mycpu)->env.tr.base = ((uc_x86_mmr *)value)->base;
|
||||
X86_CPU(uc, mycpu)->env.tr.selector = (uint16_t)((uc_x86_mmr *)value)->selector;
|
||||
X86_CPU(uc, mycpu)->env.tr.flags = ((uc_x86_mmr *)value)->flags;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr)
|
||||
DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64)
|
||||
|
||||
DEF_HELPER_1(bitrev, i32, i32)
|
||||
DEF_HELPER_1(ff1, i32, i32)
|
||||
|
|
|
@ -3043,11 +3043,8 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s)
|
|||
}
|
||||
|
||||
// Unicorn: trace this instruction on request
|
||||
if (env->uc->hook_insn) {
|
||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, s->pc);
|
||||
if (trace)
|
||||
gen_uc_tracecode(tcg_ctx, 2, trace->callback, env->uc, s->pc, trace->user_data);
|
||||
|
||||
if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, s->pc)) {
|
||||
gen_uc_tracecode(tcg_ctx, 2, UC_HOOK_CODE_IDX, env->uc, s->pc);
|
||||
// the callback might want to stop emulation immediately
|
||||
check_exit_request(tcg_ctx);
|
||||
}
|
||||
|
@ -3109,13 +3106,10 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb,
|
|||
// Unicorn: trace this block on request
|
||||
// Only hook this block if it is not broken from previous translation due to
|
||||
// full translation cache
|
||||
if (env->uc->hook_block && !env->uc->block_full) {
|
||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start);
|
||||
if (trace) {
|
||||
// save block address to see if we need to patch block size later
|
||||
env->uc->block_addr = pc_start;
|
||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data);
|
||||
}
|
||||
if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) {
|
||||
// save block address to see if we need to patch block size later
|
||||
env->uc->block_addr = pc_start;
|
||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start);
|
||||
}
|
||||
|
||||
gen_tb_start(tcg_ctx);
|
||||
|
|
|
@ -6,14 +6,8 @@
|
|||
#include "sysemu/cpus.h"
|
||||
#include "unicorn.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#include "unicorn_common.h"
|
||||
|
||||
#define READ_QWORD(x) ((uint64)x)
|
||||
#define READ_DWORD(x) (x & 0xffffffff)
|
||||
#define READ_WORD(x) (x & 0xffff)
|
||||
#define READ_BYTE_H(x) ((x & 0xffff) >> 8)
|
||||
#define READ_BYTE_L(x) (x & 0xff)
|
||||
#include "uc_priv.h"
|
||||
|
||||
|
||||
static void m68k_set_pc(struct uc_struct *uc, uint64_t address)
|
||||
|
@ -51,12 +45,6 @@ int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff))
|
||||
#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff))
|
||||
#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff))
|
||||
#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff))
|
||||
|
||||
int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
||||
{
|
||||
CPUState *mycpu = first_cpu;
|
||||
|
@ -70,6 +58,9 @@ int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
|||
default: break;
|
||||
case UC_M68K_REG_PC:
|
||||
M68K_CPU(uc, mycpu)->env.pc = *(uint32_t *)value;
|
||||
// force to quit execution and flush TB
|
||||
uc->quit_request = true;
|
||||
uc_emu_stop(uc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr)
|
||||
DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64)
|
||||
|
||||
DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int)
|
||||
DEF_HELPER_2(raise_exception, noreturn, env, i32)
|
||||
|
|
|
@ -11343,12 +11343,9 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, bool *insn_n
|
|||
n_bytes = 2;
|
||||
|
||||
// Unicorn: trace this instruction on request
|
||||
if (env->uc->hook_insn) {
|
||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc);
|
||||
if (trace) {
|
||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data);
|
||||
*insn_need_patch = true;
|
||||
}
|
||||
if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, ctx->pc)) {
|
||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_CODE_IDX, env->uc, ctx->pc);
|
||||
*insn_need_patch = true;
|
||||
// the callback might want to stop emulation immediately
|
||||
check_exit_request(tcg_ctx);
|
||||
}
|
||||
|
@ -13942,12 +13939,9 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, bool *ins
|
|||
}
|
||||
|
||||
// Unicorn: trace this instruction on request
|
||||
if (env->uc->hook_insn) {
|
||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc);
|
||||
if (trace) {
|
||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data);
|
||||
*insn_need_patch = true;
|
||||
}
|
||||
if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, ctx->pc)) {
|
||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_CODE_IDX, env->uc, ctx->pc);
|
||||
*insn_need_patch = true;
|
||||
// the callback might want to stop emulation immediately
|
||||
check_exit_request(tcg_ctx);
|
||||
}
|
||||
|
@ -18504,13 +18498,10 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx)
|
|||
// Unicorn: trace this instruction on request
|
||||
static void hook_insn(CPUMIPSState *env, DisasContext *ctx, bool *insn_need_patch, int *insn_patch_offset, int offset_value)
|
||||
{
|
||||
if (env->uc->hook_insn) {
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc);
|
||||
if (trace) {
|
||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data);
|
||||
*insn_need_patch = true;
|
||||
}
|
||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||
if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, ctx->pc)) {
|
||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_CODE_IDX, env->uc, ctx->pc);
|
||||
*insn_need_patch = true;
|
||||
// the callback might want to stop emulation immediately
|
||||
check_exit_request(tcg_ctx);
|
||||
*insn_patch_offset = offset_value;
|
||||
|
@ -19223,13 +19214,10 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
|
|||
// Unicorn: trace this block on request
|
||||
// Only hook this block if it is not broken from previous translation due to
|
||||
// full translation cache
|
||||
if (env->uc->hook_block && !env->uc->block_full) {
|
||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start);
|
||||
if (trace) {
|
||||
// save block address to see if we need to patch block size later
|
||||
env->uc->block_addr = pc_start;
|
||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data);
|
||||
}
|
||||
if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) {
|
||||
// save block address to see if we need to patch block size later
|
||||
env->uc->block_addr = pc_start;
|
||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start);
|
||||
}
|
||||
|
||||
gen_tb_start(tcg_ctx);
|
||||
|
@ -19275,7 +19263,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
|
|||
int insn_patch_offset = 1;
|
||||
|
||||
// Unicorn: save param buffer
|
||||
if (env->uc->hook_insn)
|
||||
if (HOOK_EXISTS(env->uc, UC_HOOK_CODE))
|
||||
save_opparam_ptr = tcg_ctx->gen_opparam_ptr;
|
||||
|
||||
is_slot = ctx.hflags & MIPS_HFLAG_BMASK;
|
||||
|
|
|
@ -6,15 +6,8 @@
|
|||
#include "sysemu/cpus.h"
|
||||
#include "unicorn.h"
|
||||
#include "cpu.h"
|
||||
|
||||
#include "unicorn_common.h"
|
||||
|
||||
|
||||
#define READ_QWORD(x) ((uint64)x)
|
||||
#define READ_DWORD(x) (x & 0xffffffff)
|
||||
#define READ_WORD(x) (x & 0xffff)
|
||||
#define READ_BYTE_H(x) ((x & 0xffff) >> 8)
|
||||
#define READ_BYTE_L(x) (x & 0xff)
|
||||
#include "uc_priv.h"
|
||||
|
||||
|
||||
static uint64_t mips_mem_redirect(uint64_t address)
|
||||
|
@ -64,12 +57,6 @@ int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff))
|
||||
#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff))
|
||||
#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff))
|
||||
#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff))
|
||||
|
||||
int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
||||
{
|
||||
CPUState *mycpu = first_cpu;
|
||||
|
@ -81,6 +68,9 @@ int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
|||
default: break;
|
||||
case UC_MIPS_REG_PC:
|
||||
MIPS_CPU(uc, mycpu)->env.active_tc.PC = *(uint32_t *)value;
|
||||
// force to quit execution and flush TB
|
||||
uc->quit_request = true;
|
||||
uc_emu_stop(uc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr)
|
||||
DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64)
|
||||
DEF_HELPER_1(power_down, void, env)
|
||||
|
||||
#ifndef TARGET_SPARC64
|
||||
|
|
|
@ -2630,18 +2630,9 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn, bool hook_ins
|
|||
tcg_gen_debug_insn_start(tcg_ctx, dc->pc);
|
||||
}
|
||||
|
||||
// end address tells us to stop emulation
|
||||
if (dc->pc == dc->uc->addr_end) {
|
||||
insn = 0x91d02000; // generate TRAP to end this TB
|
||||
hook_insn = false; // do not hook this instruction
|
||||
}
|
||||
|
||||
// Unicorn: trace this instruction on request
|
||||
if (hook_insn && dc->uc->hook_insn) {
|
||||
struct hook_struct *trace = hook_find(dc->uc, UC_HOOK_CODE, dc->pc);
|
||||
if (trace)
|
||||
gen_uc_tracecode(tcg_ctx, 4, trace->callback, dc->uc, dc->pc, trace->user_data);
|
||||
|
||||
if (hook_insn && HOOK_EXISTS_BOUNDED(dc->uc, UC_HOOK_CODE, dc->pc)) {
|
||||
gen_uc_tracecode(tcg_ctx, 4, UC_HOOK_CODE_IDX, dc->uc, dc->pc);
|
||||
// the callback might want to stop emulation immediately
|
||||
check_exit_request(tcg_ctx);
|
||||
}
|
||||
|
@ -5408,9 +5399,8 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu,
|
|||
// early check to see if the address of this block is the until address
|
||||
if (pc_start == env->uc->addr_end) {
|
||||
gen_tb_start(tcg_ctx);
|
||||
insn = 0x91d02000; // generate TRAP to end this TB
|
||||
disas_sparc_insn(dc, insn, false);
|
||||
goto exit_gen_loop;
|
||||
gen_helper_power_down(tcg_ctx, tcg_ctx->cpu_env);
|
||||
goto done_generating;
|
||||
}
|
||||
|
||||
max_insns = tb->cflags & CF_COUNT_MASK;
|
||||
|
@ -5428,13 +5418,10 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu,
|
|||
// Unicorn: trace this block on request
|
||||
// Only hook this block if it is not broken from previous translation due to
|
||||
// full translation cache
|
||||
if (env->uc->hook_block && !env->uc->block_full) {
|
||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start);
|
||||
if (trace) {
|
||||
// save block address to see if we need to patch block size later
|
||||
env->uc->block_addr = pc_start;
|
||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data);
|
||||
}
|
||||
if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) {
|
||||
// save block address to see if we need to patch block size later
|
||||
env->uc->block_addr = pc_start;
|
||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start);
|
||||
}
|
||||
|
||||
gen_tb_start(tcg_ctx);
|
||||
|
|
|
@ -7,13 +7,7 @@
|
|||
#include "unicorn.h"
|
||||
#include "cpu.h"
|
||||
#include "unicorn_common.h"
|
||||
|
||||
|
||||
#define READ_QWORD(x) ((uint64)x)
|
||||
#define READ_DWORD(x) (x & 0xffffffff)
|
||||
#define READ_WORD(x) (x & 0xffff)
|
||||
#define READ_BYTE_H(x) ((x & 0xffff) >> 8)
|
||||
#define READ_BYTE_L(x) (x & 0xff)
|
||||
#include "uc_priv.h"
|
||||
|
||||
|
||||
static bool sparc_stop_interrupt(int intno)
|
||||
|
@ -87,6 +81,9 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
|||
case UC_SPARC_REG_PC:
|
||||
SPARC_CPU(uc, mycpu)->env.pc = *(uint32_t *)value;
|
||||
SPARC_CPU(uc, mycpu)->env.npc = *(uint32_t *)value + 4;
|
||||
// force to quit execution and flush TB
|
||||
uc->quit_request = true;
|
||||
uc_emu_stop(uc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,13 +7,7 @@
|
|||
#include "unicorn.h"
|
||||
#include "cpu.h"
|
||||
#include "unicorn_common.h"
|
||||
|
||||
|
||||
#define READ_QWORD(x) ((uint64)x)
|
||||
#define READ_DWORD(x) (x & 0xffffffff)
|
||||
#define READ_WORD(x) (x & 0xffff)
|
||||
#define READ_BYTE_H(x) ((x & 0xffff) >> 8)
|
||||
#define READ_BYTE_L(x) (x & 0xff)
|
||||
#include "uc_priv.h"
|
||||
|
||||
|
||||
static bool sparc_stop_interrupt(int intno)
|
||||
|
|
|
@ -1209,7 +1209,7 @@ static inline void tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
|
|||
tcg_out_mov(s, ttype, r1, addrlo);
|
||||
|
||||
// Unicorn: fast path if hookmem is not enable
|
||||
if (!s->uc->hook_mem_read && !s->uc->hook_mem_write)
|
||||
if (!HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ) && !HOOK_EXISTS(s->uc, UC_HOOK_MEM_WRITE))
|
||||
tcg_out_opc(s, OPC_JCC_long + JCC_JNE, 0, 0, 0);
|
||||
else
|
||||
tcg_out_opc(s, OPC_JMP_long, 0, 0, 0); /* slow_path */
|
||||
|
|
|
@ -27,14 +27,13 @@
|
|||
|
||||
int gen_new_label(TCGContext *);
|
||||
|
||||
static inline void gen_uc_tracecode(TCGContext *tcg_ctx, int32_t size, void *callback, void *uc, uint64_t pc, void *data)
|
||||
static inline void gen_uc_tracecode(TCGContext *tcg_ctx, int32_t size, int32_t type, void *uc, uint64_t pc)
|
||||
{
|
||||
TCGv_i32 tsize = tcg_const_i32(tcg_ctx, size);
|
||||
TCGv_ptr tcallback = tcg_const_ptr(tcg_ctx, callback);
|
||||
TCGv_i32 ttype = tcg_const_i32(tcg_ctx, type);
|
||||
TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, uc);
|
||||
TCGv_i64 tpc = tcg_const_i64(tcg_ctx, pc);
|
||||
TCGv_ptr tdata = tcg_const_ptr(tcg_ctx, data);
|
||||
gen_helper_uc_tracecode(tcg_ctx, tsize, tcallback, tuc, tpc, tdata);
|
||||
gen_helper_uc_tracecode(tcg_ctx, tsize, ttype, tuc, tpc);
|
||||
}
|
||||
|
||||
static inline void tcg_gen_op0(TCGContext *s, TCGOpcode opc)
|
||||
|
|
|
@ -179,7 +179,7 @@ static int cpu_gen_code(CPUArchState *env, TranslationBlock *tb, int *gen_code_s
|
|||
gen_intermediate_code(env, tb);
|
||||
|
||||
// Unicorn: when tracing block, patch 1st operand for block size
|
||||
if (env->uc->hook_block && env->uc->block_addr == tb->pc) {
|
||||
if (env->uc->block_addr == tb->pc && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, tb->pc)) {
|
||||
if (env->uc->block_full) // block size is unknown
|
||||
*(s->gen_opparam_buf + 1) = 0;
|
||||
else
|
||||
|
|
|
@ -29,8 +29,8 @@
|
|||
|
||||
static void error_exit(int err, const char *msg)
|
||||
{
|
||||
// fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err));
|
||||
// abort();
|
||||
fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err));
|
||||
abort();
|
||||
}
|
||||
|
||||
void qemu_mutex_init(QemuMutex *mutex)
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||
#ifndef UNICORN_AUTOGEN_X86_64_H
|
||||
#define UNICORN_AUTOGEN_X86_64_H
|
||||
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_x86_64
|
||||
#define use_idiv_instructions_rt use_idiv_instructions_rt_x86_64
|
||||
#define tcg_target_deposit_valid tcg_target_deposit_valid_x86_64
|
||||
#define helper_power_down helper_power_down_x86_64
|
||||
|
|
|
@ -142,13 +142,13 @@ static void do_nx_demo(bool cause_fault)
|
|||
|
||||
/*
|
||||
bits 32
|
||||
page0:
|
||||
page0: @0
|
||||
times 4091 inc eax
|
||||
jmp page2
|
||||
page1:
|
||||
times 4095 inc eax
|
||||
page1: @1000
|
||||
times 4095 inc eax (or INC ECX)
|
||||
hlt
|
||||
page2:
|
||||
page2: @2000
|
||||
jmp page1
|
||||
*/
|
||||
memset(code_buf, 0x40, sizeof(code_buf)); // fill with inc eax
|
||||
|
@ -168,9 +168,9 @@ 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, (uint64_t)1, (uint64_t)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) != UC_ERR_OK) {
|
||||
hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) {
|
||||
printf("not ok - Failed to install hooks\n");
|
||||
return;
|
||||
}
|
||||
|
@ -248,10 +248,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, (uint64_t)1, (uint64_t)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) != UC_ERR_OK) {
|
||||
hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) {
|
||||
printf("not ok - Failed to install hooks\n");
|
||||
return;
|
||||
}
|
||||
|
@ -326,10 +326,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, (uint64_t)1, (uint64_t)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) != UC_ERR_OK) {
|
||||
hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) {
|
||||
printf("not ok - Failed to install hooks\n");
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -77,10 +77,10 @@ static void test_arm(void)
|
|||
uc_reg_write(uc, UC_ARM_REG_R3, &r3);
|
||||
|
||||
// tracing all basic blocks with customized callback
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
||||
|
||||
// tracing one instruction at ADDRESS with customized callback
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS);
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS);
|
||||
|
||||
// emulate machine code in infinite time (last param = 0), or when
|
||||
// finishing all the code.
|
||||
|
@ -128,10 +128,10 @@ static void test_thumb(void)
|
|||
uc_reg_write(uc, UC_ARM_REG_SP, &sp);
|
||||
|
||||
// tracing all basic blocks with customized callback
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
||||
|
||||
// tracing one instruction at ADDRESS with customized callback
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS);
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS);
|
||||
|
||||
// emulate machine code in infinite time (last param = 0), or when
|
||||
// finishing all the code.
|
||||
|
|
|
@ -75,10 +75,10 @@ static void test_arm64(void)
|
|||
uc_reg_write(uc, UC_ARM64_REG_X15, &x15);
|
||||
|
||||
// tracing all basic blocks with customized callback
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
||||
|
||||
// tracing one instruction at ADDRESS with customized callback
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS);
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS);
|
||||
|
||||
// emulate machine code in infinite time (last param = 0), or when
|
||||
// finishing all the code.
|
||||
|
|
|
@ -108,10 +108,10 @@ static void test_m68k(void)
|
|||
uc_reg_write(uc, UC_M68K_REG_SR, &sr);
|
||||
|
||||
// tracing all basic blocks with customized callback
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
||||
|
||||
// tracing all instruction
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0);
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
||||
|
||||
// emulate machine code in infinite time (last param = 0), or when
|
||||
// finishing all the code.
|
||||
|
|
|
@ -72,10 +72,10 @@ static void test_mips_eb(void)
|
|||
uc_reg_write(uc, UC_MIPS_REG_1, &r1);
|
||||
|
||||
// tracing all basic blocks with customized callback
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
||||
|
||||
// tracing one instruction at ADDRESS with customized callback
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS);
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS);
|
||||
|
||||
// emulate machine code in infinite time (last param = 0), or when
|
||||
// finishing all the code.
|
||||
|
@ -105,7 +105,7 @@ static void test_mips_el(void)
|
|||
printf("Emulate MIPS code (little-endian)\n");
|
||||
|
||||
// Initialize emulator in MIPS mode
|
||||
err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc);
|
||||
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));
|
||||
|
@ -122,10 +122,10 @@ static void test_mips_el(void)
|
|||
uc_reg_write(uc, UC_MIPS_REG_1, &r1);
|
||||
|
||||
// tracing all basic blocks with customized callback
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
||||
|
||||
// tracing one instruction at ADDRESS with customized callback
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS);
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, ADDRESS, ADDRESS);
|
||||
|
||||
// emulate machine code in infinite time (last param = 0), or when
|
||||
// finishing all the code.
|
||||
|
|
|
@ -57,7 +57,7 @@ static void test_sparc(void)
|
|||
printf("Emulate SPARC code\n");
|
||||
|
||||
// Initialize emulator in Sparc mode
|
||||
err = uc_open(UC_ARCH_SPARC, UC_MODE_32, &uc);
|
||||
err = uc_open(UC_ARCH_SPARC, UC_MODE_SPARC32|UC_MODE_BIG_ENDIAN, &uc);
|
||||
if (err) {
|
||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||
err, uc_strerror(err));
|
||||
|
@ -76,10 +76,10 @@ static void test_sparc(void)
|
|||
uc_reg_write(uc, UC_SPARC_REG_G3, &g3);
|
||||
|
||||
// tracing all basic blocks with customized callback
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
||||
|
||||
// tracing all instructions with customized callback
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0);
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
||||
|
||||
// emulate machine code in infinite time (last param = 0), or when
|
||||
// finishing all the code.
|
||||
|
|
|
@ -219,10 +219,10 @@ static void test_i386(void)
|
|||
uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
|
||||
|
||||
// tracing all basic blocks with customized callback
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
||||
|
||||
// tracing all instruction by having @begin > @end
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0);
|
||||
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) - 1, 0, 0);
|
||||
|
@ -289,10 +289,10 @@ static void test_i386_map_ptr(void)
|
|||
uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
|
||||
|
||||
// tracing all basic blocks with customized callback
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
||||
|
||||
// tracing all instruction by having @begin > @end
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0);
|
||||
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) - 1, 0, 0);
|
||||
|
@ -345,10 +345,10 @@ static void test_i386_jump(void)
|
|||
}
|
||||
|
||||
// tracing 1 basic block with customized callback
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS);
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, ADDRESS, ADDRESS);
|
||||
|
||||
// tracing 1 instruction at ADDRESS
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)ADDRESS, (uint64_t)ADDRESS);
|
||||
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);
|
||||
|
@ -447,10 +447,10 @@ static void test_i386_invalid_mem_read(void)
|
|||
uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
|
||||
|
||||
// tracing all basic blocks with customized callback
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
||||
|
||||
// tracing all instruction by having @begin > @end
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0);
|
||||
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);
|
||||
|
@ -505,13 +505,13 @@ static void test_i386_invalid_mem_write(void)
|
|||
uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
|
||||
|
||||
// tracing all basic blocks with customized callback
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
||||
|
||||
// tracing all instruction by having @begin > @end
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0);
|
||||
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);
|
||||
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);
|
||||
|
@ -576,10 +576,10 @@ static void test_i386_jump_invalid(void)
|
|||
uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
|
||||
|
||||
// tracing all basic blocks with customized callback
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
||||
|
||||
// tracing all instructions by having @begin > @end
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0);
|
||||
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);
|
||||
|
@ -632,15 +632,15 @@ static void test_i386_inout(void)
|
|||
uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx);
|
||||
|
||||
// tracing all basic blocks with customized callback
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, 1, 0);
|
||||
|
||||
// tracing all instructions
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0);
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
||||
|
||||
// uc IN instruction
|
||||
uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_in, NULL, UC_X86_INS_IN);
|
||||
uc_hook_add(uc, &trace3, UC_HOOK_INSN, hook_in, NULL, 1, 0, UC_X86_INS_IN);
|
||||
// uc OUT instruction
|
||||
uc_hook_add(uc, &trace4, UC_HOOK_INSN, hook_out, NULL, 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);
|
||||
|
@ -721,16 +721,16 @@ static void test_x86_64(void)
|
|||
uc_reg_write(uc, UC_X86_REG_R15, &r15);
|
||||
|
||||
// tracing all basic blocks with customized callback
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0);
|
||||
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, (uint64_t)ADDRESS, (uint64_t)(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, (uint64_t)1, (uint64_t)0);
|
||||
uc_hook_add(uc, &trace3, UC_HOOK_MEM_WRITE, hook_mem64, NULL, 1, 0);
|
||||
|
||||
// tracing all memory READ access (with @begin > @end)
|
||||
uc_hook_add(uc, &trace4, UC_HOOK_MEM_READ, hook_mem64, NULL, (uint64_t)1, (uint64_t)0);
|
||||
uc_hook_add(uc, &trace4, UC_HOOK_MEM_READ, hook_mem64, NULL, 1, 0);
|
||||
|
||||
// emulate machine code in infinite time (last param = 0), or when
|
||||
// finishing all the code.
|
||||
|
@ -804,7 +804,7 @@ static void test_x86_64_syscall(void)
|
|||
}
|
||||
|
||||
// hook interrupts for syscall
|
||||
uc_hook_add(uc, &trace1, UC_HOOK_INSN, hook_syscall, NULL, 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);
|
||||
|
|
|
@ -138,7 +138,7 @@ static void test_i386(void)
|
|||
uc_hook_add(uc, &trace1, UC_HOOK_CODE, hook_code, NULL, 1, 0);
|
||||
|
||||
// handle interrupt ourself
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_INTR, hook_intr, NULL);
|
||||
uc_hook_add(uc, &trace2, UC_HOOK_INTR, hook_intr, NULL, 1, 0);
|
||||
|
||||
printf("\n>>> Start tracing this Linux code\n");
|
||||
|
||||
|
|
30
tests/regress/LICENSE
Normal file
30
tests/regress/LICENSE
Normal file
|
@ -0,0 +1,30 @@
|
|||
This is the software license for Unicorn regression tests. The regression tests
|
||||
are written by several Unicorn contributors (See CREDITS.TXT) and maintained by
|
||||
Hoang-Vu Dang <dang.hvu@gmail.com>
|
||||
|
||||
Copyright (c) 2015, Unicorn contributors
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
* Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
* Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
* Neither the name of the developer(s) nor the names of its
|
||||
contributors may be used to endorse or promote products derived from this
|
||||
software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
POSSIBILITY OF SUCH DAMAGE.
|
|
@ -37,6 +37,7 @@ TESTS += mips_branch_likely_issue
|
|||
TESTS += hook_extrainvoke
|
||||
TESTS += sysenter_hook_x86
|
||||
TESTS += emu_clear_errors
|
||||
TESTS += mem_fuzz
|
||||
|
||||
all: $(TESTS)
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue