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
*.o
*.a
*.dSYM
qemu/config-all-devices.mak
@ -93,12 +94,12 @@ tmp/
bindings/python/build/
config.log
regress/map_crash
regress/sigill
regress/sigill2
regress/block_test
regress/map_write
regress/ro_mem_test
regress/nr_mem_test
regress/timeout_segfault
regress/rep_movsb
map_crash
sigill
sigill2
block_test
map_write
ro_mem_test
nr_mem_test
timeout_segfault
rep_movsb

View File

@ -35,11 +35,11 @@ Unicorn requires few dependent packages as followings
[1] Tailor Unicorn to your need.
Out of 8 archtitectures supported by Unicorn (Arm, Arm64, Mips, PPC, Sparc,
SystemZ, XCore & X86), if you just need several selected archs, choose which
ones you want to compile in by editing "config.mk" before going to next steps.
Out of 6 archtitectures supported by Unicorn (Arm, Arm64, M68K, Mips, Sparc,
& X86), if you just need several selected archs, choose which ones you want
to compile in by editing "config.mk" before going to next steps.
By default, all 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
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.
Look for the bindings under directory bindings/, and refer to README file
of corresponding languages.
[11] Unit tests
Automated unit tests use the cmocka unit testing framework (https://cmocka.org/).
It can be installed in most Linux distros using the package manager, e.g.
`sudo yum install libcmocka libcmocka-devel`, or you can easily build and install it from source.
You can run the tests by running `make test` in the project directory.

View File

@ -249,6 +249,11 @@ else
endif
.PHONY: test
test: all
$(MAKE) -C tests/unit test
install: all $(PKGCFGF)
mkdir -p $(LIBDIR)
ifeq ($(UNICORN_SHARED),yes)
@ -302,6 +307,7 @@ ifeq (,$(findstring yes,$(UNICORN_BUILD_CORE_ONLY)))
cd samples && $(MAKE) clean
rm -f $(BLDIR)/samples/lib$(LIBNAME).$(EXT)
endif
$(MAKE) -C tests/unit clean
ifdef 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:
cd python && $(MAKE) gen_const
cd go && $(MAKE) gen_const
cd java && $(MAKE) gen_const
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:
rangeMode = true
callback = C.hookCode_cgo
case HOOK_MEM_INVALID:
rangeMode = true
callback = C.hookMemInvalid_cgo
case HOOK_MEM_READ, HOOK_MEM_WRITE, HOOK_MEM_READ_WRITE:
case HOOK_MEM_READ, HOOK_MEM_WRITE, HOOK_MEM_READ | HOOK_MEM_WRITE:
rangeMode = true
callback = C.hookMemAccess_cgo
case HOOK_INTR:
@ -92,7 +89,14 @@ func (u *uc) HookAdd(htype int, cb interface{}, extra ...uint64) (Hook, error) {
return 0, errors.New("Unknown instruction type.")
}
default:
return 0, errors.New("Unknown hook type.")
// 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.")
}
}
var h2 C.uc_hook
data := &HookData{u, cb}

View File

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

View File

