Merge remote-tracking branch 'upstream/master' into change-handle-based-api

# Conflicts:
#	qemu/target-i386/unicorn.c
This commit is contained in:
Jonathon Reinhart 2015-09-01 13:17:03 -04:00
commit 2c802a3e4b
17 changed files with 504 additions and 77 deletions

2
.gitignore vendored
View file

@ -87,3 +87,5 @@ regress/block_test
regress/map_write regress/map_write
regress/ro_mem_test regress/ro_mem_test
regress/nr_mem_test regress/nr_mem_test
regress/timeout_segfault
regress/rep_movsb

View file

@ -66,11 +66,11 @@ Unicorn requires few dependent packages as followings
- To compile for current platform, run: - To compile for current platform, run:
$ ./make.sh $ ./make.sh
- On 64-bit OS, run the command below to cross-compile Unicorn for 32-bit binary: - On 64-bit OS, run the command below to cross-compile Unicorn for 32-bit binary:
$ ./make.sh nix32 $ ./make.sh nix32
@ -78,32 +78,32 @@ Unicorn requires few dependent packages as followings
To install Unicorn, run: To install Unicorn, run:
$ sudo ./make.sh install $ sudo ./make.sh install
For FreeBSD/OpenBSD, where sudo is unavailable, run: For FreeBSD/OpenBSD, where sudo is unavailable, run:
$ su; ./make.sh install $ su; ./make.sh install
Users are then required to enter root password to copy Unicorn into machine Users are then required to enter root password to copy Unicorn into machine
system directories. system directories.
Afterwards, run ./tests/test* to see the tests disassembling sample code. Afterwards, run ./samples/sample_all.sh to see the sample emulations.
NOTE: The core framework installed by "./make.sh install" consist of NOTE: The core framework installed by "./make.sh install" consist of
following files: following files:
/usr/include/unicorn/unicorn.h /usr/include/unicorn/unicorn.h
/usr/include/unicorn/x86.h /usr/include/unicorn/x86.h
/usr/include/unicorn/arm.h /usr/include/unicorn/arm.h
/usr/include/unicorn/arm64.h /usr/include/unicorn/arm64.h
/usr/include/unicorn/mips.h /usr/include/unicorn/mips.h
/usr/include/unicorn/ppc.h /usr/include/unicorn/ppc.h
/usr/include/unicorn/sparc.h /usr/include/unicorn/sparc.h
/usr/include/unicorn/m68k.h /usr/include/unicorn/m68k.h
/usr/include/unicorn/platform.h /usr/include/unicorn/platform.h
/usr/lib/libunicorn.so (for Linux/*nix), or /usr/lib/libunicorn.dylib (OSX) /usr/lib/libunicorn.so (for Linux/*nix), or /usr/lib/libunicorn.dylib (OSX)
/usr/lib/libunicorn.a /usr/lib/libunicorn.a
@ -112,19 +112,18 @@ Unicorn requires few dependent packages as followings
To cross-compile for Windows, Linux & gcc-mingw-w64-i686 (and also gcc-mingw-w64-x86-64 To cross-compile for Windows, Linux & gcc-mingw-w64-i686 (and also gcc-mingw-w64-x86-64
for 64-bit binaries) are required. for 64-bit binaries) are required.
- To cross-compile Windows 32-bit binary, simply run: - To cross-compile Windows 32-bit binary, simply run:
$ ./make.sh cross-win32 $ ./make.sh cross-win32
- To cross-compile Windows 64-bit binary, run: - To cross-compile Windows 64-bit binary, run:
$ ./make.sh cross-win64 $ ./make.sh cross-win64
Resulted files libunicorn.dll, libunicorn.dll.a & tests/test*.exe can then Resulted files unicorn.dll, unicorn.lib & samples/sample*.exe can then
be used on Windows machine. be used on Windows machine.
To run sample_x86.exe on Windows 32-bit, you need the following files: To run sample_x86.exe on Windows 32-bit, you need the following files:
- unicorn.dll - unicorn.dll
- /usr/i686-w64-mingw32/sys-root/mingw/bin/libglib-2.0-0.dll - /usr/i686-w64-mingw32/sys-root/mingw/bin/libglib-2.0-0.dll
- /usr/lib/gcc/i686-w64-mingw32/4.8/libgcc_s_sjlj-1.dll - /usr/lib/gcc/i686-w64-mingw32/4.8/libgcc_s_sjlj-1.dll
@ -145,17 +144,17 @@ Unicorn requires few dependent packages as followings
To cross-compile for iOS (iPhone/iPad/iPod), Mac OSX with XCode installed is required. To cross-compile for iOS (iPhone/iPad/iPod), Mac OSX with XCode installed is required.
- To cross-compile for ArmV7 (iPod 4, iPad 1/2/3, iPhone4, iPhone4S), run: - To cross-compile for ArmV7 (iPod 4, iPad 1/2/3, iPhone4, iPhone4S), run:
$ ./make.sh ios_armv7 $ ./make.sh ios_armv7
- To cross-compile for ArmV7s (iPad 4, iPhone 5C, iPad mini), run: - To cross-compile for ArmV7s (iPad 4, iPhone 5C, iPad mini), run:
$ ./make.sh ios_armv7s $ ./make.sh ios_armv7s
- To cross-compile for Arm64 (iPhone 5S, iPad mini Retina, iPad Air), run: - To cross-compile for Arm64 (iPhone 5S, iPad mini Retina, iPad Air), run:
$ ./make.sh ios_arm64 $ ./make.sh ios_arm64
- To cross-compile for all iDevices (armv7 + armv7s + arm64), run: - To cross-compile for all iDevices (armv7 + armv7s + arm64), run:
$ ./make.sh ios $ ./make.sh ios
Resulted files libunicorn.dylib, libunicorn.a & tests/test* can then Resulted files libunicorn.dylib, libunicorn.a & tests/test* can then
be used on iOS devices. be used on iOS devices.
@ -167,47 +166,69 @@ Unicorn requires few dependent packages as followings
To cross-compile for Android (smartphone/tablet), Android NDK is required. To cross-compile for Android (smartphone/tablet), Android NDK is required.
NOTE: Only ARM and ARM64 are currently supported. NOTE: Only ARM and ARM64 are currently supported.
$ NDK=/android/android-ndk-r10e ./make.sh cross-android arm $ NDK=/android/android-ndk-r10e ./make.sh cross-android arm
or or
$ NDK=/android/android-ndk-r10e ./make.sh cross-android arm64 $ NDK=/android/android-ndk-r10e ./make.sh cross-android arm64
Resulted files libunicorn.so, libunicorn.a & tests/test* can then Resulted files libunicorn.so, libunicorn.a & tests/test* can then
be used on Android devices. be used on Android devices.
[7] Compile on Windows with Cygwin [7] Compile on Windows with MinGW (MSYS2)
To compile under Cygwin gcc-mingw-w64-i686 or x86_64-w64-mingw32 run: To compile with MinGW you need to install MSYS2: https://msys2.github.io/
Follow the install instructions and don't forget to update the system packages as written in 5 & 6 paragraphs
- To compile Windows 32-bit binary with MinGW, run:
$ pacman -S make
$ pacman -S pkg-config
$ pacman -S mingw-w64-i686-glib2
$ pacman -S mingw-w64-i686-toolchain
$ ./make.sh cross-win32
- To compile Windows 32-bit binary under Cygwin, run: - To compile Windows 64-bit binary with MinGW, run:
$ pacman -S make
$ pacman -S pkg-config
$ pacman -S mingw-w64-x86_64-glib2
$ pacman -S mingw-w64-x86_64-toolchain
$ ./make.sh cross-win64
$ ./make.sh cygwin-mingw32 Resulted files unicorn.dll, unicorn.lib & samples/sample*.exe can then
- To compile Windows 64-bit binary under Cygwin, run:
$ ./make.sh cygwin-mingw64
Resulted files libunicorn.dll, libunicorn.dll.a & tests/test*.exe can then
be used on Windows machine. be used on Windows machine.
To run sample_x86.exe on Windows 32-bit, you need the following files:
- unicorn.dll
- %MSYS2%\mingw32\bin\libiconv-2.dll
- %MSYS2%\mingw32\bin\libintl-8.dll
- %MSYS2%\mingw32\bin\libglib-2.0-0.dll
- %MSYS2%\mingw32\bin\libgcc_s_dw2-1.dll
- %MSYS2%\mingw32\bin\libwinpthread-1.dll
To run sample_x86.exe on Windows 64-bit, you need the following files:
- unicorn.dll
- %MSYS2%\mingw64\bin\libiconv-2.dll
- %MSYS2%\mingw64\bin\libintl-8.dll
- %MSYS2%\mingw64\bin\libglib-2.0-0.dll
- %MSYS2%\mingw64\bin\libgcc_s_seh-1.dll
- %MSYS2%\mingw64\bin\libwinpthread-1.dll
[8] By default, "cc" (default C compiler on the system) is used as compiler. [8] By default, "cc" (default C compiler on the system) is used as compiler.
- To use "clang" compiler instead, run the command below: - To use "clang" compiler instead, run the command below:
$ ./make.sh clang $ ./make.sh clang
- To use "gcc" compiler instead, run: - To use "gcc" compiler instead, run:
$ ./make.sh gcc $ ./make.sh gcc
[9] To uninstall Unicorn, run the command below: [9] To uninstall Unicorn, run the command below:
$ sudo ./make.sh uninstall $ sudo ./make.sh uninstall

View file

@ -37,6 +37,8 @@ Luke Burnett
Parker Thompson Parker Thompson
Daniel Godas-Lopez Daniel Godas-Lopez
Antonio "s4tan" Parata Antonio "s4tan" Parata
Corey Kallenberg
Shift
Contributors (in no particular order) Contributors (in no particular order)
===================================== =====================================

View file

@ -17,6 +17,10 @@ void hookMemAccess_cgo(uch handle, uc_mem_type type, uint64_t addr, int size, in
hookMemAccess(handle, type, addr, size, value, user); hookMemAccess(handle, type, addr, size, value, user);
} }
void hookInterrupt_cgo(uch handle, uint32_t intno, void *user) {
hookInterrupt(handle, intno, user);
}
uint32_t hookX86In_cgo(uch handle, uint32_t port, uint32_t size, void *user) { uint32_t hookX86In_cgo(uch handle, uint32_t port, uint32_t size, void *user) {
return hookX86In(handle, port, size, user); return hookX86In(handle, port, size, user);
} }

View file

@ -17,33 +17,39 @@ type HookData struct {
} }
//export hookCode //export hookCode
func hookCode(handle C.uch, addr C.uint64_t, size C.uint32_t, user unsafe.Pointer) { func hookCode(handle C.uch, addr uint64, size uint32, user unsafe.Pointer) {
hook := (*HookData)(user) hook := (*HookData)(user)
hook.Callback.(func(*Uc, uint64, uint32))(hook.Uc, uint64(addr), uint32(size)) hook.Callback.(func(*Uc, uint64, uint32))(hook.Uc, uint64(addr), uint32(size))
} }
//export hookMemInvalid //export hookMemInvalid
func hookMemInvalid(handle C.uch, typ C.uc_mem_type, addr C.uint64_t, size int, value C.int64_t, user unsafe.Pointer) C.bool { func hookMemInvalid(handle C.uch, typ C.uc_mem_type, addr uint64, size int, value int64, user unsafe.Pointer) bool {
hook := (*HookData)(user) hook := (*HookData)(user)
return C.bool(hook.Callback.(func(*Uc, int, uint64, int, int64) bool)(hook.Uc, int(typ), uint64(addr), size, int64(value))) return hook.Callback.(func(*Uc, int, uint64, int, int64) bool)(hook.Uc, int(typ), addr, size, value)
} }
//export hookMemAccess //export hookMemAccess
func hookMemAccess(handle C.uch, typ C.uc_mem_type, addr C.uint64_t, size int, value C.int64_t, user unsafe.Pointer) { func hookMemAccess(handle C.uch, typ C.uc_mem_type, addr uint64, size int, value int64, user unsafe.Pointer) {
hook := (*HookData)(user) hook := (*HookData)(user)
hook.Callback.(func(*Uc, int, uint64, int, int64))(hook.Uc, int(typ), uint64(addr), size, int64(value)) hook.Callback.(func(*Uc, int, uint64, int, int64))(hook.Uc, int(typ), addr, size, value)
}
//export hookInterrupt
func hookInterrupt(handle C.uch, intno uint32, user unsafe.Pointer) {
hook := (*HookData)(user)
hook.Callback.(func(*Uc, uint32))(hook.Uc, intno)
} }
//export hookX86In //export hookX86In
func hookX86In(handle C.uch, port, size uint32, user unsafe.Pointer) C.uint32_t { func hookX86In(handle C.uch, port, size uint32, user unsafe.Pointer) uint32 {
hook := (*HookData)(user) hook := (*HookData)(user)
return C.uint32_t(hook.Callback.(func(*Uc, uint32, uint32) uint32)(hook.Uc, port, size)) return hook.Callback.(func(*Uc, uint32, uint32) uint32)(hook.Uc, port, size)
} }
//export hookX86Out //export hookX86Out
func hookX86Out(handle C.uch, port, size, value uint32, user unsafe.Pointer) { func hookX86Out(handle C.uch, port, size, value uint32, user unsafe.Pointer) {
hook := (*HookData)(user) hook := (*HookData)(user)
hook.Callback.(func(*Uc, uint32, uint32, uint32))(hook.Uc, uint32(port), uint32(size), uint32(value)) hook.Callback.(func(*Uc, uint32, uint32, uint32))(hook.Uc, port, size, value)
} }
//export hookX86Syscall //export hookX86Syscall
@ -64,6 +70,8 @@ func (u *Uc) HookAdd(htype int, cb interface{}, insn ...int) (C.uch, error) {
callback = C.hookMemInvalid_cgo callback = C.hookMemInvalid_cgo
case UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE, UC_HOOK_MEM_READ_WRITE: case UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE, UC_HOOK_MEM_READ_WRITE:
callback = C.hookMemAccess_cgo callback = C.hookMemAccess_cgo
case UC_HOOK_INTR:
callback = C.hookInterrupt_cgo
case UC_HOOK_INSN: case UC_HOOK_INSN:
extra = C.int(insn[0]) extra = C.int(insn[0])
switch extra { switch extra {

View file

@ -2,6 +2,7 @@ uc_err uc_hook_add2(uch handle, uch *h2, uc_hook_t type, void *callback, void *u
void hookCode_cgo(uch handle, uint64_t addr, uint32_t size, void *user); void hookCode_cgo(uch handle, uint64_t addr, uint32_t size, void *user);
bool hookMemInvalid_cgo(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user); bool hookMemInvalid_cgo(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user);
void hookMemAccess_cgo(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user); void hookMemAccess_cgo(uch handle, uc_mem_type type, uint64_t addr, int size, int64_t value, void *user);
void hookInterrupt_cgo(uch handle, uint32_t intno, void *user);
uint32_t hookX86In_cgo(uch handle, uint32_t port, uint32_t size, void *user); uint32_t hookX86In_cgo(uch handle, uint32_t port, uint32_t size, void *user);
void hookX86Out_cgo(uch handle, uint32_t port, uint32_t size, uint32_t value, void *user); void hookX86Out_cgo(uch handle, uint32_t port, uint32_t size, uint32_t value, void *user);
void hookX86Syscall_cgo(uch handle, void *user); void hookX86Syscall_cgo(uch handle, void *user);

View file

@ -1,19 +1,19 @@
/\'. _,, /\'. _,.
|.\ \ .'_/ |:\ \. .'_/
_.-- |(\\ \ .'_.' _.- |(\\ \ .'_.'
_.-' \_\\ \\_),/ _/ _.-' ,__\\ \\_),/ _/
_).' .:::::::.___ .' _:.' .:::::::.___ ,'
// ' ./::::::\\o\( // ' ./::::::\<o\(
// //::/ '"( \ // /|::/ `"( \
//_ //::( '. '. ;/_ / ::( `. `.
/_'/ /||:::\ '. \ /_'/ | ::::\ `. \
'// '\\:::':\_ -<_' _'- '// '\ :::':\_ _, ` _'-
/ | '\::/|::::.._ _ )( / | '\.:/|::::.._ `-__ )/
| | \:| \:( '.(_'._) | | \;| \:( '.(_ \_)
| | \( \::. '-) | | \( \::. '-)
\ \ . '""""---. \ \ , '""""---.
\ \ \ . _.-...) \ \ \ , _.-...)
\ \/\. \:.___.-'..:::/ \ \/\. \:,___.-'..:::/
\ |\\:..\:::::'.::::/ \ |\\:,.\:::::'.::::/
' '.:::::'..:::"' ` `:;::::'.::;::'
'":::""' '":;:""'

View file

@ -205,6 +205,8 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq
have_tb_lock = true; have_tb_lock = true;
tb = tb_find_fast(env); // qq tb = tb_find_fast(env); // qq
if (!tb) { // invalid TB due to invalid code? if (!tb) { // invalid TB due to invalid code?
uc->invalid_error = UC_ERR_CODE_INVALID;
ret = EXCP_HLT;
break; break;
} }
/* Note: we do it here to avoid a gcc bug on Mac OS X when /* Note: we do it here to avoid a gcc bug on Mac OS X when

View file

@ -986,12 +986,22 @@ void helper_fstenv(CPUX86State *env, target_ulong ptr, int data32)
} }
} }
} }
if (data32) {
// DFLAG enum: tcg.h, case here to int
if (env->hflags & HF_CS64_MASK) {
cpu_stl_data(env, ptr, env->fpuc);
cpu_stl_data(env, ptr + 4, fpus);
cpu_stl_data(env, ptr + 8, fptag);
cpu_stl_data(env, ptr + 12, env->fpip); /* fpip */
cpu_stl_data(env, ptr + 20, 0); /* fpcs */
cpu_stl_data(env, ptr + 24, 0); /* fpoo */
cpu_stl_data(env, ptr + 28, 0); /* fpos */
} else if (data32) {
/* 32 bit */ /* 32 bit */
cpu_stl_data(env, ptr, env->fpuc); cpu_stl_data(env, ptr, env->fpuc);
cpu_stl_data(env, ptr + 4, fpus); cpu_stl_data(env, ptr + 4, fpus);
cpu_stl_data(env, ptr + 8, fptag); cpu_stl_data(env, ptr + 8, fptag);
cpu_stl_data(env, ptr + 12, 0); /* fpip */ cpu_stl_data(env, ptr + 12, env->fpip); /* fpip */
cpu_stl_data(env, ptr + 16, 0); /* fpcs */ cpu_stl_data(env, ptr + 16, 0); /* fpcs */
cpu_stl_data(env, ptr + 20, 0); /* fpoo */ cpu_stl_data(env, ptr + 20, 0); /* fpoo */
cpu_stl_data(env, ptr + 24, 0); /* fpos */ cpu_stl_data(env, ptr + 24, 0); /* fpos */
@ -1000,11 +1010,12 @@ void helper_fstenv(CPUX86State *env, target_ulong ptr, int data32)
cpu_stw_data(env, ptr, env->fpuc); cpu_stw_data(env, ptr, env->fpuc);
cpu_stw_data(env, ptr + 2, fpus); cpu_stw_data(env, ptr + 2, fpus);
cpu_stw_data(env, ptr + 4, fptag); cpu_stw_data(env, ptr + 4, fptag);
cpu_stw_data(env, ptr + 6, 0); cpu_stw_data(env, ptr + 6, env->fpip);
cpu_stw_data(env, ptr + 8, 0); cpu_stw_data(env, ptr + 8, 0);
cpu_stw_data(env, ptr + 10, 0); cpu_stw_data(env, ptr + 10, 0);
cpu_stw_data(env, ptr + 12, 0); cpu_stw_data(env, ptr + 12, 0);
} }
} }
void helper_fldenv(CPUX86State *env, target_ulong ptr, int data32) void helper_fldenv(CPUX86State *env, target_ulong ptr, int data32)

