This commit is contained in:
Nguyen Anh Quynh 2015-09-26 10:44:15 +08:00
commit 15f087be74
111 changed files with 2768 additions and 1218 deletions

19
.gitignore vendored
View file

@ -3,6 +3,7 @@
*.d *.d
*.o *.o
*.a *.a
*.dSYM
qemu/config-all-devices.mak qemu/config-all-devices.mak
@ -93,12 +94,12 @@ tmp/
bindings/python/build/ bindings/python/build/
config.log config.log
regress/map_crash map_crash
regress/sigill sigill
regress/sigill2 sigill2
regress/block_test block_test
regress/map_write map_write
regress/ro_mem_test ro_mem_test
regress/nr_mem_test nr_mem_test
regress/timeout_segfault timeout_segfault
regress/rep_movsb rep_movsb

View file

@ -35,11 +35,11 @@ Unicorn requires few dependent packages as followings
[1] Tailor Unicorn to your need. [1] Tailor Unicorn to your need.
Out of 8 archtitectures supported by Unicorn (Arm, Arm64, Mips, PPC, Sparc, Out of 6 archtitectures supported by Unicorn (Arm, Arm64, M68K, Mips, Sparc,
SystemZ, XCore & X86), if you just need several selected archs, choose which & X86), if you just need several selected archs, choose which ones you want
ones you want to compile in by editing "config.mk" before going to next steps. to compile in by editing "config.mk" before going to next steps.
By default, all 8 architectures are compiled. By default, all 6 architectures are compiled.
The other way of customize Unicorn without having to edit config.mk is to The other way of customize Unicorn without having to edit config.mk is to
pass the desired options on the commandline to ./make.sh. Currently, pass the desired options on the commandline to ./make.sh. Currently,
@ -246,3 +246,12 @@ Unicorn requires few dependent packages as followings
So far, only Python is supported by bindings in the main code. So far, only Python is supported by bindings in the main code.
Look for the bindings under directory bindings/, and refer to README file Look for the bindings under directory bindings/, and refer to README file
of corresponding languages. of corresponding languages.
[11] Unit tests
Automated unit tests use the cmocka unit testing framework (https://cmocka.org/).
It can be installed in most Linux distros using the package manager, e.g.
`sudo yum install libcmocka libcmocka-devel`, or you can easily build and install it from source.
You can run the tests by running `make test` in the project directory.

View file

@ -249,6 +249,11 @@ else
endif endif
.PHONY: test
test: all
$(MAKE) -C tests/unit test
install: all $(PKGCFGF) install: all $(PKGCFGF)
mkdir -p $(LIBDIR) mkdir -p $(LIBDIR)
ifeq ($(UNICORN_SHARED),yes) ifeq ($(UNICORN_SHARED),yes)
@ -302,6 +307,7 @@ ifeq (,$(findstring yes,$(UNICORN_BUILD_CORE_ONLY)))
cd samples && $(MAKE) clean cd samples && $(MAKE) clean
rm -f $(BLDIR)/samples/lib$(LIBNAME).$(EXT) rm -f $(BLDIR)/samples/lib$(LIBNAME).$(EXT)
endif endif
$(MAKE) -C tests/unit clean
ifdef BUILDDIR ifdef BUILDDIR
rm -rf $(BUILDDIR) rm -rf $(BUILDDIR)

24
README
View file

@ -1,24 +0,0 @@
Unicorn is a lightweight multi-platform, multi-architecture CPU emulator framework.
Unicorn offers some unparalleled features:
- Multi-architectures: Arm, Arm64 (Armv8), M68K, Mips, Sparc, & X86 (include X86_64).
- Clean/simple/lightweight/intuitive architecture-neutral API.
- Implemented in pure C language, with bindings for Python available.
- Native support for Windows & *nix (with Mac OSX, Linux, *BSD & Solaris confirmed).
- High performace by using Just-In-Time compiler technique.
- Support fine-grained instrumentation at various levels.
- Thread-safe by design.
- Distributed under open source license GPL.
Further information is available at http://www.unicorn-engine.org
[Compile]
See COMPILE.TXT file for how to compile and install Unicorn.
[License]
This project is released under the GPL license.

30
README.md Normal file
View file

@ -0,0 +1,30 @@
Unicorn Engine
==============
Unicorn is a lightweight, multi-platform, multi-architecture CPU emulator framework
based on [QEMU](http://qemu.org).
Unicorn offers some unparalleled features:
- Multi-architecture: ARM, AMM64 (ARMv8), M68K, MIPS, SPARC, and X86 (16, 32, 64-bit)
- Clean/simple/lightweight/intuitive architecture-neutral API
- Implemented in pure C language, with bindings for Python, Java, and Go
- Native support for Windows & *nix (with Mac OSX, Linux, *BSD & Solaris confirmed)
- High performace via Just-In-Time compilation
- Support for fine-grained instrumentation at various levels
- Thread-safety by design
- Distributed under open source license GPL
Further information is available at http://www.unicorn-engine.org
Compilation
-----------
See [COMPILE.TXT](COMPILE.TXT) file for how to compile and install Unicorn.
License
-------
This project is released under the GPL license.

View file

@ -16,6 +16,7 @@ SAMPLE_X86 = $(TMPDIR)/sample_x86
all: all:
cd python && $(MAKE) gen_const cd python && $(MAKE) gen_const
cd go && $(MAKE) gen_const cd go && $(MAKE) gen_const
cd java && $(MAKE) gen_const
samples: expected python samples: expected python

View file

@ -71,10 +71,7 @@ func (u *uc) HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) {
case HOOK_BLOCK, HOOK_CODE: case HOOK_BLOCK, HOOK_CODE:
rangeMode = true rangeMode = true
callback = C.hookCode_cgo callback = C.hookCode_cgo
case HOOK_MEM_INVALID: case HOOK_MEM_READ, HOOK_MEM_WRITE, HOOK_MEM_READ | HOOK_MEM_WRITE:
rangeMode = true
callback = C.hookMemInvalid_cgo
case HOOK_MEM_READ, HOOK_MEM_WRITE, HOOK_MEM_READ_WRITE:
rangeMode = true rangeMode = true
callback = C.hookMemAccess_cgo callback = C.hookMemAccess_cgo
case HOOK_INTR: case HOOK_INTR:
@ -92,8 +89,15 @@ func (u *uc) HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) {
return 0, errors.New("Unknown instruction type.") return 0, errors.New("Unknown instruction type.")
} }
default: default:
// special case for mask
if htype&(HOOK_MEM_READ_INVALID|HOOK_MEM_WRITE_INVALID|HOOK_MEM_FETCH_INVALID|
HOOK_MEM_READ_PROT|HOOK_MEM_WRITE_PROT|HOOK_MEM_FETCH_PROT) != 0 {
rangeMode = true
callback = C.hookMemInvalid_cgo
} else {
return 0, errors.New("Unknown hook type.") return 0, errors.New("Unknown hook type.")
} }
}
var h2 C.uc_hook var h2 C.uc_hook
data := &HookData{u, cb} data := &HookData{u, cb}
if rangeMode { if rangeMode {

View file

@ -57,21 +57,21 @@ const (
SPARC_REG_FCC1 = 50 SPARC_REG_FCC1 = 50
SPARC_REG_FCC2 = 51 SPARC_REG_FCC2 = 51
SPARC_REG_FCC3 = 52 SPARC_REG_FCC3 = 52
SPARC_REG_FP = 53 SPARC_REG_G0 = 53
SPARC_REG_G0 = 54 SPARC_REG_G1 = 54
SPARC_REG_G1 = 55 SPARC_REG_G2 = 55
SPARC_REG_G2 = 56 SPARC_REG_G3 = 56
SPARC_REG_G3 = 57 SPARC_REG_G4 = 57
SPARC_REG_G4 = 58 SPARC_REG_G5 = 58
SPARC_REG_G5 = 59 SPARC_REG_G6 = 59
SPARC_REG_G6 = 60 SPARC_REG_G7 = 60
SPARC_REG_G7 = 61 SPARC_REG_I0 = 61
SPARC_REG_I0 = 62 SPARC_REG_I1 = 62
SPARC_REG_I1 = 63 SPARC_REG_I2 = 63
SPARC_REG_I2 = 64 SPARC_REG_I3 = 64
SPARC_REG_I3 = 65 SPARC_REG_I4 = 65
SPARC_REG_I4 = 66 SPARC_REG_I5 = 66
SPARC_REG_I5 = 67 SPARC_REG_FP = 67
SPARC_REG_I7 = 68 SPARC_REG_I7 = 68
SPARC_REG_ICC = 69 SPARC_REG_ICC = 69
SPARC_REG_L0 = 70 SPARC_REG_L0 = 70
@ -88,12 +88,12 @@ const (
SPARC_REG_O3 = 81 SPARC_REG_O3 = 81
SPARC_REG_O4 = 82 SPARC_REG_O4 = 82
SPARC_REG_O5 = 83 SPARC_REG_O5 = 83
SPARC_REG_O7 = 84 SPARC_REG_SP = 84
SPARC_REG_SP = 85 SPARC_REG_O7 = 85
SPARC_REG_Y = 86 SPARC_REG_Y = 86
SPARC_REG_XCC = 87 SPARC_REG_XCC = 87
SPARC_REG_PC = 88 SPARC_REG_PC = 88
SPARC_REG_ENDING = 89 SPARC_REG_ENDING = 89
SPARC_REG_O6 = 85 SPARC_REG_O6 = 84
SPARC_REG_I6 = 53 SPARC_REG_I6 = 67
) )

View file

@ -48,26 +48,33 @@ const (
ERR_MAP = 12 ERR_MAP = 12
ERR_WRITE_PROT = 13 ERR_WRITE_PROT = 13
ERR_READ_PROT = 14 ERR_READ_PROT = 14
ERR_EXEC_PROT = 15 ERR_FETCH_PROT = 15
ERR_ARG = 16 ERR_ARG = 16
ERR_READ_UNALIGNED = 17 ERR_READ_UNALIGNED = 17
ERR_WRITE_UNALIGNED = 18 ERR_WRITE_UNALIGNED = 18
ERR_FETCH_UNALIGNED = 19 ERR_FETCH_UNALIGNED = 19
MEM_READ = 16 MEM_READ = 16
MEM_WRITE = 17 MEM_WRITE = 17
MEM_READ_WRITE = 18 MEM_FETCH = 18
MEM_FETCH = 19 MEM_READ_INVALID = 19
MEM_WRITE_PROT = 20 MEM_WRITE_INVALID = 20
MEM_READ_PROT = 21 MEM_FETCH_INVALID = 21
MEM_EXEC_PROT = 22 MEM_WRITE_PROT = 22
HOOK_INTR = 32 MEM_READ_PROT = 23
HOOK_INSN = 33 MEM_FETCH_PROT = 24
HOOK_CODE = 34 HOOK_INTR = 1
HOOK_BLOCK = 35 HOOK_INSN = 2
HOOK_MEM_INVALID = 36 HOOK_CODE = 4
HOOK_MEM_READ = 37 HOOK_BLOCK = 8
HOOK_MEM_WRITE = 38 HOOK_MEM_READ_INVALID = 16
HOOK_MEM_READ_WRITE = 39 HOOK_MEM_WRITE_INVALID = 32
HOOK_MEM_FETCH_INVALID = 64
HOOK_MEM_READ_PROT = 128
HOOK_MEM_WRITE_PROT = 256
HOOK_MEM_FETCH_PROT = 512
HOOK_MEM_READ = 1024
HOOK_MEM_WRITE = 2048
HOOK_MEM_FETCH = 4096
PROT_NONE = 0 PROT_NONE = 0
PROT_READ = 1 PROT_READ = 1

View file

@ -1,78 +1,26 @@
.PHONY: gen_const clean jar all lib samples install
.PHONY: gen_const clean all: gen_const
$(MAKE) -f Makefile.build all
JAVA_HOME := $(shell jrunscript -e 'java.lang.System.out.println(java.lang.System.getProperty("java.home"));') lib:
$(MAKE) -f Makefile.build lib
JAVA_INC := $(shell realpath $(JAVA_HOME)/../include) samples:
$(MAKE) -f Makefile.build samples
JAVA_PLATFORM_INC := $(shell dirname `find $(JAVA_INC) -name jni_md.h`) jar:
$(MAKE) -f Makefile.build jar
UNICORN_INC=../../include
SAMPLES := $(shell ls samples/*.java)
SRC := $(shell ls unicorn/*.java)
OS := $(shell uname)
ifeq ($(OS),Darwin)
LIB_EXT=.dylib
endif
ifeq ($(OS),Linux)
LIB_EXT=.so
else
LIB_EXT=.dll
endif
CC=gcc
CFLAGS=-fPIC
LDFLAGS=-shared -fPIC
LIBS=-lunicorn
LIBDIR=-L../../
INCS=-I$(JAVA_INC) -I$(JAVA_PLATFORM_INC) -I$(UNICORN_INC)
JC=javac
CLASSPATH=./
.SUFFIXES: .java .class
%.class: %.java
$(JC) $(JFLAGS) $<
OBJS=unicorn_Unicorn.o
JARFILE=unicorn.jar
all: lib jar samples
%.o: %.c
$(CC) -c $(CFLAGS) $(INCS) $< -o $@
unicorn_Unicorn.h: unicorn/Unicorn.java
javah unicorn.Unicorn
unicorn_Unicorn.o: unicorn_Unicorn.c unicorn_Unicorn.h
$(CC) -c $(CFLAGS) $(INCS) $< -o $@
libunicorn_java$(LIB_EXT): unicorn_Unicorn.o
lib: libunicorn_java$(LIB_EXT) unicorn_Unicorn.h
$(CC) -o $< $(LDFLAGS) $(OBJS) $(LIBDIR) $(LIBS)
samples: $(SAMPLES:.java=.class)
jarfiles: $(SRC:.java=.class)
jar: jarfiles
jar cf $(JARFILE) unicorn/*.class
install: lib jar install: lib jar
cp libunicorn_java$(LIB_EXT) $(JAVA_HOME)/lib/ext $(MAKE) -f Makefile.build install
cp $(JARFILE) $(JAVA_HOME)/lib/ext
gen_const: gen_const:
cd .. && python const_generator.py java cd .. && python const_generator.py java
clean: clean:
rm unicorn/*.class rm -f unicorn/*.class
rm samples/*.class rm -f samples/*.class
rm *.so rm -f *.so
rm *.dylib rm -f *.dylib
rm *.dll rm -f *.dll

View file

@ -0,0 +1,78 @@
.PHONY: gen_const clean
JAVA_HOME := $(shell jrunscript -e 'java.lang.System.out.println(java.lang.System.getProperty("java.home"));')
JAVA_INC := $(shell realpath $(JAVA_HOME)/../include)
JAVA_PLATFORM_INC := $(shell dirname `find $(JAVA_INC) -name jni_md.h`)
UNICORN_INC=../../include
SAMPLES := $(shell ls samples/*.java)
SRC := $(shell ls unicorn/*.java)
OS := $(shell uname)
ifeq ($(OS),Darwin)
LIB_EXT=.dylib
endif
ifeq ($(OS),Linux)
LIB_EXT=.so
else
LIB_EXT=.dll
endif
CC=gcc
CFLAGS=-fPIC
LDFLAGS=-shared -fPIC
LIBS=-lunicorn
LIBDIR=-L../../
INCS=-I$(JAVA_INC) -I$(JAVA_PLATFORM_INC) -I$(UNICORN_INC)
JC=javac
CLASSPATH=./
.SUFFIXES: .java .class
%.class: %.java
$(JC) $(JFLAGS) $<
OBJS=unicorn_Unicorn.o
JARFILE=unicorn.jar
all: lib jar samples
%.o: %.c
$(CC) -c $(CFLAGS) $(INCS) $< -o $@
unicorn_Unicorn.h: unicorn/Unicorn.java
javah unicorn.Unicorn
unicorn_Unicorn.o: unicorn_Unicorn.c unicorn_Unicorn.h
$(CC) -c $(CFLAGS) $(INCS) $< -o $@
libunicorn_java$(LIB_EXT): unicorn_Unicorn.o
lib: libunicorn_java$(LIB_EXT) unicorn_Unicorn.h
$(CC) -o $< $(LDFLAGS) $(OBJS) $(LIBDIR) $(LIBS)
samples: $(SAMPLES:.java=.class)
jarfiles: $(SRC:.java=.class)
jar: jarfiles
jar cf $(JARFILE) unicorn/*.class
install: lib jar
cp libunicorn_java$(LIB_EXT) $(JAVA_HOME)/lib/ext
cp $(JARFILE) $(JAVA_HOME)/lib/ext
gen_const:
cd .. && python const_generator.py java
clean:
rm unicorn/*.class
rm samples/*.class
rm *.so
rm *.dylib
rm *.dll

View file

@ -83,10 +83,8 @@ public class Sample_x86 {
} }
} }
private static class MyMemInvalidHook implements MemoryInvalidHook { private static class MyWriteInvalidHook implements EventMemHook {
public boolean hook(Unicorn u, int type, long address, int size, long value, Object user) { public boolean hook(Unicorn u, long address, int size, long value, Object user) {
switch(type) {
case Unicorn.UC_MEM_WRITE:
System.out.printf(">>> Missing memory is being WRITE at 0x%x, data size = %d, data value = 0x%x\n", System.out.printf(">>> Missing memory is being WRITE at 0x%x, data size = %d, data value = 0x%x\n",
address, size, value); address, size, value);
// map this memory in with 2MB in size // map this memory in with 2MB in size
@ -94,8 +92,6 @@ public class Sample_x86 {
// return true to indicate we want to continue // return true to indicate we want to continue
return true; return true;
} }
return false;
}
} }
// callback for tracing instruction // callback for tracing instruction
@ -423,7 +419,7 @@ public class Sample_x86 {
u.hook_add(new MyCodeHook(), 1, 0, null); u.hook_add(new MyCodeHook(), 1, 0, null);
// intercept invalid memory events // intercept invalid memory events
u.hook_add(new MyMemInvalidHook(), null); u.hook_add(new MyWriteInvalidHook(), Unicorn.UC_HOOK_MEM_WRITE_INVALID, null);
// emulate machine code in infinite time // emulate machine code in infinite time
try { try {

View file

@ -21,9 +21,9 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
package unicorn; package unicorn;
public interface ReadWriteHook extends Hook { public interface EventMemHook extends Hook {
public void hook(Unicorn u, int type, long address, int size, long value, Object user); public boolean hook(Unicorn u, long address, int size, long value, Object user);
} }

View file

@ -21,9 +21,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
package unicorn; package unicorn;
public interface MemoryInvalidHook extends Hook { public interface MemHook extends ReadHook,WriteHook {
public boolean hook(Unicorn u, int type, long address, int size, long value, Object user);
} }

View file

@ -59,21 +59,21 @@ public interface SparcConst {
public static final int UC_SPARC_REG_FCC1 = 50; public static final int UC_SPARC_REG_FCC1 = 50;
public static final int UC_SPARC_REG_FCC2 = 51; public static final int UC_SPARC_REG_FCC2 = 51;
public static final int UC_SPARC_REG_FCC3 = 52; public static final int UC_SPARC_REG_FCC3 = 52;
public static final int UC_SPARC_REG_FP = 53; public static final int UC_SPARC_REG_G0 = 53;
public static final int UC_SPARC_REG_G0 = 54; public static final int UC_SPARC_REG_G1 = 54;
public static final int UC_SPARC_REG_G1 = 55; public static final int UC_SPARC_REG_G2 = 55;
public static final int UC_SPARC_REG_G2 = 56; public static final int UC_SPARC_REG_G3 = 56;
public static final int UC_SPARC_REG_G3 = 57; public static final int UC_SPARC_REG_G4 = 57;
public static final int UC_SPARC_REG_G4 = 58; public static final int UC_SPARC_REG_G5 = 58;
public static final int UC_SPARC_REG_G5 = 59; public static final int UC_SPARC_REG_G6 = 59;
public static final int UC_SPARC_REG_G6 = 60; public static final int UC_SPARC_REG_G7 = 60;
public static final int UC_SPARC_REG_G7 = 61; public static final int UC_SPARC_REG_I0 = 61;
public static final int UC_SPARC_REG_I0 = 62; public static final int UC_SPARC_REG_I1 = 62;
public static final int UC_SPARC_REG_I1 = 63; public static final int UC_SPARC_REG_I2 = 63;
public static final int UC_SPARC_REG_I2 = 64; public static final int UC_SPARC_REG_I3 = 64;
public static final int UC_SPARC_REG_I3 = 65; public static final int UC_SPARC_REG_I4 = 65;
public static final int UC_SPARC_REG_I4 = 66; public static final int UC_SPARC_REG_I5 = 66;
public static final int UC_SPARC_REG_I5 = 67; public static final int UC_SPARC_REG_FP = 67;
public static final int UC_SPARC_REG_I7 = 68; public static final int UC_SPARC_REG_I7 = 68;
public static final int UC_SPARC_REG_ICC = 69; public static final int UC_SPARC_REG_ICC = 69;
public static final int UC_SPARC_REG_L0 = 70; public static final int UC_SPARC_REG_L0 = 70;
@ -90,13 +90,13 @@ public interface SparcConst {
public static final int UC_SPARC_REG_O3 = 81; public static final int UC_SPARC_REG_O3 = 81;
public static final int UC_SPARC_REG_O4 = 82; public static final int UC_SPARC_REG_O4 = 82;
public static final int UC_SPARC_REG_O5 = 83; public static final int UC_SPARC_REG_O5 = 83;
public static final int UC_SPARC_REG_O7 = 84; public static final int UC_SPARC_REG_SP = 84;
public static final int UC_SPARC_REG_SP = 85; public static final int UC_SPARC_REG_O7 = 85;
public static final int UC_SPARC_REG_Y = 86; public static final int UC_SPARC_REG_Y = 86;
public static final int UC_SPARC_REG_XCC = 87; public static final int UC_SPARC_REG_XCC = 87;
public static final int UC_SPARC_REG_PC = 88; public static final int UC_SPARC_REG_PC = 88;
public static final int UC_SPARC_REG_ENDING = 89; public static final int UC_SPARC_REG_ENDING = 89;
public static final int UC_SPARC_REG_O6 = 85; public static final int UC_SPARC_REG_O6 = 84;
public static final int UC_SPARC_REG_I6 = 53; public static final int UC_SPARC_REG_I6 = 67;
} }

View file

@ -31,10 +31,15 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S
private long interruptHandle = 0; private long interruptHandle = 0;
private long codeHandle = 0; private long codeHandle = 0;
private long memInvalidHandle = 0; private Hashtable<Integer, Long> eventMemHandles = new Hashtable<Integer, Long>();
private long readInvalidHandle = 0;
private long writeInvalidHandle = 0;
private long fetchProtHandle = 0;
private long readProtHandle = 0;
private long writeProtHandle = 0;
private long readHandle = 0; private long readHandle = 0;
private long writeHandle = 0; private long writeHandle = 0;
private long readWriteHandle = 0;
private long inHandle = 0; private long inHandle = 0;
private long outHandle = 0; private long outHandle = 0;
private long syscallHandle = 0; private long syscallHandle = 0;
@ -51,21 +56,28 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S
private ArrayList<Tuple> blockList = new ArrayList<Tuple>(); private ArrayList<Tuple> blockList = new ArrayList<Tuple>();
private ArrayList<Tuple> intrList = new ArrayList<Tuple>(); private ArrayList<Tuple> intrList = new ArrayList<Tuple>();
private ArrayList<Tuple> codeList = new ArrayList<Tuple>(); private ArrayList<Tuple> codeList = new ArrayList<Tuple>();
private ArrayList<Tuple> memInvalidList = new ArrayList<Tuple>();
private ArrayList<Tuple> readList = new ArrayList<Tuple>(); private ArrayList<Tuple> readList = new ArrayList<Tuple>();
private ArrayList<Tuple> writeList = new ArrayList<Tuple>(); private ArrayList<Tuple> writeList = new ArrayList<Tuple>();
private ArrayList<Tuple> readWriteList = new ArrayList<Tuple>();
private ArrayList<Tuple> inList = new ArrayList<Tuple>(); private ArrayList<Tuple> inList = new ArrayList<Tuple>();
private ArrayList<Tuple> outList = new ArrayList<Tuple>(); private ArrayList<Tuple> outList = new ArrayList<Tuple>();
private ArrayList<Tuple> syscallList = new ArrayList<Tuple>(); private ArrayList<Tuple> syscallList = new ArrayList<Tuple>();
private Hashtable<Integer, ArrayList<Tuple> > eventMemLists = new Hashtable<Integer, ArrayList<Tuple> >();
private ArrayList<ArrayList<Tuple>> allLists = new ArrayList<ArrayList<Tuple>>(); private ArrayList<ArrayList<Tuple>> allLists = new ArrayList<ArrayList<Tuple>>();
private static Hashtable<Integer,Integer> eventMemMap = new Hashtable<Integer,Integer>();
private static Hashtable<Long,Unicorn> unicorns = new Hashtable<Long,Unicorn>(); private static Hashtable<Long,Unicorn> unicorns = new Hashtable<Long,Unicorn>();
//required to load native method implementations //required to load native method implementations
static { static {
System.loadLibrary("unicorn_java"); //loads unicorn.dll or libunicorn.so System.loadLibrary("unicorn_java"); //loads unicorn.dll or libunicorn.so
eventMemMap.put(UC_HOOK_MEM_READ_INVALID, UC_MEM_READ_INVALID);
eventMemMap.put(UC_HOOK_MEM_WRITE_INVALID, UC_MEM_WRITE_INVALID);
eventMemMap.put(UC_HOOK_MEM_FETCH_INVALID, UC_MEM_FETCH_INVALID);
eventMemMap.put(UC_HOOK_MEM_READ_PROT, UC_MEM_READ_PROT);
eventMemMap.put(UC_HOOK_MEM_WRITE_PROT, UC_MEM_WRITE_PROT);
eventMemMap.put(UC_HOOK_MEM_FETCH_PROT, UC_MEM_FETCH_PROT);
} }
/** /**
@ -128,25 +140,29 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S
} }
/** /**
* Invoke all UC_HOOK_MEM_INVALID callbacks registered for a specific Unicorn. * Invoke all UC_HOOK_MEM_XXX_INVALID andor UC_HOOK_MEM_XXX_PROT callbacks registered
* for a specific Unicorn.
* This function gets invoked from the native C callback registered for * This function gets invoked from the native C callback registered for
* for UC_HOOK_MEM_INVALID * for UC_HOOK_MEM_XXX_INVALID or UC_HOOK_MEM_XXX_PROT
* *
* @param eng A Unicorn uc_engine* eng returned by uc_open * @param eng A Unicorn uc_engine* eng returned by uc_open
* @param type This memory is being read (UC_MEM_READ), or written (UC_MEM_WRITE) * @param type The type of event that is taking place
* @param address Address of instruction being executed * @param address Address of instruction being executed
* @param size Size of data being read or written * @param size Size of data being read or written
* @param value Value of data being written to memory, or irrelevant if type = READ. * @param value Value of data being written to memory, or irrelevant if type = READ.
* @return true to continue, or false to stop program (due to invalid memory). * @return true to continue, or false to stop program (due to invalid memory).
* @see hook_add, unicorn.MemoryInvalidHook * @see hook_add, unicorn.EventMemHook
*/ */
private static boolean invokeMemInvalidCallbacks(long eng, int type, long address, int size, long value) { private static boolean invokeEventMemCallbacks(long eng, int type, long address, int size, long value) {
Unicorn u = unicorns.get(eng); Unicorn u = unicorns.get(eng);
boolean result = true; boolean result = true;
if (u != null) { if (u != null) {
for (Tuple p : u.memInvalidList) { ArrayList<Tuple> funcList = u.eventMemLists.get(type);
MemoryInvalidHook mh = (MemoryInvalidHook)p.function; if (funcList != null) {
result &= mh.hook(u, type, address, size, value, p.data); for (Tuple p : funcList) {
EventMemHook emh = (EventMemHook)p.function;
result &= emh.hook(u, address, size, value, p.data);
}
} }
} }
return result; return result;
@ -193,28 +209,6 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S
} }
} }
/**
* Invoke all UC_HOOK_MEM_READ_WRITE callbacks registered for a specific Unicorn.
* This function gets invoked from the native C callback registered for
* for UC_HOOK_MEM_READ_WRITE
*
* @param eng A Unicorn uc_engine* eng returned by uc_open
* @param type Type of access being performed (UC_MEM_READ, UC_MEM_WRITE, UC_MEM_READ_WRITE)
* @param address Address of instruction being executed
* @param size Size of data being read
* @param value value being written (if applicable)
* @see hook_add, unicorn.ReadWriteHook
*/
private static void invokeReadWriteCallbacks(long eng, int type, long address, int size, long value) {
Unicorn u = unicorns.get(eng);
if (u != null) {
for (Tuple p : u.readWriteList) {
ReadWriteHook rwh = (ReadWriteHook)p.function;
rwh.hook(u, type, address, size, value, p.data);
}
}
}
/** /**
* Invoke all UC_HOOK_INSN callbacks registered for a specific Unicorn. * Invoke all UC_HOOK_INSN callbacks registered for a specific Unicorn.
* This is specifically for the x86 IN instruction. * This is specifically for the x86 IN instruction.
@ -303,10 +297,8 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S
allLists.add(blockList); allLists.add(blockList);
allLists.add(intrList); allLists.add(intrList);
allLists.add(codeList); allLists.add(codeList);
allLists.add(memInvalidList);
allLists.add(readList); allLists.add(readList);
allLists.add(writeList); allLists.add(writeList);
allLists.add(readWriteList);
allLists.add(inList); allLists.add(inList);
allLists.add(outList); allLists.add(outList);
allLists.add(syscallList); allLists.add(syscallList);
@ -528,34 +520,47 @@ public class Unicorn implements UnicornConst, ArmConst, Arm64Const, M68kConst, S
} }
/** /**
* Hook registration for UC_HOOK_MEM_READ_WRITE hooks. The registered callback function will be * Hook registration for UC_HOOK_MEM_WRITE | UC_HOOK_MEM_WRITE hooks. The registered callback function will be
* invoked whenever a memory read or write is performed within the address range begin <= mem_addr <= end. For * invoked whenever a memory write or read is performed within the address range begin <= addr <= end. For
* the special case in which begin > end, the callback will be invoked for ALL memory reads and writes. * the special case in which begin > end, the callback will be invoked for ALL memory writes.
* *
* @param callback Implementation of a ReadWriteHook interface * @param callback Implementation of a MemHook interface
* @param begin Start address of memory read/write range * @param begin Start address of memory range
* @param end End address of memory read/write range * @param end End address of memory range
* @param user_data User data to be passed to the callback function each time the event is triggered * @param user_data User data to be passed to the callback function each time the event is triggered
*/ */
public void hook_add(ReadWriteHook callback, long begin, long end, Object user_data) throws UnicornException { public void hook_add(MemHook callback, long begin, long end, Object user_data) throws UnicornException {
if (readWriteHandle == 0) { hook_add((ReadHook)callback, begin, end, user_data);
readWriteHandle = registerHook(eng, UC_HOOK_MEM_READ_WRITE, begin, end); hook_add((WriteHook)callback, begin, end, user_data);
}
readWriteList.add(new Tuple(callback, user_data));
} }
/** /**
* Hook registration for UC_HOOK_MEM_INVALID hooks. The registered callback function will be * Hook registration for UC_HOOK_MEM_XXX_INVALID and UC_HOOK_MEM_XXX_PROT hooks.
* invoked whenever a read or write is attempted from an unmapped memory address. * The registered callback function will be invoked whenever a read or write is
* attempted from an invalid or protected memory address.
* *
* @param callback Implementation of a MemoryInvalidHook interface * @param callback Implementation of a EventMemHook interface
* @param type Type of memory event being hooked such as UC_HOOK_MEM_READ_INVALID or UC_HOOK_MEM_WRITE_PROT
* @param user_data User data to be passed to the callback function each time the event is triggered * @param user_data User data to be passed to the callback function each time the event is triggered
*/ */
public void hook_add(MemoryInvalidHook callback, Object user_data) throws UnicornException { public void hook_add(EventMemHook callback, int type, Object user_data) throws UnicornException {
if (memInvalidHandle == 0) { //test all of the EventMem related bits in type
memInvalidHandle = registerHook(eng, UC_HOOK_MEM_INVALID); for (Integer htype : eventMemMap.keySet()) {
if ((type & htype) != 0) { //the 'htype' bit is set in type
Long handle = eventMemHandles.get(htype);
if (handle == null) {
eventMemHandles.put(htype, registerHook(eng, htype));
}
int cbType = eventMemMap.get(htype);
ArrayList<Tuple> flist = eventMemLists.get(cbType);
if (flist == null) {
flist = new ArrayList<Tuple>();
allLists.add(flist);
eventMemLists.put(cbType, flist);
}
flist.add(new Tuple(callback, user_data));
}
} }
memInvalidList.add(new Tuple(callback, user_data));
} }
/** /**

View file

@ -50,23 +50,33 @@ public interface UnicornConst {
public static final int UC_ERR_MAP = 12; public static final int UC_ERR_MAP = 12;
public static final int UC_ERR_WRITE_PROT = 13; public static final int UC_ERR_WRITE_PROT = 13;
public static final int UC_ERR_READ_PROT = 14; public static final int UC_ERR_READ_PROT = 14;
public static final int UC_ERR_EXEC_PROT = 15; public static final int UC_ERR_FETCH_PROT = 15;
public static final int UC_ERR_ARG = 16; public static final int UC_ERR_ARG = 16;
public static final int UC_ERR_READ_UNALIGNED = 17;
public static final int UC_ERR_WRITE_UNALIGNED = 18;
public static final int UC_ERR_FETCH_UNALIGNED = 19;
public static final int UC_MEM_READ = 16; public static final int UC_MEM_READ = 16;
public static final int UC_MEM_WRITE = 17; public static final int UC_MEM_WRITE = 17;
public static final int UC_MEM_READ_WRITE = 18; public static final int UC_MEM_FETCH = 18;
public static final int UC_MEM_FETCH = 19; public static final int UC_MEM_READ_INVALID = 19;
public static final int UC_MEM_WRITE_PROT = 20; public static final int UC_MEM_WRITE_INVALID = 20;
public static final int UC_MEM_READ_PROT = 21; public static final int UC_MEM_FETCH_INVALID = 21;
public static final int UC_MEM_EXEC_PROT = 22; public static final int UC_MEM_WRITE_PROT = 22;
public static final int UC_HOOK_INTR = 32; public static final int UC_MEM_READ_PROT = 23;
public static final int UC_HOOK_INSN = 33; public static final int UC_MEM_FETCH_PROT = 24;
public static final int UC_HOOK_CODE = 34; public static final int UC_HOOK_INTR = 1;
public static final int UC_HOOK_BLOCK = 35; public static final int UC_HOOK_INSN = 2;
public static final int UC_HOOK_MEM_INVALID = 36; public static final int UC_HOOK_CODE = 4;
public static final int UC_HOOK_MEM_READ = 37; public static final int UC_HOOK_BLOCK = 8;
public static final int UC_HOOK_MEM_WRITE = 38; public static final int UC_HOOK_MEM_READ_INVALID = 16;
public static final int UC_HOOK_MEM_READ_WRITE = 39; public static final int UC_HOOK_MEM_WRITE_INVALID = 32;
public static final int UC_HOOK_MEM_FETCH_INVALID = 64;
public static final int UC_HOOK_MEM_READ_PROT = 128;
public static final int UC_HOOK_MEM_WRITE_PROT = 256;
public static final int UC_HOOK_MEM_FETCH_PROT = 512;
public static final int UC_HOOK_MEM_READ = 1024;
public static final int UC_HOOK_MEM_WRITE = 2048;
public static final int UC_HOOK_MEM_FETCH = 4096;
public static final int UC_PROT_NONE = 0; public static final int UC_PROT_NONE = 0;
public static final int UC_PROT_READ = 1; public static final int UC_PROT_READ = 1;

View file

@ -33,10 +33,9 @@ static jmethodID invokeBlockCallbacks = 0;
static jmethodID invokeInterruptCallbacks = 0; static jmethodID invokeInterruptCallbacks = 0;
static jmethodID invokeCodeCallbacks = 0; static jmethodID invokeCodeCallbacks = 0;
static jmethodID invokeMemInvalidCallbacks = 0; static jmethodID invokeEventMemCallbacks = 0;
static jmethodID invokeReadCallbacks = 0; static jmethodID invokeReadCallbacks = 0;
static jmethodID invokeWriteCallbacks = 0; static jmethodID invokeWriteCallbacks = 0;
static jmethodID invokeReadWriteCallbacks = 0;
static jmethodID invokeInCallbacks = 0; static jmethodID invokeInCallbacks = 0;
static jmethodID invokeOutCallbacks = 0; static jmethodID invokeOutCallbacks = 0;
static jmethodID invokeSyscallCallbacks = 0; static jmethodID invokeSyscallCallbacks = 0;
@ -157,9 +156,6 @@ static void cb_hookmem(uc_engine *eng, uc_mem_type type,
case UC_MEM_WRITE: case UC_MEM_WRITE:
(*env)->CallStaticVoidMethod(env, clz, invokeWriteCallbacks, (jlong)eng, (jlong)address, (int)size, (jlong)value); (*env)->CallStaticVoidMethod(env, clz, invokeWriteCallbacks, (jlong)eng, (jlong)address, (int)size, (jlong)value);
break; break;
case UC_MEM_READ_WRITE:
(*env)->CallStaticVoidMethod(env, clz, invokeReadWriteCallbacks, (jlong)eng, (int)type, (jlong)address, (int)size, (jlong)value);
break;
} }
(*cachedJVM)->DetachCurrentThread(cachedJVM); (*cachedJVM)->DetachCurrentThread(cachedJVM);
} }
@ -179,7 +175,7 @@ static bool cb_eventmem(uc_engine *eng, uc_mem_type type,
if ((*env)->ExceptionCheck(env)) { if ((*env)->ExceptionCheck(env)) {
return false; return false;
} }
jboolean res = (*env)->CallStaticBooleanMethod(env, clz, invokeMemInvalidCallbacks, (jlong)eng, (int)type, (jlong)address, (int)size, (jlong)value); jboolean res = (*env)->CallStaticBooleanMethod(env, clz, invokeEventMemCallbacks, (jlong)eng, (int)type, (jlong)address, (int)size, (jlong)value);
(*cachedJVM)->DetachCurrentThread(cachedJVM); (*cachedJVM)->DetachCurrentThread(cachedJVM);
return res; return res;
} }
@ -393,9 +389,14 @@ JNIEXPORT jlong JNICALL Java_unicorn_Unicorn_registerHook__JI
} }
err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookintr, env); err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookintr, env);
break; break;
case UC_HOOK_MEM_INVALID: // Hook for all invalid memory access events case UC_HOOK_MEM_FETCH_INVALID: // Hook for all invalid memory access events
if (invokeMemInvalidCallbacks == 0) { case UC_HOOK_MEM_READ_INVALID: // Hook for all invalid memory access events
invokeMemInvalidCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeMemInvalidCallbacks", "(JIJIJ)Z"); case UC_HOOK_MEM_WRITE_INVALID: // Hook for all invalid memory access events
case UC_HOOK_MEM_FETCH_PROT: // Hook for all invalid memory access events
case UC_HOOK_MEM_READ_PROT: // Hook for all invalid memory access events
case UC_HOOK_MEM_WRITE_PROT: // Hook for all invalid memory access events
if (invokeEventMemCallbacks == 0) {
invokeEventMemCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeEventMemCallbacks", "(JIJIJ)Z");
} }
err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_eventmem, env); err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_eventmem, env);
break; break;
@ -471,12 +472,6 @@ JNIEXPORT jlong JNICALL Java_unicorn_Unicorn_registerHook__JIJJ
} }
err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookmem, env, arg1, arg2); err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookmem, env, arg1, arg2);
break; break;
case UC_HOOK_MEM_READ_WRITE: // Hook all memory accesses (either READ or WRITE).
if (invokeReadWriteCallbacks == 0) {
invokeReadWriteCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeReadWriteCallbacks", "(JIJIJ)V");
}
err = uc_hook_add((uc_engine*)eng, &hh, (uc_hook_type)type, cb_hookmem, env, arg1, arg2);
break;
} }
return (jlong)hh; return (jlong)hh;
} }

View file

@ -33,7 +33,7 @@ def hook_code(uc, address, size, user_data):
# callback for tracing invalid memory access (READ or WRITE) # callback for tracing invalid memory access (READ or WRITE)
def hook_mem_invalid(uc, access, address, size, value, user_data): def hook_mem_invalid(uc, access, address, size, value, user_data):
if access == UC_MEM_WRITE: if access == UC_MEM_WRITE_INVALID:
print(">>> Missing memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" \ print(">>> Missing memory is being WRITE at 0x%x, data size = %u, data value = 0x%x" \
%(address, size, value)) %(address, size, value))
# map this memory in with 2MB in size # map this memory in with 2MB in size
@ -231,7 +231,7 @@ def test_i386_invalid_mem_write():
#mu.hook_add(UC_HOOK_CODE, hook_code) #mu.hook_add(UC_HOOK_CODE, hook_code)
# intercept invalid memory events # intercept invalid memory events
mu.hook_add(UC_HOOK_MEM_INVALID, hook_mem_invalid) mu.hook_add(UC_HOOK_MEM_READ_INVALID | UC_HOOK_MEM_WRITE_INVALID, hook_mem_invalid)
try: try:
# emulate machine code in infinite time # emulate machine code in infinite time
@ -349,7 +349,7 @@ def test_x86_64():
mu.hook_add(UC_HOOK_MEM_WRITE, hook_mem_access) mu.hook_add(UC_HOOK_MEM_WRITE, hook_mem_access)
mu.hook_add(UC_HOOK_MEM_READ, hook_mem_access) mu.hook_add(UC_HOOK_MEM_READ, hook_mem_access)
# actually you can also use READ_WRITE to trace all memory access # actually you can also use READ_WRITE to trace all memory access
#mu.hook_add(UC_HOOK_MEM_READ_WRITE, hook_mem_access) #mu.hook_add(UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, hook_mem_access)
try: try:
# emulate machine code in infinite time # emulate machine code in infinite time

View file

@ -55,21 +55,21 @@ UC_SPARC_REG_FCC0 = 49
UC_SPARC_REG_FCC1 = 50 UC_SPARC_REG_FCC1 = 50
UC_SPARC_REG_FCC2 = 51 UC_SPARC_REG_FCC2 = 51
UC_SPARC_REG_FCC3 = 52 UC_SPARC_REG_FCC3 = 52
UC_SPARC_REG_FP = 53 UC_SPARC_REG_G0 = 53
UC_SPARC_REG_G0 = 54 UC_SPARC_REG_G1 = 54
UC_SPARC_REG_G1 = 55 UC_SPARC_REG_G2 = 55
UC_SPARC_REG_G2 = 56 UC_SPARC_REG_G3 = 56
UC_SPARC_REG_G3 = 57 UC_SPARC_REG_G4 = 57
UC_SPARC_REG_G4 = 58 UC_SPARC_REG_G5 = 58
UC_SPARC_REG_G5 = 59 UC_SPARC_REG_G6 = 59
UC_SPARC_REG_G6 = 60 UC_SPARC_REG_G7 = 60
UC_SPARC_REG_G7 = 61 UC_SPARC_REG_I0 = 61
UC_SPARC_REG_I0 = 62 UC_SPARC_REG_I1 = 62
UC_SPARC_REG_I1 = 63 UC_SPARC_REG_I2 = 63
UC_SPARC_REG_I2 = 64 UC_SPARC_REG_I3 = 64
UC_SPARC_REG_I3 = 65 UC_SPARC_REG_I4 = 65
UC_SPARC_REG_I4 = 66 UC_SPARC_REG_I5 = 66
UC_SPARC_REG_I5 = 67 UC_SPARC_REG_FP = 67
UC_SPARC_REG_I7 = 68 UC_SPARC_REG_I7 = 68
UC_SPARC_REG_ICC = 69 UC_SPARC_REG_ICC = 69
UC_SPARC_REG_L0 = 70 UC_SPARC_REG_L0 = 70
@ -86,11 +86,11 @@ UC_SPARC_REG_O2 = 80
UC_SPARC_REG_O3 = 81 UC_SPARC_REG_O3 = 81
UC_SPARC_REG_O4 = 82 UC_SPARC_REG_O4 = 82
UC_SPARC_REG_O5 = 83 UC_SPARC_REG_O5 = 83
UC_SPARC_REG_O7 = 84 UC_SPARC_REG_SP = 84
UC_SPARC_REG_SP = 85 UC_SPARC_REG_O7 = 85
UC_SPARC_REG_Y = 86 UC_SPARC_REG_Y = 86
UC_SPARC_REG_XCC = 87 UC_SPARC_REG_XCC = 87
UC_SPARC_REG_PC = 88 UC_SPARC_REG_PC = 88
UC_SPARC_REG_ENDING = 89 UC_SPARC_REG_ENDING = 89
UC_SPARC_REG_O6 = 85 UC_SPARC_REG_O6 = 84
UC_SPARC_REG_I6 = 53 UC_SPARC_REG_I6 = 67

View file

@ -141,6 +141,7 @@ class Uc(object):
raise UcError(status) raise UcError(status)
# internal mapping table to save callback & userdata # internal mapping table to save callback & userdata
self._callbacks = {} self._callbacks = {}
self._ctype_cbs = {}
self._callback_count = 0 self._callback_count = 0
@ -261,6 +262,7 @@ class Uc(object):
# save callback & user_data # save callback & user_data
self._callback_count += 1 self._callback_count += 1
self._callbacks[self._callback_count] = (callback, user_data) self._callbacks[self._callback_count] = (callback, user_data)
cb = None
if htype in (UC_HOOK_BLOCK, UC_HOOK_CODE): if htype in (UC_HOOK_BLOCK, UC_HOOK_CODE):
begin = ctypes.c_uint64(arg1) begin = ctypes.c_uint64(arg1)
@ -270,11 +272,13 @@ class Uc(object):
cb = ctypes.cast(UC_HOOK_CODE_CB(self._hookcode_cb), UC_HOOK_CODE_CB) cb = ctypes.cast(UC_HOOK_CODE_CB(self._hookcode_cb), UC_HOOK_CODE_CB)
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, cb, \ status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, cb, \
ctypes.cast(self._callback_count, ctypes.c_void_p), begin, end) ctypes.cast(self._callback_count, ctypes.c_void_p), begin, end)
elif htype == UC_HOOK_MEM_INVALID: elif htype & UC_HOOK_MEM_READ_INVALID or htype & UC_HOOK_MEM_WRITE_INVALID or \
htype & UC_HOOK_MEM_FETCH_INVALID or htype & UC_HOOK_MEM_READ_PROT or \
htype & UC_HOOK_MEM_WRITE_PROT or htype & UC_HOOK_MEM_FETCH_PROT:
cb = ctypes.cast(UC_HOOK_MEM_INVALID_CB(self._hook_mem_invalid_cb), UC_HOOK_MEM_INVALID_CB) cb = ctypes.cast(UC_HOOK_MEM_INVALID_CB(self._hook_mem_invalid_cb), UC_HOOK_MEM_INVALID_CB)
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \ status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
cb, ctypes.cast(self._callback_count, ctypes.c_void_p)) cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
elif htype in (UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE, UC_HOOK_MEM_READ_WRITE): elif htype in (UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE, UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE):
cb = ctypes.cast(UC_HOOK_MEM_ACCESS_CB(self._hook_mem_access_cb), UC_HOOK_MEM_ACCESS_CB) cb = ctypes.cast(UC_HOOK_MEM_ACCESS_CB(self._hook_mem_access_cb), UC_HOOK_MEM_ACCESS_CB)
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \ status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
cb, ctypes.cast(self._callback_count, ctypes.c_void_p)) cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
@ -293,6 +297,9 @@ class Uc(object):
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \ status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
cb, ctypes.cast(self._callback_count, ctypes.c_void_p)) cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
# save the ctype function so gc will leave it alone.
self._ctype_cbs[self._callback_count] = cb
if status != UC_ERR_OK: if status != UC_ERR_OK:
raise UcError(status) raise UcError(status)

View file

@ -46,26 +46,33 @@ UC_ERR_INSN_INVALID = 11
UC_ERR_MAP = 12 UC_ERR_MAP = 12
UC_ERR_WRITE_PROT = 13 UC_ERR_WRITE_PROT = 13
UC_ERR_READ_PROT = 14 UC_ERR_READ_PROT = 14
UC_ERR_EXEC_PROT = 15 UC_ERR_FETCH_PROT = 15
UC_ERR_ARG = 16 UC_ERR_ARG = 16
UC_ERR_READ_UNALIGNED = 17 UC_ERR_READ_UNALIGNED = 17
UC_ERR_WRITE_UNALIGNED = 18 UC_ERR_WRITE_UNALIGNED = 18
UC_ERR_FETCH_UNALIGNED = 19 UC_ERR_FETCH_UNALIGNED = 19
UC_MEM_READ = 16 UC_MEM_READ = 16
UC_MEM_WRITE = 17 UC_MEM_WRITE = 17
UC_MEM_READ_WRITE = 18 UC_MEM_FETCH = 18
UC_MEM_FETCH = 19 UC_MEM_READ_INVALID = 19
UC_MEM_WRITE_PROT = 20 UC_MEM_WRITE_INVALID = 20
UC_MEM_READ_PROT = 21 UC_MEM_FETCH_INVALID = 21
UC_MEM_EXEC_PROT = 22 UC_MEM_WRITE_PROT = 22
UC_HOOK_INTR = 32 UC_MEM_READ_PROT = 23
UC_HOOK_INSN = 33 UC_MEM_FETCH_PROT = 24
UC_HOOK_CODE = 34 UC_HOOK_INTR = 1
UC_HOOK_BLOCK = 35 UC_HOOK_INSN = 2
UC_HOOK_MEM_INVALID = 36 UC_HOOK_CODE = 4
UC_HOOK_MEM_READ = 37 UC_HOOK_BLOCK = 8
UC_HOOK_MEM_WRITE = 38 UC_HOOK_MEM_READ_INVALID = 16
UC_HOOK_MEM_READ_WRITE = 39 UC_HOOK_MEM_WRITE_INVALID = 32
UC_HOOK_MEM_FETCH_INVALID = 64
UC_HOOK_MEM_READ_PROT = 128
UC_HOOK_MEM_WRITE_PROT = 256
UC_HOOK_MEM_FETCH_PROT = 512
UC_HOOK_MEM_READ = 1024
UC_HOOK_MEM_WRITE = 2048
UC_HOOK_MEM_FETCH = 4096
UC_PROT_NONE = 0 UC_PROT_NONE = 0
UC_PROT_READ = 1 UC_PROT_READ = 1

30
hook.c
View file

@ -73,7 +73,7 @@ size_t hook_add(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, vo
if (begin > end) if (begin > end)
uc->hook_write_idx = i; uc->hook_write_idx = i;
break; break;
case UC_HOOK_MEM_READ_WRITE: case UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE:
uc->hook_mem_read = true; uc->hook_mem_read = true;
uc->hook_mem_write = true; uc->hook_mem_write = true;
if (begin > end) { if (begin > end) {
@ -109,8 +109,28 @@ uc_err hook_del(struct uc_struct *uc, uc_hook hh)
uc->hook_write_idx = 0; uc->hook_write_idx = 0;
} }
if (hh == uc->hook_mem_idx) { if (hh == uc->hook_mem_read_idx) {
uc->hook_mem_idx = 0; uc->hook_mem_read_idx = 0;
}
if (hh == uc->hook_mem_write_idx) {
uc->hook_mem_write_idx = 0;
}
if (hh == uc->hook_mem_fetch_idx) {
uc->hook_mem_fetch_idx = 0;
}
if (hh == uc->hook_mem_read_prot_idx) {
uc->hook_mem_read_prot_idx = 0;
}
if (hh == uc->hook_mem_write_prot_idx) {
uc->hook_mem_write_prot_idx = 0;
}
if (hh == uc->hook_mem_fetch_prot_idx) {
uc->hook_mem_fetch_prot_idx = 0;
} }
if (hh == uc->hook_intr_idx) { if (hh == uc->hook_intr_idx) {
@ -176,13 +196,13 @@ static struct hook_struct *_hook_find(struct uc_struct *uc, int type, uint64_t a
} }
break; break;
case UC_HOOK_MEM_READ: case UC_HOOK_MEM_READ:
if (uc->hook_callbacks[i].hook_type == UC_HOOK_MEM_READ || uc->hook_callbacks[i].hook_type == UC_HOOK_MEM_READ_WRITE) { if (uc->hook_callbacks[i].hook_type & UC_HOOK_MEM_READ) {
if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end) if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end)
return &uc->hook_callbacks[i]; return &uc->hook_callbacks[i];
} }
break; break;
case UC_HOOK_MEM_WRITE: case UC_HOOK_MEM_WRITE:
if (uc->hook_callbacks[i].hook_type == UC_HOOK_MEM_WRITE || uc->hook_callbacks[i].hook_type == UC_HOOK_MEM_READ_WRITE) { if (uc->hook_callbacks[i].hook_type & UC_HOOK_MEM_WRITE) {
if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end) if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end)
return &uc->hook_callbacks[i]; return &uc->hook_callbacks[i];
} }

View file

@ -152,7 +152,13 @@ struct uc_struct {
bool hook_block, hook_insn, hook_mem_read, hook_mem_write; bool hook_block, hook_insn, hook_mem_read, hook_mem_write;
uint64_t block_addr; // save the last block address we hooked uint64_t block_addr; // save the last block address we hooked
// indexes to event callbacks // indexes to event callbacks
int hook_mem_idx; // for handling invalid memory access int hook_mem_read_idx; // for handling invalid memory read access on unmapped memory
int hook_mem_write_idx; // for handling invalid memory write access on unmapped memory
int hook_mem_fetch_idx; // for handling invalid memory fetch access on unmapped memory
int hook_mem_read_prot_idx; // for handling invalid memory read access on read-protected memory
int hook_mem_write_prot_idx; // for handling invalid memory write access on write-protected memory
int hook_mem_fetch_prot_idx; // for handling invalid memory fetch access on non-executable memory
int hook_intr_idx; // for handling interrupt int hook_intr_idx; // for handling interrupt
int hook_out_idx; // for handling OUT instruction (X86) int hook_out_idx; // for handling OUT instruction (X86)
int hook_in_idx; // for handling IN instruction (X86) int hook_in_idx; // for handling IN instruction (X86)

View file

@ -75,7 +75,6 @@ typedef enum uc_sparc_reg {
UC_SPARC_REG_FCC1, UC_SPARC_REG_FCC1,
UC_SPARC_REG_FCC2, UC_SPARC_REG_FCC2,
UC_SPARC_REG_FCC3, UC_SPARC_REG_FCC3,
UC_SPARC_REG_FP,
UC_SPARC_REG_G0, UC_SPARC_REG_G0,
UC_SPARC_REG_G1, UC_SPARC_REG_G1,
UC_SPARC_REG_G2, UC_SPARC_REG_G2,
@ -90,6 +89,7 @@ typedef enum uc_sparc_reg {
UC_SPARC_REG_I3, UC_SPARC_REG_I3,
UC_SPARC_REG_I4, UC_SPARC_REG_I4,
UC_SPARC_REG_I5, UC_SPARC_REG_I5,
UC_SPARC_REG_FP,
UC_SPARC_REG_I7, UC_SPARC_REG_I7,
UC_SPARC_REG_ICC, // Integer condition codes UC_SPARC_REG_ICC, // Integer condition codes
UC_SPARC_REG_L0, UC_SPARC_REG_L0,
@ -106,8 +106,8 @@ typedef enum uc_sparc_reg {
UC_SPARC_REG_O3, UC_SPARC_REG_O3,
UC_SPARC_REG_O4, UC_SPARC_REG_O4,
UC_SPARC_REG_O5, UC_SPARC_REG_O5,
UC_SPARC_REG_O7,
UC_SPARC_REG_SP, UC_SPARC_REG_SP,
UC_SPARC_REG_O7,
UC_SPARC_REG_Y, UC_SPARC_REG_Y,
// special register // special register

View file

@ -120,7 +120,7 @@ typedef enum uc_err {
UC_ERR_MAP, // Invalid memory mapping: uc_mem_map() UC_ERR_MAP, // Invalid memory mapping: uc_mem_map()
UC_ERR_WRITE_PROT, // Quit emulation due to UC_MEM_WRITE_PROT violation: uc_emu_start() UC_ERR_WRITE_PROT, // Quit emulation due to UC_MEM_WRITE_PROT violation: uc_emu_start()
UC_ERR_READ_PROT, // Quit emulation due to UC_MEM_READ_PROT violation: uc_emu_start() UC_ERR_READ_PROT, // Quit emulation due to UC_MEM_READ_PROT violation: uc_emu_start()
UC_ERR_EXEC_PROT, // Quit emulation due to UC_MEM_EXEC_PROT violation: uc_emu_start() UC_ERR_FETCH_PROT, // Quit emulation due to UC_MEM_FETCH_PROT violation: uc_emu_start()
UC_ERR_ARG, // Inavalid argument provided to uc_xxx function (See specific function API) UC_ERR_ARG, // Inavalid argument provided to uc_xxx function (See specific function API)
UC_ERR_READ_UNALIGNED, // Unaligned read UC_ERR_READ_UNALIGNED, // Unaligned read
UC_ERR_WRITE_UNALIGNED, // Unaligned write UC_ERR_WRITE_UNALIGNED, // Unaligned write
@ -153,28 +153,48 @@ typedef void (*uc_cb_insn_out_t)(uc_engine *uc, uint32_t port, int size, uint32_
// All type of memory accesses for UC_HOOK_MEM_* // All type of memory accesses for UC_HOOK_MEM_*
typedef enum uc_mem_type { typedef enum uc_mem_type {
UC_MEM_READ = 16, // Unmapped memory is read from UC_MEM_READ = 16, // Memory is read from
UC_MEM_WRITE, // Unmapped memory is written to UC_MEM_WRITE, // Memory is written to
UC_MEM_READ_WRITE, // Unmapped memory is accessed (either READ or WRITE) UC_MEM_FETCH, // Memory is fetched
UC_MEM_FETCH, // Unmapped memory is fetched UC_MEM_READ_INVALID, // Unmapped memory is read from
UC_MEM_WRITE_INVALID, // Unmapped memory is written to
UC_MEM_FETCH_INVALID, // Unmapped memory is fetched
UC_MEM_WRITE_PROT, // Write to write protected, but mapped, memory UC_MEM_WRITE_PROT, // Write to write protected, but mapped, memory
UC_MEM_READ_PROT, // Read from read protected, but mapped, memory UC_MEM_READ_PROT, // Read from read protected, but mapped, memory
UC_MEM_EXEC_PROT, // Fetch from non-executable, but mapped, memory UC_MEM_FETCH_PROT, // Fetch from non-executable, but mapped, memory
} uc_mem_type; } uc_mem_type;
// All type of hooks for uc_hook_add() API. // All type of hooks for uc_hook_add() API.
typedef enum uc_hook_type { typedef enum uc_hook_type {
UC_HOOK_INTR = 32, // Hook all interrupt events UC_HOOK_INTR = 1 << 0, // Hook all interrupt events
UC_HOOK_INSN, // Hook a particular instruction UC_HOOK_INSN = 1 << 1, // Hook a particular instruction
UC_HOOK_CODE, // Hook a range of code UC_HOOK_CODE = 1 << 2, // Hook a range of code
UC_HOOK_BLOCK, // Hook basic blocks UC_HOOK_BLOCK = 1 << 3, // Hook basic blocks
UC_HOOK_MEM_INVALID, // Hook for all invalid memory access events UC_HOOK_MEM_READ_INVALID = 1 << 4, // Hook for invalid memory read events
UC_HOOK_MEM_READ, // Hook all memory read events. UC_HOOK_MEM_WRITE_INVALID = 1 << 5, // Hook for invalid memory write events
UC_HOOK_MEM_WRITE, // Hook all memory write events. UC_HOOK_MEM_FETCH_INVALID = 1 << 6, // Hook for invalid memory fetch for execution events
UC_HOOK_MEM_READ_WRITE, // Hook all memory accesses (either READ or WRITE). UC_HOOK_MEM_READ_PROT = 1 << 7, // Hook for memory read on read-protected memory
UC_HOOK_MEM_WRITE_PROT = 1 << 8, // Hook for memory write on write-protected memory
UC_HOOK_MEM_FETCH_PROT = 1 << 9, // Hook for memory fetch on non-executable memory
UC_HOOK_MEM_READ = 1 << 10, // Hook memory read events.
UC_HOOK_MEM_WRITE = 1 << 11, // Hook memory write events.
UC_HOOK_MEM_FETCH = 1 << 12, // Hook memory fetch for execution events
} uc_hook_type; } uc_hook_type;
// Callback function for hooking memory (UC_HOOK_MEM_*) // hook type for all events of unmapped memory access
#define UC_HOOK_MEM_INVALID (UC_HOOK_MEM_READ_INVALID + UC_HOOK_MEM_WRITE_INVALID + UC_HOOK_MEM_FETCH_INVALID)
// hook type for all events of illegal protected memory access
#define UC_HOOK_MEM_PROT (UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_FETCH_PROT)
// hook type for all events of illegal read memory access
#define UC_HOOK_MEM_READ_ERR (UC_HOOK_MEM_READ_PROT + UC_HOOK_MEM_READ_INVALID)
// hook type for all events of illegal write memory access
#define UC_HOOK_MEM_WRITE_ERR (UC_HOOK_MEM_WRITE_PROT + UC_HOOK_MEM_WRITE_INVALID)
// hook type for all events of illegal fetch memory access
#define UC_HOOK_MEM_FETCH_ERR (UC_HOOK_MEM_FETCH_PROT + UC_HOOK_MEM_FETCH_INVALID)
// hook type for all events of illegal memory access
#define UC_HOOK_MEM_ERR (UC_HOOK_MEM_INVALID + UC_HOOK_MEM_PROT)
// Callback function for hooking memory (UC_MEM_READ, UC_MEM_WRITE & UC_MEM_FETCH)
// @type: this memory is being READ, or WRITE // @type: this memory is being READ, or WRITE
// @address: address where the code is being executed // @address: address where the code is being executed
// @size: size of data being read or written // @size: size of data being read or written
@ -183,7 +203,8 @@ typedef enum uc_hook_type {
typedef void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type, typedef void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type,
uint64_t address, int size, int64_t value, void *user_data); uint64_t address, int size, int64_t value, void *user_data);
// Callback function for handling memory events (for UC_HOOK_MEM_INVALID) // Callback function for handling invalid memory access events (UC_MEM_*_INVALID and
// UC_MEM_*PROT events)
// @type: this memory is being READ, or WRITE // @type: this memory is being READ, or WRITE
// @address: address where the code is being executed // @address: address where the code is being executed
// @size: size of data being read or written // @size: size of data being read or written
@ -380,7 +401,7 @@ uc_err uc_emu_stop(uc_engine *uc);
for detailed error). for detailed error).
*/ */
UNICORN_EXPORT UNICORN_EXPORT
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, uc_hook_type type, void *callback, void *user_data, ...); uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...);
/* /*
Unregister (remove) a hook callback. Unregister (remove) a hook callback.

View file

@ -300,7 +300,7 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
(addr & TARGET_PAGE_MASK))) { (addr & TARGET_PAGE_MASK))) {
cpu_ldub_code(env1, addr); cpu_ldub_code(env1, addr);
//check for NX related error from softmmu //check for NX related error from softmmu
if (env1->invalid_error == UC_ERR_EXEC_PROT) { if (env1->invalid_error == UC_ERR_FETCH_PROT) {
env1->invalid_error = UC_ERR_CODE_INVALID; env1->invalid_error = UC_ERR_CODE_INVALID;
return -1; return -1;
} }

View file

@ -33,11 +33,13 @@
static void sun4u_init(struct uc_struct *uc, MachineState *machine) static void sun4u_init(struct uc_struct *uc, MachineState *machine)
{ {
const char *cpu_model = machine->cpu_model; const char *cpu_model = machine->cpu_model;
SPARCCPU *cpu;
if (cpu_model == NULL) if (cpu_model == NULL)
cpu_model = "sun4uv"; cpu_model = "Sun UltraSparc IV";
if (cpu_sparc_init(uc, cpu_model) == NULL) { cpu = cpu_sparc_init(uc, cpu_model);
if (cpu == NULL) {
fprintf(stderr, "Unable to find Sparc CPU definition\n"); fprintf(stderr, "Unable to find Sparc CPU definition\n");
exit(1); exit(1);
} }
@ -45,7 +47,7 @@ static void sun4u_init(struct uc_struct *uc, MachineState *machine)
void sun4u_machine_init(struct uc_struct *uc) void sun4u_machine_init(struct uc_struct *uc)
{ {
QEMUMachine sun4u_machine = { static QEMUMachine sun4u_machine = {
.name = "sun4u", .name = "sun4u",
.init = sun4u_init, .init = sun4u_init,
.max_cpus = 1, // XXX for now .max_cpus = 1, // XXX for now

View file

@ -177,7 +177,7 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
target_ulong tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; target_ulong tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ;
uintptr_t haddr; uintptr_t haddr;
DATA_TYPE res; DATA_TYPE res;
int mem_access, error_code; int error_code;
struct uc_struct *uc = env->uc; struct uc_struct *uc = env->uc;
MemoryRegion *mr = memory_mapping(uc, addr); MemoryRegion *mr = memory_mapping(uc, addr);
@ -185,15 +185,16 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
// memory can be unmapped while reading or fetching // memory can be unmapped while reading or fetching
if (mr == NULL) { if (mr == NULL) {
#if defined(SOFTMMU_CODE_ACCESS) #if defined(SOFTMMU_CODE_ACCESS)
mem_access = UC_MEM_FETCH;
error_code = UC_ERR_FETCH_INVALID; error_code = UC_ERR_FETCH_INVALID;
if (uc->hook_mem_fetch_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_idx].callback)(
uc, UC_MEM_FETCH_INVALID, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_fetch_idx].user_data)) {
#else #else
mem_access = UC_MEM_READ;
error_code = UC_ERR_READ_INVALID; error_code = UC_ERR_READ_INVALID;
if (uc->hook_mem_read_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_idx].callback)(
uc, UC_MEM_READ_INVALID, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_read_idx].user_data)) {
#endif #endif
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
uc, mem_access, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
env->invalid_error = UC_ERR_OK; env->invalid_error = UC_ERR_OK;
mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time? mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time?
} else { } else {
@ -208,13 +209,13 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
#if defined(SOFTMMU_CODE_ACCESS) #if defined(SOFTMMU_CODE_ACCESS)
// Unicorn: callback on fetch from NX // Unicorn: callback on fetch from NX
if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( if (uc->hook_mem_fetch_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].callback)(
uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) { uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].user_data)) {
env->invalid_error = UC_ERR_OK; env->invalid_error = UC_ERR_OK;
} else { } else {
env->invalid_addr = addr; env->invalid_addr = addr;
env->invalid_error = UC_ERR_EXEC_PROT; env->invalid_error = UC_ERR_FETCH_PROT;
// printf("***** Invalid fetch (non-executable) at " TARGET_FMT_lx "\n", addr); // printf("***** Invalid fetch (non-executable) at " TARGET_FMT_lx "\n", addr);
cpu_exit(uc->current_cpu); cpu_exit(uc->current_cpu);
return 0; return 0;
@ -233,9 +234,9 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
// Unicorn: callback on non-readable memory // Unicorn: callback on non-readable memory
if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( if (uc->hook_mem_read_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_prot_idx].callback)(
uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) { uc->hook_callbacks[uc->hook_mem_read_prot_idx].user_data)) {
env->invalid_error = UC_ERR_OK; env->invalid_error = UC_ERR_OK;
} }
else { else {
@ -367,7 +368,7 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
target_ulong tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ; target_ulong tlb_addr = env->tlb_table[mmu_idx][index].ADDR_READ;
uintptr_t haddr; uintptr_t haddr;
DATA_TYPE res; DATA_TYPE res;
int mem_access, error_code; int error_code;
struct uc_struct *uc = env->uc; struct uc_struct *uc = env->uc;
MemoryRegion *mr = memory_mapping(uc, addr); MemoryRegion *mr = memory_mapping(uc, addr);
@ -375,15 +376,16 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
// memory can be unmapped while reading or fetching // memory can be unmapped while reading or fetching
if (mr == NULL) { if (mr == NULL) {
#if defined(SOFTMMU_CODE_ACCESS) #if defined(SOFTMMU_CODE_ACCESS)
mem_access = UC_MEM_FETCH;
error_code = UC_ERR_FETCH_INVALID; error_code = UC_ERR_FETCH_INVALID;
if (uc->hook_mem_fetch_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_idx].callback)(
uc, UC_MEM_FETCH_INVALID, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_fetch_idx].user_data)) {
#else #else
mem_access = UC_MEM_READ;
error_code = UC_ERR_READ_INVALID; error_code = UC_ERR_READ_INVALID;
if (uc->hook_mem_read_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_idx].callback)(
uc, UC_MEM_READ_INVALID, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_read_idx].user_data)) {
#endif #endif
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
uc, mem_access, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
env->invalid_error = UC_ERR_OK; env->invalid_error = UC_ERR_OK;
mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time? mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time?
} else { } else {
@ -398,13 +400,13 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
#if defined(SOFTMMU_CODE_ACCESS) #if defined(SOFTMMU_CODE_ACCESS)
// Unicorn: callback on fetch from NX // Unicorn: callback on fetch from NX
if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( if (uc->hook_mem_fetch_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].callback)(
uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0, uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) { uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].user_data)) {
env->invalid_error = UC_ERR_OK; env->invalid_error = UC_ERR_OK;
} else { } else {
env->invalid_addr = addr; env->invalid_addr = addr;
env->invalid_error = UC_ERR_EXEC_PROT; env->invalid_error = UC_ERR_FETCH_PROT;
// printf("***** Invalid fetch (non-executable) at " TARGET_FMT_lx "\n", addr); // printf("***** Invalid fetch (non-executable) at " TARGET_FMT_lx "\n", addr);
cpu_exit(uc->current_cpu); cpu_exit(uc->current_cpu);
return 0; return 0;
@ -423,9 +425,9 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
// Unicorn: callback on non-readable memory // Unicorn: callback on non-readable memory
if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( if (uc->hook_mem_read_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_prot_idx].callback)(
uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) { uc->hook_callbacks[uc->hook_mem_read_prot_idx].user_data)) {
env->invalid_error = UC_ERR_OK; env->invalid_error = UC_ERR_OK;
} else { } else {
env->invalid_addr = addr; env->invalid_addr = addr;
@ -608,10 +610,10 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
} }
// Unicorn: callback on invalid memory // Unicorn: callback on invalid memory
if (uc->hook_mem_idx && mr == NULL) { if (uc->hook_mem_write_idx && mr == NULL) {
if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_idx].callback)(
uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val, uc, UC_MEM_WRITE_INVALID, addr, DATA_SIZE, (int64_t)val,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) { uc->hook_callbacks[uc->hook_mem_write_idx].user_data)) {
// save error & quit // save error & quit
env->invalid_addr = addr; env->invalid_addr = addr;
env->invalid_error = UC_ERR_WRITE_INVALID; env->invalid_error = UC_ERR_WRITE_INVALID;
@ -620,14 +622,15 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
return; return;
} else { } else {
env->invalid_error = UC_ERR_OK; env->invalid_error = UC_ERR_OK;
mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time?
} }
} }
// Unicorn: callback on non-writable memory // Unicorn: callback on non-writable memory
if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( if (uc->hook_mem_write_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_prot_idx].callback)(
uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val, uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) { uc->hook_callbacks[uc->hook_mem_write_prot_idx].user_data)) {
env->invalid_error = UC_ERR_OK; env->invalid_error = UC_ERR_OK;
} }
else { else {
@ -754,10 +757,10 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
} }
// Unicorn: callback on invalid memory // Unicorn: callback on invalid memory
if (uc->hook_mem_idx && mr == NULL) { if (uc->hook_mem_write_idx && mr == NULL) {
if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_idx].callback)(
uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val, uc, UC_MEM_WRITE_INVALID, addr, DATA_SIZE, (int64_t)val,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) { uc->hook_callbacks[uc->hook_mem_write_idx].user_data)) {
// save error & quit // save error & quit
env->invalid_addr = addr; env->invalid_addr = addr;
env->invalid_error = UC_ERR_WRITE_INVALID; env->invalid_error = UC_ERR_WRITE_INVALID;
@ -766,14 +769,15 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
return; return;
} else { } else {
env->invalid_error = UC_ERR_OK; env->invalid_error = UC_ERR_OK;
mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time?
} }
} }
// Unicorn: callback on non-writable memory // Unicorn: callback on non-writable memory
if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)( if (uc->hook_mem_write_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_prot_idx].callback)(
uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val, uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) { uc->hook_callbacks[uc->hook_mem_write_prot_idx].user_data)) {
env->invalid_error = UC_ERR_OK; env->invalid_error = UC_ERR_OK;
} }
else { else {

View file

@ -11105,6 +11105,13 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
tcg_clear_temp_count(); tcg_clear_temp_count();
// Unicorn: early check to see if the address of this block is the until address
if (tb->pc == env->uc->addr_end) {
gen_tb_start(tcg_ctx);
gen_exception_insn(dc, 0, EXCP_SWI, 0);
goto done_generating;
}
// Unicorn: trace this block on request // Unicorn: trace this block on request
// Only hook this block if it is not broken from previous translation due to // Only hook this block if it is not broken from previous translation due to
// full translation cache // full translation cache

View file

@ -11228,6 +11228,13 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
tcg_clear_temp_count(); tcg_clear_temp_count();
// Unicorn: early check to see if the address of this block is the until address
if (tb->pc == env->uc->addr_end) {
gen_tb_start(tcg_ctx);
gen_exception_insn(dc, 0, EXCP_SWI, 0);
goto done_generating;
}
// Unicorn: trace this block on request // Unicorn: trace this block on request
// Only hook this block if it is not broken from previous translation due to // Only hook this block if it is not broken from previous translation due to
// full translation cache // full translation cache

View file

@ -3101,6 +3101,13 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb,
if (max_insns == 0) if (max_insns == 0)
max_insns = CF_COUNT_MASK; max_insns = CF_COUNT_MASK;
// Unicorn: early check to see if the address of this block is the until address
if (tb->pc == env->uc->addr_end) {
gen_tb_start(tcg_ctx);
gen_exception(dc, dc->pc, EXCP_TRAP15);
goto done_generating;
}
// Unicorn: trace this block on request // Unicorn: trace this block on request
// Only hook this block if it is not broken from previous translation due to // Only hook this block if it is not broken from previous translation due to
// full translation cache // full translation cache
@ -3179,6 +3186,8 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb,
break; break;
} }
} }
done_generating:
gen_tb_end(tcg_ctx, tb, num_insns); gen_tb_end(tcg_ctx, tb, num_insns);
*tcg_ctx->gen_opc_ptr = INDEX_op_end; *tcg_ctx->gen_opc_ptr = INDEX_op_end;

View file

@ -1415,7 +1415,7 @@ enum {
* exception condition */ * exception condition */
BS_STOP = 1, /* We want to stop translation for any reason */ BS_STOP = 1, /* We want to stop translation for any reason */
BS_BRANCH = 2, /* We reached a branch condition */ BS_BRANCH = 2, /* We reached a branch condition */
BS_EXCP = 3, /* We reached an exception condition */ // qq BS_EXCP = 3, /* We reached an exception condition */
}; };
static const char * const regnames[] = { static const char * const regnames[] = {
@ -11322,7 +11322,7 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
return 4; return 4;
} }
static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, int is_slot)
{ {
TCGContext *tcg_ctx = ctx->uc->tcg_ctx; TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
TCGv **cpu_gpr = (TCGv **)tcg_ctx->cpu_gpr; TCGv **cpu_gpr = (TCGv **)tcg_ctx->cpu_gpr;
@ -11343,7 +11343,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
n_bytes = 2; n_bytes = 2;
// Unicorn: trace this instruction on request // Unicorn: trace this instruction on request
if (env->uc->hook_insn) { if (!is_slot && env->uc->hook_insn) {
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc); struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc);
if (trace) if (trace)
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data); gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data);
@ -13928,7 +13928,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx,
} }
} }
static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, int is_slot)
{ {
TCGContext *tcg_ctx = env->uc->tcg_ctx; TCGContext *tcg_ctx = env->uc->tcg_ctx;
TCGv **cpu_gpr = (TCGv **)tcg_ctx->cpu_gpr; TCGv **cpu_gpr = (TCGv **)tcg_ctx->cpu_gpr;
@ -13943,7 +13943,7 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx)
} }
// Unicorn: trace this instruction on request // Unicorn: trace this instruction on request
if (env->uc->hook_insn) { if (!is_slot && env->uc->hook_insn) {
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc); struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc);
if (trace) if (trace)
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data); gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data);
@ -18503,7 +18503,7 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx)
} }
} }
static void decode_opc (CPUMIPSState *env, DisasContext *ctx) static void decode_opc (CPUMIPSState *env, DisasContext *ctx, int is_slot)
{ {
TCGContext *tcg_ctx = ctx->uc->tcg_ctx; TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
#if defined(TARGET_MIPS64) #if defined(TARGET_MIPS64)
@ -18514,6 +18514,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
uint32_t op, op1; uint32_t op, op1;
int16_t imm; int16_t imm;
/* make sure instructions are on a word boundary */ /* make sure instructions are on a word boundary */
if (ctx->pc & 0x3) { if (ctx->pc & 0x3) {
env->CP0_BadVAddr = ctx->pc; env->CP0_BadVAddr = ctx->pc;
@ -18522,7 +18523,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
} }
// Unicorn: trace this instruction on request // Unicorn: trace this instruction on request
if (env->uc->hook_insn) { if (!is_slot && env->uc->hook_insn) {
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc); struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc);
if (trace) if (trace)
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data); gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data);
@ -19207,6 +19208,13 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
max_insns = CF_COUNT_MASK; max_insns = CF_COUNT_MASK;
LOG_DISAS("\ntb %p idx %d hflags %04x\n", tb, ctx.mem_idx, ctx.hflags); LOG_DISAS("\ntb %p idx %d hflags %04x\n", tb, ctx.mem_idx, ctx.hflags);
// Unicorn: early check to see if the address of this block is the until address
if (tb->pc == env->uc->addr_end) {
gen_tb_start(tcg_ctx);
generate_exception(&ctx, EXCP_SYSCALL);
goto done_generating;
}
// Unicorn: trace this block on request // Unicorn: trace this block on request
// Only hook this block if it is not broken from previous translation due to // Only hook this block if it is not broken from previous translation due to
// full translation cache // full translation cache
@ -19220,7 +19228,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
} }
gen_tb_start(tcg_ctx); gen_tb_start(tcg_ctx);
while (ctx.bstate == BS_NONE) { // qq while (ctx.bstate == BS_NONE) {
if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) { if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
QTAILQ_FOREACH(bp, &cs->breakpoints, entry) { QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
if (bp->pc == ctx.pc) { if (bp->pc == ctx.pc) {
@ -19261,16 +19269,16 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
save_opparam_ptr = tcg_ctx->gen_opparam_ptr; save_opparam_ptr = tcg_ctx->gen_opparam_ptr;
is_slot = ctx.hflags & MIPS_HFLAG_BMASK; is_slot = ctx.hflags & MIPS_HFLAG_BMASK;
if (!(ctx.hflags & MIPS_HFLAG_M16)) { // qq if (!(ctx.hflags & MIPS_HFLAG_M16)) {
ctx.opcode = cpu_ldl_code(env, ctx.pc); ctx.opcode = cpu_ldl_code(env, ctx.pc);
insn_bytes = 4; insn_bytes = 4;
decode_opc(env, &ctx); decode_opc(env, &ctx, is_slot);
} else if (ctx.insn_flags & ASE_MICROMIPS) { // qq } else if (ctx.insn_flags & ASE_MICROMIPS) {
ctx.opcode = cpu_lduw_code(env, ctx.pc); ctx.opcode = cpu_lduw_code(env, ctx.pc);
insn_bytes = decode_micromips_opc(env, &ctx); insn_bytes = decode_micromips_opc(env, &ctx, is_slot);
} else if (ctx.insn_flags & ASE_MIPS16) { // qq } else if (ctx.insn_flags & ASE_MIPS16) {
ctx.opcode = cpu_lduw_code(env, ctx.pc); ctx.opcode = cpu_lduw_code(env, ctx.pc);
insn_bytes = decode_mips16_opc(env, &ctx); insn_bytes = decode_mips16_opc(env, &ctx, is_slot);
} else { } else {
generate_exception(&ctx, EXCP_RI); generate_exception(&ctx, EXCP_RI);
ctx.bstate = BS_STOP; ctx.bstate = BS_STOP;

View file

@ -42,6 +42,7 @@ void sparc_reg_reset(struct uc_struct *uc)
env->pc = 0; env->pc = 0;
env->npc = 0; env->npc = 0;
env->regwptr = env->regbase;
} }
int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
@ -50,6 +51,12 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7)
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0]; *(int32_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0];
else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7)
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0];
else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7)
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0];
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0];
else { else {
switch(regid) { switch(regid) {
default: break; default: break;
@ -62,18 +69,18 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
return 0; return 0;
} }
#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff))
#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff))
#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff))
#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff))
int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
{ {
CPUState *mycpu = first_cpu; CPUState *mycpu = first_cpu;
if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7)
SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint32_t *)value; SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint32_t *)value;
else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7)
SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0] = *(uint32_t *)value;
else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7)
SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint32_t *)value;
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint32_t *)value;
else { else {
switch(regid) { switch(regid) {
default: break; default: break;
@ -84,7 +91,6 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
} }
} }
return 0; return 0;
} }