@ -48,26 +48,33 @@ const (
ERR_MAP = 12
ERR_WRITE_PROT = 13
ERR_READ_PROT = 14
ERR_EXEC_PROT = 15
ERR_FETCH_PROT = 15
ERR_ARG = 16
ERR_READ_UNALIGNED = 17
ERR_WRITE_UNALIGNED = 18
ERR_FETCH_UNALIGNED = 19
MEM_READ = 16
MEM_WRITE = 17
MEM_READ_WRITE = 18
MEM_FETCH = 19
MEM_WRITE_PROT = 20
MEM_READ_PROT = 21
MEM_EXEC_PROT = 22
HOOK_INTR = 32
HOOK_INSN = 33
HOOK_CODE = 34
HOOK_BLOCK = 35
HOOK_MEM_INVALID = 36
HOOK_MEM_READ = 37
HOOK_MEM_WRITE = 38
HOOK_MEM_READ_WRITE = 39
MEM_FETCH = 18
MEM_READ_INVALID = 19
MEM_WRITE_INVALID = 20
MEM_FETCH_INVALID = 21
MEM_WRITE_PROT = 22
MEM_READ_PROT = 23
MEM_FETCH_PROT = 24
HOOK_INTR = 1
HOOK_INSN = 2
HOOK_CODE = 4
HOOK_BLOCK = 8
HOOK_MEM_READ_INVALID = 16
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_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`)
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
jar:
$(MAKE) -f Makefile.build jar
install: lib jar
cp libunicorn_java$(LIB_EXT) $(JAVA_HOME)/lib/ext
cp $(JARFILE) $(JAVA_HOME)/lib/ext
$(MAKE) -f Makefile.build install
gen_const:
cd .. && python const_generator.py java
clean:
rm unicorn/*.class
rm samples/*.class
rm *.so
rm *.dylib
rm *.dll
rm -f unicorn/*.class
rm -f samples/*.class
rm -f *.so
rm -f *.dylib
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,18 +83,14 @@ public class Sample_x86 {
}
}
private static class MyMemInvalidHook implements MemoryInvalidHook {
public boolean hook(Unicorn u, int type, 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",
address, size, value);
// map this memory in with 2MB in size
u.mem_map(0xaaaa0000, 2 * 1024*1024, Unicorn.UC_PROT_ALL);
// return true to indicate we want to continue
return true;
}
return false;
private static class MyWriteInvalidHook implements EventMemHook {
public boolean hook(Unicorn u, long address, int size, long value, Object user) {
System.out.printf(">>> Missing memory is being WRITE at 0x%x, data size = %d, data value = 0x%x\n",
address, size, value);
// map this memory in with 2MB in size
u.mem_map(0xaaaa0000, 2 * 1024*1024, Unicorn.UC_PROT_ALL);
// return true to indicate we want to continue
return true;
}
}
@ -423,7 +419,7 @@ public class Sample_x86 {
u.hook_add(new MyCodeHook(), 1, 0, null);
// 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
try {

View File

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

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_FCC2 = 51;
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 = 54;
public static final int UC_SPARC_REG_G1 = 55;
public static final int UC_SPARC_REG_G2 = 56;
public static final int UC_SPARC_REG_G3 = 57;
public static final int UC_SPARC_REG_G4 = 58;
public static final int UC_SPARC_REG_G5 = 59;
public static final int UC_SPARC_REG_G6 = 60;
public static final int UC_SPARC_REG_G7 = 61;
public static final int UC_SPARC_REG_I0 = 62;
public static final int UC_SPARC_REG_I1 = 63;
public static final int UC_SPARC_REG_I2 = 64;
public static final int UC_SPARC_REG_I3 = 65;
public static final int UC_SPARC_REG_I4 = 66;
public static final int UC_SPARC_REG_I5 = 67;
public static final int UC_SPARC_REG_G0 = 53;
public static final int UC_SPARC_REG_G1 = 54;
public static final int UC_SPARC_REG_G2 = 55;
public static final int UC_SPARC_REG_G3 = 56;
public static final int UC_SPARC_REG_G4 = 57;
public static final int UC_SPARC_REG_G5 = 58;
public static final int UC_SPARC_REG_G6 = 59;
public static final int UC_SPARC_REG_G7 = 60;
public static final int UC_SPARC_REG_I0 = 61;
public static final int UC_SPARC_REG_I1 = 62;
public static final int UC_SPARC_REG_I2 = 63;
public static final int UC_SPARC_REG_I3 = 64;
public static final int UC_SPARC_REG_I4 = 65;
public static final int UC_SPARC_REG_I5 = 66;
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_ICC = 69;
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_O4 = 82;
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 = 85;
public static final int UC_SPARC_REG_SP = 84;
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_XCC = 87;
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_O6 = 85;
public static final int UC_SPARC_REG_I6 = 53;
public static final int UC_SPARC_REG_O6 = 84;
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 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 writeHandle = 0;
private long readWriteHandle = 0;
private long inHandle = 0;
private long outHandle = 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> intrList = 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> writeList = new ArrayList<Tuple>();
private ArrayList<Tuple> readWriteList = new ArrayList<Tuple>();
private ArrayList<Tuple> inList = new ArrayList<Tuple>();
private ArrayList<Tuple> outList = 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 static Hashtable<Integer,Integer> eventMemMap = new Hashtable<Integer,Integer>();
private static Hashtable<Long,Unicorn> unicorns = new Hashtable<Long,Unicorn>();
//required to load native method implementations
static {
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
* 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 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 size Size of data being read or written
* @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).
* @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);
boolean result = true;
if (u != null) {
for (Tuple p : u.memInvalidList) {
MemoryInvalidHook mh = (MemoryInvalidHook)p.function;
result &= mh.hook(u, type, address, size, value, p.data);
ArrayList<Tuple> funcList = u.eventMemLists.get(type);
if (funcList != null) {
for (Tuple p : funcList) {
EventMemHook emh = (EventMemHook)p.function;
result &= emh.hook(u, address, size, value, p.data);
}
}
}
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.
* 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(intrList);
allLists.add(codeList);
allLists.add(memInvalidList);
allLists.add(readList);
allLists.add(writeList);
allLists.add(readWriteList);
allLists.add(inList);
allLists.add(outList);
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
* invoked whenever a memory read or write is performed within the address range begin <= mem_addr <= end. For
* the special case in which begin > end, the callback will be invoked for ALL memory reads and writes.
* Hook registration for UC_HOOK_MEM_WRITE | UC_HOOK_MEM_WRITE hooks. The registered callback function will be
* 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 writes.
*
* @param callback Implementation of a ReadWriteHook interface
* @param begin Start address of memory read/write range
* @param end End address of memory read/write range
* @param callback Implementation of a MemHook interface
* @param begin Start address of memory 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
*/
public void hook_add(ReadWriteHook callback, long begin, long end, Object user_data) throws UnicornException {
if (readWriteHandle == 0) {
readWriteHandle = registerHook(eng, UC_HOOK_MEM_READ_WRITE, begin, end);
}
readWriteList.add(new Tuple(callback, user_data));
public void hook_add(MemHook callback, long begin, long end, Object user_data) throws UnicornException {
hook_add((ReadHook)callback, begin, end, user_data);
hook_add((WriteHook)callback, begin, end, user_data);
}
/**
* Hook registration for UC_HOOK_MEM_INVALID hooks. The registered callback function will be
* invoked whenever a read or write is attempted from an unmapped memory address.
* Hook registration for UC_HOOK_MEM_XXX_INVALID and UC_HOOK_MEM_XXX_PROT hooks.
* 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
*/
public void hook_add(MemoryInvalidHook callback, Object user_data) throws UnicornException {
if (memInvalidHandle == 0) {
memInvalidHandle = registerHook(eng, UC_HOOK_MEM_INVALID);
public void hook_add(EventMemHook callback, int type, Object user_data) throws UnicornException {
//test all of the EventMem related bits in type
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_WRITE_PROT = 13;
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_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_WRITE = 17;
public static final int UC_MEM_READ_WRITE = 18;
public static final int UC_MEM_FETCH = 19;
public static final int UC_MEM_WRITE_PROT = 20;
public static final int UC_MEM_READ_PROT = 21;
public static final int UC_MEM_EXEC_PROT = 22;
public static final int UC_HOOK_INTR = 32;
public static final int UC_HOOK_INSN = 33;
public static final int UC_HOOK_CODE = 34;
public static final int UC_HOOK_BLOCK = 35;
public static final int UC_HOOK_MEM_INVALID = 36;
public static final int UC_HOOK_MEM_READ = 37;
public static final int UC_HOOK_MEM_WRITE = 38;
public static final int UC_HOOK_MEM_READ_WRITE = 39;
public static final int UC_MEM_FETCH = 18;
public static final int UC_MEM_READ_INVALID = 19;
public static final int UC_MEM_WRITE_INVALID = 20;
public static final int UC_MEM_FETCH_INVALID = 21;
public static final int UC_MEM_WRITE_PROT = 22;
public static final int UC_MEM_READ_PROT = 23;
public static final int UC_MEM_FETCH_PROT = 24;
public static final int UC_HOOK_INTR = 1;
public static final int UC_HOOK_INSN = 2;
public static final int UC_HOOK_CODE = 4;
public static final int UC_HOOK_BLOCK = 8;
public static final int UC_HOOK_MEM_READ_INVALID = 16;
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_READ = 1;

View File

@ -33,10 +33,9 @@ static jmethodID invokeBlockCallbacks = 0;
static jmethodID invokeInterruptCallbacks = 0;
static jmethodID invokeCodeCallbacks = 0;
static jmethodID invokeMemInvalidCallbacks = 0;
static jmethodID invokeEventMemCallbacks = 0;
static jmethodID invokeReadCallbacks = 0;
static jmethodID invokeWriteCallbacks = 0;
static jmethodID invokeReadWriteCallbacks = 0;
static jmethodID invokeInCallbacks = 0;
static jmethodID invokeOutCallbacks = 0;
static jmethodID invokeSyscallCallbacks = 0;
@ -157,9 +156,6 @@ static void cb_hookmem(uc_engine *eng, uc_mem_type type,
case UC_MEM_WRITE:
(*env)->CallStaticVoidMethod(env, clz, invokeWriteCallbacks, (jlong)eng, (jlong)address, (int)size, (jlong)value);
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);
}
@ -179,7 +175,7 @@ static bool cb_eventmem(uc_engine *eng, uc_mem_type type,
if ((*env)->ExceptionCheck(env)) {
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);
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);
break;
case UC_HOOK_MEM_INVALID: // Hook for all invalid memory access events
if (invokeMemInvalidCallbacks == 0) {
invokeMemInvalidCallbacks = (*env)->GetStaticMethodID(env, clz, "invokeMemInvalidCallbacks", "(JIJIJ)Z");
case UC_HOOK_MEM_FETCH_INVALID: // Hook for all invalid memory access events
case UC_HOOK_MEM_READ_INVALID: // Hook for all invalid memory access events
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);
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);
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;
}

View File

@ -33,7 +33,7 @@ def hook_code(uc, address, size, user_data):
# callback for tracing invalid memory access (READ or WRITE)
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" \
%(address, size, value))
# 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)
# 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:
# 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_READ, hook_mem_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:
# 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_FCC2 = 51
UC_SPARC_REG_FCC3 = 52
UC_SPARC_REG_FP = 53
UC_SPARC_REG_G0 = 54
UC_SPARC_REG_G1 = 55
UC_SPARC_REG_G2 = 56
UC_SPARC_REG_G3 = 57
UC_SPARC_REG_G4 = 58
UC_SPARC_REG_G5 = 59
UC_SPARC_REG_G6 = 60
UC_SPARC_REG_G7 = 61
UC_SPARC_REG_I0 = 62
UC_SPARC_REG_I1 = 63
UC_SPARC_REG_I2 = 64
UC_SPARC_REG_I3 = 65
UC_SPARC_REG_I4 = 66
UC_SPARC_REG_I5 = 67
UC_SPARC_REG_G0 = 53
UC_SPARC_REG_G1 = 54
UC_SPARC_REG_G2 = 55
UC_SPARC_REG_G3 = 56
UC_SPARC_REG_G4 = 57
UC_SPARC_REG_G5 = 58
UC_SPARC_REG_G6 = 59
UC_SPARC_REG_G7 = 60
UC_SPARC_REG_I0 = 61
UC_SPARC_REG_I1 = 62
UC_SPARC_REG_I2 = 63
UC_SPARC_REG_I3 = 64
UC_SPARC_REG_I4 = 65
UC_SPARC_REG_I5 = 66
UC_SPARC_REG_FP = 67
UC_SPARC_REG_I7 = 68
UC_SPARC_REG_ICC = 69
UC_SPARC_REG_L0 = 70
@ -86,11 +86,11 @@ UC_SPARC_REG_O2 = 80
UC_SPARC_REG_O3 = 81
UC_SPARC_REG_O4 = 82
UC_SPARC_REG_O5 = 83
UC_SPARC_REG_O7 = 84
UC_SPARC_REG_SP = 85
UC_SPARC_REG_SP = 84
UC_SPARC_REG_O7 = 85
UC_SPARC_REG_Y = 86
UC_SPARC_REG_XCC = 87
UC_SPARC_REG_PC = 88
UC_SPARC_REG_ENDING = 89
UC_SPARC_REG_O6 = 85
UC_SPARC_REG_I6 = 53
UC_SPARC_REG_O6 = 84
UC_SPARC_REG_I6 = 67

View File

@ -141,6 +141,7 @@ class Uc(object):
raise UcError(status)
# internal mapping table to save callback & userdata
self._callbacks = {}
self._ctype_cbs = {}
self._callback_count = 0
@ -261,6 +262,7 @@ class Uc(object):
# save callback & user_data
self._callback_count += 1
self._callbacks[self._callback_count] = (callback, user_data)
cb = None
if htype in (UC_HOOK_BLOCK, UC_HOOK_CODE):
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)
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, cb, \
ctypes.cast(self._callback_count, ctypes.c_void_p), begin, end)
elif htype == UC_HOOK_MEM_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)
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
elif htype in (UC_HOOK_MEM_READ, UC_HOOK_MEM_WRITE, UC_HOOK_MEM_READ_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)
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
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, \
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:
raise UcError(status)

View File

@ -46,26 +46,33 @@ UC_ERR_INSN_INVALID = 11
UC_ERR_MAP = 12
UC_ERR_WRITE_PROT = 13
UC_ERR_READ_PROT = 14
UC_ERR_EXEC_PROT = 15
UC_ERR_FETCH_PROT = 15
UC_ERR_ARG = 16
UC_ERR_READ_UNALIGNED = 17
UC_ERR_WRITE_UNALIGNED = 18
UC_ERR_FETCH_UNALIGNED = 19
UC_MEM_READ = 16
UC_MEM_WRITE = 17
UC_MEM_READ_WRITE = 18
UC_MEM_FETCH = 19
UC_MEM_WRITE_PROT = 20
UC_MEM_READ_PROT = 21
UC_MEM_EXEC_PROT = 22
UC_HOOK_INTR = 32
UC_HOOK_INSN = 33
UC_HOOK_CODE = 34
UC_HOOK_BLOCK = 35
UC_HOOK_MEM_INVALID = 36
UC_HOOK_MEM_READ = 37
UC_HOOK_MEM_WRITE = 38
UC_HOOK_MEM_READ_WRITE = 39
UC_MEM_FETCH = 18
UC_MEM_READ_INVALID = 19
UC_MEM_WRITE_INVALID = 20
UC_MEM_FETCH_INVALID = 21
UC_MEM_WRITE_PROT = 22
UC_MEM_READ_PROT = 23
UC_MEM_FETCH_PROT = 24
UC_HOOK_INTR = 1
UC_HOOK_INSN = 2
UC_HOOK_CODE = 4
UC_HOOK_BLOCK = 8
UC_HOOK_MEM_READ_INVALID = 16
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_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)
uc->hook_write_idx = i;
break;
case UC_HOOK_MEM_READ_WRITE:
case UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE:
uc->hook_mem_read = true;
uc->hook_mem_write = true;
if (begin > end) {
@ -109,8 +109,28 @@ uc_err hook_del(struct uc_struct *uc, uc_hook hh)
uc->hook_write_idx = 0;
}
if (hh == uc->hook_mem_idx) {
uc->hook_mem_idx = 0;
if (hh == uc->hook_mem_read_idx) {
uc->hook_mem_read_idx = 0;
}
if (hh == uc->hook_mem_write_idx) {
uc->hook_mem_write_idx = 0;
}
if (hh == uc->hook_mem_fetch_idx) {
uc->hook_mem_fetch_idx = 0;
}
if (hh == uc->hook_mem_read_prot_idx) {
uc->hook_mem_read_prot_idx = 0;
}
if (hh == uc->hook_mem_write_prot_idx) {
uc->hook_mem_write_prot_idx = 0;
}
if (hh == uc->hook_mem_fetch_prot_idx) {
uc->hook_mem_fetch_prot_idx = 0;
}
if (hh == uc->hook_intr_idx) {
@ -176,13 +196,13 @@ static struct hook_struct *_hook_find(struct uc_struct *uc, int type, uint64_t a
}
break;
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)
return &uc->hook_callbacks[i];
}
break;
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)
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;
uint64_t block_addr; // save the last block address we hooked
// 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_out_idx; // for handling OUT 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_FCC2,
UC_SPARC_REG_FCC3,
UC_SPARC_REG_FP,
UC_SPARC_REG_G0,
UC_SPARC_REG_G1,
UC_SPARC_REG_G2,
@ -90,6 +89,7 @@ typedef enum uc_sparc_reg {
UC_SPARC_REG_I3,
UC_SPARC_REG_I4,
UC_SPARC_REG_I5,
UC_SPARC_REG_FP,
UC_SPARC_REG_I7,
UC_SPARC_REG_ICC, // Integer condition codes
UC_SPARC_REG_L0,
@ -106,14 +106,14 @@ typedef enum uc_sparc_reg {
UC_SPARC_REG_O3,
UC_SPARC_REG_O4,
UC_SPARC_REG_O5,
UC_SPARC_REG_O7,
UC_SPARC_REG_SP,
UC_SPARC_REG_O7,
UC_SPARC_REG_Y,
// special register
UC_SPARC_REG_XCC,
// pseudo register
// pseudo register
UC_SPARC_REG_PC, // program counter register
UC_SPARC_REG_ENDING, // <-- mark the end of the list of registers

View File

@ -120,7 +120,7 @@ typedef enum uc_err {
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_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_READ_UNALIGNED, // Unaligned read
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_*
typedef enum uc_mem_type {
UC_MEM_READ = 16, // Unmapped memory is read from
UC_MEM_WRITE, // Unmapped memory is written to
UC_MEM_READ_WRITE, // Unmapped memory is accessed (either READ or WRITE)
UC_MEM_FETCH, // Unmapped memory is fetched
UC_MEM_READ = 16, // Memory is read from
UC_MEM_WRITE, // Memory is written to
UC_MEM_FETCH, // 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_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;
// All type of hooks for uc_hook_add() API.
typedef enum uc_hook_type {
UC_HOOK_INTR = 32, // Hook all interrupt events
UC_HOOK_INSN, // Hook a particular instruction
UC_HOOK_CODE, // Hook a range of code
UC_HOOK_BLOCK, // Hook basic blocks
UC_HOOK_MEM_INVALID, // Hook for all invalid memory access events
UC_HOOK_MEM_READ, // Hook all memory read events.
UC_HOOK_MEM_WRITE, // Hook all memory write events.
UC_HOOK_MEM_READ_WRITE, // Hook all memory accesses (either READ or WRITE).
UC_HOOK_INTR = 1 << 0, // Hook all interrupt events
UC_HOOK_INSN = 1 << 1, // Hook a particular instruction
UC_HOOK_CODE = 1 << 2, // Hook a range of code
UC_HOOK_BLOCK = 1 << 3, // Hook basic blocks
UC_HOOK_MEM_READ_INVALID = 1 << 4, // Hook for invalid memory read events
UC_HOOK_MEM_WRITE_INVALID = 1 << 5, // Hook for invalid memory write events
UC_HOOK_MEM_FETCH_INVALID = 1 << 6, // Hook for invalid memory fetch for execution events
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;
// 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
// @address: address where the code is being executed
// @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,
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
// @address: address where the code is being executed
// @size: size of data being read or written
@ -380,7 +401,7 @@ uc_err uc_emu_stop(uc_engine *uc);
for detailed error).
*/
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.

View File

@ -300,7 +300,7 @@ tb_page_addr_t get_page_addr_code(CPUArchState *env1, target_ulong addr)
(addr & TARGET_PAGE_MASK))) {
cpu_ldub_code(env1, addr);
//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;
return -1;
}

View File

@ -33,11 +33,13 @@
static void sun4u_init(struct uc_struct *uc, MachineState *machine)
{
const char *cpu_model = machine->cpu_model;
SPARCCPU *cpu;
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");
exit(1);
}
@ -45,7 +47,7 @@ static void sun4u_init(struct uc_struct *uc, MachineState *machine)
void sun4u_machine_init(struct uc_struct *uc)
{
QEMUMachine sun4u_machine = {
static QEMUMachine sun4u_machine = {
.name = "sun4u",
.init = sun4u_init,
.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;
uintptr_t haddr;
DATA_TYPE res;
int mem_access, error_code;
int error_code;
struct uc_struct *uc = env->uc;
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
if (mr == NULL) {
#if defined(SOFTMMU_CODE_ACCESS)
mem_access = UC_MEM_FETCH;
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
mem_access = UC_MEM_READ;
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
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;
mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time?
} else {
@ -208,13 +209,13 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
#if defined(SOFTMMU_CODE_ACCESS)
// Unicorn: callback on fetch from NX
if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
if (uc->hook_mem_fetch_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].callback)(
uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].user_data)) {
env->invalid_error = UC_ERR_OK;
} else {
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);
cpu_exit(uc->current_cpu);
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
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->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;
}
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;
uintptr_t haddr;
DATA_TYPE res;
int mem_access, error_code;
int error_code;
struct uc_struct *uc = env->uc;
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
if (mr == NULL) {
#if defined(SOFTMMU_CODE_ACCESS)
mem_access = UC_MEM_FETCH;
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
mem_access = UC_MEM_READ;
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
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;
mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time?
} else {
@ -398,13 +400,13 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
#if defined(SOFTMMU_CODE_ACCESS)
// Unicorn: callback on fetch from NX
if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable
if (uc->hook_mem_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
uc, UC_MEM_EXEC_PROT, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
if (uc->hook_mem_fetch_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].callback)(
uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0,
uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].user_data)) {
env->invalid_error = UC_ERR_OK;
} else {
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);
cpu_exit(uc->current_cpu);
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
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->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;
} else {
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
if (uc->hook_mem_idx && mr == NULL) {
if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
if (uc->hook_mem_write_idx && mr == NULL) {
if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_idx].callback)(
uc, UC_MEM_WRITE_INVALID, addr, DATA_SIZE, (int64_t)val,
uc->hook_callbacks[uc->hook_mem_write_idx].user_data)) {
// save error & quit
env->invalid_addr = addr;
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;
} else {
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
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->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;
}
else {
@ -754,10 +757,10 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
}
// Unicorn: callback on invalid memory
if (uc->hook_mem_idx && mr == NULL) {
if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_idx].callback)(
uc, UC_MEM_WRITE, addr, DATA_SIZE, (int64_t)val,
uc->hook_callbacks[uc->hook_mem_idx].user_data)) {
if (uc->hook_mem_write_idx && mr == NULL) {
if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_idx].callback)(
uc, UC_MEM_WRITE_INVALID, addr, DATA_SIZE, (int64_t)val,
uc->hook_callbacks[uc->hook_mem_write_idx].user_data)) {
// save error & quit
env->invalid_addr = addr;
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;
} else {
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
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->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;
}
else {

View File

@ -11105,6 +11105,13 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
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
// Only hook this block if it is not broken from previous translation due to
// full translation cache

View File

@ -11228,6 +11228,13 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
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
// Only hook this block if it is not broken from previous translation due to
// full translation cache

View File

@ -3101,6 +3101,13 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb,
if (max_insns == 0)
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
// Only hook this block if it is not broken from previous translation due to
// full translation cache
@ -3179,6 +3186,8 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb,
break;
}
}
done_generating:
gen_tb_end(tcg_ctx, tb, num_insns);
*tcg_ctx->gen_opc_ptr = INDEX_op_end;

View File

@ -1415,7 +1415,7 @@ enum {
* exception condition */
BS_STOP = 1, /* We want to stop translation for any reason */
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[] = {
@ -11322,7 +11322,7 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
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;
TCGv **cpu_gpr = (TCGv **)tcg_ctx->cpu_gpr;
@ -11343,7 +11343,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
n_bytes = 2;
// 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);
if (trace)
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;
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
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);
if (trace)
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;
#if defined(TARGET_MIPS64)
@ -18514,6 +18514,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
uint32_t op, op1;
int16_t imm;
/* make sure instructions are on a word boundary */
if (ctx->pc & 0x3) {
env->CP0_BadVAddr = ctx->pc;
@ -18522,7 +18523,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
}
// 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);
if (trace)
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;
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
// Only hook this block if it is not broken from previous translation due to
// full translation cache
@ -19220,7 +19228,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
}
gen_tb_start(tcg_ctx);
while (ctx.bstate == BS_NONE) { // qq
while (ctx.bstate == BS_NONE) {
if (unlikely(!QTAILQ_EMPTY(&cs->breakpoints))) {
QTAILQ_FOREACH(bp, &cs->breakpoints, entry) {
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;
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);
insn_bytes = 4;
decode_opc(env, &ctx);
} else if (ctx.insn_flags & ASE_MICROMIPS) { // qq
decode_opc(env, &ctx, is_slot);
} else if (ctx.insn_flags & ASE_MICROMIPS) {
ctx.opcode = cpu_lduw_code(env, ctx.pc);
insn_bytes = decode_micromips_opc(env, &ctx);
} else if (ctx.insn_flags & ASE_MIPS16) { // qq
insn_bytes = decode_micromips_opc(env, &ctx, is_slot);
} else if (ctx.insn_flags & ASE_MIPS16) {
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 {
generate_exception(&ctx, EXCP_RI);
ctx.bstate = BS_STOP;

View File

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

View File

@ -6,6 +6,7 @@
#include "sysemu/cpus.h"
#include "unicorn.h"
#include "cpu.h"
#include "unicorn_common.h"
#define READ_QWORD(x) ((uint64)x)
@ -15,6 +16,22 @@
#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)
{
CPUArchState *env = first_cpu->env_ptr;
@ -25,6 +42,7 @@ void sparc_reg_reset(struct uc_struct *uc)
env->pc = 0;
env->npc = 0;
env->regwptr = env->regbase;
}
int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
@ -32,38 +50,44 @@ int sparc_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
CPUState *mycpu = first_cpu;
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 {
switch(regid) {
default: break;
case UC_SPARC_REG_PC:
*(int32_t *)value = SPARC_CPU(uc, mycpu)->env.pc;
break;
*(int64_t *)value = SPARC_CPU(uc, mycpu)->env.pc;
break;
}
}
return 0;
}
#define WRITE_DWORD(x, w) (x = (x & ~0xffffffff) | (w & 0xffffffff))
#define WRITE_WORD(x, w) (x = (x & ~0xffff) | (w & 0xffff))
#define WRITE_BYTE_H(x, b) (x = (x & ~0xff00) | (b & 0xff))
#define WRITE_BYTE_L(x, b) (x = (x & ~0xff) | (b & 0xff))
int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
{
CPUState *mycpu = first_cpu;
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 {
switch(regid) {
default: break;
case UC_SPARC_REG_PC:
SPARC_CPU(uc, mycpu)->env.pc = *(uint32_t *)value;
SPARC_CPU(uc, mycpu)->env.npc = *(uint32_t *)value + 4;
break;
SPARC_CPU(uc, mycpu)->env.pc = *(uint64_t *)value;
SPARC_CPU(uc, mycpu)->env.npc = *(uint64_t *)value + 4;
break;
}
}
@ -80,4 +104,7 @@ void sparc64_uc_init(struct uc_struct* uc)
uc->reg_read = sparc_reg_read;
uc->reg_write = sparc_reg_write;
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);
}
#if 0
/* liveness analysis: end of basic block: all temps are dead, globals
and local temps should be in memory. */
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;
}
}
#endif
/* Liveness analysis : update the opc_dead_args array to tell if a
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 (def->flags & TCG_OPF_BB_END) {
// Unicorn: do not optimize dead temps.
if (def->flags & TCG_OPF_BB_END && op != INDEX_op_brcond_i32) {
// Unicorn: do not optimize dead temps on brcond,
// this causes problem because check_exit_request() inserts
// brcond instruction in the middle of the TB,
// 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) {
/* globals should be synced to memory */
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;
TranslationBlock *tb;
tb_page_addr_t phys_pc, phys_page2;
target_ulong virt_page2;
int code_gen_size;
phys_pc = get_page_addr_code(env, pc);
@ -1094,11 +1093,13 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
tcg_ctx->code_gen_ptr = (void *)(((uintptr_t)tcg_ctx->code_gen_ptr +
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;
if ((pc & TARGET_PAGE_MASK) != virt_page2) {
phys_page2 = get_page_addr_code(env, virt_page2);
/* 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) {
phys_page2 = get_page_addr_code(env, virt_page2);
}
}
tb_link_page(cpu->uc, tb, phys_pc, phys_page2);
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:
printf("not ok - UC_HOOK_MEM_INVALID type: %d at 0x%" PRIx64 "\n", type, addr);
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);
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);
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);
return false;
case UC_MEM_WRITE_PROT:
@ -147,7 +147,8 @@ static void do_nx_demo(bool cause_fault)
// intercept code and invalid memory events
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK ||
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");
return;
}
@ -226,7 +227,9 @@ static void do_perms_demo(bool change_perms)
// intercept code and invalid memory events
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK ||
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");
return;
}
@ -302,7 +305,9 @@ static void do_unmap_demo(bool do_unmap)
// intercept code and invalid memory events
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK ||
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");
return;
}

View File

@ -73,7 +73,7 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
default:
// return false to indicate we want to stop emulation
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",
address, size, value);
// 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);
// 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
err = uc_emu_start(uc, ADDRESS, ADDRESS + sizeof(X86_CODE32_MEM_WRITE) - 1, 0, 0);

View File

@ -1,5 +1,5 @@
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 += 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) {
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;
case UC_MEM_EXEC_PROT:
case UC_MEM_FETCH_PROT:
printf("# Fetch from non-executable memory at 0x%"PRIx64 "\n", addr);
//make page executable
@ -221,11 +221,11 @@ int main(int argc, char **argv, char **envp)
}
// intercept invalid memory events
if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) {
printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID ucr\n", log_num++);
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 memory invalid handler\n", log_num++);
return 8;
} 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

View File

@ -138,7 +138,7 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
uint32_t testval;
switch(type) {
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;
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);
@ -229,11 +229,11 @@ int main(int argc, char **argv, char **envp)
}
// intercept invalid memory events
if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) {
printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID ucr\n", log_num++);
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 memory invalid handler\n", log_num++);
return 7;
} 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

View File

@ -133,7 +133,7 @@ static bool hook_mem_invalid(uc_engine *uc, uc_mem_type type,
uint32_t testval;
switch(type) {
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;
case UC_MEM_WRITE:
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
if (uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID, hook_mem_invalid, NULL) != UC_ERR_OK) {
printf("not ok %d - Failed to install UC_HOOK_MEM_INVALID ucr\n", log_num++);
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 memory invalid handler\n", log_num++);
return 7;
} 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

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.x86_const import *
import regress
code = 'f20f1005aa120000'.decode('hex')
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 'reference: ', code.encode('hex'), dis(code, addr)
addr = 0x400000
mu = Uc(UC_ARCH_X86, UC_MODE_64)
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))
class Movsd(regress.RegressTest):
def runTest(self):
addr = 0x400000
mu = Uc(UC_ARCH_X86, UC_MODE_64)
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);
// 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
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);
// 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
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