View file

@ -248,6 +248,11 @@ static void gen_update_cc_op(DisasContext *s)
} }
} }
static void fpu_update_ip(CPUX86State *env, target_ulong pc)
{
env->fpip = pc;
}
#ifdef TARGET_X86_64 #ifdef TARGET_X86_64
#define NB_OP_SIZES 4 #define NB_OP_SIZES 4
@ -6110,6 +6115,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
/* fcomp needs pop */ /* fcomp needs pop */
gen_helper_fpop(tcg_ctx, cpu_env); gen_helper_fpop(tcg_ctx, cpu_env);
} }
fpu_update_ip(env, pc_start);
} }
break; break;
case 0x08: /* flds */ case 0x08: /* flds */
@ -6194,6 +6200,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_helper_fpop(tcg_ctx, cpu_env); gen_helper_fpop(tcg_ctx, cpu_env);
break; break;
} }
fpu_update_ip(env, pc_start);
break; break;
case 0x0c: /* fldenv mem */ case 0x0c: /* fldenv mem */
gen_update_cc_op(s); gen_update_cc_op(s);
@ -6219,12 +6226,14 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_update_cc_op(s); gen_update_cc_op(s);
gen_jmp_im(s, pc_start - s->cs_base); gen_jmp_im(s, pc_start - s->cs_base);
gen_helper_fldt_ST0(tcg_ctx, cpu_env, cpu_A0); gen_helper_fldt_ST0(tcg_ctx, cpu_env, cpu_A0);
fpu_update_ip(env, pc_start);
break; break;
case 0x1f: /* fstpt mem */ case 0x1f: /* fstpt mem */
gen_update_cc_op(s); gen_update_cc_op(s);
gen_jmp_im(s, pc_start - s->cs_base); gen_jmp_im(s, pc_start - s->cs_base);
gen_helper_fstt_ST0(tcg_ctx, cpu_env, cpu_A0); gen_helper_fstt_ST0(tcg_ctx, cpu_env, cpu_A0);
gen_helper_fpop(tcg_ctx, cpu_env); gen_helper_fpop(tcg_ctx, cpu_env);
fpu_update_ip(env, pc_start);
break; break;
case 0x2c: /* frstor mem */ case 0x2c: /* frstor mem */
gen_update_cc_op(s); gen_update_cc_op(s);
@ -6245,21 +6254,25 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
gen_update_cc_op(s); gen_update_cc_op(s);
gen_jmp_im(s, pc_start - s->cs_base); gen_jmp_im(s, pc_start - s->cs_base);
gen_helper_fbld_ST0(tcg_ctx, cpu_env, cpu_A0); gen_helper_fbld_ST0(tcg_ctx, cpu_env, cpu_A0);
fpu_update_ip(env, pc_start);
break; break;
case 0x3e: /* fbstp */ case 0x3e: /* fbstp */
gen_update_cc_op(s); gen_update_cc_op(s);
gen_jmp_im(s, pc_start - s->cs_base); gen_jmp_im(s, pc_start - s->cs_base);
gen_helper_fbst_ST0(tcg_ctx, cpu_env, cpu_A0); gen_helper_fbst_ST0(tcg_ctx, cpu_env, cpu_A0);
gen_helper_fpop(tcg_ctx, cpu_env); gen_helper_fpop(tcg_ctx, cpu_env);
fpu_update_ip(env, pc_start);
break; break;
case 0x3d: /* fildll */ case 0x3d: /* fildll */
tcg_gen_qemu_ld_i64(s->uc, cpu_tmp1_i64, cpu_A0, s->mem_index, MO_LEQ); tcg_gen_qemu_ld_i64(s->uc, cpu_tmp1_i64, cpu_A0, s->mem_index, MO_LEQ);
gen_helper_fildll_ST0(tcg_ctx, cpu_env, cpu_tmp1_i64); gen_helper_fildll_ST0(tcg_ctx, cpu_env, cpu_tmp1_i64);
fpu_update_ip(env, pc_start);
break; break;
case 0x3f: /* fistpll */ case 0x3f: /* fistpll */
gen_helper_fistll_ST0(tcg_ctx, cpu_tmp1_i64, cpu_env); gen_helper_fistll_ST0(tcg_ctx, cpu_tmp1_i64, cpu_env);
tcg_gen_qemu_st_i64(s->uc, cpu_tmp1_i64, cpu_A0, s->mem_index, MO_LEQ); tcg_gen_qemu_st_i64(s->uc, cpu_tmp1_i64, cpu_A0, s->mem_index, MO_LEQ);
gen_helper_fpop(tcg_ctx, cpu_env); gen_helper_fpop(tcg_ctx, cpu_env);
fpu_update_ip(env, pc_start);
break; break;
default: default:
goto illegal_op; goto illegal_op;
@ -6574,6 +6587,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
default: default:
goto illegal_op; goto illegal_op;
} }
fpu_update_ip(env, pc_start);
} }
break; break;
/************************/ /************************/