View file

@ -6,6 +6,7 @@
#include "sysemu/cpus.h" #include "sysemu/cpus.h"
#include "unicorn.h" #include "unicorn.h"
#include "cpu.h" #include "cpu.h"
#include "unicorn_common.h"
#define READ_QWORD(x) ((uint64)x) #define READ_QWORD(x) ((uint64)x)
@ -15,6 +16,22 @@
#define READ_BYTE_L(x) (x & 0xff) #define READ_BYTE_L(x) (x & 0xff)
static bool sparc_stop_interrupt(int intno)
{
switch(intno) {
default:
return false;
case TT_ILL_INSN:
return true;
}
}
static void sparc_set_pc(struct uc_struct *uc, uint64_t address)
{
((CPUSPARCState *)uc->current_cpu->env_ptr)->pc = address;
((CPUSPARCState *)uc->current_cpu->env_ptr)->npc = address + 4;
}
void sparc_reg_reset(struct uc_struct *uc) void sparc_reg_reset(struct uc_struct *uc)
{ {
CPUArchState *env = first_cpu->env_ptr; CPUArchState *env = first_cpu->env_ptr;
@ -25,6 +42,7 @@ void sparc_reg_reset(struct uc_struct *uc)
env->pc = 0; env->pc = 0;
env->npc = 0; env->npc = 0;
env->regwptr = env->regbase;
} }
int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value) int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
@ -32,12 +50,18 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
CPUState *mycpu = first_cpu; CPUState *mycpu = first_cpu;
if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7)
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0]; *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0];
else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7)
*(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0];
else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7)
*(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0];
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
*(int64_t *)value = SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0];
else { else {
switch(regid) { switch(regid) {
default: break; default: break;
case UC_SPARC_REG_PC: case UC_SPARC_REG_PC:
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.pc; *(int64_t *)value = SPARC_CPU(uc, mycpu)->env.pc;
break; break;
} }
} }
@ -45,24 +69,24 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
return 0; return 0;
} }
#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff))
#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff))
#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff))
#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff))
int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value) int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
{ {
CPUState *mycpu = first_cpu; CPUState *mycpu = first_cpu;
if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7) if (regid >= UC_SPARC_REG_G0 && regid <= UC_SPARC_REG_G7)
SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint32_t *)value; SPARC_CPU(uc, mycpu)->env.gregs[regid - UC_SPARC_REG_G0] = *(uint64_t *)value;
else if (regid >= UC_SPARC_REG_O0 && regid <= UC_SPARC_REG_O7)
SPARC_CPU(uc, mycpu)->env.regwptr[regid - UC_SPARC_REG_O0] = *(uint64_t *)value;
else if (regid >= UC_SPARC_REG_L0 && regid <= UC_SPARC_REG_L7)
SPARC_CPU(uc, mycpu)->env.regwptr[8 + regid - UC_SPARC_REG_L0] = *(uint64_t *)value;
else if (regid >= UC_SPARC_REG_I0 && regid <= UC_SPARC_REG_I7)
SPARC_CPU(uc, mycpu)->env.regwptr[16 + regid - UC_SPARC_REG_I0] = *(uint64_t *)value;
else { else {
switch(regid) { switch(regid) {
default: break; default: break;
case UC_SPARC_REG_PC: case UC_SPARC_REG_PC:
SPARC_CPU(uc, mycpu)->env.pc = *(uint32_t *)value; SPARC_CPU(uc, mycpu)->env.pc = *(uint64_t *)value;
SPARC_CPU(uc, mycpu)->env.npc = *(uint32_t *)value + 4; SPARC_CPU(uc, mycpu)->env.npc = *(uint64_t *)value + 4;
break; break;
} }
} }
@ -80,4 +104,7 @@ void sparc64_uc_init(struct uc_struct* uc)
uc->reg_read = sparc_reg_read; uc->reg_read = sparc_reg_read;
uc->reg_write = sparc_reg_write; uc->reg_write = sparc_reg_write;
uc->reg_reset = sparc_reg_reset; uc->reg_reset = sparc_reg_reset;
uc->set_pc = sparc_set_pc;
uc->stop_interrupt = sparc_stop_interrupt;
uc_common_init(uc);
} }

