mirror of
https://github.com/Vita3K/unicorn.git
synced 2025-02-22 21:32:36 +00:00
Merge branch 'master' of https://github.com/unicorn-engine/unicorn
This commit is contained in:
commit
15f087be74
19
.gitignore
vendored
19
.gitignore
vendored
@ -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
|
||||
|
17
COMPILE.TXT
17
COMPILE.TXT
@ -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.
|
||||
|
6
Makefile
6
Makefile
@ -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
24
README
@ -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
30
README.md
Normal 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.
|
@ -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
|
||||
|
||||
|
@ -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}
|
||||
|
@ -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
|
||||
)
|
@ -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
|
||||
|
@ -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
|
||||
|
78
bindings/java/Makefile.build
Normal file
78
bindings/java/Makefile.build
Normal 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
|
@ -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 {
|
||||
|
@ -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);
|
||||
|
||||
}
|
||||
|
@ -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 {
|
||||
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
|
@ -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));
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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
30
hook.c
@ -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];
|
||||
}
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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)
|
@ -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)
|
@ -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()
|
@ -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))
|
||||
|
@ -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))
|
@ -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()
|
||||
|
@ -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
|
@ -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
|
@ -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)
|
@ -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))
|
||||
|
@ -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"
|
@ -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')
|
@ -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"
|
@ -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"
|
@ -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).'
|
@ -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
|
@ -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))
|
@ -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)
|
@ -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)
|
@ -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)
|
@ -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)
|
@ -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))
|
||||
|
@ -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))
|
||||
|
@ -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)
|
||||
|
@ -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)
|
@ -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)
|
@ -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)
|
@ -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)
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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
27
tests/regress/arm_bxeq_hang.py
Executable 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()
|
32
tests/regress/arm_movr12_hang.py
Executable file
32
tests/regress/arm_movr12_hang.py
Executable 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
64
tests/regress/callback-pc.py
Executable 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
37
tests/regress/crash_tb.py
Executable 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
20
tests/regress/deadlock_1.py
Executable 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()
|
20
tests/regress/emu_stop_segfault.py
Executable file
20
tests/regress/emu_stop_segfault.py
Executable 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
69
tests/regress/fpu_ip.py
Executable 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
38
tests/regress/fpu_mem_write.py
Executable 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
57
tests/regress/hang.py
Executable 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
39
tests/regress/jmp_ebx_hang.py
Executable 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()
|
@ -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
|
@ -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
|
@ -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
40
tests/regress/memmap.py
Executable 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()
|
35
tests/regress/memmap_segfault.py
Executable file
35
tests/regress/memmap_segfault.py
Executable 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()
|
36
tests/regress/mips_branch_delay.py
Executable file
36
tests/regress/mips_branch_delay.py
Executable 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
41
tests/regress/mips_except.py
Executable 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()
|
||||
|
@ -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()
|
@ -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
21
tests/regress/pshufb.py
Executable 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()
|
31
tests/regress/reg_write_sign_extension.py
Executable file
31
tests/regress/reg_write_sign_extension.py
Executable 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
34
tests/regress/regress.py
Executable 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
13
tests/regress/regress.sh
Executable 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
|
||||
|
@ -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
24
tests/regress/sparc64.py
Executable 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
205
tests/regress/sparc_reg.py
Executable 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
Loading…
x
Reference in New Issue
Block a user