View file

@ -52,6 +52,12 @@ void x86_reg_reset(struct uc_struct *uc)
{ {
CPUArchState *env = first_cpu->env_ptr; CPUArchState *env = first_cpu->env_ptr;
env->features[FEAT_1_EDX] = CPUID_CX8 | CPUID_CMOV | CPUID_SSE2 | CPUID_FXSR | CPUID_SSE | CPUID_CLFLUSH;
env->features[FEAT_1_ECX] = CPUID_EXT_SSSE3 | CPUID_EXT_SSE41 | CPUID_EXT_SSE42 | CPUID_EXT_AES;
env->features[FEAT_8000_0001_EDX] = CPUID_EXT2_3DNOW | CPUID_EXT2_RDTSCP;
env->features[FEAT_8000_0001_ECX] = CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | CPUID_EXT3_SKINIT | CPUID_EXT3_CR8LEG;
env->features[FEAT_7_0_EBX] = CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP;
env->invalid_error = UC_ERR_OK; // no error env->invalid_error = UC_ERR_OK; // no error
memset(env->regs, 0, sizeof(env->regs)); memset(env->regs, 0, sizeof(env->regs));
memset(env->segs, 0, sizeof(env->segs)); memset(env->segs, 0, sizeof(env->segs));

View file

@ -6,6 +6,7 @@ TESTS += sigill sigill2
TESTS += block_test TESTS += block_test
TESTS += ro_mem_test nr_mem_test TESTS += ro_mem_test nr_mem_test
TESTS += timeout_segfault TESTS += timeout_segfault
TESTS += rep_movsb
all: $(TESTS) all: $(TESTS)

61
regress/fpu_ip.py Executable file
View file

@ -0,0 +1,61 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
from capstone import *
ESP = 0x2000
PAGE_SIZE = 2 * 1024 * 1024
# mov [esp], DWORD 0x37f
# fldcw [esp]
# fnop
# fnstenv [esp + 8]
# pop ecx
CODE = b'\xc7\x04\x24\x7f\x03\x00\x00\xd9\x2c\x24\xd9\xd0\xd9\x74\x24\x08\x59'
class SimpleEngine:
def __init__(self):
self.capmd = Cs(CS_ARCH_X86, CS_MODE_32)
def disas_single(self, data):
for i in self.capmd.disasm(data, 16):
print("\t%s\t%s" % (i.mnemonic, i.op_str))
break
disasm = SimpleEngine()
def hook_code(uc, addr, size, user_data):
mem = uc.mem_read(addr, size)
print(" 0x%X:" % (addr)),
disasm.disas_single(str(mem))
def mem_reader(addr, size):
tmp = mu.mem_read(addr, size)
for i in tmp:
print(" 0x%x" % i),
print("")
mu = Uc(UC_ARCH_X86, UC_MODE_32)
mu.mem_map(0x0, PAGE_SIZE)
mu.mem_write(0x4000, CODE)
mu.reg_write(UC_X86_REG_ESP, ESP)
mu.hook_add(UC_HOOK_CODE, hook_code)
mu.emu_start(0x4000, 0, 0, 5)
esp = mu.reg_read(UC_X86_REG_ESP)
print("value at ESP [0x%X - 4]: " % esp)
mem_reader(esp + 14, 4)
# EXPECTED OUTPUT:
# 0x4000: mov dword ptr [esp], 0x37f
# 0x4007: fldcw word ptr [esp]
# 0x400A: fnop
# 0x400C: fnstenv dword ptr [esp + 8]
# 0x4010: pop ecx
# value at ESP [0x2004 - 4]:
# 0x0 0x0 0xa 0x40
# ^ this value should match the fnop instuction addr

62
regress/fpu_ip64.py Executable file
View file

@ -0,0 +1,62 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
from capstone import *
ESP = 0x2000
PAGE_SIZE = 2 * 1024 * 1024
# mov [esp], DWORD 0x37f
# fldcw [esp]
# fnop
# fnstenv [esp + 8]
# pop ecx
CODE = "C704247F030000D92C24D9D0D974240859".decode('hex')
class SimpleEngine:
def __init__(self):
self.capmd = Cs(CS_ARCH_X86, CS_MODE_64)
def disas_single(self, data):
for i in self.capmd.disasm(data, 16):
print("\t%s\t%s" % (i.mnemonic, i.op_str))
break
disasm = SimpleEngine()
def hook_code(uc, addr, size, user_data):
mem = uc.mem_read(addr, size)
print(" 0x%X:" % (addr)),
disasm.disas_single(str(mem))
def mem_reader(addr, size):
tmp = mu.mem_read(addr, size)
for i in tmp:
print(" 0x%x" % i),
print("")
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(0x0, PAGE_SIZE)
mu.mem_write(0x4000, CODE)
mu.reg_write(UC_X86_REG_RSP, ESP)
mu.hook_add(UC_HOOK_CODE, hook_code)
mu.emu_start(0x4000, 0, 0, 5)
rsp = mu.reg_read(UC_X86_REG_RSP)
print("Value of FPIP: [0x%X]" % (rsp + 10))
mem_reader(rsp + 10, 8)
# EXPECTED OUTPUT:
# 0x4000: mov dword ptr [rsp], 0x37f
# 0x4007: fldcw word ptr [rsp]
# 0x400A: fnop
# 0x400C: fnstenv dword ptr [rsp + 8]
# 0x4010: pop rcx
# Value of FPIP: [0x2012]
# 0x0 0x0 0xa 0x40 0x0 0x0 0x0 0x0
# WHERE: the value of FPIP should be the address of fnop

37
regress/jmp_ebx_hang.py Executable file
View file

@ -0,0 +1,37 @@
#!/usr/bin/env python
"""See https://github.com/unicorn-engine/unicorn/issues/82"""
import unicorn
CODE_ADDR = 0x10101000
CODE = b'\xff\xe3' # jmp ebx
mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
mu.mem_map(CODE_ADDR, 1024 * 4)
mu.mem_write(CODE_ADDR, CODE)
# If EBX is zero then an exception is raised, as expected
mu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, 0x0)
print(">>> jmp ebx (ebx = 0)");
try:
mu.emu_start(CODE_ADDR, CODE_ADDR + 2, count=1)
except unicorn.UcError as e:
print("ERROR: %s" % e)
assert(e.errno == unicorn.UC_ERR_CODE_INVALID)
else:
assert(False)
print(">>> jmp ebx (ebx = 0xaa96a47f)");
mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
mu.mem_map(CODE_ADDR, 1024 * 4)
# If we write this address to EBX then the emulator hangs on emu_start
mu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, 0xaa96a47f)
mu.mem_write(CODE_ADDR, CODE)
try:
mu.emu_start(CODE_ADDR, CODE_ADDR + 2, count=1)
except unicorn.UcError as e:
print("ERROR: %s" % e)
assert(e.errno == unicorn.UC_ERR_CODE_INVALID)
else:
assert(False)
print "Success"