View file

@ -1431,7 +1431,6 @@ static inline void tcg_la_func_end(TCGContext *s, uint8_t *dead_temps,
memset(mem_temps + s->nb_globals, 0, s->nb_temps - s->nb_globals); memset(mem_temps + s->nb_globals, 0, s->nb_temps - s->nb_globals);
} }
#if 0
/* liveness analysis: end of basic block: all temps are dead, globals /* liveness analysis: end of basic block: all temps are dead, globals
and local temps should be in memory. */ and local temps should be in memory. */
static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps, static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps,
@ -1445,7 +1444,6 @@ static inline void tcg_la_bb_end(TCGContext *s, uint8_t *dead_temps,
mem_temps[i] = s->temps[i].temp_local; mem_temps[i] = s->temps[i].temp_local;
} }
} }
#endif
/* Liveness analysis : update the opc_dead_args array to tell if a /* Liveness analysis : update the opc_dead_args array to tell if a
given input arguments is dead. Instructions updating dead given input arguments is dead. Instructions updating dead
@ -1684,12 +1682,12 @@ static void tcg_liveness_analysis(TCGContext *s)
} }
/* if end of basic block, update */ /* if end of basic block, update */
if (def->flags & TCG_OPF_BB_END) { if (def->flags & TCG_OPF_BB_END && op != INDEX_op_brcond_i32) {
// Unicorn: do not optimize dead temps. // Unicorn: do not optimize dead temps on brcond,
// this causes problem because check_exit_request() inserts // this causes problem because check_exit_request() inserts
// brcond instruction in the middle of the TB, // brcond instruction in the middle of the TB,
// which incorrectly flags end-of-block // which incorrectly flags end-of-block
// tcg_la_bb_end(s, dead_temps, mem_temps); tcg_la_bb_end(s, dead_temps, mem_temps);
} else if (def->flags & TCG_OPF_SIDE_EFFECTS) { } else if (def->flags & TCG_OPF_SIDE_EFFECTS) {
/* globals should be synced to memory */ /* globals should be synced to memory */
memset(mem_temps, 1, s->nb_globals); memset(mem_temps, 1, s->nb_globals);

View file

@ -1073,7 +1073,6 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
TCGContext *tcg_ctx = env->uc->tcg_ctx; TCGContext *tcg_ctx = env->uc->tcg_ctx;
TranslationBlock *tb; TranslationBlock *tb;
tb_page_addr_t phys_pc, phys_page2; tb_page_addr_t phys_pc, phys_page2;
target_ulong virt_page2;
int code_gen_size; int code_gen_size;
phys_pc = get_page_addr_code(env, pc); phys_pc = get_page_addr_code(env, pc);
@ -1094,12 +1093,14 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
tcg_ctx->code_gen_ptr = (void *)(((uintptr_t)tcg_ctx->code_gen_ptr + tcg_ctx->code_gen_ptr = (void *)(((uintptr_t)tcg_ctx->code_gen_ptr +
code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
/* check next page if needed */
virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
phys_page2 = -1; phys_page2 = -1;
/* check next page if needed */
if (tb->size) {
target_ulong virt_page2 = (pc + tb->size - 1) & TARGET_PAGE_MASK;
if ((pc & TARGET_PAGE_MASK) != virt_page2) { if ((pc & TARGET_PAGE_MASK) != virt_page2) {
phys_page2 = get_page_addr_code(env, virt_page2); phys_page2 = get_page_addr_code(env, virt_page2);
} }
}
tb_link_page(cpu->uc, tb, phys_pc, phys_page2); tb_link_page(cpu->uc, tb, phys_pc, phys_page2);
return tb; return tb;
} }

View file

@ -1,15 +0,0 @@
#!/usr/bin/python
from unicorn import *
from unicorn.arm_const import *
uc = Uc(UC_ARCH_ARM, UC_MODE_ARM)
uc.mem_map(0x1000, 0x1000)
uc.mem_write(0x1000, '1eff2f010000a0e1'.decode('hex'))
def hook_block(uc, addr, *args):
print 'enter block 0x%04x' % addr
uc.reg_write(UC_ARM_REG_LR, 0x1004)
uc.hook_add(UC_HOOK_BLOCK, hook_block)
print 'block should only run once'
uc.emu_start(0x1000, 0x1004, timeout=250)

View file

@ -1,17 +0,0 @@
#!/usr/bin/python
from unicorn import *
from unicorn.arm_const import *
uc = Uc(UC_ARCH_ARM, UC_MODE_ARM)
uc.mem_map(0x1000, 0x1000)
uc.mem_write(0x1000, '00c000e3'.decode('hex'))
def hook_block(uc, addr, *args):
print 'enter block 0x%04x' % addr
uc.reg_write(UC_ARM_REG_R12, 0x123)
print 'r12 =', uc.reg_read(UC_ARM_REG_R12)
uc.hook_add(UC_HOOK_BLOCK, hook_block)
print 'block should only run once'
uc.emu_start(0x1000, 0x1004, timeout=250)
print 'r12 =', uc.reg_read(UC_ARM_REG_R12)

View file

@ -1,56 +0,0 @@
#!/usr/bin/env python
# reg_write() can't modify PC from within trace callbacks
from __future__ import print_function
from unicorn import *
from unicorn.arm_const import *
BASE_ADDRESS = 0x10000000
# sub sp, #0xc
THUMB_CODE = "\x83\xb0" * 5
# callback for tracing instructions
def hook_code(uc, address, size, user_data):
print(">>> Tracing instruction at 0x%x, instruction size = %u" % (address, size))
mu = user_data
print(">>> Setting PC to 0xffffffff")
mu.reg_write(ARM_REG_PC, 0xffffffff)
# callback for tracing basic blocks
def hook_block(uc, address, size, user_data):
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
mu = user_data
print(">>> Setting PC to 0xffffffff")
mu.reg_write(ARM_REG_PC, 0xffffffff)
# set up emulation
def instruction_trace_test():
try:
# initialize emulator in ARM's Thumb mode
mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB)
# map some memory
mu.mem_map(BASE_ADDRESS, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(BASE_ADDRESS, THUMB_CODE)
# setup stack
mu.reg_write(UC_ARM_REG_SP, BASE_ADDRESS + 2 * 1024 * 1024)
# tracing all instructions with customized callback
mu.hook_add(UC_HOOK_CODE, hook_code, user_data=mu)
# tracing all basic blocks with customized callback
mu.hook_add(UC_HOOK_BLOCK, hook_block, user_data=mu)
# emulate machine code in infinite time
mu.emu_start(BASE_ADDRESS, BASE_ADDRESS + len(THUMB_CODE))
except UcError as e:
print("ERROR: %s" % e)
if __name__ == '__main__':
instruction_trace_test()

View file

@ -1,32 +0,0 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
CODE_ADDR = 0x0
binary1 = b'\xb8\x02\x00\x00\x00'
binary2 = b'\xb8\x01\x00\x00\x00'
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(CODE_ADDR, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(CODE_ADDR, binary1)
# emu for maximum 1 sec.
mu.emu_start(CODE_ADDR, len(binary1), UC_SECOND_SCALE)
print("RAX = %x" %mu.reg_read(UC_X86_REG_RAX))
# write machine code to be emulated to memory
mu.mem_write(CODE_ADDR, binary2)
# emu for maximum 1 sec.
mu.emu_start(CODE_ADDR, len(binary2), UC_SECOND_SCALE)
print("RAX = %x" %mu.reg_read(UC_X86_REG_RAX))

View file

@ -1,11 +0,0 @@
#!/usr/bin/python
# From issue #1 of Ryan Hileman
from unicorn import *
CODE = b"\x90\x91\x92"
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(0x100000, 4 * 1024)
mu.mem_write(0x100000, CODE)
mu.emu_start(0x100000, 0x1000 + len(CODE))

View file

@ -1,13 +0,0 @@
#!/usr/bin/python
"""See https://github.com/unicorn-engine/unicorn/issues/65"""
import unicorn
ADDR = 0x10101000
mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
mu.mem_map(ADDR, 1024 * 4)
mu.mem_write(ADDR, b'\x41')
mu.emu_start(ADDR, ADDR + 1, count=1)
# The following should not trigger a null pointer dereference
mu.emu_stop()

View file

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

View file

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

View file

@ -1,32 +0,0 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
ESP = 0x2000
PAGE_SIZE = 1 * 1024 * 1024
# fstcw [esp]
# pop ecx
CODE = b'\x9B\xD9\x3C\x24\x59'
def mem_reader(addr, size):
tmp = mu.mem_read(addr, size)
for i in tmp:
print(" 0x%x" % i),
print("")
def hook_mem_write(uc, access, address, size, value, user_data):
print("mem WRITE: 0x%x, data size = %u, data value = 0x%x" % (address, size, value))
return True
mu = Uc(UC_ARCH_X86, UC_MODE_32)
mu.mem_map(0, PAGE_SIZE)
mu.mem_write(0, CODE)
mu.reg_write(UC_X86_REG_ESP, ESP)
mu.hook_add(UC_HOOK_MEM_WRITE, hook_mem_write)
mu.emu_start(0x0, 0, 0, 2)
esp = mu.reg_read(UC_X86_REG_ESP)
print("value at ESP [0x%X]: " % esp)
mem_reader(esp, 10)

View file

@ -1,53 +0,0 @@
#!/usr/bin/python
from __future__ import print_function
from unicorn import *
from unicorn.x86_const import *
# callback for tracing instructions
def hook_code(uc, address, size, user_data):
tmp = uc.mem_read(address, size)
print("[0x%x] =" %(address), end="")
for i in tmp:
print(" %02x" %i, end="")
print("")
# callback for tracing Linux interrupt
def hook_intr(uc, intno, user_data):
# only handle Linux syscall
rip = uc.reg_read(UC_X86_REG_RIP)
if intno != 0x80:
print("=== 0x%x: got interrupt %x, quit" %(rip, intno));
uc.emu_stop()
return
eax = uc.reg_read(UC_X86_REG_EAX)
print(">>> 0x%x: interrupt 0x%x, EAX = 0x%x" %(rip, intno, eax))
binary1 = b'\xeb\x1c\x5a\x89\xd6\x8b\x02\x66\x3d\xca\x7d\x75\x06\x66\x05\x03\x03\x89\x02\xfe\xc2\x3d\x41\x41\x41\x41\x75\xe9\xff\xe6\xe8\xdf\xff\xff\xff\x31\xd2\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xca\x7d\x41\x41\x41\x41\x41\x41\x41\x41'
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(0, 2 * 1024 * 1024)
# tracing all instructions with customized callback
mu.hook_add(UC_HOOK_CODE, hook_code)
# handle interrupt ourself
mu.hook_add(UC_HOOK_INTR, hook_intr)
# setup stack
mu.reg_write(UC_X86_REG_RSP, 1024 * 1024)
# fill in memory with 0xCC (software breakpoint int 3)
for i in xrange(1 * 1024):
mu.mem_write(0 + i, b'\xcc')
# write machine code to be emulated to memory
mu.mem_write(0, binary1)
mu.emu_start(0, len(binary1))

View file

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

View file

@ -1,14 +0,0 @@
#!/usr/bin/python
# By Ryan Hileman, issue #9
# this prints out 2 lines and the contents must be the same
from unicorn import *
uc = Uc(UC_ARCH_X86, UC_MODE_64)
uc.mem_map(0x8048000, 0x2000)
uc.mem_write(0x8048000, 'test')
print 1, str(uc.mem_read(0x8048000, 4)).encode('hex')
uc.mem_map(0x804a000, 0x8000)
print 2, str(uc.mem_read(0x8048000, 4)).encode('hex')

View file

@ -1,8 +0,0 @@
#!/usr/bin/env python
import unicorn
u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
u.mem_map(0x2000, 0)
u.mem_map(0x4000, 1)
print "I am never reached"

View file

@ -1,25 +0,0 @@
#!/usr/bin/env python
import unicorn
u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
u.mem_map(0x2000, 0x1000)
u.mem_read(0x2000, 1)
for i in range(20):
try:
u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
u.mem_map(i*0x1000, 5)
u.mem_read(i*0x1000, 1)
print hex(i*0x1000) + " succeeeded"
except unicorn.UcError:
print hex(i*0x1000) + " failed"
for i in range(20):
try:
u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
u.mem_map(i*0x1000, 5)
u.mem_read(i*0x1000, 1)
print hex(i*0x1000) + " succeeeded"
except unicorn.UcError:
print hex(i*0x1000) + " failed"

View file

@ -1,8 +0,0 @@
#!/usr/bin/python
from unicorn import *
uc = Uc(UC_ARCH_X86, UC_MODE_32)
uc.mem_map(0x0000, 0x2000)
uc.mem_map(0x2000, 0x4000)
uc.mem_write(0x1000, 0x1004 * ' ')
print 'If not reached, then we have BUG (crash on x86_64 Linux).'

View file

@ -1,12 +0,0 @@
#!/usr/bin/env python
import unicorn
for i in range(20):
#try:
u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
u.mem_map(i*0x1000, 5)
u.mem_read(i*0x1000+6, 1)
print hex(i*0x1000) + " succeeeded"
#except unicorn.UcError as e:
# print hex(i*0x1000) + " failed:",e

View file

@ -1,29 +0,0 @@
#!/usr/bin/python
from capstone import *
from unicorn import *
from unicorn.mips_const import *
md = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_LITTLE_ENDIAN)
def disas(code, addr):
for i in md.disasm(code, addr):
print '0x%x: %s %s' % (i.address, str(i.bytes).encode('hex'), i.op_str)
def hook_code(uc, addr, size, _):
mem = str(uc.mem_read(addr, size))
disas(mem, addr)
CODE = 0x400000
asm = '0000a4126a00822800000000'.decode('hex')
print 'Input instructions:'
disas(asm, CODE)
print
print 'Hooked instructions:'
uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN)
uc.hook_add(UC_HOOK_CODE, hook_code)
uc.mem_map(CODE, 0x1000)
uc.mem_write(CODE, asm)
uc.emu_start(CODE, CODE + len(asm))

View file

@ -1,38 +0,0 @@
#!/usr/bin/python
from unicorn import *
from unicorn.mips_const import *
def hook_intr(uc, intno, _):
print 'interrupt', intno
CODE = 0x400000
asm = '0000a48f'.decode('hex') # lw $a0, ($sp)
uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN)
uc.hook_add(UC_HOOK_INTR, hook_intr)
uc.mem_map(CODE, 0x1000)
uc.mem_write(CODE, asm)
try:
print 'unaligned access (exc 12)'
uc.reg_write(UC_MIPS_REG_SP, 0x400001)
uc.emu_start(CODE, CODE + len(asm), 300)
print
except UcError as e:
print("ERROR: %s" % e)
try:
print 'dunno (exc 26)'
uc.reg_write(UC_MIPS_REG_SP, 0xFFFFFFF0)
uc.emu_start(CODE, CODE + len(asm), 200)
print
except UcError as e:
print("ERROR: %s" % e)
try:
print 'unassigned access (exc 28)'
uc.reg_write(UC_MIPS_REG_SP, 0x80000000)
uc.emu_start(CODE, CODE + len(asm), 100)
print
except UcError as e:
print("ERROR: %s" % e)

View file

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

View file

@ -1,23 +0,0 @@
#!/usr/bin/env python
"""See https://github.com/unicorn-engine/unicorn/issues/98"""
import unicorn
ADDR = 0xffaabbcc
def hook_mem_invalid(mu, access, address, size, value, user_data):
print ">>> Access type: %u, expected value: 0x%x, actual value: 0x%x" % (access, ADDR, address)
assert(address == ADDR)
mu.mem_map(address & 0xfffff000, 4 * 1024)
mu.mem_write(address, b'\xcc')
return True
mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
mu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, ADDR)
mu.mem_map(0x10000000, 1024 * 4)
# jmp ebx
mu.mem_write(0x10000000, b'\xff\xe3')
mu.hook_add(unicorn.UC_HOOK_MEM_INVALID, hook_mem_invalid)
mu.emu_start(0x10000000, 0x10000000 + 2, count=1)

View file

@ -1,11 +0,0 @@
#!/usr/bin/python
from unicorn import *
from unicorn.sparc_const import *
uc = Uc(UC_ARCH_SPARC, UC_MODE_32)
uc.reg_write(UC_SPARC_REG_SP, 100)
uc.reg_write(UC_SPARC_REG_FP, 100)
print 'writing sp = 100, fp = 100'
print 'sp =', uc.reg_read(UC_SPARC_REG_SP)
print 'fp =', uc.reg_read(UC_SPARC_REG_FP)

View file

@ -1,32 +0,0 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
binary1 = b'\xb8\x02\x00\x00\x00' # mov eax, 2
binary2 = b'\xb8\x01\x00\x00\x00' # mov eax, 1
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(0, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(0, binary1 + binary2)
# emu for maximum 1 instruction.
mu.emu_start(0, 5, 0, 1)
print("RAX = %u" %mu.reg_read(UC_X86_REG_RAX))
pos = mu.reg_read(UC_X86_REG_RIP)
print("RIP = %x" %pos)
mu.emu_start(5, 10, 0, 1)
pos = mu.reg_read(UC_X86_REG_RIP)
print("RIP = %x" %pos)
print("RAX = %u" %mu.reg_read(UC_X86_REG_RAX))

View file

@ -1,32 +0,0 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
binary1 = b'\xb8\x02\x00\x00\x00' # mov eax, 2
binary2 = b'\xb8\x01\x00\x00\x00' # mov eax, 1
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(0, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(0, binary1 + binary2)
# emu for maximum 1 instruction.
mu.emu_start(0, 10, 0, 1)
print("RAX = %u" %mu.reg_read(UC_X86_REG_RAX))
pos = mu.reg_read(UC_X86_REG_RIP)
print("RIP = %x" %pos)
mu.emu_start(5, 10, 0, 1)
pos = mu.reg_read(UC_X86_REG_RIP)
print("RIP = %x" %pos)
print("RAX = %u" %mu.reg_read(UC_X86_REG_RAX))

View file

@ -1,23 +0,0 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
binary1 = b'\x40\x01\xc1\x31\xf6' # inc eax; add ecx, eax; xor esi, esi
mu = Uc(UC_ARCH_X86, UC_MODE_32)
mu.mem_map(0, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(0, binary1)
# emu for maximum 1 instruction.
mu.emu_start(0, 10, 0, 1)
print("EAX = %u" %mu.reg_read(UC_X86_REG_EAX))
pos = mu.reg_read(UC_X86_REG_EIP)
print("EIP = %x" %pos)

View file

@ -1,32 +0,0 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
binary1 = b'\x40\x01\xc1\x31\xf6\x90\x90\x90' # inc eax; add ecx, eax; xor esi, esi
mu = Uc(UC_ARCH_X86, UC_MODE_32)
mu.mem_map(0, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(0, binary1)
pos = 0
# emu for maximum 1 instruction.
mu.emu_start(pos, len(binary1), 0, 1)
print("EAX = %u" %mu.reg_read(UC_X86_REG_EAX))
pos = mu.reg_read(UC_X86_REG_EIP)
print("EIP = %x" %pos)
# emu to the end
mu.emu_start(pos, len(binary1))
print("EAX = %u" %mu.reg_read(UC_X86_REG_EAX))
pos = mu.reg_read(UC_X86_REG_EIP)
print("EIP = %x" %pos)

View file

@ -1,39 +0,0 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
from unicorn.arm_const import *
# adds r1, #0x48
# ldrsb r7, [r7, r7]
# ldrsh r7, [r2, r1]
# ldr r0, [pc, #0x168]
# cmp r7, #0xbf
# str r7, [r5, #0x20]
# ldr r1, [r5, #0x64]
# strb r7, [r5, #0xc]
# ldr r0, [pc, #0x1a0]
binary1 = b'\x48\x31\xff\x57\x57\x5e\x5a\x48\xbf\x2f\x2f\x62\x69\x6e\x2f\x73\x68\x48\xc1\xef\x08\x57\x54\x5f\x6a\x3b\x58\x0f\x05'
binary1 = b'\x48\x31\xff\x57'
#adds r1, #0x48
#ldrsb r7, [r7, r7]
mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB)
mu.mem_map(0, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(0, binary1)
mu.reg_write(ARM_REG_R13, 1*1024*1024)
pos = 0
# emu for maximum 1 instruction.
mu.emu_start(pos, len(binary1), 0, 1)
print("R1 = %x" % mu.reg_read(ARM_REG_R1))
pos = mu.reg_read(ARM_REG_R15)
print("RIP = %x" %pos)

View file

@ -1,22 +0,0 @@
#!/usr/bin/python
# By Ryan Hileman, issue #16
from unicorn import *
from unicorn.arm_const import *
try:
uc = Uc(UC_ARCH_ARM, UC_MODE_32)
uc.reg_write(UC_ARM_REG_SP, 4)
print 'Writing 4 to SP'
print 'SP =', uc.reg_read(UC_ARM_REG_SP)
except UcError as e:
print("ERROR: %s" % e)
try:
print "==========="
uc = Uc(UC_ARCH_ARM, UC_MODE_ARM)
uc.reg_write(UC_ARM_REG_SP, 4)
print 'Writing 4 to SP'
print 'SP =', uc.reg_read(UC_ARM_REG_SP)
except UcError as e:
print("ERROR: %s" % e)

View file

@ -1,12 +0,0 @@
#!/usr/bin/python
from unicorn import *
from unicorn.arm64_const import *
try:
uc = Uc(UC_ARCH_ARM64, UC_MODE_ARM)
uc.reg_write(UC_ARM64_REG_SP, 4)
print 'Writing 4 to SP'
print 'SP =', uc.reg_read(UC_ARM64_REG_SP)
except UcError as e:
print("ERROR: %s" % e)

View file

@ -79,13 +79,13 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
default: default:
printf("not ok - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", type, addr); printf("not ok - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", type, addr);
return false; return false;
case UC_MEM_READ: case UC_MEM_READ_INVALID:
printf("not ok - Read from invalid memory at 0x%"PRIx64 ", data size = %u\n", addr, size); printf("not ok - Read from invalid memory at 0x%"PRIx64 ", data size = %u\n", addr, size);
return false; return false;
case UC_MEM_WRITE: case UC_MEM_WRITE_INVALID:
printf("not ok - Write to invalid memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); printf("not ok - Write to invalid memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value);
return false; return false;
case UC_MEM_EXEC_PROT: case UC_MEM_FETCH_PROT:
printf("not ok - Fetch from non-executable memory at 0x%"PRIx64 "\n", addr); printf("not ok - Fetch from non-executable memory at 0x%"PRIx64 "\n", addr);
return false; return false;
case UC_MEM_WRITE_PROT: case UC_MEM_WRITE_PROT:
@ -147,7 +147,8 @@ static void do_nx_demo(bool cause_fault)
// intercept code and invalid memory events // intercept code and invalid memory events
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK || if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK ||
uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { uc_hook_add(uc, &trace1, UC_HOOK_MEM_ERR,
hook_mem_invalid, NULL) != UC_ERR_OK) {
printf("not ok - Failed to install hooks\n"); printf("not ok - Failed to install hooks\n");
return; return;
} }
@ -226,7 +227,9 @@ static void do_perms_demo(bool change_perms)
// intercept code and invalid memory events // intercept code and invalid memory events
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK || if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK ||
uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { uc_hook_add(uc, &trace1,
UC_HOOK_MEM_READ_INVALID | UC_HOOK_MEM_WRITE_INVALID | UC_HOOK_MEM_FETCH_INVALID | UC_HOOK_MEM_FETCH_PROT | UC_HOOK_MEM_WRITE_PROT | UC_HOOK_MEM_READ_PROT,
hook_mem_invalid, NULL) != UC_ERR_OK) {
printf("not ok - Failed to install hooks\n"); printf("not ok - Failed to install hooks\n");
return; return;
} }
@ -302,7 +305,9 @@ static void do_unmap_demo(bool do_unmap)
// intercept code and invalid memory events // intercept code and invalid memory events
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK || if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK ||
uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { uc_hook_add(uc, &trace1,
UC_HOOK_MEM_READ_INVALID | UC_HOOK_MEM_WRITE_INVALID | UC_HOOK_MEM_FETCH_INVALID | UC_HOOK_MEM_FETCH_PROT | UC_HOOK_MEM_WRITE_PROT | UC_HOOK_MEM_READ_PROT,
hook_mem_invalid, NULL) != UC_ERR_OK) {
printf("not ok - Failed to install hooks\n"); printf("not ok - Failed to install hooks\n");
return; return;
} }

View file

@ -73,7 +73,7 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
default: default:
// return false to indicate we want to stop emulation // return false to indicate we want to stop emulation
return false; return false;
case UC_MEM_WRITE: case UC_MEM_WRITE_INVALID:
printf(">>> Missing memory is being WRITE at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", printf(">>> Missing memory is being WRITE at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n",
address, size, value); address, size, value);
// map this memory in with 2MB in size // map this memory in with 2MB in size
@ -421,7 +421,7 @@ static void test_i386_invalid_mem_write(void)
uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0); uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0);
// intercept invalid memory events // intercept invalid memory events
uc_hook_add(uc, &trace3, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL); uc_hook_add(uc, &trace3, UC_HOOK_MEM_READ_INVALID | UC_HOOK_MEM_WRITE_INVALID, hook_mem_invalid, NULL);
// emulate machine code in infinite time // emulate machine code in infinite time
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_WRITE) - 1, 0, 0); err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_WRITE) - 1, 0, 0);

