diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 00000000..cbc1c215 --- /dev/null +++ b/.appveyor.yml @@ -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 diff --git a/.gitignore b/.gitignore index ae776b30..03e0ab10 100644 --- a/.gitignore +++ b/.gitignore @@ -70,7 +70,13 @@ mem_unmap.static mem_apis mem_apis.exe mem_apis.static - +sample_batch_reg +sample_batch_reg.exe +sample_batch_reg.static +sample_x86_32_gdt_and_seg_regs +sample_x86_32_gdt_and_seg_regs.exe +sample_x86_32_gdt_and_seg_regs.static +mem_64_c libunicorn*.dll libunicorn*.so @@ -128,6 +134,12 @@ threaded_emu_start emu_stop_in_hook_overrun mips_branch_likely_issue emu_clear_errors +001-bad_condition_code_0xe +002-qemu__fatal__unimplemented_control_register_write_0xffb___0x0 +003-qemu__fatal__wdebug_not_implemented +004-segmentation_fault_1 +005-qemu__fatal__illegal_instruction__0000___00000404 +006-qemu__fatal__illegal_instruction__0421___00040026 test_mem_map_ptr test_mem_high @@ -139,6 +151,14 @@ test_multihook test_pc_change mem_fuzz test_x86_soft_paging +test_hookcounts + +memleak_x86 +memleak_arm +memleak_arm64 +memleak_mips +memleak_m68k +memleak_sparc ################# diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 00000000..39c18b8e --- /dev/null +++ b/.travis.yml @@ -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 diff --git a/COMPILE.TXT b/COMPILE.TXT deleted file mode 100644 index e2e932dd..00000000 --- a/COMPILE.TXT +++ /dev/null @@ -1,304 +0,0 @@ -This documentation explains how to compile, install & run Unicorn on MacOSX, -Linux, *BSD & Solaris. We also show steps to cross-compile for Microsoft Windows. - - *-*-*-*-*-* - -[0] Dependencies - -Unicorn requires few dependent packages as follows. - -- For Mac OS X, "pkg-config" and "glib" are needed. - Brew users can install "pkg-config" and "glib" with: - - $ brew install pkg-config glib - -- For Linux, "glib2-dev" is needed. - Ubuntu/Debian users can install this with: - - $ sudo apt-get install libglib2.0-dev - -- For Windows, cross-compile requires Mingw. Mingw-glib2 is needed. - At the moment, it is confirmed that Unicorn can be compiled either on Ubuntu - or Windows. - - - On Ubuntu 14.04 64-bit, do: - - 1. Download DEB packages for Mingw64 from: - - https://launchpad.net/~greg-hellings/+archive/ubuntu/mingw-libs/+build/2924251 - - 2. To cross-compile for Windows 32-bit, install Mingw with (ignore all the warnings): - - $ sudo dpkg -i --force-depends mingw64-x86-glib2_2.31.0_all.deb - - To cross-compile for Windows 64-bit, install Mingw with: - - $ sudo dpkg -i --force-depends mingw64-x64-glib2_2.31.0_all.deb - - - - On Windows, install MinGW via package MSYS2 at https://msys2.github.io/ - - Follow the install instructions and don't forget to update the system packages with: - - $ pacman --needed -Sy bash pacman pacman-mirrors msys2-runtime - - Then close MSYS2, run it again from Start menu and update the rest with: - - $ pacman -Su - - Finally, install required toolchain to build C projects. - - - To compile for Windows 32-bit, run: - $ pacman -S python2 - $ pacman -S make - $ pacman -S pkg-config - $ pacman -S mingw-w64-i686-glib2 - $ pacman -S mingw-w64-i686-toolchain - - - To compile for Windows 64-bit, run: - $ pacman -S python2 - $ pacman -S make - $ pacman -S pkg-config - $ pacman -S mingw-w64-x86_64-glib2 - $ pacman -S mingw-w64-x86_64-toolchain - -- For Cygwin, "make", "gcc-core", "pkg-config", "libpcre-devel", "zlib-devel" - and "libglib2.0-devel" are needed. - - If apt-cyg is available, you can install these with: - - $ apt-cyg install make gcc-core pkg-config libpcre-devel zlib-devel libglib2.0-devel - - - -[1] Tailor Unicorn to your need. - - Out of 6 archtitectures supported by Unicorn (Arm, Arm64, M68K, Mips, Sparc, - & X86), if you just need several selected archs, choose which ones you want - to compile in by editing "config.mk" before going to next steps. - - By default, all 6 architectures are compiled. - - The other way of customize Unicorn without having to edit config.mk is to - pass the desired options on the commandline to ./make.sh. Currently, - Unicorn supports 4 options, as follows. - - - UNICORN_ARCHS: specify list of architectures to compiled in. - - UNICORN_STATIC: build static library. - - UNICORN_SHARED: build dynamic (shared) library. - - UNICORN_QEMU_FLAGS: specify extra flags for qemu's configure script - - To avoid editing config.mk for these customization, we can pass their values to - make.sh, as follows. - - $ UNICORN_ARCHS="arm aarch64 x86" ./make.sh - - NOTE: on commandline, put these values in front of ./make.sh, not after it. - - For each option, refer to docs/README for more details. - - - -[2] Compile and install from source on *nix - - To build Unicorn on *nix (such as MacOSX, Linux, *BSD, Solaris): - - - To compile for current platform, run: - - $ ./make.sh - - - Unicorn requires Python 2.x to compile. If Python 2.x is not the default - Python interpreter, ensure that the appropriate option is set: - - $ UNICORN_QEMU_FLAGS="--python=/path/to/python2" ./make.sh - - - To cross-compile Unicorn on 64-bit OS to target 32-bit binary, run: - - $ ./make.sh nix32 - - After compiling, install Unicorn with: - - $ sudo ./make.sh install - - For FreeBSD/OpenBSD, where sudo is unavailable, run: - - $ su; ./make.sh install - - Users are then required to enter root password to copy Unicorn into machine - system directories. - - Afterwards, run ./samples/sample_all.sh to test the sample emulations. - - - NOTE: The core framework installed by "./make.sh install" consist of - following files: - - /usr/include/unicorn/unicorn.h - /usr/include/unicorn/x86.h - /usr/include/unicorn/arm.h - /usr/include/unicorn/arm64.h - /usr/include/unicorn/mips.h - /usr/include/unicorn/ppc.h - /usr/include/unicorn/sparc.h - /usr/include/unicorn/m68k.h - /usr/include/unicorn/platform.h - /usr/lib/libunicorn.so (for Linux/*nix), or /usr/lib/libunicorn.dylib (OSX) - /usr/lib/libunicorn.a - - - -[3] Compile from source on Windows - with MinGW (MSYS2) - - To compile with MinGW, install MSYS2 as instructed in the first section. - Then, build Unicorn with the next steps: - - - To compile Windows 32-bit binary with MinGW, run: - $ ./make.sh cross-win32 - - - To compile Windows 64-bit binary with MinGW, run: - $ ./make.sh cross-win64 - - Resulted files unicorn.dll, unicorn.lib & samples/sample*.exe can then - 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 - - - -[4] Compile and install from source on Cygwin - - To build Unicorn on Cygwin, run: - - $ ./make.sh - - After compiling, install Unicorn with: - - $ ./make.sh install - - Resulted files cygunicorn.dll, libunicorn.dll.a and libunicorn.a can be - used on Cygwin but not native Windows. - - NOTE: The core framework installed by "./make.sh install" consist of - following files: - - /usr/include/unicorn/*.h - /usr/bin/cygunicorn.dll - /usr/lib/libunicorn.dll.a - /usr/lib/libunicorn.a - - - -[5] Cross-compile for Windows from *nix - - To cross-compile for Windows, Linux & gcc-mingw-w64-i686 (and also gcc-mingw-w64-x86-64 - for 64-bit binaries) are required. - - - To cross-compile Windows 32-bit binary, simply run: - - $ ./make.sh cross-win32 - - - To cross-compile Windows 64-bit binary, run: - - $ ./make.sh cross-win64 - - Resulted files unicorn.dll, unicorn.lib & samples/sample*.exe can then - be used on Windows machine. - - To run sample_x86.exe on Windows 32-bit, you need the following files: - - unicorn.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/i686-w64-mingw32/lib/libwinpthread-1.dll - - To run sample_x86.exe on Windows 64-bit, you need the following files: - - unicorn.dll - - /usr/x86_64-w64-mingw32/sys-root/mingw/bin/libglib-2.0-0.dll - - /usr/lib/gcc/x86_64-w64-mingw32/4.8/libgcc_s_sjlj-1.dll - - /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll - - Then run either "sample_x86.exe -32" or "sample_x86.exe -64" to test emulators for X86 32-bit or X86 64-bit. - For other architectures, run "sample_xxx.exe" found in the same directory. - - - -[6] Cross-compile for iOS from Mac OSX. - - 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: - $ ./make.sh ios_armv7 - - - To cross-compile for ArmV7s (iPad 4, iPhone 5C, iPad mini), run: - $ ./make.sh ios_armv7s - - - To cross-compile for Arm64 (iPhone 5S, iPad mini Retina, iPad Air), run: - $ ./make.sh ios_arm64 - - - To cross-compile for all iDevices (armv7 + armv7s + arm64), run: - $ ./make.sh ios - - Resulted files libunicorn.dylib, libunicorn.a & tests/test* can then - be used on iOS devices. - - - -[7] Cross-compile for Android - - To cross-compile for Android (smartphone/tablet), Android NDK is required. - NOTE: Only ARM and ARM64 are currently supported. - - $ NDK=/android/android-ndk-r10e ./make.sh cross-android arm - or - $ NDK=/android/android-ndk-r10e ./make.sh cross-android arm64 - - Resulted files libunicorn.so, libunicorn.a & tests/test* can then - be used on Android devices. - - - -[8] By default, "cc" (default C compiler on the system) is used as compiler. - - - To use "clang" compiler instead, run the command below: - - $ ./make.sh clang - - - To use "gcc" compiler instead, run: - - $ ./make.sh gcc - - - -[9] To uninstall Unicorn, run the command below: - - $ sudo ./make.sh uninstall - - - -[10] Language bindings - - Look for the bindings under directory bindings/, and refer to README file - of corresponding languages. - - - -[11] Unit tests - - Automated unit tests use the cmocka unit testing framework (https://cmocka.org/). - It can be installed in most Linux distros using the package manager, e.g. - `sudo yum install libcmocka libcmocka-devel`, or you can easily build and install it from source. - - You can run the tests by running `make test` in the project directory. diff --git a/CREDITS.TXT b/CREDITS.TXT index e4319580..a79b053b 100644 --- a/CREDITS.TXT +++ b/CREDITS.TXT @@ -59,3 +59,7 @@ Chris Eagle: Java binding Ryan Hileman: Go binding Antonio Parata: .NET binding Jonathon Reinhart: C unit test +Sascha Schirra: Ruby binding +Adrian Herrera: Haskell binding +practicalswift: Various cool bugs found by fuzzing +farmdve: Memory leaking fix diff --git a/Makefile b/Makefile index 5bd94a93..e2216003 100644 --- a/Makefile +++ b/Makefile @@ -64,6 +64,13 @@ else CFLAGS += -O3 endif +ifeq ($(UNICORN_ASAN),yes) +CC = clang -fsanitize=address -fno-omit-frame-pointer +CXX = clang++ -fsanitize=address -fno-omit-frame-pointer +AR = llvm-ar +LDFLAGS := -fsanitize=address ${LDFLAGS} +endif + ifeq ($(CROSS),) CC ?= cc AR ?= ar @@ -213,18 +220,17 @@ config: qemu/config-host.h-timestamp: ifeq ($(UNICORN_DEBUG),yes) cd qemu && \ - ./configure --extra-cflags="$(UNICORN_CFLAGS)" --target-list="$(UNICORN_TARGETS)" ${UNICORN_QEMU_FLAGS} + ./configure --cc="${CC}" --extra-cflags="$(UNICORN_CFLAGS)" --target-list="$(UNICORN_TARGETS)" ${UNICORN_QEMU_FLAGS} printf "$(UNICORN_ARCHS)" > config.log else cd qemu && \ - ./configure --disable-debug-info --extra-cflags="$(UNICORN_CFLAGS)" --target-list="$(UNICORN_TARGETS)" ${UNICORN_QEMU_FLAGS} + ./configure --cc="${CC}" --disable-debug-info --extra-cflags="$(UNICORN_CFLAGS)" --target-list="$(UNICORN_TARGETS)" ${UNICORN_QEMU_FLAGS} printf "$(UNICORN_ARCHS)" > config.log endif compile_lib: config qemu/config-host.h-timestamp rm -rf lib$(LIBNAME)* $(LIBNAME)*.lib $(LIBNAME)*.dll cyg$(LIBNAME)*.dll && cd qemu && $(MAKE) -j 4 $(MAKE) unicorn - cd samples && $(MAKE) clean unicorn: $(LIBRARY) $(ARCHIVE) @@ -265,8 +271,7 @@ endif test: all $(MAKE) -C tests/unit test - -install: all $(PKGCFGF) +install: compile_lib $(PKGCFGF) mkdir -p $(DESTDIR)$(LIBDIR) ifeq ($(UNICORN_SHARED),yes) ifeq ($(IS_CYGWIN),1) diff --git a/README.md b/README.md index 942e1b8e..eb061cdd 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,11 @@ Unicorn Engine ============== +[![Join the chat at https://gitter.im/unicorn-engine/chat](https://badges.gitter.im/unicorn-engine/unicorn.svg)](https://gitter.im/unicorn-engine/chat?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) + +[![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). @@ -8,7 +13,7 @@ Unicorn offers some unparalleled features: - Multi-architecture: ARM, ARM64 (ARMv8), M68K, MIPS, SPARC, and X86 (16, 32, 64-bit) - Clean/simple/lightweight/intuitive architecture-neutral API -- Implemented in pure C language, with bindings for Python, Java, and Go +- Implemented in pure C language, with bindings for Rust, Ruby, Python, Java, MSVC, .NET, Go, Delphi/Free Pascal and Haskell. - Native support for Windows & *nix (with Mac OSX, Linux, *BSD & Solaris confirmed) - High performance via Just-In-Time compilation - Support for fine-grained instrumentation at various levels @@ -27,7 +32,7 @@ This project is released under the [GPL license](COPYING). Compilation & Docs ------------------ -See [COMPILE.TXT](COMPILE.TXT) file for how to compile and install Unicorn. +See [docs/COMPILE.md](docs/COMPILE.md) file for how to compile and install Unicorn. More documentation is available in [docs/README.md](docs/README.md). diff --git a/bindings/Makefile b/bindings/Makefile index 652a6457..ed232686 100644 --- a/bindings/Makefile +++ b/bindings/Makefile @@ -1,31 +1,35 @@ # Unicorn Engine # By Nguyen Anh Quynh & Dang Hoang Vu, 2015 -TMPDIR = /tmp/unicorn_sample +TMP_DIR = /tmp/unicorn_sample DIFF = diff -u -w -SAMPLE_ARM = $(TMPDIR)/sample_arm -SAMPLE_ARM64 = $(TMPDIR)/sample_arm64 -SAMPLE_MIPS = $(TMPDIR)/sample_mips -SAMPLE_M68K = $(TMPDIR)/sample_m68k -SAMPLE_SPARC = $(TMPDIR)/sample_sparc -SAMPLE_X86 = $(TMPDIR)/sample_x86 +SAMPLE_ARM = $(TMP_DIR)/sample_arm +SAMPLE_ARM64 = $(TMP_DIR)/sample_arm64 +SAMPLE_MIPS = $(TMP_DIR)/sample_mips +SAMPLE_M68K = $(TMP_DIR)/sample_m68k +SAMPLE_SPARC = $(TMP_DIR)/sample_sparc +SAMPLE_X86 = $(TMP_DIR)/sample_x86 -.PHONY: all expected python +.PHONY: build install samples sample_python expected python sample_diff clean check -all: +build: cd python && $(MAKE) gen_const cd go && $(MAKE) gen_const cd java && $(MAKE) gen_const python const_generator.py dotnet +install: build + cd python && $(MAKE) install + cd java && $(MAKE) install + samples: expected python sample_python: expected python expected: cd ../samples && $(MAKE) - mkdir -p $(TMPDIR) + mkdir -p $(TMP_DIR) ../samples/sample_arm > $(SAMPLE_ARM)_e ../samples/sample_arm64 > $(SAMPLE_ARM64)_e ../samples/sample_mips > $(SAMPLE_MIPS)_e @@ -52,8 +56,9 @@ sample_diff: FORCE $(DIFF) $(SAMPLE_X86)_e $(SAMPLE_X86)_o clean: - rm -rf $(TMPDIR) + rm -rf $(TMP_DIR) cd python && $(MAKE) clean + cd java && $(MAKE) clean check: make -C python check diff --git a/bindings/README b/bindings/README index c3abec91..292c5796 100644 --- a/bindings/README +++ b/bindings/README @@ -7,8 +7,13 @@ The following bindings are contributed by community. - Go binding: by Ryan Hileman. - .NET binding: by Antonio Parata. - MSVC binding: by Zak Escano +- Ruby binding: by Sascha Schirra +- Haskell binding: by Adrian Herrera. More bindings created & maintained externally by community are available as follows. - UnicornPascal: Delphi/Free Pascal binding (by Stievie). https://github.com/stievie/UnicornPascal + +- Unicorn-Rs: Rust binding (by Sébastien Duquette) + https://github.com/ekse/unicorn-rs diff --git a/bindings/const_generator.py b/bindings/const_generator.py index 826340b2..c224d082 100644 --- a/bindings/const_generator.py +++ b/bindings/const_generator.py @@ -24,6 +24,22 @@ template = { 'comment_open': '#', 'comment_close': '', }, + 'ruby': { + 'header': "# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [%s_const.rb]\n\nmodule Unicorn\n", + 'footer': "end", + 'line_format': '\tUC_%s = %s\n', + 'out_file': './ruby/unicorn_gem/lib/unicorn/%s_const.rb', + # prefixes for constant filenames of all archs - case sensitive + 'arm.h': 'arm', + 'arm64.h': 'arm64', + 'mips.h': 'mips', + 'x86.h': 'x86', + 'sparc.h': 'sparc', + 'm68k.h': 'm68k', + 'unicorn.h': 'unicorn', + 'comment_open': '#', + 'comment_close': '', + }, 'go': { 'header': "package unicorn\n// For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [%s_const.go]\nconst (\n", 'footer': ")", diff --git a/bindings/dotnet/UnicornManaged/Const/Common.fs b/bindings/dotnet/UnicornManaged/Const/Common.fs index 0f42d3d7..ef9004e6 100644 --- a/bindings/dotnet/UnicornManaged/Const/Common.fs +++ b/bindings/dotnet/UnicornManaged/Const/Common.fs @@ -93,6 +93,7 @@ module Common = 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 diff --git a/bindings/dotnet/UnicornManaged/Const/X86.fs b/bindings/dotnet/UnicornManaged/Const/X86.fs index e293d5a1..d0526f87 100644 --- a/bindings/dotnet/UnicornManaged/Const/X86.fs +++ b/bindings/dotnet/UnicornManaged/Const/X86.fs @@ -255,7 +255,9 @@ module X86 = let UC_X86_REG_GDTR = 243 let UC_X86_REG_LDTR = 244 let UC_X86_REG_TR = 245 - let UC_X86_REG_ENDING = 246 + let UC_X86_REG_FPCW = 246 + let UC_X86_REG_FPTAG = 247 + let UC_X86_REG_ENDING = 248 // X86 instructions diff --git a/bindings/go/sample.go b/bindings/go/sample.go index 0128cfea..6c66ace7 100644 --- a/bindings/go/sample.go +++ b/bindings/go/sample.go @@ -19,10 +19,10 @@ var asm = strings.Join([]string{ func addHooks(mu uc.Unicorn) { mu.HookAdd(uc.HOOK_BLOCK, func(mu uc.Unicorn, addr uint64, size uint32) { fmt.Printf("Block: 0x%x, 0x%x\n", addr, size) - }) + }, 1, 0) mu.HookAdd(uc.HOOK_CODE, func(mu uc.Unicorn, addr uint64, size uint32) { fmt.Printf("Code: 0x%x, 0x%x\n", addr, size) - }) + }, 1, 0) mu.HookAdd(uc.HOOK_MEM_READ|uc.HOOK_MEM_WRITE, func(mu uc.Unicorn, access int, addr uint64, size int, value int64) { if access == uc.MEM_WRITE { fmt.Printf("Mem write") @@ -30,7 +30,7 @@ func addHooks(mu uc.Unicorn) { fmt.Printf("Mem read") } fmt.Printf(": @0x%x, 0x%x = 0x%x\n", addr, size, value) - }) + }, 1, 0) invalid := uc.HOOK_MEM_READ_INVALID | uc.HOOK_MEM_WRITE_INVALID | uc.HOOK_MEM_FETCH_INVALID mu.HookAdd(invalid, func(mu uc.Unicorn, access int, addr uint64, size int, value int64) bool { switch access { @@ -45,11 +45,11 @@ func addHooks(mu uc.Unicorn) { } fmt.Printf(": @0x%x, 0x%x = 0x%x\n", addr, size, value) return false - }) + }, 1, 0) mu.HookAdd(uc.HOOK_INSN, func(mu uc.Unicorn) { rax, _ := mu.RegRead(uc.X86_REG_RAX) fmt.Printf("Syscall: %d\n", rax) - }, uc.X86_INS_SYSCALL) + }, 1, 0, uc.X86_INS_SYSCALL) } func run() error { diff --git a/bindings/go/unicorn/uc.c b/bindings/go/unicorn/uc.c new file mode 100644 index 00000000..d21e66fa --- /dev/null +++ b/bindings/go/unicorn/uc.c @@ -0,0 +1,25 @@ +#include +#include +#include "_cgo_export.h" + +uc_err uc_reg_read_batch_helper(uc_engine *handle, int *regs, uint64_t *val_out, int count) { + void **val_ref = malloc(sizeof(void *) * count); + int i; + for (i = 0; i < count; i++) { + val_ref[i] = (void *)&val_out[i]; + } + uc_err ret = uc_reg_read_batch(handle, regs, val_ref, count); + free(val_ref); + return ret; +} + +uc_err uc_reg_write_batch_helper(uc_engine *handle, int *regs, uint64_t *val_in, int count) { + void **val_ref = malloc(sizeof(void *) * count); + int i; + for (i = 0; i < count; i++) { + val_ref[i] = (void *)&val_in[i]; + } + uc_err ret = uc_reg_write_batch(handle, regs, (void *const *)val_ref, count); + free(val_ref); + return ret; +} diff --git a/bindings/go/unicorn/uc.h b/bindings/go/unicorn/uc.h new file mode 100644 index 00000000..06022346 --- /dev/null +++ b/bindings/go/unicorn/uc.h @@ -0,0 +1,2 @@ +uc_err uc_reg_read_batch_helper(uc_engine *handle, int *regs, uint64_t *val_out, int count); +uc_err uc_reg_write_batch_helper(uc_engine *handle, int *regs, uint64_t *val_in, int count); diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index 2b0e456c..42f619f9 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -7,8 +7,10 @@ import ( ) /* +#cgo CFLAGS: -O3 #cgo LDFLAGS: -lunicorn #include +#include "uc.h" */ import "C" @@ -41,7 +43,9 @@ type Unicorn interface { MemReadInto(dst []byte, addr uint64) error MemWrite(addr uint64, data []byte) error RegRead(reg int) (uint64, error) + RegReadBatch(regs []int) ([]uint64, error) RegWrite(reg int, value uint64) error + RegWriteBatch(regs []int, vals []uint64) error RegReadMmr(reg int) (*X86Mmr, error) RegWriteMmr(reg int, value *X86Mmr) error Start(begin, until uint64) error @@ -62,9 +66,14 @@ type UcOptions struct { Timeout, Count uint64 } -func NewUnicorn(arch, mode int) (Unicorn, error) { +func Version() (int, int) { var major, minor C.uint C.uc_version(&major, &minor) + return int(major), int(minor) +} + +func NewUnicorn(arch, mode int) (Unicorn, error) { + major, minor := Version() if major != C.UC_API_MAJOR || minor != C.UC_API_MINOR { return nil, UcError(ERR_VERSION) } @@ -112,6 +121,38 @@ func (u *uc) RegRead(reg int) (uint64, error) { return uint64(val), errReturn(ucerr) } +func (u *uc) RegWriteBatch(regs []int, vals []uint64) error { + if len(regs) == 0 { + return nil + } + if len(vals) < len(regs) { + regs = regs[:len(vals)] + } + cregs := make([]C.int, len(regs)) + for i, v := range regs { + cregs[i] = C.int(v) + } + cregs2 := (*C.int)(unsafe.Pointer(&cregs[0])) + cvals := (*C.uint64_t)(unsafe.Pointer(&vals[0])) + ucerr := C.uc_reg_write_batch_helper(u.handle, cregs2, cvals, C.int(len(regs))) + return errReturn(ucerr) +} + +func (u *uc) RegReadBatch(regs []int) ([]uint64, error) { + if len(regs) == 0 { + return nil, nil + } + cregs := make([]C.int, len(regs)) + for i, v := range regs { + cregs[i] = C.int(v) + } + cregs2 := (*C.int)(unsafe.Pointer(&cregs[0])) + vals := make([]uint64, len(regs)) + cvals := (*C.uint64_t)(unsafe.Pointer(&vals[0])) + ucerr := C.uc_reg_read_batch_helper(u.handle, cregs2, cvals, C.int(len(regs))) + return vals, errReturn(ucerr) +} + func (u *uc) MemRegions() ([]*MemRegion, error) { var regions *C.struct_uc_mem_region var count C.uint32_t @@ -120,7 +161,7 @@ func (u *uc) MemRegions() ([]*MemRegion, error) { return nil, errReturn(ucerr) } ret := make([]*MemRegion, count) - tmp := (*[1 << 30]C.struct_uc_mem_region)(unsafe.Pointer(regions))[: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), diff --git a/bindings/go/unicorn/unicorn_const.go b/bindings/go/unicorn/unicorn_const.go index 1faff075..01b62fca 100644 --- a/bindings/go/unicorn/unicorn_const.go +++ b/bindings/go/unicorn/unicorn_const.go @@ -88,6 +88,7 @@ const ( HOOK_MEM_INVALID = 1008 HOOK_MEM_VALID = 7168 QUERY_MODE = 1 + QUERY_PAGE_SIZE = 2 PROT_NONE = 0 PROT_READ = 1 diff --git a/bindings/go/unicorn/x86_const.go b/bindings/go/unicorn/x86_const.go index 49e2310f..ef18c08e 100644 --- a/bindings/go/unicorn/x86_const.go +++ b/bindings/go/unicorn/x86_const.go @@ -250,7 +250,9 @@ const ( X86_REG_GDTR = 243 X86_REG_LDTR = 244 X86_REG_TR = 245 - X86_REG_ENDING = 246 + X86_REG_FPCW = 246 + X86_REG_FPTAG = 247 + X86_REG_ENDING = 248 // X86 instructions diff --git a/bindings/haskell/.gitignore b/bindings/haskell/.gitignore new file mode 100644 index 00000000..3b5b7859 --- /dev/null +++ b/bindings/haskell/.gitignore @@ -0,0 +1,23 @@ +dist +cabal-dev +*.o +*.hi +*.chi +*.chs.h +*.dyn_o +*.dyn_hi +.virtualenv +.hpc +.hsenv +.cabal-sandbox/ +cabal.sandbox.config +*.prof +*.aux +*.hp +SampleArm +SampleArm64 +SampleM68k +SampleMips +SampleSparc +SampleX86 +Shellcode diff --git a/bindings/haskell/README.TXT b/bindings/haskell/README.TXT new file mode 100644 index 00000000..93766f6d --- /dev/null +++ b/bindings/haskell/README.TXT @@ -0,0 +1,31 @@ +This documentation explains how to install Haskell binding for Unicorn +from source. + + +0. Install the core engine as dependency + + Follow README in the root directory to compile & install the core. + + On *nix, this can simply be done by (project root directory): + + $ sudo ./make.sh install + + +1. Change directories into the Haskell bindings, build and install + + $ cd bindings/haskell + $ cabal install + + +If you are installing into a sandbox, run `cabal sandbox init` before +installing Unicorn's dependencies. + +If the build fails, install c2hs manually `cabal install c2hs` (note that this +will probably also require you to run `cabal install alex` and `cabal install +happy` as well). If you are NOT using a sandbox, ensure that `$HOME/.cabal/bin` +is on your PATH. + +To build a sample (after having built and installed the Haskell bindings) + + $ cd bindings/haskell + $ ghc --make samples/SampleArm.hs diff --git a/bindings/haskell/Setup.hs b/bindings/haskell/Setup.hs new file mode 100644 index 00000000..9a994af6 --- /dev/null +++ b/bindings/haskell/Setup.hs @@ -0,0 +1,2 @@ +import Distribution.Simple +main = defaultMain diff --git a/bindings/haskell/samples/SampleArm.hs b/bindings/haskell/samples/SampleArm.hs new file mode 100644 index 00000000..3de51f36 --- /dev/null +++ b/bindings/haskell/samples/SampleArm.hs @@ -0,0 +1,133 @@ +-- Sample code to demonstrate how to emulate ARM code + +import Unicorn +import Unicorn.Hook +import qualified Unicorn.CPU.Arm as Arm + +import qualified Data.ByteString as BS +import Data.Word +import qualified Numeric as N (showHex) + +-- Code to be emulated +-- +-- mov r0, #0x37; sub r1, r2, r3 +armCode :: BS.ByteString +armCode = BS.pack [0x37, 0x00, 0xa0, 0xe3, 0x03, 0x10, 0x42, 0xe0] + +-- sub sp, #0xc +thumbCode :: BS.ByteString +thumbCode = BS.pack [0x83, 0xb0] + +-- Memory address where emulation starts +address :: Word64 +address = 0x10000 + +-- Pretty-print integral as hex +showHex :: (Integral a, Show a) => a -> String +showHex = + flip N.showHex "" + +-- Calculate code length +codeLength :: Num a => BS.ByteString -> a +codeLength = + fromIntegral . BS.length + +hookBlock :: BlockHook () +hookBlock _ addr size _ = + putStrLn $ ">>> Tracing basic block at 0x" ++ showHex addr ++ + ", block size = 0x" ++ (maybe "0" showHex size) + +hookCode :: CodeHook () +hookCode _ addr size _ = + putStrLn $ ">>> Tracing instruction at 0x" ++ showHex addr ++ + ", instruction size = 0x" ++ (maybe "0" showHex size) + +testArm :: IO () +testArm = do + putStrLn "Emulate ARM code" + + result <- runEmulator $ do + -- Initialize emulator in ARM mode + uc <- open ArchArm [ModeArm] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address armCode + + -- Initialize machine registers + regWrite uc Arm.R0 0x1234 + regWrite uc Arm.R2 0x6789 + regWrite uc Arm.R3 0x3333 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing one instruction at address with customized callback + codeHookAdd uc hookCode () address address + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all the code + let codeLen = codeLength armCode + start uc address (address + codeLen) Nothing Nothing + + -- Return the results + r0 <- regRead uc Arm.R0 + r1 <- regRead uc Arm.R1 + + return (r0, r1) + case result of + Right (r0, r1) -> do + -- Now print out some registers + putStrLn ">>> Emulation done. Below is the CPU context" + putStrLn $ ">>> R0 = 0x" ++ showHex r0 + putStrLn $ ">>> R1 = 0x" ++ showHex r1 + Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++ + strerror err ++ ")" + +testThumb :: IO () +testThumb = do + putStrLn "Emulate THUMB code" + + result <- runEmulator $ do + -- Initialize emulator in ARM mode + uc <- open ArchArm [ModeThumb] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address thumbCode + + -- Initialize machine registers + regWrite uc Arm.Sp 0x1234 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing one instruction at address with customized callback + codeHookAdd uc hookCode () address address + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all the code + let codeLen = codeLength thumbCode + start uc address (address + codeLen) Nothing Nothing + + -- Return the results + sp <- regRead uc Arm.Sp + + return sp + case result of + Right sp -> do + -- Now print out some registers + putStrLn ">>> Emulation done. Below is the CPU context" + putStrLn $ ">>> SP = 0x" ++ showHex sp + Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++ + strerror err ++ ")" + +main :: IO () +main = do + testArm + putStrLn "==========================" + testThumb diff --git a/bindings/haskell/samples/SampleArm64.hs b/bindings/haskell/samples/SampleArm64.hs new file mode 100644 index 00000000..db1158ae --- /dev/null +++ b/bindings/haskell/samples/SampleArm64.hs @@ -0,0 +1,85 @@ +-- Sample code to demonstrate how to emulate ARM64 code + +import Unicorn +import Unicorn.Hook +import qualified Unicorn.CPU.Arm64 as Arm64 + +import qualified Data.ByteString as BS +import Data.Word +import qualified Numeric as N (showHex) + +-- Code to be emulated +-- +-- add x11, x13, x15 +armCode :: BS.ByteString +armCode = BS.pack [0xab, 0x01, 0x0f, 0x8b] + +-- Memory address where emulation starts +address :: Word64 +address = 0x10000 + +-- Pretty-print integral as hex +showHex :: (Integral a, Show a) => a -> String +showHex = + flip N.showHex "" + +-- Calculate code length +codeLength :: Num a => BS.ByteString -> a +codeLength = + fromIntegral . BS.length + +hookBlock :: BlockHook () +hookBlock _ addr size _ = + putStrLn $ ">>> Tracing basic block at 0x" ++ showHex addr ++ + ", block size = 0x" ++ (maybe "0" showHex size) + +hookCode :: CodeHook () +hookCode _ addr size _ = + putStrLn $ ">>> Tracing instruction at 0x" ++ showHex addr ++ + ", instruction size = 0x" ++ (maybe "0" showHex size) + +testArm64 :: IO () +testArm64 = do + putStrLn "Emulate ARM64 code" + + result <- runEmulator $ do + -- Initialize emulator in ARM mode + uc <- open ArchArm64 [ModeArm] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address armCode + + -- Initialize machine registers + regWrite uc Arm64.X11 0x1234 + regWrite uc Arm64.X13 0x6789 + regWrite uc Arm64.X15 0x3333 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing one instruction at address with customized callback + codeHookAdd uc hookCode () address address + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all the code + let codeLen = codeLength armCode + start uc address (address + codeLen) Nothing Nothing + + -- Return the results + x11 <- regRead uc Arm64.X11 + + return x11 + case result of + Right x11 -> do + -- Now print out some registers + putStrLn $ ">>> Emulation done. Below is the CPU context" + putStrLn $ ">>> X11 = 0x" ++ showHex x11 + Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++ + strerror err ++ ")" + +main :: IO () +main = + testArm64 diff --git a/bindings/haskell/samples/SampleM68k.hs b/bindings/haskell/samples/SampleM68k.hs new file mode 100644 index 00000000..d77f4cfd --- /dev/null +++ b/bindings/haskell/samples/SampleM68k.hs @@ -0,0 +1,142 @@ +-- Sample code to demonstrate how to emulate m68k code + +import Unicorn +import Unicorn.Hook +import qualified Unicorn.CPU.M68k as M68k + +import qualified Data.ByteString as BS +import Data.Word +import qualified Numeric as N (showHex) + +-- Code to be emulated +-- +-- movq #-19, %d3 +m68kCode :: BS.ByteString +m68kCode = BS.pack [0x76, 0xed] + +-- Memory address where emulation starts +address :: Word64 +address = 0x10000 + +-- Pretty-print integral as hex +showHex :: (Integral a, Show a) => a -> String +showHex = + flip N.showHex "" + +-- Calculate code length +codeLength :: Num a => BS.ByteString -> a +codeLength = + fromIntegral . BS.length + +hookBlock :: BlockHook () +hookBlock _ addr size _ = + putStrLn $ ">>> Tracing basic block at 0x" ++ showHex addr ++ + ", block size = 0x" ++ (maybe "0" showHex size) + +hookCode :: CodeHook () +hookCode _ addr size _ = + putStrLn $ ">>> Tracing instruction at 0x" ++ showHex addr ++ + ", instruction size = 0x" ++ (maybe "0" showHex size) + +testM68k :: IO () +testM68k = do + putStrLn "Emulate M68K code" + + result <- runEmulator $ do + -- Initialize emulator in M68K mode + uc <- open ArchM68k [ModeBigEndian] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address m68kCode + + -- Initialize machine registers + regWrite uc M68k.D0 0x0000 + regWrite uc M68k.D1 0x0000 + regWrite uc M68k.D2 0x0000 + regWrite uc M68k.D3 0x0000 + regWrite uc M68k.D4 0x0000 + regWrite uc M68k.D5 0x0000 + regWrite uc M68k.D6 0x0000 + regWrite uc M68k.D7 0x0000 + + regWrite uc M68k.A0 0x0000 + regWrite uc M68k.A1 0x0000 + regWrite uc M68k.A2 0x0000 + regWrite uc M68k.A3 0x0000 + regWrite uc M68k.A4 0x0000 + regWrite uc M68k.A5 0x0000 + regWrite uc M68k.A6 0x0000 + regWrite uc M68k.A7 0x0000 + + regWrite uc M68k.Pc 0x0000 + regWrite uc M68k.Sr 0x0000 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing all instruction + codeHookAdd uc hookCode () 1 0 + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all the code + let codeLen = codeLength m68kCode + start uc address (address + codeLen) Nothing Nothing + + -- Return the results + d0 <- regRead uc M68k.D0 + d1 <- regRead uc M68k.D1 + d2 <- regRead uc M68k.D2 + d3 <- regRead uc M68k.D3 + d4 <- regRead uc M68k.D4 + d5 <- regRead uc M68k.D5 + d6 <- regRead uc M68k.D6 + d7 <- regRead uc M68k.D7 + + a0 <- regRead uc M68k.A0 + a1 <- regRead uc M68k.A1 + a2 <- regRead uc M68k.A2 + a3 <- regRead uc M68k.A3 + a4 <- regRead uc M68k.A4 + a5 <- regRead uc M68k.A5 + a6 <- regRead uc M68k.A6 + a7 <- regRead uc M68k.A7 + + pc <- regRead uc M68k.Pc + sr <- regRead uc M68k.Sr + + return (d0, d1, d2, d3, d4, d5, d6, d7, + a0, a1, a2, a3, a4, a5, a6, a7, + pc, sr) + case result of + Right (d0, d1, d2, d3, d4, d5, d6, d7, + a0, a1, a2, a3, a4, a5, a6, a7, + pc, sr) -> do + -- Now print out some registers + putStrLn ">>> Emulation done. Below is the CPU context" + putStrLn $ ">>> A0 = 0x" ++ showHex a0 ++ + "\t\t>>> D0 = 0x" ++ showHex d0 + putStrLn $ ">>> A1 = 0x" ++ showHex a1 ++ + "\t\t>>> D1 = 0x" ++ showHex d1 + putStrLn $ ">>> A2 = 0x" ++ showHex a2 ++ + "\t\t>>> D2 = 0x" ++ showHex d2 + putStrLn $ ">>> A3 = 0x" ++ showHex a3 ++ + "\t\t>>> D3 = 0x" ++ showHex d3 + putStrLn $ ">>> A4 = 0x" ++ showHex a4 ++ + "\t\t>>> D4 = 0x" ++ showHex d4 + putStrLn $ ">>> A5 = 0x" ++ showHex a5 ++ + "\t\t>>> D5 = 0x" ++ showHex d5 + putStrLn $ ">>> A6 = 0x" ++ showHex a6 ++ + "\t\t>>> D6 = 0x" ++ showHex d6 + putStrLn $ ">>> A7 = 0x" ++ showHex a7 ++ + "\t\t>>> D7 = 0x" ++ showHex d7 + putStrLn $ ">>> PC = 0x" ++ showHex pc + putStrLn $ ">>> SR = 0x" ++ showHex sr + Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++ + strerror err ++ ")" + +main :: IO () +main = + testM68k diff --git a/bindings/haskell/samples/SampleMips.hs b/bindings/haskell/samples/SampleMips.hs new file mode 100644 index 00000000..83efdbd3 --- /dev/null +++ b/bindings/haskell/samples/SampleMips.hs @@ -0,0 +1,129 @@ +-- Sample code to demonstrate how to emulate Mips code (big endian) + +import Unicorn +import Unicorn.Hook +import qualified Unicorn.CPU.Mips as Mips + +import qualified Data.ByteString as BS +import Data.Word +import qualified Numeric as N (showHex) + +-- Code to be emulated +-- +-- ori $at, $at, 0x3456 +mipsCodeEb :: BS.ByteString +mipsCodeEb = BS.pack [0x34, 0x21, 0x34, 0x56] + +-- ori $at, $at, 0x3456 +mipsCodeEl :: BS.ByteString +mipsCodeEl = BS.pack [0x56, 0x34, 0x21, 0x34] + +-- Memory address where emulation starts +address :: Word64 +address = 0x10000 + +-- Pretty-print integral as hex +showHex :: (Integral a, Show a) => a -> String +showHex = + flip N.showHex "" + +-- Calculate code length +codeLength :: Num a => BS.ByteString -> a +codeLength = + fromIntegral . BS.length + +hookBlock :: BlockHook () +hookBlock _ addr size _ = + putStrLn $ ">>> Tracing basic block at 0x" ++ showHex addr ++ + ", block size = 0x" ++ (maybe "0" showHex size) + +hookCode :: CodeHook () +hookCode _ addr size _ = + putStrLn $ ">>> Tracing instruction at 0x" ++ showHex addr ++ + ", instruction size = 0x" ++ (maybe "0" showHex size) + +testMipsEb :: IO () +testMipsEb = do + putStrLn "Emulate MIPS code (big-endian)" + + result <- runEmulator $ do + -- Initialize emulator in MIPS mode + uc <- open ArchMips [ModeMips32, ModeBigEndian] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address mipsCodeEb + + -- Initialise machine registers + regWrite uc Mips.Reg1 0x6789 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing one instruction at address with customized callback + codeHookAdd uc hookCode () address address + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all the code + let codeLen = codeLength mipsCodeEb + start uc address (address + codeLen) Nothing Nothing + + -- Return the results + r1 <- regRead uc Mips.Reg1 + + return r1 + case result of + Right r1 -> do + -- Now print out some registers + putStrLn ">>> Emulation done. Below is the CPU context" + putStrLn $ ">>> R1 = 0x" ++ showHex r1 + Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++ + strerror err ++ ")" + +testMipsEl :: IO () +testMipsEl = do + putStrLn "===========================" + putStrLn "Emulate MIPS code (little-endian)" + + result <- runEmulator $ do + -- Initialize emulator in MIPS mode + uc <- open ArchMips [ModeMips32, ModeLittleEndian] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address mipsCodeEl + + -- Initialize machine registers + regWrite uc Mips.Reg1 0x6789 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing one instruction at address with customized callback + codeHookAdd uc hookCode () address address + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all the code + let codeLen = codeLength mipsCodeEl + start uc address (address + codeLen) Nothing Nothing + + -- Return the results + r1 <- regRead uc Mips.Reg1 + + return r1 + case result of + Right r1 -> do + -- Now print out some registers + putStrLn ">>> Emulation done. Below is the CPU context" + putStrLn $ ">>> R1 = 0x" ++ showHex r1 + Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++ + strerror err ++ ")" + +main :: IO () +main = do + testMipsEb + testMipsEl diff --git a/bindings/haskell/samples/SampleSparc.hs b/bindings/haskell/samples/SampleSparc.hs new file mode 100644 index 00000000..02a0984b --- /dev/null +++ b/bindings/haskell/samples/SampleSparc.hs @@ -0,0 +1,85 @@ +-- Sample code to demonstrate how to emulate Sparc code + +import Unicorn +import Unicorn.Hook +import qualified Unicorn.CPU.Sparc as Sparc + +import qualified Data.ByteString as BS +import Data.Word +import qualified Numeric as N (showHex) + +-- Code to be emulated +-- +-- add %g1, %g2, %g3 +sparcCode :: BS.ByteString +sparcCode = BS.pack [0x86, 0x00, 0x40, 0x02] + +-- Memory address where emulation starts +address :: Word64 +address = 0x10000 + +-- Pretty-print integral as hex +showHex :: (Integral a, Show a) => a -> String +showHex = + flip N.showHex "" + +-- Calculate code length +codeLength :: Num a => BS.ByteString -> a +codeLength = + fromIntegral . BS.length + +hookBlock :: BlockHook () +hookBlock _ addr size _ = + putStrLn $ ">>> Tracing basic block at 0x" ++ showHex addr ++ + ", block size = 0x" ++ (maybe "0" showHex size) + +hookCode :: CodeHook () +hookCode _ addr size _ = + putStrLn $ ">>> Tracing instruction at 0x" ++ showHex addr ++ + ", instruction size = 0x" ++ (maybe "0" showHex size) + +testSparc :: IO () +testSparc = do + putStrLn "Emulate SPARC code" + + result <- runEmulator $ do + -- Initialize emulator in Sparc mode + uc <- open ArchSparc [ModeSparc32, ModeBigEndian] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address sparcCode + + -- Initialize machine registers + regWrite uc Sparc.G1 0x1230 + regWrite uc Sparc.G2 0x6789 + regWrite uc Sparc.G3 0x5555 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing all instructions with customized callback + codeHookAdd uc hookCode () 1 0 + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all the code + let codeLen = codeLength sparcCode + start uc address (address + codeLen) Nothing Nothing + + -- Return results + g3 <- regRead uc Sparc.G3 + + return g3 + case result of + Right g3 -> do + -- Now print out some registers + putStrLn ">>> Emulation done. Below is the CPU context" + putStrLn $ ">>> G3 = 0x" ++ showHex g3 + Left err -> putStrLn $ "Failed with error: " ++ show err ++ " (" ++ + strerror err ++ ")" + +main :: IO () +main = + testSparc diff --git a/bindings/haskell/samples/SampleX86.hs b/bindings/haskell/samples/SampleX86.hs new file mode 100644 index 00000000..fad686af --- /dev/null +++ b/bindings/haskell/samples/SampleX86.hs @@ -0,0 +1,675 @@ +-- Sample code to demonstrate how to emulate X86 code + +import Unicorn +import Unicorn.Hook +import qualified Unicorn.CPU.X86 as X86 + +import Control.Monad.Trans.Class (lift) +import qualified Data.ByteString as BS +import Data.Word +import qualified Numeric as N (showHex) +import System.Environment + +-- Code to be emulated +-- +-- inc ecx; dec edx +x86Code32 :: BS.ByteString +x86Code32 = BS.pack [0x41, 0x4a] + +-- jmp 4; nop; nop; nop; nop; nop; nop +x86Code32Jump :: BS.ByteString +x86Code32Jump = BS.pack [0xeb, 0x02, 0x90, 0x90, 0x90, 0x90, 0x90, 0x90] + +-- inc ecx; dec edx; jmp self-loop +x86Code32Loop :: BS.ByteString +x86Code32Loop = BS.pack [0x41, 0x4a, 0xeb, 0xfe] + +-- mov [0xaaaaaaaa], ecx; inc ecx; dec edx +x86Code32MemWrite :: BS.ByteString +x86Code32MemWrite = BS.pack [0x89, 0x0d, 0xaa, 0xaa, 0xaa, 0xaa, 0x41, 0x4a] + +-- mov ecx, [0xaaaaaaaa]; inc ecx; dec edx +x86Code32MemRead :: BS.ByteString +x86Code32MemRead = BS.pack [0x8b, 0x0d, 0xaa, 0xaa, 0xaa, 0xaa, 0x41, 0x4a] + +-- jmp ouside; inc ecx; dec edx +x86Code32JmpInvalid :: BS.ByteString +x86Code32JmpInvalid = BS.pack [0xe9, 0xe9, 0xee, 0xee, 0xee, 0x41, 0x4a] + +-- inc ecx; in al, 0x3f; dec edx; out 0x46, al; inc ebx +x86Code32InOut :: BS.ByteString +x86Code32InOut = BS.pack [0x41, 0xe4, 0x3f, 0x4a, 0xe6, 0x46, 0x43] + +x86Code64 :: BS.ByteString +x86Code64 = BS.pack [0x41, 0xbc, 0x3b, 0xb0, 0x28, 0x2a, 0x49, 0x0f, 0xc9, + 0x90, 0x4d, 0x0f, 0xad, 0xcf, 0x49, 0x87, 0xfd, 0x90, + 0x48, 0x81, 0xd2, 0x8a, 0xce, 0x77, 0x35, 0x48, 0xf7, + 0xd9, 0x4d, 0x29, 0xf4, 0x49, 0x81, 0xc9, 0xf6, 0x8a, + 0xc6, 0x53, 0x4d, 0x87, 0xed, 0x48, 0x0f, 0xad, 0xd2, + 0x49, 0xf7, 0xd4, 0x48, 0xf7, 0xe1, 0x4d, 0x19, 0xc5, + 0x4d, 0x89, 0xc5, 0x48, 0xf7, 0xd6, 0x41, 0xb8, 0x4f, + 0x8d, 0x6b, 0x59, 0x4d, 0x87, 0xd0, 0x68, 0x6a, 0x1e, + 0x09, 0x3c, 0x59] + +-- add byte ptr [bx + si], al +x86Code16 :: BS.ByteString +x86Code16 = BS.pack [0x00, 0x00] + +-- SYSCALL +x86Code64Syscall :: BS.ByteString +x86Code64Syscall = BS.pack [0x0f, 0x05] + +-- Memory address where emulation starts +address :: Word64 +address = 0x1000000 + +-- Pretty-print integral as hex +showHex :: (Integral a, Show a) => a -> String +showHex i = + N.showHex (fromIntegral i :: Word64) "" + +-- Pretty-print byte string as hex +showHexBS :: BS.ByteString -> String +showHexBS = + concatMap (flip N.showHex "") . reverse . BS.unpack + +-- Write a string (with a newline character) to standard output in the emulator +emuPutStrLn :: String -> Emulator () +emuPutStrLn = + lift . putStrLn + +-- Calculate code length +codeLength :: Num a => BS.ByteString -> a +codeLength = + fromIntegral . BS.length + +-- Callback for tracing basic blocks +hookBlock :: BlockHook () +hookBlock _ addr size _ = + putStrLn $ ">>> Tracing basic block at 0x" ++ showHex addr ++ + ", block size = 0x" ++ (maybe "0" showHex size) + +-- Callback for tracing instruction +hookCode :: CodeHook () +hookCode uc addr size _ = do + runEmulator $ do + emuPutStrLn $ ">>> Tracing instruction at 0x" ++ showHex addr ++ + ", instruction size = 0x" ++ (maybe "0" showHex size) + + eflags <- regRead uc X86.Eflags + emuPutStrLn $ ">>> --- EFLAGS is 0x" ++ showHex eflags + return () + +-- Callback for tracing instruction +hookCode64 :: CodeHook () +hookCode64 uc addr size _ = do + runEmulator $ do + rip <- regRead uc X86.Rip + emuPutStrLn $ ">>> Tracing instruction at 0x" ++ showHex addr ++ + ", instruction size = 0x" ++ (maybe "0" showHex size) + emuPutStrLn $ ">>> RIP is 0x" ++ showHex rip + return () + +-- Callback for tracing memory access (READ or WRITE) +hookMemInvalid :: MemoryEventHook () +hookMemInvalid uc MemWriteUnmapped addr size (Just value) _ = do + runEmulator $ do + emuPutStrLn $ ">>> Missing memory is being WRITE at 0x" ++ + showHex addr ++ ", data size = " ++ show size ++ + ", data value = 0x" ++ showHex value + memMap uc 0xaaaa0000 (2 * 1024 * 1024) [ProtAll] + return True +hookMemInvalid _ _ _ _ _ _ = + return False + +hookMem64 :: MemoryHook () +hookMem64 _ MemRead addr size _ _ = + putStrLn $ ">>> Memory is being READ at 0x" ++ showHex addr ++ + ", data size = " ++ show size +hookMem64 _ MemWrite addr size (Just value) _ = + putStrLn $ ">>> Memory is being WRITE at 0x" ++ showHex addr ++ + ", data size = " ++ show size ++ ", data value = 0x" ++ + showHex value + +-- Callback for IN instruction (X86) +-- This returns the data read from the port +hookIn :: InHook () +hookIn uc port size _ = do + result <- runEmulator $ do + eip <- regRead uc X86.Eip + + emuPutStrLn $ "--- reading from port 0x" ++ showHex port ++ + ", size: " ++ show size ++ ", address: 0x" ++ showHex eip + + case size of + -- Read 1 byte to AL + 1 -> return 0xf1 + -- Read 2 byte to AX + 2 -> return 0xf2 + -- Read 4 byte to EAX + 4 -> return 0xf4 + -- Should never reach this + _ -> return 0 + case result of + Right r -> return r + Left _ -> return 0 + +-- Callback for OUT instruction (X86) +hookOut :: OutHook () +hookOut uc port size value _ = do + runEmulator $ do + eip <- regRead uc X86.Eip + + emuPutStrLn $ "--- writing to port 0x" ++ showHex port ++ ", size: " ++ + show size ++ ", value: 0x" ++ showHex value ++ + ", address: 0x" ++ showHex eip + + -- Confirm that value is indeed the value of AL/AX/EAX + case size of + 1 -> do + tmp <- regRead uc X86.Al + emuPutStrLn $ "--- register value = 0x" ++ showHex tmp + 2 -> do + tmp <- regRead uc X86.Ax + emuPutStrLn $ "--- register value = 0x" ++ showHex tmp + 4 -> do + tmp <- regRead uc X86.Eax + emuPutStrLn $ "--- register value = 0x" ++ showHex tmp + -- Should never reach this + _ -> return () + return () + +-- Callback for SYSCALL instruction (X86) +hookSyscall :: SyscallHook () +hookSyscall uc _ = do + runEmulator $ do + rax <- regRead uc X86.Rax + if rax == 0x100 then + regWrite uc X86.Rax 0x200 + else + emuPutStrLn $ "ERROR: was not expecting rax=0x" ++ showHex rax ++ + " in syscall" + return () + +testI386 :: IO () +testI386 = do + putStrLn "Emulate i386 code" + + result <- runEmulator $ do + -- Initialize emulator in X86-32bit mode + uc <- open ArchX86 [Mode32] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address x86Code32 + + -- Initialize machine registers + regWrite uc X86.Ecx 0x1234 + regWrite uc X86.Edx 0x7890 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing all instruction by having @begin > @end + codeHookAdd uc hookCode () 1 0 + + -- Emulate machine code in infinite time + let codeLen = codeLength x86Code32 + start uc address (address + codeLen) Nothing Nothing + + -- Now print out some registers + emuPutStrLn ">>> Emulation done. Below is the CPU context" + + ecx <- regRead uc X86.Ecx + edx <- regRead uc X86.Edx + emuPutStrLn $ ">>> ECX = 0x" ++ showHex ecx + emuPutStrLn $ ">>> EDX = 0x" ++ showHex edx + + -- Read from memory + tmp <- memRead uc address 4 + emuPutStrLn $ ">>> Read 4 bytes from [0x" ++ showHex address ++ + "] = 0x" ++ showHexBS tmp + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +testI386Jump :: IO () +testI386Jump = do + putStrLn "===================================" + putStrLn "Emulate i386 code with jump" + + result <- runEmulator $ do + -- Initialize emulator in X86-32bit mode + uc <- open ArchX86 [Mode32] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address x86Code32Jump + + -- Tracing 1 basic block with customized callback + blockHookAdd uc hookBlock () address address + + -- Tracing 1 instruction at address + codeHookAdd uc hookCode () address address + + -- Emulate machine code ininfinite time + let codeLen = codeLength x86Code32Jump + start uc address (address + codeLen) Nothing Nothing + + emuPutStrLn ">>> Emulation done. Below is the CPU context" + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +-- Emulate code that loop forever +testI386Loop :: IO () +testI386Loop = do + putStrLn "===================================" + putStrLn "Emulate i386 code that loop forever" + + result <- runEmulator $ do + -- Initialize emulator in X86-32bit mode + uc <- open ArchX86 [Mode32] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated in memory + memWrite uc address x86Code32Loop + + -- Initialize machine registers + regWrite uc X86.Ecx 0x1234 + regWrite uc X86.Edx 0x7890 + + -- Emulate machine code in 2 seconds, so we can quit even if the code + -- loops + let codeLen = codeLength x86Code32Loop + start uc address (address + codeLen) (Just $ 2 * 1000000) Nothing + + -- Now print out some registers + emuPutStrLn ">>> Emulation done. Below is the CPU context" + + ecx <- regRead uc X86.Ecx + edx <- regRead uc X86.Edx + + emuPutStrLn $ ">>> ECX = 0x" ++ showHex ecx + emuPutStrLn $ ">>> EDX = 0x" ++ showHex edx + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +-- Emulate code that read invalid memory +testI386InvalidMemRead :: IO () +testI386InvalidMemRead = do + putStrLn "===================================" + putStrLn "Emulate i386 code that read from invalid memory" + + result <- runEmulator $ do + -- Initialize emulator in X86-32bit mode + uc <- open ArchX86 [Mode32] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address x86Code32MemRead + + -- Initialize machine registers + regWrite uc X86.Ecx 0x1234 + regWrite uc X86.Edx 0x7890 + + -- Tracing all basic block with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing all instructions by having @beegin > @end + codeHookAdd uc hookCode () 1 0 + + -- Emulate machine code in infinite time + let codeLen = codeLength x86Code32MemRead + start uc address (address + codeLen) Nothing Nothing + + -- Now print out some registers + emuPutStrLn ">>> Emulation done. Below is the CPU context" + + ecx <- regRead uc X86.Ecx + edx <- regRead uc X86.Edx + + emuPutStrLn $ ">>> ECX = 0x" ++ showHex ecx + emuPutStrLn $ ">>> EDX = 0x" ++ showHex edx + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +-- Emulate code that write invalid memory +testI386InvalidMemWrite :: IO () +testI386InvalidMemWrite = do + putStrLn "===================================" + putStrLn "Emulate i386 code that write to invalid memory" + + result <- runEmulator $ do + -- Initialize emulator in X86-32bit mode + uc <- open ArchX86 [Mode32] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address x86Code32MemWrite + + -- Initialize machine registers + regWrite uc X86.Ecx 0x1234 + regWrite uc X86.Edx 0x7890 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing all instruction by having @begin > @end + codeHookAdd uc hookCode () 1 0 + + -- Intercept invalid memory events + memoryEventHookAdd uc HookMemReadUnmapped hookMemInvalid () 1 0 + memoryEventHookAdd uc HookMemWriteUnmapped hookMemInvalid () 1 0 + + -- Emulate machine code in infinite time + let codeLen = codeLength x86Code32MemWrite + start uc address (address + codeLen) Nothing Nothing + + -- Now print out some registers + emuPutStrLn ">>> Emulation done. Below is the CPU context" + + ecx <- regRead uc X86.Ecx + edx <- regRead uc X86.Edx + emuPutStrLn $ ">>> ECX = 0x" ++ showHex ecx + emuPutStrLn $ ">>> EDX = 0x" ++ showHex edx + + -- Read from memory + tmp <- memRead uc 0xaaaaaaaa 4 + emuPutStrLn $ ">>> Read 4 bytes from [0x" ++ showHex 0xaaaaaaaa ++ + "] = 0x" ++ showHexBS tmp + + tmp <- memRead uc 0xffffffaa 4 + emuPutStrLn $ ">>> Read 4 bytes from [0x" ++ showHex 0xffffffaa ++ + "] = 0x" ++ showHexBS tmp + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +-- Emulate code that jump to invalid memory +testI386JumpInvalid :: IO () +testI386JumpInvalid = do + putStrLn "===================================" + putStrLn "Emulate i386 code that jumps to invalid memory" + + result <- runEmulator $ do + -- Initialize emulator in X86-32bit mode + uc <- open ArchX86 [Mode32] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address x86Code32JmpInvalid + + -- Initialize machine registers + regWrite uc X86.Ecx 0x1234 + regWrite uc X86.Edx 0x7890 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing all instructions by having @begin > @end + codeHookAdd uc hookCode () 1 0 + + -- Emulate machine code in infinite time + let codeLen = codeLength x86Code32JmpInvalid + start uc address (address + codeLen) Nothing Nothing + + -- Now print out some registers + emuPutStrLn ">>> Emulation done. Below is the CPU context" + + ecx <- regRead uc X86.Ecx + edx <- regRead uc X86.Edx + + emuPutStrLn $ ">>> ECX = 0x" ++ showHex ecx + emuPutStrLn $ ">>> EDX = 0x" ++ showHex edx + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +testI386InOut :: IO () +testI386InOut = do + putStrLn "===================================" + putStrLn "Emulate i386 code with IN/OUT instructions" + + result <- runEmulator $ do + -- Initialize emulator in X86-32bit mode + uc <- open ArchX86 [Mode32] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address x86Code32InOut + + -- Initialize machine registers + regWrite uc X86.Eax 0x1234 + regWrite uc X86.Ecx 0x6789 + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing all instructions + codeHookAdd uc hookCode () 1 0 + + -- uc IN instruction + inHookAdd uc hookIn () 1 0 + + -- uc OUT instruction + outHookAdd uc hookOut () 1 0 + + -- Emulate machine code in infinite time + let codeLen = codeLength x86Code32InOut + start uc address (address + codeLen) Nothing Nothing + + -- Now print out some registers + emuPutStrLn ">>> Emulation done. Below is the CPU context" + + eax <- regRead uc X86.Eax + ecx <- regRead uc X86.Ecx + + emuPutStrLn $ ">>> EAX = 0x" ++ showHex eax + emuPutStrLn $ ">>> ECX = 0x" ++ showHex ecx + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +testX8664 :: IO () +testX8664 = do + putStrLn "Emulate x86_64 code" + + result <- runEmulator $ do + -- Initialize emualator in X86-64bit mode + uc <- open ArchX86 [Mode64] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address x86Code64 + + -- Initialize machine registers + regWrite uc X86.Rsp (fromIntegral address + 0x200000) + + regWrite uc X86.Rax 0x71f3029efd49d41d + regWrite uc X86.Rbx 0xd87b45277f133ddb + regWrite uc X86.Rcx 0xab40d1ffd8afc461 + regWrite uc X86.Rdx 0x919317b4a733f01 + regWrite uc X86.Rsi 0x4c24e753a17ea358 + regWrite uc X86.Rdi 0xe509a57d2571ce96 + regWrite uc X86.R8 0xea5b108cc2b9ab1f + regWrite uc X86.R9 0x19ec097c8eb618c1 + regWrite uc X86.R10 0xec45774f00c5f682 + regWrite uc X86.R11 0xe17e9dbec8c074aa + regWrite uc X86.R12 0x80f86a8dc0f6d457 + regWrite uc X86.R13 0x48288ca5671c5492 + regWrite uc X86.R14 0x595f72f6e4017f6e + regWrite uc X86.R15 0x1efd97aea331cccc + + -- Tracing all basic blocks with customized callback + blockHookAdd uc hookBlock () 1 0 + + -- Tracing all instructions in the range [address, address+20] + codeHookAdd uc hookCode64 () address (address + 20) + + -- Tracing all memory WRITE access (with @begin > @end) + memoryHookAdd uc HookMemWrite hookMem64 () 1 0 + + -- Tracing all memory READ access (with @begin > @end) + memoryHookAdd uc HookMemRead hookMem64 () 1 0 + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all the code + let codeLen = codeLength x86Code64 + start uc address (address + codeLen) Nothing Nothing + + -- Now print out some registers + emuPutStrLn ">>> Emulation done. Below is the CPU context" + + rax <- regRead uc X86.Rax + rbx <- regRead uc X86.Rbx + rcx <- regRead uc X86.Rcx + rdx <- regRead uc X86.Rdx + rsi <- regRead uc X86.Rsi + rdi <- regRead uc X86.Rdi + r8 <- regRead uc X86.R8 + r9 <- regRead uc X86.R9 + r10 <- regRead uc X86.R10 + r11 <- regRead uc X86.R11 + r12 <- regRead uc X86.R12 + r13 <- regRead uc X86.R13 + r14 <- regRead uc X86.R14 + r15 <- regRead uc X86.R15 + + emuPutStrLn $ ">>> RAX = 0x" ++ showHex rax + emuPutStrLn $ ">>> RBX = 0x" ++ showHex rbx + emuPutStrLn $ ">>> RCX = 0x" ++ showHex rcx + emuPutStrLn $ ">>> RDX = 0x" ++ showHex rdx + emuPutStrLn $ ">>> RSI = 0x" ++ showHex rsi + emuPutStrLn $ ">>> RDI = 0x" ++ showHex rdi + emuPutStrLn $ ">>> R8 = 0x" ++ showHex r8 + emuPutStrLn $ ">>> R9 = 0x" ++ showHex r9 + emuPutStrLn $ ">>> R10 = 0x" ++ showHex r10 + emuPutStrLn $ ">>> R11 = 0x" ++ showHex r11 + emuPutStrLn $ ">>> R12 = 0x" ++ showHex r12 + emuPutStrLn $ ">>> R13 = 0x" ++ showHex r13 + emuPutStrLn $ ">>> R14 = 0x" ++ showHex r14 + emuPutStrLn $ ">>> R15 = 0x" ++ showHex r15 + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +testX8664Syscall :: IO () +testX8664Syscall = do + putStrLn "===================================" + putStrLn "Emulate x86_64 code with 'syscall' instruction" + + result <- runEmulator $ do + -- Initialize emulator in X86-64bit mode + uc <- open ArchX86 [Mode64] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address x86Code64Syscall + + -- Hook interrupts for syscall + syscallHookAdd uc hookSyscall () 1 0 + + -- Initialize machine registers + regWrite uc X86.Rax 0x100 + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all code + let codeLen = codeLength x86Code64Syscall + start uc address (address + codeLen) Nothing Nothing + + -- Now print out some registers + emuPutStrLn ">>> Emulation done. Below is the CPU context" + + rax <- regRead uc X86.Rax + emuPutStrLn $ ">>> RAX = 0x" ++ showHex rax + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +testX8616 :: IO () +testX8616 = do + putStrLn "Emulate x86 16-bit code" + + result <- runEmulator $ do + -- Initialize emulator in X86-16bit mode + uc <- open ArchX86 [Mode16] + + -- Map 8KB memory for this emulation + memMap uc 0 (8 * 1024) [ProtAll] + + -- Write machine code to be emulated in memory + memWrite uc 0 x86Code16 + + -- Initialize machine registers + regWrite uc X86.Eax 7 + regWrite uc X86.Ebx 5 + regWrite uc X86.Esi 6 + + -- Emulate machine code in infinite time (last param = Nothing), or + -- when finishing all the code + let codeLen = codeLength x86Code16 + start uc 0 codeLen Nothing Nothing + + -- Now print out some registers + emuPutStrLn ">>> Emulation done. Below is the CPU context" + + -- Read from memory + tmp <- memRead uc 11 1 + emuPutStrLn $ ">>> Read 1 bytes from [0x" ++ showHex 11 ++ + "] = 0x" ++ showHexBS tmp + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +main :: IO () +main = do + progName <- getProgName + args <- getArgs + case args of + ["-32"] -> do + testI386 + testI386InOut + testI386Jump + testI386Loop + testI386InvalidMemRead + testI386InvalidMemWrite + testI386JumpInvalid + ["-64"] -> do + testX8664 + testX8664Syscall + ["-16"] -> testX8616 + -- Test memleak + ["-0"] -> testI386 + _ -> putStrLn $ "Syntax: " ++ progName ++ " <-16|-32|-64>" + diff --git a/bindings/haskell/samples/Shellcode.hs b/bindings/haskell/samples/Shellcode.hs new file mode 100644 index 00000000..65ad979c --- /dev/null +++ b/bindings/haskell/samples/Shellcode.hs @@ -0,0 +1,153 @@ +-- Sample code to trace code with Linux code with syscall + +import Unicorn +import Unicorn.Hook +import qualified Unicorn.CPU.X86 as X86 + +import Control.Monad.Trans.Class (lift) +import qualified Data.ByteString as BS +import Data.Word +import qualified Numeric as N (showHex) +import System.Environment + +-- Code to be emulated +x86Code32 :: BS.ByteString +x86Code32 = BS.pack [0xeb, 0x19, 0x31, 0xc0, 0x31, 0xdb, 0x31, 0xd2, 0x31, + 0xc9, 0xb0, 0x04, 0xb3, 0x01, 0x59, 0xb2, 0x05, 0xcd, + 0x80, 0x31, 0xc0, 0xb0, 0x01, 0x31, 0xdb, 0xcd, 0x80, + 0xe8, 0xe2, 0xff, 0xff, 0xff, 0x68, 0x65, 0x6c, 0x6c, + 0x6f] + +x86Code32Self :: BS.ByteString +x86Code32Self = BS.pack [0xeb, 0x1c, 0x5a, 0x89, 0xd6, 0x8b, 0x02, 0x66, 0x3d, + 0xca, 0x7d, 0x75, 0x06, 0x66, 0x05, 0x03, 0x03, 0x89, + 0x02, 0xfe, 0xc2, 0x3d, 0x41, 0x41, 0x41, 0x41, 0x75, + 0xe9, 0xff, 0xe6, 0xe8, 0xdf, 0xff, 0xff, 0xff, 0x31, + 0xd2, 0x6a, 0x0b, 0x58, 0x99, 0x52, 0x68, 0x2f, 0x2f, + 0x73, 0x68, 0x68, 0x2f, 0x62, 0x69, 0x6e, 0x89, 0xe3, + 0x52, 0x53, 0x89, 0xe1, 0xca, 0x7d, 0x41, 0x41, 0x41, + 0x41, 0x41, 0x41, 0x41, 0x41] + +-- Memory address where emulation starts +address :: Word64 +address = 0x1000000 + +-- Pretty-print integral as hex +showHex :: (Integral a, Show a) => a -> String +showHex = + flip N.showHex "" + +-- Pretty-print byte string as hex +showHexBS :: BS.ByteString -> String +showHexBS = + concatMap (flip N.showHex " ") . BS.unpack + +-- Write a string (with a newline character) to standard output in the emulator +emuPutStrLn :: String -> Emulator () +emuPutStrLn = + lift . putStrLn + +-- Calculate code length +codeLength :: Num a => BS.ByteString -> a +codeLength = + fromIntegral . BS.length + +-- Callback for tracing instructions +hookCode :: CodeHook () +hookCode uc addr size _ = do + runEmulator $ do + emuPutStrLn $ "Tracing instruction at 0x" ++ showHex addr ++ + ", instruction size = 0x" ++ (maybe "0" showHex size) + + eip <- regRead uc X86.Eip + tmp <- memRead uc addr (maybe 0 id size) + + emuPutStrLn $ "*** EIP = " ++ showHex eip ++ " ***: " ++ showHexBS tmp + return () + +-- Callback for handling interrupts +-- ref: http://syscalls.kernelgrok.com +hookIntr :: InterruptHook () +hookIntr uc intno _ + | intno == 0x80 = do + runEmulator $ do + eax <- regRead uc X86.Eax + eip <- regRead uc X86.Eip + + case eax of + -- sys_exit + 1 -> do + emuPutStrLn $ ">>> 0x" ++ showHex eip ++ + ": interrupt 0x" ++ showHex intno ++ + ", SYS_EXIT. quit!\n" + stop uc + -- sys_write + 4 -> do + -- ECX = buffer address + ecx <- regRead uc X86.Ecx + + -- EDX = buffer size + edx <- regRead uc X86.Edx + + -- Read the buffer in + buffer <- memRead uc (fromIntegral ecx) (fromIntegral edx) + err <- errno uc + if err == ErrOk then + emuPutStrLn $ ">>> 0x" ++ showHex eip ++ + ": interrupt 0x" ++ showHex intno ++ + ", SYS_WRITE. buffer = 0x" ++ + showHex ecx ++ ", size = " ++ + show edx ++ ", content = " ++ + showHexBS buffer + else + emuPutStrLn $ ">>> 0x" ++ showHex eip ++ + ": interrupt 0x" ++ showHex intno ++ + ", SYS_WRITE. buffer = 0x" ++ + showHex ecx ++ ", size = " ++ show edx ++ + " (cannot get content)" + _ -> emuPutStrLn $ ">>> 0x" ++ showHex eip ++ + ": interrupt 0x" ++ showHex intno ++ + ", EAX = 0x" ++ showHex eax + return () + | otherwise = return () + +testI386 :: IO () +testI386 = do + result <- runEmulator $ do + emuPutStrLn "Emulate i386 code" + + -- Initialize emulator in X86-32bit mode + uc <- open ArchX86 [Mode32] + + -- Map 2MB memory for this emulation + memMap uc address (2 * 1024 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address x86Code32Self + + -- Initialize machine registers + regWrite uc X86.Esp (fromIntegral address + 0x200000) + + -- Tracing all instructions by having @begin > @end + codeHookAdd uc hookCode () 1 0 + + -- Handle interrupt ourself + interruptHookAdd uc hookIntr () 1 0 + + emuPutStrLn "\n>>> Start tracing this Linux code" + + -- Emulate machine code in infinite time + let codeLen = codeLength x86Code32Self + start uc address (address + codeLen) Nothing Nothing + case result of + Right _ -> putStrLn "\n>>> Emulation done." + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + +main :: IO () +main = do + progName <- getProgName + args <- getArgs + case args of + ["-32"] -> testI386 + _ -> putStrLn $ "Syntax: " ++ progName ++ " <-32|-64>" diff --git a/bindings/haskell/src/Unicorn.hs b/bindings/haskell/src/Unicorn.hs new file mode 100644 index 00000000..856133ff --- /dev/null +++ b/bindings/haskell/src/Unicorn.hs @@ -0,0 +1,284 @@ +{-| +Module : Unicorn +Description : The Unicorn CPU emulator. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Unicorn is a lightweight, multi-platform, multi-architecture CPU emulator +framework based on QEMU. + +Further information is available at . +-} +module Unicorn ( + -- * Emulator control + Emulator, + Engine, + Architecture(..), + Mode(..), + QueryType(..), + runEmulator, + open, + query, + start, + stop, + + -- * Register operations + regWrite, + regRead, + + -- * Memory operations + MemoryPermission(..), + MemoryRegion(..), + memWrite, + memRead, + memMap, + memUnmap, + memProtect, + memRegions, + + -- * Error handling + Error(..), + errno, + strerror, + + -- * Misc. + version, +) where + +import Control.Monad (liftM) +import Control.Monad.Trans.Class (lift) +import Control.Monad.Trans.Either (hoistEither, left, right, runEitherT) +import Foreign + +import Prelude hiding (until) +import Data.ByteString (ByteString, pack) + +import Unicorn.Internal.Core +import Unicorn.Internal.Unicorn + +------------------------------------------------------------------------------- +-- Emulator control +------------------------------------------------------------------------------- + +-- | Run the Unicorn emulator and return a result on success, or an 'Error' on +-- failure. +runEmulator :: Emulator a -- ^ The emulation code to execute + -> IO (Either Error a) -- ^ A result on success, or an 'Error' on + -- failure +runEmulator = + runEitherT + +-- | Create a new instance of the Unicorn engine. +open :: Architecture -- ^ CPU architecture + -> [Mode] -- ^ CPU hardware mode + -> Emulator Engine -- ^ A 'Unicorn' engine on success, or an 'Error' on + -- failure +open arch mode = do + (err, ucPtr) <- lift $ ucOpen arch mode + if err == ErrOk then + -- Return a pointer to the unicorn engine if ucOpen completed + -- successfully + lift $ mkEngine ucPtr + else + -- Otherwise return the error + left err + +-- | Query internal status of the Unicorn engine. +query :: Engine -- ^ 'Unicorn' engine handle + -> QueryType -- ^ Query type + -> Emulator Int -- ^ The result of the query +query uc queryType = do + (err, result) <- lift $ ucQuery uc queryType + if err == ErrOk then + right result + else + left err + +-- | Emulate machine code for a specific duration of time. +start :: Engine -- ^ 'Unicorn' engine handle + -> Word64 -- ^ Address where emulation starts + -> Word64 -- ^ Address where emulation stops (i.e. when this + -- address is hit) + -> Maybe Int -- ^ Optional duration to emulate code (in + -- microseconds). + -- If 'Nothing' is provided, continue to emulate + -- until the code is finished + -> Maybe Int -- ^ Optional number of instructions to emulate. If + -- 'Nothing' is provided, emulate all the code + -- available, until the code is finished + -> Emulator () -- ^ An 'Error' on failure +start uc begin until timeout count = do + err <- lift $ ucEmuStart uc begin until (maybeZ timeout) (maybeZ count) + if err == ErrOk then + right () + else + left err + where maybeZ = maybe 0 id + +-- | Stop emulation (which was started by 'start'). +-- This is typically called from callback functions registered by tracing APIs. +-- +-- NOTE: For now, this will stop execution only after the current block. +stop :: Engine -- ^ 'Unicorn' engine handle + -> Emulator () -- ^ An 'Error' on failure +stop uc = do + err <- lift $ ucEmuStop uc + if err == ErrOk then + right () + else + left err + +------------------------------------------------------------------------------- +-- Register operations +------------------------------------------------------------------------------- + +-- | Write to register. +regWrite :: Reg r => + Engine -- ^ 'Unicorn' engine handle + -> r -- ^ Register ID to write to + -> Int64 -- ^ Value to write to register + -> Emulator () -- ^ An 'Error' on failure +regWrite uc regId value = do + err <- lift . alloca $ \ptr -> do + poke ptr value + ucRegWrite uc regId ptr + if err == ErrOk then + right () + else + left err + +-- | Read register value. +regRead :: Reg r => + Engine -- ^ 'Unicorn' engine handle + -> r -- ^ Register ID to read from + -> Emulator Int64 -- ^ The value read from the register on success, + -- or an 'Error' on failure +regRead uc regId = do + (err, val) <- lift $ ucRegRead uc regId + if err == ErrOk then + right val + else + left err + +------------------------------------------------------------------------------- +-- Memory operations +------------------------------------------------------------------------------- + +-- | Write to memory. +memWrite :: Engine -- ^ 'Unicorn' engine handle + -> Word64 -- ^ Starting memory address of bytes to write + -> ByteString -- ^ The data to write + -> Emulator () -- ^ An 'Error' on failure +memWrite uc address bytes = do + err <- lift $ ucMemWrite uc address bytes + if err == ErrOk then + right () + else + left err + +-- | Read memory contents. +memRead :: Engine -- ^ 'Unicorn' engine handle + -> Word64 -- ^ Starting memory address to read + -- from + -> Int -- ^ Size of memory to read (in bytes) + -> Emulator ByteString -- ^ The memory contents on success, or + -- an 'Error' on failure +memRead uc address size = do + -- Allocate an array of the given size + result <- lift . allocaArray size $ \ptr -> do + err <- ucMemRead uc address ptr size + if err == ErrOk then + -- If ucMemRead completed successfully, pack the contents of the + -- array into a ByteString and return it + liftM (Right . pack) (peekArray size ptr) + else + -- Otherwise return the error + return $ Left err + hoistEither result + +-- | Map a range of memory. +memMap :: Engine -- ^ 'Unicorn' engine handle + -> Word64 -- ^ Start address of the new memory region to + -- be mapped in. This address must be + -- aligned to 4KB, or this will return with + -- 'ErrArg' error + -> Int -- ^ Size of the new memory region to be mapped + -- in. This size must be a multiple of 4KB, or + -- this will return with an 'ErrArg' error + -> [MemoryPermission] -- ^ Permissions for the newly mapped region + -> Emulator () -- ^ An 'Error' on failure +memMap uc address size perms = do + err <- lift $ ucMemMap uc address size perms + if err == ErrOk then + right () + else + left err + +-- | Unmap a range of memory. +memUnmap :: Engine -- ^ 'Unicorn' engine handle + -> Word64 -- ^ Start addres of the memory region to be unmapped. + -- This address must be aligned to 4KB or this will + -- return with an 'ErrArg' error + -> Int -- ^ Size of the memory region to be modified. This + -- must be a multiple of 4KB, or this will return with + -- an 'ErrArg' error + -> Emulator () -- ^ An 'Error' on failure +memUnmap uc address size = do + err <- lift $ ucMemUnmap uc address size + if err == ErrOk then + right () + else + left err + +-- | Change permissions on a range of memory. +memProtect :: Engine -- ^ 'Unicorn' engine handle + -> Word64 -- ^ Start address of the memory region to + -- modify. This address must be aligned to + -- 4KB, or this will return with an + -- 'ErrArg' error + -> Int -- ^ Size of the memory region to be + -- modified. This size must be a multiple + -- of 4KB, or this will return with an + -- 'ErrArg' error + -> [MemoryPermission] -- ^ New permissions for the mapped region + -> Emulator () -- ^ An 'Error' on failure +memProtect uc address size perms = do + err <- lift $ ucMemProtect uc address size perms + if err == ErrOk then + right () + else + left err + +-- | Retrieve all memory regions mapped by 'memMap'. +memRegions :: Engine -- ^ 'Unicorn' engine handle + -> Emulator [MemoryRegion] -- ^ A list of memory regions +memRegions uc = do + (err, regionPtr, count) <- lift $ ucMemRegions uc + if err == ErrOk then do + regions <- lift $ peekArray count regionPtr + right regions + else + left err + +------------------------------------------------------------------------------- +-- Misc. +------------------------------------------------------------------------------- + +-- | Combined API version & major and minor version numbers. Returns a +-- hexadecimal number as (major << 8 | minor), which encodes both major and +-- minor versions. +version :: Int +version = + ucVersion nullPtr nullPtr + +-- | Report the 'Error' of the last failed API call. +errno :: Engine -- ^ 'Unicorn' engine handle + -> Emulator Error -- ^ The last 'Error' code +errno = + lift . ucErrno + +-- | Return a string describing the given 'Error'. +strerror :: Error -- ^ The 'Error' code + -> String -- ^ Description of the error code +strerror = + ucStrerror diff --git a/bindings/haskell/src/Unicorn/CPU/Arm.chs b/bindings/haskell/src/Unicorn/CPU/Arm.chs new file mode 100644 index 00000000..fbc3294c --- /dev/null +++ b/bindings/haskell/src/Unicorn/CPU/Arm.chs @@ -0,0 +1,29 @@ +{-# LANGUAGE ForeignFunctionInterface #-} + +{-| +Module : Unicorn.CPU.Arm +Description : Definitions for the ARM architecture. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Definitions for the ARM architecture. +-} +module Unicorn.CPU.Arm ( + Register(..), +) where + +import Unicorn.Internal.Core (Reg) + +{# context lib="unicorn" #} + +#include + +-- | ARM registers. +{# enum uc_arm_reg as Register + {underscoreToCase} + omit (UC_ARM_REG_INVALID, + UC_ARM_REG_ENDING) + with prefix="UC_ARM_REG_" + deriving (Show, Eq, Bounded) #} + +instance Reg Register diff --git a/bindings/haskell/src/Unicorn/CPU/Arm64.chs b/bindings/haskell/src/Unicorn/CPU/Arm64.chs new file mode 100644 index 00000000..6174ef89 --- /dev/null +++ b/bindings/haskell/src/Unicorn/CPU/Arm64.chs @@ -0,0 +1,29 @@ +{-# LANGUAGE ForeignFunctionInterface #-} + +{-| +Module : Unicorn.CPU.Arm64 +Description : Definitions for the ARM64 (ARMv8) architecture. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Definitions for the ARM64 (ARMv8) architecture. +-} +module Unicorn.CPU.Arm64 ( + Register(..), +) where + +import Unicorn.Internal.Core (Reg) + +{# context lib="unicorn" #} + +#include + +-- | ARM64 registers. +{# enum uc_arm64_reg as Register + {underscoreToCase} + omit (UC_ARM64_REG_INVALID, + UC_ARM64_REG_ENDING) + with prefix="UC_ARM64_REG_" + deriving (Show, Eq, Bounded) #} + +instance Reg Register diff --git a/bindings/haskell/src/Unicorn/CPU/M68k.chs b/bindings/haskell/src/Unicorn/CPU/M68k.chs new file mode 100644 index 00000000..25753aa4 --- /dev/null +++ b/bindings/haskell/src/Unicorn/CPU/M68k.chs @@ -0,0 +1,29 @@ +{-# LANGUAGE ForeignFunctionInterface #-} + +{-| +Module : Unicorn.CPU.Mk68k +Description : Definitions for the MK68K architecture. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Definitions for the MK68K architecture. +-} +module Unicorn.CPU.M68k ( + Register(..), +) where + +import Unicorn.Internal.Core (Reg) + +{# context lib="unicorn" #} + +#include + +-- | M68K registers. +{# enum uc_m68k_reg as Register + {underscoreToCase} + omit (UC_M68K_REG_INVALID, + UC_M68K_REG_ENDING) + with prefix="UC_M68K_REG_" + deriving (Show, Eq, Bounded) #} + +instance Reg Register diff --git a/bindings/haskell/src/Unicorn/CPU/Mips.chs b/bindings/haskell/src/Unicorn/CPU/Mips.chs new file mode 100644 index 00000000..b234ba72 --- /dev/null +++ b/bindings/haskell/src/Unicorn/CPU/Mips.chs @@ -0,0 +1,61 @@ +{-# LANGUAGE ForeignFunctionInterface #-} + +{-| +Module : Unicorn.CPU.Mips +Description : Definitions for the MIPS architecture. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Definitions for the MIPS architecture. +-} +module Unicorn.CPU.Mips ( + Register(..), +) where + +import Unicorn.Internal.Core (Reg) + +{# context lib="unicorn" #} + +#include + +-- | MIPS registers. +{# enum UC_MIPS_REG as Register + {underscoreToCase, + UC_MIPS_REG_0 as Reg0, + UC_MIPS_REG_1 as Reg1, + UC_MIPS_REG_2 as Reg2, + UC_MIPS_REG_3 as Reg3, + UC_MIPS_REG_4 as Reg4, + UC_MIPS_REG_5 as Reg5, + UC_MIPS_REG_6 as Reg6, + UC_MIPS_REG_7 as Reg7, + UC_MIPS_REG_8 as Reg8, + UC_MIPS_REG_9 as Reg9, + UC_MIPS_REG_10 as Reg10, + UC_MIPS_REG_11 as Reg11, + UC_MIPS_REG_12 as Reg12, + UC_MIPS_REG_13 as Reg13, + UC_MIPS_REG_14 as Reg14, + UC_MIPS_REG_15 as Reg15, + UC_MIPS_REG_16 as Reg16, + UC_MIPS_REG_17 as Reg17, + UC_MIPS_REG_18 as Reg18, + UC_MIPS_REG_19 as Reg19, + UC_MIPS_REG_20 as Reg20, + UC_MIPS_REG_21 as Reg21, + UC_MIPS_REG_22 as Reg22, + UC_MIPS_REG_23 as Reg23, + UC_MIPS_REG_24 as Reg24, + UC_MIPS_REG_25 as Reg25, + UC_MIPS_REG_26 as Reg26, + UC_MIPS_REG_27 as Reg27, + UC_MIPS_REG_28 as Reg28, + UC_MIPS_REG_29 as Reg29, + UC_MIPS_REG_30 as Reg30, + UC_MIPS_REG_31 as Reg31} + omit (UC_MIPS_REG_INVALID, + UC_MIPS_REG_ENDING) + with prefix="UC_MIPS_REG_" + deriving (Show, Eq, Bounded) #} + +instance Reg Register diff --git a/bindings/haskell/src/Unicorn/CPU/Sparc.chs b/bindings/haskell/src/Unicorn/CPU/Sparc.chs new file mode 100644 index 00000000..a94c1b22 --- /dev/null +++ b/bindings/haskell/src/Unicorn/CPU/Sparc.chs @@ -0,0 +1,29 @@ +{-# LANGUAGE ForeignFunctionInterface #-} + +{-| +Module : Unicorn.CPU.Sparc +Description : Definitions for the SPARC architecture. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Definitions for the SPARC architecture. +-} +module Unicorn.CPU.Sparc ( + Register(..), +) where + +import Unicorn.Internal.Core (Reg) + +{# context lib="unicorn" #} + +#include + +-- | SPARC registers. +{# enum uc_sparc_reg as Register + {underscoreToCase} + omit (UC_SPARC_REG_INVALID, + UC_SPARC_REG_ENDING) + with prefix="UC_SPARC_REG_" + deriving (Show, Eq, Bounded) #} + +instance Reg Register diff --git a/bindings/haskell/src/Unicorn/CPU/X86.chs b/bindings/haskell/src/Unicorn/CPU/X86.chs new file mode 100644 index 00000000..eb99c978 --- /dev/null +++ b/bindings/haskell/src/Unicorn/CPU/X86.chs @@ -0,0 +1,65 @@ +{-# LANGUAGE ForeignFunctionInterface #-} + +{-| +Module : Unicorn.CPU.X86 +Description : Definitions for the X86 architecture. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Definitions for the X86 architecture. +-} +module Unicorn.CPU.X86 ( + Mmr(..), + Register(..), + Instruction(..), +) where + +import Control.Applicative +import Data.Word +import Foreign + +import Unicorn.Internal.Core (Reg) + +{# context lib="unicorn" #} + +#include + +-- | Memory-managemen Register for instructions IDTR, GDTR, LDTR, TR. +-- Borrow from SegmentCache in qemu/target-i386/cpu.h +data Mmr = Mmr { + mmrSelector :: Word16, -- ^ Not used by GDTR and IDTR + mmrBase :: Word64, -- ^ Handle 32 or 64 bit CPUs + mmrLimit :: Word32, + mmrFlags :: Word32 -- ^ Not used by GDTR and IDTR +} + +instance Storable Mmr where + sizeOf _ = {# sizeof uc_x86_mmr #} + alignment _ = {# alignof uc_x86_mmr #} + peek p = Mmr <$> liftA fromIntegral ({# get uc_x86_mmr->selector #} p) + <*> liftA fromIntegral ({# get uc_x86_mmr->base #} p) + <*> liftA fromIntegral ({# get uc_x86_mmr->limit #} p) + <*> liftA fromIntegral ({# get uc_x86_mmr->flags #} p) + poke p mmr = do + {# set uc_x86_mmr.selector #} p (fromIntegral $ mmrSelector mmr) + {# set uc_x86_mmr.base #} p (fromIntegral $ mmrBase mmr) + {# set uc_x86_mmr.limit #} p (fromIntegral $ mmrLimit mmr) + {# set uc_x86_mmr.flags #} p (fromIntegral $ mmrFlags mmr) + +-- | X86 registers. +{# enum uc_x86_reg as Register + {underscoreToCase} + omit (UC_X86_REG_INVALID, + UC_X86_REG_ENDING) + with prefix="UC_X86_REG_" + deriving (Show, Eq, Bounded) #} + +instance Reg Register + +-- | X86 instructions. +{# enum uc_x86_insn as Instruction + {underscoreToCase} + omit (UC_X86_INS_INVALID, + UC_X86_INS_ENDING) + with prefix="UC_X86_INS_" + deriving (Show, Eq, Bounded) #} diff --git a/bindings/haskell/src/Unicorn/Hook.hs b/bindings/haskell/src/Unicorn/Hook.hs new file mode 100644 index 00000000..2e13ebc4 --- /dev/null +++ b/bindings/haskell/src/Unicorn/Hook.hs @@ -0,0 +1,223 @@ +{-| +Module : Unicorn.Hook +Description : Unicorn hooks. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Insert hook points into the Unicorn emulator engine. +-} +module Unicorn.Hook ( + -- * Hook types + Hook, + MemoryHookType(..), + MemoryEventHookType(..), + MemoryAccess(..), + + -- * Hook callbacks + CodeHook, + InterruptHook, + BlockHook, + InHook, + OutHook, + SyscallHook, + MemoryHook, + MemoryReadHook, + MemoryWriteHook, + MemoryEventHook, + + -- * Hook callback management + codeHookAdd, + interruptHookAdd, + blockHookAdd, + inHookAdd, + outHookAdd, + syscallHookAdd, + memoryHookAdd, + memoryEventHookAdd, + hookDel, +) where + +import Control.Monad +import Control.Monad.Trans.Class +import Control.Monad.Trans.Either (hoistEither, left, right) +import Foreign + +import Unicorn.Internal.Core +import Unicorn.Internal.Hook +import qualified Unicorn.CPU.X86 as X86 + +------------------------------------------------------------------------------- +-- Hook callback management (registration and deletion) +------------------------------------------------------------------------------- + +-- | Register a callback for a code hook event. +codeHookAdd :: Storable a + => Engine -- ^ 'Unicorn' engine handle + -> CodeHook a -- ^ Code hook callback + -> a -- ^ User-defined data. This will be passed to + -- the callback function + -> Word64 -- ^ Start address + -> Word64 -- ^ End address + -> Emulator Hook -- ^ The hook handle on success, or an 'Error' + -- on failure +codeHookAdd uc callback userData begin end = do + result <- lift . alloca $ \userDataPtr -> do + poke userDataPtr userData + funPtr <- marshalCodeHook callback + getResult $ ucHookAdd uc HookCode funPtr userDataPtr begin end + hoistEither result + +-- | Register a callback for an interrupt hook event. +interruptHookAdd :: Storable a + => Engine -- ^ 'Unicorn' engine handle + -> InterruptHook a -- ^ Interrupt callback + -> a -- ^ User-defined data. This will be passed + -- to the callback function + -> Word64 -- ^ Start address + -> Word64 -- ^ End address + -> Emulator Hook -- ^ The hook handle on success, or 'Error' + -- on failure +interruptHookAdd uc callback userData begin end = do + result <- lift . alloca $ \userDataPtr -> do + poke userDataPtr userData + funPtr <- marshalInterruptHook callback + getResult $ ucHookAdd uc HookIntr funPtr userDataPtr begin end + hoistEither result + +-- | Register a callback for a block hook event. +blockHookAdd :: Storable a + => Engine -- ^ 'Unicorn' engine handle + -> BlockHook a -- ^ Block callback + -> a -- ^ User-defined data. This will be passed to + -- the callback function + -> Word64 -- ^ Start address + -> Word64 -- ^ End address + -> Emulator Hook -- ^ The hook handle on success, or an 'Error' + -- on failure +blockHookAdd uc callback userData begin end = do + result <- lift . alloca $ \userDataPtr -> do + poke userDataPtr userData + funPtr <- marshalBlockHook callback + getResult $ ucHookAdd uc HookBlock funPtr userDataPtr begin end + hoistEither result + +-- | Register a callback for an IN instruction hook event (X86). +inHookAdd :: Storable a + => Engine -- ^ 'Unicorn' engine handle + -> InHook a -- ^ IN instruction callback + -> a -- ^ User-defined data. This will be passed to the + -- callback function + -> Word64 -- ^ Start address + -> Word64 -- ^ End address + -> Emulator Hook -- ^ The hook handle on success, or an 'Error' on + -- failure +inHookAdd uc callback userData begin end = do + result <- lift . alloca $ \userDataPtr -> do + poke userDataPtr userData + funPtr <- marshalInHook callback + getResult $ ucInsnHookAdd uc HookInsn funPtr userDataPtr begin end + X86.In + hoistEither result + +-- | Register a callback for an OUT instruction hook event (X86). +outHookAdd :: Storable a + => Engine -- ^ 'Unicorn' engine handle + -> OutHook a -- ^ OUT instruction callback + -> a -- ^ User-defined data. This will be passed to the + -- callback function + -> Word64 -- ^ Start address + -> Word64 -- ^ End address + -> Emulator Hook -- ^ The hook handle on success, or an 'Error' on + -- failure +outHookAdd uc callback userData begin end = do + result <- lift . alloca $ \userDataPtr -> do + poke userDataPtr userData + funPtr <- marshalOutHook callback + getResult $ ucInsnHookAdd uc HookInsn funPtr userDataPtr begin end + X86.Out + hoistEither result + +-- | Register a callback for a SYSCALL instruction hook event (X86). +syscallHookAdd :: Storable a + => Engine -- ^ 'Unicorn' engine handle + -> SyscallHook a -- ^ SYSCALL instruction callback + -> a -- ^ User-defined data. This will be passed to + -- the callback function + -> Word64 -- ^ Start address + -> Word64 -- ^ End address + -> Emulator Hook -- ^ The hook handle on success, or an 'Error' + -- on failure +syscallHookAdd uc callback userData begin end = do + result <- lift . alloca $ \userDataPtr -> do + poke userDataPtr userData + funPtr <- marshalSyscallHook callback + getResult $ ucInsnHookAdd uc HookInsn funPtr userDataPtr begin end + X86.Syscall + hoistEither result + +-- | Register a callback for a valid memory access event. +memoryHookAdd :: Storable a + => Engine -- ^ 'Unicorn' engine handle + -> MemoryHookType -- ^ A valid memory access (e.g. read, write, + -- etc.) to trigger the callback on + -> MemoryHook a -- ^ Memory access callback + -> a -- ^ User-defined data. This will be passed to + -- the callback function + -> Word64 -- ^ Start address + -> Word64 -- ^ End address + -> Emulator Hook -- ^ The hook handle on success, or an 'Error' + -- on failure +memoryHookAdd uc memHookType callback userData begin end = do + result <- lift . alloca $ \userDataPtr -> do + poke userDataPtr userData + funPtr <- marshalMemoryHook callback + getResult $ ucHookAdd uc memHookType funPtr userDataPtr begin end + hoistEither result + +-- | Register a callback for an invalid memory access event. +memoryEventHookAdd :: Storable a + => Engine -- ^ 'Unicorn' engine handle + -> MemoryEventHookType -- ^ An invalid memory access (e.g. + -- read, write, etc.) to trigger + -- the callback on + -> MemoryEventHook a -- ^ Invalid memory access callback + -> a -- ^ User-defined data. This will + -- be passed to the callback + -- function + -> Word64 -- ^ Start address + -> Word64 -- ^ End address + -> Emulator Hook -- ^ The hook handle on success, or + -- an 'Error' on failure +memoryEventHookAdd uc memEventHookType callback userData begin end = do + result <- lift . alloca $ \userDataPtr -> do + poke userDataPtr userData + funPtr <- marshalMemoryEventHook callback + getResult $ ucHookAdd uc memEventHookType funPtr userDataPtr begin end + hoistEither result + +-- | Unregister (remove) a hook callback. +hookDel :: Engine -- ^ 'Unicorn' engine handle + -> Hook -- ^ 'Hook' handle + -> Emulator () -- ^ 'ErrOk' on success, or other value on failure +hookDel uc hook = do + err <- lift $ ucHookDel uc hook + if err == ErrOk then + right () + else + left err + +------------------------------------------------------------------------------- +-- Helper functions +------------------------------------------------------------------------------- + +-- Takes the tuple returned by `ucHookAdd`, an IO (Error, Hook), and +-- returns either a `Right Hook` if no error occurred or a `Left Error` if an +-- error occurred +getResult :: IO (Error, Hook) -> IO (Either Error Hook) +getResult = + liftM (uncurry checkResult) + where checkResult err hook = + if err == ErrOk then + Right hook + else + Left err diff --git a/bindings/haskell/src/Unicorn/Internal/Core.chs b/bindings/haskell/src/Unicorn/Internal/Core.chs new file mode 100644 index 00000000..ec1d5db8 --- /dev/null +++ b/bindings/haskell/src/Unicorn/Internal/Core.chs @@ -0,0 +1,52 @@ +{-# LANGUAGE ForeignFunctionInterface #-} + +{-| +Module : Unicorn.Internal.Core +Description : Core Unicorn components. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Defines core Unicorn components. + +This module should not be directly imported; it is only exposed because of the +way cabal handles ordering of chs files. +-} +module Unicorn.Internal.Core where + +import Control.Monad +import Control.Monad.Trans.Either (EitherT) +import Foreign + +{# context lib="unicorn" #} + +#include +#include "unicorn_wrapper.h" + +-- | The Unicorn engine. +{# pointer *uc_engine as Engine + foreign finalizer uc_close_wrapper as close + newtype #} + +-- | A pointer to a Unicorn engine. +{# pointer *uc_engine as EnginePtr -> Engine #} + +-- | Make a new Unicorn engine out of an engine pointer. The returned Unicorn +-- engine will automatically close 'uc_close_wrapper' when it goes out of +-- scope. +mkEngine :: EnginePtr -> IO Engine +mkEngine ptr = + liftM Engine (newForeignPtr close ptr) + +-- | Errors encountered by the Unicorn API. These values are returned by +-- 'errno'. +{# enum uc_err as Error + {underscoreToCase} + with prefix = "UC_" + deriving (Show, Eq, Bounded) #} + +-- | The emulator runs in the IO monad and allows for the handling of errors +-- "under the hood". +type Emulator a = EitherT Error IO a + +-- | An architecture-dependent register. +class Enum a => Reg a diff --git a/bindings/haskell/src/Unicorn/Internal/Hook.chs b/bindings/haskell/src/Unicorn/Internal/Hook.chs new file mode 100644 index 00000000..00a8a123 --- /dev/null +++ b/bindings/haskell/src/Unicorn/Internal/Hook.chs @@ -0,0 +1,415 @@ +{-# LANGUAGE ForeignFunctionInterface #-} + +{-| +Module : Unicorn.Internal.Hook +Description : Unicorn hooks. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Low-level bindings for inserting hook points into the Unicorn emulator engine. + +This module should not be directly imported; it is only exposed because of the +way cabal handles ordering of chs files. +-} +module Unicorn.Internal.Hook ( + -- * Types + Hook, + HookType(..), + MemoryHookType(..), + MemoryEventHookType(..), + MemoryAccess(..), + + -- * Hook callback bindings + CodeHook, + InterruptHook, + BlockHook, + InHook, + OutHook, + SyscallHook, + MemoryHook, + MemoryReadHook, + MemoryWriteHook, + MemoryEventHook, + + -- * Hook marshalling + marshalCodeHook, + marshalInterruptHook, + marshalBlockHook, + marshalInHook, + marshalOutHook, + marshalSyscallHook, + marshalMemoryHook, + marshalMemoryReadHook, + marshalMemoryWriteHook, + marshalMemoryEventHook, + + -- * Hook registration and deletion bindings + ucHookAdd, + ucInsnHookAdd, + ucHookDel, +) where + +import Control.Monad +import Foreign + +import Unicorn.Internal.Util + +{# context lib="unicorn" #} + +{# import Unicorn.Internal.Core #} +{# import Unicorn.CPU.X86 #} + +#include +#include "unicorn_wrapper.h" + +------------------------------------------------------------------------------- +-- Types +------------------------------------------------------------------------------- + +-- When we pass a Unicorn engine to a hook callback, we do not want this engine +-- object to be freed automatically when the callback returns (which is what +-- would typically occur when using a ForeignPtr), because we want to continue +-- using the Unicorn engine outside the callback. To avoid this, +-- unicorn_wrapper.h provides a dummy "close" function that does nothing. When +-- we go to create a Unicorn engine to pass to a callback, we use a pointer to +-- this dummy close function as the finalizer pointer. When the callback +-- returns, the Unicorn engine remains untouched! +-- +-- XX Is there a better way to do this? +foreign import ccall "&uc_close_dummy" + closeDummy :: FunPtr (EnginePtr -> IO ()) + +mkEngineNC :: EnginePtr -> IO Engine +mkEngineNC ptr = + liftM Engine (newForeignPtr closeDummy ptr) + +-- | A Unicorn hook. +type Hook = {# type uc_hook #} + +-- Hook types. These are used internally within this module by the callback +-- registration functions and are not exposed to the user. +-- +-- Note that the both valid and invalid memory access hooks are omitted from +-- this enum (and are exposed to the user). +{# enum uc_hook_type as HookType + {underscoreToCase} + omit (UC_HOOK_MEM_READ_UNMAPPED, + UC_HOOK_MEM_WRITE_UNMAPPED, + UC_HOOK_MEM_FETCH_UNMAPPED, + UC_HOOK_MEM_READ_PROT, + UC_HOOK_MEM_WRITE_PROT, + UC_HOOK_MEM_FETCH_PROT, + UC_HOOK_MEM_READ, + UC_HOOK_MEM_WRITE, + UC_HOOK_MEM_FETCH) + with prefix="UC_" + deriving (Show, Eq, Bounded) #} + +-- | Memory hook types (for valid memory accesses). +{# enum uc_hook_type as MemoryHookType + {underscoreToCase} + omit (UC_HOOK_INTR, + UC_HOOK_INSN, + UC_HOOK_CODE, + UC_HOOK_BLOCK, + UC_HOOK_MEM_READ_UNMAPPED, + UC_HOOK_MEM_WRITE_UNMAPPED, + UC_HOOK_MEM_FETCH_UNMAPPED, + UC_HOOK_MEM_READ_PROT, + UC_HOOK_MEM_WRITE_PROT, + UC_HOOK_MEM_FETCH_PROT) + with prefix="UC_" + deriving (Show, Eq, Bounded) #} + +-- | Memory event hook types (for invalid memory accesses). +{# enum uc_hook_type as MemoryEventHookType + {underscoreToCase} + omit (UC_HOOK_INTR, + UC_HOOK_INSN, + UC_HOOK_CODE, + UC_HOOK_BLOCK, + UC_HOOK_MEM_READ, + UC_HOOK_MEM_WRITE, + UC_HOOK_MEM_FETCH) + with prefix="UC_" + deriving (Show, Eq, Bounded) #} + +-- | Unify the hook types with a type class +class Enum a => HookTypeC a + +instance HookTypeC HookType +instance HookTypeC MemoryHookType +instance HookTypeC MemoryEventHookType + +-- | Memory access. +{# enum uc_mem_type as MemoryAccess + {underscoreToCase} + with prefix="UC_" + deriving (Show, Eq, Bounded) #} + +------------------------------------------------------------------------------- +-- Hook callbacks +------------------------------------------------------------------------------- + +-- | Callback function for tracing code. +type CodeHook a = Engine -- ^ 'Unicorn' engine handle + -> Word64 -- ^ Addres where the code is being executed + -> Maybe Int -- ^ Size of machine instruction(s) being + -- executed, or 'Nothing' when size is unknown + -> a -- ^ User data passed to tracing APIs + -> IO () + +type CCodeHook = EnginePtr -> Word64 -> Word32 -> Ptr () -> IO () + +foreign import ccall "wrapper" + mkCodeHook :: CCodeHook -> IO {# type uc_cb_hookcode_t #} + +marshalCodeHook :: Storable a + => CodeHook a -> IO {# type uc_cb_hookcode_t #} +marshalCodeHook codeHook = + mkCodeHook $ \ucPtr address size userDataPtr -> do + uc <- mkEngineNC ucPtr + userData <- castPtrAndPeek userDataPtr + let maybeSize = if size == 0 then Nothing + else Just $ fromIntegral size + codeHook uc address maybeSize userData + +-- | Callback function for tracing interrupts. +type InterruptHook a = Engine -- ^ 'Unicorn' engine handle + -> Int -- ^ Interrupt number + -> a -- ^ User data passed to tracing APIs + -> IO () + +type CInterruptHook = EnginePtr -> Word32 -> Ptr () -> IO () + +foreign import ccall "wrapper" + mkInterruptHook :: CInterruptHook -> IO {# type uc_cb_hookintr_t #} + +marshalInterruptHook :: Storable a + => InterruptHook a -> IO {# type uc_cb_hookintr_t #} +marshalInterruptHook interruptHook = + mkInterruptHook $ \ucPtr intNo userDataPtr -> do + uc <- mkEngineNC ucPtr + userData <- castPtrAndPeek userDataPtr + interruptHook uc (fromIntegral intNo) userData + +-- | Callback function for tracing blocks. +type BlockHook a = CodeHook a + +marshalBlockHook :: Storable a + => BlockHook a -> IO {# type uc_cb_hookcode_t #} +marshalBlockHook = + marshalCodeHook + +-- | Callback function for tracing IN instructions (X86). +type InHook a = Engine -- ^ 'Unicorn' engine handle + -> Int -- ^ Port number + -> Int -- ^ Data size (1/2/4) to be read from this port + -> a -- ^ User data passed to tracing APIs + -> IO Word32 -- ^ The data read from the port + +type CInHook = EnginePtr -> Word32 -> Int32 -> Ptr () -> IO Word32 + +foreign import ccall "wrapper" + mkInHook :: CInHook -> IO {# type uc_cb_insn_in_t #} + +marshalInHook :: Storable a + => InHook a -> IO {# type uc_cb_insn_in_t #} +marshalInHook inHook = + mkInHook $ \ucPtr port size userDataPtr -> do + uc <- mkEngineNC ucPtr + userData <- castPtrAndPeek userDataPtr + inHook uc (fromIntegral port) (fromIntegral size) userData + +-- | Callback function for tracing OUT instructions (X86). +type OutHook a = Engine -- ^ 'Unicorn' engine handle + -> Int -- ^ Port number + -> Int -- ^ Data size (1/2/4) to be written to this port + -> Int -- ^ Data value to be written to this port + -> a -- ^ User data passed to tracing APIs + -> IO () + +type COutHook = EnginePtr -> Word32 -> Int32 -> Word32 -> Ptr () -> IO () + +foreign import ccall "wrapper" + mkOutHook :: COutHook -> IO {# type uc_cb_insn_out_t #} + +marshalOutHook :: Storable a + => OutHook a -> IO {# type uc_cb_insn_out_t #} +marshalOutHook outHook = + mkOutHook $ \ucPtr port size value userDataPtr -> do + uc <- mkEngineNC ucPtr + userData <- castPtrAndPeek userDataPtr + outHook uc (fromIntegral port) (fromIntegral size) (fromIntegral value) + userData + +-- | Callback function for tracing SYSCALL instructions (X86). +type SyscallHook a = Engine -- ^ 'Unicorn' engine handle + -> a -- ^ User data passed to tracing APIs + -> IO () + +type CSyscallHook = Ptr () -> Ptr () -> IO () + +foreign import ccall "wrapper" + mkSyscallHook :: CSyscallHook -> IO {# type uc_cb_insn_syscall_t #} + +marshalSyscallHook :: Storable a + => SyscallHook a -> IO {# type uc_cb_insn_syscall_t #} +marshalSyscallHook syscallHook = + mkSyscallHook $ \ucPtr userDataPtr -> do + uc <- mkEngineNC $ castPtr ucPtr + userData <- castPtrAndPeek userDataPtr + syscallHook uc userData + +-- | Callback function for hooking memory operations. +type MemoryHook a = Engine -- ^ 'Unicorn' engine handle + -> MemoryAccess -- ^ Memory access; read or write + -> Word64 -- ^ Address where the code is being + -- executed + -> Int -- ^ Size of data being read or written + -> Maybe Int -- ^ Value of data being wrriten, or + -- 'Nothing' if read + -> a -- ^ User data passed to tracing APIs + -> IO () + +type CMemoryHook = EnginePtr + -> Int32 + -> Word64 + -> Int32 + -> Int64 + -> Ptr () + -> IO () + +foreign import ccall "wrapper" + mkMemoryHook :: CMemoryHook -> IO {# type uc_cb_hookmem_t #} + +marshalMemoryHook :: Storable a + => MemoryHook a -> IO {# type uc_cb_hookmem_t #} +marshalMemoryHook memoryHook = + mkMemoryHook $ \ucPtr memAccessI address size value userDataPtr -> do + uc <- mkEngineNC ucPtr + userData <- castPtrAndPeek userDataPtr + let memAccess = toMemAccess memAccessI + maybeValue = case memAccess of + MemRead -> Nothing + MemWrite -> Just $ fromIntegral value + _ -> undefined -- XX Handle this? + memoryHook uc memAccess address (fromIntegral size) maybeValue userData + +-- | Callback function for hooking memory reads. +type MemoryReadHook a = Engine -- ^ 'Unicorn' engine handle + -> Word64 -- ^ Address where the code is being executed + -> Int -- ^ Size of data being read + -> a -- ^ User data passed to tracing APIs + -> IO () + +marshalMemoryReadHook :: Storable a + => MemoryReadHook a -> IO {# type uc_cb_hookmem_t #} +marshalMemoryReadHook memoryReadHook = + mkMemoryHook $ \ucPtr _ address size _ userDataPtr -> do + uc <- mkEngineNC ucPtr + userData <- castPtrAndPeek userDataPtr + memoryReadHook uc address (fromIntegral size) userData + +-- | Callback function for hooking memory writes. +type MemoryWriteHook a = Engine -- ^ 'Unicorn' engine handle + -> Word64 -- ^ Address where the code is being + -- executed + -> Int -- ^ Size of data being written + -> Int -- ^ Value of data being written + -> a -- ^ User data passed to tracing APIs + -> IO () + +marshalMemoryWriteHook :: Storable a + => MemoryWriteHook a -> IO {# type uc_cb_hookmem_t #} +marshalMemoryWriteHook memoryWriteHook = + mkMemoryHook $ \ucPtr _ address size value userDataPtr -> do + uc <- mkEngineNC ucPtr + userData <- castPtrAndPeek userDataPtr + memoryWriteHook uc address (fromIntegral size) (fromIntegral value) + userData + +-- | Callback function for handling invalid memory access events. +type MemoryEventHook a = Engine -- ^ 'Unicorn' engine handle + -> MemoryAccess -- ^ Memory access; read or write + -> Word64 -- ^ Address where the code is being + -- executed + -> Int -- ^ Size of data being read or written + -> Maybe Int -- ^ Value of data being written, or + -- 'Nothing' if read + -> a -- ^ User data passed to tracing APIs + -> IO Bool -- ^ Return 'True' to continue, or + -- 'False' to stop the program (due to + -- invalid memory) + +type CMemoryEventHook = EnginePtr + -> Int32 + -> Word64 + -> Int32 + -> Int64 + -> Ptr () + -> IO Int32 + +foreign import ccall "wrapper" + mkMemoryEventHook :: CMemoryEventHook -> IO {# type uc_cb_eventmem_t #} + +marshalMemoryEventHook :: Storable a + => MemoryEventHook a -> IO {# type uc_cb_eventmem_t #} +marshalMemoryEventHook eventMemoryHook = + mkMemoryEventHook $ \ucPtr memAccessI address size value userDataPtr -> do + uc <- mkEngineNC ucPtr + userData <- castPtrAndPeek userDataPtr + let memAccess = toMemAccess memAccessI + maybeValue = case memAccess of + MemReadUnmapped -> Nothing + MemReadProt -> Nothing + MemWriteUnmapped -> Just $ fromIntegral value + MemWriteProt -> Just $ fromIntegral value + _ -> undefined -- XX Handle this? + res <- eventMemoryHook uc memAccess address (fromIntegral size) + maybeValue userData + return $ boolToInt res + where boolToInt True = 1 + boolToInt False = 0 + + +------------------------------------------------------------------------------- +-- Hook callback registration (and deletion) +------------------------------------------------------------------------------- + +{# fun variadic uc_hook_add as ucHookAdd + `(Storable a, HookTypeC h)' => + {`Engine', + alloca- `Hook' peek*, + enumToNum `h', + castFunPtrToPtr `FunPtr b', + castPtr `Ptr a', + `Word64', + `Word64'} + -> `Error' #} + +{# fun variadic uc_hook_add[int] as ucInsnHookAdd + `(Storable a, HookTypeC h)' => + {`Engine', + alloca- `Hook' peek*, + enumToNum `h', + castFunPtrToPtr `FunPtr b', + castPtr `Ptr a', + `Word64', + `Word64', + enumToNum `Instruction'} + -> `Error' #} + +-- | Unregister (remove) a hook callback. +{# fun uc_hook_del as ^ + {`Engine', + fromIntegral `Hook'} + -> `Error' #} + +------------------------------------------------------------------------------- +-- Helper functions +------------------------------------------------------------------------------- + +toMemAccess :: Integral a => a -> MemoryAccess +toMemAccess = + toEnum . fromIntegral diff --git a/bindings/haskell/src/Unicorn/Internal/Unicorn.chs b/bindings/haskell/src/Unicorn/Internal/Unicorn.chs new file mode 100644 index 00000000..f5d179dd --- /dev/null +++ b/bindings/haskell/src/Unicorn/Internal/Unicorn.chs @@ -0,0 +1,242 @@ +{-# LANGUAGE ForeignFunctionInterface #-} +{-# LANGUAGE ScopedTypeVariables #-} + +{-| +Module : Unicorn.Internal.Unicorn +Description : The Unicorn CPU emulator. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 + +Low-level bindings for the Unicorn CPU emulator framework. + +This module should not be directly imported; it is only exposed because of the +way cabal handles ordering of chs files. +-} +module Unicorn.Internal.Unicorn ( + -- * Types + Architecture(..), + Mode(..), + MemoryPermission(..), + MemoryRegion(..), + QueryType(..), + + -- * Function bindings + ucOpen, + ucQuery, + ucEmuStart, + ucEmuStop, + ucRegWrite, + ucRegRead, + ucMemWrite, + ucMemRead, + ucMemMap, + ucMemUnmap, + ucMemProtect, + ucMemRegions, + ucVersion, + ucErrno, + ucStrerror, +) where + +import Foreign +import Foreign.C + +import Control.Applicative +import Data.ByteString (ByteString, useAsCStringLen) +import Prelude hiding (until) + +import Unicorn.Internal.Util + +{# context lib="unicorn" #} + +{# import Unicorn.Internal.Core #} + +#include + +------------------------------------------------------------------------------- +-- Types +------------------------------------------------------------------------------- + +-- | CPU architecture. +{# enum uc_arch as Architecture + {underscoreToCase} + with prefix = "UC_" + deriving (Show, Eq, Bounded) #} + +-- | CPU hardware mode. +{# enum uc_mode as Mode + {underscoreToCase} + with prefix="UC_" + deriving (Show, Eq, Bounded) #} + +-- | Memory permissions. +{# enum uc_prot as MemoryPermission + {underscoreToCase} + with prefix="UC_" + deriving (Show, Eq, Bounded) #} + +-- | Memory region mapped by 'memMap'. Retrieve the list of memory regions with +-- 'memRegions'. +data MemoryRegion = MemoryRegion { + mrBegin :: Word64, -- ^ Begin address of the region (inclusive) + mrEnd :: Word64, -- ^ End address of the region (inclusive) + mrPerms :: [MemoryPermission] -- ^ Memory permissions of the region +} + +instance Storable MemoryRegion where + sizeOf _ = {# sizeof uc_mem_region #} + alignment _ = {# alignof uc_mem_region #} + peek p = MemoryRegion + <$> liftA fromIntegral ({# get uc_mem_region->begin #} p) + <*> liftA fromIntegral ({# get uc_mem_region->end #} p) + <*> liftA expandMemPerms ({# get uc_mem_region->perms #} p) + poke p mr = do + {# set uc_mem_region.begin #} p (fromIntegral $ mrBegin mr) + {# set uc_mem_region.end #} p (fromIntegral $ mrEnd mr) + {# set uc_mem_region.perms #} p (combineEnums $ mrPerms mr) + +-- | A pointer to a memory region. +{# pointer *uc_mem_region as MemoryRegionPtr -> MemoryRegion #} + +-- | Query types for the 'query' API. +{# enum uc_query_type as QueryType + {underscoreToCase} + with prefix="UC_" + deriving (Show, Eq, Bounded) #} + +------------------------------------------------------------------------------- +-- Emulator control +------------------------------------------------------------------------------- + +{# fun uc_open as ^ + {`Architecture', + combineEnums `[Mode]', + alloca- `EnginePtr' peek*} + -> `Error' #} + +{# fun uc_query as ^ + {`Engine', + `QueryType', + alloca- `Int' castPtrAndPeek*} + -> `Error' #} + +{# fun uc_emu_start as ^ + {`Engine', + `Word64', + `Word64', + `Int', + `Int'} + -> `Error' #} + +{# fun uc_emu_stop as ^ + {`Engine'} + -> `Error' #} + +------------------------------------------------------------------------------- +-- Register operations +------------------------------------------------------------------------------- + +{# fun uc_reg_write as ^ + `Reg r' => + {`Engine', + enumToNum `r', + castPtr `Ptr Int64'} + -> `Error' #} + +{# fun uc_reg_read as ^ + `Reg r' => + {`Engine', + enumToNum `r', + allocaInt64ToVoid- `Int64' castPtrAndPeek*} + -> `Error' #} + +------------------------------------------------------------------------------- +-- Memory operations +------------------------------------------------------------------------------- + +{# fun uc_mem_write as ^ + {`Engine', + `Word64', + withByteStringLen* `ByteString'&} + -> `Error' #} + +{# fun uc_mem_read as ^ + {`Engine', + `Word64', + castPtr `Ptr Word8', + `Int'} + -> `Error' #} + +{# fun uc_mem_map as ^ + {`Engine', + `Word64', + `Int', + combineEnums `[MemoryPermission]'} + -> `Error' #} + +{# fun uc_mem_unmap as ^ + {`Engine', + `Word64', + `Int'} + -> `Error' #} + +{# fun uc_mem_protect as ^ + {`Engine', + `Word64', + `Int', + combineEnums `[MemoryPermission]'} + -> `Error' #} + +{# fun uc_mem_regions as ^ + {`Engine', + alloca- `MemoryRegionPtr' peek*, + alloca- `Int' castPtrAndPeek*} + -> `Error' #} + +------------------------------------------------------------------------------- +-- Misc. +------------------------------------------------------------------------------- + +{# fun pure unsafe uc_version as ^ + {id `Ptr CUInt', + id `Ptr CUInt'} + -> `Int' #} + +{# fun unsafe uc_errno as ^ + {`Engine'} + -> `Error' #} + +{# fun pure unsafe uc_strerror as ^ + {`Error'} + -> `String' #} + +------------------------------------------------------------------------------- +-- Helper functions +------------------------------------------------------------------------------- + +expandMemPerms :: (Integral a, Bits a) => a -> [MemoryPermission] +expandMemPerms perms = + -- Only interested in the 3 least-significant bits + let maskedPerms = fromIntegral $ perms .&. 0x7 in + if maskedPerms == 0x0 then + [ProtNone] + else if maskedPerms == 0x7 then + [ProtAll] + else + checkRWE maskedPerms [ProtRead, ProtWrite, ProtExec] + where + checkRWE p (x:xs) = + if p .&. (fromEnum x) /= 0 then + x : checkRWE p xs + else + checkRWE p xs + checkRWE _ [] = + [] + +allocaInt64ToVoid :: (Ptr () -> IO b) -> IO b +allocaInt64ToVoid f = + alloca $ \(ptr :: Ptr Int64) -> poke ptr 0 >> f (castPtr ptr) + +withByteStringLen :: ByteString -> ((Ptr (), CULong) -> IO a) -> IO a +withByteStringLen bs f = + useAsCStringLen bs $ \(ptr, len) -> f (castPtr ptr, fromIntegral len) diff --git a/bindings/haskell/src/Unicorn/Internal/Util.hs b/bindings/haskell/src/Unicorn/Internal/Util.hs new file mode 100644 index 00000000..5ec07f7e --- /dev/null +++ b/bindings/haskell/src/Unicorn/Internal/Util.hs @@ -0,0 +1,26 @@ +{-| +Module : Unicorn.Internal.Util +Description : Utility (aka helper) functions for the Unicorn emulator. +Copyright : (c) Adrian Herrera, 2016 +License : GPL-2 +-} +module Unicorn.Internal.Util where + +import Control.Applicative +import Data.Bits +import Foreign + +-- | Combine a list of Enums by performing a bitwise-OR. +combineEnums :: (Enum a, Num b, Bits b) => [a] -> b +combineEnums = + foldr ((.|.) <$> enumToNum) 0 + +-- | Cast a pointer and then peek inside it. +castPtrAndPeek :: Storable a => Ptr b -> IO a +castPtrAndPeek = + peek . castPtr + +-- | Convert an 'Eum' to a 'Num'. +enumToNum :: (Enum a, Num b) => a -> b +enumToNum = + fromIntegral . fromEnum diff --git a/bindings/haskell/src/cbits/unicorn_wrapper.c b/bindings/haskell/src/cbits/unicorn_wrapper.c new file mode 100644 index 00000000..1ee60706 --- /dev/null +++ b/bindings/haskell/src/cbits/unicorn_wrapper.c @@ -0,0 +1,8 @@ +#include "unicorn_wrapper.h" + +void uc_close_wrapper(uc_engine *uc) { + uc_close(uc); +} + +void uc_close_dummy(uc_engine *uc) { +} diff --git a/bindings/haskell/src/include/unicorn_wrapper.h b/bindings/haskell/src/include/unicorn_wrapper.h new file mode 100644 index 00000000..76d414aa --- /dev/null +++ b/bindings/haskell/src/include/unicorn_wrapper.h @@ -0,0 +1,16 @@ +#ifndef UNICORN_WRAPPER_H +#define UNICORN_WRAPPER_H + +#include + +/* + * Wrap Unicorn's uc_close function and ignore the returned error code. + */ +void uc_close_wrapper(uc_engine *uc); + +/* + * Doesn't actually do anything. + */ +void uc_close_dummy(uc_engine *uc); + +#endif diff --git a/bindings/haskell/unicorn.cabal b/bindings/haskell/unicorn.cabal new file mode 100644 index 00000000..77af442e --- /dev/null +++ b/bindings/haskell/unicorn.cabal @@ -0,0 +1,42 @@ +-- Initial unicorn.cabal generated by cabal init. For further +-- documentation, see http://haskell.org/cabal/users-guide/ + +name: unicorn +version: 0.1.0.0 +category: FFI, Emulation +synopsis: Unicorn CPU emulator engine +description: Haskell bindings for the Unicorn CPU emulator engine. +homepage: https://github.com/unicorn-engine/unicorn +author: Adrian Herrera +license: GPL +copyright: (c) 2016, Adrian Herrera +category: System +build-type: Simple +stability: experimental +cabal-version: >=1.10 +extra-source-files: cbits/, include/ + +library + exposed-modules: Unicorn.Internal.Core + Unicorn.Internal.Unicorn + Unicorn.CPU.Arm64 + Unicorn.CPU.Arm + Unicorn.CPU.M68k + Unicorn.CPU.Mips + Unicorn.CPU.Sparc + Unicorn.CPU.X86 + Unicorn.Internal.Hook + Unicorn.Hook + Unicorn + other-modules: Unicorn.Internal.Util + build-depends: base >=4 && <5, + bytestring >= 0.9.1, + transformers <= 0.5, + either >= 4.4 + hs-source-dirs: src + c-sources: src/cbits/unicorn_wrapper.c + include-dirs: src/include + build-tools: c2hs + pkgconfig-depends: unicorn + default-language: Haskell2010 + ghc-options: -Wall diff --git a/bindings/java/samples/Sample_x86_mmr.java b/bindings/java/samples/Sample_x86_mmr.java index 87bd8a0a..e2b1a6dd 100644 --- a/bindings/java/samples/Sample_x86_mmr.java +++ b/bindings/java/samples/Sample_x86_mmr.java @@ -36,7 +36,7 @@ public class Sample_x86_mmr { } // map 4k - uc.mem_map(ADDRESS, 0x1000, Unicorn.UC_PROT_ALL); + uc.mem_map(0x400000, 0x1000, Unicorn.UC_PROT_ALL); X86_MMR ldtr1 = new X86_MMR(0x1111111122222222L, 0x33333333, 0x44444444, (short)0x5555); X86_MMR ldtr2; diff --git a/bindings/java/unicorn/UnicornConst.java b/bindings/java/unicorn/UnicornConst.java index 64b52236..033267ae 100644 --- a/bindings/java/unicorn/UnicornConst.java +++ b/bindings/java/unicorn/UnicornConst.java @@ -90,6 +90,7 @@ public interface UnicornConst { 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; diff --git a/bindings/java/unicorn/X86Const.java b/bindings/java/unicorn/X86Const.java index 9c6d93ee..7afed1f9 100644 --- a/bindings/java/unicorn/X86Const.java +++ b/bindings/java/unicorn/X86Const.java @@ -252,7 +252,9 @@ public interface X86Const { 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_ENDING = 246; + 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 diff --git a/bindings/java/unicorn_Unicorn.c b/bindings/java/unicorn_Unicorn.c index 8b3bcfe2..a1e6fbc7 100644 --- a/bindings/java/unicorn_Unicorn.c +++ b/bindings/java/unicorn_Unicorn.c @@ -519,7 +519,7 @@ JNIEXPORT jlong JNICALL Java_unicorn_Unicorn_registerHook__JI if (invokeInterruptCallbacks == 0) { invokeInterruptCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeInterruptCallbacks", "(JI)V"); } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookintr, env); + err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookintr, env, 1, 0); break; case UC_HOOK_MEM_FETCH_UNMAPPED: // Hook for all invalid memory access events case UC_HOOK_MEM_READ_UNMAPPED: // Hook for all invalid memory access events @@ -530,7 +530,7 @@ JNIEXPORT jlong JNICALL Java_unicorn_Unicorn_registerHook__JI if (invokeEventMemCallbacks == 0) { invokeEventMemCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeEventMemCallbacks", "(JIJIJ)Z"); } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_eventmem, env); + err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_eventmem, env, 1, 0); break; } return (jlong)hh; @@ -552,18 +552,18 @@ JNIEXPORT jlong JNICALL Java_unicorn_Unicorn_registerHook__JII if (invokeOutCallbacks == 0) { invokeOutCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeOutCallbacks", "(JIII)V"); } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_insn_out, env, arg1); + err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_insn_out, env, 1, 0, arg1); case UC_X86_INS_IN: if (invokeInCallbacks == 0) { invokeInCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeInCallbacks", "(JII)I"); } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_insn_in, env, arg1); + err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_insn_in, env, 1, 0, arg1); case UC_X86_INS_SYSENTER: case UC_X86_INS_SYSCALL: if (invokeSyscallCallbacks == 0) { invokeSyscallCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeSyscallCallbacks", "(J)V"); } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_insn_syscall, env, arg1); + err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_insn_syscall, env, 1, 0, arg1); } break; } @@ -584,25 +584,25 @@ JNIEXPORT jlong JNICALL Java_unicorn_Unicorn_registerHook__JIJJ if (invokeCodeCallbacks == 0) { invokeCodeCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeCodeCallbacks", "(JJI)V"); } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookcode, env, arg1, arg2); + err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookcode, env, 1, 0, arg1, arg2); break; case UC_HOOK_BLOCK: // Hook basic blocks if (invokeBlockCallbacks == 0) { invokeBlockCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeBlockCallbacks", "(JJI)V"); } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookblock, env, arg1, arg2); + err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookblock, env, 1, 0, arg1, arg2); break; case UC_HOOK_MEM_READ: // Hook all memory read events. if (invokeReadCallbacks == 0) { invokeReadCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeReadCallbacks", "(JJI)V"); } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookmem, env, arg1, arg2); + err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookmem, env, 1, 0, arg1, arg2); break; case UC_HOOK_MEM_WRITE: // Hook all memory write events. if (invokeWriteCallbacks == 0) { invokeWriteCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeWriteCallbacks", "(JJIJ)V"); } - err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookmem, env, arg1, arg2); + err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookmem, env, 1, 0, arg1, arg2); break; } return (jlong)hh; diff --git a/bindings/msvc/unicorn.def b/bindings/msvc/unicorn.def index c8d88b3b..d53f96a3 100644 --- a/bindings/msvc/unicorn.def +++ b/bindings/msvc/unicorn.def @@ -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 diff --git a/bindings/msvc/unicorn_dynload.c b/bindings/msvc/unicorn_dynload.c index ca9b4e2a..5db754f8 100644 --- a/bindings/msvc/unicorn_dynload.c +++ b/bindings/msvc/unicorn_dynload.c @@ -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 diff --git a/bindings/msvc/unicorn_dynload.h b/bindings/msvc/unicorn_dynload.h index 638f5250..2618bde5 100644 --- a/bindings/msvc/unicorn_dynload.h +++ b/bindings/msvc/unicorn_dynload.h @@ -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: diff --git a/bindings/python/setup.py b/bindings/python/setup.py index 66ea8ab0..6b98bae5 100755 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -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")) diff --git a/bindings/python/unicorn/__init__.py b/bindings/python/unicorn/__init__.py index 3f63904c..9d2b717c 100644 --- a/bindings/python/unicorn/__init__.py +++ b/bindings/python/unicorn/__init__.py @@ -1,4 +1,4 @@ # Unicorn Python bindings, by Nguyen Anh Quynnh 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__ diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 3d784368..e1c94491 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -1,42 +1,55 @@ # Unicorn Python bindings, by Nguyen Anh Quynnh + +import ctypes +import ctypes.util +import distutils.sysconfig +import inspect +import os.path +import platform import sys + +from . import x86_const, unicorn_const as uc + +if not hasattr(sys.modules[__name__], "__file__"): + __file__ = inspect.getfile(inspect.currentframe()) + _python2 = sys.version_info[0] < 3 if _python2: range = xrange -from . import arm_const, arm64_const, mips_const, sparc_const, m68k_const, x86_const -from .unicorn_const import * -import ctypes, ctypes.util, sys -from platform import system -from os.path import split, join, dirname, exists -import distutils.sysconfig +_lib_path = os.path.split(__file__)[0] +_all_libs = ( + "unicorn.dll", + "libunicorn.so", + "libunicorn.dylib", +) - -import inspect -if not hasattr(sys.modules[__name__], '__file__'): - __file__ = inspect.getfile(inspect.currentframe()) - -_lib_path = split(__file__)[0] -_all_libs = ('unicorn.dll', 'libunicorn.so', 'libunicorn.dylib') # Windows DLL in dependency order -_all_windows_dlls = ("libwinpthread-1.dll", "libgcc_s_seh-1.dll", "libgcc_s_dw2-1.dll", "libiconv-2.dll", "libintl-8.dll", "libglib-2.0-0.dll") +_all_windows_dlls = ( + "libwinpthread-1.dll", + "libgcc_s_seh-1.dll", + "libgcc_s_dw2-1.dll", + "libiconv-2.dll", + "libintl-8.dll", + "libglib-2.0-0.dll", +) _found = False for _lib in _all_libs: try: - if _lib == 'unicorn.dll': + if _lib == "unicorn.dll": for dll in _all_windows_dlls: # load all the rest DLLs first - _lib_file = join(_lib_path, dll) - if exists(_lib_file): + _lib_file = os.path.join(_lib_path, dll) + if os.path.exists(_lib_file): ctypes.cdll.LoadLibrary(_lib_file) - _lib_file = join(_lib_path, _lib) + _lib_file = os.path.join(_lib_path, _lib) _uc = ctypes.cdll.LoadLibrary(_lib_file) _found = True break except OSError: pass -if _found == False: +if not _found: # try loading from default paths for _lib in _all_libs: try: @@ -46,17 +59,17 @@ if _found == False: except OSError: pass -if _found == False: +if not _found: # last try: loading from python lib directory _lib_path = distutils.sysconfig.get_python_lib() for _lib in _all_libs: try: - if _lib == 'unicorn.dll': + if _lib == "unicorn.dll": for dll in _all_windows_dlls: # load all the rest DLLs first - _lib_file = join(_lib_path, 'unicorn', dll) - if exists(_lib_file): + _lib_file = os.path.join(_lib_path, "unicorn", dll) + if os.path.exists(_lib_file): ctypes.cdll.LoadLibrary(_lib_file) - _lib_file = join(_lib_path, 'unicorn', _lib) + _lib_file = os.path.join(_lib_path, "unicorn", _lib) _uc = ctypes.cdll.LoadLibrary(_lib_file) _found = True break @@ -65,11 +78,11 @@ if _found == False: # Attempt Darwin specific load (10.11 specific), # since LD_LIBRARY_PATH is not guaranteed to exist -if (_found == False) and (system() == 'Darwin'): - _lib_path = '/usr/local/lib/' +if not _found and platform.system() == "Darwin": + _lib_path = "/usr/local/lib/" for _lib in _all_libs: try: - _lib_file = join(_lib_path, _lib) + _lib_file = os.path.join(_lib_path, _lib) # print "Trying to load:", _lib_file _uc = ctypes.cdll.LoadLibrary(_lib_file) _found = True @@ -77,10 +90,12 @@ if (_found == False) and (system() == 'Darwin'): except OSError: pass -if _found == False: +if not _found: raise ImportError("ERROR: fail to load the dynamic library.") +__version__ = "%s.%s" % (uc.UC_API_MAJOR, uc.UC_API_MINOR) + # setup all the function prototype def _setup_prototype(lib, fname, restype, *argtypes): getattr(lib, fname).restype = restype @@ -110,20 +125,28 @@ _setup_prototype(_uc, "uc_mem_protect", ucerr, uc_engine, ctypes.c_uint64, ctype _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") +_uc.uc_hook_add = _uc.uc_hook_add _uc.uc_hook_add.restype = ucerr UC_HOOK_CODE_CB = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_uint64, ctypes.c_size_t, ctypes.c_void_p) -UC_HOOK_MEM_INVALID_CB = ctypes.CFUNCTYPE(ctypes.c_bool, uc_engine, ctypes.c_int, \ - ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p) -UC_HOOK_MEM_ACCESS_CB = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_int, \ - ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p) -UC_HOOK_INTR_CB = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_uint32, \ - ctypes.c_void_p) -UC_HOOK_INSN_IN_CB = ctypes.CFUNCTYPE(ctypes.c_uint32, uc_engine, ctypes.c_uint32, \ - ctypes.c_int, ctypes.c_void_p) -UC_HOOK_INSN_OUT_CB = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_uint32, \ - ctypes.c_int, ctypes.c_uint32, ctypes.c_void_p) +UC_HOOK_MEM_INVALID_CB = ctypes.CFUNCTYPE( + ctypes.c_bool, uc_engine, ctypes.c_int, + ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p +) +UC_HOOK_MEM_ACCESS_CB = ctypes.CFUNCTYPE( + None, uc_engine, ctypes.c_int, + ctypes.c_uint64, ctypes.c_int, ctypes.c_int64, ctypes.c_void_p +) +UC_HOOK_INTR_CB = ctypes.CFUNCTYPE( + None, uc_engine, ctypes.c_uint32, ctypes.c_void_p +) +UC_HOOK_INSN_IN_CB = ctypes.CFUNCTYPE( + ctypes.c_uint32, uc_engine, ctypes.c_uint32, ctypes.c_int, ctypes.c_void_p +) +UC_HOOK_INSN_OUT_CB = ctypes.CFUNCTYPE( + None, uc_engine, ctypes.c_uint32, + ctypes.c_int, ctypes.c_uint32, ctypes.c_void_p +) UC_HOOK_INSN_SYSCALL_CB = ctypes.CFUNCTYPE(None, uc_engine, ctypes.c_void_p) @@ -146,7 +169,10 @@ def uc_version(): # return the binding's version def version_bind(): - return (UC_API_MAJOR, UC_API_MINOR, (UC_API_MAJOR << 8) + UC_API_MINOR) + return ( + uc.UC_API_MAJOR, uc.UC_API_MINOR, + (uc.UC_API_MAJOR << 8) + uc.UC_API_MINOR, + ) # check to see if this engine supports a particular arch @@ -154,19 +180,37 @@ 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 (major, minor, _combined) = uc_version() - if major != UC_API_MAJOR or minor != UC_API_MINOR: + if major != uc.UC_API_MAJOR or minor != uc.UC_API_MINOR: self._uch = None # our binding version is different from the core's API version - raise UcError(UC_ERR_VERSION) + raise UcError(uc.UC_ERR_VERSION) self._arch, self._mode = arch, mode self._uch = ctypes.c_void_p() status = _uc.uc_open(arch, mode, ctypes.byref(self._uch)) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: self._uch = None raise UcError(status) # internal mapping table to save callback & userdata @@ -174,146 +218,158 @@ class Uc(object): self._ctype_cbs = {} self._callback_count = 0 - # destructor to be called automatically when object is destroyed. def __del__(self): if self._uch: try: status = _uc.uc_close(self._uch) self._uch = None - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) - except: # _uc might be pulled from under our feet + except: # _uc might be pulled from under our feet pass - # emulate from @begin, and stop when reaching address @until def emu_start(self, begin, until, timeout=0, count=0): status = _uc.uc_emu_start(self._uch, begin, until, timeout, count) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) - # stop emulation def emu_stop(self): status = _uc.uc_emu_stop(self._uch) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) - # return the value of a register def reg_read(self, reg_id): + if self._arch == uc.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.UC_ERR_OK: + raise UcError(status) + return reg.selector, reg.base, reg.limit, 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.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)) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) return reg.value - # write to a register def reg_write(self, reg_id, value): - # 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) + reg = None + if self._arch == uc.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.limit = 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.UC_ERR_OK: + raise UcError(status) # read data from memory def mem_read(self, address, size): data = ctypes.create_string_buffer(size) status = _uc.uc_mem_read(self._uch, address, data, size) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) return bytearray(data) - # write to memory def mem_write(self, address, data): status = _uc.uc_mem_write(self._uch, address, data, len(data)) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) - # map a range of memory - def mem_map(self, address, size, perms=UC_PROT_ALL): + def mem_map(self, address, size, perms=uc.UC_PROT_ALL): status = _uc.uc_mem_map(self._uch, address, size, perms) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) - # map a range of memory from a raw host memory address def mem_map_ptr(self, address, size, perms, ptr): status = _uc.uc_mem_map_ptr(self._uch, address, size, perms, ptr) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) - # unmap a range of memory def mem_unmap(self, address, size): status = _uc.uc_mem_unmap(self._uch, address, size) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) - # protect a range of memory - def mem_protect(self, address, size, perms=UC_PROT_ALL): + def mem_protect(self, address, size, perms=uc.UC_PROT_ALL): status = _uc.uc_mem_protect(self._uch, address, size, perms) - if status != UC_ERR_OK: + if status != uc.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: + if status != uc.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 (cb, data) = self._callbacks[user_data] cb(self, address, size, data) - def _hook_mem_invalid_cb(self, handle, access, address, size, value, user_data): # call user's callback with self object (cb, data) = self._callbacks[user_data] return cb(self, access, address, size, value, data) - def _hook_mem_access_cb(self, handle, access, address, size, value, user_data): # call user's callback with self object (cb, data) = self._callbacks[user_data] cb(self, access, address, size, value, data) - def _hook_intr_cb(self, handle, intno, user_data): # call user's callback with self object (cb, data) = self._callbacks[user_data] cb(self, intno, data) - def _hook_insn_in_cb(self, handle, port, size, user_data): # call user's callback with self object (cb, data) = self._callbacks[user_data] return cb(self, port, size, data) - def _hook_insn_out_cb(self, handle, port, size, value, user_data): # call user's callback with self object (cb, data) = self._callbacks[user_data] cb(self, port, size, value, data) - def _hook_insn_syscall_cb(self, handle, user_data): # call user's callback with self object (cb, data) = self._callbacks[user_data] cb(self, data) - # add a hook def hook_add(self, htype, callback, user_data=None, begin=1, end=0, arg1=0): _h2 = uc_hook_h() @@ -323,61 +379,83 @@ class Uc(object): self._callbacks[self._callback_count] = (callback, user_data) cb = None - if htype == UC_HOOK_INSN: + if htype == uc.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) - if arg1 == x86_const.UC_X86_INS_OUT: # OUT instruction + if arg1 == x86_const.UC_X86_INS_OUT: # OUT instruction cb = ctypes.cast(UC_HOOK_INSN_OUT_CB(self._hook_insn_out_cb), UC_HOOK_INSN_OUT_CB) - if arg1 in (x86_const.UC_X86_INS_SYSCALL, x86_const.UC_X86_INS_SYSENTER): # SYSCALL/SYSENTER instruction + 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), ctypes.c_uint64(begin), ctypes.c_uint64(end), insn) - elif htype == UC_HOOK_INTR: + 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), insn + ) + elif htype == uc.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), ctypes.c_uint64(begin), ctypes.c_uint64(end)) + 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: - if htype in (UC_HOOK_BLOCK, UC_HOOK_CODE): + if htype in (uc.UC_HOOK_BLOCK, uc.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: + 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.UC_HOOK_MEM_READ_UNMAPPED | + uc.UC_HOOK_MEM_WRITE_UNMAPPED | + uc.UC_HOOK_MEM_FETCH_UNMAPPED | + uc.UC_HOOK_MEM_READ_PROT | + uc.UC_HOOK_MEM_WRITE_PROT | + uc.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)) + 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)) + 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 - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) return _h2.value - # delete a hook def hook_del(self, h): _h = uc_hook_h(h) status = _uc.uc_hook_del(self._uch, _h) - if status != UC_ERR_OK: + if status != uc.UC_ERR_OK: raise UcError(status) h = 0 # print out debugging info def debug(): - archs = { "arm": UC_ARCH_ARM, "arm64": UC_ARCH_ARM64, \ - "mips": UC_ARCH_MIPS, "sparc": UC_ARCH_SPARC, \ - "m68k": UC_ARCH_M68K, "x86": UC_ARCH_X86 } + archs = { + "arm": uc.UC_ARCH_ARM, + "arm64": uc.UC_ARCH_ARM64, + "mips": uc.UC_ARCH_MIPS, + "sparc": uc.UC_ARCH_SPARC, + "m68k": uc.UC_ARCH_M68K, + "x86": uc.UC_ARCH_X86, + } all_archs = "" keys = archs.keys() @@ -385,7 +463,8 @@ def debug(): if uc_arch_supported(archs[k]): all_archs += "-%s" % k - (major, minor, _combined) = uc_version() + major, minor, _combined = uc_version() - return "python-%s-c%u.%u-b%u.%u" % (all_archs, major, minor, UC_API_MAJOR, UC_API_MINOR) - + return "python-%s-c%u.%u-b%u.%u" % ( + all_archs, major, minor, uc.UC_API_MAJOR, uc.UC_API_MINOR + ) diff --git a/bindings/python/unicorn/unicorn_const.py b/bindings/python/unicorn/unicorn_const.py index bdb8ed01..89ccd919 100644 --- a/bindings/python/unicorn/unicorn_const.py +++ b/bindings/python/unicorn/unicorn_const.py @@ -86,6 +86,7 @@ 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 diff --git a/bindings/python/unicorn/x86_const.py b/bindings/python/unicorn/x86_const.py index a0cf0abc..ee5ba38f 100644 --- a/bindings/python/unicorn/x86_const.py +++ b/bindings/python/unicorn/x86_const.py @@ -248,7 +248,9 @@ UC_X86_REG_IDTR = 242 UC_X86_REG_GDTR = 243 UC_X86_REG_LDTR = 244 UC_X86_REG_TR = 245 -UC_X86_REG_ENDING = 246 +UC_X86_REG_FPCW = 246 +UC_X86_REG_FPTAG = 247 +UC_X86_REG_ENDING = 248 # X86 instructions diff --git a/bindings/ruby/Makefile b/bindings/ruby/Makefile new file mode 100644 index 00000000..6e801fc6 --- /dev/null +++ b/bindings/ruby/Makefile @@ -0,0 +1,11 @@ +# Ruby binding for Unicorn engine. Sascha Schirra + +.PHONY: gen_const + +install: + $(MAKE) gen_const + cd unicorn_gem && rake build + cd unicorn_gem && gem install --local pkg/unicorn-0.9.0.gem + +gen_const: + cd .. && python const_generator.py ruby diff --git a/bindings/ruby/README.md b/bindings/ruby/README.md new file mode 100644 index 00000000..67a2109f --- /dev/null +++ b/bindings/ruby/README.md @@ -0,0 +1,24 @@ +# Installation + +## Software requirements + +### Linux +- ruby >= 1.9.3 +- rubygems +- make +- gcc + +### Mac OS +- ruby >= 1.9.3 +- rubygems +- make +- XCode + +## Install unicorn + * cd path_to_unicorn + * ./make.sh install + +## Install ruby binding + * cd bindings/ruby + * make install + \ No newline at end of file diff --git a/bindings/ruby/sample_arm.rb b/bindings/ruby/sample_arm.rb new file mode 100644 index 00000000..dd0e4a06 --- /dev/null +++ b/bindings/ruby/sample_arm.rb @@ -0,0 +1,106 @@ +#!/usr/bin/env ruby + +require 'unicorn' +require 'unicorn/arm_const' + +include Unicorn + +# code to be emulated +ARM_CODE = "\x37\x00\xa0\xe3\x03\x10\x42\xe0" # mov r0, #0x37; sub r1, r2, r3 +THUMB_CODE = "\x83\xb0" # sub sp, #0xc +# memory address where emulation starts +ADDRESS = 0x10000 + + +# callback for tracing basic blocks +$hook_block = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing basic block at 0x%x, block size = 0x%x" % [address, size]) +end + + +# callback for tracing instructions +$hook_code = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing instruction at 0x%x, instruction size = %u" % [address, size]) +end + + +# Test ARM +def test_arm() + puts("Emulate ARM code") + begin + # Initialize emulator in ARM mode + mu = Uc.new UC_ARCH_ARM, UC_MODE_ARM + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, ARM_CODE) + + # initialize machine registers + mu.reg_write(UC_ARM_REG_R0, 0x1234) + mu.reg_write(UC_ARM_REG_R2, 0x6789) + mu.reg_write(UC_ARM_REG_R3, 0x3333) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, $hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, $hook_code) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + ARM_CODE.bytesize) + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + r0 = mu.reg_read(UC_ARM_REG_R0) + r1 = mu.reg_read(UC_ARM_REG_R1) + puts(">>> R0 = 0x%x" % r0) + puts(">>> R1 = 0x%x" % r1) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +def test_thumb() + puts("Emulate THUMB code") + begin + # Initialize emulator in thumb mode + mu = Uc.new UC_ARCH_ARM, UC_MODE_THUMB + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, THUMB_CODE) + + # initialize machine registers + mu.reg_write(UC_ARM_REG_SP, 0x1234) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, $hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, $hook_code) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + THUMB_CODE.bytesize) + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + sp = mu.reg_read(UC_ARM_REG_SP) + puts(">>> SP = 0x%x" % sp) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +test_arm() +puts("=" * 20) +test_thumb() diff --git a/bindings/ruby/sample_arm64.rb b/bindings/ruby/sample_arm64.rb new file mode 100644 index 00000000..45b0c9c6 --- /dev/null +++ b/bindings/ruby/sample_arm64.rb @@ -0,0 +1,69 @@ +#!/usr/bin/env ruby +# Sample code for ARM64 of Unicorn. Nguyen Anh Quynh +# Ruby sample ported by Sascha Schirra +require 'unicorn' +require 'unicorn/arm64_const' + +include Unicorn + +# code to be emulated +ARM64_CODE = "\xab\x01\x0f\x8b" #add x11, x13, x15 + +# memory address where emulation starts +ADDRESS = 0x10000 + + +# callback for tracing basic blocks +$hook_block = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing basic block at 0x%x, block size = 0x%x" % [address, size]) +end + + +# callback for tracing instructions +$hook_code = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing instruction at 0x%x, instruction size = %u" % [address, size]) +end + + +# Test ARM64 +def test_arm64() + puts("Emulate ARM64 code") + begin + # Initialize emulator in ARM mode + mu = Uc.new UC_ARCH_ARM64, UC_MODE_ARM + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, ARM64_CODE) + + # initialize machine registers + mu.reg_write(UC_ARM64_REG_X11, 0x1234) + mu.reg_write(UC_ARM64_REG_X13, 0x6789) + mu.reg_write(UC_ARM64_REG_X15, 0x3333) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, $hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, $hook_code) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + ARM64_CODE.bytesize) + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + x11 = mu.reg_read(UC_ARM64_REG_X11) + x13 = mu.reg_read(UC_ARM64_REG_X13) + x15 = mu.reg_read(UC_ARM64_REG_X15) + puts(">>> X11 = 0x%x" % x11) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +test_arm64() diff --git a/bindings/ruby/sample_m68k.rb b/bindings/ruby/sample_m68k.rb new file mode 100644 index 00000000..1acff39f --- /dev/null +++ b/bindings/ruby/sample_m68k.rb @@ -0,0 +1,65 @@ +#!/usr/bin/env ruby +# Sample code for ARM of Unicorn. Nguyen Anh Quynh +# Ruby sample ported by Sascha Schirra + +require 'unicorn' +require 'unicorn/m68k_const' + +include Unicorn + +# code to be emulated +M68K_CODE = "\x76\xed" # movq #-19, %d3 +# memory address where emulation starts +ADDRESS = 0x10000 + + +# callback for tracing basic blocks +$hook_block = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing basic block at 0x%x, block size = 0x%x" % [address, size]) +end + + +# callback for tracing instructions +$hook_code = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing instruction at 0x%x, instruction size = %u" % [address, size]) +end + + +# Test m68k +def test_m68k() + puts("Emulate M68K code") + begin + # Initialize emulator in m68k mode + mu = Uc.new UC_ARCH_M68K, UC_MODE_BIG_ENDIAN + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, M68K_CODE) + + # initialize machine registers + mu.reg_write(UC_M68K_REG_D3, 0x1234) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, $hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, $hook_code) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + M68K_CODE.bytesize) + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + d3 = mu.reg_read(UC_M68K_REG_D3) + puts(">>> D3 = 0x%x" % d3) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +test_m68k() diff --git a/bindings/ruby/sample_mips.rb b/bindings/ruby/sample_mips.rb new file mode 100644 index 00000000..ec30e87d --- /dev/null +++ b/bindings/ruby/sample_mips.rb @@ -0,0 +1,104 @@ +#!/usr/bin/env ruby +# Sample code for MIPS of Unicorn. Nguyen Anh Quynh +# Ruby sample ported by Sascha Schirra +require 'unicorn' +require 'unicorn/mips_const' + +include Unicorn + +# code to be emulated +MIPS_CODE_EB = "\x34\x21\x34\x56" # ori $at, $at, 0x3456; +MIPS_CODE_EL = "\x56\x34\x21\x34" # ori $at, $at, 0x3456; + +# memory address where emulation starts +ADDRESS = 0x10000 + + +# callback for tracing basic blocks +$hook_block = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing basic block at 0x%x, block size = 0x%x" % [address, size]) +end + + +# callback for tracing instructions +$hook_code = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing instruction at 0x%x, instruction size = %u" % [address, size]) +end + +# Test MIPS EB +def test_mips_eb() + puts("Emulate MIPS code (big-endian)") + begin + # Initialize emulator in MIPS32 + EB mode + mu = Uc.new UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, MIPS_CODE_EB) + + # initialize machine registers + mu.reg_write(UC_MIPS_REG_1, 0x6789) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, $hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, $hook_code) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + MIPS_CODE_EB.bytesize) + + # now puts out some registers + puts(">>> Emulation done. Below is the CPU context") + + r1 = mu.reg_read(UC_MIPS_REG_1) + puts(">>> r1 = 0x%x" % r1) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +# Test MIPS EL +def test_mips_el() + puts("Emulate MIPS code (little-endian)") + begin + # Initialize emulator in MIPS32 + EL mode + mu = Uc.new UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, MIPS_CODE_EL) + + # initialize machine registers + mu.reg_write(UC_MIPS_REG_1, 0x6789) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, $hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, $hook_code) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + MIPS_CODE_EL.bytesize) + + # now puts out some registers + puts(">>> Emulation done. Below is the CPU context") + + r1 = mu.reg_read(UC_MIPS_REG_1) + puts(">>> r1 = 0x%x" % r1) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +test_mips_eb() +puts("=" * 20) +test_mips_el() diff --git a/bindings/ruby/sample_sparc.rb b/bindings/ruby/sample_sparc.rb new file mode 100644 index 00000000..052be189 --- /dev/null +++ b/bindings/ruby/sample_sparc.rb @@ -0,0 +1,65 @@ +#!/usr/bin/env ruby +# Sample code for SPARC of Unicorn. Nguyen Anh Quynh +# Ruby sample ported by Sascha Schirra +require 'unicorn' +require 'unicorn/sparc_const' + +include Unicorn + +# code to be emulated +SPARC_CODE = "\x86\x00\x40\x02" # add %g1, %g2, %g3; +# memory address where emulation starts +ADDRESS = 0x10000 + + +# callback for tracing basic blocks +$hook_block = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing basic block at 0x%x, block size = 0x%x" % [address, size]) +end + + +# callback for tracing instructions +$hook_code = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing instruction at 0x%x, instruction size = %u" % [address, size]) +end + +# Test SPARC +def test_sparc() + puts("Emulate SPARC code") + begin + # Initialize emulator in SPARC EB mode + mu = Uc.new UC_ARCH_SPARC, UC_MODE_SPARC32|UC_MODE_BIG_ENDIAN + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, SPARC_CODE) + + # initialize machine registers + mu.reg_write(UC_SPARC_REG_G1, 0x1230) + mu.reg_write(UC_SPARC_REG_G2, 0x6789) + mu.reg_write(UC_SPARC_REG_G3, 0x5555) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, $hook_block) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, $hook_code) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + SPARC_CODE.bytesize) + + # now puts out some registers + puts(">>> Emulation done. Below is the CPU context") + + g3 = mu.reg_read(UC_SPARC_REG_G3) + puts(">>> G3 = 0x%x" %g3) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +test_sparc() diff --git a/bindings/ruby/sample_x86.rb b/bindings/ruby/sample_x86.rb new file mode 100644 index 00000000..86496d9b --- /dev/null +++ b/bindings/ruby/sample_x86.rb @@ -0,0 +1,509 @@ +#!/usr/bin/env ruby +require 'unicorn' +require 'unicorn/x86_const' + +include Unicorn + +X86_CODE32 = "\x41\x4a" # INC ecx; DEC edx +X86_CODE32_LOOP = "\x41\x4a\xeb\xfe" # INC ecx; DEC edx; JMP self-loop +X86_CODE32_MEM_READ = "\x8B\x0D\xAA\xAA\xAA\xAA\x41\x4a" # mov ecx,[0xaaaaaaaa]; INC ecx; DEC edx +X86_CODE32_MEM_WRITE = "\x89\x0D\xAA\xAA\xAA\xAA\x41\x4a" # mov [0xaaaaaaaa], ecx; INC ecx; DEC edx +X86_CODE64 = "\x41\xBC\x3B\xB0\x28\x2A\x49\x0F\xC9\x90\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9\x4D\x29\xF4\x49\x81\xC9\xF6\x8A\xC6\x53\x4D\x87\xED\x48\x0F\xAD\xD2\x49\xF7\xD4\x48\xF7\xE1\x4D\x19\xC5\x4D\x89\xC5\x48\xF7\xD6\x41\xB8\x4F\x8D\x6B\x59\x4D\x87\xD0\x68\x6A\x1E\x09\x3C\x59" +X86_CODE32_INOUT = "\x41\xE4\x3F\x4a\xE6\x46\x43" # INC ecx; IN AL, 0x3f; DEC edx; OUT 0x46, AL; INC ebx +X86_CODE64_SYSCALL = "\x0f\x05" # SYSCALL +X86_CODE16 = "\x00\x00" # add byte ptr [bx + si], al + +# memory address where emulation starts +ADDRESS = 0x1000000 + + +# callback for tracing basic blocks +HOOK_BLOCK = Proc.new do |uc, address, size, user_data | + puts(">>> Tracing basic block at 0x%x, block size = 0x%x" % [address, size]) +end + +# callback for tracing instructions +HOOK_CODE = Proc.new do |uc, address, size, user_data| + puts(">>> Tracing instruction at 0x%x, instruction size = %u" % [address, size]) +end + + +# callback for tracing invalid memory access (READ or WRITE) +HOOK_MEM_INVALID = lambda do |uc, access, address, size, value, user_data| + if access == UC_MEM_WRITE_UNMAPPED + puts(">>> Missing memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" % [address, size, value]) + # map this memory in with 2MB in size + uc.mem_map(0xaaaa0000, 2 * 1024*1024) + # return True to indicate we want to continue emulation + return true + else + puts(">>> Missing memory is being READ at 0x%x" % address) + # return False to indicate we want to stop emulation + return false + end +end + + +# callback for tracing memory access (READ or WRITE) +HOOK_MEM_ACCESS = Proc.new do |uc, access, address, size, value, user_data| + if access == UC_MEM_WRITE + puts(">>> Memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" % [address, size, value]) + else # READ + puts(">>> Memory is being READ at 0x%x, data size = %u" % [address, size]) + end +end + +# callback for IN instruction +HOOK_IN = lambda do |uc, port, size, user_data| + eip = uc.reg_read(UC_X86_REG_EIP) + puts("--- reading from port 0x%x, size: %u, address: 0x%x" % [port, size, eip]) + if size == 1 + # read 1 byte to AL + return 0xf1 + end + if size == 2 + # read 2 byte to AX + return 0xf2 + end + if size == 4 + # read 4 byte to EAX + return 0xf4 + end + # we should never reach here + return 0 +end + + +# callback for OUT instruction +HOOK_OUT = Proc.new do |uc, port, size, value, user_data| + eip = uc.reg_read(UC_X86_REG_EIP) + puts("--- writing to port 0x%x, size: %u, value: 0x%x, address: 0x%x" % [port, size, value, eip]) + + # confirm that value is indeed the value of AL/AX/EAX + v = 0 + if size == 1 + # read 1 byte in AL + v = uc.reg_read(UC_X86_REG_AL) + end + if size == 2 + # read 2 bytes in AX + v = uc.reg_read(UC_X86_REG_AX) + end + if size == 4 + # read 4 bytes in EAX + v = uc.reg_read(UC_X86_REG_EAX) + end + + puts("--- register value = 0x%x" %v) +end + + +# Test X86 32 bit +def test_i386() + puts("Emulate i386 code") + begin + # Initialize emulator in X86-32bit mode + mu = Uc.new UC_ARCH_X86, UC_MODE_32 + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, X86_CODE32) + + # initialize machine registers + mu.reg_write(UC_X86_REG_ECX, 0x1234) + mu.reg_write(UC_X86_REG_EDX, 0x7890) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, HOOK_BLOCK) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, HOOK_CODE) + mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED, HOOK_MEM_INVALID) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + X86_CODE32.bytesize) + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + r_ecx = mu.reg_read(UC_X86_REG_ECX) + r_edx = mu.reg_read(UC_X86_REG_EDX) + puts(">>> ECX = 0x%x" % r_ecx) + puts(">>> EDX = 0x%x" % r_edx) + + # read from memory + tmp = mu.mem_read(ADDRESS, 2) + print(">>> Read 2 bytes from [0x%x] =" % (ADDRESS)) + tmp.each_byte { |i| print(" 0x%x" % i) } + + puts + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +def test_i386_loop() + puts("Emulate i386 code with infinite loop - wait for 2 seconds then stop emulation") + begin + # Initialize emulator in X86-32bit mode + mu = Uc.new UC_ARCH_X86, UC_MODE_32 + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, X86_CODE32_LOOP) + + # initialize machine registers + mu.reg_write(UC_X86_REG_ECX, 0x1234) + mu.reg_write(UC_X86_REG_EDX, 0x7890) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + X86_CODE32_LOOP.bytesize, 2 * UC_SECOND_SCALE) + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + r_ecx = mu.reg_read(UC_X86_REG_ECX) + r_edx = mu.reg_read(UC_X86_REG_EDX) + puts(">>> ECX = 0x%x" % r_ecx) + puts(">>> EDX = 0x%x" % r_edx) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +def test_i386_invalid_mem_read() + puts("Emulate i386 code that read from invalid memory") + begin + # Initialize emulator in X86-32bit mode + mu = Uc.new UC_ARCH_X86, UC_MODE_32 + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, X86_CODE32_MEM_READ) + + # initialize machine registers + mu.reg_write(UC_X86_REG_ECX, 0x1234) + mu.reg_write(UC_X86_REG_EDX, 0x7890) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, HOOK_BLOCK) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, HOOK_CODE) + + begin + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + X86_CODE32_MEM_READ.bytesize) + rescue UcError => e + puts("ERROR: %s" % e) + end + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + r_ecx = mu.reg_read(UC_X86_REG_ECX) + r_edx = mu.reg_read(UC_X86_REG_EDX) + puts(">>> ECX = 0x%x" % r_ecx) + puts(">>> EDX = 0x%x" % r_edx) + + rescue UcError => e + print("ERROR: %s" % e) + end +end + + +def test_i386_invalid_mem_write() + puts("Emulate i386 code that write to invalid memory") + begin + # Initialize emulator in X86-32bit mode + mu = Uc.new UC_ARCH_X86, UC_MODE_32 + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, X86_CODE32_MEM_WRITE) + + # initialize machine registers + mu.reg_write(UC_X86_REG_ECX, 0x1234) + mu.reg_write(UC_X86_REG_EDX, 0x7890) + + # tracing all basic blocks with customized callback + #mu.hook_add(UC_HOOK_BLOCK, HOOK_BLOCK) + + # tracing all instructions with customized callback + #mu.hook_add(UC_HOOK_CODE, HOOK_CODE) + + # intercept invalid memory events + mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, HOOK_MEM_INVALID) + + begin + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + X86_CODE32_MEM_WRITE.bytesize) + rescue UcError => e + puts "ERROR: %s" % e + end + + # now print out some registers + puts ">>> Emulation done. Below is the CPU context" + + r_ecx = mu.reg_read(UC_X86_REG_ECX) + r_edx = mu.reg_read(UC_X86_REG_EDX) + puts ">>> ECX = 0x%x" % r_ecx + puts ">>> EDX = 0x%x" % r_edx + + begin + # read from memory + print ">>> Read 4 bytes from [0x%x] = " % (0xaaaaaaaa) + tmp = mu.mem_read(0xaaaaaaaa, 4) + tmp.each_byte { |i| print(" 0x%x" % i) } + puts + + print ">>> Read 4 bytes from [0x%x] = " % 0xffffffaa + tmp = mu.mem_read(0xffffffaa, 4) + tmp.each_byte { |i| puts(" 0x%x" % i) } + puts + + rescue UcError => e + puts "ERROR: %s" % e + end + + rescue UcError => e + puts "ERROR: %s" % e + end +end + +# Test X86 32 bit with IN/OUT instruction +def test_i386_inout() + puts("Emulate i386 code with IN/OUT instructions") + begin + # Initialize emulator in X86-32bit mode + mu = Uc.new UC_ARCH_X86, UC_MODE_32 + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, X86_CODE32_INOUT) + + # initialize machine registers + mu.reg_write(UC_X86_REG_EAX, 0x1234) + mu.reg_write(UC_X86_REG_ECX, 0x6789) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, HOOK_BLOCK) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, HOOK_CODE) + + # handle IN & OUT instruction + mu.hook_add(UC_HOOK_INSN, HOOK_IN, nil, 1, 0, UC_X86_INS_IN) + mu.hook_add(UC_HOOK_INSN, HOOK_OUT, nil, 1, 0, UC_X86_INS_OUT) + + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + X86_CODE32_INOUT.bytesize) + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + r_ecx = mu.reg_read(UC_X86_REG_ECX) + r_eax = mu.reg_read(UC_X86_REG_EAX) + puts ">>> EAX = 0x%x" % r_eax + puts ">>> ECX = 0x%x" % r_ecx + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +def test_x86_64() + puts("Emulate x86_64 code") + begin + # Initialize emulator in X86-64bit mode + mu = Uc.new UC_ARCH_X86, UC_MODE_64 + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, X86_CODE64) + + # initialize machine registers + mu.reg_write(UC_X86_REG_RAX, 0x71f3029efd49d41d) + mu.reg_write(UC_X86_REG_RBX, 0xd87b45277f133ddb) + mu.reg_write(UC_X86_REG_RCX, 0xab40d1ffd8afc461) + mu.reg_write(UC_X86_REG_RDX, 0x919317b4a733f01) + mu.reg_write(UC_X86_REG_RSI, 0x4c24e753a17ea358) + mu.reg_write(UC_X86_REG_RDI, 0xe509a57d2571ce96) + mu.reg_write(UC_X86_REG_R8, 0xea5b108cc2b9ab1f) + mu.reg_write(UC_X86_REG_R9, 0x19ec097c8eb618c1) + mu.reg_write(UC_X86_REG_R10, 0xec45774f00c5f682) + mu.reg_write(UC_X86_REG_R11, 0xe17e9dbec8c074aa) + mu.reg_write(UC_X86_REG_R12, 0x80f86a8dc0f6d457) + mu.reg_write(UC_X86_REG_R13, 0x48288ca5671c5492) + mu.reg_write(UC_X86_REG_R14, 0x595f72f6e4017f6e) + mu.reg_write(UC_X86_REG_R15, 0x1efd97aea331cccc) + + # setup stack + mu.reg_write(UC_X86_REG_RSP, ADDRESS + 0x200000) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, HOOK_BLOCK) + + # tracing all instructions in range [ADDRESS, ADDRESS+20] + mu.hook_add(UC_HOOK_CODE, HOOK_CODE, 0, ADDRESS, ADDRESS+20) + + # tracing all memory READ & WRITE access + mu.hook_add(UC_HOOK_MEM_WRITE, HOOK_MEM_ACCESS) + mu.hook_add(UC_HOOK_MEM_READ, HOOK_MEM_ACCESS) + # actually you can also use READ_WRITE to trace all memory access + #mu.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, hook_mem_access) + + begin + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + X86_CODE64.bytesize) + rescue UcError => e + puts("ERROR: %s" % e) + end + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + rax = mu.reg_read(UC_X86_REG_RAX) + rbx = mu.reg_read(UC_X86_REG_RBX) + rcx = mu.reg_read(UC_X86_REG_RCX) + rdx = mu.reg_read(UC_X86_REG_RDX) + rsi = mu.reg_read(UC_X86_REG_RSI) + rdi = mu.reg_read(UC_X86_REG_RDI) + r8 = mu.reg_read(UC_X86_REG_R8) + r9 = mu.reg_read(UC_X86_REG_R9) + r10 = mu.reg_read(UC_X86_REG_R10) + r11 = mu.reg_read(UC_X86_REG_R11) + r12 = mu.reg_read(UC_X86_REG_R12) + r13 = mu.reg_read(UC_X86_REG_R13) + r14 = mu.reg_read(UC_X86_REG_R14) + r15 = mu.reg_read(UC_X86_REG_R15) + + puts(">>> RAX = %d" % rax) + puts(">>> RBX = %d" % rbx) + puts(">>> RCX = %d" % rcx) + puts(">>> RDX = %d" % rdx) + puts(">>> RSI = %d" % rsi) + puts(">>> RDI = %d" % rdi) + puts(">>> R8 = %d" % r8) + puts(">>> R9 = %d" % r9) + puts(">>> R10 = %d" % r10) + puts(">>> R11 = %d" % r11) + puts(">>> R12 = %d" % r12) + puts(">>> R13 = %d" % r13) + puts(">>> R14 = %d" % r14) + puts(">>> R15 = %d" % r15) + #BUG + mu.emu_start(ADDRESS, ADDRESS + X86_CODE64.bytesize) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +def test_x86_64_syscall() + puts("Emulate x86_64 code with 'syscall' instruction") + begin + # Initialize emulator in X86-64bit mode + mu = Uc.new UC_ARCH_X86, UC_MODE_64 + + # map 2MB memory for this emulation + mu.mem_map(ADDRESS, 2 * 1024 * 1024) + + # write machine code to be emulated to memory + mu.mem_write(ADDRESS, X86_CODE64_SYSCALL) + + hook_syscall = Proc.new do |mu, user_data| + rax = mu.reg_read(UC_X86_REG_RAX) + if rax == 0x100 + mu.reg_write(UC_X86_REG_RAX, 0x200) + else + puts('ERROR: was not expecting rax=%d in syscall' % rax) + end + end + + # hook interrupts for syscall + mu.hook_add(UC_HOOK_INSN, hook_syscall, nil, 1, 0, UC_X86_INS_SYSCALL) + + # syscall handler is expecting rax=0x100 + mu.reg_write(UC_X86_REG_RAX, 0x100) + + begin + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + X86_CODE64_SYSCALL.bytesize) + rescue UcError => e + puts("ERROR: %s" % e) + end + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + rax = mu.reg_read(UC_X86_REG_RAX) + puts(">>> RAX = 0x%x" % rax) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +def test_x86_16() + puts("Emulate x86 16-bit code") + begin + # Initialize emulator in X86-16bit mode + mu = Uc.new UC_ARCH_X86, UC_MODE_16 + + # map 8KB memory for this emulation + mu.mem_map(0, 8 * 1024) + + # set CPU registers + mu.reg_write(UC_X86_REG_EAX, 7) + mu.reg_write(UC_X86_REG_EBX, 5) + mu.reg_write(UC_X86_REG_ESI, 6) + + # write machine code to be emulated to memory + mu.mem_write(0, X86_CODE16) + + # emulate machine code in infinite time + mu.emu_start(0, X86_CODE16.bytesize) + + # now print out some registers + puts(">>> Emulation done. Below is the CPU context") + + tmp = mu.mem_read(11, 1) + puts("[0x%x] = 0x%x" % [11, tmp[0].ord]) + + rescue UcError => e + puts("ERROR: %s" % e) + end +end + + +test_i386() +puts("=" * 20) +test_i386_loop() +puts("=" * 20) +test_i386_invalid_mem_read() +puts("=" * 20) +test_i386_invalid_mem_write() +puts("=" * 20) +test_i386_inout() +puts("=" * 20) +test_x86_64() +puts("=" * 20) +test_x86_64_syscall() +puts("=" * 20) +test_x86_16() diff --git a/bindings/ruby/sample_x86_gdt.rb b/bindings/ruby/sample_x86_gdt.rb new file mode 100644 index 00000000..ea6c9431 --- /dev/null +++ b/bindings/ruby/sample_x86_gdt.rb @@ -0,0 +1,97 @@ +#!/usr/bin/env ruby +require 'unicorn' +require 'unicorn/x86_const' + +include Unicorn + +F_GRANULARITY = 0x8 +F_PROT_32 = 0x4 +F_LONG = 0x2 +F_AVAILABLE = 0x1 + +A_PRESENT = 0x80 + +A_PRIV_3 = 0x60 +A_PRIV_2 = 0x40 +A_PRIV_1 = 0x20 +A_PRIV_0 = 0x0 + +A_CODE = 0x10 +A_DATA = 0x10 +A_TSS = 0x0 +A_GATE = 0x0 + +A_DATA_WRITABLE = 0x2 +A_CODE_READABLE = 0x2 + +A_DIR_CON_BIT = 0x4 + +S_GDT = 0x0 +S_LDT = 0x4 +S_PRIV_3 = 0x3 +S_PRIV_2 = 0x2 +S_PRIV_1 = 0x1 +S_PRIV_0 = 0x0 + +def create_selector(idx, flags) + to_ret = flags + to_ret |= idx << 3 + return to_ret +end + +def create_gdt_entry(base, limit, access, flags) + + to_ret = limit & 0xffff; + to_ret |= (base & 0xffffff) << 16; + to_ret |= (access & 0xff) << 40; + to_ret |= ((limit >> 16) & 0xf) << 48; + to_ret |= (flags & 0xff) << 52; + to_ret |= ((base >> 24) & 0xff) << 56; + return [to_ret].pack('Q') +end + +def write_gdt(uc, gdt, mem) + gdt.each_index do |idx| + offset = idx * GDT_ENTRY_SIZE + uc.mem_write(mem + offset, gdt[idx]) + end +end + +CODE_ADDR = 0x40000 +CODE_SIZE = 0x1000 + +GDT_ADDR = 0x3000 +GDT_LIMIT = 0x1000 +GDT_ENTRY_SIZE = 0x8 + +GS_SEGMENT_ADDR = 0x5000 +GS_SEGMENT_SIZE = 0x1000 + +uc = Uc.new UC_ARCH_X86, UC_MODE_32 + +uc.mem_map(GDT_ADDR, GDT_LIMIT) +uc.mem_map(GS_SEGMENT_ADDR, GS_SEGMENT_SIZE) +uc.mem_map(CODE_ADDR, CODE_SIZE) + +gdt = Array.new (31) {|i| create_gdt_entry(0,0,0,0)} +gdt[15] = create_gdt_entry(GS_SEGMENT_ADDR, GS_SEGMENT_SIZE, A_PRESENT | A_DATA | A_DATA_WRITABLE | A_PRIV_3 | A_DIR_CON_BIT, F_PROT_32) +gdt[16] = create_gdt_entry(0, 0xfffff000 , A_PRESENT | A_DATA | A_DATA_WRITABLE | A_PRIV_3 | A_DIR_CON_BIT, F_PROT_32) # Data Segment +gdt[17] = create_gdt_entry(0, 0xfffff000 , A_PRESENT | A_CODE | A_CODE_READABLE | A_PRIV_3 | A_DIR_CON_BIT, F_PROT_32) # Code Segment +gdt[18] = create_gdt_entry(0, 0xfffff000 , A_PRESENT | A_DATA | A_DATA_WRITABLE | A_PRIV_0 | A_DIR_CON_BIT, F_PROT_32) # Stack Segment + +write_gdt(uc, gdt, GDT_ADDR) +uc.reg_write(UC_X86_REG_GDTR, [0, GDT_ADDR, gdt.length * GDT_ENTRY_SIZE-1, 0x0]) + +selector = create_selector(15, S_GDT | S_PRIV_3) +uc.reg_write(UC_X86_REG_GS, selector) + +selector = create_selector(16, S_GDT | S_PRIV_3) +uc.reg_write(UC_X86_REG_DS, selector) + +selector = create_selector(17, S_GDT | S_PRIV_3) +uc.reg_write(UC_X86_REG_CS, selector) + +selector = create_selector(18, S_GDT | S_PRIV_0) +uc.reg_write(UC_X86_REG_SS, selector) + + diff --git a/bindings/ruby/unicorn_gem/Gemfile b/bindings/ruby/unicorn_gem/Gemfile new file mode 100644 index 00000000..fa75df15 --- /dev/null +++ b/bindings/ruby/unicorn_gem/Gemfile @@ -0,0 +1,3 @@ +source 'https://rubygems.org' + +gemspec diff --git a/bindings/ruby/unicorn_gem/Rakefile b/bindings/ruby/unicorn_gem/Rakefile new file mode 100644 index 00000000..43022f71 --- /dev/null +++ b/bindings/ruby/unicorn_gem/Rakefile @@ -0,0 +1,2 @@ +require "bundler/gem_tasks" +task :default => :spec diff --git a/bindings/ruby/unicorn_gem/ext/extconf.rb b/bindings/ruby/unicorn_gem/ext/extconf.rb new file mode 100644 index 00000000..cdbfc837 --- /dev/null +++ b/bindings/ruby/unicorn_gem/ext/extconf.rb @@ -0,0 +1,8 @@ +require 'mkmf' + +extension_name = 'unicorn' + +dir_config(extension_name) +have_library('unicorn') + +create_makefile(extension_name) \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/ext/unicorn.c b/bindings/ruby/unicorn_gem/ext/unicorn.c new file mode 100644 index 00000000..c7979343 --- /dev/null +++ b/bindings/ruby/unicorn_gem/ext/unicorn.c @@ -0,0 +1,424 @@ +/* + +Ruby bindings for the Unicorn Emulator Engine + +Copyright(c) 2016 Sascha Schirra + +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. + +*/ +#include "ruby.h" +#include +#include +#include "unicorn.h" + +VALUE UnicornModule = Qnil; +VALUE UcClass = Qnil; +VALUE UcError = Qnil; + + +void Init_unicorn() { + rb_require("unicorn/unicorn_const"); + UnicornModule = rb_define_module("Unicorn"); + UcError = rb_define_class_under(UnicornModule, "UcError", rb_eStandardError); + + UcClass = rb_define_class_under(UnicornModule, "Uc", rb_cObject); + rb_define_method(UcClass, "initialize", m_uc_initialize, 2); + rb_define_method(UcClass, "emu_start", m_uc_emu_start, -1); + rb_define_method(UcClass, "emu_stop", m_uc_emu_stop, 0); + rb_define_method(UcClass, "reg_read", m_uc_reg_read, 1); + rb_define_method(UcClass, "reg_write", m_uc_reg_write, 2); + rb_define_method(UcClass, "mem_read", m_uc_mem_read, 2); + rb_define_method(UcClass, "mem_write", m_uc_mem_write, 2); + rb_define_method(UcClass, "mem_map", m_uc_mem_map, -1); + rb_define_method(UcClass, "mem_unmap", m_uc_mem_unmap, 2); + rb_define_method(UcClass, "mem_protect", m_uc_mem_protect, 3); + rb_define_method(UcClass, "hook_add", m_uc_hook_add, -1); + rb_define_method(UcClass, "hook_del", m_uc_hook_del, 1); + rb_define_method(UcClass, "query", m_uc_hook_del, 1); +} + +VALUE m_uc_initialize(VALUE self, VALUE arch, VALUE mode) { + uc_engine *_uc; + uc_err err; + err = uc_open(NUM2INT(arch), NUM2INT(mode), &_uc); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + + VALUE uc = Data_Wrap_Struct(UcClass, 0, uc_close, _uc); + rb_iv_set(self, "@uch", uc); + + return self; +} + +VALUE m_uc_emu_start(int argc, VALUE* argv, VALUE self){ + VALUE begin; + VALUE until; + VALUE timeout; + VALUE count; + uc_err err; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + + rb_scan_args(argc, argv, "22",&begin, &until, &timeout, &count); + if (NIL_P(timeout)) + timeout = INT2NUM(0); + + if (NIL_P(count)) + count = INT2NUM(0); + + err = uc_emu_start(_uc, NUM2ULL(begin), NUM2ULL(until), NUM2INT(timeout), NUM2INT(count)); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return Qnil; +} + +VALUE m_uc_emu_stop(VALUE self){ + uc_err err; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + + err = uc_emu_stop(_uc); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return Qnil; +} + +VALUE m_uc_reg_read(VALUE self, VALUE reg_id){ + uc_err err; + int32_t tmp_reg = NUM2INT(reg_id); + int64_t reg_value = 0; + VALUE to_ret; + uc_x86_mmr mmr; + + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + switch(tmp_reg){ + case UC_X86_REG_GDTR: + case UC_X86_REG_IDTR: + case UC_X86_REG_LDTR: + case UC_X86_REG_TR: + mmr.selector = 0; + mmr.base = 0; + mmr.limit = 0; + mmr.flags = 0; + err = uc_reg_read(_uc, tmp_reg, &mmr); + + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + VALUE mmr_ary = rb_ary_new(); + reg_value = mmr.selector; + rb_ary_store(mmr_ary, 0, UINT2NUM(reg_value)); + rb_ary_store(mmr_ary, 1, ULL2NUM(mmr.base)); + rb_ary_store(mmr_ary, 2, UINT2NUM(mmr.limit)); + rb_ary_store(mmr_ary, 3, UINT2NUM(mmr.flags)); + return mmr_ary; + default: + err = uc_reg_read(_uc, tmp_reg, ®_value); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return LL2NUM(reg_value); + } + +} + +VALUE m_uc_reg_write(VALUE self, VALUE reg_id, VALUE reg_value){ + uc_err err; + int32_t tmp_reg = NUM2INT(reg_id); + uc_x86_mmr mmr; + int64_t tmp; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + + switch(tmp_reg){ + case UC_X86_REG_GDTR: + case UC_X86_REG_IDTR: + case UC_X86_REG_LDTR: + case UC_X86_REG_TR: + Check_Type(reg_value, T_ARRAY); + + mmr.selector = NUM2USHORT(rb_ary_entry(reg_value,0)); + mmr.base = NUM2ULL(rb_ary_entry(reg_value,1)); + mmr.limit = NUM2UINT(rb_ary_entry(reg_value,2)); + mmr.flags = NUM2UINT(rb_ary_entry(reg_value,3)); + err = uc_reg_write(_uc, tmp_reg, &mmr); + break; + default: + tmp = NUM2ULL(reg_value); + + err = uc_reg_write(_uc, NUM2INT(reg_id), &tmp); + break; + } + + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return Qnil; +} + +VALUE m_uc_mem_read(VALUE self, VALUE address, VALUE size){ + size_t isize = NUM2UINT(size); + uint8_t bytes[isize]; + uc_err err; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + + err = uc_mem_read(_uc, NUM2ULL(address), &bytes, isize); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return rb_str_new(bytes, isize); +} + +VALUE m_uc_mem_write(VALUE self, VALUE address, VALUE bytes){ + uc_err err; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + err = uc_mem_write(_uc, NUM2ULL(address), StringValuePtr(bytes), RSTRING_LEN(bytes)); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return Qnil; +} + +VALUE m_uc_mem_map(int argc, VALUE* argv, VALUE self){ + uc_err err; + VALUE address; + VALUE size; + VALUE perms; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + rb_scan_args(argc, argv, "21",&address, &size, &perms); + if (NIL_P(perms)) + perms = INT2NUM(UC_PROT_ALL); + + err = uc_mem_map(_uc, NUM2ULL(address), NUM2UINT(size), NUM2UINT(perms)); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return Qnil; +} + +VALUE m_uc_mem_unmap(VALUE self, VALUE address, VALUE size){ + uc_err err; + uc_engine *_uc; + _uc = (uc_engine*) NUM2ULL(rb_iv_get(self, "@uch")); + err = uc_mem_unmap(_uc, NUM2ULL(address), NUM2UINT(size)); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return Qnil; +} + +VALUE m_uc_mem_protect(VALUE self, VALUE address, VALUE size, VALUE perms){ + uc_err err; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + err = uc_mem_protect(_uc, NUM2ULL(address), NUM2UINT(size), NUM2UINT(perms)); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return Qnil; +} + +static void cb_hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data){ + VALUE passthrough = (VALUE)user_data; + VALUE cb; + VALUE ud; + VALUE rUc; + + cb = rb_ary_entry(passthrough, 0); + ud = rb_ary_entry(passthrough, 1); + rUc = rb_ary_entry(passthrough, 2); + rb_funcall(cb, rb_intern("call"), 4, rUc, ULL2NUM(address), UINT2NUM(size), ud); +} + +static void cb_hook_mem_access(uc_engine *uc, uint32_t access, uint64_t address, uint32_t size, int64_t value, void *user_data){ + VALUE passthrough = (VALUE)user_data; + VALUE cb; + VALUE ud; + VALUE rUc; + + cb = rb_ary_entry(passthrough, 0); + ud = rb_ary_entry(passthrough, 1); + rUc = rb_ary_entry(passthrough, 2); + + rb_funcall(cb, rb_intern("call"), 6, rUc, UINT2NUM(access), ULL2NUM(address), UINT2NUM(size), LL2NUM(value), ud); +} + +static bool cb_hook_mem_invalid(uc_engine *uc, uint32_t access, uint64_t address, uint32_t size, int64_t value, void *user_data){ + VALUE passthrough = (VALUE)user_data; + VALUE cb; + VALUE ud; + VALUE rUc; + + cb = rb_ary_entry(passthrough, 0); + ud = rb_ary_entry(passthrough, 1); + rUc = rb_ary_entry(passthrough, 2); + return RTEST(rb_funcall(cb, rb_intern("call"), 6, rUc, UINT2NUM(access), ULL2NUM(address), UINT2NUM(size), LL2NUM(value), ud)); +} + +static uint32_t cb_hook_insn_in(uc_engine *uc, uint32_t port, int size, void *user_data){ + VALUE passthrough = (VALUE)user_data; + VALUE cb; + VALUE ud; + VALUE rUc; + + cb = rb_ary_entry(passthrough, 0); + ud = rb_ary_entry(passthrough, 1); + rUc = rb_ary_entry(passthrough, 2); + return NUM2UINT(rb_funcall(cb, rb_intern("call"), 4, rUc, UINT2NUM(port), INT2NUM(size), ud)); +} + +static void cb_hook_insn_out(uc_engine *uc, uint32_t port, int size, uint32_t value, void *user_data){ + VALUE passthrough = (VALUE)user_data; + VALUE cb; + VALUE ud; + VALUE rUc; + + cb = rb_ary_entry(passthrough, 0); + ud = rb_ary_entry(passthrough, 1); + rUc = rb_ary_entry(passthrough, 2); + rb_funcall(cb, rb_intern("call"), 5, rUc, UINT2NUM(port), INT2NUM(size), UINT2NUM(value), ud); +} + +static void cb_hook_insn_syscall(uc_engine *uc, void *user_data){ + VALUE passthrough = (VALUE)user_data; + VALUE cb; + VALUE ud; + VALUE rUc; + + cb = rb_ary_entry(passthrough, 0); + ud = rb_ary_entry(passthrough, 1); + rUc = rb_ary_entry(passthrough, 2); + rb_funcall(cb, rb_intern("call"), 2, rUc, ud); +} + +static void cb_hook_intr(uc_engine *uc, uint64_t address, uint32_t size, int64_t value, void *user_data){ + VALUE passthrough = (VALUE)user_data; + VALUE cb; + VALUE ud; + VALUE rUc; + + cb = rb_ary_entry(passthrough, 0); + ud = rb_ary_entry(passthrough, 1); + rUc = rb_ary_entry(passthrough, 2); + rb_funcall(cb, rb_intern("call"), 5, rUc, ULL2NUM(address), UINT2NUM(size), LL2NUM(value), ud); +} + +VALUE m_uc_hook_add(int argc, VALUE* argv, VALUE self){ + VALUE hook_type; + VALUE callback; + VALUE user_data; + VALUE begin; + VALUE end; + VALUE arg1; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + rb_scan_args(argc, argv, "24",&hook_type, &callback, &user_data, &begin, &end, &arg1); + if (NIL_P(begin)) + begin = ULL2NUM(1); + + if (NIL_P(end)) + end = ULL2NUM(0); + + if (NIL_P(arg1)) + arg1 = INT2NUM(0); + + VALUE passthrough; + uc_hook trace; + uc_err err; + + if (rb_class_of(callback) != rb_cProc) + rb_raise(UcError, "Expected Proc callback"); + + passthrough = rb_ary_new(); + rb_ary_store(passthrough, 0, callback); + rb_ary_store(passthrough, 1, user_data); + rb_ary_store(passthrough, 2, self); + + uint32_t htype = NUM2UINT(hook_type); + if(htype == UC_HOOK_INSN){ + switch(NUM2INT(arg1)){ + case UC_X86_INS_IN: + err = uc_hook_add(_uc, &trace, htype, cb_hook_insn_in,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end), NUM2INT(arg1)); + break; + case UC_X86_INS_OUT: + err = uc_hook_add(_uc, &trace, htype, cb_hook_insn_out,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end), NUM2INT(arg1)); + break; + case UC_X86_INS_SYSCALL: + case UC_X86_INS_SYSENTER: + err = uc_hook_add(_uc, &trace, htype, cb_hook_insn_syscall,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end), NUM2INT(arg1)); + break; + } + } + else if(htype == UC_HOOK_INTR){ + err = uc_hook_add(_uc, &trace, htype, cb_hook_intr,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end)); + } + else if(htype == UC_HOOK_CODE || htype == UC_HOOK_BLOCK){ + err = uc_hook_add(_uc, &trace, htype, cb_hook_code,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end)); + } + else if (htype & UC_HOOK_MEM_READ_UNMAPPED + || htype & UC_HOOK_MEM_WRITE_UNMAPPED + || htype & UC_HOOK_MEM_FETCH_UNMAPPED + || htype & UC_HOOK_MEM_READ_PROT + || htype & UC_HOOK_MEM_WRITE_PROT + || htype & UC_HOOK_MEM_FETCH_PROT + || htype & UC_HOOK_MEM_READ_INVALID + || htype & UC_HOOK_MEM_WRITE_INVALID + || htype & UC_HOOK_MEM_FETCH_INVALID + || htype & UC_HOOK_MEM_UNMAPPED + || htype & UC_HOOK_MEM_PROT + || htype & UC_HOOK_MEM_INVALID) { + err = uc_hook_add(_uc, &trace, htype, cb_hook_mem_invalid,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end)); + } + else{ + err = uc_hook_add(_uc, &trace, htype, cb_hook_mem_access,(void *)passthrough, NUM2ULL(begin), NUM2ULL(end)); + } + + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return INT2NUM(trace); +} + +VALUE m_uc_hook_del(VALUE self, VALUE hook){ + int h = NUM2INT(hook); + uc_err err; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + err = uc_hook_del(_uc, h); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return Qnil; +} + +VALUE m_uc_query(VALUE self, VALUE query_mode){ + int qm = NUM2INT(query_mode); + size_t result; + uc_err err; + uc_engine *_uc; + Data_Get_Struct(rb_iv_get(self,"@uch"), uc_engine, _uc); + err = uc_query(_uc, qm, &result); + if (err != UC_ERR_OK) { + rb_raise(UcError, "%s", uc_strerror(err)); + } + return INT2NUM(result); +} diff --git a/bindings/ruby/unicorn_gem/ext/unicorn.h b/bindings/ruby/unicorn_gem/ext/unicorn.h new file mode 100644 index 00000000..05fb2608 --- /dev/null +++ b/bindings/ruby/unicorn_gem/ext/unicorn.h @@ -0,0 +1,33 @@ +/* + +Ruby bindings for the Unicorn Emulator Engine + +Copyright(c) 2016 Sascha Schirra + +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. + +*/ +VALUE m_uc_initialize(VALUE self, VALUE arch, VALUE mode); +VALUE m_uc_emu_start(int argc, VALUE* argv, VALUE self); +VALUE m_uc_emu_stop(VALUE self); +VALUE m_uc_reg_read(VALUE self, VALUE reg_id); +VALUE m_uc_reg_write(VALUE self, VALUE reg_id, VALUE reg_value); +VALUE m_uc_mem_read(VALUE self, VALUE address, VALUE size); +VALUE m_uc_mem_write(VALUE self, VALUE address, VALUE bytes); +VALUE m_uc_mem_map(int argc, VALUE* argv, VALUE self); +VALUE m_uc_mem_unmap(VALUE self, VALUE address, VALUE size); +VALUE m_uc_mem_protect(VALUE self, VALUE address, VALUE size, VALUE perms); +VALUE m_uc_hook_add(int argc, VALUE* argv, VALUE self); +VALUE m_uc_hook_del(VALUE self, VALUE hook); +VALUE m_uc_query(VALUE self, VALUE query_mode); \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/lib/unicorn/arm64_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn/arm64_const.rb new file mode 100644 index 00000000..7767d96b --- /dev/null +++ b/bindings/ruby/unicorn_gem/lib/unicorn/arm64_const.rb @@ -0,0 +1,277 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [arm64_const.rb] + +module Unicorn + +# ARM64 registers + + UC_ARM64_REG_INVALID = 0 + UC_ARM64_REG_X29 = 1 + UC_ARM64_REG_X30 = 2 + UC_ARM64_REG_NZCV = 3 + UC_ARM64_REG_SP = 4 + UC_ARM64_REG_WSP = 5 + UC_ARM64_REG_WZR = 6 + UC_ARM64_REG_XZR = 7 + UC_ARM64_REG_B0 = 8 + UC_ARM64_REG_B1 = 9 + UC_ARM64_REG_B2 = 10 + UC_ARM64_REG_B3 = 11 + UC_ARM64_REG_B4 = 12 + UC_ARM64_REG_B5 = 13 + UC_ARM64_REG_B6 = 14 + UC_ARM64_REG_B7 = 15 + UC_ARM64_REG_B8 = 16 + UC_ARM64_REG_B9 = 17 + UC_ARM64_REG_B10 = 18 + UC_ARM64_REG_B11 = 19 + UC_ARM64_REG_B12 = 20 + UC_ARM64_REG_B13 = 21 + UC_ARM64_REG_B14 = 22 + UC_ARM64_REG_B15 = 23 + UC_ARM64_REG_B16 = 24 + UC_ARM64_REG_B17 = 25 + UC_ARM64_REG_B18 = 26 + UC_ARM64_REG_B19 = 27 + UC_ARM64_REG_B20 = 28 + UC_ARM64_REG_B21 = 29 + UC_ARM64_REG_B22 = 30 + UC_ARM64_REG_B23 = 31 + UC_ARM64_REG_B24 = 32 + UC_ARM64_REG_B25 = 33 + UC_ARM64_REG_B26 = 34 + UC_ARM64_REG_B27 = 35 + UC_ARM64_REG_B28 = 36 + UC_ARM64_REG_B29 = 37 + UC_ARM64_REG_B30 = 38 + UC_ARM64_REG_B31 = 39 + UC_ARM64_REG_D0 = 40 + UC_ARM64_REG_D1 = 41 + UC_ARM64_REG_D2 = 42 + UC_ARM64_REG_D3 = 43 + UC_ARM64_REG_D4 = 44 + UC_ARM64_REG_D5 = 45 + UC_ARM64_REG_D6 = 46 + UC_ARM64_REG_D7 = 47 + UC_ARM64_REG_D8 = 48 + UC_ARM64_REG_D9 = 49 + UC_ARM64_REG_D10 = 50 + UC_ARM64_REG_D11 = 51 + UC_ARM64_REG_D12 = 52 + UC_ARM64_REG_D13 = 53 + UC_ARM64_REG_D14 = 54 + UC_ARM64_REG_D15 = 55 + UC_ARM64_REG_D16 = 56 + UC_ARM64_REG_D17 = 57 + UC_ARM64_REG_D18 = 58 + UC_ARM64_REG_D19 = 59 + UC_ARM64_REG_D20 = 60 + UC_ARM64_REG_D21 = 61 + UC_ARM64_REG_D22 = 62 + UC_ARM64_REG_D23 = 63 + UC_ARM64_REG_D24 = 64 + UC_ARM64_REG_D25 = 65 + UC_ARM64_REG_D26 = 66 + UC_ARM64_REG_D27 = 67 + UC_ARM64_REG_D28 = 68 + UC_ARM64_REG_D29 = 69 + UC_ARM64_REG_D30 = 70 + UC_ARM64_REG_D31 = 71 + UC_ARM64_REG_H0 = 72 + UC_ARM64_REG_H1 = 73 + UC_ARM64_REG_H2 = 74 + UC_ARM64_REG_H3 = 75 + UC_ARM64_REG_H4 = 76 + UC_ARM64_REG_H5 = 77 + UC_ARM64_REG_H6 = 78 + UC_ARM64_REG_H7 = 79 + UC_ARM64_REG_H8 = 80 + UC_ARM64_REG_H9 = 81 + UC_ARM64_REG_H10 = 82 + UC_ARM64_REG_H11 = 83 + UC_ARM64_REG_H12 = 84 + UC_ARM64_REG_H13 = 85 + UC_ARM64_REG_H14 = 86 + UC_ARM64_REG_H15 = 87 + UC_ARM64_REG_H16 = 88 + UC_ARM64_REG_H17 = 89 + UC_ARM64_REG_H18 = 90 + UC_ARM64_REG_H19 = 91 + UC_ARM64_REG_H20 = 92 + UC_ARM64_REG_H21 = 93 + UC_ARM64_REG_H22 = 94 + UC_ARM64_REG_H23 = 95 + UC_ARM64_REG_H24 = 96 + UC_ARM64_REG_H25 = 97 + UC_ARM64_REG_H26 = 98 + UC_ARM64_REG_H27 = 99 + UC_ARM64_REG_H28 = 100 + UC_ARM64_REG_H29 = 101 + UC_ARM64_REG_H30 = 102 + UC_ARM64_REG_H31 = 103 + UC_ARM64_REG_Q0 = 104 + UC_ARM64_REG_Q1 = 105 + UC_ARM64_REG_Q2 = 106 + UC_ARM64_REG_Q3 = 107 + UC_ARM64_REG_Q4 = 108 + UC_ARM64_REG_Q5 = 109 + UC_ARM64_REG_Q6 = 110 + UC_ARM64_REG_Q7 = 111 + UC_ARM64_REG_Q8 = 112 + UC_ARM64_REG_Q9 = 113 + UC_ARM64_REG_Q10 = 114 + UC_ARM64_REG_Q11 = 115 + UC_ARM64_REG_Q12 = 116 + UC_ARM64_REG_Q13 = 117 + UC_ARM64_REG_Q14 = 118 + UC_ARM64_REG_Q15 = 119 + UC_ARM64_REG_Q16 = 120 + UC_ARM64_REG_Q17 = 121 + UC_ARM64_REG_Q18 = 122 + UC_ARM64_REG_Q19 = 123 + UC_ARM64_REG_Q20 = 124 + UC_ARM64_REG_Q21 = 125 + UC_ARM64_REG_Q22 = 126 + UC_ARM64_REG_Q23 = 127 + UC_ARM64_REG_Q24 = 128 + UC_ARM64_REG_Q25 = 129 + UC_ARM64_REG_Q26 = 130 + UC_ARM64_REG_Q27 = 131 + UC_ARM64_REG_Q28 = 132 + UC_ARM64_REG_Q29 = 133 + UC_ARM64_REG_Q30 = 134 + UC_ARM64_REG_Q31 = 135 + UC_ARM64_REG_S0 = 136 + UC_ARM64_REG_S1 = 137 + UC_ARM64_REG_S2 = 138 + UC_ARM64_REG_S3 = 139 + UC_ARM64_REG_S4 = 140 + UC_ARM64_REG_S5 = 141 + UC_ARM64_REG_S6 = 142 + UC_ARM64_REG_S7 = 143 + UC_ARM64_REG_S8 = 144 + UC_ARM64_REG_S9 = 145 + UC_ARM64_REG_S10 = 146 + UC_ARM64_REG_S11 = 147 + UC_ARM64_REG_S12 = 148 + UC_ARM64_REG_S13 = 149 + UC_ARM64_REG_S14 = 150 + UC_ARM64_REG_S15 = 151 + UC_ARM64_REG_S16 = 152 + UC_ARM64_REG_S17 = 153 + UC_ARM64_REG_S18 = 154 + UC_ARM64_REG_S19 = 155 + UC_ARM64_REG_S20 = 156 + UC_ARM64_REG_S21 = 157 + UC_ARM64_REG_S22 = 158 + UC_ARM64_REG_S23 = 159 + UC_ARM64_REG_S24 = 160 + UC_ARM64_REG_S25 = 161 + UC_ARM64_REG_S26 = 162 + UC_ARM64_REG_S27 = 163 + UC_ARM64_REG_S28 = 164 + UC_ARM64_REG_S29 = 165 + UC_ARM64_REG_S30 = 166 + UC_ARM64_REG_S31 = 167 + UC_ARM64_REG_W0 = 168 + UC_ARM64_REG_W1 = 169 + UC_ARM64_REG_W2 = 170 + UC_ARM64_REG_W3 = 171 + UC_ARM64_REG_W4 = 172 + UC_ARM64_REG_W5 = 173 + UC_ARM64_REG_W6 = 174 + UC_ARM64_REG_W7 = 175 + UC_ARM64_REG_W8 = 176 + UC_ARM64_REG_W9 = 177 + UC_ARM64_REG_W10 = 178 + UC_ARM64_REG_W11 = 179 + UC_ARM64_REG_W12 = 180 + UC_ARM64_REG_W13 = 181 + UC_ARM64_REG_W14 = 182 + UC_ARM64_REG_W15 = 183 + UC_ARM64_REG_W16 = 184 + UC_ARM64_REG_W17 = 185 + UC_ARM64_REG_W18 = 186 + UC_ARM64_REG_W19 = 187 + UC_ARM64_REG_W20 = 188 + UC_ARM64_REG_W21 = 189 + UC_ARM64_REG_W22 = 190 + UC_ARM64_REG_W23 = 191 + UC_ARM64_REG_W24 = 192 + UC_ARM64_REG_W25 = 193 + UC_ARM64_REG_W26 = 194 + UC_ARM64_REG_W27 = 195 + UC_ARM64_REG_W28 = 196 + UC_ARM64_REG_W29 = 197 + UC_ARM64_REG_W30 = 198 + UC_ARM64_REG_X0 = 199 + UC_ARM64_REG_X1 = 200 + UC_ARM64_REG_X2 = 201 + UC_ARM64_REG_X3 = 202 + UC_ARM64_REG_X4 = 203 + UC_ARM64_REG_X5 = 204 + UC_ARM64_REG_X6 = 205 + UC_ARM64_REG_X7 = 206 + UC_ARM64_REG_X8 = 207 + UC_ARM64_REG_X9 = 208 + UC_ARM64_REG_X10 = 209 + UC_ARM64_REG_X11 = 210 + UC_ARM64_REG_X12 = 211 + UC_ARM64_REG_X13 = 212 + UC_ARM64_REG_X14 = 213 + UC_ARM64_REG_X15 = 214 + UC_ARM64_REG_X16 = 215 + UC_ARM64_REG_X17 = 216 + UC_ARM64_REG_X18 = 217 + UC_ARM64_REG_X19 = 218 + UC_ARM64_REG_X20 = 219 + UC_ARM64_REG_X21 = 220 + UC_ARM64_REG_X22 = 221 + UC_ARM64_REG_X23 = 222 + UC_ARM64_REG_X24 = 223 + UC_ARM64_REG_X25 = 224 + UC_ARM64_REG_X26 = 225 + UC_ARM64_REG_X27 = 226 + UC_ARM64_REG_X28 = 227 + UC_ARM64_REG_V0 = 228 + UC_ARM64_REG_V1 = 229 + UC_ARM64_REG_V2 = 230 + UC_ARM64_REG_V3 = 231 + UC_ARM64_REG_V4 = 232 + UC_ARM64_REG_V5 = 233 + UC_ARM64_REG_V6 = 234 + UC_ARM64_REG_V7 = 235 + UC_ARM64_REG_V8 = 236 + UC_ARM64_REG_V9 = 237 + UC_ARM64_REG_V10 = 238 + UC_ARM64_REG_V11 = 239 + UC_ARM64_REG_V12 = 240 + UC_ARM64_REG_V13 = 241 + UC_ARM64_REG_V14 = 242 + UC_ARM64_REG_V15 = 243 + UC_ARM64_REG_V16 = 244 + UC_ARM64_REG_V17 = 245 + UC_ARM64_REG_V18 = 246 + UC_ARM64_REG_V19 = 247 + UC_ARM64_REG_V20 = 248 + UC_ARM64_REG_V21 = 249 + UC_ARM64_REG_V22 = 250 + UC_ARM64_REG_V23 = 251 + UC_ARM64_REG_V24 = 252 + UC_ARM64_REG_V25 = 253 + UC_ARM64_REG_V26 = 254 + UC_ARM64_REG_V27 = 255 + UC_ARM64_REG_V28 = 256 + UC_ARM64_REG_V29 = 257 + UC_ARM64_REG_V30 = 258 + UC_ARM64_REG_V31 = 259 + +# pseudo registers + UC_ARM64_REG_PC = 260 + UC_ARM64_REG_ENDING = 261 + +# alias registers + UC_ARM64_REG_IP1 = 215 + UC_ARM64_REG_IP0 = 216 + UC_ARM64_REG_FP = 1 + UC_ARM64_REG_LR = 2 +end \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/lib/unicorn/arm_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn/arm_const.rb new file mode 100644 index 00000000..2a80d44c --- /dev/null +++ b/bindings/ruby/unicorn_gem/lib/unicorn/arm_const.rb @@ -0,0 +1,128 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [arm_const.rb] + +module Unicorn + +# ARM registers + + UC_ARM_REG_INVALID = 0 + UC_ARM_REG_APSR = 1 + UC_ARM_REG_APSR_NZCV = 2 + UC_ARM_REG_CPSR = 3 + UC_ARM_REG_FPEXC = 4 + UC_ARM_REG_FPINST = 5 + UC_ARM_REG_FPSCR = 6 + UC_ARM_REG_FPSCR_NZCV = 7 + UC_ARM_REG_FPSID = 8 + UC_ARM_REG_ITSTATE = 9 + UC_ARM_REG_LR = 10 + UC_ARM_REG_PC = 11 + UC_ARM_REG_SP = 12 + UC_ARM_REG_SPSR = 13 + UC_ARM_REG_D0 = 14 + UC_ARM_REG_D1 = 15 + UC_ARM_REG_D2 = 16 + UC_ARM_REG_D3 = 17 + UC_ARM_REG_D4 = 18 + UC_ARM_REG_D5 = 19 + UC_ARM_REG_D6 = 20 + UC_ARM_REG_D7 = 21 + UC_ARM_REG_D8 = 22 + UC_ARM_REG_D9 = 23 + UC_ARM_REG_D10 = 24 + UC_ARM_REG_D11 = 25 + UC_ARM_REG_D12 = 26 + UC_ARM_REG_D13 = 27 + UC_ARM_REG_D14 = 28 + UC_ARM_REG_D15 = 29 + UC_ARM_REG_D16 = 30 + UC_ARM_REG_D17 = 31 + UC_ARM_REG_D18 = 32 + UC_ARM_REG_D19 = 33 + UC_ARM_REG_D20 = 34 + UC_ARM_REG_D21 = 35 + UC_ARM_REG_D22 = 36 + UC_ARM_REG_D23 = 37 + UC_ARM_REG_D24 = 38 + UC_ARM_REG_D25 = 39 + UC_ARM_REG_D26 = 40 + UC_ARM_REG_D27 = 41 + UC_ARM_REG_D28 = 42 + UC_ARM_REG_D29 = 43 + UC_ARM_REG_D30 = 44 + UC_ARM_REG_D31 = 45 + UC_ARM_REG_FPINST2 = 46 + UC_ARM_REG_MVFR0 = 47 + UC_ARM_REG_MVFR1 = 48 + UC_ARM_REG_MVFR2 = 49 + UC_ARM_REG_Q0 = 50 + UC_ARM_REG_Q1 = 51 + UC_ARM_REG_Q2 = 52 + UC_ARM_REG_Q3 = 53 + UC_ARM_REG_Q4 = 54 + UC_ARM_REG_Q5 = 55 + UC_ARM_REG_Q6 = 56 + UC_ARM_REG_Q7 = 57 + UC_ARM_REG_Q8 = 58 + UC_ARM_REG_Q9 = 59 + UC_ARM_REG_Q10 = 60 + UC_ARM_REG_Q11 = 61 + UC_ARM_REG_Q12 = 62 + UC_ARM_REG_Q13 = 63 + UC_ARM_REG_Q14 = 64 + UC_ARM_REG_Q15 = 65 + UC_ARM_REG_R0 = 66 + UC_ARM_REG_R1 = 67 + UC_ARM_REG_R2 = 68 + UC_ARM_REG_R3 = 69 + UC_ARM_REG_R4 = 70 + UC_ARM_REG_R5 = 71 + UC_ARM_REG_R6 = 72 + UC_ARM_REG_R7 = 73 + UC_ARM_REG_R8 = 74 + UC_ARM_REG_R9 = 75 + UC_ARM_REG_R10 = 76 + UC_ARM_REG_R11 = 77 + UC_ARM_REG_R12 = 78 + UC_ARM_REG_S0 = 79 + UC_ARM_REG_S1 = 80 + UC_ARM_REG_S2 = 81 + UC_ARM_REG_S3 = 82 + UC_ARM_REG_S4 = 83 + UC_ARM_REG_S5 = 84 + UC_ARM_REG_S6 = 85 + UC_ARM_REG_S7 = 86 + UC_ARM_REG_S8 = 87 + UC_ARM_REG_S9 = 88 + UC_ARM_REG_S10 = 89 + UC_ARM_REG_S11 = 90 + UC_ARM_REG_S12 = 91 + UC_ARM_REG_S13 = 92 + UC_ARM_REG_S14 = 93 + UC_ARM_REG_S15 = 94 + UC_ARM_REG_S16 = 95 + UC_ARM_REG_S17 = 96 + UC_ARM_REG_S18 = 97 + UC_ARM_REG_S19 = 98 + UC_ARM_REG_S20 = 99 + UC_ARM_REG_S21 = 100 + UC_ARM_REG_S22 = 101 + UC_ARM_REG_S23 = 102 + UC_ARM_REG_S24 = 103 + UC_ARM_REG_S25 = 104 + UC_ARM_REG_S26 = 105 + UC_ARM_REG_S27 = 106 + UC_ARM_REG_S28 = 107 + UC_ARM_REG_S29 = 108 + UC_ARM_REG_S30 = 109 + UC_ARM_REG_S31 = 110 + UC_ARM_REG_ENDING = 111 + +# alias registers + UC_ARM_REG_R13 = 12 + UC_ARM_REG_R14 = 10 + UC_ARM_REG_R15 = 11 + UC_ARM_REG_SB = 75 + UC_ARM_REG_SL = 76 + UC_ARM_REG_FP = 77 + UC_ARM_REG_IP = 78 +end \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/lib/unicorn/m68k_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn/m68k_const.rb new file mode 100644 index 00000000..2c53636d --- /dev/null +++ b/bindings/ruby/unicorn_gem/lib/unicorn/m68k_const.rb @@ -0,0 +1,27 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [m68k_const.rb] + +module Unicorn + +# M68K registers + + UC_M68K_REG_INVALID = 0 + UC_M68K_REG_A0 = 1 + UC_M68K_REG_A1 = 2 + UC_M68K_REG_A2 = 3 + UC_M68K_REG_A3 = 4 + UC_M68K_REG_A4 = 5 + UC_M68K_REG_A5 = 6 + UC_M68K_REG_A6 = 7 + UC_M68K_REG_A7 = 8 + UC_M68K_REG_D0 = 9 + UC_M68K_REG_D1 = 10 + UC_M68K_REG_D2 = 11 + UC_M68K_REG_D3 = 12 + UC_M68K_REG_D4 = 13 + UC_M68K_REG_D5 = 14 + UC_M68K_REG_D6 = 15 + UC_M68K_REG_D7 = 16 + UC_M68K_REG_SR = 17 + UC_M68K_REG_PC = 18 + UC_M68K_REG_ENDING = 19 +end \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/lib/unicorn/mips_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn/mips_const.rb new file mode 100644 index 00000000..d92e94e5 --- /dev/null +++ b/bindings/ruby/unicorn_gem/lib/unicorn/mips_const.rb @@ -0,0 +1,198 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [mips_const.rb] + +module Unicorn + +# MIPS registers + + UC_MIPS_REG_INVALID = 0 + +# General purpose registers + UC_MIPS_REG_PC = 1 + UC_MIPS_REG_0 = 2 + UC_MIPS_REG_1 = 3 + UC_MIPS_REG_2 = 4 + UC_MIPS_REG_3 = 5 + UC_MIPS_REG_4 = 6 + UC_MIPS_REG_5 = 7 + UC_MIPS_REG_6 = 8 + UC_MIPS_REG_7 = 9 + UC_MIPS_REG_8 = 10 + UC_MIPS_REG_9 = 11 + UC_MIPS_REG_10 = 12 + UC_MIPS_REG_11 = 13 + UC_MIPS_REG_12 = 14 + UC_MIPS_REG_13 = 15 + UC_MIPS_REG_14 = 16 + UC_MIPS_REG_15 = 17 + UC_MIPS_REG_16 = 18 + UC_MIPS_REG_17 = 19 + UC_MIPS_REG_18 = 20 + UC_MIPS_REG_19 = 21 + UC_MIPS_REG_20 = 22 + UC_MIPS_REG_21 = 23 + UC_MIPS_REG_22 = 24 + UC_MIPS_REG_23 = 25 + UC_MIPS_REG_24 = 26 + UC_MIPS_REG_25 = 27 + UC_MIPS_REG_26 = 28 + UC_MIPS_REG_27 = 29 + UC_MIPS_REG_28 = 30 + UC_MIPS_REG_29 = 31 + UC_MIPS_REG_30 = 32 + UC_MIPS_REG_31 = 33 + +# DSP registers + UC_MIPS_REG_DSPCCOND = 34 + UC_MIPS_REG_DSPCARRY = 35 + UC_MIPS_REG_DSPEFI = 36 + UC_MIPS_REG_DSPOUTFLAG = 37 + UC_MIPS_REG_DSPOUTFLAG16_19 = 38 + UC_MIPS_REG_DSPOUTFLAG20 = 39 + UC_MIPS_REG_DSPOUTFLAG21 = 40 + UC_MIPS_REG_DSPOUTFLAG22 = 41 + UC_MIPS_REG_DSPOUTFLAG23 = 42 + UC_MIPS_REG_DSPPOS = 43 + UC_MIPS_REG_DSPSCOUNT = 44 + +# ACC registers + UC_MIPS_REG_AC0 = 45 + UC_MIPS_REG_AC1 = 46 + UC_MIPS_REG_AC2 = 47 + UC_MIPS_REG_AC3 = 48 + +# COP registers + UC_MIPS_REG_CC0 = 49 + UC_MIPS_REG_CC1 = 50 + UC_MIPS_REG_CC2 = 51 + UC_MIPS_REG_CC3 = 52 + UC_MIPS_REG_CC4 = 53 + UC_MIPS_REG_CC5 = 54 + UC_MIPS_REG_CC6 = 55 + UC_MIPS_REG_CC7 = 56 + +# FPU registers + UC_MIPS_REG_F0 = 57 + UC_MIPS_REG_F1 = 58 + UC_MIPS_REG_F2 = 59 + UC_MIPS_REG_F3 = 60 + UC_MIPS_REG_F4 = 61 + UC_MIPS_REG_F5 = 62 + UC_MIPS_REG_F6 = 63 + UC_MIPS_REG_F7 = 64 + UC_MIPS_REG_F8 = 65 + UC_MIPS_REG_F9 = 66 + UC_MIPS_REG_F10 = 67 + UC_MIPS_REG_F11 = 68 + UC_MIPS_REG_F12 = 69 + UC_MIPS_REG_F13 = 70 + UC_MIPS_REG_F14 = 71 + UC_MIPS_REG_F15 = 72 + UC_MIPS_REG_F16 = 73 + UC_MIPS_REG_F17 = 74 + UC_MIPS_REG_F18 = 75 + UC_MIPS_REG_F19 = 76 + UC_MIPS_REG_F20 = 77 + UC_MIPS_REG_F21 = 78 + UC_MIPS_REG_F22 = 79 + UC_MIPS_REG_F23 = 80 + UC_MIPS_REG_F24 = 81 + UC_MIPS_REG_F25 = 82 + UC_MIPS_REG_F26 = 83 + UC_MIPS_REG_F27 = 84 + UC_MIPS_REG_F28 = 85 + UC_MIPS_REG_F29 = 86 + UC_MIPS_REG_F30 = 87 + UC_MIPS_REG_F31 = 88 + UC_MIPS_REG_FCC0 = 89 + UC_MIPS_REG_FCC1 = 90 + UC_MIPS_REG_FCC2 = 91 + UC_MIPS_REG_FCC3 = 92 + UC_MIPS_REG_FCC4 = 93 + UC_MIPS_REG_FCC5 = 94 + UC_MIPS_REG_FCC6 = 95 + UC_MIPS_REG_FCC7 = 96 + +# AFPR128 + UC_MIPS_REG_W0 = 97 + UC_MIPS_REG_W1 = 98 + UC_MIPS_REG_W2 = 99 + UC_MIPS_REG_W3 = 100 + UC_MIPS_REG_W4 = 101 + UC_MIPS_REG_W5 = 102 + UC_MIPS_REG_W6 = 103 + UC_MIPS_REG_W7 = 104 + UC_MIPS_REG_W8 = 105 + UC_MIPS_REG_W9 = 106 + UC_MIPS_REG_W10 = 107 + UC_MIPS_REG_W11 = 108 + UC_MIPS_REG_W12 = 109 + UC_MIPS_REG_W13 = 110 + UC_MIPS_REG_W14 = 111 + UC_MIPS_REG_W15 = 112 + UC_MIPS_REG_W16 = 113 + UC_MIPS_REG_W17 = 114 + UC_MIPS_REG_W18 = 115 + UC_MIPS_REG_W19 = 116 + UC_MIPS_REG_W20 = 117 + UC_MIPS_REG_W21 = 118 + UC_MIPS_REG_W22 = 119 + UC_MIPS_REG_W23 = 120 + UC_MIPS_REG_W24 = 121 + UC_MIPS_REG_W25 = 122 + UC_MIPS_REG_W26 = 123 + UC_MIPS_REG_W27 = 124 + UC_MIPS_REG_W28 = 125 + UC_MIPS_REG_W29 = 126 + UC_MIPS_REG_W30 = 127 + UC_MIPS_REG_W31 = 128 + UC_MIPS_REG_HI = 129 + UC_MIPS_REG_LO = 130 + UC_MIPS_REG_P0 = 131 + UC_MIPS_REG_P1 = 132 + UC_MIPS_REG_P2 = 133 + UC_MIPS_REG_MPL0 = 134 + UC_MIPS_REG_MPL1 = 135 + UC_MIPS_REG_MPL2 = 136 + UC_MIPS_REG_ENDING = 137 + UC_MIPS_REG_ZERO = 2 + UC_MIPS_REG_AT = 3 + UC_MIPS_REG_V0 = 4 + UC_MIPS_REG_V1 = 5 + UC_MIPS_REG_A0 = 6 + UC_MIPS_REG_A1 = 7 + UC_MIPS_REG_A2 = 8 + UC_MIPS_REG_A3 = 9 + UC_MIPS_REG_T0 = 10 + UC_MIPS_REG_T1 = 11 + UC_MIPS_REG_T2 = 12 + UC_MIPS_REG_T3 = 13 + UC_MIPS_REG_T4 = 14 + UC_MIPS_REG_T5 = 15 + UC_MIPS_REG_T6 = 16 + UC_MIPS_REG_T7 = 17 + UC_MIPS_REG_S0 = 18 + UC_MIPS_REG_S1 = 19 + UC_MIPS_REG_S2 = 20 + UC_MIPS_REG_S3 = 21 + UC_MIPS_REG_S4 = 22 + UC_MIPS_REG_S5 = 23 + UC_MIPS_REG_S6 = 24 + UC_MIPS_REG_S7 = 25 + UC_MIPS_REG_T8 = 26 + UC_MIPS_REG_T9 = 27 + UC_MIPS_REG_K0 = 28 + UC_MIPS_REG_K1 = 29 + UC_MIPS_REG_GP = 30 + UC_MIPS_REG_SP = 31 + UC_MIPS_REG_FP = 32 + UC_MIPS_REG_S8 = 32 + UC_MIPS_REG_RA = 33 + UC_MIPS_REG_HI0 = 45 + UC_MIPS_REG_HI1 = 46 + UC_MIPS_REG_HI2 = 47 + UC_MIPS_REG_HI3 = 48 + UC_MIPS_REG_LO0 = 45 + UC_MIPS_REG_LO1 = 46 + UC_MIPS_REG_LO2 = 47 + UC_MIPS_REG_LO3 = 48 +end \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/lib/unicorn/sparc_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn/sparc_const.rb new file mode 100644 index 00000000..85d9eef1 --- /dev/null +++ b/bindings/ruby/unicorn_gem/lib/unicorn/sparc_const.rb @@ -0,0 +1,99 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [sparc_const.rb] + +module Unicorn + +# SPARC registers + + UC_SPARC_REG_INVALID = 0 + UC_SPARC_REG_F0 = 1 + UC_SPARC_REG_F1 = 2 + UC_SPARC_REG_F2 = 3 + UC_SPARC_REG_F3 = 4 + UC_SPARC_REG_F4 = 5 + UC_SPARC_REG_F5 = 6 + UC_SPARC_REG_F6 = 7 + UC_SPARC_REG_F7 = 8 + UC_SPARC_REG_F8 = 9 + UC_SPARC_REG_F9 = 10 + UC_SPARC_REG_F10 = 11 + UC_SPARC_REG_F11 = 12 + UC_SPARC_REG_F12 = 13 + UC_SPARC_REG_F13 = 14 + UC_SPARC_REG_F14 = 15 + UC_SPARC_REG_F15 = 16 + UC_SPARC_REG_F16 = 17 + UC_SPARC_REG_F17 = 18 + UC_SPARC_REG_F18 = 19 + UC_SPARC_REG_F19 = 20 + UC_SPARC_REG_F20 = 21 + UC_SPARC_REG_F21 = 22 + UC_SPARC_REG_F22 = 23 + UC_SPARC_REG_F23 = 24 + UC_SPARC_REG_F24 = 25 + UC_SPARC_REG_F25 = 26 + UC_SPARC_REG_F26 = 27 + UC_SPARC_REG_F27 = 28 + UC_SPARC_REG_F28 = 29 + UC_SPARC_REG_F29 = 30 + UC_SPARC_REG_F30 = 31 + UC_SPARC_REG_F31 = 32 + UC_SPARC_REG_F32 = 33 + UC_SPARC_REG_F34 = 34 + UC_SPARC_REG_F36 = 35 + UC_SPARC_REG_F38 = 36 + UC_SPARC_REG_F40 = 37 + UC_SPARC_REG_F42 = 38 + UC_SPARC_REG_F44 = 39 + UC_SPARC_REG_F46 = 40 + UC_SPARC_REG_F48 = 41 + UC_SPARC_REG_F50 = 42 + UC_SPARC_REG_F52 = 43 + UC_SPARC_REG_F54 = 44 + UC_SPARC_REG_F56 = 45 + UC_SPARC_REG_F58 = 46 + UC_SPARC_REG_F60 = 47 + UC_SPARC_REG_F62 = 48 + UC_SPARC_REG_FCC0 = 49 + UC_SPARC_REG_FCC1 = 50 + UC_SPARC_REG_FCC2 = 51 + UC_SPARC_REG_FCC3 = 52 + UC_SPARC_REG_G0 = 53 + UC_SPARC_REG_G1 = 54 + UC_SPARC_REG_G2 = 55 + UC_SPARC_REG_G3 = 56 + UC_SPARC_REG_G4 = 57 + UC_SPARC_REG_G5 = 58 + UC_SPARC_REG_G6 = 59 + UC_SPARC_REG_G7 = 60 + UC_SPARC_REG_I0 = 61 + UC_SPARC_REG_I1 = 62 + UC_SPARC_REG_I2 = 63 + UC_SPARC_REG_I3 = 64 + UC_SPARC_REG_I4 = 65 + UC_SPARC_REG_I5 = 66 + UC_SPARC_REG_FP = 67 + UC_SPARC_REG_I7 = 68 + UC_SPARC_REG_ICC = 69 + UC_SPARC_REG_L0 = 70 + UC_SPARC_REG_L1 = 71 + UC_SPARC_REG_L2 = 72 + UC_SPARC_REG_L3 = 73 + UC_SPARC_REG_L4 = 74 + UC_SPARC_REG_L5 = 75 + UC_SPARC_REG_L6 = 76 + UC_SPARC_REG_L7 = 77 + UC_SPARC_REG_O0 = 78 + UC_SPARC_REG_O1 = 79 + UC_SPARC_REG_O2 = 80 + UC_SPARC_REG_O3 = 81 + UC_SPARC_REG_O4 = 82 + UC_SPARC_REG_O5 = 83 + UC_SPARC_REG_SP = 84 + UC_SPARC_REG_O7 = 85 + UC_SPARC_REG_Y = 86 + UC_SPARC_REG_XCC = 87 + UC_SPARC_REG_PC = 88 + UC_SPARC_REG_ENDING = 89 + UC_SPARC_REG_O6 = 84 + UC_SPARC_REG_I6 = 67 +end \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/lib/unicorn/unicorn_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn/unicorn_const.rb new file mode 100644 index 00000000..7fe8a994 --- /dev/null +++ b/bindings/ruby/unicorn_gem/lib/unicorn/unicorn_const.rb @@ -0,0 +1,98 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [unicorn_const.rb] + +module Unicorn + UC_API_MAJOR = 1 + + UC_API_MINOR = 0 + UC_SECOND_SCALE = 1000000 + UC_MILISECOND_SCALE = 1000 + UC_ARCH_ARM = 1 + UC_ARCH_ARM64 = 2 + UC_ARCH_MIPS = 3 + UC_ARCH_X86 = 4 + UC_ARCH_PPC = 5 + UC_ARCH_SPARC = 6 + UC_ARCH_M68K = 7 + UC_ARCH_MAX = 8 + + UC_MODE_LITTLE_ENDIAN = 0 + UC_MODE_BIG_ENDIAN = 1073741824 + + UC_MODE_ARM = 0 + 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_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 + UC_ERR_ARCH = 2 + UC_ERR_HANDLE = 3 + UC_ERR_MODE = 4 + UC_ERR_VERSION = 5 + UC_ERR_READ_UNMAPPED = 6 + UC_ERR_WRITE_UNMAPPED = 7 + UC_ERR_FETCH_UNMAPPED = 8 + UC_ERR_HOOK = 9 + UC_ERR_INSN_INVALID = 10 + UC_ERR_MAP = 11 + UC_ERR_WRITE_PROT = 12 + UC_ERR_READ_PROT = 13 + UC_ERR_FETCH_PROT = 14 + UC_ERR_ARG = 15 + UC_ERR_READ_UNALIGNED = 16 + UC_ERR_WRITE_UNALIGNED = 17 + UC_ERR_FETCH_UNALIGNED = 18 + UC_ERR_HOOK_EXIST = 19 + UC_ERR_RESOURCE = 20 + UC_MEM_READ = 16 + UC_MEM_WRITE = 17 + UC_MEM_FETCH = 18 + UC_MEM_READ_UNMAPPED = 19 + UC_MEM_WRITE_UNMAPPED = 20 + UC_MEM_FETCH_UNMAPPED = 21 + UC_MEM_WRITE_PROT = 22 + UC_MEM_READ_PROT = 23 + UC_MEM_FETCH_PROT = 24 + UC_HOOK_INTR = 1 + UC_HOOK_INSN = 2 + UC_HOOK_CODE = 4 + UC_HOOK_BLOCK = 8 + UC_HOOK_MEM_READ_UNMAPPED = 16 + UC_HOOK_MEM_WRITE_UNMAPPED = 32 + UC_HOOK_MEM_FETCH_UNMAPPED = 64 + UC_HOOK_MEM_READ_PROT = 128 + UC_HOOK_MEM_WRITE_PROT = 256 + UC_HOOK_MEM_FETCH_PROT = 512 + UC_HOOK_MEM_READ = 1024 + UC_HOOK_MEM_WRITE = 2048 + UC_HOOK_MEM_FETCH = 4096 + UC_HOOK_MEM_UNMAPPED = 112 + UC_HOOK_MEM_PROT = 896 + 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 + UC_PROT_WRITE = 2 + UC_PROT_EXEC = 4 + UC_PROT_ALL = 7 +end \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/lib/unicorn/version.rb b/bindings/ruby/unicorn_gem/lib/unicorn/version.rb new file mode 100644 index 00000000..ad18d0e7 --- /dev/null +++ b/bindings/ruby/unicorn_gem/lib/unicorn/version.rb @@ -0,0 +1,3 @@ +module Unicorn + VERSION = "1.0.0" +end diff --git a/bindings/ruby/unicorn_gem/lib/unicorn/x86_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn/x86_const.rb new file mode 100644 index 00000000..2226de17 --- /dev/null +++ b/bindings/ruby/unicorn_gem/lib/unicorn/x86_const.rb @@ -0,0 +1,1598 @@ +# For Unicorn Engine. AUTO-GENERATED FILE, DO NOT EDIT [x86_const.rb] + +module Unicorn + +# X86 registers + + UC_X86_REG_INVALID = 0 + UC_X86_REG_AH = 1 + UC_X86_REG_AL = 2 + UC_X86_REG_AX = 3 + UC_X86_REG_BH = 4 + UC_X86_REG_BL = 5 + UC_X86_REG_BP = 6 + UC_X86_REG_BPL = 7 + UC_X86_REG_BX = 8 + UC_X86_REG_CH = 9 + UC_X86_REG_CL = 10 + UC_X86_REG_CS = 11 + UC_X86_REG_CX = 12 + UC_X86_REG_DH = 13 + UC_X86_REG_DI = 14 + UC_X86_REG_DIL = 15 + UC_X86_REG_DL = 16 + UC_X86_REG_DS = 17 + UC_X86_REG_DX = 18 + UC_X86_REG_EAX = 19 + UC_X86_REG_EBP = 20 + UC_X86_REG_EBX = 21 + UC_X86_REG_ECX = 22 + UC_X86_REG_EDI = 23 + UC_X86_REG_EDX = 24 + UC_X86_REG_EFLAGS = 25 + UC_X86_REG_EIP = 26 + UC_X86_REG_EIZ = 27 + UC_X86_REG_ES = 28 + UC_X86_REG_ESI = 29 + UC_X86_REG_ESP = 30 + UC_X86_REG_FPSW = 31 + UC_X86_REG_FS = 32 + UC_X86_REG_GS = 33 + UC_X86_REG_IP = 34 + UC_X86_REG_RAX = 35 + UC_X86_REG_RBP = 36 + UC_X86_REG_RBX = 37 + UC_X86_REG_RCX = 38 + UC_X86_REG_RDI = 39 + UC_X86_REG_RDX = 40 + UC_X86_REG_RIP = 41 + UC_X86_REG_RIZ = 42 + UC_X86_REG_RSI = 43 + UC_X86_REG_RSP = 44 + UC_X86_REG_SI = 45 + UC_X86_REG_SIL = 46 + UC_X86_REG_SP = 47 + UC_X86_REG_SPL = 48 + UC_X86_REG_SS = 49 + UC_X86_REG_CR0 = 50 + UC_X86_REG_CR1 = 51 + UC_X86_REG_CR2 = 52 + UC_X86_REG_CR3 = 53 + UC_X86_REG_CR4 = 54 + UC_X86_REG_CR5 = 55 + UC_X86_REG_CR6 = 56 + UC_X86_REG_CR7 = 57 + UC_X86_REG_CR8 = 58 + UC_X86_REG_CR9 = 59 + UC_X86_REG_CR10 = 60 + UC_X86_REG_CR11 = 61 + UC_X86_REG_CR12 = 62 + UC_X86_REG_CR13 = 63 + UC_X86_REG_CR14 = 64 + UC_X86_REG_CR15 = 65 + UC_X86_REG_DR0 = 66 + UC_X86_REG_DR1 = 67 + UC_X86_REG_DR2 = 68 + UC_X86_REG_DR3 = 69 + UC_X86_REG_DR4 = 70 + UC_X86_REG_DR5 = 71 + UC_X86_REG_DR6 = 72 + UC_X86_REG_DR7 = 73 + UC_X86_REG_DR8 = 74 + UC_X86_REG_DR9 = 75 + UC_X86_REG_DR10 = 76 + UC_X86_REG_DR11 = 77 + UC_X86_REG_DR12 = 78 + UC_X86_REG_DR13 = 79 + UC_X86_REG_DR14 = 80 + UC_X86_REG_DR15 = 81 + UC_X86_REG_FP0 = 82 + UC_X86_REG_FP1 = 83 + UC_X86_REG_FP2 = 84 + UC_X86_REG_FP3 = 85 + UC_X86_REG_FP4 = 86 + UC_X86_REG_FP5 = 87 + UC_X86_REG_FP6 = 88 + UC_X86_REG_FP7 = 89 + UC_X86_REG_K0 = 90 + UC_X86_REG_K1 = 91 + UC_X86_REG_K2 = 92 + UC_X86_REG_K3 = 93 + UC_X86_REG_K4 = 94 + UC_X86_REG_K5 = 95 + UC_X86_REG_K6 = 96 + UC_X86_REG_K7 = 97 + UC_X86_REG_MM0 = 98 + UC_X86_REG_MM1 = 99 + UC_X86_REG_MM2 = 100 + UC_X86_REG_MM3 = 101 + UC_X86_REG_MM4 = 102 + UC_X86_REG_MM5 = 103 + UC_X86_REG_MM6 = 104 + UC_X86_REG_MM7 = 105 + UC_X86_REG_R8 = 106 + UC_X86_REG_R9 = 107 + UC_X86_REG_R10 = 108 + UC_X86_REG_R11 = 109 + UC_X86_REG_R12 = 110 + UC_X86_REG_R13 = 111 + UC_X86_REG_R14 = 112 + UC_X86_REG_R15 = 113 + UC_X86_REG_ST0 = 114 + UC_X86_REG_ST1 = 115 + UC_X86_REG_ST2 = 116 + UC_X86_REG_ST3 = 117 + UC_X86_REG_ST4 = 118 + UC_X86_REG_ST5 = 119 + UC_X86_REG_ST6 = 120 + UC_X86_REG_ST7 = 121 + UC_X86_REG_XMM0 = 122 + UC_X86_REG_XMM1 = 123 + UC_X86_REG_XMM2 = 124 + UC_X86_REG_XMM3 = 125 + UC_X86_REG_XMM4 = 126 + UC_X86_REG_XMM5 = 127 + UC_X86_REG_XMM6 = 128 + UC_X86_REG_XMM7 = 129 + UC_X86_REG_XMM8 = 130 + UC_X86_REG_XMM9 = 131 + UC_X86_REG_XMM10 = 132 + UC_X86_REG_XMM11 = 133 + UC_X86_REG_XMM12 = 134 + UC_X86_REG_XMM13 = 135 + UC_X86_REG_XMM14 = 136 + UC_X86_REG_XMM15 = 137 + UC_X86_REG_XMM16 = 138 + UC_X86_REG_XMM17 = 139 + UC_X86_REG_XMM18 = 140 + UC_X86_REG_XMM19 = 141 + UC_X86_REG_XMM20 = 142 + UC_X86_REG_XMM21 = 143 + UC_X86_REG_XMM22 = 144 + UC_X86_REG_XMM23 = 145 + UC_X86_REG_XMM24 = 146 + UC_X86_REG_XMM25 = 147 + UC_X86_REG_XMM26 = 148 + UC_X86_REG_XMM27 = 149 + UC_X86_REG_XMM28 = 150 + UC_X86_REG_XMM29 = 151 + UC_X86_REG_XMM30 = 152 + UC_X86_REG_XMM31 = 153 + UC_X86_REG_YMM0 = 154 + UC_X86_REG_YMM1 = 155 + UC_X86_REG_YMM2 = 156 + UC_X86_REG_YMM3 = 157 + UC_X86_REG_YMM4 = 158 + UC_X86_REG_YMM5 = 159 + UC_X86_REG_YMM6 = 160 + UC_X86_REG_YMM7 = 161 + UC_X86_REG_YMM8 = 162 + UC_X86_REG_YMM9 = 163 + UC_X86_REG_YMM10 = 164 + UC_X86_REG_YMM11 = 165 + UC_X86_REG_YMM12 = 166 + UC_X86_REG_YMM13 = 167 + UC_X86_REG_YMM14 = 168 + UC_X86_REG_YMM15 = 169 + UC_X86_REG_YMM16 = 170 + UC_X86_REG_YMM17 = 171 + UC_X86_REG_YMM18 = 172 + UC_X86_REG_YMM19 = 173 + UC_X86_REG_YMM20 = 174 + UC_X86_REG_YMM21 = 175 + UC_X86_REG_YMM22 = 176 + UC_X86_REG_YMM23 = 177 + UC_X86_REG_YMM24 = 178 + UC_X86_REG_YMM25 = 179 + UC_X86_REG_YMM26 = 180 + UC_X86_REG_YMM27 = 181 + UC_X86_REG_YMM28 = 182 + UC_X86_REG_YMM29 = 183 + UC_X86_REG_YMM30 = 184 + UC_X86_REG_YMM31 = 185 + UC_X86_REG_ZMM0 = 186 + UC_X86_REG_ZMM1 = 187 + UC_X86_REG_ZMM2 = 188 + UC_X86_REG_ZMM3 = 189 + UC_X86_REG_ZMM4 = 190 + UC_X86_REG_ZMM5 = 191 + UC_X86_REG_ZMM6 = 192 + UC_X86_REG_ZMM7 = 193 + UC_X86_REG_ZMM8 = 194 + UC_X86_REG_ZMM9 = 195 + UC_X86_REG_ZMM10 = 196 + UC_X86_REG_ZMM11 = 197 + UC_X86_REG_ZMM12 = 198 + UC_X86_REG_ZMM13 = 199 + UC_X86_REG_ZMM14 = 200 + UC_X86_REG_ZMM15 = 201 + UC_X86_REG_ZMM16 = 202 + UC_X86_REG_ZMM17 = 203 + UC_X86_REG_ZMM18 = 204 + UC_X86_REG_ZMM19 = 205 + UC_X86_REG_ZMM20 = 206 + UC_X86_REG_ZMM21 = 207 + UC_X86_REG_ZMM22 = 208 + UC_X86_REG_ZMM23 = 209 + UC_X86_REG_ZMM24 = 210 + UC_X86_REG_ZMM25 = 211 + UC_X86_REG_ZMM26 = 212 + UC_X86_REG_ZMM27 = 213 + UC_X86_REG_ZMM28 = 214 + UC_X86_REG_ZMM29 = 215 + UC_X86_REG_ZMM30 = 216 + UC_X86_REG_ZMM31 = 217 + UC_X86_REG_R8B = 218 + UC_X86_REG_R9B = 219 + UC_X86_REG_R10B = 220 + UC_X86_REG_R11B = 221 + UC_X86_REG_R12B = 222 + UC_X86_REG_R13B = 223 + UC_X86_REG_R14B = 224 + UC_X86_REG_R15B = 225 + UC_X86_REG_R8D = 226 + UC_X86_REG_R9D = 227 + UC_X86_REG_R10D = 228 + UC_X86_REG_R11D = 229 + UC_X86_REG_R12D = 230 + UC_X86_REG_R13D = 231 + UC_X86_REG_R14D = 232 + UC_X86_REG_R15D = 233 + UC_X86_REG_R8W = 234 + UC_X86_REG_R9W = 235 + UC_X86_REG_R10W = 236 + UC_X86_REG_R11W = 237 + UC_X86_REG_R12W = 238 + UC_X86_REG_R13W = 239 + UC_X86_REG_R14W = 240 + UC_X86_REG_R15W = 241 + 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 + + UC_X86_INS_INVALID = 0 + UC_X86_INS_AAA = 1 + UC_X86_INS_AAD = 2 + UC_X86_INS_AAM = 3 + UC_X86_INS_AAS = 4 + UC_X86_INS_FABS = 5 + UC_X86_INS_ADC = 6 + UC_X86_INS_ADCX = 7 + UC_X86_INS_ADD = 8 + UC_X86_INS_ADDPD = 9 + UC_X86_INS_ADDPS = 10 + UC_X86_INS_ADDSD = 11 + UC_X86_INS_ADDSS = 12 + UC_X86_INS_ADDSUBPD = 13 + UC_X86_INS_ADDSUBPS = 14 + UC_X86_INS_FADD = 15 + UC_X86_INS_FIADD = 16 + UC_X86_INS_FADDP = 17 + UC_X86_INS_ADOX = 18 + UC_X86_INS_AESDECLAST = 19 + UC_X86_INS_AESDEC = 20 + UC_X86_INS_AESENCLAST = 21 + UC_X86_INS_AESENC = 22 + UC_X86_INS_AESIMC = 23 + UC_X86_INS_AESKEYGENASSIST = 24 + UC_X86_INS_AND = 25 + UC_X86_INS_ANDN = 26 + UC_X86_INS_ANDNPD = 27 + UC_X86_INS_ANDNPS = 28 + UC_X86_INS_ANDPD = 29 + UC_X86_INS_ANDPS = 30 + UC_X86_INS_ARPL = 31 + UC_X86_INS_BEXTR = 32 + UC_X86_INS_BLCFILL = 33 + UC_X86_INS_BLCI = 34 + UC_X86_INS_BLCIC = 35 + UC_X86_INS_BLCMSK = 36 + UC_X86_INS_BLCS = 37 + UC_X86_INS_BLENDPD = 38 + UC_X86_INS_BLENDPS = 39 + UC_X86_INS_BLENDVPD = 40 + UC_X86_INS_BLENDVPS = 41 + UC_X86_INS_BLSFILL = 42 + UC_X86_INS_BLSI = 43 + UC_X86_INS_BLSIC = 44 + UC_X86_INS_BLSMSK = 45 + UC_X86_INS_BLSR = 46 + UC_X86_INS_BOUND = 47 + UC_X86_INS_BSF = 48 + UC_X86_INS_BSR = 49 + UC_X86_INS_BSWAP = 50 + UC_X86_INS_BT = 51 + UC_X86_INS_BTC = 52 + UC_X86_INS_BTR = 53 + UC_X86_INS_BTS = 54 + UC_X86_INS_BZHI = 55 + UC_X86_INS_CALL = 56 + UC_X86_INS_CBW = 57 + UC_X86_INS_CDQ = 58 + UC_X86_INS_CDQE = 59 + UC_X86_INS_FCHS = 60 + UC_X86_INS_CLAC = 61 + UC_X86_INS_CLC = 62 + UC_X86_INS_CLD = 63 + UC_X86_INS_CLFLUSH = 64 + UC_X86_INS_CLFLUSHOPT = 65 + UC_X86_INS_CLGI = 66 + UC_X86_INS_CLI = 67 + UC_X86_INS_CLTS = 68 + UC_X86_INS_CLWB = 69 + UC_X86_INS_CMC = 70 + UC_X86_INS_CMOVA = 71 + UC_X86_INS_CMOVAE = 72 + UC_X86_INS_CMOVB = 73 + UC_X86_INS_CMOVBE = 74 + UC_X86_INS_FCMOVBE = 75 + UC_X86_INS_FCMOVB = 76 + UC_X86_INS_CMOVE = 77 + UC_X86_INS_FCMOVE = 78 + UC_X86_INS_CMOVG = 79 + UC_X86_INS_CMOVGE = 80 + UC_X86_INS_CMOVL = 81 + UC_X86_INS_CMOVLE = 82 + UC_X86_INS_FCMOVNBE = 83 + UC_X86_INS_FCMOVNB = 84 + UC_X86_INS_CMOVNE = 85 + UC_X86_INS_FCMOVNE = 86 + UC_X86_INS_CMOVNO = 87 + UC_X86_INS_CMOVNP = 88 + UC_X86_INS_FCMOVNU = 89 + UC_X86_INS_CMOVNS = 90 + UC_X86_INS_CMOVO = 91 + UC_X86_INS_CMOVP = 92 + UC_X86_INS_FCMOVU = 93 + UC_X86_INS_CMOVS = 94 + UC_X86_INS_CMP = 95 + UC_X86_INS_CMPPD = 96 + UC_X86_INS_CMPPS = 97 + UC_X86_INS_CMPSB = 98 + UC_X86_INS_CMPSD = 99 + UC_X86_INS_CMPSQ = 100 + UC_X86_INS_CMPSS = 101 + UC_X86_INS_CMPSW = 102 + UC_X86_INS_CMPXCHG16B = 103 + UC_X86_INS_CMPXCHG = 104 + UC_X86_INS_CMPXCHG8B = 105 + UC_X86_INS_COMISD = 106 + UC_X86_INS_COMISS = 107 + UC_X86_INS_FCOMP = 108 + UC_X86_INS_FCOMPI = 109 + UC_X86_INS_FCOMI = 110 + UC_X86_INS_FCOM = 111 + UC_X86_INS_FCOS = 112 + UC_X86_INS_CPUID = 113 + UC_X86_INS_CQO = 114 + UC_X86_INS_CRC32 = 115 + UC_X86_INS_CVTDQ2PD = 116 + UC_X86_INS_CVTDQ2PS = 117 + UC_X86_INS_CVTPD2DQ = 118 + UC_X86_INS_CVTPD2PS = 119 + UC_X86_INS_CVTPS2DQ = 120 + UC_X86_INS_CVTPS2PD = 121 + UC_X86_INS_CVTSD2SI = 122 + UC_X86_INS_CVTSD2SS = 123 + UC_X86_INS_CVTSI2SD = 124 + UC_X86_INS_CVTSI2SS = 125 + UC_X86_INS_CVTSS2SD = 126 + UC_X86_INS_CVTSS2SI = 127 + UC_X86_INS_CVTTPD2DQ = 128 + UC_X86_INS_CVTTPS2DQ = 129 + UC_X86_INS_CVTTSD2SI = 130 + UC_X86_INS_CVTTSS2SI = 131 + UC_X86_INS_CWD = 132 + UC_X86_INS_CWDE = 133 + UC_X86_INS_DAA = 134 + UC_X86_INS_DAS = 135 + UC_X86_INS_DATA16 = 136 + UC_X86_INS_DEC = 137 + UC_X86_INS_DIV = 138 + UC_X86_INS_DIVPD = 139 + UC_X86_INS_DIVPS = 140 + UC_X86_INS_FDIVR = 141 + UC_X86_INS_FIDIVR = 142 + UC_X86_INS_FDIVRP = 143 + UC_X86_INS_DIVSD = 144 + UC_X86_INS_DIVSS = 145 + UC_X86_INS_FDIV = 146 + UC_X86_INS_FIDIV = 147 + UC_X86_INS_FDIVP = 148 + UC_X86_INS_DPPD = 149 + UC_X86_INS_DPPS = 150 + UC_X86_INS_RET = 151 + UC_X86_INS_ENCLS = 152 + UC_X86_INS_ENCLU = 153 + UC_X86_INS_ENTER = 154 + UC_X86_INS_EXTRACTPS = 155 + UC_X86_INS_EXTRQ = 156 + UC_X86_INS_F2XM1 = 157 + UC_X86_INS_LCALL = 158 + UC_X86_INS_LJMP = 159 + UC_X86_INS_FBLD = 160 + UC_X86_INS_FBSTP = 161 + UC_X86_INS_FCOMPP = 162 + UC_X86_INS_FDECSTP = 163 + UC_X86_INS_FEMMS = 164 + UC_X86_INS_FFREE = 165 + UC_X86_INS_FICOM = 166 + UC_X86_INS_FICOMP = 167 + UC_X86_INS_FINCSTP = 168 + UC_X86_INS_FLDCW = 169 + UC_X86_INS_FLDENV = 170 + UC_X86_INS_FLDL2E = 171 + UC_X86_INS_FLDL2T = 172 + UC_X86_INS_FLDLG2 = 173 + UC_X86_INS_FLDLN2 = 174 + UC_X86_INS_FLDPI = 175 + UC_X86_INS_FNCLEX = 176 + UC_X86_INS_FNINIT = 177 + UC_X86_INS_FNOP = 178 + UC_X86_INS_FNSTCW = 179 + UC_X86_INS_FNSTSW = 180 + UC_X86_INS_FPATAN = 181 + UC_X86_INS_FPREM = 182 + UC_X86_INS_FPREM1 = 183 + UC_X86_INS_FPTAN = 184 + UC_X86_INS_FFREEP = 185 + UC_X86_INS_FRNDINT = 186 + UC_X86_INS_FRSTOR = 187 + UC_X86_INS_FNSAVE = 188 + UC_X86_INS_FSCALE = 189 + UC_X86_INS_FSETPM = 190 + UC_X86_INS_FSINCOS = 191 + UC_X86_INS_FNSTENV = 192 + UC_X86_INS_FXAM = 193 + UC_X86_INS_FXRSTOR = 194 + UC_X86_INS_FXRSTOR64 = 195 + UC_X86_INS_FXSAVE = 196 + UC_X86_INS_FXSAVE64 = 197 + UC_X86_INS_FXTRACT = 198 + UC_X86_INS_FYL2X = 199 + UC_X86_INS_FYL2XP1 = 200 + UC_X86_INS_MOVAPD = 201 + UC_X86_INS_MOVAPS = 202 + UC_X86_INS_ORPD = 203 + UC_X86_INS_ORPS = 204 + UC_X86_INS_VMOVAPD = 205 + UC_X86_INS_VMOVAPS = 206 + UC_X86_INS_XORPD = 207 + UC_X86_INS_XORPS = 208 + UC_X86_INS_GETSEC = 209 + UC_X86_INS_HADDPD = 210 + UC_X86_INS_HADDPS = 211 + UC_X86_INS_HLT = 212 + UC_X86_INS_HSUBPD = 213 + UC_X86_INS_HSUBPS = 214 + UC_X86_INS_IDIV = 215 + UC_X86_INS_FILD = 216 + UC_X86_INS_IMUL = 217 + UC_X86_INS_IN = 218 + UC_X86_INS_INC = 219 + UC_X86_INS_INSB = 220 + UC_X86_INS_INSERTPS = 221 + UC_X86_INS_INSERTQ = 222 + UC_X86_INS_INSD = 223 + UC_X86_INS_INSW = 224 + UC_X86_INS_INT = 225 + UC_X86_INS_INT1 = 226 + UC_X86_INS_INT3 = 227 + UC_X86_INS_INTO = 228 + UC_X86_INS_INVD = 229 + UC_X86_INS_INVEPT = 230 + UC_X86_INS_INVLPG = 231 + UC_X86_INS_INVLPGA = 232 + UC_X86_INS_INVPCID = 233 + UC_X86_INS_INVVPID = 234 + UC_X86_INS_IRET = 235 + UC_X86_INS_IRETD = 236 + UC_X86_INS_IRETQ = 237 + UC_X86_INS_FISTTP = 238 + UC_X86_INS_FIST = 239 + UC_X86_INS_FISTP = 240 + UC_X86_INS_UCOMISD = 241 + UC_X86_INS_UCOMISS = 242 + UC_X86_INS_VCOMISD = 243 + UC_X86_INS_VCOMISS = 244 + UC_X86_INS_VCVTSD2SS = 245 + UC_X86_INS_VCVTSI2SD = 246 + UC_X86_INS_VCVTSI2SS = 247 + UC_X86_INS_VCVTSS2SD = 248 + UC_X86_INS_VCVTTSD2SI = 249 + UC_X86_INS_VCVTTSD2USI = 250 + UC_X86_INS_VCVTTSS2SI = 251 + UC_X86_INS_VCVTTSS2USI = 252 + UC_X86_INS_VCVTUSI2SD = 253 + UC_X86_INS_VCVTUSI2SS = 254 + UC_X86_INS_VUCOMISD = 255 + UC_X86_INS_VUCOMISS = 256 + UC_X86_INS_JAE = 257 + UC_X86_INS_JA = 258 + UC_X86_INS_JBE = 259 + UC_X86_INS_JB = 260 + UC_X86_INS_JCXZ = 261 + UC_X86_INS_JECXZ = 262 + UC_X86_INS_JE = 263 + UC_X86_INS_JGE = 264 + UC_X86_INS_JG = 265 + UC_X86_INS_JLE = 266 + UC_X86_INS_JL = 267 + UC_X86_INS_JMP = 268 + UC_X86_INS_JNE = 269 + UC_X86_INS_JNO = 270 + UC_X86_INS_JNP = 271 + UC_X86_INS_JNS = 272 + UC_X86_INS_JO = 273 + UC_X86_INS_JP = 274 + UC_X86_INS_JRCXZ = 275 + UC_X86_INS_JS = 276 + UC_X86_INS_KANDB = 277 + UC_X86_INS_KANDD = 278 + UC_X86_INS_KANDNB = 279 + UC_X86_INS_KANDND = 280 + UC_X86_INS_KANDNQ = 281 + UC_X86_INS_KANDNW = 282 + UC_X86_INS_KANDQ = 283 + UC_X86_INS_KANDW = 284 + UC_X86_INS_KMOVB = 285 + UC_X86_INS_KMOVD = 286 + UC_X86_INS_KMOVQ = 287 + UC_X86_INS_KMOVW = 288 + UC_X86_INS_KNOTB = 289 + UC_X86_INS_KNOTD = 290 + UC_X86_INS_KNOTQ = 291 + UC_X86_INS_KNOTW = 292 + UC_X86_INS_KORB = 293 + UC_X86_INS_KORD = 294 + UC_X86_INS_KORQ = 295 + UC_X86_INS_KORTESTB = 296 + UC_X86_INS_KORTESTD = 297 + UC_X86_INS_KORTESTQ = 298 + UC_X86_INS_KORTESTW = 299 + UC_X86_INS_KORW = 300 + UC_X86_INS_KSHIFTLB = 301 + UC_X86_INS_KSHIFTLD = 302 + UC_X86_INS_KSHIFTLQ = 303 + UC_X86_INS_KSHIFTLW = 304 + UC_X86_INS_KSHIFTRB = 305 + UC_X86_INS_KSHIFTRD = 306 + UC_X86_INS_KSHIFTRQ = 307 + UC_X86_INS_KSHIFTRW = 308 + UC_X86_INS_KUNPCKBW = 309 + UC_X86_INS_KXNORB = 310 + UC_X86_INS_KXNORD = 311 + UC_X86_INS_KXNORQ = 312 + UC_X86_INS_KXNORW = 313 + UC_X86_INS_KXORB = 314 + UC_X86_INS_KXORD = 315 + UC_X86_INS_KXORQ = 316 + UC_X86_INS_KXORW = 317 + UC_X86_INS_LAHF = 318 + UC_X86_INS_LAR = 319 + UC_X86_INS_LDDQU = 320 + UC_X86_INS_LDMXCSR = 321 + UC_X86_INS_LDS = 322 + UC_X86_INS_FLDZ = 323 + UC_X86_INS_FLD1 = 324 + UC_X86_INS_FLD = 325 + UC_X86_INS_LEA = 326 + UC_X86_INS_LEAVE = 327 + UC_X86_INS_LES = 328 + UC_X86_INS_LFENCE = 329 + UC_X86_INS_LFS = 330 + UC_X86_INS_LGDT = 331 + UC_X86_INS_LGS = 332 + UC_X86_INS_LIDT = 333 + UC_X86_INS_LLDT = 334 + UC_X86_INS_LMSW = 335 + UC_X86_INS_OR = 336 + UC_X86_INS_SUB = 337 + UC_X86_INS_XOR = 338 + UC_X86_INS_LODSB = 339 + UC_X86_INS_LODSD = 340 + UC_X86_INS_LODSQ = 341 + UC_X86_INS_LODSW = 342 + UC_X86_INS_LOOP = 343 + UC_X86_INS_LOOPE = 344 + UC_X86_INS_LOOPNE = 345 + UC_X86_INS_RETF = 346 + UC_X86_INS_RETFQ = 347 + UC_X86_INS_LSL = 348 + UC_X86_INS_LSS = 349 + UC_X86_INS_LTR = 350 + UC_X86_INS_XADD = 351 + UC_X86_INS_LZCNT = 352 + UC_X86_INS_MASKMOVDQU = 353 + UC_X86_INS_MAXPD = 354 + UC_X86_INS_MAXPS = 355 + UC_X86_INS_MAXSD = 356 + UC_X86_INS_MAXSS = 357 + UC_X86_INS_MFENCE = 358 + UC_X86_INS_MINPD = 359 + UC_X86_INS_MINPS = 360 + UC_X86_INS_MINSD = 361 + UC_X86_INS_MINSS = 362 + UC_X86_INS_CVTPD2PI = 363 + UC_X86_INS_CVTPI2PD = 364 + UC_X86_INS_CVTPI2PS = 365 + UC_X86_INS_CVTPS2PI = 366 + UC_X86_INS_CVTTPD2PI = 367 + UC_X86_INS_CVTTPS2PI = 368 + UC_X86_INS_EMMS = 369 + UC_X86_INS_MASKMOVQ = 370 + UC_X86_INS_MOVD = 371 + UC_X86_INS_MOVDQ2Q = 372 + UC_X86_INS_MOVNTQ = 373 + UC_X86_INS_MOVQ2DQ = 374 + UC_X86_INS_MOVQ = 375 + UC_X86_INS_PABSB = 376 + UC_X86_INS_PABSD = 377 + UC_X86_INS_PABSW = 378 + UC_X86_INS_PACKSSDW = 379 + UC_X86_INS_PACKSSWB = 380 + UC_X86_INS_PACKUSWB = 381 + UC_X86_INS_PADDB = 382 + UC_X86_INS_PADDD = 383 + UC_X86_INS_PADDQ = 384 + UC_X86_INS_PADDSB = 385 + UC_X86_INS_PADDSW = 386 + UC_X86_INS_PADDUSB = 387 + UC_X86_INS_PADDUSW = 388 + UC_X86_INS_PADDW = 389 + UC_X86_INS_PALIGNR = 390 + UC_X86_INS_PANDN = 391 + UC_X86_INS_PAND = 392 + UC_X86_INS_PAVGB = 393 + UC_X86_INS_PAVGW = 394 + UC_X86_INS_PCMPEQB = 395 + UC_X86_INS_PCMPEQD = 396 + UC_X86_INS_PCMPEQW = 397 + UC_X86_INS_PCMPGTB = 398 + UC_X86_INS_PCMPGTD = 399 + UC_X86_INS_PCMPGTW = 400 + UC_X86_INS_PEXTRW = 401 + UC_X86_INS_PHADDSW = 402 + UC_X86_INS_PHADDW = 403 + UC_X86_INS_PHADDD = 404 + UC_X86_INS_PHSUBD = 405 + UC_X86_INS_PHSUBSW = 406 + UC_X86_INS_PHSUBW = 407 + UC_X86_INS_PINSRW = 408 + UC_X86_INS_PMADDUBSW = 409 + UC_X86_INS_PMADDWD = 410 + UC_X86_INS_PMAXSW = 411 + UC_X86_INS_PMAXUB = 412 + UC_X86_INS_PMINSW = 413 + UC_X86_INS_PMINUB = 414 + UC_X86_INS_PMOVMSKB = 415 + UC_X86_INS_PMULHRSW = 416 + UC_X86_INS_PMULHUW = 417 + UC_X86_INS_PMULHW = 418 + UC_X86_INS_PMULLW = 419 + UC_X86_INS_PMULUDQ = 420 + UC_X86_INS_POR = 421 + UC_X86_INS_PSADBW = 422 + UC_X86_INS_PSHUFB = 423 + UC_X86_INS_PSHUFW = 424 + UC_X86_INS_PSIGNB = 425 + UC_X86_INS_PSIGND = 426 + UC_X86_INS_PSIGNW = 427 + UC_X86_INS_PSLLD = 428 + UC_X86_INS_PSLLQ = 429 + UC_X86_INS_PSLLW = 430 + UC_X86_INS_PSRAD = 431 + UC_X86_INS_PSRAW = 432 + UC_X86_INS_PSRLD = 433 + UC_X86_INS_PSRLQ = 434 + UC_X86_INS_PSRLW = 435 + UC_X86_INS_PSUBB = 436 + UC_X86_INS_PSUBD = 437 + UC_X86_INS_PSUBQ = 438 + UC_X86_INS_PSUBSB = 439 + UC_X86_INS_PSUBSW = 440 + UC_X86_INS_PSUBUSB = 441 + UC_X86_INS_PSUBUSW = 442 + UC_X86_INS_PSUBW = 443 + UC_X86_INS_PUNPCKHBW = 444 + UC_X86_INS_PUNPCKHDQ = 445 + UC_X86_INS_PUNPCKHWD = 446 + UC_X86_INS_PUNPCKLBW = 447 + UC_X86_INS_PUNPCKLDQ = 448 + UC_X86_INS_PUNPCKLWD = 449 + UC_X86_INS_PXOR = 450 + UC_X86_INS_MONITOR = 451 + UC_X86_INS_MONTMUL = 452 + UC_X86_INS_MOV = 453 + UC_X86_INS_MOVABS = 454 + UC_X86_INS_MOVBE = 455 + UC_X86_INS_MOVDDUP = 456 + UC_X86_INS_MOVDQA = 457 + UC_X86_INS_MOVDQU = 458 + UC_X86_INS_MOVHLPS = 459 + UC_X86_INS_MOVHPD = 460 + UC_X86_INS_MOVHPS = 461 + UC_X86_INS_MOVLHPS = 462 + UC_X86_INS_MOVLPD = 463 + UC_X86_INS_MOVLPS = 464 + UC_X86_INS_MOVMSKPD = 465 + UC_X86_INS_MOVMSKPS = 466 + UC_X86_INS_MOVNTDQA = 467 + UC_X86_INS_MOVNTDQ = 468 + UC_X86_INS_MOVNTI = 469 + UC_X86_INS_MOVNTPD = 470 + UC_X86_INS_MOVNTPS = 471 + UC_X86_INS_MOVNTSD = 472 + UC_X86_INS_MOVNTSS = 473 + UC_X86_INS_MOVSB = 474 + UC_X86_INS_MOVSD = 475 + UC_X86_INS_MOVSHDUP = 476 + UC_X86_INS_MOVSLDUP = 477 + UC_X86_INS_MOVSQ = 478 + UC_X86_INS_MOVSS = 479 + UC_X86_INS_MOVSW = 480 + UC_X86_INS_MOVSX = 481 + UC_X86_INS_MOVSXD = 482 + UC_X86_INS_MOVUPD = 483 + UC_X86_INS_MOVUPS = 484 + UC_X86_INS_MOVZX = 485 + UC_X86_INS_MPSADBW = 486 + UC_X86_INS_MUL = 487 + UC_X86_INS_MULPD = 488 + UC_X86_INS_MULPS = 489 + UC_X86_INS_MULSD = 490 + UC_X86_INS_MULSS = 491 + UC_X86_INS_MULX = 492 + UC_X86_INS_FMUL = 493 + UC_X86_INS_FIMUL = 494 + UC_X86_INS_FMULP = 495 + UC_X86_INS_MWAIT = 496 + UC_X86_INS_NEG = 497 + UC_X86_INS_NOP = 498 + UC_X86_INS_NOT = 499 + UC_X86_INS_OUT = 500 + UC_X86_INS_OUTSB = 501 + UC_X86_INS_OUTSD = 502 + UC_X86_INS_OUTSW = 503 + UC_X86_INS_PACKUSDW = 504 + UC_X86_INS_PAUSE = 505 + UC_X86_INS_PAVGUSB = 506 + UC_X86_INS_PBLENDVB = 507 + UC_X86_INS_PBLENDW = 508 + UC_X86_INS_PCLMULQDQ = 509 + UC_X86_INS_PCMPEQQ = 510 + UC_X86_INS_PCMPESTRI = 511 + UC_X86_INS_PCMPESTRM = 512 + UC_X86_INS_PCMPGTQ = 513 + UC_X86_INS_PCMPISTRI = 514 + UC_X86_INS_PCMPISTRM = 515 + UC_X86_INS_PCOMMIT = 516 + UC_X86_INS_PDEP = 517 + UC_X86_INS_PEXT = 518 + UC_X86_INS_PEXTRB = 519 + UC_X86_INS_PEXTRD = 520 + UC_X86_INS_PEXTRQ = 521 + UC_X86_INS_PF2ID = 522 + UC_X86_INS_PF2IW = 523 + UC_X86_INS_PFACC = 524 + UC_X86_INS_PFADD = 525 + UC_X86_INS_PFCMPEQ = 526 + UC_X86_INS_PFCMPGE = 527 + UC_X86_INS_PFCMPGT = 528 + UC_X86_INS_PFMAX = 529 + UC_X86_INS_PFMIN = 530 + UC_X86_INS_PFMUL = 531 + UC_X86_INS_PFNACC = 532 + UC_X86_INS_PFPNACC = 533 + UC_X86_INS_PFRCPIT1 = 534 + UC_X86_INS_PFRCPIT2 = 535 + UC_X86_INS_PFRCP = 536 + UC_X86_INS_PFRSQIT1 = 537 + UC_X86_INS_PFRSQRT = 538 + UC_X86_INS_PFSUBR = 539 + UC_X86_INS_PFSUB = 540 + UC_X86_INS_PHMINPOSUW = 541 + UC_X86_INS_PI2FD = 542 + UC_X86_INS_PI2FW = 543 + UC_X86_INS_PINSRB = 544 + UC_X86_INS_PINSRD = 545 + UC_X86_INS_PINSRQ = 546 + UC_X86_INS_PMAXSB = 547 + UC_X86_INS_PMAXSD = 548 + UC_X86_INS_PMAXUD = 549 + UC_X86_INS_PMAXUW = 550 + UC_X86_INS_PMINSB = 551 + UC_X86_INS_PMINSD = 552 + UC_X86_INS_PMINUD = 553 + UC_X86_INS_PMINUW = 554 + UC_X86_INS_PMOVSXBD = 555 + UC_X86_INS_PMOVSXBQ = 556 + UC_X86_INS_PMOVSXBW = 557 + UC_X86_INS_PMOVSXDQ = 558 + UC_X86_INS_PMOVSXWD = 559 + UC_X86_INS_PMOVSXWQ = 560 + UC_X86_INS_PMOVZXBD = 561 + UC_X86_INS_PMOVZXBQ = 562 + UC_X86_INS_PMOVZXBW = 563 + UC_X86_INS_PMOVZXDQ = 564 + UC_X86_INS_PMOVZXWD = 565 + UC_X86_INS_PMOVZXWQ = 566 + UC_X86_INS_PMULDQ = 567 + UC_X86_INS_PMULHRW = 568 + UC_X86_INS_PMULLD = 569 + UC_X86_INS_POP = 570 + UC_X86_INS_POPAW = 571 + UC_X86_INS_POPAL = 572 + UC_X86_INS_POPCNT = 573 + UC_X86_INS_POPF = 574 + UC_X86_INS_POPFD = 575 + UC_X86_INS_POPFQ = 576 + UC_X86_INS_PREFETCH = 577 + UC_X86_INS_PREFETCHNTA = 578 + UC_X86_INS_PREFETCHT0 = 579 + UC_X86_INS_PREFETCHT1 = 580 + UC_X86_INS_PREFETCHT2 = 581 + UC_X86_INS_PREFETCHW = 582 + UC_X86_INS_PSHUFD = 583 + UC_X86_INS_PSHUFHW = 584 + UC_X86_INS_PSHUFLW = 585 + UC_X86_INS_PSLLDQ = 586 + UC_X86_INS_PSRLDQ = 587 + UC_X86_INS_PSWAPD = 588 + UC_X86_INS_PTEST = 589 + UC_X86_INS_PUNPCKHQDQ = 590 + UC_X86_INS_PUNPCKLQDQ = 591 + UC_X86_INS_PUSH = 592 + UC_X86_INS_PUSHAW = 593 + UC_X86_INS_PUSHAL = 594 + UC_X86_INS_PUSHF = 595 + UC_X86_INS_PUSHFD = 596 + UC_X86_INS_PUSHFQ = 597 + UC_X86_INS_RCL = 598 + UC_X86_INS_RCPPS = 599 + UC_X86_INS_RCPSS = 600 + UC_X86_INS_RCR = 601 + UC_X86_INS_RDFSBASE = 602 + UC_X86_INS_RDGSBASE = 603 + UC_X86_INS_RDMSR = 604 + UC_X86_INS_RDPMC = 605 + UC_X86_INS_RDRAND = 606 + UC_X86_INS_RDSEED = 607 + UC_X86_INS_RDTSC = 608 + UC_X86_INS_RDTSCP = 609 + UC_X86_INS_ROL = 610 + UC_X86_INS_ROR = 611 + UC_X86_INS_RORX = 612 + UC_X86_INS_ROUNDPD = 613 + UC_X86_INS_ROUNDPS = 614 + UC_X86_INS_ROUNDSD = 615 + UC_X86_INS_ROUNDSS = 616 + UC_X86_INS_RSM = 617 + UC_X86_INS_RSQRTPS = 618 + UC_X86_INS_RSQRTSS = 619 + UC_X86_INS_SAHF = 620 + UC_X86_INS_SAL = 621 + UC_X86_INS_SALC = 622 + UC_X86_INS_SAR = 623 + UC_X86_INS_SARX = 624 + UC_X86_INS_SBB = 625 + UC_X86_INS_SCASB = 626 + UC_X86_INS_SCASD = 627 + UC_X86_INS_SCASQ = 628 + UC_X86_INS_SCASW = 629 + UC_X86_INS_SETAE = 630 + UC_X86_INS_SETA = 631 + UC_X86_INS_SETBE = 632 + UC_X86_INS_SETB = 633 + UC_X86_INS_SETE = 634 + UC_X86_INS_SETGE = 635 + UC_X86_INS_SETG = 636 + UC_X86_INS_SETLE = 637 + UC_X86_INS_SETL = 638 + UC_X86_INS_SETNE = 639 + UC_X86_INS_SETNO = 640 + UC_X86_INS_SETNP = 641 + UC_X86_INS_SETNS = 642 + UC_X86_INS_SETO = 643 + UC_X86_INS_SETP = 644 + UC_X86_INS_SETS = 645 + UC_X86_INS_SFENCE = 646 + UC_X86_INS_SGDT = 647 + UC_X86_INS_SHA1MSG1 = 648 + UC_X86_INS_SHA1MSG2 = 649 + UC_X86_INS_SHA1NEXTE = 650 + UC_X86_INS_SHA1RNDS4 = 651 + UC_X86_INS_SHA256MSG1 = 652 + UC_X86_INS_SHA256MSG2 = 653 + UC_X86_INS_SHA256RNDS2 = 654 + UC_X86_INS_SHL = 655 + UC_X86_INS_SHLD = 656 + UC_X86_INS_SHLX = 657 + UC_X86_INS_SHR = 658 + UC_X86_INS_SHRD = 659 + UC_X86_INS_SHRX = 660 + UC_X86_INS_SHUFPD = 661 + UC_X86_INS_SHUFPS = 662 + UC_X86_INS_SIDT = 663 + UC_X86_INS_FSIN = 664 + UC_X86_INS_SKINIT = 665 + UC_X86_INS_SLDT = 666 + UC_X86_INS_SMSW = 667 + UC_X86_INS_SQRTPD = 668 + UC_X86_INS_SQRTPS = 669 + UC_X86_INS_SQRTSD = 670 + UC_X86_INS_SQRTSS = 671 + UC_X86_INS_FSQRT = 672 + UC_X86_INS_STAC = 673 + UC_X86_INS_STC = 674 + UC_X86_INS_STD = 675 + UC_X86_INS_STGI = 676 + UC_X86_INS_STI = 677 + UC_X86_INS_STMXCSR = 678 + UC_X86_INS_STOSB = 679 + UC_X86_INS_STOSD = 680 + UC_X86_INS_STOSQ = 681 + UC_X86_INS_STOSW = 682 + UC_X86_INS_STR = 683 + UC_X86_INS_FST = 684 + UC_X86_INS_FSTP = 685 + UC_X86_INS_FSTPNCE = 686 + UC_X86_INS_FXCH = 687 + UC_X86_INS_SUBPD = 688 + UC_X86_INS_SUBPS = 689 + UC_X86_INS_FSUBR = 690 + UC_X86_INS_FISUBR = 691 + UC_X86_INS_FSUBRP = 692 + UC_X86_INS_SUBSD = 693 + UC_X86_INS_SUBSS = 694 + UC_X86_INS_FSUB = 695 + UC_X86_INS_FISUB = 696 + UC_X86_INS_FSUBP = 697 + UC_X86_INS_SWAPGS = 698 + UC_X86_INS_SYSCALL = 699 + UC_X86_INS_SYSENTER = 700 + UC_X86_INS_SYSEXIT = 701 + UC_X86_INS_SYSRET = 702 + UC_X86_INS_T1MSKC = 703 + UC_X86_INS_TEST = 704 + UC_X86_INS_UD2 = 705 + UC_X86_INS_FTST = 706 + UC_X86_INS_TZCNT = 707 + UC_X86_INS_TZMSK = 708 + UC_X86_INS_FUCOMPI = 709 + UC_X86_INS_FUCOMI = 710 + UC_X86_INS_FUCOMPP = 711 + UC_X86_INS_FUCOMP = 712 + UC_X86_INS_FUCOM = 713 + UC_X86_INS_UD2B = 714 + UC_X86_INS_UNPCKHPD = 715 + UC_X86_INS_UNPCKHPS = 716 + UC_X86_INS_UNPCKLPD = 717 + UC_X86_INS_UNPCKLPS = 718 + UC_X86_INS_VADDPD = 719 + UC_X86_INS_VADDPS = 720 + UC_X86_INS_VADDSD = 721 + UC_X86_INS_VADDSS = 722 + UC_X86_INS_VADDSUBPD = 723 + UC_X86_INS_VADDSUBPS = 724 + UC_X86_INS_VAESDECLAST = 725 + UC_X86_INS_VAESDEC = 726 + UC_X86_INS_VAESENCLAST = 727 + UC_X86_INS_VAESENC = 728 + UC_X86_INS_VAESIMC = 729 + UC_X86_INS_VAESKEYGENASSIST = 730 + UC_X86_INS_VALIGND = 731 + UC_X86_INS_VALIGNQ = 732 + UC_X86_INS_VANDNPD = 733 + UC_X86_INS_VANDNPS = 734 + UC_X86_INS_VANDPD = 735 + UC_X86_INS_VANDPS = 736 + UC_X86_INS_VBLENDMPD = 737 + UC_X86_INS_VBLENDMPS = 738 + UC_X86_INS_VBLENDPD = 739 + UC_X86_INS_VBLENDPS = 740 + UC_X86_INS_VBLENDVPD = 741 + UC_X86_INS_VBLENDVPS = 742 + UC_X86_INS_VBROADCASTF128 = 743 + UC_X86_INS_VBROADCASTI32X4 = 744 + UC_X86_INS_VBROADCASTI64X4 = 745 + UC_X86_INS_VBROADCASTSD = 746 + UC_X86_INS_VBROADCASTSS = 747 + UC_X86_INS_VCMPPD = 748 + UC_X86_INS_VCMPPS = 749 + UC_X86_INS_VCMPSD = 750 + UC_X86_INS_VCMPSS = 751 + UC_X86_INS_VCOMPRESSPD = 752 + UC_X86_INS_VCOMPRESSPS = 753 + UC_X86_INS_VCVTDQ2PD = 754 + UC_X86_INS_VCVTDQ2PS = 755 + UC_X86_INS_VCVTPD2DQX = 756 + UC_X86_INS_VCVTPD2DQ = 757 + UC_X86_INS_VCVTPD2PSX = 758 + UC_X86_INS_VCVTPD2PS = 759 + UC_X86_INS_VCVTPD2UDQ = 760 + UC_X86_INS_VCVTPH2PS = 761 + UC_X86_INS_VCVTPS2DQ = 762 + UC_X86_INS_VCVTPS2PD = 763 + UC_X86_INS_VCVTPS2PH = 764 + UC_X86_INS_VCVTPS2UDQ = 765 + UC_X86_INS_VCVTSD2SI = 766 + UC_X86_INS_VCVTSD2USI = 767 + UC_X86_INS_VCVTSS2SI = 768 + UC_X86_INS_VCVTSS2USI = 769 + UC_X86_INS_VCVTTPD2DQX = 770 + UC_X86_INS_VCVTTPD2DQ = 771 + UC_X86_INS_VCVTTPD2UDQ = 772 + UC_X86_INS_VCVTTPS2DQ = 773 + UC_X86_INS_VCVTTPS2UDQ = 774 + UC_X86_INS_VCVTUDQ2PD = 775 + UC_X86_INS_VCVTUDQ2PS = 776 + UC_X86_INS_VDIVPD = 777 + UC_X86_INS_VDIVPS = 778 + UC_X86_INS_VDIVSD = 779 + UC_X86_INS_VDIVSS = 780 + UC_X86_INS_VDPPD = 781 + UC_X86_INS_VDPPS = 782 + UC_X86_INS_VERR = 783 + UC_X86_INS_VERW = 784 + UC_X86_INS_VEXP2PD = 785 + UC_X86_INS_VEXP2PS = 786 + UC_X86_INS_VEXPANDPD = 787 + UC_X86_INS_VEXPANDPS = 788 + UC_X86_INS_VEXTRACTF128 = 789 + UC_X86_INS_VEXTRACTF32X4 = 790 + UC_X86_INS_VEXTRACTF64X4 = 791 + UC_X86_INS_VEXTRACTI128 = 792 + UC_X86_INS_VEXTRACTI32X4 = 793 + UC_X86_INS_VEXTRACTI64X4 = 794 + UC_X86_INS_VEXTRACTPS = 795 + UC_X86_INS_VFMADD132PD = 796 + UC_X86_INS_VFMADD132PS = 797 + UC_X86_INS_VFMADDPD = 798 + UC_X86_INS_VFMADD213PD = 799 + UC_X86_INS_VFMADD231PD = 800 + UC_X86_INS_VFMADDPS = 801 + UC_X86_INS_VFMADD213PS = 802 + UC_X86_INS_VFMADD231PS = 803 + UC_X86_INS_VFMADDSD = 804 + UC_X86_INS_VFMADD213SD = 805 + UC_X86_INS_VFMADD132SD = 806 + UC_X86_INS_VFMADD231SD = 807 + UC_X86_INS_VFMADDSS = 808 + UC_X86_INS_VFMADD213SS = 809 + UC_X86_INS_VFMADD132SS = 810 + UC_X86_INS_VFMADD231SS = 811 + UC_X86_INS_VFMADDSUB132PD = 812 + UC_X86_INS_VFMADDSUB132PS = 813 + UC_X86_INS_VFMADDSUBPD = 814 + UC_X86_INS_VFMADDSUB213PD = 815 + UC_X86_INS_VFMADDSUB231PD = 816 + UC_X86_INS_VFMADDSUBPS = 817 + UC_X86_INS_VFMADDSUB213PS = 818 + UC_X86_INS_VFMADDSUB231PS = 819 + UC_X86_INS_VFMSUB132PD = 820 + UC_X86_INS_VFMSUB132PS = 821 + UC_X86_INS_VFMSUBADD132PD = 822 + UC_X86_INS_VFMSUBADD132PS = 823 + UC_X86_INS_VFMSUBADDPD = 824 + UC_X86_INS_VFMSUBADD213PD = 825 + UC_X86_INS_VFMSUBADD231PD = 826 + UC_X86_INS_VFMSUBADDPS = 827 + UC_X86_INS_VFMSUBADD213PS = 828 + UC_X86_INS_VFMSUBADD231PS = 829 + UC_X86_INS_VFMSUBPD = 830 + UC_X86_INS_VFMSUB213PD = 831 + UC_X86_INS_VFMSUB231PD = 832 + UC_X86_INS_VFMSUBPS = 833 + UC_X86_INS_VFMSUB213PS = 834 + UC_X86_INS_VFMSUB231PS = 835 + UC_X86_INS_VFMSUBSD = 836 + UC_X86_INS_VFMSUB213SD = 837 + UC_X86_INS_VFMSUB132SD = 838 + UC_X86_INS_VFMSUB231SD = 839 + UC_X86_INS_VFMSUBSS = 840 + UC_X86_INS_VFMSUB213SS = 841 + UC_X86_INS_VFMSUB132SS = 842 + UC_X86_INS_VFMSUB231SS = 843 + UC_X86_INS_VFNMADD132PD = 844 + UC_X86_INS_VFNMADD132PS = 845 + UC_X86_INS_VFNMADDPD = 846 + UC_X86_INS_VFNMADD213PD = 847 + UC_X86_INS_VFNMADD231PD = 848 + UC_X86_INS_VFNMADDPS = 849 + UC_X86_INS_VFNMADD213PS = 850 + UC_X86_INS_VFNMADD231PS = 851 + UC_X86_INS_VFNMADDSD = 852 + UC_X86_INS_VFNMADD213SD = 853 + UC_X86_INS_VFNMADD132SD = 854 + UC_X86_INS_VFNMADD231SD = 855 + UC_X86_INS_VFNMADDSS = 856 + UC_X86_INS_VFNMADD213SS = 857 + UC_X86_INS_VFNMADD132SS = 858 + UC_X86_INS_VFNMADD231SS = 859 + UC_X86_INS_VFNMSUB132PD = 860 + UC_X86_INS_VFNMSUB132PS = 861 + UC_X86_INS_VFNMSUBPD = 862 + UC_X86_INS_VFNMSUB213PD = 863 + UC_X86_INS_VFNMSUB231PD = 864 + UC_X86_INS_VFNMSUBPS = 865 + UC_X86_INS_VFNMSUB213PS = 866 + UC_X86_INS_VFNMSUB231PS = 867 + UC_X86_INS_VFNMSUBSD = 868 + UC_X86_INS_VFNMSUB213SD = 869 + UC_X86_INS_VFNMSUB132SD = 870 + UC_X86_INS_VFNMSUB231SD = 871 + UC_X86_INS_VFNMSUBSS = 872 + UC_X86_INS_VFNMSUB213SS = 873 + UC_X86_INS_VFNMSUB132SS = 874 + UC_X86_INS_VFNMSUB231SS = 875 + UC_X86_INS_VFRCZPD = 876 + UC_X86_INS_VFRCZPS = 877 + UC_X86_INS_VFRCZSD = 878 + UC_X86_INS_VFRCZSS = 879 + UC_X86_INS_VORPD = 880 + UC_X86_INS_VORPS = 881 + UC_X86_INS_VXORPD = 882 + UC_X86_INS_VXORPS = 883 + UC_X86_INS_VGATHERDPD = 884 + UC_X86_INS_VGATHERDPS = 885 + UC_X86_INS_VGATHERPF0DPD = 886 + UC_X86_INS_VGATHERPF0DPS = 887 + UC_X86_INS_VGATHERPF0QPD = 888 + UC_X86_INS_VGATHERPF0QPS = 889 + UC_X86_INS_VGATHERPF1DPD = 890 + UC_X86_INS_VGATHERPF1DPS = 891 + UC_X86_INS_VGATHERPF1QPD = 892 + UC_X86_INS_VGATHERPF1QPS = 893 + UC_X86_INS_VGATHERQPD = 894 + UC_X86_INS_VGATHERQPS = 895 + UC_X86_INS_VHADDPD = 896 + UC_X86_INS_VHADDPS = 897 + UC_X86_INS_VHSUBPD = 898 + UC_X86_INS_VHSUBPS = 899 + UC_X86_INS_VINSERTF128 = 900 + UC_X86_INS_VINSERTF32X4 = 901 + UC_X86_INS_VINSERTF32X8 = 902 + UC_X86_INS_VINSERTF64X2 = 903 + UC_X86_INS_VINSERTF64X4 = 904 + UC_X86_INS_VINSERTI128 = 905 + UC_X86_INS_VINSERTI32X4 = 906 + UC_X86_INS_VINSERTI32X8 = 907 + UC_X86_INS_VINSERTI64X2 = 908 + UC_X86_INS_VINSERTI64X4 = 909 + UC_X86_INS_VINSERTPS = 910 + UC_X86_INS_VLDDQU = 911 + UC_X86_INS_VLDMXCSR = 912 + UC_X86_INS_VMASKMOVDQU = 913 + UC_X86_INS_VMASKMOVPD = 914 + UC_X86_INS_VMASKMOVPS = 915 + UC_X86_INS_VMAXPD = 916 + UC_X86_INS_VMAXPS = 917 + UC_X86_INS_VMAXSD = 918 + UC_X86_INS_VMAXSS = 919 + UC_X86_INS_VMCALL = 920 + UC_X86_INS_VMCLEAR = 921 + UC_X86_INS_VMFUNC = 922 + UC_X86_INS_VMINPD = 923 + UC_X86_INS_VMINPS = 924 + UC_X86_INS_VMINSD = 925 + UC_X86_INS_VMINSS = 926 + UC_X86_INS_VMLAUNCH = 927 + UC_X86_INS_VMLOAD = 928 + UC_X86_INS_VMMCALL = 929 + UC_X86_INS_VMOVQ = 930 + UC_X86_INS_VMOVDDUP = 931 + UC_X86_INS_VMOVD = 932 + UC_X86_INS_VMOVDQA32 = 933 + UC_X86_INS_VMOVDQA64 = 934 + UC_X86_INS_VMOVDQA = 935 + UC_X86_INS_VMOVDQU16 = 936 + UC_X86_INS_VMOVDQU32 = 937 + UC_X86_INS_VMOVDQU64 = 938 + UC_X86_INS_VMOVDQU8 = 939 + UC_X86_INS_VMOVDQU = 940 + UC_X86_INS_VMOVHLPS = 941 + UC_X86_INS_VMOVHPD = 942 + UC_X86_INS_VMOVHPS = 943 + UC_X86_INS_VMOVLHPS = 944 + UC_X86_INS_VMOVLPD = 945 + UC_X86_INS_VMOVLPS = 946 + UC_X86_INS_VMOVMSKPD = 947 + UC_X86_INS_VMOVMSKPS = 948 + UC_X86_INS_VMOVNTDQA = 949 + UC_X86_INS_VMOVNTDQ = 950 + UC_X86_INS_VMOVNTPD = 951 + UC_X86_INS_VMOVNTPS = 952 + UC_X86_INS_VMOVSD = 953 + UC_X86_INS_VMOVSHDUP = 954 + UC_X86_INS_VMOVSLDUP = 955 + UC_X86_INS_VMOVSS = 956 + UC_X86_INS_VMOVUPD = 957 + UC_X86_INS_VMOVUPS = 958 + UC_X86_INS_VMPSADBW = 959 + UC_X86_INS_VMPTRLD = 960 + UC_X86_INS_VMPTRST = 961 + UC_X86_INS_VMREAD = 962 + UC_X86_INS_VMRESUME = 963 + UC_X86_INS_VMRUN = 964 + UC_X86_INS_VMSAVE = 965 + UC_X86_INS_VMULPD = 966 + UC_X86_INS_VMULPS = 967 + UC_X86_INS_VMULSD = 968 + UC_X86_INS_VMULSS = 969 + UC_X86_INS_VMWRITE = 970 + UC_X86_INS_VMXOFF = 971 + UC_X86_INS_VMXON = 972 + UC_X86_INS_VPABSB = 973 + UC_X86_INS_VPABSD = 974 + UC_X86_INS_VPABSQ = 975 + UC_X86_INS_VPABSW = 976 + UC_X86_INS_VPACKSSDW = 977 + UC_X86_INS_VPACKSSWB = 978 + UC_X86_INS_VPACKUSDW = 979 + UC_X86_INS_VPACKUSWB = 980 + UC_X86_INS_VPADDB = 981 + UC_X86_INS_VPADDD = 982 + UC_X86_INS_VPADDQ = 983 + UC_X86_INS_VPADDSB = 984 + UC_X86_INS_VPADDSW = 985 + UC_X86_INS_VPADDUSB = 986 + UC_X86_INS_VPADDUSW = 987 + UC_X86_INS_VPADDW = 988 + UC_X86_INS_VPALIGNR = 989 + UC_X86_INS_VPANDD = 990 + UC_X86_INS_VPANDND = 991 + UC_X86_INS_VPANDNQ = 992 + UC_X86_INS_VPANDN = 993 + UC_X86_INS_VPANDQ = 994 + UC_X86_INS_VPAND = 995 + UC_X86_INS_VPAVGB = 996 + UC_X86_INS_VPAVGW = 997 + UC_X86_INS_VPBLENDD = 998 + UC_X86_INS_VPBLENDMB = 999 + UC_X86_INS_VPBLENDMD = 1000 + UC_X86_INS_VPBLENDMQ = 1001 + UC_X86_INS_VPBLENDMW = 1002 + UC_X86_INS_VPBLENDVB = 1003 + UC_X86_INS_VPBLENDW = 1004 + UC_X86_INS_VPBROADCASTB = 1005 + UC_X86_INS_VPBROADCASTD = 1006 + UC_X86_INS_VPBROADCASTMB2Q = 1007 + UC_X86_INS_VPBROADCASTMW2D = 1008 + UC_X86_INS_VPBROADCASTQ = 1009 + UC_X86_INS_VPBROADCASTW = 1010 + UC_X86_INS_VPCLMULQDQ = 1011 + UC_X86_INS_VPCMOV = 1012 + UC_X86_INS_VPCMPB = 1013 + UC_X86_INS_VPCMPD = 1014 + UC_X86_INS_VPCMPEQB = 1015 + UC_X86_INS_VPCMPEQD = 1016 + UC_X86_INS_VPCMPEQQ = 1017 + UC_X86_INS_VPCMPEQW = 1018 + UC_X86_INS_VPCMPESTRI = 1019 + UC_X86_INS_VPCMPESTRM = 1020 + UC_X86_INS_VPCMPGTB = 1021 + UC_X86_INS_VPCMPGTD = 1022 + UC_X86_INS_VPCMPGTQ = 1023 + UC_X86_INS_VPCMPGTW = 1024 + UC_X86_INS_VPCMPISTRI = 1025 + UC_X86_INS_VPCMPISTRM = 1026 + UC_X86_INS_VPCMPQ = 1027 + UC_X86_INS_VPCMPUB = 1028 + UC_X86_INS_VPCMPUD = 1029 + UC_X86_INS_VPCMPUQ = 1030 + UC_X86_INS_VPCMPUW = 1031 + UC_X86_INS_VPCMPW = 1032 + UC_X86_INS_VPCOMB = 1033 + UC_X86_INS_VPCOMD = 1034 + UC_X86_INS_VPCOMPRESSD = 1035 + UC_X86_INS_VPCOMPRESSQ = 1036 + UC_X86_INS_VPCOMQ = 1037 + UC_X86_INS_VPCOMUB = 1038 + UC_X86_INS_VPCOMUD = 1039 + UC_X86_INS_VPCOMUQ = 1040 + UC_X86_INS_VPCOMUW = 1041 + UC_X86_INS_VPCOMW = 1042 + UC_X86_INS_VPCONFLICTD = 1043 + UC_X86_INS_VPCONFLICTQ = 1044 + UC_X86_INS_VPERM2F128 = 1045 + UC_X86_INS_VPERM2I128 = 1046 + UC_X86_INS_VPERMD = 1047 + UC_X86_INS_VPERMI2D = 1048 + UC_X86_INS_VPERMI2PD = 1049 + UC_X86_INS_VPERMI2PS = 1050 + UC_X86_INS_VPERMI2Q = 1051 + UC_X86_INS_VPERMIL2PD = 1052 + UC_X86_INS_VPERMIL2PS = 1053 + UC_X86_INS_VPERMILPD = 1054 + UC_X86_INS_VPERMILPS = 1055 + UC_X86_INS_VPERMPD = 1056 + UC_X86_INS_VPERMPS = 1057 + UC_X86_INS_VPERMQ = 1058 + UC_X86_INS_VPERMT2D = 1059 + UC_X86_INS_VPERMT2PD = 1060 + UC_X86_INS_VPERMT2PS = 1061 + UC_X86_INS_VPERMT2Q = 1062 + UC_X86_INS_VPEXPANDD = 1063 + UC_X86_INS_VPEXPANDQ = 1064 + UC_X86_INS_VPEXTRB = 1065 + UC_X86_INS_VPEXTRD = 1066 + UC_X86_INS_VPEXTRQ = 1067 + UC_X86_INS_VPEXTRW = 1068 + UC_X86_INS_VPGATHERDD = 1069 + UC_X86_INS_VPGATHERDQ = 1070 + UC_X86_INS_VPGATHERQD = 1071 + UC_X86_INS_VPGATHERQQ = 1072 + UC_X86_INS_VPHADDBD = 1073 + UC_X86_INS_VPHADDBQ = 1074 + UC_X86_INS_VPHADDBW = 1075 + UC_X86_INS_VPHADDDQ = 1076 + UC_X86_INS_VPHADDD = 1077 + UC_X86_INS_VPHADDSW = 1078 + UC_X86_INS_VPHADDUBD = 1079 + UC_X86_INS_VPHADDUBQ = 1080 + UC_X86_INS_VPHADDUBW = 1081 + UC_X86_INS_VPHADDUDQ = 1082 + UC_X86_INS_VPHADDUWD = 1083 + UC_X86_INS_VPHADDUWQ = 1084 + UC_X86_INS_VPHADDWD = 1085 + UC_X86_INS_VPHADDWQ = 1086 + UC_X86_INS_VPHADDW = 1087 + UC_X86_INS_VPHMINPOSUW = 1088 + UC_X86_INS_VPHSUBBW = 1089 + UC_X86_INS_VPHSUBDQ = 1090 + UC_X86_INS_VPHSUBD = 1091 + UC_X86_INS_VPHSUBSW = 1092 + UC_X86_INS_VPHSUBWD = 1093 + UC_X86_INS_VPHSUBW = 1094 + UC_X86_INS_VPINSRB = 1095 + UC_X86_INS_VPINSRD = 1096 + UC_X86_INS_VPINSRQ = 1097 + UC_X86_INS_VPINSRW = 1098 + UC_X86_INS_VPLZCNTD = 1099 + UC_X86_INS_VPLZCNTQ = 1100 + UC_X86_INS_VPMACSDD = 1101 + UC_X86_INS_VPMACSDQH = 1102 + UC_X86_INS_VPMACSDQL = 1103 + UC_X86_INS_VPMACSSDD = 1104 + UC_X86_INS_VPMACSSDQH = 1105 + UC_X86_INS_VPMACSSDQL = 1106 + UC_X86_INS_VPMACSSWD = 1107 + UC_X86_INS_VPMACSSWW = 1108 + UC_X86_INS_VPMACSWD = 1109 + UC_X86_INS_VPMACSWW = 1110 + UC_X86_INS_VPMADCSSWD = 1111 + UC_X86_INS_VPMADCSWD = 1112 + UC_X86_INS_VPMADDUBSW = 1113 + UC_X86_INS_VPMADDWD = 1114 + UC_X86_INS_VPMASKMOVD = 1115 + UC_X86_INS_VPMASKMOVQ = 1116 + UC_X86_INS_VPMAXSB = 1117 + UC_X86_INS_VPMAXSD = 1118 + UC_X86_INS_VPMAXSQ = 1119 + UC_X86_INS_VPMAXSW = 1120 + UC_X86_INS_VPMAXUB = 1121 + UC_X86_INS_VPMAXUD = 1122 + UC_X86_INS_VPMAXUQ = 1123 + UC_X86_INS_VPMAXUW = 1124 + UC_X86_INS_VPMINSB = 1125 + UC_X86_INS_VPMINSD = 1126 + UC_X86_INS_VPMINSQ = 1127 + UC_X86_INS_VPMINSW = 1128 + UC_X86_INS_VPMINUB = 1129 + UC_X86_INS_VPMINUD = 1130 + UC_X86_INS_VPMINUQ = 1131 + UC_X86_INS_VPMINUW = 1132 + UC_X86_INS_VPMOVDB = 1133 + UC_X86_INS_VPMOVDW = 1134 + UC_X86_INS_VPMOVM2B = 1135 + UC_X86_INS_VPMOVM2D = 1136 + UC_X86_INS_VPMOVM2Q = 1137 + UC_X86_INS_VPMOVM2W = 1138 + UC_X86_INS_VPMOVMSKB = 1139 + UC_X86_INS_VPMOVQB = 1140 + UC_X86_INS_VPMOVQD = 1141 + UC_X86_INS_VPMOVQW = 1142 + UC_X86_INS_VPMOVSDB = 1143 + UC_X86_INS_VPMOVSDW = 1144 + UC_X86_INS_VPMOVSQB = 1145 + UC_X86_INS_VPMOVSQD = 1146 + UC_X86_INS_VPMOVSQW = 1147 + UC_X86_INS_VPMOVSXBD = 1148 + UC_X86_INS_VPMOVSXBQ = 1149 + UC_X86_INS_VPMOVSXBW = 1150 + UC_X86_INS_VPMOVSXDQ = 1151 + UC_X86_INS_VPMOVSXWD = 1152 + UC_X86_INS_VPMOVSXWQ = 1153 + UC_X86_INS_VPMOVUSDB = 1154 + UC_X86_INS_VPMOVUSDW = 1155 + UC_X86_INS_VPMOVUSQB = 1156 + UC_X86_INS_VPMOVUSQD = 1157 + UC_X86_INS_VPMOVUSQW = 1158 + UC_X86_INS_VPMOVZXBD = 1159 + UC_X86_INS_VPMOVZXBQ = 1160 + UC_X86_INS_VPMOVZXBW = 1161 + UC_X86_INS_VPMOVZXDQ = 1162 + UC_X86_INS_VPMOVZXWD = 1163 + UC_X86_INS_VPMOVZXWQ = 1164 + UC_X86_INS_VPMULDQ = 1165 + UC_X86_INS_VPMULHRSW = 1166 + UC_X86_INS_VPMULHUW = 1167 + UC_X86_INS_VPMULHW = 1168 + UC_X86_INS_VPMULLD = 1169 + UC_X86_INS_VPMULLQ = 1170 + UC_X86_INS_VPMULLW = 1171 + UC_X86_INS_VPMULUDQ = 1172 + UC_X86_INS_VPORD = 1173 + UC_X86_INS_VPORQ = 1174 + UC_X86_INS_VPOR = 1175 + UC_X86_INS_VPPERM = 1176 + UC_X86_INS_VPROTB = 1177 + UC_X86_INS_VPROTD = 1178 + UC_X86_INS_VPROTQ = 1179 + UC_X86_INS_VPROTW = 1180 + UC_X86_INS_VPSADBW = 1181 + UC_X86_INS_VPSCATTERDD = 1182 + UC_X86_INS_VPSCATTERDQ = 1183 + UC_X86_INS_VPSCATTERQD = 1184 + UC_X86_INS_VPSCATTERQQ = 1185 + UC_X86_INS_VPSHAB = 1186 + UC_X86_INS_VPSHAD = 1187 + UC_X86_INS_VPSHAQ = 1188 + UC_X86_INS_VPSHAW = 1189 + UC_X86_INS_VPSHLB = 1190 + UC_X86_INS_VPSHLD = 1191 + UC_X86_INS_VPSHLQ = 1192 + UC_X86_INS_VPSHLW = 1193 + UC_X86_INS_VPSHUFB = 1194 + UC_X86_INS_VPSHUFD = 1195 + UC_X86_INS_VPSHUFHW = 1196 + UC_X86_INS_VPSHUFLW = 1197 + UC_X86_INS_VPSIGNB = 1198 + UC_X86_INS_VPSIGND = 1199 + UC_X86_INS_VPSIGNW = 1200 + UC_X86_INS_VPSLLDQ = 1201 + UC_X86_INS_VPSLLD = 1202 + UC_X86_INS_VPSLLQ = 1203 + UC_X86_INS_VPSLLVD = 1204 + UC_X86_INS_VPSLLVQ = 1205 + UC_X86_INS_VPSLLW = 1206 + UC_X86_INS_VPSRAD = 1207 + UC_X86_INS_VPSRAQ = 1208 + UC_X86_INS_VPSRAVD = 1209 + UC_X86_INS_VPSRAVQ = 1210 + UC_X86_INS_VPSRAW = 1211 + UC_X86_INS_VPSRLDQ = 1212 + UC_X86_INS_VPSRLD = 1213 + UC_X86_INS_VPSRLQ = 1214 + UC_X86_INS_VPSRLVD = 1215 + UC_X86_INS_VPSRLVQ = 1216 + UC_X86_INS_VPSRLW = 1217 + UC_X86_INS_VPSUBB = 1218 + UC_X86_INS_VPSUBD = 1219 + UC_X86_INS_VPSUBQ = 1220 + UC_X86_INS_VPSUBSB = 1221 + UC_X86_INS_VPSUBSW = 1222 + UC_X86_INS_VPSUBUSB = 1223 + UC_X86_INS_VPSUBUSW = 1224 + UC_X86_INS_VPSUBW = 1225 + UC_X86_INS_VPTESTMD = 1226 + UC_X86_INS_VPTESTMQ = 1227 + UC_X86_INS_VPTESTNMD = 1228 + UC_X86_INS_VPTESTNMQ = 1229 + UC_X86_INS_VPTEST = 1230 + UC_X86_INS_VPUNPCKHBW = 1231 + UC_X86_INS_VPUNPCKHDQ = 1232 + UC_X86_INS_VPUNPCKHQDQ = 1233 + UC_X86_INS_VPUNPCKHWD = 1234 + UC_X86_INS_VPUNPCKLBW = 1235 + UC_X86_INS_VPUNPCKLDQ = 1236 + UC_X86_INS_VPUNPCKLQDQ = 1237 + UC_X86_INS_VPUNPCKLWD = 1238 + UC_X86_INS_VPXORD = 1239 + UC_X86_INS_VPXORQ = 1240 + UC_X86_INS_VPXOR = 1241 + UC_X86_INS_VRCP14PD = 1242 + UC_X86_INS_VRCP14PS = 1243 + UC_X86_INS_VRCP14SD = 1244 + UC_X86_INS_VRCP14SS = 1245 + UC_X86_INS_VRCP28PD = 1246 + UC_X86_INS_VRCP28PS = 1247 + UC_X86_INS_VRCP28SD = 1248 + UC_X86_INS_VRCP28SS = 1249 + UC_X86_INS_VRCPPS = 1250 + UC_X86_INS_VRCPSS = 1251 + UC_X86_INS_VRNDSCALEPD = 1252 + UC_X86_INS_VRNDSCALEPS = 1253 + UC_X86_INS_VRNDSCALESD = 1254 + UC_X86_INS_VRNDSCALESS = 1255 + UC_X86_INS_VROUNDPD = 1256 + UC_X86_INS_VROUNDPS = 1257 + UC_X86_INS_VROUNDSD = 1258 + UC_X86_INS_VROUNDSS = 1259 + UC_X86_INS_VRSQRT14PD = 1260 + UC_X86_INS_VRSQRT14PS = 1261 + UC_X86_INS_VRSQRT14SD = 1262 + UC_X86_INS_VRSQRT14SS = 1263 + UC_X86_INS_VRSQRT28PD = 1264 + UC_X86_INS_VRSQRT28PS = 1265 + UC_X86_INS_VRSQRT28SD = 1266 + UC_X86_INS_VRSQRT28SS = 1267 + UC_X86_INS_VRSQRTPS = 1268 + UC_X86_INS_VRSQRTSS = 1269 + UC_X86_INS_VSCATTERDPD = 1270 + UC_X86_INS_VSCATTERDPS = 1271 + UC_X86_INS_VSCATTERPF0DPD = 1272 + UC_X86_INS_VSCATTERPF0DPS = 1273 + UC_X86_INS_VSCATTERPF0QPD = 1274 + UC_X86_INS_VSCATTERPF0QPS = 1275 + UC_X86_INS_VSCATTERPF1DPD = 1276 + UC_X86_INS_VSCATTERPF1DPS = 1277 + UC_X86_INS_VSCATTERPF1QPD = 1278 + UC_X86_INS_VSCATTERPF1QPS = 1279 + UC_X86_INS_VSCATTERQPD = 1280 + UC_X86_INS_VSCATTERQPS = 1281 + UC_X86_INS_VSHUFPD = 1282 + UC_X86_INS_VSHUFPS = 1283 + UC_X86_INS_VSQRTPD = 1284 + UC_X86_INS_VSQRTPS = 1285 + UC_X86_INS_VSQRTSD = 1286 + UC_X86_INS_VSQRTSS = 1287 + UC_X86_INS_VSTMXCSR = 1288 + UC_X86_INS_VSUBPD = 1289 + UC_X86_INS_VSUBPS = 1290 + UC_X86_INS_VSUBSD = 1291 + UC_X86_INS_VSUBSS = 1292 + UC_X86_INS_VTESTPD = 1293 + UC_X86_INS_VTESTPS = 1294 + UC_X86_INS_VUNPCKHPD = 1295 + UC_X86_INS_VUNPCKHPS = 1296 + UC_X86_INS_VUNPCKLPD = 1297 + UC_X86_INS_VUNPCKLPS = 1298 + UC_X86_INS_VZEROALL = 1299 + UC_X86_INS_VZEROUPPER = 1300 + UC_X86_INS_WAIT = 1301 + UC_X86_INS_WBINVD = 1302 + UC_X86_INS_WRFSBASE = 1303 + UC_X86_INS_WRGSBASE = 1304 + UC_X86_INS_WRMSR = 1305 + UC_X86_INS_XABORT = 1306 + UC_X86_INS_XACQUIRE = 1307 + UC_X86_INS_XBEGIN = 1308 + UC_X86_INS_XCHG = 1309 + UC_X86_INS_XCRYPTCBC = 1310 + UC_X86_INS_XCRYPTCFB = 1311 + UC_X86_INS_XCRYPTCTR = 1312 + UC_X86_INS_XCRYPTECB = 1313 + UC_X86_INS_XCRYPTOFB = 1314 + UC_X86_INS_XEND = 1315 + UC_X86_INS_XGETBV = 1316 + UC_X86_INS_XLATB = 1317 + UC_X86_INS_XRELEASE = 1318 + UC_X86_INS_XRSTOR = 1319 + UC_X86_INS_XRSTOR64 = 1320 + UC_X86_INS_XRSTORS = 1321 + UC_X86_INS_XRSTORS64 = 1322 + UC_X86_INS_XSAVE = 1323 + UC_X86_INS_XSAVE64 = 1324 + UC_X86_INS_XSAVEC = 1325 + UC_X86_INS_XSAVEC64 = 1326 + UC_X86_INS_XSAVEOPT = 1327 + UC_X86_INS_XSAVEOPT64 = 1328 + UC_X86_INS_XSAVES = 1329 + UC_X86_INS_XSAVES64 = 1330 + UC_X86_INS_XSETBV = 1331 + UC_X86_INS_XSHA1 = 1332 + UC_X86_INS_XSHA256 = 1333 + UC_X86_INS_XSTORE = 1334 + UC_X86_INS_XTEST = 1335 + UC_X86_INS_FDISI8087_NOP = 1336 + UC_X86_INS_FENI8087_NOP = 1337 + UC_X86_INS_ENDING = 1338 +end \ No newline at end of file diff --git a/bindings/ruby/unicorn_gem/pkg/.gitignore b/bindings/ruby/unicorn_gem/pkg/.gitignore new file mode 100644 index 00000000..b7e77251 --- /dev/null +++ b/bindings/ruby/unicorn_gem/pkg/.gitignore @@ -0,0 +1,10 @@ +/.bundle/ +/.yardoc +/Gemfile.lock +/_yardoc/ +/coverage/ +/doc/ +/pkg/ +/spec/reports/ +/tmp/ +*.gem diff --git a/bindings/ruby/unicorn_gem/unicorn.gemspec b/bindings/ruby/unicorn_gem/unicorn.gemspec new file mode 100644 index 00000000..67640837 --- /dev/null +++ b/bindings/ruby/unicorn_gem/unicorn.gemspec @@ -0,0 +1,21 @@ +# coding: utf-8 +lib = File.expand_path('../lib', __FILE__) +$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) +require 'unicorn/version' + +Gem::Specification.new do |spec| + spec.name = "unicorn" + spec.version = Unicorn::VERSION + spec.authors = ["Sascha Schirra"] + spec.email = ["sashs@scoding.de"] + spec.license = 'GPL-2.0' + spec.summary = %q{Ruby binding for Unicorn-Engine} + spec.description = %q{Ruby binding for Unicorn-Engine } + spec.homepage = "https://unicorn-engine.org" + + spec.files = Dir["lib/unicorn/*.rb"] + Dir["ext/unicorn.c"] + Dir["ext/unicorn.h"] + Dir["ext/extconf.rb"] + spec.require_paths = ["lib","ext"] + spec.extensions = ["ext/extconf.rb"] + spec.add_development_dependency "bundler", "~> 1.11" + spec.add_development_dependency "rake", "~> 10.0" +end diff --git a/docs/COMPILE-NIX.md b/docs/COMPILE-NIX.md new file mode 100644 index 00000000..06341b19 --- /dev/null +++ b/docs/COMPILE-NIX.md @@ -0,0 +1,170 @@ +This documentation explains how to compile, install & run Unicorn on MacOSX, +Linux, BSD, Solaris, Android & iOS. + +To compile for Microsoft Windows, see [COMPILE-WINDOWS.md](COMPILE-WINDOWS.md) + +---- + + +[0] Dependencies + +Unicorn requires few dependent packages as follows. + +- For Mac OS X, "pkg-config" and "glib" are needed. + Brew users can install "pkg-config" and "glib" with: + + $ brew install pkg-config glib + +- For Linux, "glib2-dev" is needed. + Ubuntu/Debian users can install this with: + + $ sudo apt-get install libglib2.0-dev + + + +[1] Tailor Unicorn to your need. + +Out of 6 archtitectures supported by Unicorn (Arm, Arm64, M68K, Mips, Sparc, +& X86), if you just need several selected archs, choose which ones you want +to compile in by editing "config.mk" before going to next steps. + +By default, all 6 architectures are compiled. + +The other way of customize Unicorn without having to edit config.mk is to +pass the desired options on the commandline to ./make.sh. Currently, +Unicorn supports 4 options, as follows. + + - UNICORN_ARCHS: specify list of architectures to compiled in. + - UNICORN_STATIC: build static library. + - UNICORN_SHARED: build dynamic (shared) library. + - UNICORN_QEMU_FLAGS: specify extra flags for qemu's configure script + +To avoid editing config.mk for these customization, we can pass their values to +make.sh, as follows. + + $ UNICORN_ARCHS="arm aarch64 x86" ./make.sh + +NOTE: on commandline, put these values in front of ./make.sh, not after it. + +For each option, refer to docs/README for more details. + + + +[2] Compile and install from source on *nix + +To build Unicorn on *nix (such as MacOSX, Linux, *BSD, Solaris): + +- To compile for current platform, run: + + $ ./make.sh + +- Unicorn requires Python 2.x to compile. If Python 2.x is not the default + Python interpreter, ensure that the appropriate option is set: + + $ UNICORN_QEMU_FLAGS="--python=/path/to/python2" ./make.sh + +- To cross-compile Unicorn on 64-bit OS to target 32-bit binary, run: + + $ ./make.sh nix32 + + After compiling, install Unicorn with: + + $ sudo ./make.sh install + + For FreeBSD/OpenBSD, where sudo is unavailable, run: + + $ su; ./make.sh install + + Users are then required to enter root password to copy Unicorn into machine + system directories. + + Afterwards, run ./samples/sample_all.sh to test the sample emulations. + + + NOTE: The core framework installed by "./make.sh install" consist of + following files: + + /usr/include/unicorn/unicorn.h + /usr/include/unicorn/x86.h + /usr/include/unicorn/arm.h + /usr/include/unicorn/arm64.h + /usr/include/unicorn/mips.h + /usr/include/unicorn/ppc.h + /usr/include/unicorn/sparc.h + /usr/include/unicorn/m68k.h + /usr/lib/libunicorn.so (for Linux/*nix), or /usr/lib/libunicorn.dylib (OSX) + /usr/lib/libunicorn.a + + + +[3] Cross-compile for iOS from Mac OSX. + +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: + + $ ./make.sh ios_armv7 + +- To cross-compile for ArmV7s (iPad 4, iPhone 5C, iPad mini), run: + + $ ./make.sh ios_armv7s + +- To cross-compile for Arm64 (iPhone 5S, iPad mini Retina, iPad Air), run: + + $ ./make.sh ios_arm64 + +- To cross-compile for all iDevices (armv7 + armv7s + arm64), run: + + $ ./make.sh ios + +Resulted files libunicorn.dylib, libunicorn.a & tests/test* can then +be used on iOS devices. + + + +[4] Cross-compile for Android + +To cross-compile for Android (smartphone/tablet), Android NDK is required. +NOTE: Only ARM and ARM64 are currently supported. + + $ NDK=/android/android-ndk-r10e ./make.sh cross-android arm +or + $ NDK=/android/android-ndk-r10e ./make.sh cross-android arm64 + +Resulted files libunicorn.so, libunicorn.a & tests/test* can then +be used on Android devices. + + + +[5] By default, "cc" (default C compiler on the system) is used as compiler. + +- To use "clang" compiler instead, run the command below: + + $ ./make.sh clang + +- To use "gcc" compiler instead, run: + + $ ./make.sh gcc + + + +[6] To uninstall Unicorn, run the command below: + + $ sudo ./make.sh uninstall + + + +[7] Language bindings + +Look for the bindings under directory bindings/, and refer to README file +of corresponding languages. + + + +[8] Unit tests + +Automated unit tests use the cmocka unit testing framework (https://cmocka.org/). +It can be installed in most Linux distros using the package manager, e.g. +`sudo yum install libcmocka libcmocka-devel`, or you can easily build and install it from source. + +You can run the tests by running `make test` in the project directory. diff --git a/docs/COMPILE-WINDOWS.md b/docs/COMPILE-WINDOWS.md new file mode 100644 index 00000000..f8d60f90 --- /dev/null +++ b/docs/COMPILE-WINDOWS.md @@ -0,0 +1,201 @@ +We also show steps to cross-compile Unicorn for Microsoft Windows. + +To compile for Linux, Mac OS X and Unix-based OS, see [COMPILE-NIX.md](COMPILE-NIX.md) + +--- + + +[0] Dependencies + +For Windows, cross-compile requires Mingw. Mingw-glib2 is needed. +At the moment, it is confirmed that Unicorn can be compiled either on Ubuntu +or Windows. + +- On Ubuntu 14.04 64-bit, do: + + - Download DEB packages for Mingw64 from: + + https://launchpad.net/~greg-hellings/+archive/ubuntu/mingw-libs/+build/2924251 + + - To cross-compile for Windows 32-bit, install Mingw with (ignore all the warnings): + + $ sudo dpkg -i --force-depends mingw64-x86-glib2_2.31.0_all.deb + + To cross-compile for Windows 64-bit, install Mingw with: + + $ sudo dpkg -i --force-depends mingw64-x64-glib2_2.31.0_all.deb + + +- On Windows, install MinGW via package MSYS2 at https://msys2.github.io/ + + Follow the install instructions and don't forget to update the system packages with: + + $ pacman --needed -Sy bash pacman pacman-mirrors msys2-runtime + + Then close MSYS2, run it again from Start menu and update the rest with: + + $ pacman -Su + + Finally, install required toolchain to build C projects. + + - To compile for Windows 32-bit, run: + + $ pacman -S python2 + $ pacman -S make + $ pacman -S pkg-config + $ pacman -S mingw-w64-i686-glib2 + $ pacman -S mingw-w64-i686-toolchain + + - To compile for Windows 64-bit, run: + + $ pacman -S python2 + $ pacman -S make + $ pacman -S pkg-config + $ pacman -S mingw-w64-x86_64-glib2 + $ pacman -S mingw-w64-x86_64-toolchain + +- For Cygwin, "make", "gcc-core", "pkg-config", "libpcre-devel", "zlib-devel" + and "libglib2.0-devel" are needed. + + If apt-cyg is available, you can install these with: + + $ apt-cyg install make gcc-core pkg-config libpcre-devel zlib-devel libglib2.0-devel + + + +[1] Tailor Unicorn to your need. + +Out of 6 archtitectures supported by Unicorn (Arm, Arm64, M68K, Mips, Sparc, +& X86), if you just need several selected archs, choose which ones you want +to compile in by editing "config.mk" before going to next steps. + +By default, all 6 architectures are compiled. + +The other way of customize Unicorn without having to edit config.mk is to +pass the desired options on the commandline to ./make.sh. Currently, +Unicorn supports 4 options, as follows. + + - UNICORN_ARCHS: specify list of architectures to compiled in. + - UNICORN_STATIC: build static library. + - UNICORN_SHARED: build dynamic (shared) library. + - UNICORN_QEMU_FLAGS: specify extra flags for qemu's configure script + +To avoid editing config.mk for these customization, we can pass their values to +make.sh, as follows. + + $ UNICORN_ARCHS="arm aarch64 x86" ./make.sh + +NOTE: on commandline, put these values in front of ./make.sh, not after it. + +For each option, refer to docs/README for more details. + + + +[2] Compile from source on Windows - with MinGW (MSYS2) + +To compile with MinGW, install MSYS2 as instructed in the first section. +Then, build Unicorn with the next steps: + +- To compile Windows 32-bit binary with MinGW, run: + + $ ./make.sh cross-win32 + +- To compile Windows 64-bit binary with MinGW, run: + + $ ./make.sh cross-win64 + +Resulted files unicorn.dll, unicorn.lib & samples/sample*.exe can then +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 + + + +[3] Compile and install from source on Cygwin + +To build Unicorn on Cygwin, run: + + $ ./make.sh + +After compiling, install Unicorn with: + + $ ./make.sh install + +Resulted files cygunicorn.dll, libunicorn.dll.a and libunicorn.a can be +used on Cygwin but not native Windows. + +NOTE: The core framework installed by "./make.sh install" consist of +following files: + + /usr/include/unicorn/*.h + /usr/bin/cygunicorn.dll + /usr/lib/libunicorn.dll.a + /usr/lib/libunicorn.a + + + +[4] Cross-compile for Windows from *nix + +To cross-compile for Windows, Linux & gcc-mingw-w64-i686 (and also gcc-mingw-w64-x86-64 +for 64-bit binaries) are required. + +- To cross-compile Windows 32-bit binary, simply run: + + $ ./make.sh cross-win32 + +- To cross-compile Windows 64-bit binary, run: + + $ ./make.sh cross-win64 + +Resulted files unicorn.dll, unicorn.lib & samples/sample*.exe can then +be used on Windows machine. + +To run sample_x86.exe on Windows 32-bit, you need the following files: + + unicorn.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/i686-w64-mingw32/lib/libwinpthread-1.dll + +To run sample_x86.exe on Windows 64-bit, you need the following files: + + unicorn.dll + /usr/x86_64-w64-mingw32/sys-root/mingw/bin/libglib-2.0-0.dll + /usr/lib/gcc/x86_64-w64-mingw32/4.8/libgcc_s_sjlj-1.dll + /usr/x86_64-w64-mingw32/lib/libwinpthread-1.dll + +Then run either "sample_x86.exe -32" or "sample_x86.exe -64" to test emulators for X86 32-bit or X86 64-bit. +For other architectures, run "sample_xxx.exe" found in the same directory. + + + +[5] Language bindings + +Look for the bindings under directory bindings/, and refer to README file +of corresponding languages. + + + +[6] Unit tests + +Automated unit tests use the cmocka unit testing framework (https://cmocka.org/). +It can be installed in most Linux distros using the package manager, e.g. +`sudo yum install libcmocka libcmocka-devel`, or you can easily build and install it from source. + +You can run the tests by running `make test` in the project directory. diff --git a/docs/COMPILE.md b/docs/COMPILE.md new file mode 100644 index 00000000..28c9636f --- /dev/null +++ b/docs/COMPILE.md @@ -0,0 +1,10 @@ +To compile Unicorn on Mac OS X, Linux, BSD, Solaris and all kind of nix OS, +see [COMPILE-NIX.md](COMPILE-NIX.md) + +To compile Unicorn on Windows, see [COMPILE-WINDOWS.md](COMPILE-WINDOWS.md) + +Then learn more on how to code your own tools with our samples. + + - For C sample code, see code in directory samples/sample*.c + - For Python sample code, see code in directory bindings/python/sample*.py + - For samples of other bindings, look into directories bindings// diff --git a/include/uc_priv.h b/include/uc_priv.h index 0ef5a3dd..a0879676 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -22,6 +22,17 @@ #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 { @@ -35,8 +46,8 @@ 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); +typedef int (*reg_read_t)(struct uc_struct *uc, unsigned int *regs, void **vals, int count); +typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count); typedef void (*reg_reset_t)(struct uc_struct *uc); @@ -136,7 +147,6 @@ struct uc_struct { uc_mode mode; QemuMutex qemu_global_mutex; // qemu/cpus.c QemuCond qemu_cpu_cond; // qemu/cpus.c - QemuThread *tcg_cpu_thread; // qemu/cpus.c QemuCond *tcg_halt_cond; // qemu/cpus.c struct CPUTailQ cpus; // qemu/cpu-exec.c uc_err errnum; // qemu/cpu-exec.c @@ -152,7 +162,7 @@ struct uc_struct { uc_args_uc_u64_t set_pc; // set PC for tracecode uc_args_int_t stop_interrupt; // check if the interrupt should stop emulation - uc_args_uc_t init_arch, pause_all_vcpus, cpu_exec_init_all; + uc_args_uc_t init_arch, cpu_exec_init_all; uc_args_int_uc_t vm_start; uc_args_tcg_enable_t tcg_enabled; uc_args_uc_long_t tcg_exec_init; @@ -188,10 +198,12 @@ struct uc_struct { QemuMutex flat_view_mutex; QTAILQ_HEAD(memory_listeners, MemoryListener) memory_listeners; QTAILQ_HEAD(, AddressSpace) address_spaces; + MachineState *machine_state; // qom/object.c GHashTable *type_table; Type type_interface; Object *root; + Object *owner; bool enumerating_types; // util/module.c ModuleTypeList init_type_list[MODULE_INIT_MAX]; diff --git a/include/unicorn/m68k.h b/include/unicorn/m68k.h index 80350c13..201a4e78 100644 --- a/include/unicorn/m68k.h +++ b/include/unicorn/m68k.h @@ -9,7 +9,6 @@ extern "C" { #endif #include -#include "platform.h" #ifdef _MSC_VER #pragma warning(disable:4201) diff --git a/include/unicorn/platform.h b/include/unicorn/platform.h deleted file mode 100644 index c1e80623..00000000 --- a/include/unicorn/platform.h +++ /dev/null @@ -1,28 +0,0 @@ -/* Unicorn Emulator Engine */ -/* By Axel Souchet & Nguyen Anh Quynh, 2014 */ - -// handle C99 issue (for pre-2013 VisualStudio) -#ifndef UNICORN_PLATFORM_H -#define UNICORN_PLATFORM_H - -#if !defined(__MINGW32__) && !defined(__MINGW64__) && (defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64)) -// MSVC - -// stdbool.h -#if (_MSC_VER < 1800) -#ifndef __cplusplus -typedef unsigned char bool; -#define false 0 -#define true 1 -#endif - -#else -// VisualStudio 2013+ -> C99 is supported -#include -#endif - -#else // not MSVC -> C99 is supported -#include -#endif - -#endif diff --git a/include/unicorn/sparc.h b/include/unicorn/sparc.h index 353dbb34..57a483b7 100644 --- a/include/unicorn/sparc.h +++ b/include/unicorn/sparc.h @@ -9,7 +9,6 @@ extern "C" { #endif #include -#include "platform.h" // GCC SPARC toolchain has a default macro called "sparc" which breaks // compilation diff --git a/include/unicorn/unicorn.h b/include/unicorn/unicorn.h index 35e745ca..b5d901f9 100644 --- a/include/unicorn/unicorn.h +++ b/include/unicorn/unicorn.h @@ -9,6 +9,7 @@ extern "C" { #endif #include +#include #include #if defined(UNICORN_HAS_OSXKERNEL) #include @@ -17,8 +18,6 @@ extern "C" { #include #endif -#include "platform.h" - struct uc_struct; typedef struct uc_struct uc_engine; @@ -262,6 +261,7 @@ typedef struct uc_mem_region { typedef enum uc_query_type { // Dynamically query current hardware mode. UC_QUERY_MODE = 1, + UC_QUERY_PAGE_SIZE, } uc_query_type; /* @@ -385,6 +385,34 @@ uc_err uc_reg_write(uc_engine *uc, int regid, const void *value); UNICORN_EXPORT uc_err uc_reg_read(uc_engine *uc, int regid, void *value); +/* + Write multiple register values. + + @uc: handle returned by uc_open() + @rges: array of register IDs to store + @value: pointer to array of register values + @count: length of both *regs and *vals + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_reg_write_batch(uc_engine *uc, int *regs, void *const *vals, int count); + +/* + Read multiple register values. + + @uc: handle returned by uc_open() + @rges: array of register IDs to retrieve + @value: pointer to array of values to hold registers + @count: length of both *regs and *vals + + @return UC_ERR_OK on success, or other value on failure (refer to uc_err enum + for detailed error). +*/ +UNICORN_EXPORT +uc_err uc_reg_read_batch(uc_engine *uc, int *regs, void **vals, int count); + /* Write to a range of bytes in memory. @@ -458,7 +486,7 @@ uc_err uc_emu_stop(uc_engine *uc); @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) - @begin: end 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) diff --git a/include/unicorn/x86.h b/include/unicorn/x86.h index 51401eba..b0e02d8d 100644 --- a/include/unicorn/x86.h +++ b/include/unicorn/x86.h @@ -8,6 +8,8 @@ extern "C" { #endif +#include + // Memory-Management Register for instructions IDTR, GDTR, LDTR, TR. // Borrow from SegmentCache in qemu/target-i386/cpu.h typedef struct uc_x86_mmr { @@ -73,7 +75,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_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; diff --git a/list.c b/list.c index 6dbe4782..b1627f59 100644 --- a/list.c +++ b/list.c @@ -54,6 +54,8 @@ bool list_remove(struct list *list, void *data) if (cur->data == data) { if (cur == list->head) { list->head = next; + } else { + prev->next = next; } if (cur == list->tail) { list->tail = prev; diff --git a/make.sh b/make.sh index 98cac449..bb234572 100755 --- a/make.sh +++ b/make.sh @@ -10,6 +10,13 @@ MAKE_JOBS=$((${MAKE_JOBS}+0)) [ ${MAKE_JOBS} -lt 1 ] && \ MAKE_JOBS=4 +# build for ASAN +asan() { + UNICORN_DEBUG=yes + UNICORN_ASAN=yes + ${MAKE} V=1 +} + # build iOS lib for all iDevices, or only specific device build_iOS() { IOS_SDK=`xcrun --sdk iphoneos --show-sdk-path` @@ -51,7 +58,7 @@ install() { rm -rf /usr/lib/libunicorn* rm -rf /usr/include/unicorn # install into /usr/local - PREFIX=/usr/local + PREFIX="${PREFIX-/usr/local}" ${MAKE} install else # not OSX test -d /usr/lib64 && LIBDIRARCH=lib64 @@ -64,7 +71,7 @@ uninstall() { if [ "$UNAME" = "Darwin" ]; then # find the directory automatically, so we can support both Macport & Brew PKGCFGDIR="$(pkg-config --variable pc_path pkg-config | cut -d ':' -f 1)" - PREFIX=/usr/local + PREFIX="${PREFIX-/usr/local}" ${MAKE} uninstall else # not OSX test -d /usr/lib64 && LIBDIRARCH=lib64 @@ -80,7 +87,7 @@ fi if [ -n "`echo "$UNAME" | grep BSD`" ]; then MAKE=gmake - PREFIX=/usr/local + PREFIX="${PREFIX-/usr/local}" fi [ -z "${UNAME}" ] && UNAME=$(uname) @@ -90,6 +97,7 @@ export CC INSTALL_BIN PREFIX PKGCFGDIR LIBDIRARCH LIBARCHS CFLAGS LDFLAGS case "$1" in "" ) build;; + "asan" ) asan;; "default" ) build;; "install" ) install;; "uninstall" ) uninstall;; diff --git a/qemu/Makefile.objs b/qemu/Makefile.objs index d309d2a4..e3bc755c 100644 --- a/qemu/Makefile.objs +++ b/qemu/Makefile.objs @@ -19,7 +19,7 @@ ifeq ($(CONFIG_SOFTMMU),y) common-obj-y += hw/ common-obj-y += accel.o -common-obj-y += vl.o main-loop.o qemu-timer.o +common-obj-y += vl.o qemu-timer.o endif diff --git a/qemu/aarch64.h b/qemu/aarch64.h index d75c06e1..09352a6a 100644 --- a/qemu/aarch64.h +++ b/qemu/aarch64.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_aarch64 #define par_write par_write_aarch64 #define patch_reloc patch_reloc_aarch64 -#define pause_all_vcpus pause_all_vcpus_aarch64 #define phys_map_node_alloc phys_map_node_alloc_aarch64 #define phys_map_node_reserve phys_map_node_reserve_aarch64 #define phys_mem_alloc phys_mem_alloc_aarch64 @@ -2417,9 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_aarch64 #define qemu_clock_ptr qemu_clock_ptr_aarch64 #define qemu_clocks qemu_clocks_aarch64 -#define qemu_cond_destroy qemu_cond_destroy_aarch64 -#define qemu_cpu_is_self qemu_cpu_is_self_aarch64 -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_aarch64 #define qemu_daemon qemu_daemon_aarch64 #define qemu_event_destroy qemu_event_destroy_aarch64 #define qemu_event_init qemu_event_init_aarch64 @@ -2445,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_aarch64 #define qemu_loglevel_mask qemu_loglevel_mask_aarch64 #define qemu_log_vprintf qemu_log_vprintf_aarch64 -#define qemu_mutex_destroy qemu_mutex_destroy_aarch64 #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_aarch64 #define qemu_mutex_trylock qemu_mutex_trylock_aarch64 #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_aarch64 @@ -2516,9 +2511,7 @@ #define qemu_st_helpers qemu_st_helpers_aarch64 #define qemu_strnlen qemu_strnlen_aarch64 #define qemu_strsep qemu_strsep_aarch64 -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_aarch64 #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_aarch64 -#define qemu_thread_exit qemu_thread_exit_aarch64 #define qemu_try_memalign qemu_try_memalign_aarch64 #define qentry_destroy qentry_destroy_aarch64 #define qerror_human qerror_human_aarch64 diff --git a/qemu/arm.h b/qemu/arm.h index ef850c24..6b955375 100644 --- a/qemu/arm.h +++ b/qemu/arm.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_arm #define par_write par_write_arm #define patch_reloc patch_reloc_arm -#define pause_all_vcpus pause_all_vcpus_arm #define phys_map_node_alloc phys_map_node_alloc_arm #define phys_map_node_reserve phys_map_node_reserve_arm #define phys_mem_alloc phys_mem_alloc_arm @@ -2417,9 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_arm #define qemu_clock_ptr qemu_clock_ptr_arm #define qemu_clocks qemu_clocks_arm -#define qemu_cond_destroy qemu_cond_destroy_arm -#define qemu_cpu_is_self qemu_cpu_is_self_arm -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_arm #define qemu_daemon qemu_daemon_arm #define qemu_event_destroy qemu_event_destroy_arm #define qemu_event_init qemu_event_init_arm @@ -2445,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_arm #define qemu_loglevel_mask qemu_loglevel_mask_arm #define qemu_log_vprintf qemu_log_vprintf_arm -#define qemu_mutex_destroy qemu_mutex_destroy_arm #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_arm #define qemu_mutex_trylock qemu_mutex_trylock_arm #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_arm @@ -2516,9 +2511,7 @@ #define qemu_st_helpers qemu_st_helpers_arm #define qemu_strnlen qemu_strnlen_arm #define qemu_strsep qemu_strsep_arm -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_arm #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_arm -#define qemu_thread_exit qemu_thread_exit_arm #define qemu_try_memalign qemu_try_memalign_arm #define qentry_destroy qentry_destroy_arm #define qerror_human qerror_human_arm diff --git a/qemu/cpus.c b/qemu/cpus.c index 64c73b0b..79f2eeb7 100644 --- a/qemu/cpus.c +++ b/qemu/cpus.c @@ -28,6 +28,7 @@ #include "config-host.h" #include "sysemu/sysemu.h" #include "sysemu/cpus.h" +#include "qemu/thread.h" #include "exec/address-spaces.h" // debug, can be removed later @@ -38,17 +39,13 @@ static void cpu_handle_guest_debug(CPUState *cpu); static int tcg_cpu_exec(struct uc_struct *uc, CPUArchState *env); static bool tcg_exec_all(struct uc_struct* uc); static int qemu_tcg_init_vcpu(CPUState *cpu); -static void *qemu_tcg_cpu_thread_fn(void *arg); +static void *qemu_tcg_cpu_loop(struct uc_struct *uc); int vm_start(struct uc_struct* uc) { if (resume_all_vcpus(uc)) { return -1; } - - // kick off TCG thread - qemu_mutex_unlock_iothread(uc); - return 0; } @@ -59,28 +56,9 @@ bool cpu_is_stopped(CPUState *cpu) void run_on_cpu(CPUState *cpu, void (*func)(void *data), void *data) { - if (qemu_cpu_is_self(cpu)) { - func(data); - return; - } + func(data); } -// send halt_cond/tcg_halt_cond to @cpu -bool qemu_cpu_is_self(CPUState *cpu) -{ - return qemu_thread_is_self(cpu->thread); -} - -void pause_all_vcpus(struct uc_struct *uc) -{ - CPUState *cpu; - - CPU_FOREACH(cpu) { - qemu_thread_join(cpu->thread); // qq: fix qemu_thread_join() to work for instance - } -} - - int resume_all_vcpus(struct uc_struct *uc) { CPUState *cpu; @@ -99,7 +77,6 @@ int resume_all_vcpus(struct uc_struct *uc) if (qemu_init_vcpu(cpu)) return -1; } - qemu_mutex_lock_iothread(uc); } } @@ -107,6 +84,7 @@ int resume_all_vcpus(struct uc_struct *uc) CPU_FOREACH(cpu) { cpu_resume(cpu); } + qemu_tcg_cpu_loop(uc); return 0; } @@ -116,7 +94,6 @@ int qemu_init_vcpu(CPUState *cpu) cpu->nr_cores = smp_cores; cpu->nr_threads = smp_threads; cpu->stopped = true; - cpu->uc->tcg_cpu_thread = NULL; if (tcg_enabled(cpu->uc)) return qemu_tcg_init_vcpu(cpu); @@ -125,45 +102,28 @@ int qemu_init_vcpu(CPUState *cpu) } -static void *qemu_tcg_cpu_thread_fn(void *arg) +static void *qemu_tcg_cpu_loop(struct uc_struct *uc) { - CPUState *cpu = arg; - struct uc_struct *uc = cpu->uc; + CPUState *cpu; //qemu_tcg_init_cpu_signals(); - qemu_thread_get_self(uc, cpu->thread); qemu_mutex_lock(&uc->qemu_global_mutex); CPU_FOREACH(cpu) { - cpu->thread_id = qemu_get_thread_id(); cpu->created = true; } qemu_cond_signal(&uc->qemu_cpu_cond); - /* wait for initial kick-off after machine start */ - while (QTAILQ_FIRST(&uc->cpus)->stopped) { - qemu_cond_wait(uc->tcg_halt_cond, &uc->qemu_global_mutex); - } - while (1) { -#if 0 - int count = 0; - if (count < 10) { - count++; - unsigned int eip = X86_CPU(mycpu)->env.eip; - printf(">>> current EIP = %x\n", eip); - printf(">>> ECX = %x\n", (unsigned int)X86_CPU(mycpu)->env.regs[R_ECX]); - printf(">>> EDX = %x\n", (unsigned int)X86_CPU(mycpu)->env.regs[R_EDX]); - } -#endif - if (tcg_exec_all(uc)) break; } CPU_FOREACH(cpu) { - cpu->thread_id = 0; cpu->created = false; + qemu_cond_destroy(cpu->halt_cond); + free(cpu->halt_cond); + cpu->halt_cond = NULL; } qemu_mutex_unlock(&uc->qemu_global_mutex); @@ -173,38 +133,16 @@ static void *qemu_tcg_cpu_thread_fn(void *arg) -/* For temporary buffers for forming a name */ -#define VCPU_THREAD_NAME_SIZE 16 - static int qemu_tcg_init_vcpu(CPUState *cpu) { struct uc_struct *uc = cpu->uc; - char thread_name[VCPU_THREAD_NAME_SIZE]; tcg_cpu_address_space_init(cpu, cpu->as); /* share a single thread for all cpus with TCG */ - if (!uc->tcg_cpu_thread) { - cpu->thread = g_malloc0(sizeof(QemuThread)); - cpu->halt_cond = g_malloc0(sizeof(QemuCond)); - qemu_cond_init(cpu->halt_cond); - uc->tcg_halt_cond = cpu->halt_cond; - snprintf(thread_name, VCPU_THREAD_NAME_SIZE, "CPU %d/TCG", - cpu->cpu_index); - if (qemu_thread_create(uc, cpu->thread, thread_name, qemu_tcg_cpu_thread_fn, - cpu, QEMU_THREAD_JOINABLE)) - return -1; -#ifdef _WIN32 - cpu->hThread = qemu_thread_get_handle(cpu->thread); -#endif - while (!cpu->created) { - qemu_cond_wait(&uc->qemu_cpu_cond, &uc->qemu_global_mutex); - } - uc->tcg_cpu_thread = cpu->thread; - } else { - cpu->thread = uc->tcg_cpu_thread; - cpu->halt_cond = uc->tcg_halt_cond; - } + cpu->halt_cond = g_malloc0(sizeof(QemuCond)); + qemu_cond_init(cpu->halt_cond); + uc->tcg_halt_cond = cpu->halt_cond; return 0; } diff --git a/qemu/exec.c b/qemu/exec.c index fcb2b7f4..15c4809f 100644 --- a/qemu/exec.c +++ b/qemu/exec.c @@ -432,10 +432,7 @@ void cpu_exec_init(CPUArchState *env, void *opaque) QTAILQ_INIT(&cpu->watchpoints); cpu->as = &uc->as; -#ifndef CONFIG_USER_ONLY - //cpu->as = &address_space_memory; - cpu->thread_id = qemu_get_thread_id(); -#endif + QTAILQ_INSERT_TAIL(&uc->cpus, cpu, node); //QTAILQ_INSERT_TAIL(&uc->cpus, cpu, node); #if defined(CONFIG_USER_ONLY) diff --git a/qemu/header_gen.py b/qemu/header_gen.py index 46bab7c9..95476877 100644 --- a/qemu/header_gen.py +++ b/qemu/header_gen.py @@ -2264,7 +2264,6 @@ symbols = ( 'parse_value', 'par_write', 'patch_reloc', - 'pause_all_vcpus', 'phys_map_node_alloc', 'phys_map_node_reserve', 'phys_mem_alloc', @@ -2423,9 +2422,6 @@ symbols = ( 'qemu_clock_get_us', 'qemu_clock_ptr', 'qemu_clocks', - 'qemu_cond_destroy', - 'qemu_cpu_is_self', - 'qemu_cpu_kick_thread', 'qemu_daemon', 'qemu_event_destroy', 'qemu_event_init', @@ -2451,7 +2447,6 @@ symbols = ( 'qemu_log_flush', 'qemu_loglevel_mask', 'qemu_log_vprintf', - 'qemu_mutex_destroy', 'qemu_mutex_lock_ramlist', 'qemu_mutex_trylock', 'qemu_mutex_unlock_ramlist', @@ -2522,9 +2517,7 @@ symbols = ( 'qemu_st_helpers', 'qemu_strnlen', 'qemu_strsep', - 'qemu_tcg_cpu_thread_fn', 'qemu_tcg_init_vcpu', - 'qemu_thread_exit', 'qemu_try_memalign', 'qentry_destroy', 'qerror_human', diff --git a/qemu/hw/arm/tosa.c b/qemu/hw/arm/tosa.c index fe9eaf6e..8630e46e 100644 --- a/qemu/hw/arm/tosa.c +++ b/qemu/hw/arm/tosa.c @@ -20,7 +20,7 @@ static int tosa_init(struct uc_struct *uc, MachineState *machine) { //cpu_arm_init(uc, "pxa255"); - cpu_arm_init(uc, "cortex-a15"); // FIXME + uc->cpu = cpu_arm_init(uc, "cortex-a15"); // FIXME return 0; } diff --git a/qemu/hw/arm/virt.c b/qemu/hw/arm/virt.c index 554e89d7..e2a68412 100644 --- a/qemu/hw/arm/virt.c +++ b/qemu/hw/arm/virt.c @@ -54,7 +54,7 @@ static int machvirt_init(struct uc_struct *uc, MachineState *machine) return -1; } - cpuobj = object_new(uc, object_class_get_name(oc)); + uc->cpu = cpuobj = object_new(uc, object_class_get_name(oc)); object_property_set_bool(uc, cpuobj, true, "realized", NULL); } diff --git a/qemu/hw/intc/apic.c b/qemu/hw/intc/apic.c index e58d742b..1f89770e 100644 --- a/qemu/hw/intc/apic.c +++ b/qemu/hw/intc/apic.c @@ -70,7 +70,6 @@ static void apic_sync_vapic(APICCommonState *s, int sync_type) //length = offsetof(VAPICState, enabled) - offsetof(VAPICState, isr); if (sync_type & SYNC_TO_VAPIC) { - assert(qemu_cpu_is_self(CPU(s->cpu))); vapic_state.tpr = s->tpr; vapic_state.enabled = 1; diff --git a/qemu/include/qemu/main-loop.h b/qemu/include/qemu/main-loop.h deleted file mode 100644 index 2f196e1b..00000000 --- a/qemu/include/qemu/main-loop.h +++ /dev/null @@ -1,77 +0,0 @@ -/* - * QEMU System Emulator - * - * Copyright (c) 2003-2008 Fabrice Bellard - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL - * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#ifndef QEMU_MAIN_LOOP_H -#define QEMU_MAIN_LOOP_H 1 - -#define SIG_IPI SIGUSR1 - -struct uc_struct; - -/** - * qemu_init_main_loop: Set up the process so that it can run the main loop. - * - * This includes setting up signal handlers. It should be called before - * any other threads are created. In addition, threads other than the - * main one should block signals that are trapped by the main loop. - * For simplicity, you can consider these signals to be safe: SIGUSR1, - * SIGUSR2, thread signals (SIGFPE, SIGILL, SIGSEGV, SIGBUS) and real-time - * signals if available. Remember that Windows in practice does not have - * signals, though. - * - * In the case of QEMU tools, this will also start/initialize timers. - */ -int qemu_init_main_loop(void); - -/** - * qemu_mutex_lock_iothread: Lock the main loop mutex. - * - * This function locks the main loop mutex. The mutex is taken by - * qemu_init_main_loop and always taken except while waiting on - * external events (such as with select). The mutex should be taken - * by threads other than the main loop thread when calling - * qemu_bh_new(), qemu_set_fd_handler() and basically all other - * functions documented in this file. - * - * NOTE: tools currently are single-threaded and qemu_mutex_lock_iothread - * is a no-op there. - */ -void qemu_mutex_lock_iothread(struct uc_struct* uc); - -/** - * qemu_mutex_unlock_iothread: Unlock the main loop mutex. - * - * This function unlocks the main loop mutex. The mutex is taken by - * qemu_init_main_loop and always taken except while waiting on - * external events (such as with select). The mutex should be unlocked - * as soon as possible by threads other than the main loop thread, - * because it prevents the main loop from processing callbacks, - * including timers and bottom halves. - * - * NOTE: tools currently are single-threaded and qemu_mutex_unlock_iothread - * is a no-op there. - */ -void qemu_mutex_unlock_iothread(struct uc_struct* uc); - -#endif diff --git a/qemu/include/qemu/osdep.h b/qemu/include/qemu/osdep.h index 256bb011..9e4c7403 100644 --- a/qemu/include/qemu/osdep.h +++ b/qemu/include/qemu/osdep.h @@ -183,7 +183,6 @@ int qemu_close(int fd); #endif int qemu_create_pidfile(const char *filename); -int qemu_get_thread_id(void); #ifdef _WIN32 static inline void qemu_timersub(const struct timeval *val1, diff --git a/qemu/include/qemu/thread.h b/qemu/include/qemu/thread.h index 2a402673..67e893e1 100644 --- a/qemu/include/qemu/thread.h +++ b/qemu/include/qemu/thread.h @@ -58,8 +58,6 @@ int qemu_thread_create(struct uc_struct *uc, QemuThread *thread, const char *nam void *(*start_routine)(void *), void *arg, int mode); void *qemu_thread_join(QemuThread *thread); -void qemu_thread_get_self(struct uc_struct *uc, QemuThread *thread); -bool qemu_thread_is_self(QemuThread *thread); void qemu_thread_exit(struct uc_struct *uc, void *retval); #endif diff --git a/qemu/include/qom/cpu.h b/qemu/include/qom/cpu.h index fb666d1e..08cb6ba7 100644 --- a/qemu/include/qom/cpu.h +++ b/qemu/include/qom/cpu.h @@ -436,16 +436,6 @@ static inline bool cpu_has_work(CPUState *cpu) return cc->has_work(cpu); } -/** - * qemu_cpu_is_self: - * @cpu: The vCPU to check against. - * - * Checks whether the caller is executing on the vCPU thread. - * - * Returns: %true if called from @cpu's thread, %false otherwise. - */ -bool qemu_cpu_is_self(CPUState *cpu); - /** * qemu_cpu_kick: * @cpu: The vCPU to kick. diff --git a/qemu/include/sysemu/cpus.h b/qemu/include/sysemu/cpus.h index f22ad69d..72e1deec 100644 --- a/qemu/include/sysemu/cpus.h +++ b/qemu/include/sysemu/cpus.h @@ -6,7 +6,6 @@ struct uc_struct; /* cpus.c */ void qemu_init_cpu_loop(struct uc_struct*); int resume_all_vcpus(struct uc_struct*); -void pause_all_vcpus(struct uc_struct*); void cpu_stop_current(struct uc_struct*); void cpu_synchronize_all_states(void); diff --git a/qemu/include/sysemu/iothread.h b/qemu/include/sysemu/iothread.h deleted file mode 100644 index 7c01a61d..00000000 --- a/qemu/include/sysemu/iothread.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Event loop thread - * - * Copyright Red Hat Inc., 2013 - * - * Authors: - * Stefan Hajnoczi - * - * This work is licensed under the terms of the GNU GPL, version 2 or later. - * See the COPYING file in the top-level directory. - * - */ - -#ifndef IOTHREAD_H -#define IOTHREAD_H - -#include "block/aio.h" -#include "qemu/thread.h" - -#define TYPE_IOTHREAD "iothread" - -typedef struct { - Object parent_obj; - - QemuThread thread; - AioContext *ctx; - QemuMutex init_done_lock; - QemuCond init_done_cond; /* is thread initialization done? */ - bool stopping; - int thread_id; -} IOThread; - -#define IOTHREAD(obj) \ - OBJECT_CHECK(IOThread, obj, TYPE_IOTHREAD) - -IOThread *iothread_find(const char *id); -char *iothread_get_id(IOThread *iothread); -AioContext *iothread_get_aio_context(IOThread *iothread); - -#endif /* IOTHREAD_H */ diff --git a/qemu/include/sysemu/sysemu.h b/qemu/include/sysemu/sysemu.h index f2ab6e95..e5c93292 100644 --- a/qemu/include/sysemu/sysemu.h +++ b/qemu/include/sysemu/sysemu.h @@ -2,8 +2,6 @@ #define SYSEMU_H /* Misc. things related to the system emulator. */ -#include "qemu/main-loop.h" - #include "qemu/timer.h" #include "qapi/error.h" diff --git a/qemu/m68k.h b/qemu/m68k.h index 8e41d569..bb37dedb 100644 --- a/qemu/m68k.h +++ b/qemu/m68k.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_m68k #define par_write par_write_m68k #define patch_reloc patch_reloc_m68k -#define pause_all_vcpus pause_all_vcpus_m68k #define phys_map_node_alloc phys_map_node_alloc_m68k #define phys_map_node_reserve phys_map_node_reserve_m68k #define phys_mem_alloc phys_mem_alloc_m68k @@ -2417,9 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_m68k #define qemu_clock_ptr qemu_clock_ptr_m68k #define qemu_clocks qemu_clocks_m68k -#define qemu_cond_destroy qemu_cond_destroy_m68k -#define qemu_cpu_is_self qemu_cpu_is_self_m68k -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_m68k #define qemu_daemon qemu_daemon_m68k #define qemu_event_destroy qemu_event_destroy_m68k #define qemu_event_init qemu_event_init_m68k @@ -2445,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_m68k #define qemu_loglevel_mask qemu_loglevel_mask_m68k #define qemu_log_vprintf qemu_log_vprintf_m68k -#define qemu_mutex_destroy qemu_mutex_destroy_m68k #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_m68k #define qemu_mutex_trylock qemu_mutex_trylock_m68k #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_m68k @@ -2516,9 +2511,7 @@ #define qemu_st_helpers qemu_st_helpers_m68k #define qemu_strnlen qemu_strnlen_m68k #define qemu_strsep qemu_strsep_m68k -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_m68k #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_m68k -#define qemu_thread_exit qemu_thread_exit_m68k #define qemu_try_memalign qemu_try_memalign_m68k #define qentry_destroy qentry_destroy_m68k #define qerror_human qerror_human_m68k diff --git a/qemu/main-loop.c b/qemu/main-loop.c index bb7c3d02..9d7d6290 100644 --- a/qemu/main-loop.c +++ b/qemu/main-loop.c @@ -90,6 +90,9 @@ static void qemu_cpu_kick_thread(CPUState *cpu) GetLastError()); exit(1); } + + CloseHandle(cpu->hThread); + cpu->hThread = 0; } #endif } diff --git a/qemu/memory.c b/qemu/memory.c index af38155f..3ab5c7a3 100644 --- a/qemu/memory.c +++ b/qemu/memory.c @@ -70,6 +70,7 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) { int i; target_ulong addr; + Object *obj; // Make sure all pages associated with the MemoryRegion are flushed // Only need to do this if we are in a running state @@ -87,8 +88,12 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) //shift remainder of array down over deleted pointer 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); + obj = OBJECT(mr); + obj->ref = 1; + obj->free = g_free; g_free(mr->ioeventfds); + g_free((char *)mr->name); + mr->name = NULL; break; } } @@ -97,6 +102,7 @@ void memory_unmap(struct uc_struct *uc, MemoryRegion *mr) int memory_free(struct uc_struct *uc) { MemoryRegion *mr; + Object *obj; int i; get_system_memory(uc)->enabled = false; @@ -105,9 +111,10 @@ int memory_free(struct uc_struct *uc) mr->enabled = false; memory_region_del_subregion(get_system_memory(uc), mr); mr->destructor(mr); - g_free((char *)mr->name); + obj = OBJECT(mr); + obj->ref = 1; + obj->free = g_free; g_free(mr->ioeventfds); - g_free(mr); } return 0; @@ -948,6 +955,7 @@ void memory_region_init(struct uc_struct *uc, MemoryRegion *mr, { if (!owner) { owner = qdev_get_machine(uc); + uc->owner = owner; } object_initialize(uc, mr, sizeof(*mr), TYPE_MEMORY_REGION); diff --git a/qemu/mips.h b/qemu/mips.h index 0861ed05..58113dce 100644 --- a/qemu/mips.h +++ b/qemu/mips.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_mips #define par_write par_write_mips #define patch_reloc patch_reloc_mips -#define pause_all_vcpus pause_all_vcpus_mips #define phys_map_node_alloc phys_map_node_alloc_mips #define phys_map_node_reserve phys_map_node_reserve_mips #define phys_mem_alloc phys_mem_alloc_mips @@ -2417,9 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_mips #define qemu_clock_ptr qemu_clock_ptr_mips #define qemu_clocks qemu_clocks_mips -#define qemu_cond_destroy qemu_cond_destroy_mips -#define qemu_cpu_is_self qemu_cpu_is_self_mips -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_mips #define qemu_daemon qemu_daemon_mips #define qemu_event_destroy qemu_event_destroy_mips #define qemu_event_init qemu_event_init_mips @@ -2445,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_mips #define qemu_loglevel_mask qemu_loglevel_mask_mips #define qemu_log_vprintf qemu_log_vprintf_mips -#define qemu_mutex_destroy qemu_mutex_destroy_mips #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_mips #define qemu_mutex_trylock qemu_mutex_trylock_mips #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_mips @@ -2516,9 +2511,7 @@ #define qemu_st_helpers qemu_st_helpers_mips #define qemu_strnlen qemu_strnlen_mips #define qemu_strsep qemu_strsep_mips -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_mips #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_mips -#define qemu_thread_exit qemu_thread_exit_mips #define qemu_try_memalign qemu_try_memalign_mips #define qentry_destroy qentry_destroy_mips #define qerror_human qerror_human_mips diff --git a/qemu/mips64.h b/qemu/mips64.h index be1a4b4c..d1a106f0 100644 --- a/qemu/mips64.h +++ b/qemu/mips64.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_mips64 #define par_write par_write_mips64 #define patch_reloc patch_reloc_mips64 -#define pause_all_vcpus pause_all_vcpus_mips64 #define phys_map_node_alloc phys_map_node_alloc_mips64 #define phys_map_node_reserve phys_map_node_reserve_mips64 #define phys_mem_alloc phys_mem_alloc_mips64 @@ -2417,9 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_mips64 #define qemu_clock_ptr qemu_clock_ptr_mips64 #define qemu_clocks qemu_clocks_mips64 -#define qemu_cond_destroy qemu_cond_destroy_mips64 -#define qemu_cpu_is_self qemu_cpu_is_self_mips64 -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_mips64 #define qemu_daemon qemu_daemon_mips64 #define qemu_event_destroy qemu_event_destroy_mips64 #define qemu_event_init qemu_event_init_mips64 @@ -2445,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_mips64 #define qemu_loglevel_mask qemu_loglevel_mask_mips64 #define qemu_log_vprintf qemu_log_vprintf_mips64 -#define qemu_mutex_destroy qemu_mutex_destroy_mips64 #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_mips64 #define qemu_mutex_trylock qemu_mutex_trylock_mips64 #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_mips64 @@ -2516,9 +2511,7 @@ #define qemu_st_helpers qemu_st_helpers_mips64 #define qemu_strnlen qemu_strnlen_mips64 #define qemu_strsep qemu_strsep_mips64 -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_mips64 #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_mips64 -#define qemu_thread_exit qemu_thread_exit_mips64 #define qemu_try_memalign qemu_try_memalign_mips64 #define qentry_destroy qentry_destroy_mips64 #define qerror_human qerror_human_mips64 diff --git a/qemu/mips64el.h b/qemu/mips64el.h index 9e144d9b..95505a7b 100644 --- a/qemu/mips64el.h +++ b/qemu/mips64el.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_mips64el #define par_write par_write_mips64el #define patch_reloc patch_reloc_mips64el -#define pause_all_vcpus pause_all_vcpus_mips64el #define phys_map_node_alloc phys_map_node_alloc_mips64el #define phys_map_node_reserve phys_map_node_reserve_mips64el #define phys_mem_alloc phys_mem_alloc_mips64el @@ -2417,9 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_mips64el #define qemu_clock_ptr qemu_clock_ptr_mips64el #define qemu_clocks qemu_clocks_mips64el -#define qemu_cond_destroy qemu_cond_destroy_mips64el -#define qemu_cpu_is_self qemu_cpu_is_self_mips64el -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_mips64el #define qemu_daemon qemu_daemon_mips64el #define qemu_event_destroy qemu_event_destroy_mips64el #define qemu_event_init qemu_event_init_mips64el @@ -2445,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_mips64el #define qemu_loglevel_mask qemu_loglevel_mask_mips64el #define qemu_log_vprintf qemu_log_vprintf_mips64el -#define qemu_mutex_destroy qemu_mutex_destroy_mips64el #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_mips64el #define qemu_mutex_trylock qemu_mutex_trylock_mips64el #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_mips64el @@ -2516,9 +2511,7 @@ #define qemu_st_helpers qemu_st_helpers_mips64el #define qemu_strnlen qemu_strnlen_mips64el #define qemu_strsep qemu_strsep_mips64el -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_mips64el #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_mips64el -#define qemu_thread_exit qemu_thread_exit_mips64el #define qemu_try_memalign qemu_try_memalign_mips64el #define qentry_destroy qentry_destroy_mips64el #define qerror_human qerror_human_mips64el diff --git a/qemu/mipsel.h b/qemu/mipsel.h index 8fb00f62..beabca5e 100644 --- a/qemu/mipsel.h +++ b/qemu/mipsel.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_mipsel #define par_write par_write_mipsel #define patch_reloc patch_reloc_mipsel -#define pause_all_vcpus pause_all_vcpus_mipsel #define phys_map_node_alloc phys_map_node_alloc_mipsel #define phys_map_node_reserve phys_map_node_reserve_mipsel #define phys_mem_alloc phys_mem_alloc_mipsel @@ -2417,9 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_mipsel #define qemu_clock_ptr qemu_clock_ptr_mipsel #define qemu_clocks qemu_clocks_mipsel -#define qemu_cond_destroy qemu_cond_destroy_mipsel -#define qemu_cpu_is_self qemu_cpu_is_self_mipsel -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_mipsel #define qemu_daemon qemu_daemon_mipsel #define qemu_event_destroy qemu_event_destroy_mipsel #define qemu_event_init qemu_event_init_mipsel @@ -2445,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_mipsel #define qemu_loglevel_mask qemu_loglevel_mask_mipsel #define qemu_log_vprintf qemu_log_vprintf_mipsel -#define qemu_mutex_destroy qemu_mutex_destroy_mipsel #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_mipsel #define qemu_mutex_trylock qemu_mutex_trylock_mipsel #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_mipsel @@ -2516,9 +2511,7 @@ #define qemu_st_helpers qemu_st_helpers_mipsel #define qemu_strnlen qemu_strnlen_mipsel #define qemu_strsep qemu_strsep_mipsel -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_mipsel #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_mipsel -#define qemu_thread_exit qemu_thread_exit_mipsel #define qemu_try_memalign qemu_try_memalign_mipsel #define qentry_destroy qentry_destroy_mipsel #define qerror_human qerror_human_mipsel diff --git a/qemu/powerpc.h b/qemu/powerpc.h index 5d2f53f2..6b5e109d 100644 --- a/qemu/powerpc.h +++ b/qemu/powerpc.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_powerpc #define par_write par_write_powerpc #define patch_reloc patch_reloc_powerpc -#define pause_all_vcpus pause_all_vcpus_powerpc #define phys_map_node_alloc phys_map_node_alloc_powerpc #define phys_map_node_reserve phys_map_node_reserve_powerpc #define phys_mem_alloc phys_mem_alloc_powerpc @@ -2417,9 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_powerpc #define qemu_clock_ptr qemu_clock_ptr_powerpc #define qemu_clocks qemu_clocks_powerpc -#define qemu_cond_destroy qemu_cond_destroy_powerpc -#define qemu_cpu_is_self qemu_cpu_is_self_powerpc -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_powerpc #define qemu_daemon qemu_daemon_powerpc #define qemu_event_destroy qemu_event_destroy_powerpc #define qemu_event_init qemu_event_init_powerpc @@ -2445,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_powerpc #define qemu_loglevel_mask qemu_loglevel_mask_powerpc #define qemu_log_vprintf qemu_log_vprintf_powerpc -#define qemu_mutex_destroy qemu_mutex_destroy_powerpc #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_powerpc #define qemu_mutex_trylock qemu_mutex_trylock_powerpc #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_powerpc @@ -2516,9 +2511,7 @@ #define qemu_st_helpers qemu_st_helpers_powerpc #define qemu_strnlen qemu_strnlen_powerpc #define qemu_strsep qemu_strsep_powerpc -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_powerpc #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_powerpc -#define qemu_thread_exit qemu_thread_exit_powerpc #define qemu_try_memalign qemu_try_memalign_powerpc #define qentry_destroy qentry_destroy_powerpc #define qerror_human qerror_human_powerpc diff --git a/qemu/sparc.h b/qemu/sparc.h index cf04547f..32f5512d 100644 --- a/qemu/sparc.h +++ b/qemu/sparc.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_sparc #define par_write par_write_sparc #define patch_reloc patch_reloc_sparc -#define pause_all_vcpus pause_all_vcpus_sparc #define phys_map_node_alloc phys_map_node_alloc_sparc #define phys_map_node_reserve phys_map_node_reserve_sparc #define phys_mem_alloc phys_mem_alloc_sparc @@ -2417,9 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_sparc #define qemu_clock_ptr qemu_clock_ptr_sparc #define qemu_clocks qemu_clocks_sparc -#define qemu_cond_destroy qemu_cond_destroy_sparc -#define qemu_cpu_is_self qemu_cpu_is_self_sparc -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_sparc #define qemu_daemon qemu_daemon_sparc #define qemu_event_destroy qemu_event_destroy_sparc #define qemu_event_init qemu_event_init_sparc @@ -2445,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_sparc #define qemu_loglevel_mask qemu_loglevel_mask_sparc #define qemu_log_vprintf qemu_log_vprintf_sparc -#define qemu_mutex_destroy qemu_mutex_destroy_sparc #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_sparc #define qemu_mutex_trylock qemu_mutex_trylock_sparc #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_sparc @@ -2516,9 +2511,7 @@ #define qemu_st_helpers qemu_st_helpers_sparc #define qemu_strnlen qemu_strnlen_sparc #define qemu_strsep qemu_strsep_sparc -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_sparc #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_sparc -#define qemu_thread_exit qemu_thread_exit_sparc #define qemu_try_memalign qemu_try_memalign_sparc #define qentry_destroy qentry_destroy_sparc #define qerror_human qerror_human_sparc diff --git a/qemu/sparc64.h b/qemu/sparc64.h index 2195b1d6..d42eb1fd 100644 --- a/qemu/sparc64.h +++ b/qemu/sparc64.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_sparc64 #define par_write par_write_sparc64 #define patch_reloc patch_reloc_sparc64 -#define pause_all_vcpus pause_all_vcpus_sparc64 #define phys_map_node_alloc phys_map_node_alloc_sparc64 #define phys_map_node_reserve phys_map_node_reserve_sparc64 #define phys_mem_alloc phys_mem_alloc_sparc64 @@ -2417,9 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_sparc64 #define qemu_clock_ptr qemu_clock_ptr_sparc64 #define qemu_clocks qemu_clocks_sparc64 -#define qemu_cond_destroy qemu_cond_destroy_sparc64 -#define qemu_cpu_is_self qemu_cpu_is_self_sparc64 -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_sparc64 #define qemu_daemon qemu_daemon_sparc64 #define qemu_event_destroy qemu_event_destroy_sparc64 #define qemu_event_init qemu_event_init_sparc64 @@ -2445,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_sparc64 #define qemu_loglevel_mask qemu_loglevel_mask_sparc64 #define qemu_log_vprintf qemu_log_vprintf_sparc64 -#define qemu_mutex_destroy qemu_mutex_destroy_sparc64 #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_sparc64 #define qemu_mutex_trylock qemu_mutex_trylock_sparc64 #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_sparc64 @@ -2516,9 +2511,7 @@ #define qemu_st_helpers qemu_st_helpers_sparc64 #define qemu_strnlen qemu_strnlen_sparc64 #define qemu_strsep qemu_strsep_sparc64 -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_sparc64 #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_sparc64 -#define qemu_thread_exit qemu_thread_exit_sparc64 #define qemu_try_memalign qemu_try_memalign_sparc64 #define qentry_destroy qentry_destroy_sparc64 #define qerror_human qerror_human_sparc64 diff --git a/qemu/target-arm/unicorn.h b/qemu/target-arm/unicorn.h index 797ef979..0b3fb93d 100644 --- a/qemu/target-arm/unicorn.h +++ b/qemu/target-arm/unicorn.h @@ -5,10 +5,10 @@ #define UC_QEMU_TARGET_ARM_H // functions to read & write registers -int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value); -int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); -int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value); -int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); +int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count); +int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count); +int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count); +int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count); void arm_reg_reset(struct uc_struct *uc); void arm64_reg_reset(struct uc_struct *uc); diff --git a/qemu/target-arm/unicorn_aarch64.c b/qemu/target-arm/unicorn_aarch64.c index 1ce9d6eb..e2c593a6 100644 --- a/qemu/target-arm/unicorn_aarch64.c +++ b/qemu/target-arm/unicorn_aarch64.c @@ -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) @@ -25,6 +15,23 @@ static void arm64_set_pc(struct uc_struct *uc, uint64_t address) ((CPUARMState *)uc->current_cpu->env_ptr)->pc = address; } +void arm64_release(void* ctx); + +void arm64_release(void* ctx) +{ + TCGContext *s = (TCGContext *) ctx; + + g_free(s->tb_ctx.tbs); + struct uc_struct* uc = s->uc; + ARMCPU* cpu = (ARMCPU*) uc->cpu; + g_free(cpu->cpreg_indexes); + g_free(cpu->cpreg_values); + g_free(cpu->cpreg_vmstate_indexes); + g_free(cpu->cpreg_vmstate_values); + + release_common(ctx); +} + void arm64_reg_reset(struct uc_struct *uc) { CPUArchState *env = first_cpu->env_ptr; @@ -33,62 +40,67 @@ void arm64_reg_reset(struct uc_struct *uc) env->pc = 0; } -int arm64_reg_read(struct uc_struct *uc, unsigned int regid, void *value) +int arm64_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) - *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0]; - else { - switch(regid) { - default: break; - case UC_ARM64_REG_X29: - *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[29]; - break; - case UC_ARM64_REG_X30: - *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[30]; - break; - case UC_ARM64_REG_PC: - *(uint64_t *)value = ARM_CPU(uc, mycpu)->env.pc; - break; - case UC_ARM64_REG_SP: - *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[31]; - break; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) + *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0]; + else { + switch(regid) { + default: break; + case UC_ARM64_REG_X29: + *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[29]; + break; + case UC_ARM64_REG_X30: + *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[30]; + break; + case UC_ARM64_REG_PC: + *(uint64_t *)value = ARM_CPU(uc, mycpu)->env.pc; + break; + case UC_ARM64_REG_SP: + *(int64_t *)value = ARM_CPU(uc, mycpu)->env.xregs[31]; + 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 arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) +int arm64_reg_write(struct uc_struct *uc, unsigned int *regs, void* const* vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) - ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0] = *(uint64_t *)value; - else { - switch(regid) { - default: break; - case UC_ARM64_REG_X29: - ARM_CPU(uc, mycpu)->env.xregs[29] = *(uint64_t *)value; - break; - case UC_ARM64_REG_X30: - ARM_CPU(uc, mycpu)->env.xregs[30] = *(uint64_t *)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; - break; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + if (regid >= UC_ARM64_REG_X0 && regid <= UC_ARM64_REG_X28) + ARM_CPU(uc, mycpu)->env.xregs[regid - UC_ARM64_REG_X0] = *(uint64_t *)value; + else { + switch(regid) { + default: break; + case UC_ARM64_REG_X29: + ARM_CPU(uc, mycpu)->env.xregs[29] = *(uint64_t *)value; + break; + case UC_ARM64_REG_X30: + ARM_CPU(uc, mycpu)->env.xregs[30] = *(uint64_t *)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; + break; + } } } @@ -106,5 +118,6 @@ void arm64_uc_init(struct uc_struct* uc) uc->reg_write = arm64_reg_write; uc->reg_reset = arm64_reg_reset; uc->set_pc = arm64_set_pc; + uc->release = arm64_release; uc_common_init(uc); } diff --git a/qemu/target-arm/unicorn_arm.c b/qemu/target-arm/unicorn_arm.c index 95ea812d..bf7c5dda 100644 --- a/qemu/target-arm/unicorn_arm.c +++ b/qemu/target-arm/unicorn_arm.c @@ -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) @@ -25,6 +16,23 @@ static void arm_set_pc(struct uc_struct *uc, uint64_t address) ((CPUARMState *)uc->current_cpu->env_ptr)->regs[15] = address; } +void arm_release(void* ctx); + +void arm_release(void* ctx) +{ + TCGContext *s = (TCGContext *) ctx; + + g_free(s->tb_ctx.tbs); + struct uc_struct* uc = s->uc; + ARMCPU* cpu = (ARMCPU*) uc->cpu; + g_free(cpu->cpreg_indexes); + g_free(cpu->cpreg_values); + g_free(cpu->cpreg_vmstate_indexes); + g_free(cpu->cpreg_vmstate_values); + + release_common(ctx); +} + void arm_reg_reset(struct uc_struct *uc) { (void)uc; @@ -36,67 +44,72 @@ void arm_reg_reset(struct uc_struct *uc) env->pc = 0; } -int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value) +int arm_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count) { CPUState *mycpu; + int i; mycpu = first_cpu; - 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; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + 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) +int arm_reg_write(struct uc_struct *uc, unsigned int *regs, void* const* vals, int count) { CPUState *mycpu = first_cpu; + int i; - 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); + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + 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); - break; + break; + } } } @@ -109,6 +122,7 @@ static bool arm_stop_interrupt(int intno) default: return false; case EXCP_UDEF: + case EXCP_YIELD: return true; } } @@ -141,6 +155,7 @@ 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->release = arm_release; uc->query = arm_query; uc_common_init(uc); } diff --git a/qemu/target-i386/seg_helper.c b/qemu/target-i386/seg_helper.c index 4702dfcc..326fb870 100644 --- a/qemu/target-i386/seg_helper.c +++ b/qemu/target-i386/seg_helper.c @@ -2556,7 +2556,6 @@ void helper_verw(CPUX86State *env, target_ulong selector1) CC_SRC = eflags | CC_Z; } -#if defined(CONFIG_USER_ONLY) void cpu_x86_load_seg(CPUX86State *env, int seg_reg, int selector) { if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) { @@ -2570,7 +2569,6 @@ void cpu_x86_load_seg(CPUX86State *env, int seg_reg, int selector) helper_load_seg(env, seg_reg, selector); } } -#endif /* check if Port I/O is allowed in TSS */ static inline void check_io(CPUX86State *env, int addr, int size) diff --git a/qemu/target-i386/translate.c b/qemu/target-i386/translate.c index d68cb516..e176c417 100644 --- a/qemu/target-i386/translate.c +++ b/qemu/target-i386/translate.c @@ -4721,6 +4721,19 @@ 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, diff --git a/qemu/target-i386/unicorn.c b/qemu/target-i386/unicorn.c index c8436b9b..004e2a4a 100644 --- a/qemu/target-i386/unicorn.c +++ b/qemu/target-i386/unicorn.c @@ -2,20 +2,14 @@ /* By Nguyen Anh Quynh , 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" #include /* needed for uc_x86_mmr */ - -#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 x86_set_pc(struct uc_struct *uc, uint64_t address) @@ -27,9 +21,11 @@ void x86_release(void *ctx); void x86_release(void *ctx) { - release_common(ctx); + int i; TCGContext *s = (TCGContext *) ctx; + release_common(ctx); + // arch specific g_free(s->cpu_A0); g_free(s->cpu_T[0]); @@ -41,7 +37,6 @@ void x86_release(void *ctx) g_free(s->cpu_cc_src); g_free(s->cpu_cc_src2); - int i; for (i = 0; i < CPU_NB_REGS; ++i) { g_free(s->cpu_regs[i]); } @@ -142,890 +137,979 @@ void x86_reg_reset(struct uc_struct *uc) } } -int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value) +int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count) { CPUState *mycpu = first_cpu; + int i; - switch(uc->mode) { - default: - break; - case UC_MODE_16: - switch(regid) { - default: break; - case UC_X86_REG_ES: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_ES].selector; - return 0; - case UC_X86_REG_SS: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_SS].selector; - return 0; - case UC_X86_REG_DS: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_DS].selector; - return 0; - case UC_X86_REG_FS: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_FS].selector; - return 0; - case UC_X86_REG_GS: - *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].selector; - return 0; - } - // fall-thru - case UC_MODE_32: - switch(regid) { - default: - break; - case UC_X86_REG_CR0 ... UC_X86_REG_CR4: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.cr[regid - UC_X86_REG_CR0]; - break; - case UC_X86_REG_DR0 ... UC_X86_REG_DR7: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.dr[regid - UC_X86_REG_DR0]; - break; - case UC_X86_REG_EFLAGS: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.eflags; - break; - case UC_X86_REG_EAX: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EAX]; - break; - case UC_X86_REG_AX: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EAX]); - break; - case UC_X86_REG_AH: - *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EAX]); - break; - case UC_X86_REG_AL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EAX]); - break; - case UC_X86_REG_EBX: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EBX]; - break; - case UC_X86_REG_BX: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBX]); - break; - case UC_X86_REG_BH: - *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EBX]); - break; - case UC_X86_REG_BL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBX]); - break; - case UC_X86_REG_ECX: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ECX]; - break; - case UC_X86_REG_CX: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ECX]); - break; - case UC_X86_REG_CH: - *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_ECX]); - break; - case UC_X86_REG_CL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ECX]); - break; - case UC_X86_REG_EDX: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EDX]; - break; - case UC_X86_REG_DX: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDX]); - break; - case UC_X86_REG_DH: - *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EDX]); - break; - case UC_X86_REG_DL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDX]); - break; - case UC_X86_REG_ESP: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ESP]; - break; - case UC_X86_REG_SP: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESP]); - break; - case UC_X86_REG_EBP: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EBP]; - break; - case UC_X86_REG_BP: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBP]); - break; - case UC_X86_REG_ESI: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ESI]; - break; - case UC_X86_REG_SI: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESI]); - break; - case UC_X86_REG_EDI: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EDI]; - break; - case UC_X86_REG_DI: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDI]); - break; - case UC_X86_REG_EIP: - *(int32_t *)value = X86_CPU(uc, mycpu)->env.eip; - break; - case UC_X86_REG_IP: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.eip); - break; - case UC_X86_REG_CS: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_CS].selector; - break; - case UC_X86_REG_DS: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_DS].selector; - break; - case UC_X86_REG_SS: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_SS].selector; - break; - case UC_X86_REG_ES: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_ES].selector; - break; - case UC_X86_REG_FS: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_FS].selector; - break; - case UC_X86_REG_GS: - *(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; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + 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); + } + continue; + 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; + } + continue; + case UC_X86_REG_FPCW: + *(uint16_t*) value = X86_CPU(uc, mycpu)->env.fpuc; + continue; + 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; + } + continue; + } + + switch(uc->mode) { + default: + break; + case UC_MODE_16: + switch(regid) { + default: break; + case UC_X86_REG_ES: + *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_ES].selector; + continue; + case UC_X86_REG_SS: + *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_SS].selector; + continue; + case UC_X86_REG_DS: + *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_DS].selector; + continue; + case UC_X86_REG_FS: + *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_FS].selector; + continue; + case UC_X86_REG_GS: + *(int16_t *)value = X86_CPU(uc, mycpu)->env.segs[R_GS].selector; + continue; + } + // fall-thru + case UC_MODE_32: + switch(regid) { + default: + break; + case UC_X86_REG_CR0 ... UC_X86_REG_CR4: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.cr[regid - UC_X86_REG_CR0]; + break; + case UC_X86_REG_DR0 ... UC_X86_REG_DR7: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.dr[regid - UC_X86_REG_DR0]; + break; + case UC_X86_REG_EFLAGS: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.eflags; + break; + case UC_X86_REG_EAX: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EAX]; + break; + case UC_X86_REG_AX: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EAX]); + break; + case UC_X86_REG_AH: + *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EAX]); + break; + case UC_X86_REG_AL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EAX]); + break; + case UC_X86_REG_EBX: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EBX]; + break; + case UC_X86_REG_BX: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBX]); + break; + case UC_X86_REG_BH: + *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EBX]); + break; + case UC_X86_REG_BL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBX]); + break; + case UC_X86_REG_ECX: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ECX]; + break; + case UC_X86_REG_CX: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ECX]); + break; + case UC_X86_REG_CH: + *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_ECX]); + break; + case UC_X86_REG_CL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ECX]); + break; + case UC_X86_REG_EDX: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EDX]; + break; + case UC_X86_REG_DX: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDX]); + break; + case UC_X86_REG_DH: + *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EDX]); + break; + case UC_X86_REG_DL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDX]); + break; + case UC_X86_REG_ESP: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ESP]; + break; + case UC_X86_REG_SP: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESP]); + break; + case UC_X86_REG_EBP: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EBP]; + break; + case UC_X86_REG_BP: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBP]); + break; + case UC_X86_REG_ESI: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ESI]; + break; + case UC_X86_REG_SI: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESI]); + break; + case UC_X86_REG_EDI: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EDI]; + break; + case UC_X86_REG_DI: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDI]); + break; + case UC_X86_REG_EIP: + *(int32_t *)value = X86_CPU(uc, mycpu)->env.eip; + break; + case UC_X86_REG_IP: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.eip); + break; + case UC_X86_REG_CS: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_CS].selector; + break; + case UC_X86_REG_DS: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_DS].selector; + break; + case UC_X86_REG_SS: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_SS].selector; + break; + case UC_X86_REG_ES: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_ES].selector; + break; + case UC_X86_REG_FS: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_FS].selector; + break; + case UC_X86_REG_GS: + *(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; #ifdef TARGET_X86_64 - case UC_MODE_64: - switch(regid) { - default: - break; - case UC_X86_REG_CR0 ... UC_X86_REG_CR4: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.cr[regid - UC_X86_REG_CR0]; - break; - case UC_X86_REG_DR0 ... UC_X86_REG_DR7: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.dr[regid - UC_X86_REG_DR0]; - break; - case UC_X86_REG_EFLAGS: - *(int64_t *)value = X86_CPU(uc, mycpu)->env.eflags; - break; - case UC_X86_REG_RAX: - *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EAX]; - break; - case UC_X86_REG_EAX: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EAX]); - break; - case UC_X86_REG_AX: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EAX]); - break; - case UC_X86_REG_AH: - *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EAX]); - break; - case UC_X86_REG_AL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EAX]); - break; - case UC_X86_REG_RBX: - *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EBX]; - break; - case UC_X86_REG_EBX: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EBX]); - break; - case UC_X86_REG_BX: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBX]); - break; - case UC_X86_REG_BH: - *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EBX]); - break; - case UC_X86_REG_BL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBX]); - break; - case UC_X86_REG_RCX: - *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ECX]; - break; - case UC_X86_REG_ECX: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ECX]); - break; - case UC_X86_REG_CX: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ECX]); - break; - case UC_X86_REG_CH: - *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_ECX]); - break; - case UC_X86_REG_CL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ECX]); - break; - case UC_X86_REG_RDX: - *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EDX]; - break; - case UC_X86_REG_EDX: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EDX]); - break; - case UC_X86_REG_DX: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDX]); - break; - case UC_X86_REG_DH: - *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EDX]); - break; - case UC_X86_REG_DL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDX]); - break; - case UC_X86_REG_RSP: - *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ESP]; - break; - case UC_X86_REG_ESP: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ESP]); - break; - case UC_X86_REG_SP: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESP]); - break; - case UC_X86_REG_SPL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ESP]); - break; - case UC_X86_REG_RBP: - *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EBP]; - break; - case UC_X86_REG_EBP: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EBP]); - break; - case UC_X86_REG_BP: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBP]); - break; - case UC_X86_REG_BPL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBP]); - break; - case UC_X86_REG_RSI: - *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ESI]; - break; - case UC_X86_REG_ESI: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ESI]); - break; - case UC_X86_REG_SI: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESI]); - break; - case UC_X86_REG_SIL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ESI]); - break; - case UC_X86_REG_RDI: - *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EDI]; - break; - case UC_X86_REG_EDI: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EDI]); - break; - case UC_X86_REG_DI: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDI]); - break; - case UC_X86_REG_DIL: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDI]); - break; - case UC_X86_REG_RIP: - *(uint64_t *)value = X86_CPU(uc, mycpu)->env.eip; - break; - case UC_X86_REG_EIP: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.eip); - break; - case UC_X86_REG_IP: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.eip); - break; - case UC_X86_REG_CS: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_CS].selector; - break; - case UC_X86_REG_DS: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_DS].selector; - break; - case UC_X86_REG_SS: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_SS].selector; - break; - case UC_X86_REG_ES: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_ES].selector; - break; - case UC_X86_REG_FS: - *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_FS].selector; - break; - case UC_X86_REG_GS: - *(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]); - break; - case UC_X86_REG_R8D: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[8]); - break; - case UC_X86_REG_R8W: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[8]); - break; - case UC_X86_REG_R8B: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[8]); - break; - case UC_X86_REG_R9: - *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[9]); - break; - case UC_X86_REG_R9D: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[9]); - break; - case UC_X86_REG_R9W: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[9]); - break; - case UC_X86_REG_R9B: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[9]); - break; - case UC_X86_REG_R10: - *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[10]); - break; - case UC_X86_REG_R10D: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[10]); - break; - case UC_X86_REG_R10W: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[10]); - break; - case UC_X86_REG_R10B: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[10]); - break; - case UC_X86_REG_R11: - *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[11]); - break; - case UC_X86_REG_R11D: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[11]); - break; - case UC_X86_REG_R11W: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[11]); - break; - case UC_X86_REG_R11B: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[11]); - break; - case UC_X86_REG_R12: - *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[12]); - break; - case UC_X86_REG_R12D: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[12]); - break; - case UC_X86_REG_R12W: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[12]); - break; - case UC_X86_REG_R12B: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[12]); - break; - case UC_X86_REG_R13: - *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[13]); - break; - case UC_X86_REG_R13D: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[13]); - break; - case UC_X86_REG_R13W: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[13]); - break; - case UC_X86_REG_R13B: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[13]); - break; - case UC_X86_REG_R14: - *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[14]); - break; - case UC_X86_REG_R14D: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[14]); - break; - case UC_X86_REG_R14W: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[14]); - break; - case UC_X86_REG_R14B: - *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[14]); - break; - case UC_X86_REG_R15: - *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[15]); - break; - case UC_X86_REG_R15D: - *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[15]); - break; - case UC_X86_REG_R15W: - *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[15]); - break; - 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; + case UC_MODE_64: + switch(regid) { + default: + break; + case UC_X86_REG_CR0 ... UC_X86_REG_CR4: + *(int64_t *)value = X86_CPU(uc, mycpu)->env.cr[regid - UC_X86_REG_CR0]; + break; + case UC_X86_REG_DR0 ... UC_X86_REG_DR7: + *(int64_t *)value = X86_CPU(uc, mycpu)->env.dr[regid - UC_X86_REG_DR0]; + break; + case UC_X86_REG_EFLAGS: + *(int64_t *)value = X86_CPU(uc, mycpu)->env.eflags; + break; + case UC_X86_REG_RAX: + *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EAX]; + break; + case UC_X86_REG_EAX: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EAX]); + break; + case UC_X86_REG_AX: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EAX]); + break; + case UC_X86_REG_AH: + *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EAX]); + break; + case UC_X86_REG_AL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EAX]); + break; + case UC_X86_REG_RBX: + *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EBX]; + break; + case UC_X86_REG_EBX: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EBX]); + break; + case UC_X86_REG_BX: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBX]); + break; + case UC_X86_REG_BH: + *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EBX]); + break; + case UC_X86_REG_BL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBX]); + break; + case UC_X86_REG_RCX: + *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ECX]; + break; + case UC_X86_REG_ECX: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ECX]); + break; + case UC_X86_REG_CX: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ECX]); + break; + case UC_X86_REG_CH: + *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_ECX]); + break; + case UC_X86_REG_CL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ECX]); + break; + case UC_X86_REG_RDX: + *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EDX]; + break; + case UC_X86_REG_EDX: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EDX]); + break; + case UC_X86_REG_DX: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDX]); + break; + case UC_X86_REG_DH: + *(int8_t *)value = READ_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EDX]); + break; + case UC_X86_REG_DL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDX]); + break; + case UC_X86_REG_RSP: + *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ESP]; + break; + case UC_X86_REG_ESP: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ESP]); + break; + case UC_X86_REG_SP: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESP]); + break; + case UC_X86_REG_SPL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ESP]); + break; + case UC_X86_REG_RBP: + *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EBP]; + break; + case UC_X86_REG_EBP: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EBP]); + break; + case UC_X86_REG_BP: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBP]); + break; + case UC_X86_REG_BPL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBP]); + break; + case UC_X86_REG_RSI: + *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_ESI]; + break; + case UC_X86_REG_ESI: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ESI]); + break; + case UC_X86_REG_SI: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESI]); + break; + case UC_X86_REG_SIL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ESI]); + break; + case UC_X86_REG_RDI: + *(uint64_t *)value = X86_CPU(uc, mycpu)->env.regs[R_EDI]; + break; + case UC_X86_REG_EDI: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EDI]); + break; + case UC_X86_REG_DI: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDI]); + break; + case UC_X86_REG_DIL: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDI]); + break; + case UC_X86_REG_RIP: + *(uint64_t *)value = X86_CPU(uc, mycpu)->env.eip; + break; + case UC_X86_REG_EIP: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.eip); + break; + case UC_X86_REG_IP: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.eip); + break; + case UC_X86_REG_CS: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_CS].selector; + break; + case UC_X86_REG_DS: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_DS].selector; + break; + case UC_X86_REG_SS: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_SS].selector; + break; + case UC_X86_REG_ES: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_ES].selector; + break; + case UC_X86_REG_FS: + *(int16_t *)value = (uint16_t)X86_CPU(uc, mycpu)->env.segs[R_FS].selector; + break; + case UC_X86_REG_GS: + *(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]); + break; + case UC_X86_REG_R8D: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[8]); + break; + case UC_X86_REG_R8W: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[8]); + break; + case UC_X86_REG_R8B: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[8]); + break; + case UC_X86_REG_R9: + *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[9]); + break; + case UC_X86_REG_R9D: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[9]); + break; + case UC_X86_REG_R9W: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[9]); + break; + case UC_X86_REG_R9B: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[9]); + break; + case UC_X86_REG_R10: + *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[10]); + break; + case UC_X86_REG_R10D: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[10]); + break; + case UC_X86_REG_R10W: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[10]); + break; + case UC_X86_REG_R10B: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[10]); + break; + case UC_X86_REG_R11: + *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[11]); + break; + case UC_X86_REG_R11D: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[11]); + break; + case UC_X86_REG_R11W: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[11]); + break; + case UC_X86_REG_R11B: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[11]); + break; + case UC_X86_REG_R12: + *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[12]); + break; + case UC_X86_REG_R12D: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[12]); + break; + case UC_X86_REG_R12W: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[12]); + break; + case UC_X86_REG_R12B: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[12]); + break; + case UC_X86_REG_R13: + *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[13]); + break; + case UC_X86_REG_R13D: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[13]); + break; + case UC_X86_REG_R13W: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[13]); + break; + case UC_X86_REG_R13B: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[13]); + break; + case UC_X86_REG_R14: + *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[14]); + break; + case UC_X86_REG_R14D: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[14]); + break; + case UC_X86_REG_R14W: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[14]); + break; + case UC_X86_REG_R14B: + *(int8_t *)value = READ_BYTE_L(X86_CPU(uc, mycpu)->env.regs[14]); + break; + case UC_X86_REG_R15: + *(int64_t *)value = READ_QWORD(X86_CPU(uc, mycpu)->env.regs[15]); + break; + case UC_X86_REG_R15D: + *(int32_t *)value = READ_DWORD(X86_CPU(uc, mycpu)->env.regs[15]); + break; + case UC_X86_REG_R15W: + *(int16_t *)value = READ_WORD(X86_CPU(uc, mycpu)->env.regs[15]); + break; + 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 + } } - 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) +int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count) { CPUState *mycpu = first_cpu; + int i; - switch(uc->mode) { - default: - break; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + 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); + } + continue; + 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; + } + continue; + case UC_X86_REG_FPCW: + X86_CPU(uc, mycpu)->env.fpuc = *(uint16_t *)value; + continue; + 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; + } - case UC_MODE_16: - switch(regid) { - default: break; - case UC_X86_REG_ES: - X86_CPU(uc, mycpu)->env.segs[R_ES].selector = *(uint16_t *)value; - return 0; - case UC_X86_REG_SS: - X86_CPU(uc, mycpu)->env.segs[R_SS].selector = *(uint16_t *)value; - return 0; - case UC_X86_REG_DS: - X86_CPU(uc, mycpu)->env.segs[R_DS].selector = *(uint16_t *)value; - return 0; - case UC_X86_REG_FS: - X86_CPU(uc, mycpu)->env.segs[R_FS].selector = *(uint16_t *)value; - return 0; - case UC_X86_REG_GS: - X86_CPU(uc, mycpu)->env.segs[R_GS].selector = *(uint16_t *)value; - return 0; - } - // fall-thru - case UC_MODE_32: - switch(regid) { - default: - break; - case UC_X86_REG_CR0 ... UC_X86_REG_CR4: - X86_CPU(uc, mycpu)->env.cr[regid - UC_X86_REG_CR0] = *(uint32_t *)value; - break; - case UC_X86_REG_DR0 ... UC_X86_REG_DR7: - X86_CPU(uc, mycpu)->env.dr[regid - UC_X86_REG_DR0] = *(uint32_t *)value; - break; - case UC_X86_REG_EFLAGS: - X86_CPU(uc, mycpu)->env.eflags = *(uint32_t *)value; - X86_CPU(uc, mycpu)->env.eflags0 = *(uint32_t *)value; - break; - case UC_X86_REG_EAX: - X86_CPU(uc, mycpu)->env.regs[R_EAX] = *(uint32_t *)value; - break; - case UC_X86_REG_AX: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint16_t *)value); - break; - case UC_X86_REG_AH: - WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint8_t *)value); - break; - case UC_X86_REG_AL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint8_t *)value); - break; - case UC_X86_REG_EBX: - X86_CPU(uc, mycpu)->env.regs[R_EBX] = *(uint32_t *)value; - break; - case UC_X86_REG_BX: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint16_t *)value); - break; - case UC_X86_REG_BH: - WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint8_t *)value); - break; - case UC_X86_REG_BL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint8_t *)value); - break; - case UC_X86_REG_ECX: - X86_CPU(uc, mycpu)->env.regs[R_ECX] = *(uint32_t *)value; - break; - case UC_X86_REG_CX: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint16_t *)value); - break; - case UC_X86_REG_CH: - WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint8_t *)value); - break; - case UC_X86_REG_CL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint8_t *)value); - break; - case UC_X86_REG_EDX: - X86_CPU(uc, mycpu)->env.regs[R_EDX] = *(uint32_t *)value; - break; - case UC_X86_REG_DX: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint16_t *)value); - break; - case UC_X86_REG_DH: - WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint8_t *)value); - break; - case UC_X86_REG_DL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint8_t *)value); - break; - case UC_X86_REG_ESP: - X86_CPU(uc, mycpu)->env.regs[R_ESP] = *(uint32_t *)value; - break; - case UC_X86_REG_SP: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESP], *(uint16_t *)value); - break; - case UC_X86_REG_EBP: - X86_CPU(uc, mycpu)->env.regs[R_EBP] = *(uint32_t *)value; - break; - case UC_X86_REG_BP: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBP], *(uint16_t *)value); - break; - case UC_X86_REG_ESI: - X86_CPU(uc, mycpu)->env.regs[R_ESI] = *(uint32_t *)value; - break; - case UC_X86_REG_SI: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESI], *(uint16_t *)value); - break; - case UC_X86_REG_EDI: - X86_CPU(uc, mycpu)->env.regs[R_EDI] = *(uint32_t *)value; - break; - case UC_X86_REG_DI: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDI], *(uint16_t *)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].selector = *(uint16_t *)value; - break; - case UC_X86_REG_DS: - 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].selector = *(uint16_t *)value; - break; - case UC_X86_REG_ES: - 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].selector = *(uint16_t *)value; - break; - case UC_X86_REG_GS: - 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; + continue; + } + break; + } + + switch(uc->mode) { + default: + break; + + case UC_MODE_16: + switch(regid) { + default: break; + case UC_X86_REG_ES: + X86_CPU(uc, mycpu)->env.segs[R_ES].selector = *(uint16_t *)value; + continue; + case UC_X86_REG_SS: + X86_CPU(uc, mycpu)->env.segs[R_SS].selector = *(uint16_t *)value; + continue; + case UC_X86_REG_DS: + X86_CPU(uc, mycpu)->env.segs[R_DS].selector = *(uint16_t *)value; + continue; + case UC_X86_REG_FS: + X86_CPU(uc, mycpu)->env.segs[R_FS].selector = *(uint16_t *)value; + continue; + case UC_X86_REG_GS: + X86_CPU(uc, mycpu)->env.segs[R_GS].selector = *(uint16_t *)value; + continue; + } + // fall-thru + case UC_MODE_32: + switch(regid) { + default: + break; + case UC_X86_REG_CR0 ... UC_X86_REG_CR4: + X86_CPU(uc, mycpu)->env.cr[regid - UC_X86_REG_CR0] = *(uint32_t *)value; + break; + case UC_X86_REG_DR0 ... UC_X86_REG_DR7: + X86_CPU(uc, mycpu)->env.dr[regid - UC_X86_REG_DR0] = *(uint32_t *)value; + break; + case UC_X86_REG_EFLAGS: + X86_CPU(uc, mycpu)->env.eflags = *(uint32_t *)value; + X86_CPU(uc, mycpu)->env.eflags0 = *(uint32_t *)value; + break; + case UC_X86_REG_EAX: + X86_CPU(uc, mycpu)->env.regs[R_EAX] = *(uint32_t *)value; + break; + case UC_X86_REG_AX: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint16_t *)value); + break; + case UC_X86_REG_AH: + WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint8_t *)value); + break; + case UC_X86_REG_AL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint8_t *)value); + break; + case UC_X86_REG_EBX: + X86_CPU(uc, mycpu)->env.regs[R_EBX] = *(uint32_t *)value; + break; + case UC_X86_REG_BX: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint16_t *)value); + break; + case UC_X86_REG_BH: + WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint8_t *)value); + break; + case UC_X86_REG_BL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint8_t *)value); + break; + case UC_X86_REG_ECX: + X86_CPU(uc, mycpu)->env.regs[R_ECX] = *(uint32_t *)value; + break; + case UC_X86_REG_CX: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint16_t *)value); + break; + case UC_X86_REG_CH: + WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint8_t *)value); + break; + case UC_X86_REG_CL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint8_t *)value); + break; + case UC_X86_REG_EDX: + X86_CPU(uc, mycpu)->env.regs[R_EDX] = *(uint32_t *)value; + break; + case UC_X86_REG_DX: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint16_t *)value); + break; + case UC_X86_REG_DH: + WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint8_t *)value); + break; + case UC_X86_REG_DL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint8_t *)value); + break; + case UC_X86_REG_ESP: + X86_CPU(uc, mycpu)->env.regs[R_ESP] = *(uint32_t *)value; + break; + case UC_X86_REG_SP: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESP], *(uint16_t *)value); + break; + case UC_X86_REG_EBP: + X86_CPU(uc, mycpu)->env.regs[R_EBP] = *(uint32_t *)value; + break; + case UC_X86_REG_BP: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBP], *(uint16_t *)value); + break; + case UC_X86_REG_ESI: + X86_CPU(uc, mycpu)->env.regs[R_ESI] = *(uint32_t *)value; + break; + case UC_X86_REG_SI: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESI], *(uint16_t *)value); + break; + case UC_X86_REG_EDI: + X86_CPU(uc, mycpu)->env.regs[R_EDI] = *(uint32_t *)value; + break; + case UC_X86_REG_DI: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDI], *(uint16_t *)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: + cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_CS, *(uint16_t *)value); + break; + case UC_X86_REG_DS: + cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_DS, *(uint16_t *)value); + break; + case UC_X86_REG_SS: + cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_SS, *(uint16_t *)value); + break; + case UC_X86_REG_ES: + cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_ES, *(uint16_t *)value); + break; + case UC_X86_REG_FS: + cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_FS, *(uint16_t *)value); + break; + case UC_X86_REG_GS: + cpu_x86_load_seg(&X86_CPU(uc, mycpu)->env, R_GS, *(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; #ifdef TARGET_X86_64 - case UC_MODE_64: - switch(regid) { - default: - break; - case UC_X86_REG_CR0 ... UC_X86_REG_CR4: - X86_CPU(uc, mycpu)->env.cr[regid - UC_X86_REG_CR0] = *(uint64_t *)value; - break; - case UC_X86_REG_DR0 ... UC_X86_REG_DR7: - X86_CPU(uc, mycpu)->env.dr[regid - UC_X86_REG_DR0] = *(uint64_t *)value; - break; - case UC_X86_REG_EFLAGS: - X86_CPU(uc, mycpu)->env.eflags = *(uint64_t *)value; - X86_CPU(uc, mycpu)->env.eflags0 = *(uint64_t *)value; - break; - case UC_X86_REG_RAX: - X86_CPU(uc, mycpu)->env.regs[R_EAX] = *(uint64_t *)value; - break; - case UC_X86_REG_EAX: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint32_t *)value); - break; - case UC_X86_REG_AX: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint16_t *)value); - break; - case UC_X86_REG_AH: - WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint8_t *)value); - break; - case UC_X86_REG_AL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint8_t *)value); - break; - case UC_X86_REG_RBX: - X86_CPU(uc, mycpu)->env.regs[R_EBX] = *(uint64_t *)value; - break; - case UC_X86_REG_EBX: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint32_t *)value); - break; - case UC_X86_REG_BX: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint16_t *)value); - break; - case UC_X86_REG_BH: - WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint8_t *)value); - break; - case UC_X86_REG_BL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint8_t *)value); - break; - case UC_X86_REG_RCX: - X86_CPU(uc, mycpu)->env.regs[R_ECX] = *(uint64_t *)value; - break; - case UC_X86_REG_ECX: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint32_t *)value); - break; - case UC_X86_REG_CX: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint16_t *)value); - break; - case UC_X86_REG_CH: - WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint8_t *)value); - break; - case UC_X86_REG_CL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint8_t *)value); - break; - case UC_X86_REG_RDX: - X86_CPU(uc, mycpu)->env.regs[R_EDX] = *(uint64_t *)value; - break; - case UC_X86_REG_EDX: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint32_t *)value); - break; - case UC_X86_REG_DX: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint16_t *)value); - break; - case UC_X86_REG_DH: - WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint8_t *)value); - break; - case UC_X86_REG_DL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint8_t *)value); - break; - case UC_X86_REG_RSP: - X86_CPU(uc, mycpu)->env.regs[R_ESP] = *(uint64_t *)value; - break; - case UC_X86_REG_ESP: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ESP], *(uint32_t *)value); - break; - case UC_X86_REG_SP: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESP], *(uint16_t *)value); - break; - case UC_X86_REG_SPL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ESP], *(uint8_t *)value); - break; - case UC_X86_REG_RBP: - X86_CPU(uc, mycpu)->env.regs[R_EBP] = *(uint64_t *)value; - break; - case UC_X86_REG_EBP: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EBP], *(uint32_t *)value); - break; - case UC_X86_REG_BP: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBP], *(uint16_t *)value); - break; - case UC_X86_REG_BPL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBP], *(uint8_t *)value); - break; - case UC_X86_REG_RSI: - X86_CPU(uc, mycpu)->env.regs[R_ESI] = *(uint64_t *)value; - break; - case UC_X86_REG_ESI: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ESI], *(uint32_t *)value); - break; - case UC_X86_REG_SI: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESI], *(uint16_t *)value); - break; - case UC_X86_REG_SIL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ESI], *(uint8_t *)value); - break; - case UC_X86_REG_RDI: - X86_CPU(uc, mycpu)->env.regs[R_EDI] = *(uint64_t *)value; - break; - case UC_X86_REG_EDI: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EDI], *(uint32_t *)value); - break; - case UC_X86_REG_DI: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDI], *(uint16_t *)value); - break; - case UC_X86_REG_DIL: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDI], *(uint8_t *)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].selector = *(uint16_t *)value; - break; - case UC_X86_REG_DS: - 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].selector = *(uint16_t *)value; - break; - case UC_X86_REG_ES: - 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].selector = *(uint16_t *)value; - break; - case UC_X86_REG_GS: - 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; - break; - case UC_X86_REG_R8D: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[8], *(uint32_t *)value); - break; - case UC_X86_REG_R8W: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[8], *(uint16_t *)value); - break; - case UC_X86_REG_R8B: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[8], *(uint8_t *)value); - break; - case UC_X86_REG_R9: - X86_CPU(uc, mycpu)->env.regs[9] = *(uint64_t *)value; - break; - case UC_X86_REG_R9D: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[9], *(uint32_t *)value); - break; - case UC_X86_REG_R9W: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[9], *(uint16_t *)value); - break; - case UC_X86_REG_R9B: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[9], *(uint8_t *)value); - break; - case UC_X86_REG_R10: - X86_CPU(uc, mycpu)->env.regs[10] = *(uint64_t *)value; - break; - case UC_X86_REG_R10D: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[10], *(uint32_t *)value); - break; - case UC_X86_REG_R10W: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[10], *(uint16_t *)value); - break; - case UC_X86_REG_R10B: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[10], *(uint8_t *)value); - break; - case UC_X86_REG_R11: - X86_CPU(uc, mycpu)->env.regs[11] = *(uint64_t *)value; - break; - case UC_X86_REG_R11D: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[11], *(uint32_t *)value); - break; - case UC_X86_REG_R11W: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[11], *(uint16_t *)value); - break; - case UC_X86_REG_R11B: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[11], *(uint8_t *)value); - break; - case UC_X86_REG_R12: - X86_CPU(uc, mycpu)->env.regs[12] = *(uint64_t *)value; - break; - case UC_X86_REG_R12D: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[12], *(uint32_t *)value); - break; - case UC_X86_REG_R12W: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[12], *(uint16_t *)value); - break; - case UC_X86_REG_R12B: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[12], *(uint8_t *)value); - break; - case UC_X86_REG_R13: - X86_CPU(uc, mycpu)->env.regs[13] = *(uint64_t *)value; - break; - case UC_X86_REG_R13D: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[13], *(uint32_t *)value); - break; - case UC_X86_REG_R13W: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[13], *(uint16_t *)value); - break; - case UC_X86_REG_R13B: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[13], *(uint8_t *)value); - break; - case UC_X86_REG_R14: - X86_CPU(uc, mycpu)->env.regs[14] = *(uint64_t *)value; - break; - case UC_X86_REG_R14D: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[14], *(uint32_t *)value); - break; - case UC_X86_REG_R14W: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[14], *(uint16_t *)value); - break; - case UC_X86_REG_R14B: - WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[14], *(uint8_t *)value); - break; - case UC_X86_REG_R15: - X86_CPU(uc, mycpu)->env.regs[15] = *(uint64_t *)value; - break; - case UC_X86_REG_R15D: - WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[15], *(uint32_t *)value); - break; - case UC_X86_REG_R15W: - WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[15], *(uint16_t *)value); - break; - 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; + case UC_MODE_64: + switch(regid) { + default: + break; + case UC_X86_REG_CR0 ... UC_X86_REG_CR4: + X86_CPU(uc, mycpu)->env.cr[regid - UC_X86_REG_CR0] = *(uint64_t *)value; + break; + case UC_X86_REG_DR0 ... UC_X86_REG_DR7: + X86_CPU(uc, mycpu)->env.dr[regid - UC_X86_REG_DR0] = *(uint64_t *)value; + break; + case UC_X86_REG_EFLAGS: + X86_CPU(uc, mycpu)->env.eflags = *(uint64_t *)value; + X86_CPU(uc, mycpu)->env.eflags0 = *(uint64_t *)value; + break; + case UC_X86_REG_RAX: + X86_CPU(uc, mycpu)->env.regs[R_EAX] = *(uint64_t *)value; + break; + case UC_X86_REG_EAX: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint32_t *)value); + break; + case UC_X86_REG_AX: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint16_t *)value); + break; + case UC_X86_REG_AH: + WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint8_t *)value); + break; + case UC_X86_REG_AL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EAX], *(uint8_t *)value); + break; + case UC_X86_REG_RBX: + X86_CPU(uc, mycpu)->env.regs[R_EBX] = *(uint64_t *)value; + break; + case UC_X86_REG_EBX: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint32_t *)value); + break; + case UC_X86_REG_BX: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint16_t *)value); + break; + case UC_X86_REG_BH: + WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint8_t *)value); + break; + case UC_X86_REG_BL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBX], *(uint8_t *)value); + break; + case UC_X86_REG_RCX: + X86_CPU(uc, mycpu)->env.regs[R_ECX] = *(uint64_t *)value; + break; + case UC_X86_REG_ECX: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint32_t *)value); + break; + case UC_X86_REG_CX: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint16_t *)value); + break; + case UC_X86_REG_CH: + WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint8_t *)value); + break; + case UC_X86_REG_CL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ECX], *(uint8_t *)value); + break; + case UC_X86_REG_RDX: + X86_CPU(uc, mycpu)->env.regs[R_EDX] = *(uint64_t *)value; + break; + case UC_X86_REG_EDX: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint32_t *)value); + break; + case UC_X86_REG_DX: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint16_t *)value); + break; + case UC_X86_REG_DH: + WRITE_BYTE_H(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint8_t *)value); + break; + case UC_X86_REG_DL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDX], *(uint8_t *)value); + break; + case UC_X86_REG_RSP: + X86_CPU(uc, mycpu)->env.regs[R_ESP] = *(uint64_t *)value; + break; + case UC_X86_REG_ESP: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ESP], *(uint32_t *)value); + break; + case UC_X86_REG_SP: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESP], *(uint16_t *)value); + break; + case UC_X86_REG_SPL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ESP], *(uint8_t *)value); + break; + case UC_X86_REG_RBP: + X86_CPU(uc, mycpu)->env.regs[R_EBP] = *(uint64_t *)value; + break; + case UC_X86_REG_EBP: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EBP], *(uint32_t *)value); + break; + case UC_X86_REG_BP: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EBP], *(uint16_t *)value); + break; + case UC_X86_REG_BPL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EBP], *(uint8_t *)value); + break; + case UC_X86_REG_RSI: + X86_CPU(uc, mycpu)->env.regs[R_ESI] = *(uint64_t *)value; + break; + case UC_X86_REG_ESI: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_ESI], *(uint32_t *)value); + break; + case UC_X86_REG_SI: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_ESI], *(uint16_t *)value); + break; + case UC_X86_REG_SIL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_ESI], *(uint8_t *)value); + break; + case UC_X86_REG_RDI: + X86_CPU(uc, mycpu)->env.regs[R_EDI] = *(uint64_t *)value; + break; + case UC_X86_REG_EDI: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[R_EDI], *(uint32_t *)value); + break; + case UC_X86_REG_DI: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[R_EDI], *(uint16_t *)value); + break; + case UC_X86_REG_DIL: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[R_EDI], *(uint8_t *)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].selector = *(uint16_t *)value; + break; + case UC_X86_REG_DS: + 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].selector = *(uint16_t *)value; + break; + case UC_X86_REG_ES: + 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].selector = *(uint16_t *)value; + break; + case UC_X86_REG_GS: + 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; + break; + case UC_X86_REG_R8D: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[8], *(uint32_t *)value); + break; + case UC_X86_REG_R8W: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[8], *(uint16_t *)value); + break; + case UC_X86_REG_R8B: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[8], *(uint8_t *)value); + break; + case UC_X86_REG_R9: + X86_CPU(uc, mycpu)->env.regs[9] = *(uint64_t *)value; + break; + case UC_X86_REG_R9D: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[9], *(uint32_t *)value); + break; + case UC_X86_REG_R9W: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[9], *(uint16_t *)value); + break; + case UC_X86_REG_R9B: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[9], *(uint8_t *)value); + break; + case UC_X86_REG_R10: + X86_CPU(uc, mycpu)->env.regs[10] = *(uint64_t *)value; + break; + case UC_X86_REG_R10D: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[10], *(uint32_t *)value); + break; + case UC_X86_REG_R10W: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[10], *(uint16_t *)value); + break; + case UC_X86_REG_R10B: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[10], *(uint8_t *)value); + break; + case UC_X86_REG_R11: + X86_CPU(uc, mycpu)->env.regs[11] = *(uint64_t *)value; + break; + case UC_X86_REG_R11D: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[11], *(uint32_t *)value); + break; + case UC_X86_REG_R11W: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[11], *(uint16_t *)value); + break; + case UC_X86_REG_R11B: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[11], *(uint8_t *)value); + break; + case UC_X86_REG_R12: + X86_CPU(uc, mycpu)->env.regs[12] = *(uint64_t *)value; + break; + case UC_X86_REG_R12D: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[12], *(uint32_t *)value); + break; + case UC_X86_REG_R12W: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[12], *(uint16_t *)value); + break; + case UC_X86_REG_R12B: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[12], *(uint8_t *)value); + break; + case UC_X86_REG_R13: + X86_CPU(uc, mycpu)->env.regs[13] = *(uint64_t *)value; + break; + case UC_X86_REG_R13D: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[13], *(uint32_t *)value); + break; + case UC_X86_REG_R13W: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[13], *(uint16_t *)value); + break; + case UC_X86_REG_R13B: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[13], *(uint8_t *)value); + break; + case UC_X86_REG_R14: + X86_CPU(uc, mycpu)->env.regs[14] = *(uint64_t *)value; + break; + case UC_X86_REG_R14D: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[14], *(uint32_t *)value); + break; + case UC_X86_REG_R14W: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[14], *(uint16_t *)value); + break; + case UC_X86_REG_R14B: + WRITE_BYTE_L(X86_CPU(uc, mycpu)->env.regs[14], *(uint8_t *)value); + break; + case UC_X86_REG_R15: + X86_CPU(uc, mycpu)->env.regs[15] = *(uint64_t *)value; + break; + case UC_X86_REG_R15D: + WRITE_DWORD(X86_CPU(uc, mycpu)->env.regs[15], *(uint32_t *)value); + break; + case UC_X86_REG_R15W: + WRITE_WORD(X86_CPU(uc, mycpu)->env.regs[15], *(uint16_t *)value); + break; + 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 + } } return 0; diff --git a/qemu/target-i386/unicorn.h b/qemu/target-i386/unicorn.h index a4dda81e..37e38b4f 100644 --- a/qemu/target-i386/unicorn.h +++ b/qemu/target-i386/unicorn.h @@ -5,8 +5,8 @@ #define UC_QEMU_TARGET_I386_H // functions to read & write registers -int x86_reg_read(struct uc_struct *uc, unsigned int regid, void *value); -int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); +int x86_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count); +int x86_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count); void x86_reg_reset(struct uc_struct *uc); diff --git a/qemu/target-m68k/unicorn.c b/qemu/target-m68k/unicorn.c index 0055d4a1..d2818cfe 100644 --- a/qemu/target-m68k/unicorn.c +++ b/qemu/target-m68k/unicorn.c @@ -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) @@ -31,53 +25,56 @@ void m68k_reg_reset(struct uc_struct *uc) env->pc = 0; } -int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value) +int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) - *(int32_t *)value = M68K_CPU(uc, mycpu)->env.aregs[regid - UC_M68K_REG_A0]; - else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7) - *(int32_t *)value = M68K_CPU(uc, mycpu)->env.dregs[regid - UC_M68K_REG_D0]; - else { - switch(regid) { - default: break; - case UC_M68K_REG_PC: - *(int32_t *)value = M68K_CPU(uc, mycpu)->env.pc; - break; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) + *(int32_t *)value = M68K_CPU(uc, mycpu)->env.aregs[regid - UC_M68K_REG_A0]; + else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7) + *(int32_t *)value = M68K_CPU(uc, mycpu)->env.dregs[regid - UC_M68K_REG_D0]; + else { + switch(regid) { + default: break; + case UC_M68K_REG_PC: + *(int32_t *)value = M68K_CPU(uc, mycpu)->env.pc; + 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 m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) +int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) - M68K_CPU(uc, mycpu)->env.aregs[regid - UC_M68K_REG_A0] = *(uint32_t *)value; - else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7) - M68K_CPU(uc, mycpu)->env.dregs[regid - UC_M68K_REG_D0] = *(uint32_t *)value; - else { - switch(regid) { - 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; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + if (regid >= UC_M68K_REG_A0 && regid <= UC_M68K_REG_A7) + M68K_CPU(uc, mycpu)->env.aregs[regid - UC_M68K_REG_A0] = *(uint32_t *)value; + else if (regid >= UC_M68K_REG_D0 && regid <= UC_M68K_REG_D7) + M68K_CPU(uc, mycpu)->env.dregs[regid - UC_M68K_REG_D0] = *(uint32_t *)value; + else { + switch(regid) { + 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; + } } } - return 0; } diff --git a/qemu/target-m68k/unicorn.h b/qemu/target-m68k/unicorn.h index 37ea828f..7cf8e21a 100644 --- a/qemu/target-m68k/unicorn.h +++ b/qemu/target-m68k/unicorn.h @@ -5,8 +5,8 @@ #define UC_QEMU_TARGET_M68K_H // functions to read & write registers -int m68k_reg_read(struct uc_struct *uc, unsigned int regid, void *value); -int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); +int m68k_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count); +int m68k_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count); void m68k_reg_reset(struct uc_struct *uc); diff --git a/qemu/target-mips/unicorn.c b/qemu/target-mips/unicorn.c index 6af98dce..ec8779bf 100644 --- a/qemu/target-mips/unicorn.c +++ b/qemu/target-mips/unicorn.c @@ -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) @@ -46,49 +39,52 @@ void mips_reg_reset(struct uc_struct *uc) env->active_tc.PC = 0; } -int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value) +int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) - *(int32_t *)value = MIPS_CPU(uc, mycpu)->env.active_tc.gpr[regid - UC_MIPS_REG_0]; - else { - switch(regid) { - default: break; - case UC_MIPS_REG_PC: - *(int32_t *)value = MIPS_CPU(uc, mycpu)->env.active_tc.PC; - break; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) + *(int32_t *)value = MIPS_CPU(uc, mycpu)->env.active_tc.gpr[regid - UC_MIPS_REG_0]; + else { + switch(regid) { + default: break; + case UC_MIPS_REG_PC: + *(int32_t *)value = MIPS_CPU(uc, mycpu)->env.active_tc.PC; + 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 mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) +int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) - MIPS_CPU(uc, mycpu)->env.active_tc.gpr[regid - UC_MIPS_REG_0] = *(uint32_t *)value; - else { - switch(regid) { - 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; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + if (regid >= UC_MIPS_REG_0 && regid <= UC_MIPS_REG_31) + MIPS_CPU(uc, mycpu)->env.active_tc.gpr[regid - UC_MIPS_REG_0] = *(uint32_t *)value; + else { + switch(regid) { + 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; + } } } - return 0; } diff --git a/qemu/target-mips/unicorn.h b/qemu/target-mips/unicorn.h index 874b82f1..c9639eb8 100644 --- a/qemu/target-mips/unicorn.h +++ b/qemu/target-mips/unicorn.h @@ -5,8 +5,8 @@ #define UC_QEMU_TARGET_MIPS_H // functions to read & write registers -int mips_reg_read(struct uc_struct *uc, unsigned int regid, void *value); -int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); +int mips_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count); +int mips_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count); void mips_reg_reset(struct uc_struct *uc); diff --git a/qemu/target-sparc/unicorn.c b/qemu/target-sparc/unicorn.c index e612457b..a2a3dcaa 100644 --- a/qemu/target-sparc/unicorn.c +++ b/qemu/target-sparc/unicorn.c @@ -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) @@ -45,52 +39,62 @@ void sparc_reg_reset(struct uc_struct *uc) env->regwptr = env->regbase; } -int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) +int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) - *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0]; - else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) - *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0]; - else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) - *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0]; - else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) - *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0]; - else { - switch(regid) { - default: break; - case UC_SPARC_REG_PC: - *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.pc; - break; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) + *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0]; + else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) + *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0]; + else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) + *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0]; + else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) + *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0]; + else { + switch(regid) { + default: break; + case UC_SPARC_REG_PC: + *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.pc; + break; + } } } return 0; } -int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) +int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) - SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint32_t *)value; - else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) - SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0] = *(uint32_t *)value; - else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) - SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint32_t *)value; - else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) - SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint32_t *)value; - else { - switch(regid) { - default: break; - 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; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) + SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint32_t *)value; + else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) + SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0] = *(uint32_t *)value; + else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) + SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint32_t *)value; + else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) + SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint32_t *)value; + else { + switch(regid) { + default: break; + 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; + } } } diff --git a/qemu/target-sparc/unicorn.h b/qemu/target-sparc/unicorn.h index 89771827..53bf1303 100644 --- a/qemu/target-sparc/unicorn.h +++ b/qemu/target-sparc/unicorn.h @@ -5,8 +5,8 @@ #define UC_QEMU_TARGET_SPARC_H // functions to read & write registers -int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value); -int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value); +int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count); +int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void *const *vals, int count); void sparc_reg_reset(struct uc_struct *uc); diff --git a/qemu/target-sparc/unicorn64.c b/qemu/target-sparc/unicorn64.c index e9257b75..9a748936 100644 --- a/qemu/target-sparc/unicorn64.c +++ b/qemu/target-sparc/unicorn64.c @@ -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) @@ -45,53 +39,62 @@ void sparc_reg_reset(struct uc_struct *uc) env->regwptr = env->regbase; } -int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) +int sparc_reg_read(struct uc_struct *uc, unsigned int *regs, void **vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) - *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0]; - else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) - *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0]; - else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) - *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0]; - else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) - *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0]; - else { - switch(regid) { - default: break; - case UC_SPARC_REG_PC: - *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.pc; - break; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + void *value = vals[i]; + if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) + *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0]; + else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) + *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0]; + else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) + *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0]; + else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) + *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0]; + else { + switch(regid) { + default: break; + case UC_SPARC_REG_PC: + *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.pc; + break; + } } } return 0; } -int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) +int sparc_reg_write(struct uc_struct *uc, unsigned int *regs, void* const* vals, int count) { CPUState *mycpu = first_cpu; + int i; - if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) - SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint64_t *)value; - else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) - SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0] = *(uint64_t *)value; - else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) - SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint64_t *)value; - else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) - SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint64_t *)value; - else { - switch(regid) { - default: break; - case UC_SPARC_REG_PC: - SPARC_CPU(uc, mycpu)->env.pc = *(uint64_t *)value; - SPARC_CPU(uc, mycpu)->env.npc = *(uint64_t *)value + 4; - break; + for (i = 0; i < count; i++) { + unsigned int regid = regs[i]; + const void *value = vals[i]; + if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) + SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint64_t *)value; + else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7) + SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0] = *(uint64_t *)value; + else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7) + SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint64_t *)value; + else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7) + SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint64_t *)value; + else { + switch(regid) { + default: break; + case UC_SPARC_REG_PC: + SPARC_CPU(uc, mycpu)->env.pc = *(uint64_t *)value; + SPARC_CPU(uc, mycpu)->env.npc = *(uint64_t *)value + 4; + break; + } } } - return 0; } diff --git a/qemu/translate-all.c b/qemu/translate-all.c index aec38c7c..31d4f47f 100644 --- a/qemu/translate-all.c +++ b/qemu/translate-all.c @@ -63,8 +63,6 @@ #include "uc_priv.h" -#define USE_STATIC_CODE_GEN_BUFFER - //#define DEBUG_TB_INVALIDATE //#define DEBUG_FLUSH /* make various TB consistency checks */ @@ -501,7 +499,7 @@ static inline PageDesc *page_find(struct uc_struct *uc, tb_page_addr_t index) # define MAX_CODE_GEN_BUFFER_SIZE ((size_t)-1) #endif -#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (32u * 1024 * 1024) +#define DEFAULT_CODE_GEN_BUFFER_SIZE_1 (8 * 1024 * 1024) #define DEFAULT_CODE_GEN_BUFFER_SIZE \ (DEFAULT_CODE_GEN_BUFFER_SIZE_1 < MAX_CODE_GEN_BUFFER_SIZE \ @@ -520,7 +518,7 @@ static inline size_t size_code_gen_buffer(struct uc_struct *uc, size_t tb_size) /* ??? If we relax the requirement that CONFIG_USER_ONLY use the static buffer, we could size this on RESERVED_VA, on the text segment size of the executable, or continue to use the default. */ - tb_size = (unsigned long)(uc->ram_size / 4); + tb_size = (unsigned long)DEFAULT_CODE_GEN_BUFFER_SIZE; #endif } if (tb_size < MIN_CODE_GEN_BUFFER_SIZE) { @@ -1531,15 +1529,6 @@ static void tcg_handle_interrupt(CPUState *cpu, int mask) { cpu->interrupt_request |= mask; - /* - * If called from iothread context, wake the target cpu in - * case its halted. - */ - if (!qemu_cpu_is_self(cpu)) { - qemu_cpu_kick(cpu); - return; - } - cpu->tcg_exit_req = 1; } diff --git a/qemu/unicorn_common.h b/qemu/unicorn_common.h index 2df9ccef..fb1084c8 100644 --- a/qemu/unicorn_common.h +++ b/qemu/unicorn_common.h @@ -35,12 +35,17 @@ static void release_common(void *t) { TCGContext *s = (TCGContext *)t; struct uc_struct* uc = s->uc; + CPUState *cpu; +#if TCG_TARGET_REG_BITS == 32 + int i; +#endif // Clean TCG. TCGOpDef* def = &s->tcg_op_defs[0]; g_free(def->args_ct); g_free(def->sorted_args); g_free(s->tcg_op_defs); + TCGPool *po, *to; for (po = s->pool_first; po; po = to) { to = po->next; @@ -55,9 +60,46 @@ static void release_common(void *t) memory_free(uc); // Clean CPU. + CPU_FOREACH(cpu) { + g_free(cpu->tcg_as_listener); + g_free(cpu->thread); + g_free(cpu->halt_cond); + } + + OBJECT(uc->machine_state->accelerator)->ref = 1; + OBJECT(uc->machine_state)->ref = 1; + OBJECT(uc->owner)->ref = 1; + OBJECT(uc->root)->ref = 1; + + object_unref(uc, OBJECT(uc->machine_state->accelerator)); + object_unref(uc, OBJECT(uc->machine_state)); object_unref(uc, uc->cpu); + object_unref(uc, OBJECT(&uc->io_mem_notdirty)); + object_unref(uc, OBJECT(&uc->io_mem_unassigned)); + object_unref(uc, OBJECT(&uc->io_mem_rom)); + object_unref(uc, OBJECT(uc->root)); g_hash_table_foreach(uc->type_table, free_table, uc); + g_free(uc->system_memory); + + if (uc->qemu_thread_data) + free(uc->qemu_thread_data); + +#if TCG_TARGET_REG_BITS == 32 + for(i = 0; i < s->nb_globals; i++) { + TCGTemp *ts = &s->temps[i]; + if (ts->base_type == TCG_TYPE_I64) { + if (ts->name && ((strcmp(ts->name+(strlen(ts->name)-2), "_0") == 0) || + (strcmp(ts->name+(strlen(ts->name)-2), "_1") == 0))) { + free((void *)ts->name); + } + } + } +#endif + + qemu_mutex_destroy(&uc->qemu_global_mutex); + qemu_cond_destroy(&uc->qemu_cpu_cond); + // Clean cache. tb_cleanup(uc); } @@ -70,7 +112,6 @@ static inline void uc_common_init(struct uc_struct* uc) uc->tcg_enabled = tcg_enabled; uc->tcg_exec_init = tcg_exec_init; uc->cpu_exec_init_all = cpu_exec_init_all; - uc->pause_all_vcpus = pause_all_vcpus; uc->vm_start = vm_start; uc->memory_map = memory_map; uc->memory_map_ptr = memory_map_ptr; diff --git a/qemu/util/oslib-posix.c b/qemu/util/oslib-posix.c index c936b6e9..49e902f7 100644 --- a/qemu/util/oslib-posix.c +++ b/qemu/util/oslib-posix.c @@ -71,15 +71,6 @@ extern int daemon(int, int); #include #endif -int qemu_get_thread_id(void) -{ -#if defined(__linux__) - return syscall(SYS_gettid); -#else - return getpid(); -#endif -} - int qemu_daemon(int nochdir, int noclose) { return daemon(nochdir, noclose); diff --git a/qemu/util/oslib-win32.c b/qemu/util/oslib-win32.c index eb8409ac..63b60798 100644 --- a/qemu/util/oslib-win32.c +++ b/qemu/util/oslib-win32.c @@ -37,7 +37,6 @@ #include #include "config-host.h" #include "sysemu/sysemu.h" -#include "qemu/main-loop.h" // #include "trace.h" //#include "qemu/sockets.h" @@ -167,11 +166,6 @@ int qemu_gettimeofday(qemu_timeval *tp) return 0; } -int qemu_get_thread_id(void) -{ - return GetCurrentThreadId(); -} - char * qemu_get_local_state_pathname(const char *relative_pathname) { diff --git a/qemu/util/qemu-thread-posix.c b/qemu/util/qemu-thread-posix.c index 6430f929..78bbb75c 100644 --- a/qemu/util/qemu-thread-posix.c +++ b/qemu/util/qemu-thread-posix.c @@ -426,16 +426,6 @@ int qemu_thread_create(struct uc_struct *uc, QemuThread *thread, const char *nam return 0; } -void qemu_thread_get_self(struct uc_struct *uc, QemuThread *thread) -{ - thread->thread = pthread_self(); -} - -bool qemu_thread_is_self(QemuThread *thread) -{ - return pthread_equal(pthread_self(), thread->thread); -} - void qemu_thread_exit(struct uc_struct *uc, void *retval) { pthread_exit(retval); diff --git a/qemu/util/qemu-thread-win32.c b/qemu/util/qemu-thread-win32.c index 2c2cf4ad..97ba69c6 100644 --- a/qemu/util/qemu-thread-win32.c +++ b/qemu/util/qemu-thread-win32.c @@ -276,6 +276,7 @@ static unsigned __stdcall win32_start_routine(void *arg) void *thread_arg = data->arg; if (data->mode == QEMU_THREAD_DETACHED) { + data->uc->qemu_thread_data = NULL; g_free(data); data = NULL; } @@ -359,12 +360,6 @@ int qemu_thread_create(struct uc_struct *uc, QemuThread *thread, const char *nam return 0; } -void qemu_thread_get_self(struct uc_struct *uc, QemuThread *thread) -{ - thread->data = uc->qemu_thread_data; - thread->tid = GetCurrentThreadId(); -} - HANDLE qemu_thread_get_handle(QemuThread *thread) { QemuThreadData *data; @@ -386,8 +381,3 @@ HANDLE qemu_thread_get_handle(QemuThread *thread) LeaveCriticalSection(&data->cs); return handle; } - -bool qemu_thread_is_self(QemuThread *thread) -{ - return GetCurrentThreadId() == thread->tid; -} diff --git a/qemu/vl.c b/qemu/vl.c index caf6686f..d25c8888 100644 --- a/qemu/vl.c +++ b/qemu/vl.c @@ -115,7 +115,7 @@ int machine_initialize(struct uc_struct *uc) current_machine = MACHINE(uc, object_new(uc, object_class_get_name( OBJECT_CLASS(machine_class)))); - + uc->machine_state = current_machine; current_machine->uc = uc; uc->cpu_exec_init_all(uc); @@ -123,7 +123,6 @@ int machine_initialize(struct uc_struct *uc) configure_accelerator(current_machine); qemu_init_cpu_loop(uc); - qemu_mutex_lock_iothread(uc); current_machine->cpu_model = NULL; diff --git a/qemu/x86_64.h b/qemu/x86_64.h index bbb695e5..df78a28a 100644 --- a/qemu/x86_64.h +++ b/qemu/x86_64.h @@ -2258,7 +2258,6 @@ #define parse_value parse_value_x86_64 #define par_write par_write_x86_64 #define patch_reloc patch_reloc_x86_64 -#define pause_all_vcpus pause_all_vcpus_x86_64 #define phys_map_node_alloc phys_map_node_alloc_x86_64 #define phys_map_node_reserve phys_map_node_reserve_x86_64 #define phys_mem_alloc phys_mem_alloc_x86_64 @@ -2417,9 +2416,6 @@ #define qemu_clock_get_us qemu_clock_get_us_x86_64 #define qemu_clock_ptr qemu_clock_ptr_x86_64 #define qemu_clocks qemu_clocks_x86_64 -#define qemu_cond_destroy qemu_cond_destroy_x86_64 -#define qemu_cpu_is_self qemu_cpu_is_self_x86_64 -#define qemu_cpu_kick_thread qemu_cpu_kick_thread_x86_64 #define qemu_daemon qemu_daemon_x86_64 #define qemu_event_destroy qemu_event_destroy_x86_64 #define qemu_event_init qemu_event_init_x86_64 @@ -2445,7 +2441,6 @@ #define qemu_log_flush qemu_log_flush_x86_64 #define qemu_loglevel_mask qemu_loglevel_mask_x86_64 #define qemu_log_vprintf qemu_log_vprintf_x86_64 -#define qemu_mutex_destroy qemu_mutex_destroy_x86_64 #define qemu_mutex_lock_ramlist qemu_mutex_lock_ramlist_x86_64 #define qemu_mutex_trylock qemu_mutex_trylock_x86_64 #define qemu_mutex_unlock_ramlist qemu_mutex_unlock_ramlist_x86_64 @@ -2516,9 +2511,7 @@ #define qemu_st_helpers qemu_st_helpers_x86_64 #define qemu_strnlen qemu_strnlen_x86_64 #define qemu_strsep qemu_strsep_x86_64 -#define qemu_tcg_cpu_thread_fn qemu_tcg_cpu_thread_fn_x86_64 #define qemu_tcg_init_vcpu qemu_tcg_init_vcpu_x86_64 -#define qemu_thread_exit qemu_thread_exit_x86_64 #define qemu_try_memalign qemu_try_memalign_x86_64 #define qentry_destroy qentry_destroy_x86_64 #define qerror_human qerror_human_x86_64 diff --git a/samples/Makefile b/samples/Makefile index 02a1f66d..15030da8 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -37,6 +37,13 @@ else CC = $(CROSS)gcc endif +ifeq ($(UNICORN_ASAN),yes) +CC = clang -fsanitize=address -fno-omit-frame-pointer +CXX = clang++ -fsanitize=address -fno-omit-frame-pointer +AR = llvm-ar +LDFLAGS := -fsanitize=address ${LDFLAGS} +endif + #CFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch)) #LDFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch)) @@ -75,7 +82,7 @@ ARCHIVE = $(LIBDIR)/lib$(LIBNAME).$(AR_EXT) endif endif -.PHONY: all clean +.PHONY: all clean clean_bins clean_libs UNICORN_ARCHS := $(shell if [ -e ../config.log ]; then cat ../config.log;\ else printf "$(UNICORN_ARCHS)"; fi) @@ -100,6 +107,8 @@ ifneq (,$(findstring x86,$(UNICORN_ARCHS))) SOURCES += sample_x86.c SOURCES += shellcode.c SOURCES += mem_apis.c +SOURCES += sample_x86_32_gdt_and_seg_regs.c +SOURCES += sample_batch_reg.c endif ifneq (,$(findstring m68k,$(UNICORN_ARCHS))) SOURCES += sample_m68k.c @@ -109,12 +118,16 @@ OBJS = $(addprefix $(OBJDIR)/,$(SOURCES:.c=.o)) OBJS_ELF = $(addprefix $(OBJDIR)/,$(SOURCES:.c=)) BINARY = $(addprefix $(SAMPLEDIR)/,$(SOURCES:.c=$(BIN_EXT))) -all: $(BINARY) +all: clean_bins $(BINARY) -clean: +clean_bins: rm -rf *.o $(OBJS_ELF) $(BINARY) $(SAMPLEDIR)/*.exe $(SAMPLEDIR)/*.static $(OBJDIR)/lib$(LIBNAME)* $(OBJDIR)/$(LIBNAME)* + rm -rf sample_x86 sample_arm sample_arm64 sample_mips sample_sparc sample_ppc sample_m68k shellcode mem_apis sample_x86_32_gdt_and_seg_regs sample_batch_reg + +clean_libs: rm -rf libunicorn*.so libunicorn*.lib libunicorn*.dylib unicorn*.dll unicorn*.lib - rm -rf sample_x86 sample_arm sample_arm64 sample_mips sample_sparc sample_ppc sample_m68k shellcode mem_apis + +clean: clean_bins clean_libs $(BINARY): $(OBJS) diff --git a/samples/sample_batch_reg.c b/samples/sample_batch_reg.c new file mode 100644 index 00000000..90684d75 --- /dev/null +++ b/samples/sample_batch_reg.c @@ -0,0 +1,115 @@ +#include +#include +#include +#include +#include + +int syscall_abi[] = { + UC_X86_REG_RAX, UC_X86_REG_RDI, UC_X86_REG_RSI, UC_X86_REG_RDX, + UC_X86_REG_R10, UC_X86_REG_R8, UC_X86_REG_R9 +}; + +uint64_t vals[7] = { 200, 10, 11, 12, 13, 14, 15 }; + +// This part of the API is less... clean... because Unicorn supports arbitrary register types. +// So the least intrusive solution is passing individual pointers. +// On the plus side, you only need to make this pointer array once. +void *ptrs[7]; + +void uc_perror(const char *func, uc_err err) +{ + fprintf(stderr, "Error in %s(): %s\n", func, uc_strerror(err)); +} + +#define BASE 0x10000 + +// mov rax, 100; mov rdi, 1; mov rsi, 2; mov rdx, 3; mov r10, 4; mov r8, 5; mov r9, 6; syscall +#define CODE "\x48\xc7\xc0\x64\x00\x00\x00\x48\xc7\xc7\x01\x00\x00\x00\x48\xc7\xc6\x02\x00\x00\x00\x48\xc7\xc2\x03\x00\x00\x00\x49\xc7\xc2\x04\x00\x00\x00\x49\xc7\xc0\x05\x00\x00\x00\x49\xc7\xc1\x06\x00\x00\x00\x0f\x05" + +void hook_syscall(uc_engine *uc, void *user_data) +{ + int i; + + uc_reg_read_batch(uc, syscall_abi, ptrs, 7); + + printf("syscall: {"); + + for (i = 0; i < 7; i++) { + if (i != 0) printf(", "); + printf("%" PRIu64, vals[i]); + } + + printf("}\n"); +} + +void hook_code(uc_engine *uc, uint64_t addr, uint32_t size, void *user_data) +{ + printf("HOOK_CODE: 0x%" PRIx64 ", 0x%x\n", addr, size); +} + +int main() +{ + int i; + uc_hook sys_hook; + uc_err err; + uc_engine *uc; + + // set up register pointers + for (i = 0; i < 7; i++) { + ptrs[i] = &vals[i]; + } + + if ((err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc))) { + uc_perror("uc_open", err); + return 1; + } + + // reg_write_batch + printf("reg_write_batch({200, 10, 11, 12, 13, 14, 15})\n"); + if ((err = uc_reg_write_batch(uc, syscall_abi, ptrs, 7))) { + uc_perror("uc_reg_write_batch", err); + return 1; + } + + // reg_read_batch + memset(vals, 0, sizeof(vals)); + if ((err = uc_reg_read_batch(uc, syscall_abi, ptrs, 7))) { + uc_perror("uc_reg_read_batch", err); + return 1; + } + + printf("reg_read_batch = {"); + + for (i = 0; i < 7; i++) { + if (i != 0) printf(", "); + printf("%" PRIu64, vals[i]); + } + + printf("}\n"); + + // syscall + printf("\n"); + printf("running syscall shellcode\n"); + + if ((err = uc_hook_add(uc, &sys_hook, UC_HOOK_INSN, hook_syscall, NULL, 1, 0, UC_X86_INS_SYSCALL))) { + uc_perror("uc_hook_add", err); + return 1; + } + + if ((err = uc_mem_map(uc, BASE, 0x1000, UC_PROT_ALL))) { + uc_perror("uc_mem_map", err); + return 1; + } + + if ((err = uc_mem_write(uc, BASE, CODE, sizeof(CODE) - 1))) { + uc_perror("uc_mem_write", err); + return 1; + } + + if ((err = uc_emu_start(uc, BASE, BASE + sizeof(CODE) - 1, 0, 0))) { + uc_perror("uc_emu_start", err); + return 1; + } + + return 0; +} diff --git a/samples/sample_x86.c b/samples/sample_x86.c index 264015f2..620ce5ed 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -148,7 +148,7 @@ static uint32_t hook_in(uc_engine *uc, uint32_t port, int size, void *user_data) // callback for OUT instruction (X86). static void hook_out(uc_engine *uc, uint32_t port, int size, uint32_t value, void *user_data) { - uint32_t tmp; + uint32_t tmp = 0; uint32_t eip; uc_reg_read(uc, UC_X86_REG_EIP, &eip); @@ -470,7 +470,7 @@ static void test_i386_invalid_mem_read(void) uc_close(uc); } -// emulate code that read invalid memory +// emulate code that write invalid memory static void test_i386_invalid_mem_write(void) { uc_engine *uc; @@ -532,7 +532,7 @@ static void test_i386_invalid_mem_write(void) if (!uc_mem_read(uc, 0xaaaaaaaa, &tmp, sizeof(tmp))) printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", 0xaaaaaaaa, tmp); else - printf(">>> Failed to read 4 bytes from [0x%x]\n", 0xffffffaa); + printf(">>> Failed to read 4 bytes from [0x%x]\n", 0xaaaaaaaa); if (!uc_mem_read(uc, 0xffffffaa, &tmp, sizeof(tmp))) printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", 0xffffffaa, tmp); @@ -605,6 +605,7 @@ static void test_i386_inout(void) uc_err err; uc_hook trace1, trace2, trace3, trace4; + int r_eax = 0x1234; // EAX register int r_ecx = 0x6789; // ECX register @@ -850,7 +851,7 @@ static void test_x86_16(void) uc_mem_map(uc, 0, 8 * 1024, UC_PROT_ALL); // write machine code to be emulated to memory - if (uc_mem_write(uc, 0, X86_CODE16, sizeof(X86_CODE64) - 1)) { + if (uc_mem_write(uc, 0, X86_CODE16, sizeof(X86_CODE16) - 1)) { printf("Failed to write emulation code to memory, quit!\n"); return; } @@ -913,14 +914,6 @@ int main(int argc, char **argv, char **envp) if (!strcmp(argv[1], "-16")) { test_x86_16(); } - - // test memleak - if (!strcmp(argv[1], "-0")) { - while(1) { - test_i386(); - // test_x86_64(); - } - } } else { printf("Syntax: %s <-16|-32|-64>\n", argv[0]); } diff --git a/samples/sample_x86_32_gdt_and_seg_regs.c b/samples/sample_x86_32_gdt_and_seg_regs.c new file mode 100644 index 00000000..c3531619 --- /dev/null +++ b/samples/sample_x86_32_gdt_and_seg_regs.c @@ -0,0 +1,296 @@ +/* + +Sample code to setup a GDT, and use segments. + +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. + +*/ + +#include +#include +#include +#include +#include +#include + +#pragma pack(push, 1) +struct SegmentDescriptor { + union { + struct { +#if __BYTE_ORDER == __LITTLE_ENDIAN + unsigned short limit0; + unsigned short base0; + unsigned char base1; + unsigned char type:4; + unsigned char system:1; /* S flag */ + unsigned char dpl:2; + unsigned char present:1; /* P flag */ + unsigned char limit1:4; + unsigned char avail:1; + unsigned char is_64_code:1; /* L flag */ + unsigned char db:1; /* DB flag */ + unsigned char granularity:1; /* G flag */ + unsigned char base2; +#else + unsigned char base2; + unsigned char granularity:1; /* G flag */ + unsigned char db:1; /* DB flag */ + unsigned char is_64_code:1; /* L flag */ + unsigned char avail:1; + unsigned char limit1:4; + unsigned char present:1; /* P flag */ + unsigned char dpl:2; + unsigned char system:1; /* S flag */ + unsigned char type:4; + unsigned char base1; + unsigned short base0; + unsigned short limit0; +#endif + }; + uint64_t desc; + }; +}; +#pragma pack(pop) + +#define SEGBASE(d) ((uint32_t)((((d).desc >> 16) & 0xffffff) | (((d).desc >> 32) & 0xff000000))) +#define SEGLIMIT(d) ((d).limit0 | (((unsigned int)(d).limit1) << 16)) + +/** + * Assert that err matches expect + */ +#define uc_assert_err(expect, err) \ +do { \ + uc_err __err = err; \ + if (__err != expect) { \ + fprintf(stderr, "%s", uc_strerror(__err)); \ + exit(1); \ + } \ +} while (0) + +/** + * Assert that err is UC_ERR_OK + */ +#define uc_assert_success(err) uc_assert_err(UC_ERR_OK, err) + +/** + * Assert that err is anything but UC_ERR_OK + * + * Note: Better to use uc_assert_err(, err), + * as this serves to document which errors a function will return + * in various scenarios. + */ +#define uc_assert_fail(err) \ +do { \ + uc_err __err = err; \ + if (__err == UC_ERR_OK) { \ + fprintf(stderr, "%s", uc_strerror(__err)); \ + exit(1); \ + } \ +} while (0) + +#define OK(x) uc_assert_success(x) + +/******************************************************************************/ + +static void hook_mem(uc_engine *uc, uc_mem_type type, uint64_t address, int size, int64_t value, void *user_data) +{ + switch(type) { + case UC_MEM_WRITE: + printf("mem write at 0x%"PRIx64 ", size = %u, value = 0x%"PRIx64 "\n", address, size, value); + break; + default: break; + } +} + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf("Executing at 0x%"PRIx64 ", ilen = 0x%x\n", address, size); +} + +//VERY basic descriptor init function, sets many fields to user space sane defaults +static void init_descriptor(struct SegmentDescriptor *desc, uint32_t base, uint32_t limit, uint8_t is_code) +{ + desc->desc = 0; //clear the descriptor + desc->base0 = base & 0xffff; + desc->base1 = (base >> 16) & 0xff; + desc->base2 = base >> 24; + if (limit > 0xfffff) { + //need Giant granularity + limit >>= 12; + desc->granularity = 1; + } + desc->limit0 = limit & 0xffff; + desc->limit1 = limit >> 16; + + //some sane defaults + desc->dpl = 3; + desc->present = 1; + desc->db = 1; //32 bit + desc->type = is_code ? 0xb : 3; + desc->system = 1; //code or data +} + +/* +static void hex_dump(unsigned char *ptr, unsigned int len) +{ + int i; + for (i = 0; i < len; i++) { + if (i != 0 && (i & 0xf) == 0) { + fprintf(stderr, "\n"); + } + fprintf(stderr, "%02hhx", ptr[i]); + } + fprintf(stderr, "\n"); +} +*/ + +static void gdt_demo() +{ + uc_engine *uc; + uc_hook hook1, hook2; + uc_err err; + uint8_t buf[128]; + uc_x86_mmr gdtr; + + /* + bits 32 + + push dword 0x01234567 + push dword 0x89abcdef + + mov dword [fs:0], 0x01234567 + mov dword [fs:4], 0x89abcdef + */ + + const uint8_t code[] = "\x68\x67\x45\x23\x01\x68\xef\xcd\xab\x89\x64\xc7\x05\x00\x00\x00\x00\x67\x45\x23\x01\x64\xc7\x05\x04\x00\x00\x00\xef\xcd\xab\x89"; + const uint64_t code_address = 0x1000000; + const uint64_t stack_address = 0x120000; + const uint64_t gdt_address = 0xc0000000; + const uint64_t fs_address = 0x7efdd000; + + struct SegmentDescriptor *gdt = (struct SegmentDescriptor*)calloc(31, sizeof(struct SegmentDescriptor)); + + int r_esp = stack_address + 0x1000; // initial esp + int r_cs = 0x73; + int r_ss = 0x88; //ring 0 + int r_ds = 0x7b; + int r_es = 0x7b; + int r_fs = 0x83; + + gdtr.base = gdt_address; + gdtr.limit = 31 * sizeof(struct SegmentDescriptor) - 1; + + init_descriptor(&gdt[14], 0, 0xfffff000, 1); //code segment + init_descriptor(&gdt[15], 0, 0xfffff000, 0); //data segment + init_descriptor(&gdt[16], 0x7efdd000, 0xfff, 0); //one page data segment simulate fs + init_descriptor(&gdt[17], 0, 0xfffff000, 0); //ring 0 data + gdt[17].dpl = 0; //set descriptor privilege level + + /* + fprintf(stderr, "GDT: \n"); + hex_dump((unsigned char*)gdt, 31 * sizeof(struct SegmentDescriptor)); + */ + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + uc_assert_success(err); + + uc_hook_add(uc, &hook1, UC_HOOK_CODE, hook_code, NULL, code_address, code_address + sizeof(code) - 1); + + err = uc_hook_add(uc, &hook2, UC_HOOK_MEM_WRITE, hook_mem, NULL, (uint64_t)1, (uint64_t)0); + uc_assert_success(err); + + // map 1 page of code for this emulation + err = uc_mem_map(uc, code_address, 0x1000, UC_PROT_ALL); + uc_assert_success(err); + + // map 1 page of stack for this emulation + err = uc_mem_map(uc, stack_address, 0x1000, UC_PROT_READ | UC_PROT_WRITE); + uc_assert_success(err); + + // map 64k for a GDT + err = uc_mem_map(uc, gdt_address, 0x10000, UC_PROT_WRITE | UC_PROT_READ); + uc_assert_success(err); + + //set up a GDT BEFORE you manipulate any segment registers + err = uc_reg_write(uc, UC_X86_REG_GDTR, &gdtr); + uc_assert_success(err); + + // write gdt to be emulated to memory + err = uc_mem_write(uc, gdt_address, gdt, 31 * sizeof(struct SegmentDescriptor)); + uc_assert_success(err); + + // map 1 page for FS + err = uc_mem_map(uc, fs_address, 0x1000, UC_PROT_WRITE | UC_PROT_READ); + uc_assert_success(err); + + // write machine code to be emulated to memory + err = uc_mem_write(uc, code_address, code, sizeof(code)-1); + uc_assert_success(err); + + // initialize machine registers + err = uc_reg_write(uc, UC_X86_REG_ESP, &r_esp); + uc_assert_success(err); + + // when setting SS, need rpl == cpl && dpl == cpl + // emulator starts with cpl == 0, so we need a dpl 0 descriptor and rpl 0 selector + err = uc_reg_write(uc, UC_X86_REG_SS, &r_ss); + uc_assert_success(err); + + err = uc_reg_write(uc, UC_X86_REG_CS, &r_cs); + uc_assert_success(err); + err = uc_reg_write(uc, UC_X86_REG_DS, &r_ds); + uc_assert_success(err); + err = uc_reg_write(uc, UC_X86_REG_ES, &r_es); + uc_assert_success(err); + err = uc_reg_write(uc, UC_X86_REG_FS, &r_fs); + uc_assert_success(err); + + // emulate machine code in infinite time + err = uc_emu_start(uc, code_address, code_address+sizeof(code)-1, 0, 0); + uc_assert_success(err); + + // read from memory + err = uc_mem_read(uc, r_esp - 8, buf, 8); + uc_assert_success(err); + + int i; + for (i = 0; i < 8; i++) { + fprintf(stderr, "%02hhx", buf[i]); + } + fprintf(stderr, "\n"); + + assert(memcmp(buf, "\xef\xcd\xab\x89\x67\x45\x23\x01", 8) == 0); + + // read from memory + err = uc_mem_read(uc, fs_address, buf, 8); + uc_assert_success(err); + + assert(memcmp(buf, "\x67\x45\x23\x01\xef\xcd\xab\x89", 8) == 0); + + uc_close(uc); +} + +/******************************************************************************/ + +int main(int argc, char **argv) +{ + gdt_demo(); + + fprintf(stderr, "success\n"); + + return 0; +} diff --git a/tests/regress/001-bad_condition_code_0xe.c b/tests/regress/001-bad_condition_code_0xe.c new file mode 100644 index 00000000..bcc51e8b --- /dev/null +++ b/tests/regress/001-bad_condition_code_0xe.c @@ -0,0 +1,31 @@ +#include + +#define HARDWARE_ARCHITECTURE UC_ARCH_ARM +#define HARDWARE_MODE 16 +#define MEMORY_STARTING_ADDRESS 8192 +#define MEMORY_SIZE 4096 +#define MEMORY_PERMISSIONS 6 +#define BINARY_CODE "\x56\xe8\x46\x46\x80\xf6\x8c\x56\xff\xbf\xcd\x90\xda\xa0\xed\xe8\x46\x43\x45\xe5\x80\x90\x44\x46\x04" + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { + printf("hook_code(…) called\n"); +} + +int main(int argc, char **argv, char **envp) { + uc_engine *uc; + if (uc_open(HARDWARE_ARCHITECTURE, HARDWARE_MODE, &uc)) { + printf("uc_open(…) failed\n"); + return 1; + } + uc_mem_map(uc, MEMORY_STARTING_ADDRESS, MEMORY_SIZE, MEMORY_PERMISSIONS); + if (uc_mem_write(uc, MEMORY_STARTING_ADDRESS, BINARY_CODE, sizeof(BINARY_CODE) - 1)) { + printf("uc_mem_write(…) failed\n"); + return 1; + } + uc_hook trace; + uc_hook_add(uc, &trace, UC_HOOK_CODE, hook_code, NULL, (uint64_t)MEMORY_STARTING_ADDRESS, (uint64_t)(MEMORY_STARTING_ADDRESS + 1)); + printf("uc_emu_start(…)\n"); + uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 0); + printf("done\n"); + return 0; +} diff --git a/tests/regress/002-qemu__fatal__unimplemented_control_register_write_0xffb___0x0.c b/tests/regress/002-qemu__fatal__unimplemented_control_register_write_0xffb___0x0.c new file mode 100644 index 00000000..6f8575be --- /dev/null +++ b/tests/regress/002-qemu__fatal__unimplemented_control_register_write_0xffb___0x0.c @@ -0,0 +1,31 @@ +#include + +#define HARDWARE_ARCHITECTURE UC_ARCH_M68K +#define HARDWARE_MODE 1073741824 +#define MEMORY_STARTING_ADDRESS 8388608 +#define MEMORY_SIZE 2097152 +#define MEMORY_PERMISSIONS 7 +#define BINARY_CODE "\xaf\x80\x4e\x7b\xff\xfb\x80\x4e\x3e\x80" + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { + printf("hook_code(…) called\n"); +} + +int main(int argc, char **argv, char **envp) { + uc_engine *uc; + if (uc_open(HARDWARE_ARCHITECTURE, HARDWARE_MODE, &uc)) { + printf("uc_open(…) failed\n"); + return 1; + } + uc_mem_map(uc, MEMORY_STARTING_ADDRESS, MEMORY_SIZE, MEMORY_PERMISSIONS); + if (uc_mem_write(uc, MEMORY_STARTING_ADDRESS, BINARY_CODE, sizeof(BINARY_CODE) - 1)) { + printf("uc_mem_write(…) failed\n"); + return 1; + } + uc_hook trace; + uc_hook_add(uc, &trace, UC_HOOK_CODE, hook_code, NULL, (uint64_t)MEMORY_STARTING_ADDRESS, (uint64_t)(MEMORY_STARTING_ADDRESS + 1)); + printf("uc_emu_start(…)\n"); + uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 0); + printf("done\n"); + return 0; +} diff --git a/tests/regress/003-qemu__fatal__wdebug_not_implemented.c b/tests/regress/003-qemu__fatal__wdebug_not_implemented.c new file mode 100644 index 00000000..4e07235b --- /dev/null +++ b/tests/regress/003-qemu__fatal__wdebug_not_implemented.c @@ -0,0 +1,31 @@ +#include + +#define HARDWARE_ARCHITECTURE UC_ARCH_M68K +#define HARDWARE_MODE 1073741824 +#define MEMORY_STARTING_ADDRESS 1048576 +#define MEMORY_SIZE 403456 +#define MEMORY_PERMISSIONS 7 +#define BINARY_CODE "\x42\xc7\xfb\xfb\x54\x36" + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { + printf("hook_code(…) called\n"); +} + +int main(int argc, char **argv, char **envp) { + uc_engine *uc; + if (uc_open(HARDWARE_ARCHITECTURE, HARDWARE_MODE, &uc)) { + printf("uc_open(…) failed\n"); + return 1; + } + uc_mem_map(uc, MEMORY_STARTING_ADDRESS, MEMORY_SIZE, MEMORY_PERMISSIONS); + if (uc_mem_write(uc, MEMORY_STARTING_ADDRESS, BINARY_CODE, sizeof(BINARY_CODE) - 1)) { + printf("uc_mem_write(…) failed\n"); + return 1; + } + uc_hook trace; + uc_hook_add(uc, &trace, UC_HOOK_CODE, hook_code, NULL, (uint64_t)MEMORY_STARTING_ADDRESS, (uint64_t)(MEMORY_STARTING_ADDRESS + 1)); + printf("uc_emu_start(…)\n"); + uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 0); + printf("done\n"); + return 0; +} diff --git a/tests/regress/004-segmentation_fault_1.c b/tests/regress/004-segmentation_fault_1.c new file mode 100644 index 00000000..636cae7e --- /dev/null +++ b/tests/regress/004-segmentation_fault_1.c @@ -0,0 +1,31 @@ +#include + +#define HARDWARE_ARCHITECTURE UC_ARCH_ARM +#define HARDWARE_MODE 16 +#define MEMORY_STARTING_ADDRESS 1024 +#define MEMORY_SIZE 1796096 +#define MEMORY_PERMISSIONS 7 +#define BINARY_CODE "\x20\xbf\xbf\xbf\xbf\xdd\x5d\x74\x5e\x66\x72\x10" + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { + printf("hook_code(…) called\n"); +} + +int main(int argc, char **argv, char **envp) { + uc_engine *uc; + if (uc_open(HARDWARE_ARCHITECTURE, HARDWARE_MODE, &uc)) { + printf("uc_open(…) failed\n"); + return 1; + } + uc_mem_map(uc, MEMORY_STARTING_ADDRESS, MEMORY_SIZE, MEMORY_PERMISSIONS); + if (uc_mem_write(uc, MEMORY_STARTING_ADDRESS, BINARY_CODE, sizeof(BINARY_CODE) - 1)) { + printf("uc_mem_write(…) failed\n"); + return 1; + } + uc_hook trace; + uc_hook_add(uc, &trace, UC_HOOK_CODE, hook_code, NULL, (uint64_t)MEMORY_STARTING_ADDRESS, (uint64_t)(MEMORY_STARTING_ADDRESS + 1)); + printf("uc_emu_start(…)\n"); + uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 0); + printf("done\n"); + return 0; +} diff --git a/tests/regress/005-qemu__fatal__illegal_instruction__0000___00000404.c b/tests/regress/005-qemu__fatal__illegal_instruction__0000___00000404.c new file mode 100644 index 00000000..b2bea73c --- /dev/null +++ b/tests/regress/005-qemu__fatal__illegal_instruction__0000___00000404.c @@ -0,0 +1,31 @@ +#include + +#define HARDWARE_ARCHITECTURE UC_ARCH_M68K +#define HARDWARE_MODE 1073741824 +#define MEMORY_STARTING_ADDRESS 1024 +#define MEMORY_SIZE 1044480 +#define MEMORY_PERMISSIONS 5 +#define BINARY_CODE "\x4c\x4c" + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { + printf("hook_code(…) called\n"); +} + +int main(int argc, char **argv, char **envp) { + uc_engine *uc; + if (uc_open(HARDWARE_ARCHITECTURE, HARDWARE_MODE, &uc)) { + printf("uc_open(…) failed\n"); + return 1; + } + uc_mem_map(uc, MEMORY_STARTING_ADDRESS, MEMORY_SIZE, MEMORY_PERMISSIONS); + if (uc_mem_write(uc, MEMORY_STARTING_ADDRESS, BINARY_CODE, sizeof(BINARY_CODE) - 1)) { + printf("uc_mem_write(…) failed\n"); + return 1; + } + uc_hook trace; + uc_hook_add(uc, &trace, UC_HOOK_CODE, hook_code, NULL, (uint64_t)MEMORY_STARTING_ADDRESS, (uint64_t)(MEMORY_STARTING_ADDRESS + 1)); + printf("uc_emu_start(…)\n"); + uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 0); + printf("done\n"); + return 0; +} diff --git a/tests/regress/006-qemu__fatal__illegal_instruction__0421___00040026.c b/tests/regress/006-qemu__fatal__illegal_instruction__0421___00040026.c new file mode 100644 index 00000000..607c9d5d --- /dev/null +++ b/tests/regress/006-qemu__fatal__illegal_instruction__0421___00040026.c @@ -0,0 +1,31 @@ +#include + +#define HARDWARE_ARCHITECTURE UC_ARCH_M68K +#define HARDWARE_MODE 1073741824 +#define MEMORY_STARTING_ADDRESS 262144 +#define MEMORY_SIZE 403456 +#define MEMORY_PERMISSIONS 7 +#define BINARY_CODE "\xe2\x86\x09\xbc\xf2\x17\x09\xca\xca\xca\xca\x09\x09\x09\xf2\x17\x09\x20\x09\x09\xf2\x08\x09\x03\x09\xca\x6b\x6b\x6b\x1e\xca\xca\x86\x09\x09\xf2\x17\x09\x04\x21\x09\x09\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf4\xf2" + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { + printf("hook_code(…) called\n"); +} + +int main(int argc, char **argv, char **envp) { + uc_engine *uc; + if (uc_open(HARDWARE_ARCHITECTURE, HARDWARE_MODE, &uc)) { + printf("uc_open(…) failed\n"); + return 1; + } + uc_mem_map(uc, MEMORY_STARTING_ADDRESS, MEMORY_SIZE, MEMORY_PERMISSIONS); + if (uc_mem_write(uc, MEMORY_STARTING_ADDRESS, BINARY_CODE, sizeof(BINARY_CODE) - 1)) { + printf("uc_mem_write(…) failed\n"); + return 1; + } + uc_hook trace; + uc_hook_add(uc, &trace, UC_HOOK_CODE, hook_code, NULL, (uint64_t)MEMORY_STARTING_ADDRESS, (uint64_t)(MEMORY_STARTING_ADDRESS + 1)); + printf("uc_emu_start(…)\n"); + uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 0); + printf("done\n"); + return 0; +} diff --git a/tests/regress/LICENSE b/tests/regress/LICENSE new file mode 100644 index 00000000..dd85900f --- /dev/null +++ b/tests/regress/LICENSE @@ -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 + +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. diff --git a/tests/regress/Makefile b/tests/regress/Makefile index 6b8381a9..9fc1f39c 100644 --- a/tests/regress/Makefile +++ b/tests/regress/Makefile @@ -38,6 +38,20 @@ TESTS += hook_extrainvoke TESTS += sysenter_hook_x86 TESTS += emu_clear_errors TESTS += mem_fuzz +TESTS += 001-bad_condition_code_0xe +TESTS += 002-qemu__fatal__unimplemented_control_register_write_0xffb___0x0 +TESTS += 003-qemu__fatal__wdebug_not_implemented +TESTS += 004-segmentation_fault_1 +TESTS += 005-qemu__fatal__illegal_instruction__0000___00000404 +TESTS += 006-qemu__fatal__illegal_instruction__0421___00040026 +TESTS += mem_64_c + +TESTS += memleak_x86 +TESTS += memleak_arm +TESTS += memleak_arm64 +TESTS += memleak_mips +TESTS += memleak_m68k +TESTS += memleak_sparc all: $(TESTS) diff --git a/tests/regress/block_test.c b/tests/regress/block_test.c index 9a648f07..71d1021f 100644 --- a/tests/regress/block_test.c +++ b/tests/regress/block_test.c @@ -65,7 +65,7 @@ int main() { uc_hook h1, h2; - err = uc_hook_add(uc, &h1, UC_HOOK_BLOCK, cb_hookblock, NULL, (uint64_t)1, (uint64_t)0); + err = uc_hook_add(uc, &h1, UC_HOOK_BLOCK, cb_hookblock, NULL, 1, 0); if (err != UC_ERR_OK) { fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err)); exit(0); diff --git a/tests/regress/eflags_nosync.c b/tests/regress/eflags_nosync.c index 3e141414..f026ce01 100644 --- a/tests/regress/eflags_nosync.c +++ b/tests/regress/eflags_nosync.c @@ -120,10 +120,10 @@ static void VM_exec() uc_reg_write(uc, UC_X86_REG_EDI, &r_edi); uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags); - uc_hook_add(uc, &trace1, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, (void *)hook_invalid_mem, NULL); + uc_hook_add(uc, &trace1, UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, (void *)hook_invalid_mem, NULL, 1, 0); // tracing all instruction by having @begin > @end - uc_hook_add(uc, &trace2, UC_HOOK_CODE, (void *)hook_ins, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace2, UC_HOOK_CODE, (void *)hook_ins, NULL, 1, 0); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + (sizeof(X86_CODE32) - 1), 0, 0); diff --git a/tests/regress/emu_clear_errors.c b/tests/regress/emu_clear_errors.c index 36c4e745..bed3965d 100644 --- a/tests/regress/emu_clear_errors.c +++ b/tests/regress/emu_clear_errors.c @@ -112,7 +112,7 @@ int main() { uc_hook h1; - err = uc_hook_add(uc, &h1, UC_HOOK_MEM_UNMAPPED, cb_hookunmapped, NULL); + err = uc_hook_add(uc, &h1, UC_HOOK_MEM_UNMAPPED, cb_hookunmapped, NULL, 1, 0); if (err != UC_ERR_OK) { fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err)); exit(0); diff --git a/tests/regress/emu_stop_in_hook_overrun.c b/tests/regress/emu_stop_in_hook_overrun.c index 6c18c74d..9b962a25 100644 --- a/tests/regress/emu_stop_in_hook_overrun.c +++ b/tests/regress/emu_stop_in_hook_overrun.c @@ -47,10 +47,10 @@ bool test_passed_ok = false; // This hook is used to show that code is executing in the emulator. static void mips_codehook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { - printf("Executing: %llX\n", address); + printf("Executing: %"PRIx64"\n", address); if( address == 0x100008 ) { - printf("Stopping at: %llX\n", address); + printf("Stopping at: %"PRIx64"\n", address); uc_emu_stop(uc); } } @@ -98,7 +98,7 @@ int main(int argc, char **argv, char **envp) // hook all instructions by having @begin > @end printf("uc_hook_add()\n"); - uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, 1, 0); if( err ) { printf("Failed on uc_hook_add(code) with error returned: %u\n", err); diff --git a/tests/regress/hook_extrainvoke.c b/tests/regress/hook_extrainvoke.c index 5f74e4d7..174257c9 100644 --- a/tests/regress/hook_extrainvoke.c +++ b/tests/regress/hook_extrainvoke.c @@ -58,7 +58,7 @@ static void VM_exec() uc_reg_write(uc, UC_X86_REG_ESP, &r_esp); //make stack pointer point to already mapped memory so we don't need to hook. uc_reg_write(uc, UC_X86_REG_EFLAGS, &eflags); - uc_hook_add(uc, &trace, UC_HOOK_CODE, (void *)hook_ins, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &trace, UC_HOOK_CODE, (void *)hook_ins, NULL, 1, 0); // emulate machine code in infinite time err = uc_emu_start(uc, ADDRESS, ADDRESS + (sizeof(X86_CODE32) - 1), 0, 0); diff --git a/tests/regress/invalid_read_in_cpu_tb_exec.c b/tests/regress/invalid_read_in_cpu_tb_exec.c index f9fe162c..d618c31a 100644 --- a/tests/regress/invalid_read_in_cpu_tb_exec.c +++ b/tests/regress/invalid_read_in_cpu_tb_exec.c @@ -25,7 +25,7 @@ int main(int argc, char **argv, char **envp) { return 1; } uc_hook hook; - uc_hook_add(uc, &hook, UC_HOOK_BLOCK, hook_block, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &hook, UC_HOOK_BLOCK, hook_block, NULL, 1, 0); printf("uc_emu_start(…)\n"); uc_emu_start(uc, STARTING_ADDRESS, STARTING_ADDRESS + sizeof(BINARY) - 1, 0, 20); printf("done\n"); diff --git a/tests/regress/mem_64_c.c b/tests/regress/mem_64_c.c new file mode 100644 index 00000000..e09a90da --- /dev/null +++ b/tests/regress/mem_64_c.c @@ -0,0 +1,39 @@ +#include +#include + +uint64_t starts[] = {0x10000000, 0x110004000ll}; + +int main(int argc, char **argv, char **envp) { + uc_engine *uc; + uc_err err; + int i; + // Initialize emulator in X86-64bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u\n", err); + return 1; + } + + for (i = 0; i < (sizeof(starts) / sizeof(uint64_t)); i++) { + uc_mem_map(uc, starts[i], 4096, UC_PROT_ALL); + } + + uint32_t count; + uc_mem_region *regions; + int err_count = 0; + err = uc_mem_regions(uc, ®ions, &count); + if (err == UC_ERR_OK) { + for (i = 0; i < count; i++) { + fprintf(stderr, "region %d: 0x%llx-0x%llx (%d)\n", i, regions[i].begin, regions[i].end - 1, regions[i].perms); + if (regions[i].begin != starts[i]) { + err_count++; + fprintf(stderr, " ERROR: region start does not match requested start address, expected 0x%llx, found 0x%llx\n", + starts[i], regions[i].begin); + } + } + free(regions); + } + + uc_close(uc); + return err_count; +} diff --git a/tests/regress/mem_exec.c b/tests/regress/mem_exec.c index db9a2bc1..8be1dab3 100644 --- a/tests/regress/mem_exec.c +++ b/tests/regress/mem_exec.c @@ -205,7 +205,7 @@ int main(int argc, char **argv, char **envp) printf("ok %d - Program written to memory\n", log_num++); } - 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) { printf("not ok %d - Failed to install UC_HOOK_CODE ucr\n", log_num++); return 6; } else { @@ -213,7 +213,7 @@ int main(int argc, char **argv, char **envp) } // intercept memory write events - if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE ucr\n", log_num++); return 7; } else { @@ -221,7 +221,7 @@ int main(int argc, char **argv, char **envp) } // intercept invalid memory events - if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_PROT | UC_HOOK_MEM_FETCH_PROT, hook_mem_invalid, NULL) != UC_ERR_OK) { + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_PROT | UC_HOOK_MEM_FETCH_PROT, hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install memory invalid handler\n", log_num++); return 8; } else { diff --git a/tests/regress/mem_protect.c b/tests/regress/mem_protect.c index d29dc490..3f1ec820 100644 --- a/tests/regress/mem_protect.c +++ b/tests/regress/mem_protect.c @@ -213,7 +213,7 @@ int main(int argc, char **argv, char **envp) printf("ok %d - Program written to memory\n", log_num++); } - 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) { printf("not ok %d - Failed to install UC_HOOK_CODE ucr\n", log_num++); return 5; } else { @@ -221,7 +221,7 @@ int main(int argc, char **argv, char **envp) } // intercept memory write events - if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE ucr\n", log_num++); return 6; } else { @@ -229,7 +229,7 @@ int main(int argc, char **argv, char **envp) } // intercept invalid memory events - if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_PROT, hook_mem_invalid, NULL) != UC_ERR_OK) { + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_PROT, hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install memory invalid handler\n", log_num++); return 7; } else { diff --git a/tests/regress/mem_unmap.c b/tests/regress/mem_unmap.c index 16a9f88a..17997870 100644 --- a/tests/regress/mem_unmap.c +++ b/tests/regress/mem_unmap.c @@ -208,7 +208,7 @@ int main(int argc, char **argv, char **envp) printf("ok %d - Program written to memory\n", log_num++); } - 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) { printf("not ok %d - Failed to install UC_HOOK_CODE ucr\n", log_num++); return 5; } else { @@ -216,7 +216,7 @@ int main(int argc, char **argv, char **envp) } // intercept memory write events - if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE ucr\n", log_num++); return 6; } else { @@ -224,7 +224,7 @@ int main(int argc, char **argv, char **envp) } // intercept invalid memory events - if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_invalid, NULL) != UC_ERR_OK) { + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_invalid, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install memory invalid handler\n", log_num++); return 7; } else { diff --git a/tests/regress/memleak_arm.c b/tests/regress/memleak_arm.c new file mode 100644 index 00000000..21430795 --- /dev/null +++ b/tests/regress/memleak_arm.c @@ -0,0 +1,178 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh, 2015 */ + +/* Sample code to demonstrate how to emulate ARM code */ + +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include "unicorn_dynload.h" +#else // DYNLOAD +#include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER + + +// code to be emulated +#define ARM_CODE "\x37\x00\xa0\xe3\x03\x10\x42\xe0" // mov r0, #0x37; sub r1, r2, r3 +#define THUMB_CODE "\x83\xb0" // sub sp, #0xc + +// memory address where emulation starts +#define ADDRESS 0x10000 + +static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); +} + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); +} + +static void test_arm(void) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1, trace2; + + int r0 = 0x1234; // R0 register + int r2 = 0x6789; // R1 register + int r3 = 0x3333; // R2 register + int r1; // R1 register + + printf("Emulate ARM code\n"); + + // Initialize emulator in ARM mode + err = uc_open(UC_ARCH_ARM, UC_MODE_ARM, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u (%s)\n", + err, uc_strerror(err)); + return; + } + + // map 2MB memory for this emulation + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc_mem_write(uc, ADDRESS, ARM_CODE, sizeof(ARM_CODE) - 1); + + // initialize machine registers + uc_reg_write(uc, UC_ARM_REG_R0, &r0); + uc_reg_write(uc, UC_ARM_REG_R2, &r2); + 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); + + // 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); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned: %u\n", err); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_ARM_REG_R0, &r0); + uc_reg_read(uc, UC_ARM_REG_R1, &r1); + printf(">>> R0 = 0x%x\n", r0); + printf(">>> R1 = 0x%x\n", r1); + + uc_close(uc); +} + +static void test_thumb(void) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1, trace2; + + int sp = 0x1234; // R0 register + + printf("Emulate THUMB code\n"); + + // Initialize emulator in ARM mode + err = uc_open(UC_ARCH_ARM, UC_MODE_THUMB, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u (%s)\n", + err, uc_strerror(err)); + return; + } + + // map 2MB memory for this emulation + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc_mem_write(uc, ADDRESS, THUMB_CODE, sizeof(THUMB_CODE) - 1); + + // initialize machine registers + 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); + + // 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); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(THUMB_CODE) -1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned: %u\n", err); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_ARM_REG_SP, &sp); + printf(">>> SP = 0x%x\n", sp); + + uc_close(uc); +} + +int main(int argc, char **argv, char **envp) +{ + // dynamically load shared library +#ifdef DYNLOAD + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + // test memleak + while(1) { + test_arm(); + printf("==========================\n"); + test_thumb(); + } + + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + + return 0; +} diff --git a/tests/regress/memleak_arm64.c b/tests/regress/memleak_arm64.c new file mode 100644 index 00000000..e9b43c0e --- /dev/null +++ b/tests/regress/memleak_arm64.c @@ -0,0 +1,122 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh, 2015 */ + +/* Sample code to demonstrate how to emulate ARM64 code */ + +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include "unicorn_dynload.h" +#else // DYNLOAD +#include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER + + +// code to be emulated +#define ARM_CODE "\xab\x01\x0f\x8b" // add x11, x13, x15 + +// memory address where emulation starts +#define ADDRESS 0x10000 + +static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); +} + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); +} + +static void test_arm64(void) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1, trace2; + + int64_t x11 = 0x1234; // X11 register + int64_t x13 = 0x6789; // X13 register + int64_t x15 = 0x3333; // X15 register + + printf("Emulate ARM64 code\n"); + + // Initialize emulator in ARM mode + err = uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u (%s)\n", + err, uc_strerror(err)); + return; + } + + // map 2MB memory for this emulation + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc_mem_write(uc, ADDRESS, ARM_CODE, sizeof(ARM_CODE) - 1); + + // initialize machine registers + uc_reg_write(uc, UC_ARM64_REG_X11, &x11); + uc_reg_write(uc, UC_ARM64_REG_X13, &x13); + 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); + + // 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); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(ARM_CODE) -1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned: %u\n", err); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_ARM64_REG_X11, &x11); + printf(">>> X11 = 0x%" PRIx64 "\n", x11); + + uc_close(uc); +} + +int main(int argc, char **argv, char **envp) +{ + // dynamically load shared library +#ifdef DYNLOAD + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + while(1) { + test_arm64(); + } + + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + + return 0; +} diff --git a/tests/regress/memleak_m68k.c b/tests/regress/memleak_m68k.c new file mode 100644 index 00000000..8504daf1 --- /dev/null +++ b/tests/regress/memleak_m68k.c @@ -0,0 +1,185 @@ +/* Unicorn Emulator Engine */ +/* By Loi Anh Tuan, 2015 */ + +/* Sample code to demonstrate how to emulate m68k code */ + +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include "unicorn_dynload.h" +#else // DYNLOAD +#include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER + +// code to be emulated +#define M68K_CODE "\x76\xed" // movq #-19, %d3 + +// memory address where emulation starts +#define ADDRESS 0x10000 + +static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); +} + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); +} + +static void test_m68k(void) +{ + uc_engine *uc; + uc_hook trace1, trace2; + uc_err err; + + int d0 = 0x0000; // d0 data register + int d1 = 0x0000; // d1 data register + int d2 = 0x0000; // d2 data register + int d3 = 0x0000; // d3 data register + int d4 = 0x0000; // d4 data register + int d5 = 0x0000; // d5 data register + int d6 = 0x0000; // d6 data register + int d7 = 0x0000; // d7 data register + + int a0 = 0x0000; // a0 address register + int a1 = 0x0000; // a1 address register + int a2 = 0x0000; // a2 address register + int a3 = 0x0000; // a3 address register + int a4 = 0x0000; // a4 address register + int a5 = 0x0000; // a5 address register + int a6 = 0x0000; // a6 address register + int a7 = 0x0000; // a6 address register + + int pc = 0x0000; // program counter + int sr = 0x0000; // status register + + printf("Emulate M68K code\n"); + + // Initialize emulator in M68K mode + err = uc_open(UC_ARCH_M68K, UC_MODE_BIG_ENDIAN, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u (%s)\n", + err, uc_strerror(err)); + return; + } + + // map 2MB memory for this emulation + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc_mem_write(uc, ADDRESS, M68K_CODE, sizeof(M68K_CODE) - 1); + + // initialize machine registers + uc_reg_write(uc, UC_M68K_REG_D0, &d0); + uc_reg_write(uc, UC_M68K_REG_D1, &d1); + uc_reg_write(uc, UC_M68K_REG_D2, &d2); + uc_reg_write(uc, UC_M68K_REG_D3, &d3); + uc_reg_write(uc, UC_M68K_REG_D4, &d4); + uc_reg_write(uc, UC_M68K_REG_D5, &d5); + uc_reg_write(uc, UC_M68K_REG_D6, &d6); + uc_reg_write(uc, UC_M68K_REG_D7, &d7); + + uc_reg_write(uc, UC_M68K_REG_A0, &a0); + uc_reg_write(uc, UC_M68K_REG_A1, &a1); + uc_reg_write(uc, UC_M68K_REG_A2, &a2); + uc_reg_write(uc, UC_M68K_REG_A3, &a3); + uc_reg_write(uc, UC_M68K_REG_A4, &a4); + uc_reg_write(uc, UC_M68K_REG_A5, &a5); + uc_reg_write(uc, UC_M68K_REG_A6, &a6); + uc_reg_write(uc, UC_M68K_REG_A7, &a7); + + uc_reg_write(uc, UC_M68K_REG_PC, &pc); + 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); + + // tracing all instruction + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(M68K_CODE)-1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned: %u\n", err); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_M68K_REG_D0, &d0); + uc_reg_read(uc, UC_M68K_REG_D1, &d1); + uc_reg_read(uc, UC_M68K_REG_D2, &d2); + uc_reg_read(uc, UC_M68K_REG_D3, &d3); + uc_reg_read(uc, UC_M68K_REG_D4, &d4); + uc_reg_read(uc, UC_M68K_REG_D5, &d5); + uc_reg_read(uc, UC_M68K_REG_D6, &d6); + uc_reg_read(uc, UC_M68K_REG_D7, &d7); + + uc_reg_read(uc, UC_M68K_REG_A0, &a0); + uc_reg_read(uc, UC_M68K_REG_A1, &a1); + uc_reg_read(uc, UC_M68K_REG_A2, &a2); + uc_reg_read(uc, UC_M68K_REG_A3, &a3); + uc_reg_read(uc, UC_M68K_REG_A4, &a4); + uc_reg_read(uc, UC_M68K_REG_A5, &a5); + uc_reg_read(uc, UC_M68K_REG_A6, &a6); + uc_reg_read(uc, UC_M68K_REG_A7, &a7); + + uc_reg_read(uc, UC_M68K_REG_PC, &pc); + uc_reg_read(uc, UC_M68K_REG_SR, &sr); + + printf(">>> A0 = 0x%x\t\t>>> D0 = 0x%x\n", a0, d0); + printf(">>> A1 = 0x%x\t\t>>> D1 = 0x%x\n", a1, d1); + printf(">>> A2 = 0x%x\t\t>>> D2 = 0x%x\n", a2, d2); + printf(">>> A3 = 0x%x\t\t>>> D3 = 0x%x\n", a3, d3); + printf(">>> A4 = 0x%x\t\t>>> D4 = 0x%x\n", a4, d4); + printf(">>> A5 = 0x%x\t\t>>> D5 = 0x%x\n", a5, d5); + printf(">>> A6 = 0x%x\t\t>>> D6 = 0x%x\n", a6, d6); + printf(">>> A7 = 0x%x\t\t>>> D7 = 0x%x\n", a7, d7); + printf(">>> PC = 0x%x\n", pc); + printf(">>> SR = 0x%x\n", sr); + + uc_close(uc); +} + +int main(int argc, char **argv, char **envp) +{ + // dynamically load shared library +#ifdef DYNLOAD + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + // test memleak + while(1) { + test_m68k(); + } + + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + + return 0; +} diff --git a/tests/regress/memleak_mips.c b/tests/regress/memleak_mips.c new file mode 100644 index 00000000..e82a301b --- /dev/null +++ b/tests/regress/memleak_mips.c @@ -0,0 +1,171 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh, 2015 */ + +/* Sample code to demonstrate how to emulate Mips code (big endian) */ + +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include "unicorn_dynload.h" +#else // DYNLOAD +#include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER + + +// code to be emulated +#define MIPS_CODE_EB "\x34\x21\x34\x56" // ori $at, $at, 0x3456; +#define MIPS_CODE_EL "\x56\x34\x21\x34" // ori $at, $at, 0x3456; + +// memory address where emulation starts +#define ADDRESS 0x10000 + +static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); +} + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); +} + +static void test_mips_eb(void) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1, trace2; + + int r1 = 0x6789; // R1 register + + printf("Emulate MIPS code (big-endian)\n"); + + // Initialize emulator in MIPS mode + err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_BIG_ENDIAN, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u (%s)\n", + err, uc_strerror(err)); + return; + } + + // map 2MB memory for this emulation + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc_mem_write(uc, ADDRESS, MIPS_CODE_EB, sizeof(MIPS_CODE_EB) - 1); + + // initialize machine registers + 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); + + // 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); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(MIPS_CODE_EB) - 1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err, uc_strerror(err)); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_MIPS_REG_1, &r1); + printf(">>> R1 = 0x%x\n", r1); + + uc_close(uc); +} + +static void test_mips_el(void) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1, trace2; + + int r1 = 0x6789; // R1 register + + printf("===========================\n"); + printf("Emulate MIPS code (little-endian)\n"); + + // Initialize emulator in MIPS mode + err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u (%s)\n", + err, uc_strerror(err)); + return; + } + + // map 2MB memory for this emulation + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc_mem_write(uc, ADDRESS, MIPS_CODE_EL, sizeof(MIPS_CODE_EL) - 1); + + // initialize machine registers + 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); + + // 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); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(MIPS_CODE_EL) - 1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned: %u (%s)\n", err, uc_strerror(err)); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_MIPS_REG_1, &r1); + printf(">>> R1 = 0x%x\n", r1); + + uc_close(uc); +} + +int main(int argc, char **argv, char **envp) +{ + // dynamically load shared library +#ifdef DYNLOAD + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + // test memleak + while(1) { + test_mips_eb(); + test_mips_el(); + } + + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + + return 0; +} diff --git a/tests/regress/memleak_sparc.c b/tests/regress/memleak_sparc.c new file mode 100644 index 00000000..1493d24e --- /dev/null +++ b/tests/regress/memleak_sparc.c @@ -0,0 +1,125 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh, 2015 */ + +/* Sample code to demonstrate how to emulate Sparc code */ + +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include "unicorn_dynload.h" +#else // DYNLOAD +#include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER + + +// code to be emulated +#define SPARC_CODE "\x86\x00\x40\x02" // add %g1, %g2, %g3; +//#define SPARC_CODE "\xbb\x70\x00\x00" // illegal code + +// memory address where emulation starts +#define ADDRESS 0x10000 + +static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); +} + +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); +} + +static void test_sparc(void) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1, trace2; + + int g1 = 0x1230; // G1 register + int g2 = 0x6789; // G2 register + int g3 = 0x5555; // G3 register + + printf("Emulate SPARC code\n"); + + // Initialize emulator in Sparc mode + err = uc_open(UC_ARCH_SPARC, UC_MODE_32, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u (%s)\n", + err, uc_strerror(err)); + return; + } + + // map 2MB memory for this emulation + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + uc_mem_write(uc, ADDRESS, SPARC_CODE, sizeof(SPARC_CODE) - 1); + + // initialize machine registers + uc_reg_write(uc, UC_SPARC_REG_G1, &g1); + uc_reg_write(uc, UC_SPARC_REG_G2, &g2); + 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); + + // tracing all instructions with customized callback + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(SPARC_CODE) - 1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned: %u (%s)\n", + err, uc_strerror(err)); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_SPARC_REG_G3, &g3); + printf(">>> G3 = 0x%x\n", g3); + + uc_close(uc); +} + +int main(int argc, char **argv, char **envp) +{ + // dynamically load shared library +#ifdef DYNLOAD + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + // test memleak + while(1) { + test_sparc(); + } + + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + + return 0; +} diff --git a/tests/regress/memleak_x86.c b/tests/regress/memleak_x86.c new file mode 100644 index 00000000..737f7305 --- /dev/null +++ b/tests/regress/memleak_x86.c @@ -0,0 +1,306 @@ +/* Unicorn Emulator Engine */ +/* By Nguyen Anh Quynh & Dang Hoang Vu, 2015 */ + +/* Sample code to demonstrate how to emulate X86 code */ + +// windows specific +#ifdef _MSC_VER +#include +#include +#define PRIx64 "llX" +#ifdef DYNLOAD +#include "unicorn_dynload.h" +#else // DYNLOAD +#include +#ifdef _WIN64 +#pragma comment(lib, "unicorn_staload64.lib") +#else // _WIN64 +#pragma comment(lib, "unicorn_staload.lib") +#endif // _WIN64 +#endif // DYNLOAD + +// posix specific +#else // _MSC_VER +#include +#include +#include +#endif // _MSC_VER + +// common includes +#include + + +// code to be emulated +#define X86_CODE32 "\x41\x4a" // INC ecx; DEC edx +#define X86_CODE32_JUMP "\xeb\x02\x90\x90\x90\x90\x90\x90" // jmp 4; nop; nop; nop; nop; nop; nop +// #define X86_CODE32_SELF "\xeb\x1c\x5a\x89\xd6\x8b\x02\x66\x3d\xca\x7d\x75\x06\x66\x05\x03\x03\x89\x02\xfe\xc2\x3d\x41\x41\x41\x41\x75\xe9\xff\xe6\xe8\xdf\xff\xff\xff\x31\xd2\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xca\x7d\x41\x41\x41\x41" +//#define X86_CODE32 "\x51\x51\x51\x51" // PUSH ecx; +#define X86_CODE32_LOOP "\x41\x4a\xeb\xfe" // INC ecx; DEC edx; JMP self-loop +#define X86_CODE32_MEM_WRITE "\x89\x0D\xAA\xAA\xAA\xAA\x41\x4a" // mov [0xaaaaaaaa], ecx; INC ecx; DEC edx +#define X86_CODE32_MEM_READ "\x8B\x0D\xAA\xAA\xAA\xAA\x41\x4a" // mov ecx,[0xaaaaaaaa]; INC ecx; DEC edx + +#define X86_CODE32_JMP_INVALID "\xe9\xe9\xee\xee\xee\x41\x4a" // JMP outside; INC ecx; DEC edx +#define X86_CODE32_INOUT "\x41\xE4\x3F\x4a\xE6\x46\x43" // INC ecx; IN AL, 0x3f; DEC edx; OUT 0x46, AL; INC ebx + +//#define X86_CODE64 "\x41\xBC\x3B\xB0\x28\x2A \x49\x0F\xC9 \x90 \x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9" // <== still crash +//#define X86_CODE64 "\x41\xBC\x3B\xB0\x28\x2A\x49\x0F\xC9\x90\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9" +#define X86_CODE64 "\x41\xBC\x3B\xB0\x28\x2A\x49\x0F\xC9\x90\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9\x4D\x29\xF4\x49\x81\xC9\xF6\x8A\xC6\x53\x4D\x87\xED\x48\x0F\xAD\xD2\x49\xF7\xD4\x48\xF7\xE1\x4D\x19\xC5\x4D\x89\xC5\x48\xF7\xD6\x41\xB8\x4F\x8D\x6B\x59\x4D\x87\xD0\x68\x6A\x1E\x09\x3C\x59" +#define X86_CODE16 "\x00\x00" // add byte ptr [bx + si], al +#define X86_CODE64_SYSCALL "\x0f\x05" // SYSCALL + +// memory address where emulation starts +#define ADDRESS 0x1000000 + +// callback for tracing basic blocks +static void hook_block(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + printf(">>> Tracing basic block at 0x%"PRIx64 ", block size = 0x%x\n", address, size); +} + +// callback for tracing instruction +static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + int eflags; + printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); + + uc_reg_read(uc, UC_X86_REG_EFLAGS, &eflags); + printf(">>> --- EFLAGS is 0x%x\n", eflags); + + // Uncomment below code to stop the emulation using uc_emu_stop() + // if (address == 0x1000009) + // uc_emu_stop(uc); +} + +// callback for tracing instruction +static void hook_code64(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +{ + uint64_t rip; + + uc_reg_read(uc, UC_X86_REG_RIP, &rip); + printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); + printf(">>> RIP is 0x%"PRIx64 "\n", rip); + + // Uncomment below code to stop the emulation using uc_emu_stop() + // if (address == 0x1000009) + // uc_emu_stop(uc); +} + +static void hook_mem64(uc_engine *uc, uc_mem_type type, + uint64_t address, int size, int64_t value, void *user_data) +{ + switch(type) { + default: break; + case UC_MEM_READ: + printf(">>> Memory is being READ at 0x%"PRIx64 ", data size = %u\n", + address, size); + break; + case UC_MEM_WRITE: + printf(">>> Memory is being WRITE at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", + address, size, value); + break; + } +} + +static void test_i386(void) +{ + uc_engine *uc; + uc_err err; + uint32_t tmp; + uc_hook trace1, trace2; + + int r_ecx = 0x1234; // ECX register + int r_edx = 0x7890; // EDX register + + printf("Emulate i386 code\n"); + + // Initialize emulator in X86-32bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u\n", err); + return; + } + + // map 2MB memory for this emulation + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + if (uc_mem_write(uc, ADDRESS, X86_CODE32, sizeof(X86_CODE32) - 1)) { + printf("Failed to write emulation code to memory, quit!\n"); + return; + } + + // initialize machine registers + uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx); + 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); + + // tracing all instruction by having @begin > @end + uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); + + // emulate machine code in infinite time + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32) - 1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned %u: %s\n", + err, uc_strerror(err)); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx); + uc_reg_read(uc, UC_X86_REG_EDX, &r_edx); + printf(">>> ECX = 0x%x\n", r_ecx); + printf(">>> EDX = 0x%x\n", r_edx); + + // read from memory + if (!uc_mem_read(uc, ADDRESS, &tmp, sizeof(tmp))) + printf(">>> Read 4 bytes from [0x%x] = 0x%x\n", ADDRESS, tmp); + else + printf(">>> Failed to read 4 bytes from [0x%x]\n", ADDRESS); + + uc_close(uc); +} + +static void test_x86_64(void) +{ + uc_engine *uc; + uc_err err; + uc_hook trace1, trace2, trace3, trace4; + + int64_t rax = 0x71f3029efd49d41d; + int64_t rbx = 0xd87b45277f133ddb; + int64_t rcx = 0xab40d1ffd8afc461; + int64_t rdx = 0x919317b4a733f01; + int64_t rsi = 0x4c24e753a17ea358; + int64_t rdi = 0xe509a57d2571ce96; + int64_t r8 = 0xea5b108cc2b9ab1f; + int64_t r9 = 0x19ec097c8eb618c1; + int64_t r10 = 0xec45774f00c5f682; + int64_t r11 = 0xe17e9dbec8c074aa; + int64_t r12 = 0x80f86a8dc0f6d457; + int64_t r13 = 0x48288ca5671c5492; + int64_t r14 = 0x595f72f6e4017f6e; + int64_t r15 = 0x1efd97aea331cccc; + + int64_t rsp = ADDRESS + 0x200000; + + + printf("Emulate x86_64 code\n"); + + // Initialize emulator in X86-64bit mode + err = uc_open(UC_ARCH_X86, UC_MODE_64, &uc); + if (err) { + printf("Failed on uc_open() with error returned: %u\n", err); + return; + } + + // map 2MB memory for this emulation + uc_mem_map(uc, ADDRESS, 2 * 1024 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + if (uc_mem_write(uc, ADDRESS, X86_CODE64, sizeof(X86_CODE64) - 1)) { + printf("Failed to write emulation code to memory, quit!\n"); + return; + } + + // initialize machine registers + uc_reg_write(uc, UC_X86_REG_RSP, &rsp); + + uc_reg_write(uc, UC_X86_REG_RAX, &rax); + uc_reg_write(uc, UC_X86_REG_RBX, &rbx); + uc_reg_write(uc, UC_X86_REG_RCX, &rcx); + uc_reg_write(uc, UC_X86_REG_RDX, &rdx); + uc_reg_write(uc, UC_X86_REG_RSI, &rsi); + uc_reg_write(uc, UC_X86_REG_RDI, &rdi); + uc_reg_write(uc, UC_X86_REG_R8, &r8); + uc_reg_write(uc, UC_X86_REG_R9, &r9); + uc_reg_write(uc, UC_X86_REG_R10, &r10); + uc_reg_write(uc, UC_X86_REG_R11, &r11); + uc_reg_write(uc, UC_X86_REG_R12, &r12); + uc_reg_write(uc, UC_X86_REG_R13, &r13); + uc_reg_write(uc, UC_X86_REG_R14, &r14); + 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); + + // 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)); + + // 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); + + // 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); + + // emulate machine code in infinite time (last param = 0), or when + // finishing all the code. + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE64) - 1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned %u: %s\n", + err, uc_strerror(err)); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_X86_REG_RAX, &rax); + uc_reg_read(uc, UC_X86_REG_RBX, &rbx); + uc_reg_read(uc, UC_X86_REG_RCX, &rcx); + uc_reg_read(uc, UC_X86_REG_RDX, &rdx); + uc_reg_read(uc, UC_X86_REG_RSI, &rsi); + uc_reg_read(uc, UC_X86_REG_RDI, &rdi); + uc_reg_read(uc, UC_X86_REG_R8, &r8); + uc_reg_read(uc, UC_X86_REG_R9, &r9); + uc_reg_read(uc, UC_X86_REG_R10, &r10); + uc_reg_read(uc, UC_X86_REG_R11, &r11); + uc_reg_read(uc, UC_X86_REG_R12, &r12); + uc_reg_read(uc, UC_X86_REG_R13, &r13); + uc_reg_read(uc, UC_X86_REG_R14, &r14); + uc_reg_read(uc, UC_X86_REG_R15, &r15); + + printf(">>> RAX = 0x%" PRIx64 "\n", rax); + printf(">>> RBX = 0x%" PRIx64 "\n", rbx); + printf(">>> RCX = 0x%" PRIx64 "\n", rcx); + printf(">>> RDX = 0x%" PRIx64 "\n", rdx); + printf(">>> RSI = 0x%" PRIx64 "\n", rsi); + printf(">>> RDI = 0x%" PRIx64 "\n", rdi); + printf(">>> R8 = 0x%" PRIx64 "\n", r8); + printf(">>> R9 = 0x%" PRIx64 "\n", r9); + printf(">>> R10 = 0x%" PRIx64 "\n", r10); + printf(">>> R11 = 0x%" PRIx64 "\n", r11); + printf(">>> R12 = 0x%" PRIx64 "\n", r12); + printf(">>> R13 = 0x%" PRIx64 "\n", r13); + printf(">>> R14 = 0x%" PRIx64 "\n", r14); + printf(">>> R15 = 0x%" PRIx64 "\n", r15); + + uc_close(uc); +} + +int main(int argc, char **argv, char **envp) +{ + // dynamically load shared library +#ifdef DYNLOAD + if (!uc_dyn_load(NULL, 0)) { + printf("Error dynamically loading shared library.\n"); + printf("Please check that unicorn.dll/unicorn.so is available as well as\n"); + printf("any other dependent dll/so files.\n"); + printf("The easiest way is to place them in the same directory as this app.\n"); + return 1; + } +#endif + + while(1) { + test_i386(); + test_x86_64(); + } + + // dynamically free shared library +#ifdef DYNLOAD + uc_dyn_free(); +#endif + + return 0; +} diff --git a/tests/regress/mips_branch_likely_issue.c b/tests/regress/mips_branch_likely_issue.c index 84f49cdc..75926692 100644 --- a/tests/regress/mips_branch_likely_issue.c +++ b/tests/regress/mips_branch_likely_issue.c @@ -61,7 +61,7 @@ bool test2_delayslot_hooked = false; // This hook is used to show that code is executing in the emulator. static void mips_codehook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { - printf("Test %d Executing: %llX\n", test_num, address); + printf("Test %d Executing: %"PRIx64"\n", test_num, address); if( test_num == 1 && address == 0x100010 ) { printf("Delay slot hook called!\n"); @@ -107,7 +107,7 @@ int main(int argc, char **argv, char **envp) // hook all instructions by having @begin > @end printf("uc_hook_add()\n"); - uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, 1, 0); if( err ) { printf("Failed on uc_hook_add(code) with error returned: %u\n", err); diff --git a/tests/regress/mips_delay_slot_code_hook.c b/tests/regress/mips_delay_slot_code_hook.c index 905cad8d..1feca5c1 100644 --- a/tests/regress/mips_delay_slot_code_hook.c +++ b/tests/regress/mips_delay_slot_code_hook.c @@ -59,7 +59,7 @@ static void mips_codehook(uc_engine *uc, uint64_t address, uint32_t size, void * printf("\nloop %d:\n", loop_count); loop_count++; } - printf("Code: %llX\n", address); + printf("Code: %"PRIx64"\n", address); } @@ -100,7 +100,7 @@ int main(int argc, char **argv, char **envp) } // hook all instructions by having @begin > @end - uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, 1, 0); if( err ) { printf("Failed on uc_hook_add(code) with error returned: %u\n", err); diff --git a/tests/regress/mips_invalid_read_of_size_4_when_tracing.c b/tests/regress/mips_invalid_read_of_size_4_when_tracing.c index d912a604..013016e4 100644 --- a/tests/regress/mips_invalid_read_of_size_4_when_tracing.c +++ b/tests/regress/mips_invalid_read_of_size_4_when_tracing.c @@ -25,7 +25,7 @@ int main(int argc, char **argv, char **envp) { return 1; } uc_hook trace; - uc_hook_add(uc, &trace, UC_HOOK_CODE, hook_code, NULL, (uint64_t)MEMORY_STARTING_ADDRESS, (uint64_t)(MEMORY_STARTING_ADDRESS + 1)); + uc_hook_add(uc, &trace, UC_HOOK_CODE, hook_code, NULL, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + 1); printf("uc_emu_start(…)\n"); uc_emu_start(uc, MEMORY_STARTING_ADDRESS, MEMORY_STARTING_ADDRESS + sizeof(BINARY_CODE) - 1, 0, 0); printf("done\n"); diff --git a/tests/regress/nr_mem_test.c b/tests/regress/nr_mem_test.c index 60e97db7..b6ab8d8e 100644 --- a/tests/regress/nr_mem_test.c +++ b/tests/regress/nr_mem_test.c @@ -83,10 +83,10 @@ int main(int argc, char **argv, char **envp) uc_mem_write(uc, 0x300000, (const uint8_t*)"\x41\x41\x41\x41", 4); uc_mem_write(uc, 0x400000, (const uint8_t*)"\x42\x42\x42\x42", 4); - //uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff); + //uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 0x400000, 0x400fff); // intercept invalid memory events - uc_hook_add(uc, &trace1, UC_MEM_READ_PROT, hook_mem_invalid, NULL); + uc_hook_add(uc, &trace1, UC_MEM_READ_PROT, hook_mem_invalid, NULL, 1, 0); // emulate machine code in infinite time printf("BEGIN execution\n"); diff --git a/tests/regress/rep_movsb.c b/tests/regress/rep_movsb.c index 17b22641..86594978 100644 --- a/tests/regress/rep_movsb.c +++ b/tests/regress/rep_movsb.c @@ -129,7 +129,7 @@ int main(int argc, char **argv, char **envp) printf("ok %d - Program written to memory\n", log_num++); } - 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) { printf("not ok %d - Failed to install UC_HOOK_CODE handler\n", log_num++); return 5; } @@ -138,7 +138,7 @@ int main(int argc, char **argv, char **envp) } // intercept memory write events only, NOT read events - if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) { + if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE, hook_mem_write, NULL, 1, 0) != UC_ERR_OK) { printf("not ok %d - Failed to install UC_HOOK_MEM_WRITE handler\n", log_num++); return 6; } diff --git a/tests/regress/ro_mem_test.c b/tests/regress/ro_mem_test.c index 7b430497..845859b1 100644 --- a/tests/regress/ro_mem_test.c +++ b/tests/regress/ro_mem_test.c @@ -139,10 +139,10 @@ int main(int argc, char **argv, char **envp) printf("Allowed to write to read only memory via uc_mem_write\n"); } - //uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff); + //uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, 0x400000, 0x400fff); // intercept invalid memory events - uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_WRITE_PROT, hook_mem_invalid, NULL); + uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_UNMAPPED | UC_HOOK_MEM_WRITE_PROT, hook_mem_invalid, NULL, 1, 0); // emulate machine code in infinite time printf("BEGIN execution - 1\n"); diff --git a/tests/regress/rw_hookstack.c b/tests/regress/rw_hookstack.c index e04dd64c..3d7eacaa 100644 --- a/tests/regress/rw_hookstack.c +++ b/tests/regress/rw_hookstack.c @@ -78,7 +78,7 @@ loop: } - uc_hook_add(uc, &trace, UC_HOOK_MEM_WRITE | UC_HOOK_MEM_READ, (void *)hook_mem_rw, NULL); + uc_hook_add(uc, &trace, UC_HOOK_MEM_WRITE | UC_HOOK_MEM_READ, (void *)hook_mem_rw, NULL, 1, 0); uc_reg_write(uc, UC_X86_REG_EAX, &EAX); uc_reg_write(uc, UC_X86_REG_ESP, &ESP); diff --git a/tests/regress/sigill.c b/tests/regress/sigill.c index 8ce230cd..ea8f987f 100644 --- a/tests/regress/sigill.c +++ b/tests/regress/sigill.c @@ -38,7 +38,7 @@ int main() uc_mem_write(uc, UC_BUG_WRITE_ADDR, (const uint8_t*)"\xff\xff\xff\xff\xff\xff\xff\xff", 8); } - uc_hook_add(uc, &uh_trap, UC_HOOK_INTR, _interrupt, NULL); + uc_hook_add(uc, &uh_trap, UC_HOOK_INTR, _interrupt, NULL, 1, 0); uc_emu_start(uc, UC_BUG_WRITE_ADDR, UC_BUG_WRITE_ADDR+8, 0, 1); uc_close(uc); printf ("Correct: %s\n", got_sigill? "YES": "NO"); diff --git a/tests/regress/sysenter_hook_x86.c b/tests/regress/sysenter_hook_x86.c index 4b28557b..af92c1c5 100644 --- a/tests/regress/sysenter_hook_x86.c +++ b/tests/regress/sysenter_hook_x86.c @@ -36,7 +36,7 @@ int main(int argc, char **argv, char **envp) } // Hook the SYSENTER instructions - if (uc_hook_add (uc, &sysenterHook, UC_HOOK_INSN, sysenter, NULL, UC_X86_INS_SYSENTER) != UC_ERR_OK) { + if (uc_hook_add (uc, &sysenterHook, UC_HOOK_INSN, sysenter, NULL, UC_X86_INS_SYSENTER, 1, 0) != UC_ERR_OK) { printf ("Cannot hook SYSENTER instruction\n."); return -1; } @@ -57,4 +57,4 @@ int main(int argc, char **argv, char **envp) } return 0; -} \ No newline at end of file +} diff --git a/tests/regress/tcg_liveness_analysis_bug_issue-287.py b/tests/regress/tcg_liveness_analysis_bug_issue-287.py old mode 100644 new mode 100755 diff --git a/tests/regress/threaded_emu_start.c b/tests/regress/threaded_emu_start.c index 9a5a2fa9..b75261c4 100644 --- a/tests/regress/threaded_emu_start.c +++ b/tests/regress/threaded_emu_start.c @@ -65,7 +65,7 @@ int loop_count = 0; // This hook is used to show that code is executing in the emulator. static void mips_codehook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { - printf("Code: %llX\n", address); + printf("Code: %"PRIx64"\n", address); } @@ -164,7 +164,7 @@ int main(int argc, char **argv, char **envp) // hook all instructions by having @begin > @end printf("uc_hook_add()\n"); - uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, (uint64_t)1, (uint64_t)0); + uc_hook_add(uc, &hhc, UC_HOOK_CODE, mips_codehook, NULL, 1, 0); if( err ) { printf("Failed on uc_hook_add(code) with error returned: %u\n", err); diff --git a/tests/regress/timeout_segfault.c b/tests/regress/timeout_segfault.c index 49d9a370..54b04db0 100644 --- a/tests/regress/timeout_segfault.c +++ b/tests/regress/timeout_segfault.c @@ -67,10 +67,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. @@ -118,10 +118,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. diff --git a/tests/regress/translator_buffer.py b/tests/regress/translator_buffer.py new file mode 100755 index 00000000..c302ff18 --- /dev/null +++ b/tests/regress/translator_buffer.py @@ -0,0 +1,78 @@ +#!/usr/bin/python +# By Mariano Graziano + +from unicorn import * +from unicorn.x86_const import * + +import regress, struct + + +class Emulator: + def __init__(self, code, stack): + self.mask = 0xFFFFFFFFFFFFF000 + self.unicorn_code = code + self.unicorn_stack = stack + self.mu = Uc(UC_ARCH_X86, UC_MODE_64) + size = 1 * 4096 + self.mu.mem_map(code & self.mask, size) + size = 1 * 4096 + self.mu.mem_map(stack & self.mask, size) + self.set_hooks() + + def set_hooks(self): + self.mu.hook_add(UC_HOOK_MEM_WRITE, self.hook_mem_access) + self.mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, self.hook_mem_invalid) + self.mu.hook_add(UC_HOOK_MEM_FETCH_UNMAPPED, self.hook_mem_fetch_unmapped) + + def hook_mem_fetch_unmapped(self, uc, access, address, size, value, user_data): + next_ip = self.unicorn_code + size + self.mu.reg_write(UC_X86_REG_RIP, next_ip) + self.mu.mem_write(next_ip, "\x90") + self.mu.reg_write(UC_X86_REG_RIP, address) + return True + + def hook_mem_invalid(self, uc, access, address, size, value, user_data): + return True + + def hook_mem_access(self, uc, access, address, size, value, user_data): + return True + + def emu(self, size): + ip = self.mu.reg_read(UC_X86_REG_RIP) + try: + self.mu.emu_start(ip, ip + size, timeout=10000, count=1) + except UcError as e: + print("Error %s" % e) + + def write_data(self, address, content): + self.mu.mem_write(address, content) + + +class Init(regress.RegressTest): + def init_unicorn(self, ip, sp, counter): + print "[+] Emulating IP: %x SP: %x - Counter: %x" % (ip, sp, counter) + E = Emulator(ip, sp) + E.write_data(ip, "\x90") + E.write_data(sp, self.generate_value(counter)) + E.mu.reg_write(UC_X86_REG_RSP, sp) + E.mu.reg_write(UC_X86_REG_RIP, ip) + E.emu(1) + + def generate_value(self, counter): + start = 0xffff880026f02000 + offset = counter * 8 + address = start + offset + return struct.pack(" example + # $ qemu-x86_64-static -d cpu,in_asm -singlestep ./test \ + # | grep -E 'RFL|^0x' + # 0x00000000006000b0: xor %r14,%r14 + # RIP=00000000006000b0 RFL=00000202 [-------] CPL=3 II=0 A20=1 SMM=0 HLT=0 + # 0x00000000006000b3: test %r14d,%r14d + # RIP=00000000006000b3 RFL=00000246 [---Z-P-] CPL=3 II=0 A20=1 SMM=0 HLT=0 + # 0x00000000006000b6: jne 0x6000b6 + # RIP=00000000006000b6 RFL=00000246 [---Z-P-] CPL=3 II=0 A20=1 SMM=0 HLT=0 + # 0x00000000006000b8: hlt + # RIP=00000000006000b8 RFL=00000246 [---Z-P-] CPL=3 II=0 A20=1 SMM=0 HLT=0 + self.assertEqual(0x6000b0 + 8, uc.reg_read(U.x86_const.UC_X86_REG_RIP)) + +if __name__ == '__main__': + regress.main() diff --git a/tests/regress/x86_64_eflags.py b/tests/regress/x86_64_eflags.py new file mode 100755 index 00000000..ca7c48d1 --- /dev/null +++ b/tests/regress/x86_64_eflags.py @@ -0,0 +1,38 @@ +#!/usr/bin/python +import regress +import unicorn as U + +class WrongEFLAGS(regress.RegressTest): + def test_eflags(self): + # xor r14,r14 + CODE = 'M1\xf6' + + uc = U.Uc(U.UC_ARCH_X86, U.UC_MODE_64) + uc.reg_write(U.x86_const.UC_X86_REG_RIP, 0x6000b0) + uc.reg_write(U.x86_const.UC_X86_REG_EFLAGS, 0x200) + + uc.mem_map(0x600000, 0x1000) + uc.mem_write(0x6000b0, CODE) + uc.emu_start(0x6000b0, 0, count=1) + + + # Here's the original execution trace for this on actual hardware. + # + # (gdb) x/i $pc + # => 0x6000b0: xor %r14,%r14 + # (gdb) p/x $eflags + # $1 = 0x200 + # (gdb) p $eflags + # $2 = [ IF ] + # (gdb) si + # 0x00000000006000b3 in ?? () + # (gdb) p/x $eflags + # $3 = 0x246 + # (gdb) p $eflags + # $4 = [ PF ZF IF ] + + self.assertEqual(0x6000b3, uc.reg_read(U.x86_const.UC_X86_REG_RIP)) + self.assertEqual(0x246, uc.reg_read(U.x86_const.UC_X86_REG_EFLAGS)) + +if __name__ == '__main__': + regress.main() diff --git a/tests/regress/x86_gdt.py b/tests/regress/x86_gdt.py new file mode 100755 index 00000000..5f4234a4 --- /dev/null +++ b/tests/regress/x86_gdt.py @@ -0,0 +1,94 @@ +#!/usr/bin/env python +from unicorn import * +from unicorn.x86_const import * +from struct import pack + +import regress + +F_GRANULARITY = 0x8 +F_PROT_32 = 0x4 +F_LONG = 0x2 +F_AVAILABLE = 0x1 + +A_PRESENT = 0x80 + +A_PRIV_3 = 0x60 +A_PRIV_2 = 0x40 +A_PRIV_1 = 0x20 +A_PRIV_0 = 0x0 + +A_CODE = 0x10 +A_DATA = 0x10 +A_TSS = 0x0 +A_GATE = 0x0 + +A_DATA_WRITABLE = 0x2 +A_CODE_READABLE = 0x2 + +A_DIR_CON_BIT = 0x4 + +S_GDT = 0x0 +S_LDT = 0x4 +S_PRIV_3 = 0x3 +S_PRIV_2 = 0x2 +S_PRIV_1 = 0x1 +S_PRIV_0 = 0x0 + +CODE = '65330d18000000'.decode('hex') # xor ecx, dword ptr gs:[0x18] + +def create_selector(idx, flags): + to_ret = flags + to_ret |= idx << 3 + return to_ret + +def create_gdt_entry(base, limit, access, flags): + + to_ret = limit & 0xffff; + to_ret |= (base & 0xffffff) << 16; + to_ret |= (access & 0xff) << 40; + to_ret |= ((limit >> 16) & 0xf) << 48; + to_ret |= (flags & 0xff) << 52; + to_ret |= ((base >> 24) & 0xff) << 56; + return pack(' + +#define DEBUG 1 + +#define OK(x) uc_assert_success(x) + +volatile int expected_instructions = 0; +volatile int total_instructions = 0; + + +// NOTE: It would appear that this UC_HOOK_CODE is being done before the +// uc_count_fb hook. +// So, termination by uc->emu_count has not been done yet here... +static void test_code_hook(uc_engine *uc, + uint64_t address, + uint32_t size, + void *user_data) +{ + + ++total_instructions; + if (total_instructions == expected_instructions) + { + uc_emu_stop(uc); + } + +#ifdef DEBUG + printf("instruction at 0x%"PRIx64": ", address); + uint8_t tmp[256]; + if (!uc_mem_read(uc, address, tmp, size)) { + uint32_t i; + + for (i = 0; i < size; i++) { + printf("0x%x ", tmp[i]); + } + printf("\n"); + } +#endif // DEBUG +} + + +/* Called before every test to set up a new instance */ +static int setup32(void **state) +{ + uc_hook trace1; + uc_engine *uc; + + OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc)); + + *state = uc; + + // trace all instructions + OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, test_code_hook, NULL, 1, 0)); + + return 0; +} + +/* Called after every test to clean up */ +static int teardown(void **state) +{ + uc_engine *uc = *state; + + OK(uc_close(uc)); + + *state = NULL; + return 0; +} + +/******************************************************************************/ + +static void +test_hook_count(uc_engine *uc, + const uint8_t *code, + int start_offset, + int code_length, + int count) +{ + +#define BASEADDR 0x1000000 +#define MEMSIZE (2 * 1024 * 1024) + + uint64_t address = BASEADDR + (count * MEMSIZE); + total_instructions = 0; + +#undef BASEADDR + + // map a new 2MB memory for this emulation + OK(uc_mem_map(uc, address, MEMSIZE, UC_PROT_ALL)); + + // write machine code to be emulated to memory + OK(uc_mem_write(uc, address, code, code_length)); + +#ifdef DEBUG + printf("Address: %"PRIx64"\n", address); + printf("Start : %"PRIx64"\n", address + start_offset); + printf("End : %"PRIx64"\n", address + code_length - 1); + printf("Count : %d\n", count); +#endif + expected_instructions = count; + OK(uc_emu_start(uc, + address+start_offset, + address+code_length, + 0, + count)); + + assert_int_equal(expected_instructions, total_instructions); + + // map 2MB memory for this emulation + OK(uc_mem_unmap(uc, address, MEMSIZE)); +} + + +/* Perform fine-grain emulation control of exactly 1 instruction */ +/* of 1-opcode code space*/ +static void test_hook_count_1_begin(void **state) +{ + uc_engine *uc = *state; + const uint8_t code[] = { + 0x41, // inc ECX @0x1000000 + }; + int code_length = sizeof(code); + int start_offset = 0; + int ins_count = 1; + + test_hook_count(uc, code, start_offset, code_length, ins_count); +} + + +/* Perform fine-grain emulation control of exactly 1 instruction */ +static void test_hook_count_1_midpoint(void **state) +{ + uc_engine *uc = *state; + const uint8_t code[] = { + 0x41, // inc ECX @0x1000000 + 0x41, // inc ECX + 0x41, // inc ECX + 0x41, // inc ECX @0x1000003 + 0x41, // inc ECX + 0x41, // inc ECX + 0x42, // inc EDX @0x1000006 + 0x42, // inc EDX + }; + int code_length = sizeof(code); + int start_offset = code_length/2; + int ins_count = 1; + + test_hook_count(uc, code, start_offset, code_length, ins_count); +} + + +/* Perform fine-grain emulation control of exactly 1 instruction */ +static void test_hook_count_1_end(void **state) +{ + uc_engine *uc = *state; + const uint8_t code[] = { + 0x41, // inc ECX @0x1000000 + 0x41, // inc ECX + 0x41, // inc ECX + 0x41, // inc ECX @0x1000003 + 0x41, // inc ECX + 0x41, // inc ECX + 0x42, // inc EDX @0x1000006 + 0x42, // inc EDX + }; + int code_length = sizeof(code); + int start_offset = code_length - 1; + int ins_count = 1; + + test_hook_count(uc, code, start_offset, code_length, ins_count); +} + + +/* Perform fine-grain emulation control over a range of */ +/* varied instruction steps. */ +static void test_hook_count_range(void **state) +{ + uc_engine *uc = *state; + const uint8_t code[] = { + 0x41, // inc ECX @0x1000000 + 0x41, // inc ECX + 0x41, // inc ECX + 0x41, // inc ECX @0x1000003 + 0x41, // inc ECX + 0x41, // inc ECX + 0x42, // inc EDX @0x1000006 + 0x42, // inc EDX + }; + int code_length = sizeof(code); + int start_offset; + int ins_count = 2; + + for (start_offset = 2; start_offset < (code_length - ins_count); start_offset++) + { + printf("Iteration %d\n", start_offset); + test_hook_count(uc, code, start_offset, code_length, ins_count); + } +} + + +static void test_hook_count_end(void **state) +{ + uc_engine *uc = *state; + const uint8_t code[] = { + 0x41, // inc ECX @0x1000000 + 0x41, // inc ECX + 0x41, // inc ECX + 0x41, // inc ECX @0x1000003 + 0x41, // inc ECX + 0x41, // inc ECX + 0x42, // inc EDX @0x1000006 + 0x42, // inc EDX + }; + int code_length = sizeof(code); + int ins_count = 3; + int start_offset = sizeof(code) - ins_count; + + test_hook_count(uc, code, start_offset, code_length, ins_count); +} + + +static void test_hook_count_begins(void **state) +{ + uc_engine *uc = *state; + const uint8_t code[] = { + 0x41, // inc ECX @0x1000000 + 0x41, // inc ECX + 0x41, // inc ECX + 0x41, // inc ECX @0x1000003 + 0x41, // inc ECX + 0x41, // inc ECX + 0x42, // inc EDX @0x1000006 + 0x42, // inc EDX + }; + int code_length = sizeof(code); + int ins_count = 3; + int start_offset = 0; + + test_hook_count(uc, code, start_offset, code_length, ins_count); +} + + +static void test_hook_count_midpoint(void **state) +{ + uc_engine *uc = *state; + const uint8_t code[] = { + 0x41, // inc ECX @0x1000000 + 0x41, // inc ECX + 0x41, // inc ECX + 0x41, // inc ECX @0x1000003 + 0x41, // inc ECX + 0x41, // inc ECX + 0x42, // inc EDX @0x1000006 + 0x42, // inc EDX + }; + int code_length = sizeof(code); + int ins_count = 3; + int start_offset = 2; + + test_hook_count(uc, code, start_offset, code_length, ins_count); +} + + +int main(void) +{ + const struct CMUnitTest tests[] = { + cmocka_unit_test_setup_teardown(test_hook_count_1_begin, setup32, teardown), + cmocka_unit_test_setup_teardown(test_hook_count_1_midpoint, setup32, teardown), + cmocka_unit_test_setup_teardown(test_hook_count_1_end, setup32, teardown), + cmocka_unit_test_setup_teardown(test_hook_count_begins, setup32, teardown), + cmocka_unit_test_setup_teardown(test_hook_count_range, setup32, teardown), + cmocka_unit_test_setup_teardown(test_hook_count_midpoint, setup32, teardown), + cmocka_unit_test_setup_teardown(test_hook_count_end, setup32, teardown), + }; + return cmocka_run_group_tests(tests, NULL, NULL); +} + diff --git a/tests/unit/test_mem_map.c b/tests/unit/test_mem_map.c index 303a370b..9c2b9892 100644 --- a/tests/unit/test_mem_map.c +++ b/tests/unit/test_mem_map.c @@ -158,6 +158,15 @@ static void test_strange_map(void **state) uc_mem_unmap(uc, 0x0,0x1000); } +static void test_query_page_size(void **state) +{ + uc_engine *uc = *state; + + size_t page_size; + uc_assert_success(uc_query(uc, UC_QUERY_PAGE_SIZE, &page_size)); + assert_int_equal(4096, page_size); +} + void write(uc_engine* uc, uint64_t addr, uint64_t len){ uint8_t* buff = alloca(len); memset(buff,0,len); @@ -220,6 +229,7 @@ int main(void) { test(test_unmap_double_map), test(test_overlap_unmap_double_map), test(test_strange_map), + test(test_query_page_size), }; #undef test return cmocka_run_group_tests(tests, NULL, NULL); diff --git a/uc.c b/uc.c index 298d21e0..6ab6d3c6 100644 --- a/uc.c +++ b/uc.c @@ -285,9 +285,7 @@ uc_err uc_close(uc_engine *uc) if (uc->release) uc->release(uc->tcg_ctx); -#ifndef _WIN32 free(uc->l1_map); -#endif if (uc->bounce.buffer) { free(uc->bounce.buffer); @@ -295,17 +293,12 @@ uc_err uc_close(uc_engine *uc) g_free(uc->tcg_ctx); - free((void*) uc->system_memory->name); - g_free(uc->system_memory); g_hash_table_destroy(uc->type_table); for (i = 0; i < DIRTY_MEMORY_NUM; i++) { free(uc->ram_list.dirty_memory[i]); } - // TODO: remove uc->root (created with object_new()) - uc->root->free(uc->root); - // free hooks and hook lists for (i = 0; i < UC_HOOK_MAX; i++) { cur = uc->hook[i].head; @@ -332,10 +325,10 @@ uc_err uc_close(uc_engine *uc) UNICORN_EXPORT -uc_err uc_reg_read(uc_engine *uc, int regid, void *value) +uc_err uc_reg_read_batch(uc_engine *uc, int *ids, void **vals, int count) { if (uc->reg_read) - uc->reg_read(uc, regid, value); + uc->reg_read(uc, (unsigned int *)ids, vals, count); else return -1; // FIXME: need a proper uc_err @@ -344,10 +337,10 @@ uc_err uc_reg_read(uc_engine *uc, int regid, void *value) UNICORN_EXPORT -uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) +uc_err uc_reg_write_batch(uc_engine *uc, int *ids, void *const *vals, int count) { if (uc->reg_write) - uc->reg_write(uc, regid, value); + uc->reg_write(uc, (unsigned int *)ids, vals, count); else return -1; // FIXME: need a proper uc_err @@ -355,6 +348,20 @@ uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) } +UNICORN_EXPORT +uc_err uc_reg_read(uc_engine *uc, int regid, void *value) +{ + return uc_reg_read_batch(uc, ®id, &value, 1); +} + + +UNICORN_EXPORT +uc_err uc_reg_write(uc_engine *uc, int regid, const void *value) +{ + return uc_reg_write_batch(uc, ®id, (void *const *)&value, 1); +} + + // check if a memory area is mapped // this is complicated because an area can overlap adjacent blocks static bool check_mem_area(uc_engine *uc, uint64_t address, size_t size) @@ -559,14 +566,13 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time uc->addr_end = until; + if (timeout) + enable_emu_timer(uc, timeout * 1000); // microseconds -> nanoseconds + if (uc->vm_start(uc)) { return UC_ERR_RESOURCE; } - if (timeout) - enable_emu_timer(uc, timeout * 1000); // microseconds -> nanoseconds - - uc->pause_all_vcpus(uc); // emulation is done uc->emulation_done = true; @@ -1029,15 +1035,19 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, UNICORN_EXPORT uc_err uc_hook_del(uc_engine *uc, uc_hook hh) { - int i; - struct hook *hook; - for (i = 0; i < UC_HOOK_MAX; i++) { - if (list_remove(&uc->hook[i], (void *)hh)) { - hook = (struct hook *)hh; - if (--hook->refs == 0) { - free(hook); + int i = 0; + struct hook *hook = (struct hook *)hh; + int type = hook->type; + + while ((type >> i) > 0 && i < UC_HOOK_MAX) { + if ((type >> i) & 1) { + if (list_remove(&uc->hook[i], (void *)hh)) { + if (--hook->refs == 0) { + free(hook); + } } } + i++; } return UC_ERR_OK; } @@ -1094,6 +1104,11 @@ uint32_t uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count) UNICORN_EXPORT uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result) { + if (type == UC_QUERY_PAGE_SIZE) { + *result = uc->target_page_size; + return UC_ERR_OK; + } + switch(uc->arch) { case UC_ARCH_ARM: return uc->query(uc, type, result);