12
regress/pshufb.py Executable file
View file

@ -0,0 +1,12 @@
#!/usr/bin/python
# By Ryan Hileman, issue #91
# Invalid instruction = test failed
from unicorn import *
from unicorn.x86_const import *
uc = Uc(UC_ARCH_X86, UC_MODE_64)
uc.mem_map(0x2000, 0x1000)
# pshufb xmm0, xmm1
uc.mem_write(0x2000, '660f3800c1'.decode('hex'))
uc.emu_start(0x2000, 0x2005)

183
regress/rep_movsb.c Normal file
View file

@ -0,0 +1,183 @@
/*
rep movsb regression
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.
*/
#define __STDC_FORMAT_MACROS
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unicorn/unicorn.h>
unsigned char PROGRAM[] =
"\xbe\x00\x00\x20\x00\xbf\x00\x10\x20\x00\xb9\x14\x00\x00\x00\xf3"
"\xa4\xf4";
// total size: 18 bytes
/*
bits 32
; assumes code section at 0x100000 r-x
; assumes data section at 0x200000-0x202000, rw-
mov esi, 0x200000
mov edi, 0x201000
mov ecx, 20
rep movsb
hlt
*/
static int log_num = 1;
// callback for tracing instruction
static void hook_code(uch handle, uint64_t addr, uint32_t size, void *user_data)
{
uint8_t opcode;
if (uc_mem_read(handle, addr, &opcode, 1) != UC_ERR_OK) {
printf("not ok %d - uc_mem_read fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr);
_exit(-1);
}
switch (opcode) {
case 0xf4: //hlt
printf("# Handling HLT\n");
if (uc_emu_stop(handle) != UC_ERR_OK) {
printf("not ok %d - uc_emu_stop fail during hook_code callback, addr: 0x%" PRIx64 "\n", log_num++, addr);
_exit(-1);
}
else {
printf("ok %d - hlt encountered, uc_emu_stop called\n", log_num++);
}
break;
default: //all others
break;
}
}
// callback for tracing memory access (READ or WRITE)
static void hook_mem_write(uch handle, uc_mem_type type,
uint64_t addr, int size, int64_t value, void *user_data)
{
printf("# write to memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value);
if (addr < 0x201000L) {
//this is actually a read, we don't write in this range
printf("not ok %d - write hook called for read of 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", log_num++, addr, size, value);
}
else {
printf("ok %d - write hook called for write of 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", log_num++, addr, size, value);
}
}
int main(int argc, char **argv, char **envp)
{
uch handle, trace1, trace2;
uc_err err;
uint8_t buf1[100], readbuf[100];
printf("# rep movsb test\n");
memset(buf1, 'A', 20);
// Initialize emulator in X86-32bit mode
err = uc_open(UC_ARCH_X86, UC_MODE_32, &handle);
if (err) {
printf("not ok %d - Failed on uc_open() with error returned: %u\n", log_num++, err);
return 1;
}
else {
printf("ok %d - uc_open() success\n", log_num++);
}
uc_mem_map(handle, 0x100000, 0x1000, UC_PROT_READ);
uc_mem_map(handle, 0x200000, 0x2000, UC_PROT_READ | UC_PROT_WRITE);
// fill in the data that we want to copy
if (uc_mem_write(handle, 0x200000, (uint8_t*)buf1, 20)) {
printf("not ok %d - Failed to write read buffer to memory, quit!\n", log_num++);
return 2;
}
else {
printf("ok %d - Read buffer written to memory\n", log_num++);
}
// write machine code to be emulated to memory
if (uc_mem_write(handle, 0x100000, PROGRAM, sizeof(PROGRAM))) {
printf("not ok %d - Failed to write emulation code to memory, quit!\n", log_num++);
return 4;
}
else {
printf("ok %d - Program written to memory\n", log_num++);
}
if (uc_hook_add(handle, &trace2, UC_HOOK_CODE, hook_code, NULL, 1, 0) != UC_ERR_OK) {
printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++);
return 5;
}
else {
printf("ok %d - UC_HOOK_CODE installed\n", log_num++);
}
// intercept memory write events only, NOT read events
if (uc_hook_add(handle, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL) != UC_ERR_OK) {
printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++);
return 6;
}
else {
printf("ok %d - UC_HOOK_MEM_WRITE installed\n", log_num++);
}
// emulate machine code until told to stop by hook_code
printf("# BEGIN execution\n");
err = uc_emu_start(handle, 0x100000, 0x101000, 0, 0);
if (err != UC_ERR_OK) {
printf("not ok %d - Failure on uc_emu_start() with error %u:%s\n", log_num++, err, uc_strerror(err));
return 8;
}
else {
printf("ok %d - uc_emu_start complete\n", log_num++);
}
printf("# END execution\n");
//make sure that data got copied
// fill in sections that shouldn't get touched
if (uc_mem_read(handle, 0x201000, (uint8_t*)readbuf, 20)) {
printf("not ok %d - Failed to read random buffer 1 from memory\n", log_num++);
}
else {
printf("ok %d - Random buffer 1 read from memory\n", log_num++);
if (memcmp(buf1, readbuf, 20)) {
printf("not ok %d - write buffer contents are incorrect\n", log_num++);
}
else {
printf("ok %d - write buffer contents are correct\n", log_num++);
}
}
if (uc_close(&handle) == UC_ERR_OK) {
printf("ok %d - uc_close complete\n", log_num++);
}
else {
printf("not ok %d - uc_close complete\n", log_num++);
}
return 0;
}