View file

@ -1,5 +1,5 @@
CFLAGS += -I../include CFLAGS += -I../include
LDFLAGS += ../libunicorn.a $(shell pkg-config --libs glib-2.0) -lpthread -lm LDFLAGS += ../../libunicorn.a $(shell pkg-config --libs glib-2.0) -lpthread -lm
TESTS = map_crash map_write TESTS = map_crash map_write
TESTS += sigill sigill2 TESTS += sigill sigill2

27
tests/regress/arm_bxeq_hang.py Executable file
View file

@ -0,0 +1,27 @@
#!/usr/bin/python
from unicorn import *
from unicorn.arm_const import *
import regress
class BxHang(regress.RegressTest):
def runTest(self):
uc = Uc(UC_ARCH_ARM, UC_MODE_ARM)
uc.mem_map(0x1000, 0x1000)
uc.mem_write(0x1000, '1eff2f010000a0e1'.decode('hex'))
uc.count = 0
def hook_block(uc, addr, *args):
print 'enter block 0x%04x' % addr
uc.count += 1
uc.reg_write(UC_ARM_REG_LR, 0x1004)
uc.hook_add(UC_HOOK_BLOCK, hook_block)
print 'block should only run once'
uc.emu_start(0x1000, 0x1004)
self.assertEqual(uc.count, 1)
if __name__ == '__main__':
regress.main()

