From 186540e160c4805a3472bfa31f03e24b47a206ef Mon Sep 17 00:00:00 2001 From: Stephen Date: Fri, 28 Oct 2016 16:31:52 -0700 Subject: [PATCH 01/16] make cleanup --- .appveyor.yml | 27 +- .travis.yml | 36 +-- Makefile | 98 ++---- bindings/Makefile | 17 +- bindings/go/unicorn/context.go | 28 ++ bindings/go/unicorn/context_test.go | 26 ++ bindings/go/unicorn/unicorn.go | 3 + bindings/haskell/samples/SampleX86.hs | 69 +++++ bindings/haskell/src/Unicorn.hs | 116 +++++--- bindings/haskell/src/Unicorn/CPU/Arm.chs | 21 +- bindings/haskell/src/Unicorn/CPU/Arm64.chs | 21 +- bindings/haskell/src/Unicorn/CPU/M68k.chs | 21 +- bindings/haskell/src/Unicorn/CPU/Mips.chs | 86 +++--- bindings/haskell/src/Unicorn/CPU/Sparc.chs | 21 +- bindings/haskell/src/Unicorn/CPU/X86.chs | 49 +-- bindings/haskell/src/Unicorn/Hook.hs | 59 ++-- .../haskell/src/Unicorn/Internal/Core.chs | 17 +- .../haskell/src/Unicorn/Internal/Hook.chs | 280 ++++++++++-------- .../haskell/src/Unicorn/Internal/Unicorn.chs | 279 ++++++++++------- bindings/haskell/src/Unicorn/Internal/Util.hs | 12 +- bindings/haskell/src/cbits/unicorn_wrapper.c | 4 + .../haskell/src/include/unicorn_wrapper.h | 5 + bindings/haskell/unicorn.cabal | 13 +- bindings/python/sample_arm.py | 6 +- bindings/python/sample_arm64.py | 2 +- bindings/python/sample_m68k.py | 30 +- bindings/python/sample_mips.py | 8 +- bindings/python/sample_sparc.py | 2 +- bindings/python/sample_x86.py | 236 +++++++++++---- bindings/python/setup.py | 2 +- bindings/python/unicorn/unicorn.py | 4 +- bindings/ruby/unicorn_gem/ext/unicorn.c | 42 +-- make.sh | 20 +- samples/Makefile | 131 +------- samples/sample_x86.c | 101 +++++++ samples/sample_x86_32_gdt_and_seg_regs.c | 2 +- tests/unit/Makefile | 40 +-- uc.c | 15 +- 38 files changed, 1149 insertions(+), 800 deletions(-) create mode 100644 bindings/go/unicorn/context.go create mode 100644 bindings/go/unicorn/context_test.go diff --git a/.appveyor.yml b/.appveyor.yml index 96d9d7fa..03d5d411 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -7,26 +7,15 @@ environment: CYG_CACHE: C:\cygwin64\var\cache\setup CYG_BASH: C:\cygwin64\bin\bash CC: gcc -# TODO: Uncomment -# - CYG_ROOT: C:\cygwin64 -# CYG_SETUP: setup-x86_64.exe -# CYG_MIRROR: http://cygwin.mirror.constant.com -# CYG_CACHE: C:\cygwin64\var\cache\setup -# CYG_BASH: C:\cygwin64\bin\bash -# CC: clang - CYG_ROOT: C:\cygwin CYG_SETUP: setup-x86.exe CYG_MIRROR: http://cygwin.mirror.constant.com CYG_CACHE: C:\cygwin\var\cache\setup CYG_BASH: C:\cygwin\bin\bash CC: gcc -# TODO: Uncomment -# - CYG_ROOT: C:\cygwin -# CYG_SETUP: setup-x86.exe -# CYG_MIRROR: http://cygwin.mirror.constant.com -# CYG_CACHE: C:\cygwin\var\cache\setup -# CYG_BASH: C:\cygwin\bin\bash -# CC: clang +# - MSYS_ROOT: C:\msys64 +# MSYS_BASH: C:\msys64\mingw64\bin\sh +# CC: x86_64-w64-mingw32-gcc # Cache Cygwin files to speed up build cache: @@ -42,13 +31,11 @@ init: # Install needed build dependencies install: - ps: 'if ($env:CYG_ROOT) { Start-FileDownload "http://cygwin.com/$env:CYG_SETUP" -FileName "$env:CYG_SETUP" }' - - '%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages make,gcc-core,clang,pkg-config,libpcre-devel,libglib2.0-devel,cmake --upgrade-also' - - '%CYG_BASH% -lc "cygcheck -dc cygwin"' - + - if defined CYG_ROOT (%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages make,gcc-core,clang,pkg-config,libpcre-devel,libglib2.0-devel,cmake,python-setuptools --upgrade-also) + - if defined MSYS_ROOT (%MSYS_BASH% -lc "pacman -S --noconfirm mingw-w64-x86_64-glib2") build_script: - # TODO: uncomment and enable tests - - '%CYG_BASH% -lc "export CYGWIN=winsymlinks:native; cd $APPVEYOR_BUILD_FOLDER; ./install-cmocka-linux.sh; ./make.sh; export PATH=$PATH:../../:../../cmocka/src; make test"' - #- '%CYG_BASH% -lc "export CYGWIN=winsymlinks:native; cd $APPVEYOR_BUILD_FOLDER; ./install-cmocka-linux.sh; ./make.sh"' + - if defined CYG_ROOT (%CYG_BASH% -lc "export CYGWIN=winsymlinks:native; cd $APPVEYOR_BUILD_FOLDER; ./install-cmocka-linux.sh; make; export PATH=$PATH:../../:../../cmocka/src:../:../cmocka/src; make test") + - if defined MSYS_ROOT (%MSYS_BASH% -lc "MSYS=winsymlinks, cd $(cygpath ${APPVEYOR_BUILD_FOLDER}); x86_64-w64-mingw32-gcc --version; ./install-cmocka-linux.sh; make") #- 'cd %APPVEYOR_BUILD_FOLDER% && cd bindings\dotnet && msbuild UnicornDotNet.sln' # Allows RDP #on_finish: diff --git a/.travis.yml b/.travis.yml index 3f12f302..75139721 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,42 +2,30 @@ language: c sudo: false before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update; fi - - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install glib cmocka; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" && "$MACOS_UNIVERSAL" != "yes" ]]; then brew install glib cmocka; fi + - if [[ "$TRAVIS_OS_NAME" == "osx" && "$MACOS_UNIVERSAL" == "yes" ]]; then brew install glib --universal cmocka; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./install-cmocka-linux.sh; fi script: - - if [[ $CC == *"x86_64"* ]]; then ./make.sh cross-win64; elif [[ $CC == *"i686"* ]]; then ./make.sh cross-win32; else ./make.sh && make test; fi + - make && make test # TODO make bindings enabled -# - ./make.sh && make test && make bindings -# TODO make universal build -# - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew remove glib && brew install glib --universal && make clean && ./make.sh macos-universal && make test; fi -# TODO test iOS builds # - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then make clean && ./make.sh ios; fi compiler: - clang - gcc -# TODO update mingw32 to gcc 4.7+ for compilation -# - i686-w64-mingw32-gcc -# - x86_64-w64-mingw32-gcc os: - linux - osx -#matrix: -# exclude: -# - os: osx -# compiler: i686-w64-mingw32-gcc +matrix: + include: + - os: osx + compiler: clang + env: MACOS_UNIVERSAL=yes + - os: osx + compiler: gcc + env: MACOS_UNIVERSAL=yes # - os: osx # compiler: x86_64-w64-mingw32-gcc addons: apt: packages: - - mingw-w64 - - gcc-mingw-w64 - - mingw-w64-dev - - gcc-mingw-w64-i686 - - gcc-mingw-w64-x86-64 - - binutils-mingw-w64-i686 - - binutils-mingw-w64-x86-64 -# TODO are mingw32 builds necessary? -# - mingw32 -# - mingw32-binutils -# - mingw32-runtime + # mingw-w64 packages too old in precise diff --git a/Makefile b/Makefile index 75f51228..2f828d35 100644 --- a/Makefile +++ b/Makefile @@ -63,6 +63,7 @@ ifeq ($(UNICORN_DEBUG),yes) CFLAGS += -g else CFLAGS += -O3 +UNICORN_QEMU_FLAGS += --disable-debug-info endif ifeq ($(UNICORN_ASAN),yes) @@ -97,9 +98,6 @@ PKG_VERSION = $(PKG_MAJOR).$(PKG_MINOR).$(PKG_EXTRA) endif API_MAJOR=$(shell echo `grep -e UC_API_MAJOR include/unicorn/unicorn.h | grep -v = | awk '{print $$3}'` | awk '{print $$1}') -VERSION_EXT = - -BIN_EXT = # Apple? ifeq ($(UNAME_S),Darwin) @@ -127,6 +125,8 @@ else ifneq ($(filter MINGW%,$(UNAME_S)),) EXT = dll AR_EXT = lib BIN_EXT = .exe +UNICORN_QEMU_FLAGS += --disable-stack-protector +UNICORN_CFLAGS := $(UNICORN_CFLAGS:-fPIC=) # Linux, Darwin else @@ -139,27 +139,25 @@ endif ifeq ($(UNICORN_SHARED),yes) ifneq ($(filter MINGW%,$(UNAME_S)),) -LIBRARY = $(BLDIR)/$(LIBNAME).$(EXT) +LIBRARY = $(LIBNAME).$(EXT) else ifneq ($(filter CYGWIN%,$(UNAME_S)),) -LIBRARY = $(BLDIR)/cyg$(LIBNAME).$(EXT) -LIBRARY_DLLA = $(BLDIR)/lib$(LIBNAME).$(EXT).$(AR_EXT) +LIBRARY = cyg$(LIBNAME).$(EXT) +LIBRARY_DLLA = lib$(LIBNAME).$(EXT).$(AR_EXT) $(LIBNAME)_LDFLAGS += -Wl,--out-implib=$(LIBRARY_DLLA) $(LIBNAME)_LDFLAGS += -lssp # Linux, Darwin else -LIBRARY = $(BLDIR)/lib$(LIBNAME).$(VERSION_EXT) -LIBRARY_SYMLINK = $(BLDIR)/lib$(LIBNAME).$(EXT) +LIBRARY = lib$(LIBNAME).$(VERSION_EXT) +LIBRARY_SYMLINK = lib$(LIBNAME).$(EXT) endif endif ifeq ($(UNICORN_STATIC),yes) ifneq ($(filter MINGW%,$(UNAME_S)),) -ARCHIVE = $(BLDIR)/$(LIBNAME).$(AR_EXT) -else ifneq ($(filter CYGWIN%,$(UNAME_S)),) -ARCHIVE = $(BLDIR)/lib$(LIBNAME).$(AR_EXT) -# Linux, Darwin +ARCHIVE = $(LIBNAME).$(AR_EXT) +# Cygwin, Linux, Darwin else -ARCHIVE = $(BLDIR)/lib$(LIBNAME).$(AR_EXT) +ARCHIVE = lib$(LIBNAME).$(AR_EXT) endif endif @@ -169,8 +167,6 @@ INSTALL_LIB ?= $(INSTALL_BIN) -m0755 PKGCFGF = $(LIBNAME).pc PREFIX ?= /usr DESTDIR ?= -BLDIR = . -OBJDIR = . LIBDIRARCH ?= lib # Uncomment the below line to installs x86_64 libs to lib64/ directory. @@ -200,75 +196,39 @@ else PKGCFGDIR ?= $(LIBDATADIR)/pkgconfig endif -all: compile_lib -ifeq (,$(findstring yes,$(UNICORN_BUILD_CORE_ONLY))) -ifeq ($(UNICORN_SHARED),yes) -ifeq ($(V),0) - @$(INSTALL_LIB) $(LIBRARY) $(BLDIR)/samples/ -else - $(INSTALL_LIB) $(LIBRARY) $(BLDIR)/samples/ -endif -endif - - @cd samples && $(MAKE) -endif +.PHONY: all +all: unicorn + $(MAKE) -C samples config: if [ "$(UNICORN_ARCHS)" != "`cat config.log`" ]; then $(MAKE) clean; fi qemu/config-host.h-timestamp: -ifeq ($(UNICORN_DEBUG),yes) cd qemu && \ ./configure --cc="${CC}" --extra-cflags="$(UNICORN_CFLAGS)" --target-list="$(UNICORN_TARGETS)" ${UNICORN_QEMU_FLAGS} printf "$(UNICORN_ARCHS)" > config.log -else - cd qemu && \ - ./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 - cd qemu && $(MAKE) -j 4 - $(MAKE) unicorn + $(MAKE) -C qemu -j 4 -unicorn: $(LIBRARY) $(ARCHIVE) +unicorn: compile_lib $(LIBRARY) $(ARCHIVE) -$(LIBRARY): $(UC_TARGET_OBJ) uc.o list.o -ifeq ($(UNICORN_SHARED),yes) -ifeq ($(V),0) - $(call log,GEN,$(LIBRARY)) - @$(CC) $(CFLAGS) -shared $^ -o $(LIBRARY) $(GLIB) -lm $($(LIBNAME)_LDFLAGS) -else - $(CC) $(CFLAGS) -shared $^ -o $(LIBRARY) $(GLIB) -lm $($(LIBNAME)_LDFLAGS) -endif -ifneq (,$(LIBRARY_SYMLINK)) - @ln -sf $(LIBRARY) $(LIBRARY_SYMLINK) -endif -endif +$(LIBRARY): $(UC_TARGET_OBJ) + $(CC) $(CFLAGS) -shared $(GENOBJ) uc.o list.o -o $(LIBRARY) $(GLIB) -lm $($(LIBNAME)_LDFLAGS) + ln -sf $(LIBRARY) $(LIBRARY_SYMLINK) $(ARCHIVE): $(UC_TARGET_OBJ) uc.o list.o -ifeq ($(UNICORN_STATIC),yes) -ifeq ($(V),0) - $(call log,GEN,$(ARCHIVE)) - @$(create-archive) -else - $(create-archive) -endif -endif + $(AR) q $(ARCHIVE) $^ + $(RANLIB) $(ARCHIVE) $(PKGCFGF): -ifeq ($(V),0) - $(call log,GEN,$(@:$(BLDIR)/%=%)) - @$(generate-pkgcfg) -else $(generate-pkgcfg) -endif - .PHONY: test test: all $(MAKE) -C tests/unit test + $(MAKE) -C bindings test install: compile_lib $(PKGCFGF) mkdir -p $(DESTDIR)$(LIBDIR) @@ -309,7 +269,7 @@ dist: git archive --format=zip --prefix=unicorn-$(DIST_VERSION)/ $(TAG) > unicorn-$(DIST_VERSION).zip -header: FORCE +header: $(eval TARGETS := m68k arm aarch64 mips mipsel mips64 mips64el\ powerpc sparc sparc64 x86_64) $(foreach var,$(TARGETS),\ @@ -328,10 +288,7 @@ clean: $(MAKE) -C qemu clean rm -rf *.d *.o rm -rf lib$(LIBNAME)* $(LIBNAME)*.lib $(LIBNAME)*.dll cyg$(LIBNAME)*.dll -ifeq (,$(findstring yes,$(UNICORN_BUILD_CORE_ONLY))) - cd samples && $(MAKE) clean - rm -f $(BLDIR)/samples/lib$(LIBNAME).$(EXT) -endif + $(MAKE) -C samples clean $(MAKE) -C tests/unit clean @@ -351,10 +308,3 @@ define log @printf " %-7s %s\n" "$(1)" "$(2)" endef - -define create-archive - $(AR) q $(ARCHIVE) $^ - $(RANLIB) $(ARCHIVE) -endef - -FORCE: diff --git a/bindings/Makefile b/bindings/Makefile index dee75187..7ded2e10 100644 --- a/bindings/Makefile +++ b/bindings/Makefile @@ -13,7 +13,7 @@ SAMPLE_X86 = $(TMP_DIR)/sample_x86 ENV_VARS = LD_LIBRARY_PATH=../ DYLD_LIBRARY_PATH=../ -.PHONY: build install samples sample_python expected python sample_diff clean check +.PHONY: build install expected python sample_diff clean check test build: $(MAKE) -C python gen_const @@ -26,9 +26,7 @@ install: build $(MAKE) -C python install $(MAKE) -C java install -samples: expected python - -sample_python: expected python +test: expected python sample_diff expected: $(MAKE) -C ../samples @@ -38,9 +36,11 @@ expected: $(ENV_VARS) ../samples/sample_mips > $(SAMPLE_MIPS)_e $(ENV_VARS) ../samples/sample_sparc > $(SAMPLE_SPARC)_e $(ENV_VARS) ../samples/sample_m68k > $(SAMPLE_M68K)_e - $(ENV_VARS) ../samples/sample_x86 > $(SAMPLE_X86)_e + $(ENV_VARS) ../samples/sample_x86 -16 > $(SAMPLE_X86)_e + $(ENV_VARS) ../samples/sample_x86 -32 >> $(SAMPLE_X86)_e + $(ENV_VARS) ../samples/sample_x86 -64 >> $(SAMPLE_X86)_e -python: FORCE +python: $(MAKE) -C python $(ENV_VARS) python python/sample_arm.py > $(SAMPLE_ARM)_o $(ENV_VARS) python python/sample_arm64.py > $(SAMPLE_ARM64)_o @@ -48,9 +48,8 @@ python: FORCE $(ENV_VARS) python python/sample_sparc.py > $(SAMPLE_SPARC)_o $(ENV_VARS) python python/sample_m68k.py > $(SAMPLE_M68K)_o $(ENV_VARS) python python/sample_x86.py > $(SAMPLE_X86)_o - $(MAKE) sample_diff -sample_diff: FORCE +sample_diff: $(DIFF) $(SAMPLE_ARM)_e $(SAMPLE_ARM)_o $(DIFF) $(SAMPLE_ARM64)_e $(SAMPLE_ARM64)_o $(DIFF) $(SAMPLE_MIPS)_e $(SAMPLE_MIPS)_o @@ -65,5 +64,3 @@ clean: check: make -C python check - -FORCE: diff --git a/bindings/go/unicorn/context.go b/bindings/go/unicorn/context.go new file mode 100644 index 00000000..bf5ced9b --- /dev/null +++ b/bindings/go/unicorn/context.go @@ -0,0 +1,28 @@ +package unicorn + +import ( + "runtime" +) + +// #include +import "C" + +type Context **C.uc_context + +func (u *uc) ContextSave(reuse Context) (Context, error) { + ctx := reuse + if ctx == nil { + ctx = new(*C.uc_context) + } + if err := errReturn(C.uc_context_alloc(u.handle, ctx)); err != nil { + return nil, err + } + runtime.SetFinalizer(ctx, func(p Context) { C.uc_context_free(*p) }) + if err := errReturn(C.uc_context_save(u.handle, *ctx)); err != nil { + } + return ctx, nil +} + +func (u *uc) ContextRestore(ctx Context) error { + return errReturn(C.uc_context_restore(u.handle, *ctx)) +} diff --git a/bindings/go/unicorn/context_test.go b/bindings/go/unicorn/context_test.go new file mode 100644 index 00000000..3231ef43 --- /dev/null +++ b/bindings/go/unicorn/context_test.go @@ -0,0 +1,26 @@ +package unicorn + +import ( + "testing" +) + +func TestContext(t *testing.T) { + u, err := NewUnicorn(ARCH_X86, MODE_32) + if err != nil { + t.Fatal(err) + } + u.RegWrite(X86_REG_EBP, 100) + ctx, err := u.ContextSave(nil) + if err != nil { + t.Fatal(err) + } + u.RegWrite(X86_REG_EBP, 200) + err = u.ContextRestore(ctx) + if err != nil { + t.Fatal(err) + } + val, _ := u.RegRead(X86_REG_EBP) + if val != 100 { + t.Fatal("context restore failed") + } +} diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index 59ad50e5..58e28939 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -55,6 +55,9 @@ type Unicorn interface { HookDel(hook Hook) error Query(queryType int) (uint64, error) Close() error + + ContextSave(reuse Context) (Context, error) + ContextRestore(Context) error } type uc struct { diff --git a/bindings/haskell/samples/SampleX86.hs b/bindings/haskell/samples/SampleX86.hs index fad686af..e395ed75 100644 --- a/bindings/haskell/samples/SampleX86.hs +++ b/bindings/haskell/samples/SampleX86.hs @@ -40,6 +40,10 @@ x86Code32JmpInvalid = BS.pack [0xe9, 0xe9, 0xee, 0xee, 0xee, 0x41, 0x4a] x86Code32InOut :: BS.ByteString x86Code32InOut = BS.pack [0x41, 0xe4, 0x3f, 0x4a, 0xe6, 0x46, 0x43] +-- inc eax +x86Code32Inc :: BS.ByteString +x86Code32Inc = BS.pack [0x40] + x86Code64 :: BS.ByteString x86Code64 = BS.pack [0x41, 0xbc, 0x3b, 0xb0, 0x28, 0x2a, 0x49, 0x0f, 0xc9, 0x90, 0x4d, 0x0f, 0xad, 0xcf, 0x49, 0x87, 0xfd, 0x90, @@ -494,6 +498,70 @@ testI386InOut = do Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ strerror err +-- Emulate code and save/restore the CPU context +testI386ContextSave :: IO () +testI386ContextSave = do + putStrLn "===================================" + putStrLn "Save/restore CPU context in opaque blob" + + result <- runEmulator $ do + -- Initialize emulator in X86-32bit mode + uc <- open ArchX86 [Mode32] + + -- Map 8KB memory for this emulation + memMap uc address (8 * 1024) [ProtAll] + + -- Write machine code to be emulated to memory + memWrite uc address x86Code32Inc + + -- Initialize machine registers + regWrite uc X86.Eax 0x1 + + -- Emulate machine code in infinite time + emuPutStrLn ">>> Running emulation for the first time" + + let codeLen = codeLength x86Code32Inc + 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 + + emuPutStrLn $ ">>> EAX = 0x" ++ showHex eax + + -- Allocate and save the CPU context + emuPutStrLn ">>> Saving CPU context" + + context <- contextAllocate uc + contextSave uc context + + -- Emulate machine code again + emuPutStrLn ">>> Running emulation for the second time" + + 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 + + emuPutStrLn $ ">>> EAX = 0x" ++ showHex eax + + -- Restore CPU context + contextRestore uc context + + -- Now print out some registers + emuPutStrLn ">>> Emulation done. Below is the CPU context" + + eax <- regRead uc X86.Eax + + emuPutStrLn $ ">>> EAX = 0x" ++ showHex eax + case result of + Right _ -> return () + Left err -> putStrLn $ "Failed with error " ++ show err ++ ": " ++ + strerror err + testX8664 :: IO () testX8664 = do putStrLn "Emulate x86_64 code" @@ -660,6 +728,7 @@ main = do ["-32"] -> do testI386 testI386InOut + testI386ContextSave testI386Jump testI386Loop testI386InvalidMemRead diff --git a/bindings/haskell/src/Unicorn.hs b/bindings/haskell/src/Unicorn.hs index 7f05eca4..19c07f8c 100644 --- a/bindings/haskell/src/Unicorn.hs +++ b/bindings/haskell/src/Unicorn.hs @@ -9,41 +9,47 @@ framework based on QEMU. Further information is available at . -} -module Unicorn ( - -- * Emulator control - Emulator, - Engine, - Architecture(..), - Mode(..), - QueryType(..), - runEmulator, - open, - query, - start, - stop, +module Unicorn + ( -- * Emulator control + Emulator + , Engine + , Architecture(..) + , Mode(..) + , QueryType(..) + , runEmulator + , open + , query + , start + , stop - -- * Register operations - regWrite, - regRead, + -- * Register operations + , regWrite + , regRead - -- * Memory operations - MemoryPermission(..), - MemoryRegion(..), - memWrite, - memRead, - memMap, - memUnmap, - memProtect, - memRegions, + -- * Memory operations + , MemoryPermission(..) + , MemoryRegion(..) + , memWrite + , memRead + , memMap + , memUnmap + , memProtect + , memRegions - -- * Error handling - Error(..), - errno, - strerror, + -- * Context operations + , Context + , contextAllocate + , contextSave + , contextRestore - -- * Misc. - version, -) where + -- * Error handling + , Error(..) + , errno + , strerror + + -- * Misc. + , version + ) where import Control.Monad (liftM) import Control.Monad.Trans.Class (lift) @@ -132,8 +138,8 @@ stop uc = do ------------------------------------------------------------------------------- -- | Write to register. -regWrite :: Reg r => - Engine -- ^ 'Unicorn' engine handle +regWrite :: Reg r + => Engine -- ^ 'Unicorn' engine handle -> r -- ^ Register ID to write to -> Int64 -- ^ Value to write to register -> Emulator () -- ^ An 'Error' on failure @@ -147,8 +153,8 @@ regWrite uc regId value = do left err -- | Read register value. -regRead :: Reg r => - Engine -- ^ 'Unicorn' engine handle +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 @@ -259,6 +265,46 @@ memRegions uc = do else left err +------------------------------------------------------------------------------- +-- Context operations +------------------------------------------------------------------------------- + +-- | Allocate a region that can be used to perform quick save/rollback of the +-- CPU context, which includes registers and some internal metadata. Contexts +-- may not be shared across engine instances with differing architectures or +-- modes. +contextAllocate :: Engine -- ^ 'Unicon' engine handle + -> Emulator Context -- ^ A CPU context +contextAllocate uc = do + (err, contextPtr) <- lift $ ucContextAlloc uc + if err == ErrOk then + -- Return a CPU context if ucContextAlloc completed successfully + lift $ mkContext contextPtr + else + left err + +-- | Save a copy of the internal CPU context. +contextSave :: Engine -- ^ 'Unicorn' engine handle + -> Context -- ^ A CPU context + -> Emulator () -- ^ An error on failure +contextSave uc context = do + err <- lift $ ucContextSave uc context + if err == ErrOk then + right () + else + left err + +-- | Restore the current CPU context from a saved copy. +contextRestore :: Engine -- ^ 'Unicorn' engine handle + -> Context -- ^ A CPU context + -> Emulator () -- ^ An error on failure +contextRestore uc context = do + err <- lift $ ucContextRestore uc context + if err == ErrOk then + right () + else + left err + ------------------------------------------------------------------------------- -- Misc. ------------------------------------------------------------------------------- diff --git a/bindings/haskell/src/Unicorn/CPU/Arm.chs b/bindings/haskell/src/Unicorn/CPU/Arm.chs index fbc3294c..138bf179 100644 --- a/bindings/haskell/src/Unicorn/CPU/Arm.chs +++ b/bindings/haskell/src/Unicorn/CPU/Arm.chs @@ -8,22 +8,25 @@ License : GPL-2 Definitions for the ARM architecture. -} -module Unicorn.CPU.Arm ( - Register(..), -) where +module Unicorn.CPU.Arm + ( + Register(..) + ) where import Unicorn.Internal.Core (Reg) -{# context lib="unicorn" #} +{# 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) #} + { 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 index 6174ef89..f4f1dec3 100644 --- a/bindings/haskell/src/Unicorn/CPU/Arm64.chs +++ b/bindings/haskell/src/Unicorn/CPU/Arm64.chs @@ -8,22 +8,25 @@ License : GPL-2 Definitions for the ARM64 (ARMv8) architecture. -} -module Unicorn.CPU.Arm64 ( - Register(..), -) where +module Unicorn.CPU.Arm64 + ( + Register(..) + ) where import Unicorn.Internal.Core (Reg) -{# context lib="unicorn" #} +{# 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) #} + { 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 index 25753aa4..b06ffb30 100644 --- a/bindings/haskell/src/Unicorn/CPU/M68k.chs +++ b/bindings/haskell/src/Unicorn/CPU/M68k.chs @@ -8,22 +8,25 @@ License : GPL-2 Definitions for the MK68K architecture. -} -module Unicorn.CPU.M68k ( - Register(..), -) where +module Unicorn.CPU.M68k + ( + Register(..) + ) where import Unicorn.Internal.Core (Reg) -{# context lib="unicorn" #} +{# 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) #} + { 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 index b234ba72..8ec5db4d 100644 --- a/bindings/haskell/src/Unicorn/CPU/Mips.chs +++ b/bindings/haskell/src/Unicorn/CPU/Mips.chs @@ -8,54 +8,58 @@ License : GPL-2 Definitions for the MIPS architecture. -} -module Unicorn.CPU.Mips ( - Register(..), -) where +module Unicorn.CPU.Mips + ( + Register(..) + ) where import Unicorn.Internal.Core (Reg) -{# context lib="unicorn" #} +{# 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) #} + { underscoreToCase + , UC_MIPS_REG_0 as Reg0g + , UC_MIPS_REG_1 as Reg1g + , UC_MIPS_REG_2 as Reg2g + , UC_MIPS_REG_3 as Reg3g + , UC_MIPS_REG_4 as Reg4g + , UC_MIPS_REG_5 as Reg5g + , UC_MIPS_REG_6 as Reg6g + , UC_MIPS_REG_7 as Reg7g + , UC_MIPS_REG_8 as Reg8g + , UC_MIPS_REG_9 as Reg9g + , UC_MIPS_REG_10 as Reg10g + , UC_MIPS_REG_11 as Reg11g + , UC_MIPS_REG_12 as Reg12g + , UC_MIPS_REG_13 as Reg13g + , UC_MIPS_REG_14 as Reg14g + , UC_MIPS_REG_15 as Reg15g + , UC_MIPS_REG_16 as Reg16g + , UC_MIPS_REG_17 as Reg17g + , UC_MIPS_REG_18 as Reg18g + , UC_MIPS_REG_19 as Reg19g + , UC_MIPS_REG_20 as Reg20g + , UC_MIPS_REG_21 as Reg21g + , UC_MIPS_REG_22 as Reg22g + , UC_MIPS_REG_23 as Reg23g + , UC_MIPS_REG_24 as Reg24g + , UC_MIPS_REG_25 as Reg25g + , UC_MIPS_REG_26 as Reg26g + , UC_MIPS_REG_27 as Reg27g + , UC_MIPS_REG_28 as Reg28g + , UC_MIPS_REG_29 as Reg29g + , UC_MIPS_REG_30 as Reg30g + , 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 index a94c1b22..e54262bd 100644 --- a/bindings/haskell/src/Unicorn/CPU/Sparc.chs +++ b/bindings/haskell/src/Unicorn/CPU/Sparc.chs @@ -8,22 +8,25 @@ License : GPL-2 Definitions for the SPARC architecture. -} -module Unicorn.CPU.Sparc ( - Register(..), -) where +module Unicorn.CPU.Sparc + ( + Register(..) + ) where import Unicorn.Internal.Core (Reg) -{# context lib="unicorn" #} +{# 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) #} + { 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 index eb99c978..56608c17 100644 --- a/bindings/haskell/src/Unicorn/CPU/X86.chs +++ b/bindings/haskell/src/Unicorn/CPU/X86.chs @@ -8,11 +8,12 @@ License : GPL-2 Definitions for the X86 architecture. -} -module Unicorn.CPU.X86 ( - Mmr(..), - Register(..), - Instruction(..), -) where +module Unicorn.CPU.X86 + ( + Mmr(..) + , Register(..) + , Instruction(..) + ) where import Control.Applicative import Data.Word @@ -20,18 +21,18 @@ import Foreign import Unicorn.Internal.Core (Reg) -{# context lib="unicorn" #} +{# 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 -} +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 #} @@ -48,18 +49,22 @@ instance Storable Mmr where -- | 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) #} + { 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) #} + { 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 index 2e13ebc4..9595a140 100644 --- a/bindings/haskell/src/Unicorn/Hook.hs +++ b/bindings/haskell/src/Unicorn/Hook.hs @@ -6,36 +6,36 @@ License : GPL-2 Insert hook points into the Unicorn emulator engine. -} -module Unicorn.Hook ( - -- * Hook types - Hook, - MemoryHookType(..), - MemoryEventHookType(..), - MemoryAccess(..), +module Unicorn.Hook + ( -- * Hook types + Hook + , MemoryHookType(..) + , MemoryEventHookType(..) + , MemoryAccess(..) - -- * Hook callbacks - CodeHook, - InterruptHook, - BlockHook, - InHook, - OutHook, - SyscallHook, - MemoryHook, - MemoryReadHook, - MemoryWriteHook, - MemoryEventHook, + -- * 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 + -- * Hook callback management + , codeHookAdd + , interruptHookAdd + , blockHookAdd + , inHookAdd + , outHookAdd + , syscallHookAdd + , memoryHookAdd + , memoryEventHookAdd + , hookDel + ) where import Control.Monad import Control.Monad.Trans.Class @@ -213,7 +213,8 @@ hookDel uc hook = do -- 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 :: IO (Error, Hook) + -> IO (Either Error Hook) getResult = liftM (uncurry checkResult) where checkResult err hook = diff --git a/bindings/haskell/src/Unicorn/Internal/Core.chs b/bindings/haskell/src/Unicorn/Internal/Core.chs index a69f51c3..dcc6a7fc 100644 --- a/bindings/haskell/src/Unicorn/Internal/Core.chs +++ b/bindings/haskell/src/Unicorn/Internal/Core.chs @@ -17,31 +17,34 @@ import Control.Monad import Control.Monad.Trans.Either (EitherT) import Foreign -{# context lib="unicorn" #} +{# context lib = "unicorn" #} #include #include "unicorn_wrapper.h" -- | The Unicorn engine. {# pointer *uc_engine as Engine - foreign finalizer uc_close_wrapper as close - newtype #} + 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 call 'uc_close_wrapper' when it goes out of scope. -mkEngine :: EnginePtr -> IO Engine +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) #} + { 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". diff --git a/bindings/haskell/src/Unicorn/Internal/Hook.chs b/bindings/haskell/src/Unicorn/Internal/Hook.chs index 00a8a123..affed872 100644 --- a/bindings/haskell/src/Unicorn/Internal/Hook.chs +++ b/bindings/haskell/src/Unicorn/Internal/Hook.chs @@ -11,54 +11,54 @@ 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(..), +module Unicorn.Internal.Hook + ( -- * Types + Hook + , HookType(..) + , MemoryHookType(..) + , MemoryEventHookType(..) + , MemoryAccess(..) - -- * Hook callback bindings - CodeHook, - InterruptHook, - BlockHook, - InHook, - OutHook, - SyscallHook, - MemoryHook, - MemoryReadHook, - MemoryWriteHook, - MemoryEventHook, + -- * 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 marshallin + , marshalCodeHook + , marshalInterruptHook + , marshalBlockHook + , marshalInHook + , marshalOutHook + , marshalSyscallHook + , marshalMemoryHook + , marshalMemoryReadHook + , marshalMemoryWriteHook + , marshalMemoryEventHook - -- * Hook registration and deletion bindings - ucHookAdd, - ucInsnHookAdd, - ucHookDel, -) where + -- * 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 #} +{# context lib = "unicorn" #} + #include #include "unicorn_wrapper.h" @@ -79,7 +79,8 @@ import Unicorn.Internal.Util foreign import ccall "&uc_close_dummy" closeDummy :: FunPtr (EnginePtr -> IO ()) -mkEngineNC :: EnginePtr -> IO Engine +mkEngineNC :: EnginePtr + -> IO Engine mkEngineNC ptr = liftM Engine (newForeignPtr closeDummy ptr) @@ -92,47 +93,55 @@ type Hook = {# type uc_hook #} -- 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) #} + { 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 + , UC_HOOK_MEM_READ_AFTER + ) + 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) #} + { 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) #} + { 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 + , UC_HOOK_MEM_READ_AFTER + ) + with prefix = "UC_" + deriving (Show, Eq, Bounded) +#} -- | Unify the hook types with a type class class Enum a => HookTypeC a @@ -143,9 +152,10 @@ instance HookTypeC MemoryEventHookType -- | Memory access. {# enum uc_mem_type as MemoryAccess - {underscoreToCase} - with prefix="UC_" - deriving (Show, Eq, Bounded) #} + { underscoreToCase } + with prefix = "UC_" + deriving (Show, Eq, Bounded) +#} ------------------------------------------------------------------------------- -- Hook callbacks @@ -159,16 +169,18 @@ type CodeHook a = Engine -- ^ 'Unicorn' engine handle -> a -- ^ User data passed to tracing APIs -> IO () -type CCodeHook = EnginePtr -> Word64 -> Word32 -> Ptr () -> IO () +type CCodeHook = EnginePtr -> Word64 -> Word32 -> Ptr () -> IO () foreign import ccall "wrapper" - mkCodeHook :: CCodeHook -> IO {# type uc_cb_hookcode_t #} + mkCodeHook :: CCodeHook + -> IO {# type uc_cb_hookcode_t #} marshalCodeHook :: Storable a - => CodeHook a -> IO {# type uc_cb_hookcode_t #} + => CodeHook a + -> IO {# type uc_cb_hookcode_t #} marshalCodeHook codeHook = mkCodeHook $ \ucPtr address size userDataPtr -> do - uc <- mkEngineNC ucPtr + uc <- mkEngineNC ucPtr userData <- castPtrAndPeek userDataPtr let maybeSize = if size == 0 then Nothing else Just $ fromIntegral size @@ -186,10 +198,11 @@ foreign import ccall "wrapper" mkInterruptHook :: CInterruptHook -> IO {# type uc_cb_hookintr_t #} marshalInterruptHook :: Storable a - => InterruptHook a -> IO {# type uc_cb_hookintr_t #} + => InterruptHook a + -> IO {# type uc_cb_hookintr_t #} marshalInterruptHook interruptHook = mkInterruptHook $ \ucPtr intNo userDataPtr -> do - uc <- mkEngineNC ucPtr + uc <- mkEngineNC ucPtr userData <- castPtrAndPeek userDataPtr interruptHook uc (fromIntegral intNo) userData @@ -197,7 +210,8 @@ marshalInterruptHook interruptHook = type BlockHook a = CodeHook a marshalBlockHook :: Storable a - => BlockHook a -> IO {# type uc_cb_hookcode_t #} + => BlockHook a + -> IO {# type uc_cb_hookcode_t #} marshalBlockHook = marshalCodeHook @@ -214,10 +228,11 @@ 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 #} + => InHook a + -> IO {# type uc_cb_insn_in_t #} marshalInHook inHook = mkInHook $ \ucPtr port size userDataPtr -> do - uc <- mkEngineNC ucPtr + uc <- mkEngineNC ucPtr userData <- castPtrAndPeek userDataPtr inHook uc (fromIntegral port) (fromIntegral size) userData @@ -232,13 +247,15 @@ type OutHook a = Engine -- ^ 'Unicorn' engine handle type COutHook = EnginePtr -> Word32 -> Int32 -> Word32 -> Ptr () -> IO () foreign import ccall "wrapper" - mkOutHook :: COutHook -> IO {# type uc_cb_insn_out_t #} + mkOutHook :: COutHook + -> IO {# type uc_cb_insn_out_t #} marshalOutHook :: Storable a - => OutHook a -> IO {# type uc_cb_insn_out_t #} + => OutHook a + -> IO {# type uc_cb_insn_out_t #} marshalOutHook outHook = mkOutHook $ \ucPtr port size value userDataPtr -> do - uc <- mkEngineNC ucPtr + uc <- mkEngineNC ucPtr userData <- castPtrAndPeek userDataPtr outHook uc (fromIntegral port) (fromIntegral size) (fromIntegral value) userData @@ -251,13 +268,15 @@ type SyscallHook a = Engine -- ^ 'Unicorn' engine handle type CSyscallHook = Ptr () -> Ptr () -> IO () foreign import ccall "wrapper" - mkSyscallHook :: CSyscallHook -> IO {# type uc_cb_insn_syscall_t #} + mkSyscallHook :: CSyscallHook + -> IO {# type uc_cb_insn_syscall_t #} marshalSyscallHook :: Storable a - => SyscallHook a -> IO {# type uc_cb_insn_syscall_t #} + => SyscallHook a + -> IO {# type uc_cb_insn_syscall_t #} marshalSyscallHook syscallHook = mkSyscallHook $ \ucPtr userDataPtr -> do - uc <- mkEngineNC $ castPtr ucPtr + uc <- mkEngineNC $ castPtr ucPtr userData <- castPtrAndPeek userDataPtr syscallHook uc userData @@ -281,13 +300,15 @@ type CMemoryHook = EnginePtr -> IO () foreign import ccall "wrapper" - mkMemoryHook :: CMemoryHook -> IO {# type uc_cb_hookmem_t #} + mkMemoryHook :: CMemoryHook + -> IO {# type uc_cb_hookmem_t #} marshalMemoryHook :: Storable a - => MemoryHook a -> IO {# type uc_cb_hookmem_t #} + => MemoryHook a + -> IO {# type uc_cb_hookmem_t #} marshalMemoryHook memoryHook = mkMemoryHook $ \ucPtr memAccessI address size value userDataPtr -> do - uc <- mkEngineNC ucPtr + uc <- mkEngineNC ucPtr userData <- castPtrAndPeek userDataPtr let memAccess = toMemAccess memAccessI maybeValue = case memAccess of @@ -304,10 +325,11 @@ type MemoryReadHook a = Engine -- ^ 'Unicorn' engine handle -> IO () marshalMemoryReadHook :: Storable a - => MemoryReadHook a -> IO {# type uc_cb_hookmem_t #} + => MemoryReadHook a + -> IO {# type uc_cb_hookmem_t #} marshalMemoryReadHook memoryReadHook = mkMemoryHook $ \ucPtr _ address size _ userDataPtr -> do - uc <- mkEngineNC ucPtr + uc <- mkEngineNC ucPtr userData <- castPtrAndPeek userDataPtr memoryReadHook uc address (fromIntegral size) userData @@ -321,10 +343,11 @@ type MemoryWriteHook a = Engine -- ^ 'Unicorn' engine handle -> IO () marshalMemoryWriteHook :: Storable a - => MemoryWriteHook a -> IO {# type uc_cb_hookmem_t #} + => MemoryWriteHook a + -> IO {# type uc_cb_hookmem_t #} marshalMemoryWriteHook memoryWriteHook = mkMemoryHook $ \ucPtr _ address size value userDataPtr -> do - uc <- mkEngineNC ucPtr + uc <- mkEngineNC ucPtr userData <- castPtrAndPeek userDataPtr memoryWriteHook uc address (fromIntegral size) (fromIntegral value) userData @@ -351,15 +374,17 @@ type CMemoryEventHook = EnginePtr -> IO Int32 foreign import ccall "wrapper" - mkMemoryEventHook :: CMemoryEventHook -> IO {# type uc_cb_eventmem_t #} + mkMemoryEventHook :: CMemoryEventHook + -> IO {# type uc_cb_eventmem_t #} marshalMemoryEventHook :: Storable a - => MemoryEventHook a -> IO {# type uc_cb_eventmem_t #} + => MemoryEventHook a + -> IO {# type uc_cb_eventmem_t #} marshalMemoryEventHook eventMemoryHook = mkMemoryEventHook $ \ucPtr memAccessI address size value userDataPtr -> do - uc <- mkEngineNC ucPtr + uc <- mkEngineNC ucPtr userData <- castPtrAndPeek userDataPtr - let memAccess = toMemAccess memAccessI + let memAccess = toMemAccess memAccessI maybeValue = case memAccess of MemReadUnmapped -> Nothing MemReadProt -> Nothing @@ -369,7 +394,7 @@ marshalMemoryEventHook eventMemoryHook = res <- eventMemoryHook uc memAccess address (fromIntegral size) maybeValue userData return $ boolToInt res - where boolToInt True = 1 + where boolToInt True = 1 boolToInt False = 0 @@ -378,38 +403,43 @@ marshalMemoryEventHook eventMemoryHook = ------------------------------------------------------------------------------- {# 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' #} + `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' #} + `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' #} + { `Engine' + , fromIntegral `Hook' + } -> `Error' +#} ------------------------------------------------------------------------------- -- Helper functions ------------------------------------------------------------------------------- -toMemAccess :: Integral a => a -> MemoryAccess +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 index 53bf82f5..30605282 100644 --- a/bindings/haskell/src/Unicorn/Internal/Unicorn.chs +++ b/bindings/haskell/src/Unicorn/Internal/Unicorn.chs @@ -12,33 +12,39 @@ 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(..), +module Unicorn.Internal.Unicorn + ( -- * Types + Architecture(..) + , Mode(..) + , MemoryPermission(..) + , MemoryRegion(..) + , QueryType(..) + , Context - -- * Function bindings - ucOpen, - ucQuery, - ucEmuStart, - ucEmuStop, - ucRegWrite, - ucRegRead, - ucMemWrite, - ucMemRead, - ucMemMap, - ucMemUnmap, - ucMemProtect, - ucMemRegions, - ucVersion, - ucErrno, - ucStrerror, -) where + -- * Function bindings + , ucOpen + , ucQuery + , ucEmuStart + , ucEmuStop + , ucRegWrite + , ucRegRead + , ucMemWrite + , ucMemRead + , ucMemMap + , ucMemUnmap + , ucMemProtect + , ucMemRegions + , mkContext + , ucContextAlloc + , ucContextSave + , ucContextRestore + , ucVersion + , ucErrno + , ucStrerror + ) where import Control.Applicative +import Control.Monad import Data.ByteString (ByteString, useAsCStringLen) import Foreign import Foreign.C @@ -46,11 +52,12 @@ import Prelude hiding (until) import Unicorn.Internal.Util -{# context lib="unicorn" #} - {# import Unicorn.Internal.Core #} +{# context lib = "unicorn" #} + #include +#include "unicorn_wrapper.h" ------------------------------------------------------------------------------- -- Types @@ -58,29 +65,33 @@ import Unicorn.Internal.Util -- | CPU architecture. {# enum uc_arch as Architecture - {underscoreToCase} - with prefix="UC_" - deriving (Show, Eq, Bounded) #} + { underscoreToCase } + with prefix = "UC_" + deriving (Show, Eq, Bounded) +#} -- | CPU hardware mode. {# enum uc_mode as Mode - {underscoreToCase} - with prefix="UC_" - deriving (Show, Eq, Bounded) #} + { underscoreToCase } + with prefix = "UC_" + deriving (Show, Eq, Bounded) +#} -- | Memory permissions. {# enum uc_prot as MemoryPermission - {underscoreToCase} - with prefix="UC_" - deriving (Show, Eq, Bounded) #} + { 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 -} +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 #} @@ -99,121 +110,174 @@ instance Storable MemoryRegion where -- | Query types for the 'query' API. {# enum uc_query_type as QueryType - {underscoreToCase} - with prefix="UC_" - deriving (Show, Eq, Bounded) #} + { underscoreToCase } + with prefix = "UC_" + deriving (Show, Eq, Bounded) +#} + +-- | Opaque storage for CPU context, used with the context functions. +{# pointer *uc_context as Context + foreign finalizer uc_context_free_wrapper as contextFree + newtype +#} + +-- | A pointer to a CPU context. +{# pointer *uc_context as ContextPtr -> Context #} + +-- | Make a CPU context out of a context pointer. The returned CPU context will +-- automatically call 'uc_context_free' when it goes out of scope. +mkContext :: ContextPtr + -> IO Context +mkContext ptr = + liftM Context (newForeignPtr contextFree ptr) ------------------------------------------------------------------------------- -- Emulator control ------------------------------------------------------------------------------- {# fun uc_open as ^ - {`Architecture', - combineEnums `[Mode]', - alloca- `EnginePtr' peek*} - -> `Error' #} + { `Architecture' + , combineEnums `[Mode]' + , alloca- `EnginePtr' peek* + } -> `Error' +#} {# fun uc_query as ^ - {`Engine', - `QueryType', - alloca- `Int' castPtrAndPeek*} - -> `Error' #} + { `Engine' + , `QueryType' + , alloca- `Int' castPtrAndPeek* + } -> `Error' +#} {# fun uc_emu_start as ^ - {`Engine', - `Word64', - `Word64', - `Int', - `Int'} - -> `Error' #} + { `Engine' + , `Word64' + , `Word64' + , `Int' + , `Int'} -> `Error' +#} {# fun uc_emu_stop as ^ - {`Engine'} - -> `Error' #} + { `Engine' + } -> `Error' +#} ------------------------------------------------------------------------------- -- Register operations ------------------------------------------------------------------------------- {# fun uc_reg_write as ^ - `Reg r' => - {`Engine', - enumToNum `r', - castPtr `Ptr Int64'} - -> `Error' #} + `Reg r' => + { `Engine' + , enumToNum `r' + , castPtr `Ptr Int64' + } -> `Error' +#} {# fun uc_reg_read as ^ - `Reg r' => - {`Engine', - enumToNum `r', - allocaInt64ToVoid- `Int64' castPtrAndPeek*} - -> `Error' #} + `Reg r' => + { `Engine' + , enumToNum `r' + , allocaInt64ToVoid- `Int64' castPtrAndPeek* + } -> `Error' +#} ------------------------------------------------------------------------------- -- Memory operations ------------------------------------------------------------------------------- {# fun uc_mem_write as ^ - {`Engine', - `Word64', - withByteStringLen* `ByteString'&} - -> `Error' #} + { `Engine' + , `Word64' + , withByteStringLen* `ByteString'& + } -> `Error' +#} {# fun uc_mem_read as ^ - {`Engine', - `Word64', - castPtr `Ptr Word8', - `Int'} - -> `Error' #} + { `Engine' + , `Word64' + , castPtr `Ptr Word8' + , `Int'} -> `Error' +#} {# fun uc_mem_map as ^ - {`Engine', - `Word64', - `Int', - combineEnums `[MemoryPermission]'} - -> `Error' #} + { `Engine' + , `Word64' + , `Int' + , combineEnums `[MemoryPermission]' + } -> `Error' #} {# fun uc_mem_unmap as ^ - {`Engine', - `Word64', - `Int'} - -> `Error' #} + { `Engine' + , `Word64' + , `Int' + } -> `Error' +#} {# fun uc_mem_protect as ^ - {`Engine', - `Word64', - `Int', - combineEnums `[MemoryPermission]'} - -> `Error' #} + { `Engine' + , `Word64' + , `Int' + , combineEnums `[MemoryPermission]' + } -> `Error' +#} {# fun uc_mem_regions as ^ - {`Engine', - alloca- `MemoryRegionPtr' peek*, - alloca- `Int' castPtrAndPeek*} - -> `Error' #} + { `Engine' + , alloca- `MemoryRegionPtr' peek* + , alloca- `Int' castPtrAndPeek* + } -> `Error' +#} + +------------------------------------------------------------------------------- +-- Context +------------------------------------------------------------------------------- + +{# fun uc_context_alloc as ^ + { `Engine' + , alloca- `ContextPtr' peek* + } -> `Error' +#} + +{# fun uc_context_save as ^ + { `Engine' + , `Context' + } -> `Error' +#} + +{# fun uc_context_restore as ^ + { `Engine' + , `Context' + } -> `Error' +#} ------------------------------------------------------------------------------- -- Misc. ------------------------------------------------------------------------------- {# fun pure unsafe uc_version as ^ - {id `Ptr CUInt', - id `Ptr CUInt'} - -> `Int' #} + { id `Ptr CUInt' + , id `Ptr CUInt' + } -> `Int' +#} {# fun unsafe uc_errno as ^ - {`Engine'} - -> `Error' #} + { `Engine' + } -> `Error' +#} {# fun pure unsafe uc_strerror as ^ - {`Error'} - -> `String' #} + { `Error' + } -> `String' +#} ------------------------------------------------------------------------------- -- Helper functions ------------------------------------------------------------------------------- -expandMemPerms :: (Integral a, Bits a) => a -> [MemoryPermission] +expandMemPerms :: (Integral a, Bits a) + => a + -> [MemoryPermission] expandMemPerms perms = -- Only interested in the 3 least-significant bits let maskedPerms = fromIntegral $ perms .&. 0x7 in @@ -232,10 +296,13 @@ expandMemPerms perms = checkRWE _ [] = [] -allocaInt64ToVoid :: (Ptr () -> IO b) -> IO b +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 :: 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 index 3af6a513..edaf3430 100644 --- a/bindings/haskell/src/Unicorn/Internal/Util.hs +++ b/bindings/haskell/src/Unicorn/Internal/Util.hs @@ -10,16 +10,22 @@ 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 :: (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 :: Storable a + => Ptr b + -> IO a castPtrAndPeek = peek . castPtr -- | Convert an 'Eum' to a 'Num'. -enumToNum :: (Enum a, Num b) => a -> b +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 index 1ee60706..fdbbe6d8 100644 --- a/bindings/haskell/src/cbits/unicorn_wrapper.c +++ b/bindings/haskell/src/cbits/unicorn_wrapper.c @@ -6,3 +6,7 @@ void uc_close_wrapper(uc_engine *uc) { void uc_close_dummy(uc_engine *uc) { } + +void uc_context_free_wrapper(uc_context *context) { + uc_context_free(context); +} diff --git a/bindings/haskell/src/include/unicorn_wrapper.h b/bindings/haskell/src/include/unicorn_wrapper.h index 76d414aa..e717c408 100644 --- a/bindings/haskell/src/include/unicorn_wrapper.h +++ b/bindings/haskell/src/include/unicorn_wrapper.h @@ -13,4 +13,9 @@ void uc_close_wrapper(uc_engine *uc); */ void uc_close_dummy(uc_engine *uc); +/* + * Wrap Unicorn's uc_context_free function and ignore the returned error code. + */ +void uc_context_free_wrapper(uc_context *context); + #endif diff --git a/bindings/haskell/unicorn.cabal b/bindings/haskell/unicorn.cabal index 027e09d2..d050c538 100644 --- a/bindings/haskell/unicorn.cabal +++ b/bindings/haskell/unicorn.cabal @@ -13,8 +13,9 @@ copyright: (c) 2016, Adrian Herrera category: System build-type: Simple stability: experimental -cabal-version: >=1.10 -extra-source-files: cbits/, include/ +cabal-version: >= 1.10 +extra-source-files: cbits/ + , include/ library exposed-modules: Unicorn.Internal.Core @@ -29,10 +30,10 @@ library Unicorn.Hook Unicorn other-modules: Unicorn.Internal.Util - build-depends: base >=4 && <5, - bytestring >= 0.9.1, - transformers < 0.6, - either >= 4.4 + build-depends: base >=4 && <5 + , bytestring >= 0.9.1 + , transformers < 0.6 + , either >= 4.4 hs-source-dirs: src c-sources: src/cbits/unicorn_wrapper.c include-dirs: src/include diff --git a/bindings/python/sample_arm.py b/bindings/python/sample_arm.py index e910defc..13292320 100755 --- a/bindings/python/sample_arm.py +++ b/bindings/python/sample_arm.py @@ -21,7 +21,7 @@ def hook_block(uc, address, size, user_data): # callback for tracing instructions def hook_code(uc, address, size, user_data): - print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size)) + print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size)) # Test ARM @@ -46,7 +46,7 @@ def test_arm(): 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_CODE, hook_code, begin=ADDRESS, end=ADDRESS) # emulate machine code in infinite time mu.emu_start(ADDRESS, ADDRESS + len(ARM_CODE)) @@ -100,5 +100,5 @@ def test_thumb(): if __name__ == '__main__': test_arm() - print("=" * 20) + print("=" * 26) test_thumb() diff --git a/bindings/python/sample_arm64.py b/bindings/python/sample_arm64.py index 2afee8c4..0270a401 100755 --- a/bindings/python/sample_arm64.py +++ b/bindings/python/sample_arm64.py @@ -21,7 +21,7 @@ def hook_block(uc, address, size, user_data): # callback for tracing instructions def hook_code(uc, address, size, user_data): - print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size)) + print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size)) # Test ARM64 diff --git a/bindings/python/sample_m68k.py b/bindings/python/sample_m68k.py index d9579f66..7e35cf59 100755 --- a/bindings/python/sample_m68k.py +++ b/bindings/python/sample_m68k.py @@ -20,7 +20,7 @@ def hook_block(uc, address, size, user_data): # callback for tracing instructions def hook_code(uc, address, size, user_data): - print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size)) + print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size)) # Test ARM @@ -51,8 +51,34 @@ def test_m68k(): # now print out some registers print(">>> Emulation done. Below is the CPU context") + a0 = mu.reg_read(UC_M68K_REG_A0) + a1 = mu.reg_read(UC_M68K_REG_A1) + a2 = mu.reg_read(UC_M68K_REG_A2) + a3 = mu.reg_read(UC_M68K_REG_A3) + a4 = mu.reg_read(UC_M68K_REG_A4) + a5 = mu.reg_read(UC_M68K_REG_A5) + a6 = mu.reg_read(UC_M68K_REG_A6) + a7 = mu.reg_read(UC_M68K_REG_A7) + d0 = mu.reg_read(UC_M68K_REG_D0) + d1 = mu.reg_read(UC_M68K_REG_D1) + d2 = mu.reg_read(UC_M68K_REG_D2) d3 = mu.reg_read(UC_M68K_REG_D3) - print(">>> D3 = 0x%x" %d3) + d4 = mu.reg_read(UC_M68K_REG_D4) + d5 = mu.reg_read(UC_M68K_REG_D5) + d6 = mu.reg_read(UC_M68K_REG_D6) + d7 = mu.reg_read(UC_M68K_REG_D7) + pc = mu.reg_read(UC_M68K_REG_PC) + sr = mu.reg_read(UC_M68K_REG_SR) + print(">>> A0 = 0x%x\t\t>>> D0 = 0x%x" % (a0, d0)) + print(">>> A1 = 0x%x\t\t>>> D1 = 0x%x" % (a1, d1)) + print(">>> A2 = 0x%x\t\t>>> D2 = 0x%x" % (a2, d2)) + print(">>> A3 = 0x%x\t\t>>> D3 = 0x%x" % (a3, d3)) + print(">>> A4 = 0x%x\t\t>>> D4 = 0x%x" % (a4, d4)) + print(">>> A5 = 0x%x\t\t>>> D5 = 0x%x" % (a5, d5)) + print(">>> A6 = 0x%x\t\t>>> D6 = 0x%x" % (a6, d6)) + print(">>> A7 = 0x%x\t\t>>> D7 = 0x%x" % (a7, d7)) + print(">>> PC = 0x%x" % pc) + print(">>> SR = 0x%x" % sr) except UcError as e: print("ERROR: %s" % e) diff --git a/bindings/python/sample_mips.py b/bindings/python/sample_mips.py index 9b9f9e8f..7199b631 100755 --- a/bindings/python/sample_mips.py +++ b/bindings/python/sample_mips.py @@ -22,7 +22,7 @@ def hook_block(uc, address, size, user_data): # callback for tracing instructions def hook_code(uc, address, size, user_data): - print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size)) + print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size)) # Test MIPS EB @@ -54,7 +54,7 @@ def test_mips_eb(): print(">>> Emulation done. Below is the CPU context") r1 = mu.reg_read(UC_MIPS_REG_1) - print(">>> r1 = 0x%x" %r1) + print(">>> R1 = 0x%x" %r1) except UcError as e: print("ERROR: %s" % e) @@ -89,7 +89,7 @@ def test_mips_el(): print(">>> Emulation done. Below is the CPU context") r1 = mu.reg_read(UC_MIPS_REG_1) - print(">>> r1 = 0x%x" %r1) + print(">>> R1 = 0x%x" %r1) except UcError as e: print("ERROR: %s" % e) @@ -97,5 +97,5 @@ def test_mips_el(): if __name__ == '__main__': test_mips_eb() - print("=" * 20) + print("=" * 27) test_mips_el() diff --git a/bindings/python/sample_sparc.py b/bindings/python/sample_sparc.py index f6f154d6..5dbe746e 100755 --- a/bindings/python/sample_sparc.py +++ b/bindings/python/sample_sparc.py @@ -20,7 +20,7 @@ def hook_block(uc, address, size, user_data): # callback for tracing instructions def hook_code(uc, address, size, user_data): - print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size)) + print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size)) # Test SPARC diff --git a/bindings/python/sample_x86.py b/bindings/python/sample_x86.py index 81027b2a..981a6d5e 100755 --- a/bindings/python/sample_x86.py +++ b/bindings/python/sample_x86.py @@ -8,6 +8,8 @@ from unicorn.x86_const import * X86_CODE32 = b"\x41\x4a\x66\x0f\xef\xc1" # INC ecx; DEC edx; PXOR xmm0, xmm1 X86_CODE32_LOOP = b"\x41\x4a\xeb\xfe" # INC ecx; DEC edx; JMP self-loop +X86_CODE32_JUMP = b"\xeb\x02\x90\x90\x90\x90\x90\x90" # jmp 4; nop; nop; nop; nop; nop; nop +X86_CODE32_JMP_INVALID = b"\xe9\xe9\xee\xee\xee\x41\x4a" # JMP outside; INC ecx; DEC edx X86_CODE32_MEM_READ = b"\x8B\x0D\xAA\xAA\xAA\xAA\x41\x4a" # mov ecx,[0xaaaaaaaa]; INC ecx; DEC edx X86_CODE32_MEM_WRITE = b"\x89\x0D\xAA\xAA\xAA\xAA\x41\x4a" # mov [0xaaaaaaaa], ecx; INC ecx; DEC edx X86_CODE64 = b"\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" @@ -26,9 +28,14 @@ def hook_block(uc, address, size, user_data): # callback for tracing instructions def hook_code(uc, address, size, user_data): - print(">>> Tracing instruction at 0x%x, instruction size = %u" %(address, size)) - #eip = uc.reg_read(UC_X86_REG_EIP) - #print(">>> EIP = 0x%x" %(eip)) + print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size)) + eip = uc.reg_read(UC_X86_REG_EFLAGS) + print(">>> --- EFLAGS is 0x%x" %(eip)) + +def hook_code64(uc, address, size, user_data): + print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size)) + rip = uc.reg_read(UC_X86_REG_RIP) + print(">>> RIP is 0x%x" %rip); # callback for tracing invalid memory access (READ or WRITE) @@ -128,21 +135,21 @@ def test_i386(): r_xmm0 = mu.reg_read(UC_X86_REG_XMM0) print(">>> ECX = 0x%x" %r_ecx) print(">>> EDX = 0x%x" %r_edx) - print(">>> XMM0 = 0x%x" %r_xmm0) + print(">>> XMM0 = 0x%.32x" %r_xmm0) # read from memory - tmp = mu.mem_read(ADDRESS, 2) - print(">>> Read 2 bytes from [0x%x] =" %(ADDRESS), end="") - for i in tmp: - print(" 0x%x" %i, end="") + tmp = mu.mem_read(ADDRESS, 4) + print(">>> Read 4 bytes from [0x%x] = 0x" %(ADDRESS), end="") + for i in reversed(tmp): + print("%x" %(i), end="") print("") except UcError as e: print("ERROR: %s" % e) -def test_i386_loop(): - print("Emulate i386 code with infinite loop - wait for 2 seconds then stop emulation") +def test_i386_map_ptr(): + print("Emulate i386 code - use uc_mem_map_ptr()") try: # Initialize emulator in X86-32bit mode mu = Uc(UC_ARCH_X86, UC_MODE_32) @@ -151,14 +158,20 @@ def test_i386_loop(): mu.mem_map(ADDRESS, 2 * 1024 * 1024) # write machine code to be emulated to memory - mu.mem_write(ADDRESS, X86_CODE32_LOOP) + 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) + # emulate machine code in infinite time - mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_LOOP), 2 * UC_SECOND_SCALE) + mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32), 2 * UC_SECOND_SCALE) # now print out some registers print(">>> Emulation done. Below is the CPU context") @@ -168,6 +181,13 @@ def test_i386_loop(): print(">>> ECX = 0x%x" %r_ecx) print(">>> EDX = 0x%x" %r_edx) + # read from memory + tmp = mu.mem_read(ADDRESS, 4) + print(">>> Read 4 bytes from [0x%x] = 0x" %(ADDRESS), end="") + for i in reversed(tmp): + print("%x" %(i), end="") + print("") + except UcError as e: print("ERROR: %s" % e) @@ -198,7 +218,7 @@ def test_i386_invalid_mem_read(): # emulate machine code in infinite time mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_MEM_READ)) except UcError as e: - print("ERROR: %s" % e) + print("Failed on uc_emu_start() with error returned 6: %s" % e) # now print out some registers print(">>> Emulation done. Below is the CPU context") @@ -211,6 +231,35 @@ def test_i386_invalid_mem_read(): except UcError as e: print("ERROR: %s" % e) +def test_i386_jump(): + print("Emulate i386 code with jump") + try: + # Initialize emulator in X86-32bit mode + mu = Uc(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_JUMP) + + # tracing all basic blocks with customized callback + mu.hook_add(UC_HOOK_BLOCK, hook_block, begin=ADDRESS, end=ADDRESS) + + # tracing all instructions with customized callback + mu.hook_add(UC_HOOK_CODE, hook_code, begin=ADDRESS, end=ADDRESS) + + try: + # emulate machine code in infinite time + mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_JUMP)) + except UcError as e: + print("ERROR: %s" % e) + + print(">>> Emulation done. Below is the CPU context") + + except UcError as e: + print("ERROR: %s" % e) + def test_i386_invalid_mem_write(): print("Emulate i386 code that write to invalid memory") @@ -229,10 +278,10 @@ def test_i386_invalid_mem_write(): mu.reg_write(UC_X86_REG_EDX, 0x7890) # tracing all basic blocks with customized callback - #mu.hook_add(UC_HOOK_BLOCK, hook_block) + 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_CODE, hook_code) # intercept invalid memory events mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_invalid) @@ -251,25 +300,92 @@ def test_i386_invalid_mem_write(): print(">>> ECX = 0x%x" %r_ecx) print(">>> EDX = 0x%x" %r_edx) + # read from memory + print(">>> Read 4 bytes from [0x%x] = 0x" %(0xaaaaaaaa), end="") + tmp = mu.mem_read(0xaaaaaaaa, 4) + for i in reversed(tmp): + if i != 0: + print("%x" %i, end="") + print("") + try: - # read from memory - print(">>> Read 4 bytes from [0x%x] = " %(0xaaaaaaaa), end="") - tmp = mu.mem_read(0xaaaaaaaa, 4) - for i in tmp: - print(" 0x%x" %i, end="") + tmp = mu.mem_read(0xffffffaa, 4) + print(">>> Read 4 bytes from [0x%x] = 0x" %(0xffffffaa), end="") + for i in reversed(tmp): + print("%x" %i, end="") print("") - print(">>> Read 4 bytes from [0x%x] = " %(0xffffffaa), end="") - tmp = mu.mem_read(0xffffffaa, 4) - for i in tmp: - print(" 0x%x" %i, end="") - print("") except UcError as e: - print("ERROR: %s" % e) + print(">>> Failed to read 4 bytes from [0xffffffaa]") except UcError as e: print("ERROR: %s" % e) +def test_i386_jump_invalid(): + print("Emulate i386 code that jumps to invalid memory") + try: + # Initialize emulator in X86-32bit mode + mu = Uc(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_JMP_INVALID) + + # 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) + + try: + mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_JMP_INVALID)) + except UcError as e: + print("Failed on uc_emu_start() with error returned 8: %s" %e) + + print(">>> 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) + print(">>> ECX = 0x%x" %r_ecx) + print(">>> EDX = 0x%x" %r_edx) + + except UcError as e: + print("ERROR %s" % e) + +def test_i386_loop(): + print("Emulate i386 code that loop forever") + try: + # Initialize emulator in X86-32bit mode + mu = Uc(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) + + mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_LOOP), timeout=2*UC_SECOND_SCALE) + + print(">>> 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) + print(">>> ECX = 0x%x" %r_ecx) + print(">>> EDX = 0x%x" %r_edx) + + + except UcError as e: + print("ERROR: %s" % e) # Test X86 32 bit with IN/OUT instruction def test_i386_inout(): @@ -397,7 +513,7 @@ def test_x86_64(): mu.hook_add(UC_HOOK_BLOCK, hook_block) # tracing all instructions in range [ADDRESS, ADDRESS+20] - mu.hook_add(UC_HOOK_CODE, hook_code, None, ADDRESS, ADDRESS+20) + mu.hook_add(UC_HOOK_CODE, hook_code64, None, ADDRESS, ADDRESS+20) # tracing all memory READ & WRITE access mu.hook_add(UC_HOOK_MEM_WRITE, hook_mem_access) @@ -429,23 +545,21 @@ def test_x86_64(): r14 = mu.reg_read(UC_X86_REG_R14) r15 = mu.reg_read(UC_X86_REG_R15) - print(">>> RAX = %x" %rax) - print(">>> RBX = %x" %rbx) - print(">>> RCX = %x" %rcx) - print(">>> RDX = %x" %rdx) - print(">>> RSI = %x" %rsi) - print(">>> RDI = %x" %rdi) - print(">>> R8 = %x" %r8) - print(">>> R9 = %x" %r9) - print(">>> R10 = %x" %r10) - print(">>> R11 = %x" %r11) - print(">>> R12 = %x" %r12) - print(">>> R13 = %x" %r13) - print(">>> R14 = %x" %r14) - print(">>> R15 = %x" %r15) + print(">>> RAX = 0x%x" %rax) + print(">>> RBX = 0x%x" %rbx) + print(">>> RCX = 0x%x" %rcx) + print(">>> RDX = 0x%x" %rdx) + print(">>> RSI = 0x%x" %rsi) + print(">>> RDI = 0x%x" %rdi) + print(">>> R8 = 0x%x" %r8) + print(">>> R9 = 0x%x" %r9) + print(">>> R10 = 0x%x" %r10) + print(">>> R11 = 0x%x" %r11) + print(">>> R12 = 0x%x" %r12) + print(">>> R13 = 0x%x" %r13) + print(">>> R14 = 0x%x" %r14) + print(">>> R15 = 0x%x" %r15) - #BUG - mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE64)) except UcError as e: print("ERROR: %s" % e) @@ -516,27 +630,29 @@ def test_x86_16(): print(">>> Emulation done. Below is the CPU context") tmp = mu.mem_read(11, 1) - print("[0x%x] = 0x%x" %(11, tmp[0])) + print(">>> Read 1 bytes from [0x%x] = 0x%x" %(11, tmp[0])) except UcError as e: print("ERROR: %s" % e) if __name__ == '__main__': - test_i386() - print("=" * 20) - test_i386_loop() - print("=" * 20) - test_i386_invalid_mem_read() - print("=" * 20) - test_i386_invalid_mem_write() - print("=" * 20) - test_i386_inout() - print("=" * 20) - test_i386_context_save() - print("=" * 20) - test_x86_64() - print("=" * 20) - test_x86_64_syscall() - print("=" * 20) test_x86_16() + test_i386() + print("=" * 35) + test_i386_map_ptr() + print("=" * 35) + test_i386_inout() + print("=" * 35) + test_i386_jump() + print("=" * 35) + test_i386_loop() + print("=" * 35) + test_i386_invalid_mem_read() + print("=" * 35) + test_i386_invalid_mem_write() + print("=" * 35) + test_i386_jump_invalid() + test_x86_64() + print("=" * 35) + test_x86_64_syscall() diff --git a/bindings/python/setup.py b/bindings/python/setup.py index 155b524a..aa7acb5a 100755 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -23,7 +23,7 @@ if os.path.exists(PATH_LIB64) and os.path.exists(PATH_LIB32): PKG_NAME = 'unicorn-windows' SYSTEM = sys.platform -VERSION = '1.0' +VERSION = '1.0.0' # adapted from commit e504b81 of Nguyen Tan Cong # Reference: https://docs.python.org/2/library/platform.html#cross-platform diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 1d3f584f..1bad25fa 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -63,7 +63,8 @@ _path_list = [pkg_resources.resource_filename(__name__, 'lib'), os.path.join(os.path.split(__file__)[0], 'lib'), '', distutils.sysconfig.get_python_lib(), - "/usr/local/lib/" if sys.platform == 'darwin' else '/usr/lib64'] + "/usr/local/lib/" if sys.platform == 'darwin' else '/usr/lib64', + os.environ['PATH']] for _path in _path_list: _uc = _load_lib(_path) @@ -105,7 +106,6 @@ _setup_prototype(_uc, "uc_context_alloc", ucerr, uc_engine, ctypes.POINTER(uc_co _setup_prototype(_uc, "uc_context_free", ucerr, uc_context) _setup_prototype(_uc, "uc_context_save", ucerr, uc_engine, uc_context) _setup_prototype(_uc, "uc_context_restore", ucerr, uc_engine, uc_context) -_setup_prototype(_uc, "free", None, ctypes.c_voidp) # uc_hook_add is special due to variable number of arguments _uc.uc_hook_add = _uc.uc_hook_add diff --git a/bindings/ruby/unicorn_gem/ext/unicorn.c b/bindings/ruby/unicorn_gem/ext/unicorn.c index c7979343..bd23086c 100644 --- a/bindings/ruby/unicorn_gem/ext/unicorn.c +++ b/bindings/ruby/unicorn_gem/ext/unicorn.c @@ -73,11 +73,11 @@ VALUE m_uc_emu_start(int argc, VALUE* argv, VALUE self){ 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(timeout)) + timeout = INT2NUM(0); - if (NIL_P(count)) - count = 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) { @@ -133,7 +133,7 @@ VALUE m_uc_reg_read(VALUE self, VALUE reg_id){ if (err != UC_ERR_OK) { rb_raise(UcError, "%s", uc_strerror(err)); } - return LL2NUM(reg_value); + return ULL2NUM(reg_value); } } @@ -165,7 +165,7 @@ VALUE m_uc_reg_write(VALUE self, VALUE reg_id, VALUE reg_value){ err = uc_reg_write(_uc, NUM2INT(reg_id), &tmp); break; } - + if (err != UC_ERR_OK) { rb_raise(UcError, "%s", uc_strerror(err)); } @@ -205,8 +205,8 @@ VALUE m_uc_mem_map(int argc, VALUE* argv, VALUE self){ 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); + 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) { @@ -332,14 +332,14 @@ VALUE m_uc_hook_add(int argc, VALUE* argv, VALUE self){ 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(begin)) + begin = ULL2NUM(1); - if (NIL_P(end)) - end = ULL2NUM(0); + if (NIL_P(end)) + end = ULL2NUM(0); - if (NIL_P(arg1)) - arg1 = INT2NUM(0); + if (NIL_P(arg1)) + arg1 = INT2NUM(0); VALUE passthrough; uc_hook trace; @@ -374,12 +374,12 @@ VALUE m_uc_hook_add(int argc, VALUE* argv, VALUE self){ 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 + 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 @@ -387,7 +387,7 @@ VALUE m_uc_hook_add(int argc, VALUE* argv, VALUE self){ || 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)); } diff --git a/make.sh b/make.sh index a41a7c8a..048df624 100755 --- a/make.sh +++ b/make.sh @@ -36,17 +36,6 @@ build_iOS() { ${MAKE} } -build() { - [ "$UNAME" = Darwin ] && LIBARCHS="i386 x86_64" - ${MAKE} -} - -build_macos_universal() { - [ "$UNAME" = Darwin ] && LIBARCHS="i386 x86_64" - MACOS_UNIVERSAL=yes \ - ${MAKE} -} - build_cross() { [ "$UNAME" = Darwin ] && LIBARCHS="i386 x86_64" CROSS=$1 @@ -112,17 +101,14 @@ fi export CC INSTALL_BIN PREFIX PKGCFGDIR LIBDIRARCH LIBARCHS CFLAGS LDFLAGS case "$1" in - "" ) build;; - "macos-universal" ) build_macos_universal;; + "" ) ${MAKE};; "asan" ) asan;; - "default" ) build;; "install" ) install;; "uninstall" ) uninstall;; + "macos-universal" ) MACOS_UNIVERSAL=yes ${MAKE};; "cross-win32" ) build_cross i686-w64-mingw32;; "cross-win64" ) build_cross x86_64-w64-mingw32;; - "cross-android" ) CROSS=arm-linux-androideabi build;; - "clang" ) CC=clang build;; - "gcc" ) CC=gcc build;; + "cross-android" ) CROSS=arm-linux-androideabi ${MAKE};; "ios" ) build_iOS;; "ios_armv7" ) build_iOS armv7;; "ios_armv7s" ) build_iOS armv7s;; diff --git a/samples/Makefile b/samples/Makefile index e32afc93..830cd68b 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -3,7 +3,6 @@ include ../config.mk -LIBNAME = unicorn UNAME_S := $(shell uname -s) # Find GLIB @@ -11,70 +10,34 @@ ifndef GLIB GLIB = $(shell pkg-config --libs glib-2.0) endif -UNICORN_DEP_LIBS_STATIC += -lpthread -lm $(GLIB) - # Verbose output? V ?= 0 -INCDIR = ../include -SAMPLEDIR = . -OBJDIR = . -LIBDIR = .. +CFLAGS += -Wall -Werror -I../include +LDFLAGS += -L.. +LDLIBS += -lpthread -lunicorn -lm $(GLIB) -CFLAGS += -Wall -Werror -I$(INCDIR) -LDFLAGS += -lpthread -L$(LIBDIR) -l$(LIBNAME) -LDFLAGS_STATIC += $(UNICORN_DEP_LIBS_STATIC) - -ifeq ($(CROSS),) -CC ?= cc -LDFLAGS += -lm $(GLIB) -else +ifneq ($(CROSS),) CC = $(CROSS)gcc endif ifeq ($(UNICORN_ASAN),yes) -CC = clang -fsanitize=address -fno-omit-frame-pointer -CXX = clang++ -fsanitize=address -fno-omit-frame-pointer +CC = clang +CXX = clang++ AR = llvm-ar -LDFLAGS := -fsanitize=address ${LDFLAGS} +CFLAGS += -fsanitize=address -fno-omit-frame-pointer endif - -#CFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch)) -#LDFLAGS += $(foreach arch,$(LIBARCHS),-arch $(arch)) - -BIN_EXT = -AR_EXT = a - # Cygwin? ifneq ($(filter CYGWIN%,$(UNAME_S)),) CFLAGS := $(CFLAGS:-fPIC=) -LDFLAGS += -lssp -LDFLAGS_STATIC += -lssp -BIN_EXT = .exe -AR_EXT = a +LDLIBS += -lssp # mingw? else ifneq ($(filter MINGW%,$(UNAME_S)),) CFLAGS := $(CFLAGS:-fPIC=) -BIN_EXT = .exe -AR_EXT = lib endif - -ifeq ($(UNICORN_STATIC),yes) -ifneq ($(filter MINGW%,$(UNAME_S)),) -ARCHIVE = $(LIBDIR)/$(LIBNAME).$(AR_EXT) -else ifneq ($(filter CYGWIN%,$(UNAME_S)),) -ARCHIVE = $(LIBDIR)/lib$(LIBNAME).$(AR_EXT) -else -ARCHIVE = $(LIBDIR)/lib$(LIBNAME).$(AR_EXT) -#ARCHIVE_X86 = $(LIBDIR)/lib$(LIBNAME)_x86.$(AR_EXT) -#ARCHIVE_ARM = $(LIBDIR)/lib$(LIBNAME)_arm.$(AR_EXT) -#ARCHIVE_ARM64 = $(LIBDIR)/lib$(LIBNAME)_arm64.$(AR_EXT) -endif -endif - -.PHONY: all clean clean_bins clean_libs +.PHONY: all clean UNICORN_ARCHS := $(shell if [ -e ../config.log ]; then cat ../config.log;\ else printf "$(UNICORN_ARCHS)"; fi) @@ -89,9 +52,9 @@ endif ifneq (,$(findstring mips,$(UNICORN_ARCHS))) SOURCES += sample_mips.c endif -ifneq (,$(findstring ppc,$(UNICORN_ARCHS))) +#ifneq (,$(findstring ppc,$(UNICORN_ARCHS))) #SOURCES += sample_ppc.c -endif +#endif ifneq (,$(findstring sparc,$(UNICORN_ARCHS))) SOURCES += sample_sparc.c endif @@ -106,73 +69,9 @@ ifneq (,$(findstring m68k,$(UNICORN_ARCHS))) SOURCES += sample_m68k.c endif -OBJS = $(addprefix $(OBJDIR)/,$(SOURCES:.c=.o)) -OBJS_ELF = $(addprefix $(OBJDIR)/,$(SOURCES:.c=)) -BINARY = $(addprefix $(SAMPLEDIR)/,$(SOURCES:.c=$(BIN_EXT))) +BINS = $(SOURCES:.c=) -all: $(BINARY) +all: $(BINS) -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 - -clean: clean_bins clean_libs - -$(BINARY): $(OBJS) - -$(SAMPLEDIR)/%$(BIN_EXT): $(OBJDIR)/%.o - @mkdir -p $(@D) -ifeq ($(V),0) -ifeq ($(UNICORN_SHARED),yes) - $(call log,LINK,$(notdir $@)) - @$(link-dynamic) -endif -ifeq ($(UNICORN_STATIC),yes) -ifneq ($(filter MINGW%,$(UNAME_S)),) - $(call log,LINK,$(notdir $(call staticname,$@))) - @$(link-static) -endif -endif -else -ifeq ($(UNICORN_SHARED),yes) - $(link-dynamic) -endif -ifeq ($(UNICORN_STATIC),yes) -ifneq ($(filter MINGW%,$(UNAME_S)),) - $(link-static) -endif -endif -endif - -$(OBJDIR)/%.o: %.c - @mkdir -p $(@D) -ifeq ($(V),0) - $(call log,CC,$(@:$(OBJDIR)/%=%)) - @$(compile) -else - $(compile) -endif - - -define link-dynamic - $(CC) $< $(LDFLAGS) -o $@ -endef - - -define link-static - $(CC) $< $(ARCHIVE) $(LDFLAGS_STATIC) -o $(call staticname,$@) -endef - - -staticname = $(subst $(BIN_EXT),,$(1)).static$(BIN_EXT) - -define log - @printf " %-7s %s\n" "$(1)" "$(2)" -endef - -define compile - ${CC} ${CFLAGS} -c $< -o $@ -endef +clean: + rm -rf *.o $(BINS) diff --git a/samples/sample_x86.c b/samples/sample_x86.c index 2e1d73ec..4c5da3e3 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -41,6 +41,7 @@ #define X86_CODE32_JMP_INVALID "\xe9\xe9\xee\xee\xee\x41\x4a" // JMP outside; INC ecx; DEC edx #define X86_CODE32_INOUT "\x41\xE4\x3F\x4a\xE6\x46\x43" // INC ecx; IN AL, 0x3f; DEC edx; OUT 0x46, AL; INC ebx +#define X86_CODE32_INC "\x40" // INC eax //#define X86_CODE64 "\x41\xBC\x3B\xB0\x28\x2A \x49\x0F\xC9 \x90 \x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9" // <== still crash //#define X86_CODE64 "\x41\xBC\x3B\xB0\x28\x2A\x49\x0F\xC9\x90\x4D\x0F\xAD\xCF\x49\x87\xFD\x90\x48\x81\xD2\x8A\xCE\x77\x35\x48\xF7\xD9" @@ -668,6 +669,105 @@ static void test_i386_inout(void) uc_close(uc); } +// emulate code and save/restore the CPU context +static void test_i386_context_save(void) +{ + uc_engine *uc; + uc_context *context; + uc_err err; + + int r_eax = 0x1; // EAX register + + printf("===================================\n"); + printf("Save/restore CPU context in opaque blob\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 8KB memory for this emulation + uc_mem_map(uc, ADDRESS, 8 * 1024, UC_PROT_ALL); + + // write machine code to be emulated to memory + if (uc_mem_write(uc, ADDRESS, X86_CODE32_INC, sizeof(X86_CODE32_INC) - 1)) { + printf("Failed to write emulation code to memory, quit!\n"); + return; + } + + // initialize machine registers + uc_reg_write(uc, UC_X86_REG_EAX, &r_eax); + + // emulate machine code in infinite time + printf(">>> Running emulation for the first time\n"); + + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_INC) - 1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned %u: %s\n", + err, uc_strerror(err)); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); + printf(">>> EAX = 0x%x\n", r_eax); + + // allocate and save the CPU context + printf(">>> Saving CPU context\n"); + + err = uc_context_alloc(uc, &context); + if (err) { + printf("Failed on uc_context_alloc() with error returned: %u\n", err); + return; + } + + err = uc_context_save(uc, context); + if (err) { + printf("Failed on uc_context_save() with error returned: %u\n", err); + return; + } + + // emulate machine code again + printf(">>> Running emulation for the second time\n"); + + err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_INC) - 1, 0, 0); + if (err) { + printf("Failed on uc_emu_start() with error returned %u: %s\n", + err, uc_strerror(err)); + } + + // now print out some registers + printf(">>> Emulation done. Below is the CPU context\n"); + + uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); + printf(">>> EAX = 0x%x\n", r_eax); + + // restore CPU context + err = uc_context_restore(uc, context); + if (err) { + printf("Failed on uc_context_restore() with error returned: %u\n", err); + return; + } + + // now print out some registers + printf(">>> CPU context restored. Below is the CPU context\n"); + + uc_reg_read(uc, UC_X86_REG_EAX, &r_eax); + printf(">>> EAX = 0x%x\n", r_eax); + + // free the CPU context + err = uc_context_free(context); + if (err) { + printf("Failed on uc_context_free() with error returned: %u\n", err); + return; + } + + uc_close(uc); +} + static void test_x86_64(void) { uc_engine *uc; @@ -906,6 +1006,7 @@ int main(int argc, char **argv, char **envp) test_i386(); test_i386_map_ptr(); test_i386_inout(); + test_i386_context_save(); test_i386_jump(); test_i386_loop(); test_i386_invalid_mem_read(); diff --git a/samples/sample_x86_32_gdt_and_seg_regs.c b/samples/sample_x86_32_gdt_and_seg_regs.c index c3531619..7e1e260b 100644 --- a/samples/sample_x86_32_gdt_and_seg_regs.c +++ b/samples/sample_x86_32_gdt_and_seg_regs.c @@ -269,7 +269,7 @@ static void gdt_demo() int i; for (i = 0; i < 8; i++) { - fprintf(stderr, "%02hhx", buf[i]); + fprintf(stderr, "%02x", buf[i]); } fprintf(stderr, "\n"); diff --git a/tests/unit/Makefile b/tests/unit/Makefile index ebf8eb30..0768210a 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile @@ -1,11 +1,9 @@ - CFLAGS += -Wall -Werror -Wno-unused-function -g -CFLAGS += -L ../../ -CFLAGS += -I ../../include +CFLAGS += -L ../../ -I ../../include CFLAGS += -L ../../cmocka/src -I ../../cmocka/include -EXECUTE_VARS = LD_LIBRARY_PATH=../../cmocka/src:../../ DYLD_LIBRARY_PATH=../../ +LDLIBS += -lcmocka -lunicorn -LIBS += -lcmocka -lunicorn +EXECUTE_VARS = LD_LIBRARY_PATH=../../cmocka/src:../../ DYLD_LIBRARY_PATH=../../ ifeq ($(UNICORN_ASAN),yes) CC = clang -fsanitize=address -fno-omit-frame-pointer @@ -14,9 +12,8 @@ AR = llvm-ar LDFLAGS := -fsanitize=address ${LDFLAGS} endif -ALL_TESTS = test_sanity test_x86 test_mem_map test_mem_high test_mem_map_ptr \ - test_tb_x86 test_multihook test_pc_change test_x86_soft_paging \ - test_hookcounts test_hang test_x86_shl_enter_leave test_x86_rip_bug +ALL_TESTS_SOURCES = $(wildcard *.c) +ALL_TESTS = $(ALL_TESTS_SOURCES:%.c=%) .PHONY: all all: ${ALL_TESTS} @@ -32,28 +29,11 @@ test: ${ALL_TESTS} ${EXECUTE_VARS} ./test_mem_map ${EXECUTE_VARS} ./test_mem_map_ptr ${EXECUTE_VARS} ./test_mem_high - echo "skipping test_tb_x86" #${EXECUTE_VARS} ./test_tb_x86 ${EXECUTE_VARS} ./test_multihook ${EXECUTE_VARS} ./test_pc_change - echo "skipping test_x86_soft_paging" #${EXECUTE_VARS} ./test_x86_soft_paging ${EXECUTE_VARS} ./test_hookcounts - echo "skipping test_hang" #${EXECUTE_VARS} ./test_hang - echo "skipping test_x86_sh1_enter_leave" #${EXECUTE_VARS} ./test_x86_shl_enter_leave - echo "skipping test_x86_rip_bug" #${EXECUTE_VARS} ./test_x86_rip_bug - -test_sanity: test_sanity.c -test_x86: test_x86.c -test_mem_map: test_mem_map.c -test_mem_map_ptr: test_mem_map_ptr.c -test_mem_high: test_mem_high.c -test_tb_x86: test_tb_x86.c -test_multihook: test_multihook.c -test_pc_change: test_pc_change.c -test_x86_soft_paging: test_x86_soft_paging.c -test_hookcounts: test_hookcounts.c -test_hang: test_hang.c -test_x86_shl_enter_leave: test_x86_shl_enter_leave.c -test_x86_rip_bug: test_x86_rip_bug.c - -${ALL_TESTS}: - ${CC} ${CFLAGS} -o $@ $^ ${LIBS} + echo "skipping test_tb_x86" + echo "skipping test_x86_soft_paging" + echo "skipping test_hang" + echo "skipping test_x86_sh1_enter_leave" + echo "skipping test_x86_rip_bug" diff --git a/uc.c b/uc.c index 23f672da..10ebdb6a 100644 --- a/uc.c +++ b/uc.c @@ -1,9 +1,6 @@ /* Unicorn Emulator Engine */ /* By Nguyen Anh Quynh , 2015 */ -#if defined (WIN32) || defined (WIN64) || defined (_WIN32) || defined (_WIN64) -#pragma warning(disable:4996) -#endif #if defined(UNICORN_HAS_OSXKERNEL) #include #else @@ -1162,12 +1159,24 @@ static size_t cpu_context_size(uc_arch arch, uc_mode mode) // tbl_table is the first entry in the CPU_COMMON macro, so it marks the end // of the interesting CPU registers switch (arch) { +#ifdef UNICORN_HAS_M68K case UC_ARCH_M68K: return M68K_REGS_STORAGE_SIZE; +#endif +#ifdef UNICORN_HAS_X86 case UC_ARCH_X86: return X86_REGS_STORAGE_SIZE; +#endif +#ifdef UNICORN_HAS_ARM case UC_ARCH_ARM: return ARM_REGS_STORAGE_SIZE; +#endif +#ifdef UNICORN_HAS_ARM64 case UC_ARCH_ARM64: return ARM64_REGS_STORAGE_SIZE; +#endif +#ifdef UNICORN_HAS_MIPS case UC_ARCH_MIPS: return mode & UC_MODE_MIPS64 ? MIPS64_REGS_STORAGE_SIZE : MIPS_REGS_STORAGE_SIZE; +#endif +#ifdef UNICORN_HAS_SPARC case UC_ARCH_SPARC: return mode & UC_MODE_SPARC64 ? SPARC64_REGS_STORAGE_SIZE : SPARC_REGS_STORAGE_SIZE; +#endif default: return 0; } } From 9f0cdc4be9542bb34fd7133547ade50895e2a972 Mon Sep 17 00:00:00 2001 From: Stephen Date: Mon, 7 Nov 2016 10:52:05 -0800 Subject: [PATCH 02/16] Update .travis.yml Update eflags_nosync.c Update sigill2.c Update ro_mem_test.c Update ro_mem_test.c Update nr_mem_test.c Update mem_fuzz.c Update mem_double_unmap.c Update emu_stop_in_hook_overrun.c Update eflags_nosync.c remove unused Update Makefile Update Makefile Update Makefile Update Makefile Update Makefile Update Makefile Update Makefile Update mem_64_c.c Update mem_64_c.c Update Makefile Update Makefile Update Makefile Update Makefile Update Makefile Update Makefile Update .travis.yml try android ndk build Update unicorn.py Update unicorn.py Update Makefile Update unicorn.py Update unicorn.py remove an untrue comment if a dll/so/dylib gets loaded at runtime is dependent on many different factors, primarily the LD/DYLD paths. Those do not always include the current working directory Update Makefile Update .appveyor.yml Update .travis.yml Update Makefile Update .appveyor.yml Fix bad sample --- .appveyor.yml | 34 +++++++------ .travis.yml | 6 +-- Makefile | 19 ++++--- bindings/Makefile | 53 +++++++------------- bindings/go/Makefile | 10 ++-- bindings/go/unicorn/unicorn.go | 4 +- bindings/python/sample_x86.py | 35 +++++-------- bindings/python/shellcode.py | 2 +- bindings/python/unicorn/unicorn.py | 13 +++-- bindings/ruby/Makefile | 4 +- install-cmocka-linux.sh | 8 ++- samples/sample_x86.c | 34 ++++++++----- samples/shellcode.c | 7 ++- tests/regress/Makefile | 63 +++--------------------- tests/regress/block_test.c | 2 +- tests/regress/eflags_nosync.c | 3 +- tests/regress/emu_stop_in_hook_overrun.c | 1 - tests/regress/mem_64_c.c | 5 +- tests/regress/mem_double_unmap.c | 1 - tests/regress/mem_fuzz.c | 1 - tests/regress/mem_map_large.c | 2 +- tests/regress/nr_mem_test.c | 2 +- tests/regress/ro_mem_test.c | 6 +-- tests/regress/sigill2.c | 1 - 24 files changed, 126 insertions(+), 190 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 03d5d411..6a699bb0 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,21 +1,23 @@ # Appveyor configuration file for CI build of Unicorn Engine on Windows (under Cygwin) environment: + CYG_MIRROR: http://cygwin.mirror.constant.com matrix: + - MSYSTEM: MINGW64 + BASH: C:\msys64\usr\bin\bash + CC: x86_64-w64-mingw32-gcc + - MSYSTEM: MINGW32 + BASH: C:\msys64\usr\bin\bash + CC: i686-w64-mingw32-gcc - CYG_ROOT: C:\cygwin64 - CYG_SETUP: setup-x86_64.exe - CYG_MIRROR: http://cygwin.mirror.constant.com CYG_CACHE: C:\cygwin64\var\cache\setup - CYG_BASH: C:\cygwin64\bin\bash + CYG_SETUP: setup-x86_64.exe + BASH: C:\cygwin64\bin\bash CC: gcc - CYG_ROOT: C:\cygwin - CYG_SETUP: setup-x86.exe - CYG_MIRROR: http://cygwin.mirror.constant.com CYG_CACHE: C:\cygwin\var\cache\setup - CYG_BASH: C:\cygwin\bin\bash + CYG_SETUP: setup-x86.exe + BASH: C:\cygwin\bin\bash CC: gcc -# - MSYS_ROOT: C:\msys64 -# MSYS_BASH: C:\msys64\mingw64\bin\sh -# CC: x86_64-w64-mingw32-gcc # Cache Cygwin files to speed up build cache: @@ -30,12 +32,13 @@ init: # Install needed build dependencies install: - - ps: 'if ($env:CYG_ROOT) { Start-FileDownload "http://cygwin.com/$env:CYG_SETUP" -FileName "$env:CYG_SETUP" }' - - if defined CYG_ROOT (%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages make,gcc-core,clang,pkg-config,libpcre-devel,libglib2.0-devel,cmake,python-setuptools --upgrade-also) - - if defined MSYS_ROOT (%MSYS_BASH% -lc "pacman -S --noconfirm mingw-w64-x86_64-glib2") + - ps: if (Test-Path Env:\CYG_ROOT) { Start-FileDownload "http://cygwin.com/$env:CYG_SETUP" -FileName "$env:CYG_SETUP" } + - if defined CYG_ROOT (%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages make,gcc-core,clang,pkg-config,libpcre-devel,libglib2.0-devel,cmake,python-setuptools,ruby,mingw64-i686-gcc-core,mingw64-x86_64-gcc-core --upgrade-also) + - if defined MSYSTEM (%BASH% -lc "pacman -Sy --noconfirm mingw-w64-x86_64-glib2 mingw-w64-i686-glib2 cmake") build_script: - - if defined CYG_ROOT (%CYG_BASH% -lc "export CYGWIN=winsymlinks:native; cd $APPVEYOR_BUILD_FOLDER; ./install-cmocka-linux.sh; make; export PATH=$PATH:../../:../../cmocka/src:../:../cmocka/src; make test") - - if defined MSYS_ROOT (%MSYS_BASH% -lc "MSYS=winsymlinks, cd $(cygpath ${APPVEYOR_BUILD_FOLDER}); x86_64-w64-mingw32-gcc --version; ./install-cmocka-linux.sh; make") + - if defined BASH (%BASH% -lc "cd $(cygpath ${APPVEYOR_BUILD_FOLDER}); ./install-cmocka-linux.sh; make;") + - if "%MSYSTEM%" == "MINGW64" (%BASH% -lc "cd $(cygpath ${APPVEYOR_BUILD_FOLDER}); make -C bindings/go") + # make test #- 'cd %APPVEYOR_BUILD_FOLDER% && cd bindings\dotnet && msbuild UnicornDotNet.sln' # Allows RDP #on_finish: @@ -43,4 +46,5 @@ build_script: # Disable tests for now # -test: off +test_script: + - if defined CYG_ROOT (%BASH% -lc "export CYGWIN=winsymlinks:native; cd $APPVEYOR_BUILD_FOLDER; export PATH=$PATH:$APPVEYOR_BUILD_FOLDER:$APPVEYOR_BUILD_FOLDER/cmocka/src; make test") diff --git a/.travis.yml b/.travis.yml index 75139721..543cbb42 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,9 +6,7 @@ before_install: - if [[ "$TRAVIS_OS_NAME" == "osx" && "$MACOS_UNIVERSAL" == "yes" ]]; then brew install glib --universal cmocka; fi - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ./install-cmocka-linux.sh; fi script: - - make && make test -# TODO make bindings enabled -# - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then make clean && ./make.sh ios; fi + - make && make -C bindings/go && make -C bindings/go test && make test compiler: - clang - gcc @@ -23,8 +21,6 @@ matrix: - os: osx compiler: gcc env: MACOS_UNIVERSAL=yes -# - os: osx -# compiler: x86_64-w64-mingw32-gcc addons: apt: packages: diff --git a/Makefile b/Makefile index 2f828d35..e9c04294 100644 --- a/Makefile +++ b/Makefile @@ -10,8 +10,7 @@ include pkgconfig.mk # package version LIBNAME = unicorn UNAME_S := $(shell uname -s) -GENOBJ = $(shell find qemu/$(1) -name "*.o" 2>/dev/null) $(wildcard qemu/util/*.o) $(wildcard qemu/*.o) $(wildcard qemu/qom/*.o)\ - $(wildcard qemu/hw/core/*.o) $(wildcard qemu/qapi/*.o) $(wildcard qemu/qobject/*.o) +GENOBJ = $(shell find qemu/$(1) -name "*.o" 2>/dev/null) ifneq (,$(findstring x86,$(UNICORN_ARCHS))) UC_TARGET_OBJ += $(call GENOBJ,x86_64-softmmu) @@ -196,6 +195,8 @@ else PKGCFGDIR ?= $(LIBDATADIR)/pkgconfig endif +$(LIBNAME)_LDFLAGS += $(GLIB) -lm + .PHONY: all all: unicorn $(MAKE) -C samples @@ -210,15 +211,16 @@ qemu/config-host.h-timestamp: compile_lib: config qemu/config-host.h-timestamp $(MAKE) -C qemu -j 4 + $(eval UC_TARGET_OBJ += $$(wildcard qemu/util/*.o) $$(wildcard qemu/*.o) $$(wildcard qemu/qom/*.o) $$(wildcard qemu/hw/core/*.o) $$(wildcard qemu/qapi/*.o) $$(wildcard qemu/qobject/*.o)) -unicorn: compile_lib $(LIBRARY) $(ARCHIVE) +unicorn: $(LIBRARY) $(ARCHIVE) -$(LIBRARY): $(UC_TARGET_OBJ) - $(CC) $(CFLAGS) -shared $(GENOBJ) uc.o list.o -o $(LIBRARY) $(GLIB) -lm $($(LIBNAME)_LDFLAGS) - ln -sf $(LIBRARY) $(LIBRARY_SYMLINK) +$(LIBRARY): compile_lib uc.o list.o + $(CC) $(CFLAGS) -shared $(UC_TARGET_OBJ) uc.o list.o -o $(LIBRARY) $($(LIBNAME)_LDFLAGS) + -ln -sf $(LIBRARY) $(LIBRARY_SYMLINK) -$(ARCHIVE): $(UC_TARGET_OBJ) uc.o list.o - $(AR) q $(ARCHIVE) $^ +$(ARCHIVE): compile_lib uc.o list.o + $(AR) q $(ARCHIVE) $(UC_TARGET_OBJ) uc.o list.o $(RANLIB) $(ARCHIVE) @@ -228,6 +230,7 @@ $(PKGCFGF): .PHONY: test test: all $(MAKE) -C tests/unit test + $(MAKE) -C tests/regress test $(MAKE) -C bindings test install: compile_lib $(PKGCFGF) diff --git a/bindings/Makefile b/bindings/Makefile index 7ded2e10..ed958f75 100644 --- a/bindings/Makefile +++ b/bindings/Makefile @@ -1,19 +1,17 @@ # Unicorn Engine # By Nguyen Anh Quynh & Dang Hoang Vu, 2015 -TMP_DIR = /tmp/unicorn_sample +DIFF = diff -DIFF = diff -u -w - -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 +SAMPLE_SOURCE = $(wildcard ../samples/*.c) +SAMPLE = $(SAMPLE_SOURCE:../samples/%.c=%) +SAMPLE := $(SAMPLE:mem_apis=) +SAMPLE := $(SAMPLE:sample_batch_reg=) +SAMPLE := $(SAMPLE:sample_x86_32_gdt_and_seg_regs=) +SAMPLE := $(SAMPLE:shellcode=) ENV_VARS = LD_LIBRARY_PATH=../ DYLD_LIBRARY_PATH=../ -.PHONY: build install expected python sample_diff clean check test +.PHONY: build install python c clean check test build: $(MAKE) -C python gen_const @@ -26,39 +24,22 @@ install: build $(MAKE) -C python install $(MAKE) -C java install -test: expected python sample_diff +test: $(SAMPLE:%=%.py.test) -expected: +c: $(MAKE) -C ../samples - mkdir -p $(TMP_DIR) - $(ENV_VARS) ../samples/sample_arm > $(SAMPLE_ARM)_e - $(ENV_VARS) ../samples/sample_arm64 > $(SAMPLE_ARM64)_e - $(ENV_VARS) ../samples/sample_mips > $(SAMPLE_MIPS)_e - $(ENV_VARS) ../samples/sample_sparc > $(SAMPLE_SPARC)_e - $(ENV_VARS) ../samples/sample_m68k > $(SAMPLE_M68K)_e - $(ENV_VARS) ../samples/sample_x86 -16 > $(SAMPLE_X86)_e - $(ENV_VARS) ../samples/sample_x86 -32 >> $(SAMPLE_X86)_e - $(ENV_VARS) ../samples/sample_x86 -64 >> $(SAMPLE_X86)_e - python: $(MAKE) -C python - $(ENV_VARS) python python/sample_arm.py > $(SAMPLE_ARM)_o - $(ENV_VARS) python python/sample_arm64.py > $(SAMPLE_ARM64)_o - $(ENV_VARS) python python/sample_mips.py > $(SAMPLE_MIPS)_o - $(ENV_VARS) python python/sample_sparc.py > $(SAMPLE_SPARC)_o - $(ENV_VARS) python python/sample_m68k.py > $(SAMPLE_M68K)_o - $(ENV_VARS) python python/sample_x86.py > $(SAMPLE_X86)_o +%.c.txt: c + $(ENV_VARS) ../samples/$(@:%.c.txt=%) > $@ +%.py.txt: python + $(ENV_VARS) python python/$(@:%.txt=%) > $@ -sample_diff: - $(DIFF) $(SAMPLE_ARM)_e $(SAMPLE_ARM)_o - $(DIFF) $(SAMPLE_ARM64)_e $(SAMPLE_ARM64)_o - $(DIFF) $(SAMPLE_MIPS)_e $(SAMPLE_MIPS)_o - $(DIFF) $(SAMPLE_SPARC)_e $(SAMPLE_SPARC)_o - $(DIFF) $(SAMPLE_M68K)_e $(SAMPLE_M68K)_o - $(DIFF) $(SAMPLE_X86)_e $(SAMPLE_X86)_o +%.py.test: %.c.txt %.py.txt + $(DIFF) $(@:%.py.test=%.c.txt) $(@:%.py.test=%.py.txt) clean: - rm -rf $(TMP_DIR) +# rm -rf *.txt $(MAKE) -C python clean $(MAKE) -C java clean diff --git a/bindings/go/Makefile b/bindings/go/Makefile index 17e450c2..fe898ae1 100644 --- a/bindings/go/Makefile +++ b/bindings/go/Makefile @@ -1,14 +1,12 @@ # Go binding for Unicorn engine. Ryan Hileman -.PHONY: gen_const test +.PHONY: all gen_const test -all: - $(MAKE) gen_const +all: gen_const cd unicorn && go build - $(MAKE) test gen_const: cd .. && python const_generator.py go -test: - cd unicorn && go test +test: all + cd unicorn && LD_LIBRARY_PATH=../../../ DYLD_LIBRARY_PATH=../../../ go test diff --git a/bindings/go/unicorn/unicorn.go b/bindings/go/unicorn/unicorn.go index 58e28939..6ac3ecce 100644 --- a/bindings/go/unicorn/unicorn.go +++ b/bindings/go/unicorn/unicorn.go @@ -7,8 +7,8 @@ import ( ) /* -#cgo CFLAGS: -O3 -#cgo LDFLAGS: -lunicorn +#cgo CFLAGS: -O3 -Wall -Werror -I../../../include +#cgo LDFLAGS: -L../../../ -lunicorn -lglib-2.0 #include #include "uc.h" */ diff --git a/bindings/python/sample_x86.py b/bindings/python/sample_x86.py index 981a6d5e..a6a54615 100755 --- a/bindings/python/sample_x86.py +++ b/bindings/python/sample_x86.py @@ -442,38 +442,25 @@ def test_i386_context_save(): # write machine code to be emulated to memory mu.mem_write(address, code) - print(">>> set eax to 1") + # set eax to 1 mu.reg_write(UC_X86_REG_EAX, 1) - print(">>> execute 'inc eax'") + print(">>> Running emulation for the first time") mu.emu_start(address, address+1) - print(">>> save the CPU context") + print(">>> Emulation done. Below is the CPU context") + print(">>> EAX = 0x%x" %(mu.reg_read(UC_X86_REG_EAX))) + print(">>> Saving CPU context") saved_context = mu.context_save() - print(">>> execute 'inc eax'") + print(">>> Running emulation for the second time") mu.emu_start(address, address+1) + print(">>> Emulation done. Below is the CPU context") + print(">>> EAX = 0x%x" %(mu.reg_read(UC_X86_REG_EAX))) - print(">>> assert eax == 3") - assert mu.reg_read(UC_X86_REG_EAX) == 3 - - print(">>> restore the CPU context") + print(">>> CPU context restored. Below is the CPU context") mu.context_restore(saved_context) - - print(">>> assert eax == 2") - assert mu.reg_read(UC_X86_REG_EAX) == 2 - - print(">>> execute 'inc eax'") - mu.emu_start(address, address+1) - - print(">>> assert eax == 3") - assert mu.reg_read(UC_X86_REG_EAX) == 3 - - print(">>> restore the CPU context") - mu.context_restore(saved_context) - - print(">>> assert eax == 2") - assert mu.reg_read(UC_X86_REG_EAX) == 2 + print(">>> EAX = 0x%x" %(mu.reg_read(UC_X86_REG_EAX))) except UcError as e: print("ERROR: %s" % e) @@ -644,6 +631,8 @@ if __name__ == '__main__': print("=" * 35) test_i386_inout() print("=" * 35) + test_i386_context_save() + print("=" * 35) test_i386_jump() print("=" * 35) test_i386_loop() diff --git a/bindings/python/shellcode.py b/bindings/python/shellcode.py index 898ada7b..ed65effa 100755 --- a/bindings/python/shellcode.py +++ b/bindings/python/shellcode.py @@ -21,7 +21,7 @@ def hook_code(uc, address, size, user_data): print(">>> Tracing instruction at 0x%x, instruction size = 0x%x" %(address, size)) # read this instruction code from memory tmp = uc.mem_read(address, size) - print(">>> Instruction code at [0x%x] =" %(address), end="") + print("*** EIP = %x *** :" %(address), end="") for i in tmp: print(" %02x" %i, end="") print("") diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index 1bad25fa..45056726 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -17,12 +17,11 @@ _python2 = sys.version_info[0] < 3 if _python2: range = xrange -if sys.platform == 'darwin': - _lib = "libunicorn.dylib" -elif sys.platform in ('win32', 'cygwin'): - _lib = "unicorn.dll" -else: - _lib = "libunicorn.so" +_lib = { 'darwin': 'libunicorn.dylib', + 'win32': 'unicorn.dll', + 'cygwin': 'cygunicorn.dll', + 'linux': 'libunicorn.so', + 'linux2': 'libunicorn.so' } # Windows DLL in dependency order _all_windows_dlls = ( @@ -45,7 +44,7 @@ def _load_lib(path): if sys.platform in ('win32', 'cygwin'): _load_win_support(path) - lib_file = os.path.join(path, _lib) + lib_file = os.path.join(path, _lib[sys.platform]) return ctypes.cdll.LoadLibrary(lib_file) except OSError: return None diff --git a/bindings/ruby/Makefile b/bindings/ruby/Makefile index 6e801fc6..6fa1faf3 100644 --- a/bindings/ruby/Makefile +++ b/bindings/ruby/Makefile @@ -2,8 +2,8 @@ .PHONY: gen_const -install: - $(MAKE) gen_const +# Use bundle install && rake to install gem and test +install: gen_const cd unicorn_gem && rake build cd unicorn_gem && gem install --local pkg/unicorn-0.9.0.gem diff --git a/install-cmocka-linux.sh b/install-cmocka-linux.sh index feb9bd36..86b5df11 100755 --- a/install-cmocka-linux.sh +++ b/install-cmocka-linux.sh @@ -1,8 +1,12 @@ -#!/bin/sh +#!/bin/bash set -ex mkdir cmocka wget https://cmocka.org/files/1.1/cmocka-1.1.0.tar.xz -O /tmp/cmocka-1.1.0.tar.xz -tar -xf /tmp/cmocka-1.1.0.tar.xz -C /tmp +tar -xvf /tmp/cmocka-1.1.0.tar.xz -C /tmp +if [ "$(expr substr $(uname -s) 1 5)" == "MINGW" ] ; then +cd cmocka && which cmake && cmake -G "MinGW Makefiles" /tmp/cmocka-1.1.0 && make +else cd cmocka && cmake /tmp/cmocka-1.1.0 && make +fi #cmocka does not include headers in build cp -R /tmp/cmocka-1.1.0/include/ . diff --git a/samples/sample_x86.c b/samples/sample_x86.c index 4c5da3e3..12af8372 100644 --- a/samples/sample_x86.c +++ b/samples/sample_x86.c @@ -996,13 +996,15 @@ int main(int argc, char **argv, char **envp) 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 - if (argc == 2) { - if (!strcmp(argv[1], "-32")) { + if (argc == 2) { + if (!strcmp(argv[1], "-16")) { + test_x86_16(); + } + else if (!strcmp(argv[1], "-32")) { test_i386(); test_i386_map_ptr(); test_i386_inout(); @@ -1013,19 +1015,29 @@ int main(int argc, char **argv, char **envp) test_i386_invalid_mem_write(); test_i386_jump_invalid(); } - - if (!strcmp(argv[1], "-64")) { + else if (!strcmp(argv[1], "-64")) { test_x86_64(); test_x86_64_syscall(); } - - if (!strcmp(argv[1], "-16")) { - test_x86_16(); + else if (!strcmp(argv[1], "-h")) { + printf("Syntax: %s <-16|-32|-64>\n", argv[0]); } - } else { - printf("Syntax: %s <-16|-32|-64>\n", argv[0]); - } + } + else { + test_x86_16(); + test_i386(); + test_i386_map_ptr(); + test_i386_inout(); + test_i386_context_save(); + test_i386_jump(); + test_i386_loop(); + test_i386_invalid_mem_read(); + test_i386_invalid_mem_write(); + test_i386_jump_invalid(); + test_x86_64(); + test_x86_64_syscall(); + } // dynamically free shared library #ifdef DYNLOAD uc_dyn_free(); diff --git a/samples/shellcode.c b/samples/shellcode.c index 8ad0c69b..ee706a6e 100644 --- a/samples/shellcode.c +++ b/samples/shellcode.c @@ -168,12 +168,15 @@ int main(int argc, char **argv, char **envp) } #endif - if (argc == 2) { + if (argc == 2) { if (!strcmp(argv[1], "-32")) { test_i386(); } + else if (!strcmp(argv[1], "-h")) { + printf("Syntax: %s <-32|-64>\n", argv[0]); + } } else { - printf("Syntax: %s <-32|-64>\n", argv[0]); + test_i386(); } // dynamically free shared library diff --git a/tests/regress/Makefile b/tests/regress/Makefile index 532f6da0..f9ff4a8b 100644 --- a/tests/regress/Makefile +++ b/tests/regress/Makefile @@ -1,65 +1,16 @@ +CFLAGS += -Wall -Werror -I../../include +LDLIBS += -L../../ $(shell pkg-config --libs glib-2.0) -lpthread -lm -lunicorn -CFLAGS += -I../../include +EXECUTE_VARS = LD_LIBRARY_PATH=../../cmocka/src:../../ DYLD_LIBRARY_PATH=../../ -ifeq (MING,$(findstring MING,$(shell uname -s))) -LDFLAGS += ../../unicorn.lib $(shell pkg-config --libs glib-2.0) -lpthread -lm -else -LDFLAGS += ../../libunicorn.a $(shell pkg-config --libs glib-2.0) -lpthread -lm -endif +TESTS_SOURCE = $(wildcard *.c) +TESTS = $(TESTS_SOURCE:%.c=%) -TESTS = map_crash map_write -TESTS += sigill sigill2 -TESTS += block_test -TESTS += ro_mem_test nr_mem_test -TESTS += timeout_segfault -TESTS += rep_movsb -TESTS += mem_unmap -TESTS += mem_double_unmap -TESTS += mem_protect -TESTS += mem_exec -TESTS += mips_kseg0_1 -TESTS += eflags_nosync -TESTS += 00opcode_uc_crash -TESTS += eflags_noset -TESTS += mem_map_large -TESTS += invalid_read_in_cpu_tb_exec -TESTS += invalid_write_in_cpu_tb_exec_x86_64 -TESTS += x86_16_segfault -TESTS += mips_invalid_read_of_size_4_when_tracing -TESTS += invalid_read_in_tb_flush_x86_64 -TESTS += sparc_jump_to_zero -TESTS += mips_delay_slot_code_hook -TESTS += mem_nofree -TESTS += rw_hookstack -TESTS += threaded_emu_start -TESTS += emu_stop_in_hook_overrun -TESTS += mips_branch_likely_issue -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 += mem_map_0x100000000 +.PHONY: all clean test -TESTS += memleak_x86 -TESTS += memleak_arm -TESTS += memleak_arm64 -TESTS += memleak_mips -TESTS += memleak_m68k -TESTS += memleak_sparc +test: $(TESTS) all: $(TESTS) clean: rm -f $(TESTS) - -%: %.c - $(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@ - -.PHONY: all clean diff --git a/tests/regress/block_test.c b/tests/regress/block_test.c index 71d1021f..979d989f 100644 --- a/tests/regress/block_test.c +++ b/tests/regress/block_test.c @@ -63,7 +63,7 @@ int main() { } fprintf(stderr, "ok %d - uc_mem_write\n", count++); - uc_hook h1, h2; + uc_hook h1; err = uc_hook_add(uc, &h1, UC_HOOK_BLOCK, cb_hookblock, NULL, 1, 0); if (err != UC_ERR_OK) { diff --git a/tests/regress/eflags_nosync.c b/tests/regress/eflags_nosync.c index 3510b499..433dcfbc 100644 --- a/tests/regress/eflags_nosync.c +++ b/tests/regress/eflags_nosync.c @@ -11,7 +11,7 @@ #define PAGE_4K (1 << 12) #define TARGET_PAGE_MASK ~(PAGE_4K - 1) #define TARGET_PAGE_PREPARE(addr) (((addr) + PAGE_4K - 1) & TARGET_PAGE_MASK) -#define TARGET_PAGE_ALIGN(addr) (addr - (TARGET_PAGE_PREPARE(addr) - addr) & TARGET_PAGE_MASK) +#define TARGET_PAGE_ALIGN(addr) ((addr - (TARGET_PAGE_PREPARE(addr) - addr)) & TARGET_PAGE_MASK) static uint64_t instructions = 0; @@ -69,7 +69,6 @@ static void VM_exec() { uc_engine *uc; uc_err err; - uint32_t tmp; uc_hook trace1, trace2; unsigned int r_eax, r_ebx, r_ecx, r_edx, r_ebp, r_esp, r_esi, r_edi, r_eip, eflags; unsigned int tr_eax, tr_ebx, tr_ecx, tr_edx, tr_ebp, tr_esp, tr_esi, tr_edi, tr_eip, t_eflags; diff --git a/tests/regress/emu_stop_in_hook_overrun.c b/tests/regress/emu_stop_in_hook_overrun.c index 9b962a25..2336fc4b 100644 --- a/tests/regress/emu_stop_in_hook_overrun.c +++ b/tests/regress/emu_stop_in_hook_overrun.c @@ -60,7 +60,6 @@ int main(int argc, char **argv, char **envp) { uc_engine *uc; uc_err err; - int ret; uc_hook hhc; uint32_t val; diff --git a/tests/regress/mem_64_c.c b/tests/regress/mem_64_c.c index e09a90da..b760fd08 100644 --- a/tests/regress/mem_64_c.c +++ b/tests/regress/mem_64_c.c @@ -1,4 +1,5 @@ #include +#include #include uint64_t starts[] = {0x10000000, 0x110004000ll}; @@ -24,10 +25,10 @@ int main(int argc, char **argv, char **envp) { 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); + fprintf(stderr, "region %d: 0x%"PRIx64"-0x%"PRIx64" (%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", + fprintf(stderr, " ERROR: region start does not match requested start address, expected 0x%"PRIx64", found 0x%"PRIx64"\n", starts[i], regions[i].begin); } } diff --git a/tests/regress/mem_double_unmap.c b/tests/regress/mem_double_unmap.c index 3373a5cc..e7203ab8 100644 --- a/tests/regress/mem_double_unmap.c +++ b/tests/regress/mem_double_unmap.c @@ -11,7 +11,6 @@ int main(int argc, char **argv, char **envp) { uc_engine *uc; - uc_hook trace1, trace2; uc_err err; // Initialize emulator in X86-32bit mode diff --git a/tests/regress/mem_fuzz.c b/tests/regress/mem_fuzz.c index bbf37eec..c62d74c0 100644 --- a/tests/regress/mem_fuzz.c +++ b/tests/regress/mem_fuzz.c @@ -84,7 +84,6 @@ void perform_fuzz_step(uc_engine *uc){ int main(int argc, char **argv, char **envp) { uc_engine *uc; - uc_hook trace1, trace2; uc_err err; if(argc<2){ printf("usage: mem_fuzz $seed\n"); diff --git a/tests/regress/mem_map_large.c b/tests/regress/mem_map_large.c index 33f754a4..f0f4cdbf 100644 --- a/tests/regress/mem_map_large.c +++ b/tests/regress/mem_map_large.c @@ -8,7 +8,7 @@ int main() { printf("uc_open() failed: %s\n", uc_strerror(err)); } printf("Trying large map.\n"); - if ((err = uc_mem_map(u, 0x60802000, 0x28bd211200004000, UC_PROT_ALL)) != UC_ERR_OK) { + if ((err = uc_mem_map(u, 0x60802000, (unsigned) 0x28bd211200004000, UC_PROT_ALL)) != UC_ERR_OK) { printf("uc_mem_map() failed: %s\n", uc_strerror(err)); return -1; } diff --git a/tests/regress/nr_mem_test.c b/tests/regress/nr_mem_test.c index b6ab8d8e..40ffa39f 100644 --- a/tests/regress/nr_mem_test.c +++ b/tests/regress/nr_mem_test.c @@ -55,7 +55,7 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type, int main(int argc, char **argv, char **envp) { uc_engine *uc; - uc_hook trace1, trace2; + uc_hook trace1; uc_err err; uint32_t eax, ebx; diff --git a/tests/regress/ro_mem_test.c b/tests/regress/ro_mem_test.c index 845859b1..b5b26393 100644 --- a/tests/regress/ro_mem_test.c +++ b/tests/regress/ro_mem_test.c @@ -46,7 +46,7 @@ bottom: */ // callback for tracing instruction -static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) +/*static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user_data) { uint32_t esp; printf(">>> Tracing instruction at 0x%"PRIx64 ", instruction size = 0x%x\n", address, size); @@ -55,6 +55,7 @@ static void hook_code(uc_engine *uc, uint64_t address, uint32_t size, void *user printf(">>> --- ESP is 0x%x\n", esp); } +*/ // callback for tracing memory access (READ or WRITE) static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type, @@ -95,11 +96,10 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type, int main(int argc, char **argv, char **envp) { uc_engine *uc; - uc_hook trace1, trace2; + uc_hook trace1; uc_err err; uint8_t bytes[8]; uint32_t esp; - int result; int map_stack = 0; if (argc == 2 && strcmp(argv[1], "--map-stack") == 0) { diff --git a/tests/regress/sigill2.c b/tests/regress/sigill2.c index 1e5b7284..8e6ad560 100644 --- a/tests/regress/sigill2.c +++ b/tests/regress/sigill2.c @@ -9,7 +9,6 @@ int main() { int size; - uint8_t *buf; uc_engine *uc; uc_err err = uc_open (UC_ARCH_X86, UC_MODE_64, &uc); From a931761daddfb4c7b8a788391830dec4b6b46cc9 Mon Sep 17 00:00:00 2001 From: Stephen Date: Fri, 11 Nov 2016 08:31:16 -0800 Subject: [PATCH 03/16] Update Makefile --- Makefile | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Makefile b/Makefile index e9c04294..9b5f331f 100644 --- a/Makefile +++ b/Makefile @@ -201,15 +201,12 @@ $(LIBNAME)_LDFLAGS += $(GLIB) -lm all: unicorn $(MAKE) -C samples -config: - if [ "$(UNICORN_ARCHS)" != "`cat config.log`" ]; then $(MAKE) clean; fi - -qemu/config-host.h-timestamp: +qemu/config-host.h-timestamp config.log: cd qemu && \ ./configure --cc="${CC}" --extra-cflags="$(UNICORN_CFLAGS)" --target-list="$(UNICORN_TARGETS)" ${UNICORN_QEMU_FLAGS} printf "$(UNICORN_ARCHS)" > config.log -compile_lib: config qemu/config-host.h-timestamp +compile_lib: qemu/config-host.h-timestamp config.log $(MAKE) -C qemu -j 4 $(eval UC_TARGET_OBJ += $$(wildcard qemu/util/*.o) $$(wildcard qemu/*.o) $$(wildcard qemu/qom/*.o) $$(wildcard qemu/hw/core/*.o) $$(wildcard qemu/qapi/*.o) $$(wildcard qemu/qobject/*.o)) From 6bce28c946bd7b34fbc87a53c240d36398bd965a Mon Sep 17 00:00:00 2001 From: Stephen Date: Fri, 11 Nov 2016 08:40:22 -0800 Subject: [PATCH 04/16] Update Makefile --- Makefile | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/Makefile b/Makefile index 9b5f331f..09e0b200 100644 --- a/Makefile +++ b/Makefile @@ -201,26 +201,23 @@ $(LIBNAME)_LDFLAGS += $(GLIB) -lm all: unicorn $(MAKE) -C samples -qemu/config-host.h-timestamp config.log: +qemu/config-host.h-timestamp: cd qemu && \ ./configure --cc="${CC}" --extra-cflags="$(UNICORN_CFLAGS)" --target-list="$(UNICORN_TARGETS)" ${UNICORN_QEMU_FLAGS} printf "$(UNICORN_ARCHS)" > config.log - -compile_lib: qemu/config-host.h-timestamp config.log $(MAKE) -C qemu -j 4 $(eval UC_TARGET_OBJ += $$(wildcard qemu/util/*.o) $$(wildcard qemu/*.o) $$(wildcard qemu/qom/*.o) $$(wildcard qemu/hw/core/*.o) $$(wildcard qemu/qapi/*.o) $$(wildcard qemu/qobject/*.o)) unicorn: $(LIBRARY) $(ARCHIVE) -$(LIBRARY): compile_lib uc.o list.o +$(LIBRARY): qemu/config-host.h-timestamp uc.o list.o $(CC) $(CFLAGS) -shared $(UC_TARGET_OBJ) uc.o list.o -o $(LIBRARY) $($(LIBNAME)_LDFLAGS) -ln -sf $(LIBRARY) $(LIBRARY_SYMLINK) -$(ARCHIVE): compile_lib uc.o list.o +$(ARCHIVE): qemu/config-host.h-timestamp uc.o list.o $(AR) q $(ARCHIVE) $(UC_TARGET_OBJ) uc.o list.o $(RANLIB) $(ARCHIVE) - $(PKGCFGF): $(generate-pkgcfg) @@ -230,7 +227,7 @@ test: all $(MAKE) -C tests/regress test $(MAKE) -C bindings test -install: compile_lib $(PKGCFGF) +install: qemu/config-host.h-timestamp $(PKGCFGF) mkdir -p $(DESTDIR)$(LIBDIR) ifeq ($(UNICORN_SHARED),yes) ifneq ($(filter CYGWIN%,$(UNAME_S)),) @@ -260,7 +257,7 @@ else DIST_VERSION = $(TAG) endif -bindings: compile_lib +bindings: qemu/config-host.h-timestamp $(MAKE) -C bindings build $(MAKE) -C bindings samples From f9c57cd36475040ec56010058d7a542733e9cc54 Mon Sep 17 00:00:00 2001 From: Stephen Date: Mon, 14 Nov 2016 14:47:27 -0800 Subject: [PATCH 05/16] Update install-cmocka-linux.sh --- install-cmocka-linux.sh | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/install-cmocka-linux.sh b/install-cmocka-linux.sh index 86b5df11..24594db7 100755 --- a/install-cmocka-linux.sh +++ b/install-cmocka-linux.sh @@ -1,12 +1,12 @@ -#!/bin/bash +#!/bin/sh set -ex mkdir cmocka wget https://cmocka.org/files/1.1/cmocka-1.1.0.tar.xz -O /tmp/cmocka-1.1.0.tar.xz tar -xvf /tmp/cmocka-1.1.0.tar.xz -C /tmp -if [ "$(expr substr $(uname -s) 1 5)" == "MINGW" ] ; then -cd cmocka && which cmake && cmake -G "MinGW Makefiles" /tmp/cmocka-1.1.0 && make -else cd cmocka && cmake /tmp/cmocka-1.1.0 && make +# cmake builds an so instead of a dll in mingw/msys +if [[ ! -z $MSYSTEM ]]; then +cp src/cmocka.so src/cmocka.dll fi -#cmocka does not include headers in build +# cmocka does not include headers in build cp -R /tmp/cmocka-1.1.0/include/ . From e236fb7bf6fe4da28b5fbcd44773390265fa634d Mon Sep 17 00:00:00 2001 From: Stephen Date: Mon, 14 Nov 2016 14:55:05 -0800 Subject: [PATCH 06/16] remove verbose option from tar --- install-cmocka-linux.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install-cmocka-linux.sh b/install-cmocka-linux.sh index 24594db7..eb253995 100755 --- a/install-cmocka-linux.sh +++ b/install-cmocka-linux.sh @@ -2,7 +2,7 @@ set -ex mkdir cmocka wget https://cmocka.org/files/1.1/cmocka-1.1.0.tar.xz -O /tmp/cmocka-1.1.0.tar.xz -tar -xvf /tmp/cmocka-1.1.0.tar.xz -C /tmp +tar -xf /tmp/cmocka-1.1.0.tar.xz -C /tmp cd cmocka && cmake /tmp/cmocka-1.1.0 && make # cmake builds an so instead of a dll in mingw/msys if [[ ! -z $MSYSTEM ]]; then From d4c72165348dc4be169cd9d3fa6d211994cd7d50 Mon Sep 17 00:00:00 2001 From: Stephen Date: Mon, 14 Nov 2016 14:55:37 -0800 Subject: [PATCH 07/16] add upgrade to pacman for cmake --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 6a699bb0..8b30733f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -34,7 +34,7 @@ init: install: - ps: if (Test-Path Env:\CYG_ROOT) { Start-FileDownload "http://cygwin.com/$env:CYG_SETUP" -FileName "$env:CYG_SETUP" } - if defined CYG_ROOT (%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages make,gcc-core,clang,pkg-config,libpcre-devel,libglib2.0-devel,cmake,python-setuptools,ruby,mingw64-i686-gcc-core,mingw64-x86_64-gcc-core --upgrade-also) - - if defined MSYSTEM (%BASH% -lc "pacman -Sy --noconfirm mingw-w64-x86_64-glib2 mingw-w64-i686-glib2 cmake") + - if defined MSYSTEM (%BASH% -lc "pacman -Suy --noconfirm mingw-w64-x86_64-glib2 mingw-w64-i686-glib2 cmake") build_script: - if defined BASH (%BASH% -lc "cd $(cygpath ${APPVEYOR_BUILD_FOLDER}); ./install-cmocka-linux.sh; make;") - if "%MSYSTEM%" == "MINGW64" (%BASH% -lc "cd $(cygpath ${APPVEYOR_BUILD_FOLDER}); make -C bindings/go") From 04853f1db88287e477c1263d2a695e116d635c54 Mon Sep 17 00:00:00 2001 From: Stephen Date: Tue, 15 Nov 2016 08:14:58 -0800 Subject: [PATCH 08/16] pacman double update, needed to get new packages --- .appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 8b30733f..b99c7f3e 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -34,7 +34,8 @@ init: install: - ps: if (Test-Path Env:\CYG_ROOT) { Start-FileDownload "http://cygwin.com/$env:CYG_SETUP" -FileName "$env:CYG_SETUP" } - if defined CYG_ROOT (%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages make,gcc-core,clang,pkg-config,libpcre-devel,libglib2.0-devel,cmake,python-setuptools,ruby,mingw64-i686-gcc-core,mingw64-x86_64-gcc-core --upgrade-also) - - if defined MSYSTEM (%BASH% -lc "pacman -Suy --noconfirm mingw-w64-x86_64-glib2 mingw-w64-i686-glib2 cmake") + - if defined MSYSTEM (%BASH% -lc "pacman -Suuy --noconfirm mingw-w64-x86_64-glib2 mingw-w64-i686-glib2 cmake") + - if defined MSYSTEM (%BASH% -lc "pacman -Suuy --noconfirm") build_script: - if defined BASH (%BASH% -lc "cd $(cygpath ${APPVEYOR_BUILD_FOLDER}); ./install-cmocka-linux.sh; make;") - if "%MSYSTEM%" == "MINGW64" (%BASH% -lc "cd $(cygpath ${APPVEYOR_BUILD_FOLDER}); make -C bindings/go") From e6d8a477c2e88d3971c0ae9ebf8181c6ee7c5752 Mon Sep 17 00:00:00 2001 From: Stephen Date: Tue, 15 Nov 2016 10:17:15 -0800 Subject: [PATCH 09/16] enable cmocka unit testing --- install-cmocka-linux.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/install-cmocka-linux.sh b/install-cmocka-linux.sh index eb253995..46b405a4 100755 --- a/install-cmocka-linux.sh +++ b/install-cmocka-linux.sh @@ -3,7 +3,7 @@ set -ex mkdir cmocka wget https://cmocka.org/files/1.1/cmocka-1.1.0.tar.xz -O /tmp/cmocka-1.1.0.tar.xz tar -xf /tmp/cmocka-1.1.0.tar.xz -C /tmp -cd cmocka && cmake /tmp/cmocka-1.1.0 && make +cd cmocka && cmake -DUNIT_TESTING=On /tmp/cmocka-1.1.0 && make && make test # cmake builds an so instead of a dll in mingw/msys if [[ ! -z $MSYSTEM ]]; then cp src/cmocka.so src/cmocka.dll From ab560d7a2bb9099b82523d6d19dc66d53ca39bfd Mon Sep 17 00:00:00 2001 From: Stephen Date: Tue, 15 Nov 2016 10:41:13 -0800 Subject: [PATCH 10/16] rejigger commands to fail on any step should get fails in msys builds for cmocka --- .appveyor.yml | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index b99c7f3e..3cce967f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,6 +1,8 @@ # Appveyor configuration file for CI build of Unicorn Engine on Windows (under Cygwin) environment: CYG_MIRROR: http://cygwin.mirror.constant.com + CYG_PACKAGES: make,gcc-core,clang,pkg-config,libpcre-devel,libglib2.0-devel,cmake,python-setuptools,ruby,mingw64-i686-gcc-core,mingw64-x86_64-gcc-core + MSYS_PACKAGES: mingw-w64-x86_64-glib2 mingw-w64-i686-glib2 cmake matrix: - MSYSTEM: MINGW64 BASH: C:\msys64\usr\bin\bash @@ -33,19 +35,19 @@ init: # Install needed build dependencies install: - ps: if (Test-Path Env:\CYG_ROOT) { Start-FileDownload "http://cygwin.com/$env:CYG_SETUP" -FileName "$env:CYG_SETUP" } - - if defined CYG_ROOT (%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages make,gcc-core,clang,pkg-config,libpcre-devel,libglib2.0-devel,cmake,python-setuptools,ruby,mingw64-i686-gcc-core,mingw64-x86_64-gcc-core --upgrade-also) - - if defined MSYSTEM (%BASH% -lc "pacman -Suuy --noconfirm mingw-w64-x86_64-glib2 mingw-w64-i686-glib2 cmake") + - if defined CYG_ROOT (%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages "%CYG_PACKAGES% --upgrade-also) + - if defined MSYSTEM (%BASH% -lc "pacman -Suuy --noconfirm ${MSYS_PACKAGES}") - if defined MSYSTEM (%BASH% -lc "pacman -Suuy --noconfirm") build_script: - - if defined BASH (%BASH% -lc "cd $(cygpath ${APPVEYOR_BUILD_FOLDER}); ./install-cmocka-linux.sh; make;") - - if "%MSYSTEM%" == "MINGW64" (%BASH% -lc "cd $(cygpath ${APPVEYOR_BUILD_FOLDER}); make -C bindings/go") + - if defined BASH (%BASH% -lc "cd $(cygpath ${APPVEYOR_BUILD_FOLDER}) && ./install-cmocka-linux.sh && make") + - if "%MSYSTEM%" == "MINGW64" (%BASH% -lc "cd $(cygpath ${APPVEYOR_BUILD_FOLDER}) && make -C bindings/go") # make test #- 'cd %APPVEYOR_BUILD_FOLDER% && cd bindings\dotnet && msbuild UnicornDotNet.sln' # Allows RDP #on_finish: # - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) -# Disable tests for now +# Test cygwin only # test_script: - - if defined CYG_ROOT (%BASH% -lc "export CYGWIN=winsymlinks:native; cd $APPVEYOR_BUILD_FOLDER; export PATH=$PATH:$APPVEYOR_BUILD_FOLDER:$APPVEYOR_BUILD_FOLDER/cmocka/src; make test") + - if defined CYG_ROOT (%BASH% -lc "cd $APPVEYOR_BUILD_FOLDER && export PATH=$PATH:$APPVEYOR_BUILD_FOLDER:$APPVEYOR_BUILD_FOLDER/cmocka/src && make test") From a66c96b6f4924d19288bda86f2196be39797c206 Mon Sep 17 00:00:00 2001 From: Stephen Date: Tue, 15 Nov 2016 10:42:16 -0800 Subject: [PATCH 11/16] fix quote --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 3cce967f..14f51938 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -35,7 +35,7 @@ init: # Install needed build dependencies install: - ps: if (Test-Path Env:\CYG_ROOT) { Start-FileDownload "http://cygwin.com/$env:CYG_SETUP" -FileName "$env:CYG_SETUP" } - - if defined CYG_ROOT (%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages "%CYG_PACKAGES% --upgrade-also) + - if defined CYG_ROOT (%CYG_SETUP% --quiet-mode --no-shortcuts --only-site --root "%CYG_ROOT%" --site "%CYG_MIRROR%" --local-package-dir "%CYG_CACHE%" --packages "%CYG_PACKAGES%" --upgrade-also) - if defined MSYSTEM (%BASH% -lc "pacman -Suuy --noconfirm ${MSYS_PACKAGES}") - if defined MSYSTEM (%BASH% -lc "pacman -Suuy --noconfirm") build_script: From 48a0e6ccb78c08c14b8070c07d60221cd948eb4c Mon Sep 17 00:00:00 2001 From: Stephen Date: Tue, 15 Nov 2016 10:49:19 -0800 Subject: [PATCH 12/16] make cmocka in cygwin only --- .appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 14f51938..4bfd593e 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -39,7 +39,7 @@ install: - if defined MSYSTEM (%BASH% -lc "pacman -Suuy --noconfirm ${MSYS_PACKAGES}") - if defined MSYSTEM (%BASH% -lc "pacman -Suuy --noconfirm") build_script: - - if defined BASH (%BASH% -lc "cd $(cygpath ${APPVEYOR_BUILD_FOLDER}) && ./install-cmocka-linux.sh && make") + - if defined BASH (%BASH% -lc "cd $(cygpath ${APPVEYOR_BUILD_FOLDER}) && make") - if "%MSYSTEM%" == "MINGW64" (%BASH% -lc "cd $(cygpath ${APPVEYOR_BUILD_FOLDER}) && make -C bindings/go") # make test #- 'cd %APPVEYOR_BUILD_FOLDER% && cd bindings\dotnet && msbuild UnicornDotNet.sln' @@ -50,4 +50,4 @@ build_script: # Test cygwin only # test_script: - - if defined CYG_ROOT (%BASH% -lc "cd $APPVEYOR_BUILD_FOLDER && export PATH=$PATH:$APPVEYOR_BUILD_FOLDER:$APPVEYOR_BUILD_FOLDER/cmocka/src && make test") + - if defined CYG_ROOT (%BASH% -lc "cd $APPVEYOR_BUILD_FOLDER && ./install-cmocka-linux.sh && export PATH=$PATH:$APPVEYOR_BUILD_FOLDER:$APPVEYOR_BUILD_FOLDER/cmocka/src && make test") From 4903f05f9bcc2b35e9fc12456763e0d001266646 Mon Sep 17 00:00:00 2001 From: Stephen Date: Tue, 15 Nov 2016 12:37:21 -0800 Subject: [PATCH 13/16] add msys cache --- .appveyor.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 4bfd593e..dc41ecbb 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -6,9 +6,11 @@ environment: matrix: - MSYSTEM: MINGW64 BASH: C:\msys64\usr\bin\bash + MSYS_CACHE: C:\msys64\var\cache\pacman\pkg CC: x86_64-w64-mingw32-gcc - MSYSTEM: MINGW32 BASH: C:\msys64\usr\bin\bash + MSYS_CACHE: C:\msys64\var\cache\pacman\pkg CC: i686-w64-mingw32-gcc - CYG_ROOT: C:\cygwin64 CYG_CACHE: C:\cygwin64\var\cache\setup @@ -21,9 +23,10 @@ environment: BASH: C:\cygwin\bin\bash CC: gcc -# Cache Cygwin files to speed up build +# Cache Cygwin/MSYS files to speed up build cache: - '%CYG_CACHE%' + - '%MSYS_CACHE%' clone_depth: 1 # Attempt to ensure we don't try to convert line endings to Win32 CRLF as this will cause build to fail From 3543452b06fc332e6d81365e374db41643faaefa Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 19 Nov 2016 16:48:30 +0800 Subject: [PATCH 14/16] ruby: update unicorn_const.rb --- bindings/ruby/unicorn_gem/lib/unicorn/unicorn_const.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/bindings/ruby/unicorn_gem/lib/unicorn/unicorn_const.rb b/bindings/ruby/unicorn_gem/lib/unicorn/unicorn_const.rb index 1543010d..81068a6e 100644 --- a/bindings/ruby/unicorn_gem/lib/unicorn/unicorn_const.rb +++ b/bindings/ruby/unicorn_gem/lib/unicorn/unicorn_const.rb @@ -4,6 +4,11 @@ module Unicorn UC_API_MAJOR = 1 UC_API_MINOR = 0 + UC_VERSION_MAJOR = 1 + + UC_VERSION_MINOR = 0 + + UC_VERSION_EXTRA = 0 UC_SECOND_SCALE = 1000000 UC_MILISECOND_SCALE = 1000 UC_ARCH_ARM = 1 From 2a4c316b6f58ba2d5cf733f9984888a943a8d2af Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 19 Nov 2016 16:51:08 +0800 Subject: [PATCH 15/16] python: correct a comment on sample_arm.py --- bindings/python/sample_arm.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bindings/python/sample_arm.py b/bindings/python/sample_arm.py index 13292320..402ba57a 100755 --- a/bindings/python/sample_arm.py +++ b/bindings/python/sample_arm.py @@ -45,7 +45,7 @@ def test_arm(): # tracing all basic blocks with customized callback mu.hook_add(UC_HOOK_BLOCK, hook_block) - # tracing all instructions with customized callback + # tracing one instruction at ADDRESS with customized callback mu.hook_add(UC_HOOK_CODE, hook_code, begin=ADDRESS, end=ADDRESS) # emulate machine code in infinite time From ab9bae4f3e31fefdf689f9a333f402c58e007ea2 Mon Sep 17 00:00:00 2001 From: Nguyen Anh Quynh Date: Sat, 19 Nov 2016 17:20:05 +0800 Subject: [PATCH 16/16] revert the change on verbose option for Makefile --- Makefile | 16 ++++++++++++ samples/Makefile | 65 ++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/Makefile b/Makefile index 09e0b200..b71de9ed 100644 --- a/Makefile +++ b/Makefile @@ -211,12 +211,28 @@ qemu/config-host.h-timestamp: unicorn: $(LIBRARY) $(ARCHIVE) $(LIBRARY): qemu/config-host.h-timestamp uc.o list.o +ifeq ($(UNICORN_SHARED),yes) +ifeq ($(V),0) + $(call log,GEN,$(LIBRARY)) + @$(CC) $(CFLAGS) -shared $(UC_TARGET_OBJ) uc.o list.o -o $(LIBRARY) $($(LIBNAME)_LDFLAGS) + @-ln -sf $(LIBRARY) $(LIBRARY_SYMLINK) +else $(CC) $(CFLAGS) -shared $(UC_TARGET_OBJ) uc.o list.o -o $(LIBRARY) $($(LIBNAME)_LDFLAGS) -ln -sf $(LIBRARY) $(LIBRARY_SYMLINK) +endif +endif $(ARCHIVE): qemu/config-host.h-timestamp uc.o list.o +ifeq ($(UNICORN_STATIC),yes) +ifeq ($(V),0) + $(call log,GEN,$(ARCHIVE)) + @$(AR) q $(ARCHIVE) $(UC_TARGET_OBJ) uc.o list.o + @$(RANLIB) $(ARCHIVE) +else $(AR) q $(ARCHIVE) $(UC_TARGET_OBJ) uc.o list.o $(RANLIB) $(ARCHIVE) +endif +endif $(PKGCFGF): $(generate-pkgcfg) diff --git a/samples/Makefile b/samples/Makefile index 830cd68b..c44dc127 100644 --- a/samples/Makefile +++ b/samples/Makefile @@ -10,11 +10,13 @@ ifndef GLIB GLIB = $(shell pkg-config --libs glib-2.0) endif +BIN_EXT = + # Verbose output? V ?= 0 CFLAGS += -Wall -Werror -I../include -LDFLAGS += -L.. +LDFLAGS += -L.. -lunicorn LDLIBS += -lpthread -lunicorn -lm $(GLIB) ifneq ($(CROSS),) @@ -32,9 +34,11 @@ endif ifneq ($(filter CYGWIN%,$(UNAME_S)),) CFLAGS := $(CFLAGS:-fPIC=) LDLIBS += -lssp +BIN_EXT = .exe # mingw? else ifneq ($(filter MINGW%,$(UNAME_S)),) CFLAGS := $(CFLAGS:-fPIC=) +BIN_EXT = .exe endif .PHONY: all clean @@ -69,9 +73,66 @@ ifneq (,$(findstring m68k,$(UNICORN_ARCHS))) SOURCES += sample_m68k.c endif -BINS = $(SOURCES:.c=) +BINS = $(SOURCES:.c=$(BIN_EXT)) +OBJS = $(SOURCES:.c=.o) all: $(BINS) +$(BINS): $(OBJS) + clean: rm -rf *.o $(BINS) + +%$(BIN_EXT): %.o + @mkdir -p $(@D) +ifeq ($(V),0) +ifeq ($(UNICORN_SHARED),yes) + $(call log,LINK,$(notdir $@)) + @$(link-dynamic) +endif +ifeq ($(UNICORN_STATIC),yes) +ifneq ($(filter MINGW%,$(UNAME_S)),) + $(call log,LINK,$(notdir $(call staticname,$@))) + @$(link-static) +endif +endif +else +ifeq ($(UNICORN_SHARED),yes) + $(link-dynamic) +endif +ifeq ($(UNICORN_STATIC),yes) +ifneq ($(filter MINGW%,$(UNAME_S)),) + $(link-static) +endif +endif +endif + +%.o: %.c + @mkdir -p $(@D) +ifeq ($(V),0) + $(call log,CC,$(@:%=%)) + @$(compile) +else + $(compile) +endif + + +define link-dynamic + $(CC) $< $(LDFLAGS) -o $@ +endef + + +define link-static + $(CC) $< $(ARCHIVE) $(LDFLAGS_STATIC) -o $(call staticname,$@) +endef + + +staticname = $(subst $(BIN_EXT),,$(1)).static$(BIN_EXT) + +define log + @printf " %-7s %s\n" "$(1)" "$(2)" +endef + +define compile + ${CC} ${CFLAGS} -c $< -o $@ +endef