View file

@ -0,0 +1,32 @@
#!/usr/bin/python
from unicorn import *
from unicorn.arm_const import *
import regress
class MovHang(regress.RegressTest):
def runTest(self):
uc = Uc(UC_ARCH_ARM, UC_MODE_ARM)
uc.mem_map(0x1000, 0x1000)
uc.mem_write(0x1000, '00c000e3'.decode('hex')) # movw r12, #0
def hook_block(uc, addr, *args):
print 'enter block 0x%04x' % addr
uc.count += 1
uc.reg_write(UC_ARM_REG_R12, 0x123)
self.assertEquals(uc.reg_read(UC_ARM_REG_R12), 0x123)
uc.hook_add(UC_HOOK_BLOCK, hook_block)
uc.count = 0
#print 'block should only run once'
uc.emu_start(0x1000, 0x1004, timeout=500)
self.assertEquals(uc.reg_read(UC_ARM_REG_R12), 0x0)
self.assertEquals(uc.count, 1)
if __name__ == '__main__':
regress.main()

64
tests/regress/callback-pc.py Executable file
View file

@ -0,0 +1,64 @@
#!/usr/bin/env python
# reg_write() can't modify PC from within trace callbacks
# Pull Request #4
from __future__ import print_function
from unicorn import *
from unicorn.arm_const import *
import regress
BASE_ADDRESS = 0x10000000
# sub sp, #0xc
THUMB_CODE = "\x83\xb0" * 5
# callback for tracing instructions
def hook_code(uc, address, size, user_data):
print(">>> Tracing instruction at 0x%x, instruction size = %u" % (address, size))
mu = user_data
print(">>> Setting PC to 0xffffffff")
mu.reg_write(UC_ARM_REG_PC, 0xffffffff)
# callback for tracing basic blocks
def hook_block(uc, address, size, user_data):
print(">>> Tracing basic block at 0x%x, block size = 0x%x" %(address, size))
mu = user_data
print(">>> Setting PC to 0xffffffff")
mu.reg_write(UC_ARM_REG_PC, 0xffffffff)
class CallBackPCTest(regress.RegressTest):
def runTest(self):
self.instruction_trace_test()
# set up emulation
def instruction_trace_test(self):
try:
# initialize emulator in ARM's Thumb mode
mu = Uc(UC_ARCH_ARM, UC_MODE_THUMB)
# map some memory
mu.mem_map(BASE_ADDRESS, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(BASE_ADDRESS, THUMB_CODE)
# setup stack
mu.reg_write(UC_ARM_REG_SP, BASE_ADDRESS + 2 * 1024 * 1024)
# tracing all instructions with customized callback
mu.hook_add(UC_HOOK_CODE, hook_code, user_data=mu)
# tracing all basic blocks with customized callback
mu.hook_add(UC_HOOK_BLOCK, hook_block, user_data=mu)
# emulate machine code in infinite time
mu.emu_start(BASE_ADDRESS, BASE_ADDRESS + len(THUMB_CODE))
except UcError as e:
assertFalse(0, "ERROR: %s" % e)
if __name__ == '__main__':
regress.main()

37
tests/regress/crash_tb.py Executable file
View file

@ -0,0 +1,37 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
import regress
CODE_ADDR = 0x0
binary1 = b'\xb8\x02\x00\x00\x00'
binary2 = b'\xb8\x01\x00\x00\x00'
class CrashTB(regress.RegressTest):
def runTest(self):
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(CODE_ADDR, 2 * 1024 * 1024)
# write machine code to be emulated to memory
mu.mem_write(CODE_ADDR, binary1)
# emu for maximum 1 sec.
mu.emu_start(CODE_ADDR, len(binary1), UC_SECOND_SCALE)
self.assertEqual(0x2, mu.reg_read(UC_X86_REG_RAX))
# write machine code to be emulated to memory
mu.mem_write(CODE_ADDR, binary2)
# emu for maximum 1 sec.
mu.emu_start(CODE_ADDR, len(binary2), UC_SECOND_SCALE)
self.assertEqual(0x1, mu.reg_read(UC_X86_REG_RAX))
if __name__ == '__main__':
regress.main()

20
tests/regress/deadlock_1.py Executable file
View file

@ -0,0 +1,20 @@
#!/usr/bin/python
# From issue #1 of Ryan Hileman
from unicorn import *
import regress
CODE = b"\x90\x91\x92"
class DeadLock(regress.RegressTest):
def runTest(self):
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(0x100000, 4 * 1024)
mu.mem_write(0x100000, CODE)
with self.assertRaises(UcError):
mu.emu_start(0x100000, 0x1000 + len(CODE))
if __name__ == '__main__':
regress.main()

View file

@ -0,0 +1,20 @@
#!/usr/bin/python
"""See https://github.com/unicorn-engine/unicorn/issues/65"""
import unicorn
import regress
class EmuStopSegFault(regress.RegressTest):
def runTest(self):
ADDR = 0x10101000
mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
mu.mem_map(ADDR, 1024 * 4)
mu.mem_write(ADDR, b'\x41')
mu.emu_start(ADDR, ADDR + 1, count=1)
# The following should not trigger a null pointer dereference
self.assertEqual(None, mu.emu_stop())
if __name__ == '__main__':
regress.main()

69
tests/regress/fpu_ip.py Executable file
View file

@ -0,0 +1,69 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
from capstone import *
import regress
ESP = 0x2000
PAGE_SIZE = 2 * 1024 * 1024
# mov [esp], DWORD 0x37f
# fldcw [esp]
# fnop
# fnstenv [esp + 8]
# pop ecx
CODE = b'\xc7\x04\x24\x7f\x03\x00\x00\xd9\x2c\x24\xd9\xd0\xd9\x74\x24\x08\x59'
class SimpleEngine:
def __init__(self):
self.capmd = Cs(CS_ARCH_X86, CS_MODE_32)
def disas_single(self, data):
for i in self.capmd.disasm(data, 16):
print("\t%s\t%s" % (i.mnemonic, i.op_str))
break
disasm = SimpleEngine()
def hook_code(uc, addr, size, user_data):
mem = uc.mem_read(addr, size)
print(" 0x%X:" % (addr)),
disasm.disas_single(str(mem))
class FpuIP(regress.RegressTest):
def mem_reader(self, mu, addr, size, expected):
tmp = mu.mem_read(addr, size)
for out, exp in zip(tmp, expected):
self.assertEqual(exp, out)
def test_32(self):
mu = Uc(UC_ARCH_X86, UC_MODE_32)
mu.mem_map(0x0, PAGE_SIZE)
mu.mem_write(0x4000, CODE)
mu.reg_write(UC_X86_REG_ESP, ESP)
mu.hook_add(UC_HOOK_CODE, hook_code)
mu.emu_start(0x4000, 0, 0, 5)
esp = mu.reg_read(UC_X86_REG_ESP)
self.assertEqual(0x2004, esp)
expected = [0x0, 0x0, 0xa, 0x40]
self.mem_reader(mu, esp + 14, 4, expected)
def test_64(self):
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(0x0, PAGE_SIZE)
mu.mem_write(0x4000, CODE)
mu.reg_write(UC_X86_REG_ESP, ESP)
mu.hook_add(UC_HOOK_CODE, hook_code)
mu.emu_start(0x4000, 0, 0, 5)
rsp = mu.reg_read(UC_X86_REG_RSP)
self.assertEqual(0x2012, rsp + 10)
expected = [0x0, 0x0, 0xa, 0x40, 0x0, 0x0, 0x0, 0x0]
self.mem_reader(mu, rsp + 10, 4, expected)
if __name__ == '__main__':
regress.main()

38
tests/regress/fpu_mem_write.py Executable file
View file

@ -0,0 +1,38 @@
#!/usr/bin/python
from unicorn import *
from unicorn.x86_const import *
import regress
ESP = 0x2000
PAGE_SIZE = 1 * 1024 * 1024
# wait
# fnstcw word ptr [esp]
# pop ecx
CODE = b'\x9B\xD9\x3C\x24\x59'
def hook_mem_write(uc, access, address, size, value, user_data):
print("mem WRITE: 0x%x, data size = %u, data value = 0x%x" % (address, size, value))
return True
class FpuWrite(regress.RegressTest):
def mem_reader(self, mu, addr, size, expected):
tmp = mu.mem_read(addr, size)
for i, e in zip(tmp, expected):
self.assertEquals(e, i)
def runTest(self):
mu = Uc(UC_ARCH_X86, UC_MODE_32)
mu.mem_map(0, PAGE_SIZE)
mu.mem_write(0, CODE)
mu.reg_write(UC_X86_REG_ESP, ESP)
mu.hook_add(UC_HOOK_MEM_WRITE, hook_mem_write)
mu.emu_start(0x0, 5, 0, 2)
esp = mu.reg_read(UC_X86_REG_ESP)
self.mem_reader(mu, esp, 10, [0] * 10)
if __name__ == '__main__':
regress.main()

57
tests/regress/hang.py Executable file
View file

@ -0,0 +1,57 @@
#!/usr/bin/python
from __future__ import print_function
from unicorn import *
from unicorn.x86_const import *
import regress
# callback for tracing instructions
def hook_code(uc, address, size, user_data):
tmp = uc.mem_read(address, size)
print("[0x%x] =" %(address), end="")
for i in tmp:
print(" %02x" %i, end="")
print("")
# callback for tracing Linux interrupt
def hook_intr(uc, intno, user_data):
# only handle Linux syscall
rip = uc.reg_read(UC_X86_REG_RIP)
if intno != 0x80:
print("=== 0x%x: got interrupt %x, quit" %(rip, intno));
uc.emu_stop()
return
eax = uc.reg_read(UC_X86_REG_EAX)
print(">>> 0x%x: interrupt 0x%x, EAX = 0x%x" %(rip, intno, eax))
class Hang(regress.RegressTest):
def runTest(self):
binary1 = b'\xeb\x1c\x5a\x89\xd6\x8b\x02\x66\x3d\xca\x7d\x75\x06\x66\x05\x03\x03\x89\x02\xfe\xc2\x3d\x41\x41\x41\x41\x75\xe9\xff\xe6\xe8\xdf\xff\xff\xff\x31\xd2\x6a\x0b\x58\x99\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53\x89\xe1\xca\x7d\x41\x41\x41\x41\x41\x41\x41\x41'
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.mem_map(0, 2 * 1024 * 1024)
# tracing all instructions with customized callback
mu.hook_add(UC_HOOK_CODE, hook_code)
# handle interrupt ourself
mu.hook_add(UC_HOOK_INTR, hook_intr)
# setup stack
mu.reg_write(UC_X86_REG_RSP, 1024 * 1024)
# fill in memory with 0xCC (software breakpoint int 3)
for i in xrange(1 * 1024):
mu.mem_write(0 + i, b'\xcc')
# write machine code to be emulated to memory
mu.mem_write(0, binary1)
self.assertEqual(mu.emu_start(0, len(binary1)), None)
if __name__ == '__main__':
regress.main()

39
tests/regress/jmp_ebx_hang.py Executable file
View file

@ -0,0 +1,39 @@
#!/usr/bin/env python
"""See https://github.com/unicorn-engine/unicorn/issues/82"""
import unicorn
from unicorn import *
import regress
CODE_ADDR = 0x10101000
CODE = b'\xff\xe3' # jmp ebx
class JumEbxHang(regress.RegressTest):
def runTest(self):
mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
mu.mem_map(CODE_ADDR, 1024 * 4)
mu.mem_write(CODE_ADDR, CODE)
# If EBX is zero then an exception is raised, as expected
mu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, 0x0)
print(">>> jmp ebx (ebx = 0)");
with self.assertRaises(UcError) as m:
mu.emu_start(CODE_ADDR, CODE_ADDR + 2, count=1)
self.assertEqual(m.exception.errno, unicorn.UC_ERR_CODE_INVALID)
print(">>> jmp ebx (ebx = 0xaa96a47f)");
mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
mu.mem_map(CODE_ADDR, 1024 * 4)
# If we write this address to EBX then the emulator hangs on emu_start
mu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, 0xaa96a47f)
mu.mem_write(CODE_ADDR, CODE)
with self.assertRaises(UcError) as m:
mu.emu_start(CODE_ADDR, CODE_ADDR + 2, count=1)
self.assertEqual(m.exception.errno, unicorn.UC_ERR_CODE_INVALID)
if __name__ == '__main__':
regress.main()

View file

@ -116,9 +116,9 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
{ {
switch(type) { switch(type) {
default: default:
printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); printf("not ok %d - memory invalid type: %d at 0x%" PRIx64 "\n", log_num++, type, addr);
return false; return false;
case UC_MEM_EXEC_PROT: case UC_MEM_FETCH_PROT:
printf("# Fetch from non-executable memory at 0x%"PRIx64 "\n", addr); printf("# Fetch from non-executable memory at 0x%"PRIx64 "\n", addr);
//make page executable //make page executable
@ -221,11 +221,11 @@ int main(int argc, char **argv, char **envp)
} }
// intercept invalid memory events // intercept invalid memory events
if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_PROT | UC_HOOK_MEM_FETCH_PROT, hook_mem_invalid, NULL) != UC_ERR_OK) {
printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID ucr\n", log_num++); printf("not ok %d - Failed to install memory invalid handler\n", log_num++);
return 8; return 8;
} else { } else {
printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); printf("ok %d - memory invalid handler installed\n", log_num++);
} }
// emulate machine code until told to stop by hook_code // emulate machine code until told to stop by hook_code

View file

@ -138,7 +138,7 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
uint32_t testval; uint32_t testval;
switch(type) { switch(type) {
default: default:
printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); printf("not ok %d - memory invalid type: %d at 0x%" PRIx64 "\n", log_num++, type, addr);
return false; return false;
case UC_MEM_WRITE_PROT: case UC_MEM_WRITE_PROT:
printf("# write to non-writeable memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); printf("# write to non-writeable memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value);
@ -229,11 +229,11 @@ int main(int argc, char **argv, char **envp)
} }
// intercept invalid memory events // intercept invalid memory events
if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_PROT, hook_mem_invalid, NULL) != UC_ERR_OK) {
printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID ucr\n", log_num++); printf("not ok %d - Failed to install memory invalid handler\n", log_num++);
return 7; return 7;
} else { } else {
printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); printf("ok %d - memory invalid handler installed\n", log_num++);
} }
// emulate machine code until told to stop by hook_code // emulate machine code until told to stop by hook_code

View file

@ -133,7 +133,7 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
uint32_t testval; uint32_t testval;
switch(type) { switch(type) {
default: default:
printf("not ok %d - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", log_num++, type, addr); printf("not ok %d - memory invalid type: %d at 0x%" PRIx64 "\n", log_num++, type, addr);
return false; return false;
case UC_MEM_WRITE: case UC_MEM_WRITE:
printf("# write to invalid memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value); printf("# write to invalid memory at 0x%"PRIx64 ", data size = %u, data value = 0x%"PRIx64 "\n", addr, size, value);
@ -224,11 +224,11 @@ int main(int argc, char **argv, char **envp)
} }
// intercept invalid memory events // intercept invalid memory events
if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) { if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) {
printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID ucr\n", log_num++); printf("not ok %d - Failed to install memory invalid handler\n", log_num++);
return 7; return 7;
} else { } else {
printf("ok %d - UC_HOOK_MEM_INVALID installed\n", log_num++); printf("ok %d - memory invalid handler installed\n", log_num++);
} }
// emulate machine code until told to stop by hook_code // emulate machine code until told to stop by hook_code

40
tests/regress/memmap.py Executable file
View file

@ -0,0 +1,40 @@
#!/usr/bin/python
# By Ryan Hileman, issue #9
# this prints out 2 lines and the contents must be the same
from unicorn import *
import regress
class MemMap(regress.RegressTest):
def test_mmap_write(self):
uc = Uc(UC_ARCH_X86, UC_MODE_64)
uc.mem_map(0x8048000, 0x2000)
uc.mem_write(0x8048000, 'test')
s1 = str(uc.mem_read(0x8048000, 4)).encode('hex')
self.assertEqual('test'.encode('hex'), s1)
uc.mem_map(0x804a000, 0x8000)
s2 = str(uc.mem_read(0x8048000, 4)).encode('hex')
self.assertEqual(s1, s2)
def test_mmap_invalid(self):
u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
with self.assertRaises(UcError):
u.mem_map(0x2000, 0)
with self.assertRaises(UcError):
u.mem_map(0x4000, 1)
def test_mmap_weird(self):
u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
for i in xrange(20):
with self.assertRaises(UcError):
u.mem_map(i*0x1000, 5)
u.mem_read(i*0x1000+6, 1)
if __name__ == '__main__':
regress.main()

View file

@ -0,0 +1,35 @@
#!/usr/bin/env python
import unicorn
from unicorn import *
import regress
class MmapSeg(regress.RegressTest):
def test_seg1(self):
u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
u.mem_map(0x2000, 0x1000)
u.mem_read(0x2000, 1)
for i in range(50):
u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
u.mem_map(i*0x1000, 0x1000)
u.mem_read(i*0x1000, 1)
for i in range(20):
with self.assertRaises(UcError):
u = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
u.mem_map(i*0x1000, 5)
u.mem_read(i*0x1000, 1)
def test_seg2(self):
uc = Uc(UC_ARCH_X86, UC_MODE_32)
uc.mem_map(0x0000, 0x2000)
uc.mem_map(0x2000, 0x4000)
uc.mem_write(0x1000, 0x1004 * ' ')
self.assertTrue(1,
'If not reached, then we have BUG (crash on x86_64 Linux).')
if __name__ == '__main__':
regress.main()

View file

@ -0,0 +1,36 @@
#!/usr/bin/python
from capstone import *
from unicorn import *
import regress
class MipsBranchDelay(regress.RegressTest):
def runTest(self):
md = Cs(CS_ARCH_MIPS, CS_MODE_MIPS32 + CS_MODE_LITTLE_ENDIAN)
def disas(code, addr):
for i in md.disasm(code, addr):
print '0x%x: %s %s' % (i.address, str(i.bytes).encode('hex'), i.op_str)
def hook_code(uc, addr, size, _):
mem = str(uc.mem_read(addr, size))
disas(mem, addr)
CODE = 0x400000
asm = '0000a4126a00822800000000'.decode('hex') # beq $a0, $s5, 0x4008a0; slti $v0, $a0, 0x6a; nop
print 'Input instructions:'
disas(asm, CODE)
print
print 'Hooked instructions:'
uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN)
uc.hook_add(UC_HOOK_CODE, hook_code)
uc.mem_map(CODE, 0x1000)
uc.mem_write(CODE, asm)
self.assertEqual(None, uc.emu_start(CODE, CODE + len(asm)))
if __name__ == '__main__':
regress.main()

41
tests/regress/mips_except.py Executable file
View file

@ -0,0 +1,41 @@
#!/usr/bin/python
from unicorn import *
from unicorn.mips_const import *
import regress
def hook_intr(uc, intno, _):
print 'interrupt', intno
CODE = 0x400000
asm = '0000a48f'.decode('hex') # lw $a0, ($sp)
class MipsExcept(regress.RegressTest):
def runTest(self):
uc = Uc(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN)
uc.hook_add(UC_HOOK_INTR, hook_intr)
uc.mem_map(CODE, 0x1000)
uc.mem_write(CODE, asm)
with self.assertRaises(UcError) as m:
uc.reg_write(UC_MIPS_REG_SP, 0x400001)
uc.emu_start(CODE, CODE + len(asm), 300)
self.assertEqual(UC_ERR_READ_UNALIGNED, m.exception.errno)
with self.assertRaises(UcError) as m:
uc.reg_write(UC_MIPS_REG_SP, 0xFFFFFFF0)
uc.emu_start(CODE, CODE + len(asm), 200)
self.assertEqual(UC_ERR_READ_INVALID, m.exception.errno)
with self.assertRaises(UcError) as m:
uc.reg_write(UC_MIPS_REG_SP, 0x80000000)
uc.emu_start(CODE, CODE + len(asm), 100)
self.assertEqual(UC_ERR_READ_INVALID, m.exception.errno)
if __name__ == '__main__':
regress.main()

View file

@ -5,6 +5,7 @@ from capstone import *
from unicorn import * from unicorn import *
from unicorn.x86_const import * from unicorn.x86_const import *
import regress
code = 'f20f1005aa120000'.decode('hex') code = 'f20f1005aa120000'.decode('hex')
def dis(mem, addr): def dis(mem, addr):
@ -20,9 +21,15 @@ def hook_code(uc, addr, size, user_data):
print 'instruction:', str(mem).encode('hex'), dis(mem, addr) print 'instruction:', str(mem).encode('hex'), dis(mem, addr)
print 'reference: ', code.encode('hex'), dis(code, addr) print 'reference: ', code.encode('hex'), dis(code, addr)
addr = 0x400000 class Movsd(regress.RegressTest):
mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.hook_add(UC_HOOK_CODE, hook_code) def runTest(self):
mu.mem_map(addr, 8 * 1024 * 1024) addr = 0x400000
mu.mem_write(addr, code) mu = Uc(UC_ARCH_X86, UC_MODE_64)
mu.emu_start(addr, addr + len(code)) mu.hook_add(UC_HOOK_CODE, hook_code)
mu.mem_map(addr, 8 * 1024 * 1024)
mu.mem_write(addr, code)
mu.emu_start(addr, addr + len(code))
if __name__ == '__main__':
regress.main()

View file

@ -86,7 +86,7 @@ int main(int argc, char **argv, char **envp)
//uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff); //uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff);
// intercept invalid memory events // intercept invalid memory events
uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL); uc_hook_add(uc, &trace1, UC_MEM_READ_PROT, hook_mem_invalid, NULL);
// emulate machine code in infinite time // emulate machine code in infinite time
printf("BEGIN execution\n"); printf("BEGIN execution\n");

21
tests/regress/pshufb.py Executable file
View file

@ -0,0 +1,21 @@
#!/usr/bin/python
# By Ryan Hileman, issue #91
# Invalid instruction = test failed
from unicorn import *
from unicorn.x86_const import *
import regress
class Pshufb(regress.RegressTest):
def runTest(self):
uc = Uc(UC_ARCH_X86, UC_MODE_64)
uc.mem_map(0x2000, 0x1000)
# pshufb xmm0, xmm1
uc.mem_write(0x2000, '660f3800c1'.decode('hex'))
uc.emu_start(0x2000, 0x2005)
if __name__ == '__main__':
regress.main()

View file

@ -0,0 +1,31 @@
#!/usr/bin/env python
"""See https://github.com/unicorn-engine/unicorn/issues/98"""
import unicorn
import regress
ADDR = 0xffaabbcc
def hook_mem_invalid(mu, access, address, size, value, user_data):
print ">>> Access type: %u, expected value: 0x%x, actual value: 0x%x" % (access, ADDR, address)
assert(address == ADDR)
mu.mem_map(address & 0xfffff000, 4 * 1024)
mu.mem_write(address, b'\xcc')
return True
class RegWriteSignExt(regress.RegressTest):
def runTest(self):
mu = unicorn.Uc(unicorn.UC_ARCH_X86, unicorn.UC_MODE_32)
mu.reg_write(unicorn.x86_const.UC_X86_REG_EBX, ADDR)
mu.mem_map(0x10000000, 1024 * 4)
# jmp ebx
mu.mem_write(0x10000000, b'\xff\xe3')
mu.hook_add(unicorn.UC_HOOK_MEM_FETCH_INVALID | unicorn.UC_HOOK_MEM_FETCH_PROT, hook_mem_invalid)
mu.emu_start(0x10000000, 0x10000000 + 2, count=1)
if __name__ == '__main__':
regress.main()

34
tests/regress/regress.py Executable file
View file

@ -0,0 +1,34 @@
#!/usr/bin/python
import unittest
from os.path import dirname, basename, isfile
import glob
# Find all unittest type in this directory and run it.
class RegressTest(unittest.TestCase):
pass
def main():
unittest.main()
if __name__ == '__main__':
directory = dirname(__file__)
if directory == '':
directory = '.'
modules = glob.glob(directory+"/*.py")
__all__ = [ basename(f)[:-3] for f in modules if isfile(f)]
suite = unittest.TestSuite()
for module in __all__:
m = __import__(module)
for cl in dir(m):
try:
realcl = getattr(m,cl)
if issubclass(realcl, unittest.TestCase):
suite.addTest(realcl())
except Exception as e:
pass
unittest.TextTestRunner().run(suite)

13
tests/regress/regress.sh Executable file
View file

@ -0,0 +1,13 @@
#!/bin/sh
./map_crash map_write
./sigill sigill2
./block_test
./ro_mem_test nr_mem_test
./timeout_segfault
./rep_movsb
./mem_unmap
./mem_protect
./mem_exec

View file

@ -142,7 +142,7 @@ int main(int argc, char **argv, char **envp)
//uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff); //uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)0x400000, (uint64_t)0x400fff);
// intercept invalid memory events // intercept invalid memory events
uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL); uc_hook_add(uc, &trace1, UC_HOOK_MEM_WRITE_INVALID | UC_HOOK_MEM_WRITE_PROT, hook_mem_invalid, NULL);
// emulate machine code in infinite time // emulate machine code in infinite time
printf("BEGIN execution - 1\n"); printf("BEGIN execution - 1\n");

24
tests/regress/sparc64.py Executable file
View file

@ -0,0 +1,24 @@
#!/usr/bin/python
from unicorn import *
from unicorn.sparc_const import *
PAGE_SIZE = 1 * 1024 * 1024
uc = Uc(UC_ARCH_SPARC, UC_MODE_64)
uc.reg_write(UC_SPARC_REG_SP, 100)
print 'writing sp = 100'
# 0: b0 06 20 01 inc %i0
# 4: b2 06 60 01 inc %i1
CODE = "\xb0\x06\x20\x01" \
"\xb2\x06\x60\x01"
uc.mem_map(0, PAGE_SIZE)
uc.mem_write(0, CODE)
uc.emu_start(0, len(CODE), 0, 2)
print 'sp =', uc.reg_read(UC_SPARC_REG_SP)
print 'i0 =', uc.reg_read(UC_SPARC_REG_I0)
print 'i1 =', uc.reg_read(UC_SPARC_REG_I1)

205
tests/regress/sparc_reg.py Executable file
View file

@ -0,0 +1,205 @@
#!/usr/bin/python
from unicorn import *
from unicorn.sparc_const import *
PAGE_SIZE = 1 * 1024 * 1024
uc = Uc(UC_ARCH_SPARC, UC_MODE_32)
uc.reg_write(UC_SPARC_REG_SP, 100)
uc.reg_write(UC_SPARC_REG_FP, 200)
# 0x0: \x80\x00\x20\x01 add %g0, 1, %g0
# 0x4: \x82\x00\x60\x01 add %g1, 1, %g1
# 0x8: \x84\x00\xA0\x01 add %g2, 1, %g2
# 0xc: \x86\x00\xE0\x01 add %g3, 1, %g3
# 0x10: \x88\x01\x20\x01 add %g4, 1, %g4
# 0x14: \x8A\x01\x60\x01 add %g5, 1, %g5
# 0x18: \x8C\x01\xA0\x01 add %g6, 1, %g6
# 0x1c: \x8E\x01\xE0\x01 add %g7, 1, %g7
# 0x20: \x90\x02\x20\x01 add %o0, 1, %o0
# 0x24: \x92\x02\x60\x01 add %o1, 1, %o1
# 0x28: \x94\x02\xA0\x01 add %o2, 1, %o2
# 0x2c: \x96\x02\xE0\x01 add %o3, 1, %o3
# 0x30: \x98\x03\x20\x01 add %o4, 1, %o4
# 0x34: \x9A\x03\x60\x01 add %o5, 1, %o5
# 0x38: \x9C\x03\xA0\x01 add %sp, 1, %sp
# 0x3c: \x9E\x03\xE0\x01 add %o7, 1, %o7
# 0x40: \xA0\x04\x20\x01 add %l0, 1, %l0
# 0x44: \xA2\x04\x60\x01 add %l1, 1, %l1
# 0x48: \xA4\x04\xA0\x01 add %l2, 1, %l2
# 0x4c: \xA6\x04\xE0\x01 add %l3, 1, %l3
# 0x50: \xA8\x05\x20\x01 add %l4, 1, %l4
# 0x54: \xAA\x05\x60\x01 add %l5, 1, %l5
# 0x58: \xAC\x05\xA0\x01 add %l6, 1, %l6
# 0x5c: \xAE\x05\xE0\x01 add %l7, 1, %l7
# 0x0: \xB0\x06\x20\x01 add %i0, 1, %i0
# 0x4: \xB2\x06\x60\x01 add %i1, 1, %i1
# 0x8: \xB4\x06\xA0\x01 add %i2, 1, %i2
# 0xc: \xB6\x06\xE0\x01 add %i3, 1, %i3
# 0x10: \xB8\x07\x20\x01 add %i4, 1, %i4
# 0x14: \xBA\x07\x60\x01 add %i5, 1, %i5
# 0x18: \xBC\x07\xA0\x01 add %fp, 1, %fp
# 0x1c: \xBE\x07\xE0\x01 add %i7, 1, %i7
CODE = "\x80\x00\x20\x01" \
"\x82\x00\x60\x01" \
"\x84\x00\xA0\x01" \
"\x86\x00\xE0\x01" \
"\x88\x01\x20\x01" \
"\x8A\x01\x60\x01" \
"\x8C\x01\xA0\x01" \
"\x8E\x01\xE0\x01" \
"\x90\x02\x20\x01" \
"\x92\x02\x60\x01" \
"\x94\x02\xA0\x01" \
"\x96\x02\xE0\x01" \
"\x98\x03\x20\x01" \
"\x9A\x03\x60\x01" \
"\x9C\x03\xA0\x01" \
"\x9E\x03\xE0\x01" \
"\xA0\x04\x20\x01" \
"\xA2\x04\x60\x01" \
"\xA4\x04\xA0\x01" \
"\xA6\x04\xE0\x01" \
"\xA8\x05\x20\x01" \
"\xAA\x05\x60\x01" \
"\xAC\x05\xA0\x01" \
"\xAE\x05\xE0\x01" \
"\xB0\x06\x20\x01" \
"\xB2\x06\x60\x01" \
"\xB4\x06\xA0\x01" \
"\xB6\x06\xE0\x01" \
"\xB8\x07\x20\x01" \
"\xBA\x07\x60\x01" \
"\xBC\x07\xA0\x01" \
"\xBE\x07\xE0\x01"
uc.mem_map(0, PAGE_SIZE)
uc.mem_write(0, CODE)
uc.emu_start(0, len(CODE), 0, 32)
def print_registers(mu):
g0 = mu.reg_read(UC_SPARC_REG_G0)
g1 = mu.reg_read(UC_SPARC_REG_G1)
g2 = mu.reg_read(UC_SPARC_REG_G2)
g3 = mu.reg_read(UC_SPARC_REG_G3)
g4 = mu.reg_read(UC_SPARC_REG_G4)
g5 = mu.reg_read(UC_SPARC_REG_G5)
g6 = mu.reg_read(UC_SPARC_REG_G6)
g7 = mu.reg_read(UC_SPARC_REG_G7)
o0 = mu.reg_read(UC_SPARC_REG_O0)
o1 = mu.reg_read(UC_SPARC_REG_O1)
o2 = mu.reg_read(UC_SPARC_REG_O2)
o3 = mu.reg_read(UC_SPARC_REG_O3)
o4 = mu.reg_read(UC_SPARC_REG_O4)
o5 = mu.reg_read(UC_SPARC_REG_O5)
o6 = mu.reg_read(UC_SPARC_REG_O6)
o7 = mu.reg_read(UC_SPARC_REG_O7)
l0 = mu.reg_read(UC_SPARC_REG_L0)
l1 = mu.reg_read(UC_SPARC_REG_L1)
l2 = mu.reg_read(UC_SPARC_REG_L2)
l3 = mu.reg_read(UC_SPARC_REG_L3)
l4 = mu.reg_read(UC_SPARC_REG_L4)
l5 = mu.reg_read(UC_SPARC_REG_L5)
l6 = mu.reg_read(UC_SPARC_REG_L6)
l7 = mu.reg_read(UC_SPARC_REG_L7)
i0 = mu.reg_read(UC_SPARC_REG_I0)
i1 = mu.reg_read(UC_SPARC_REG_I1)
i2 = mu.reg_read(UC_SPARC_REG_I2)
i3 = mu.reg_read(UC_SPARC_REG_I3)
i4 = mu.reg_read(UC_SPARC_REG_I4)
i5 = mu.reg_read(UC_SPARC_REG_I5)
i6 = mu.reg_read(UC_SPARC_REG_I6)
i7 = mu.reg_read(UC_SPARC_REG_I7)
pc = mu.reg_read(UC_SPARC_REG_PC)
sp = mu.reg_read(UC_SPARC_REG_SP)
fp = mu.reg_read(UC_SPARC_REG_FP)
print(" G0 = %d" % g0)
print(" G1 = %d" % g1)
print(" G2 = %d" % g2)
print(" G3 = %d" % g3)
print(" G4 = %d" % g4)
print(" G5 = %d" % g5)
print(" G6 = %d" % g6)
print(" G7 = %d" % g7)
print("")
print(" O0 = %d" % o0)
print(" O1 = %d" % o1)
print(" O2 = %d" % o2)
print(" O3 = %d" % o3)
print(" O4 = %d" % o4)
print(" O5 = %d" % o5)
print(" O6 = %d" % o6)
print(" O7 = %d" % o7)
print("")
print(" L0 = %d" % l0)
print(" L1 = %d" % l1)
print(" L2 = %d" % l2)
print(" L3 = %d" % l3)
print(" L4 = %d" % l4)
print(" L5 = %d" % l5)
print(" L6 = %d" % l6)
print(" L7 = %d" % l7)
print("")
print(" I0 = %d" % i0)
print(" I1 = %d" % i1)
print(" I2 = %d" % i2)
print(" I3 = %d" % i3)
print(" I4 = %d" % i4)
print(" I5 = %d" % i5)
print(" I6 = %d" % i6)
print(" I7 = %d" % i7)
print("")
print(" PC = %d" % pc)
print(" SP = %d" % sp)
print(" FP = %d" % fp)
print("")
print_registers(uc)
assert uc.reg_read(UC_SPARC_REG_PC) == 128 # make sure we executed all instructions
assert uc.reg_read(UC_SPARC_REG_SP) == 101
assert uc.reg_read(UC_SPARC_REG_FP) == 201
assert uc.reg_read(UC_SPARC_REG_G0) == 0 # G0 is always zero
assert uc.reg_read(UC_SPARC_REG_G1) == 1
assert uc.reg_read(UC_SPARC_REG_G2) == 1
assert uc.reg_read(UC_SPARC_REG_G3) == 1
assert uc.reg_read(UC_SPARC_REG_G4) == 1
assert uc.reg_read(UC_SPARC_REG_G5) == 1
assert uc.reg_read(UC_SPARC_REG_G6) == 1
assert uc.reg_read(UC_SPARC_REG_G7) == 1
assert uc.reg_read(UC_SPARC_REG_O0) == 1
assert uc.reg_read(UC_SPARC_REG_O1) == 1
assert uc.reg_read(UC_SPARC_REG_O2) == 1
assert uc.reg_read(UC_SPARC_REG_O3) == 1
assert uc.reg_read(UC_SPARC_REG_O4) == 1
assert uc.reg_read(UC_SPARC_REG_O5) == 1
assert uc.reg_read(UC_SPARC_REG_O6) == 101
assert uc.reg_read(UC_SPARC_REG_O7) == 1
assert uc.reg_read(UC_SPARC_REG_L0) == 1
assert uc.reg_read(UC_SPARC_REG_L1) == 1
assert uc.reg_read(UC_SPARC_REG_L2) == 1
assert uc.reg_read(UC_SPARC_REG_L3) == 1
assert uc.reg_read(UC_SPARC_REG_L4) == 1
assert uc.reg_read(UC_SPARC_REG_L5) == 1
assert uc.reg_read(UC_SPARC_REG_L6) == 1
assert uc.reg_read(UC_SPARC_REG_L7) == 1
assert uc.reg_read(UC_SPARC_REG_I0) == 1
assert uc.reg_read(UC_SPARC_REG_I1) == 1
assert uc.reg_read(UC_SPARC_REG_I2) == 1
assert uc.reg_read(UC_SPARC_REG_I3) == 1
assert uc.reg_read(UC_SPARC_REG_I4) == 1
assert uc.reg_read(UC_SPARC_REG_I5) == 1
assert uc.reg_read(UC_SPARC_REG_I6) == 201
assert uc.reg_read(UC_SPARC_REG_I7) == 1

Some files were not shown because too many files have changed in this diff Show more