mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2025-06-18 12:40:20 +00:00
fix merge conflict
This commit is contained in:
commit
20b01a6933
6
.gitignore
vendored
6
.gitignore
vendored
|
@ -8,6 +8,8 @@
|
||||||
*.so.*
|
*.so.*
|
||||||
*.exe
|
*.exe
|
||||||
*.dll
|
*.dll
|
||||||
|
*.class
|
||||||
|
*.jar
|
||||||
|
|
||||||
qemu/config-all-devices.mak
|
qemu/config-all-devices.mak
|
||||||
|
|
||||||
|
@ -125,12 +127,16 @@ mips_delay_slot_code_hook
|
||||||
threaded_emu_start
|
threaded_emu_start
|
||||||
emu_stop_in_hook_overrun
|
emu_stop_in_hook_overrun
|
||||||
mips_branch_likely_issue
|
mips_branch_likely_issue
|
||||||
|
emu_clear_errors
|
||||||
|
|
||||||
test_mem_map_ptr
|
test_mem_map_ptr
|
||||||
test_mem_high
|
test_mem_high
|
||||||
rw_hookstack
|
rw_hookstack
|
||||||
hook_extrainvoke
|
hook_extrainvoke
|
||||||
sysenter_hook_x86
|
sysenter_hook_x86
|
||||||
|
test_tb_x86
|
||||||
|
test_multihook
|
||||||
|
test_pc_change
|
||||||
|
|
||||||
memleak_x86
|
memleak_x86
|
||||||
memleak_arm
|
memleak_arm
|
||||||
|
|
6
Makefile
6
Makefile
|
@ -222,13 +222,13 @@ else
|
||||||
endif
|
endif
|
||||||
|
|
||||||
compile_lib: config qemu/config-host.h-timestamp
|
compile_lib: config qemu/config-host.h-timestamp
|
||||||
rm -rf lib$(LIBNAME)* $(LIBNAME)*.lib $(LIBNAME)*.dll cyg$(LIBNAME)*.dll && cd qemu && $(MAKE) -j 8
|
rm -rf lib$(LIBNAME)* $(LIBNAME)*.lib $(LIBNAME)*.dll cyg$(LIBNAME)*.dll && cd qemu && $(MAKE) -j 4
|
||||||
$(MAKE) unicorn
|
$(MAKE) unicorn
|
||||||
cd samples && $(MAKE) clean
|
cd samples && $(MAKE) clean
|
||||||
|
|
||||||
unicorn: $(LIBRARY) $(ARCHIVE)
|
unicorn: $(LIBRARY) $(ARCHIVE)
|
||||||
|
|
||||||
$(LIBRARY): $(UC_TARGET_OBJ) uc.o hook.o
|
$(LIBRARY): $(UC_TARGET_OBJ) uc.o list.o
|
||||||
ifeq ($(UNICORN_SHARED),yes)
|
ifeq ($(UNICORN_SHARED),yes)
|
||||||
ifeq ($(V),0)
|
ifeq ($(V),0)
|
||||||
$(call log,GEN,$(LIBRARY))
|
$(call log,GEN,$(LIBRARY))
|
||||||
|
@ -241,7 +241,7 @@ ifneq (,$(LIBRARY_SYMLINK))
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
$(ARCHIVE): $(UC_TARGET_OBJ) uc.o hook.o
|
$(ARCHIVE): $(UC_TARGET_OBJ) uc.o list.o
|
||||||
ifeq ($(UNICORN_STATIC),yes)
|
ifeq ($(UNICORN_STATIC),yes)
|
||||||
ifeq ($(V),0)
|
ifeq ($(V),0)
|
||||||
$(call log,GEN,$(ARCHIVE))
|
$(call log,GEN,$(ARCHIVE))
|
||||||
|
|
31
README.md
31
README.md
|
@ -18,13 +18,32 @@ Unicorn offers some unparalleled features:
|
||||||
Further information is available at http://www.unicorn-engine.org
|
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
|
License
|
||||||
-------
|
-------
|
||||||
|
|
||||||
This project is released under the [GPL license](COPYING).
|
This project is released under the [GPL license](COPYING).
|
||||||
|
|
||||||
|
|
||||||
|
Compilation & Docs
|
||||||
|
------------------
|
||||||
|
|
||||||
|
See [COMPILE.TXT](COMPILE.TXT) file for how to compile and install Unicorn.
|
||||||
|
|
||||||
|
More documentation is available in [docs/README.md](docs/README.md).
|
||||||
|
|
||||||
|
|
||||||
|
Contact
|
||||||
|
-------
|
||||||
|
|
||||||
|
[Contact us](http://www.unicorn-engine.org/contact/) via mailing list, email or twitter for any questions.
|
||||||
|
|
||||||
|
|
||||||
|
Contribute
|
||||||
|
----------
|
||||||
|
|
||||||
|
If you want to contribute, please pick up something from our [Github issues](https://github.com/unicorn-engine/unicorn/issues).
|
||||||
|
|
||||||
|
We also maintain a list of more challenged problems in a [TODO list](https://github.com/unicorn-engine/unicorn/wiki/TODO).
|
||||||
|
|
||||||
|
[CREDITS.TXT](CREDITS.TXT) records important contributors of our project.
|
||||||
|
|
||||||
|
|
|
@ -116,7 +116,8 @@ def gen(lang):
|
||||||
|
|
||||||
if f[0].startswith("UC_" + prefix.upper()):
|
if f[0].startswith("UC_" + prefix.upper()):
|
||||||
if len(f) > 1 and f[1] not in ('//', '='):
|
if len(f) > 1 and f[1] not in ('//', '='):
|
||||||
print("Error: Unable to convert %s" % f)
|
print("WARNING: Unable to convert %s" % f)
|
||||||
|
print(" Line =", line)
|
||||||
continue
|
continue
|
||||||
elif len(f) > 1 and f[1] == '=':
|
elif len(f) > 1 and f[1] == '=':
|
||||||
rhs = ''.join(f[2:])
|
rhs = ''.join(f[2:])
|
||||||
|
|
|
@ -21,22 +21,26 @@ module Common =
|
||||||
let UC_ARCH_MAX = 8
|
let UC_ARCH_MAX = 8
|
||||||
|
|
||||||
let UC_MODE_LITTLE_ENDIAN = 0
|
let UC_MODE_LITTLE_ENDIAN = 0
|
||||||
|
let UC_MODE_BIG_ENDIAN = 1073741824
|
||||||
|
|
||||||
let UC_MODE_ARM = 0
|
let UC_MODE_ARM = 0
|
||||||
let UC_MODE_16 = 2
|
|
||||||
let UC_MODE_32 = 4
|
|
||||||
let UC_MODE_64 = 8
|
|
||||||
let UC_MODE_THUMB = 16
|
let UC_MODE_THUMB = 16
|
||||||
let UC_MODE_MCLASS = 32
|
let UC_MODE_MCLASS = 32
|
||||||
let UC_MODE_V8 = 64
|
let UC_MODE_V8 = 64
|
||||||
let UC_MODE_MICRO = 16
|
let UC_MODE_MICRO = 16
|
||||||
let UC_MODE_MIPS3 = 32
|
let UC_MODE_MIPS3 = 32
|
||||||
let UC_MODE_MIPS32R6 = 64
|
let UC_MODE_MIPS32R6 = 64
|
||||||
let UC_MODE_V9 = 16
|
|
||||||
let UC_MODE_QPX = 16
|
|
||||||
let UC_MODE_BIG_ENDIAN = 1073741824
|
|
||||||
let UC_MODE_MIPS32 = 4
|
let UC_MODE_MIPS32 = 4
|
||||||
let UC_MODE_MIPS64 = 8
|
let UC_MODE_MIPS64 = 8
|
||||||
|
let UC_MODE_16 = 2
|
||||||
|
let UC_MODE_32 = 4
|
||||||
|
let UC_MODE_64 = 8
|
||||||
|
let UC_MODE_PPC32 = 4
|
||||||
|
let UC_MODE_PPC64 = 8
|
||||||
|
let UC_MODE_QPX = 16
|
||||||
|
let UC_MODE_SPARC32 = 4
|
||||||
|
let UC_MODE_SPARC64 = 8
|
||||||
|
let UC_MODE_V9 = 16
|
||||||
|
|
||||||
let UC_ERR_OK = 0
|
let UC_ERR_OK = 0
|
||||||
let UC_ERR_NOMEM = 1
|
let UC_ERR_NOMEM = 1
|
||||||
|
@ -87,6 +91,8 @@ module Common =
|
||||||
let UC_HOOK_MEM_WRITE_INVALID = 288
|
let UC_HOOK_MEM_WRITE_INVALID = 288
|
||||||
let UC_HOOK_MEM_FETCH_INVALID = 576
|
let UC_HOOK_MEM_FETCH_INVALID = 576
|
||||||
let UC_HOOK_MEM_INVALID = 1008
|
let UC_HOOK_MEM_INVALID = 1008
|
||||||
|
let UC_HOOK_MEM_VALID = 7168
|
||||||
|
let UC_QUERY_MODE = 1
|
||||||
|
|
||||||
let UC_PROT_NONE = 0
|
let UC_PROT_NONE = 0
|
||||||
let UC_PROT_READ = 1
|
let UC_PROT_READ = 1
|
||||||
|
|
|
@ -16,22 +16,26 @@ const (
|
||||||
ARCH_MAX = 8
|
ARCH_MAX = 8
|
||||||
|
|
||||||
MODE_LITTLE_ENDIAN = 0
|
MODE_LITTLE_ENDIAN = 0
|
||||||
|
MODE_BIG_ENDIAN = 1073741824
|
||||||
|
|
||||||
MODE_ARM = 0
|
MODE_ARM = 0
|
||||||
MODE_16 = 2
|
|
||||||
MODE_32 = 4
|
|
||||||
MODE_64 = 8
|
|
||||||
MODE_THUMB = 16
|
MODE_THUMB = 16
|
||||||
MODE_MCLASS = 32
|
MODE_MCLASS = 32
|
||||||
MODE_V8 = 64
|
MODE_V8 = 64
|
||||||
MODE_MICRO = 16
|
MODE_MICRO = 16
|
||||||
MODE_MIPS3 = 32
|
MODE_MIPS3 = 32
|
||||||
MODE_MIPS32R6 = 64
|
MODE_MIPS32R6 = 64
|
||||||
MODE_V9 = 16
|
|
||||||
MODE_QPX = 16
|
|
||||||
MODE_BIG_ENDIAN = 1073741824
|
|
||||||
MODE_MIPS32 = 4
|
MODE_MIPS32 = 4
|
||||||
MODE_MIPS64 = 8
|
MODE_MIPS64 = 8
|
||||||
|
MODE_16 = 2
|
||||||
|
MODE_32 = 4
|
||||||
|
MODE_64 = 8
|
||||||
|
MODE_PPC32 = 4
|
||||||
|
MODE_PPC64 = 8
|
||||||
|
MODE_QPX = 16
|
||||||
|
MODE_SPARC32 = 4
|
||||||
|
MODE_SPARC64 = 8
|
||||||
|
MODE_V9 = 16
|
||||||
|
|
||||||
ERR_OK = 0
|
ERR_OK = 0
|
||||||
ERR_NOMEM = 1
|
ERR_NOMEM = 1
|
||||||
|
@ -82,6 +86,8 @@ const (
|
||||||
HOOK_MEM_WRITE_INVALID = 288
|
HOOK_MEM_WRITE_INVALID = 288
|
||||||
HOOK_MEM_FETCH_INVALID = 576
|
HOOK_MEM_FETCH_INVALID = 576
|
||||||
HOOK_MEM_INVALID = 1008
|
HOOK_MEM_INVALID = 1008
|
||||||
|
HOOK_MEM_VALID = 7168
|
||||||
|
QUERY_MODE = 1
|
||||||
|
|
||||||
PROT_NONE = 0
|
PROT_NONE = 0
|
||||||
PROT_READ = 1
|
PROT_READ = 1
|
||||||
|
|
|
@ -113,7 +113,7 @@ public class Sample_mips {
|
||||||
System.out.print("Emulate MIPS code (little-endian)\n");
|
System.out.print("Emulate MIPS code (little-endian)\n");
|
||||||
|
|
||||||
// Initialize emulator in MIPS mode
|
// Initialize emulator in MIPS mode
|
||||||
Unicorn u = new Unicorn(Unicorn.UC_ARCH_MIPS, Unicorn.UC_MODE_MIPS32);
|
Unicorn u = new Unicorn(Unicorn.UC_ARCH_MIPS, Unicorn.UC_MODE_MIPS32 + Unicorn.UC_MODE_LITTLE_ENDIAN);
|
||||||
|
|
||||||
// map 2MB memory for this emulation
|
// map 2MB memory for this emulation
|
||||||
u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL);
|
u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL);
|
||||||
|
|
|
@ -76,7 +76,7 @@ public class Sample_sparc {
|
||||||
System.out.print("Emulate SPARC code\n");
|
System.out.print("Emulate SPARC code\n");
|
||||||
|
|
||||||
// Initialize emulator in Sparc mode
|
// Initialize emulator in Sparc mode
|
||||||
Unicorn u = new Unicorn(Unicorn.UC_ARCH_SPARC, Unicorn.UC_MODE_32);
|
Unicorn u = new Unicorn(Unicorn.UC_ARCH_SPARC, Unicorn.UC_MODE_32 + Unicorn.UC_MODE_BIG_ENDIAN);
|
||||||
|
|
||||||
// map 2MB memory for this emulation
|
// map 2MB memory for this emulation
|
||||||
u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL);
|
u.mem_map(ADDRESS, 2 * 1024 * 1024, Unicorn.UC_PROT_ALL);
|
||||||
|
|
|
@ -18,22 +18,26 @@ public interface UnicornConst {
|
||||||
public static final int UC_ARCH_MAX = 8;
|
public static final int UC_ARCH_MAX = 8;
|
||||||
|
|
||||||
public static final int UC_MODE_LITTLE_ENDIAN = 0;
|
public static final int UC_MODE_LITTLE_ENDIAN = 0;
|
||||||
|
public static final int UC_MODE_BIG_ENDIAN = 1073741824;
|
||||||
|
|
||||||
public static final int UC_MODE_ARM = 0;
|
public static final int UC_MODE_ARM = 0;
|
||||||
public static final int UC_MODE_16 = 2;
|
|
||||||
public static final int UC_MODE_32 = 4;
|
|
||||||
public static final int UC_MODE_64 = 8;
|
|
||||||
public static final int UC_MODE_THUMB = 16;
|
public static final int UC_MODE_THUMB = 16;
|
||||||
public static final int UC_MODE_MCLASS = 32;
|
public static final int UC_MODE_MCLASS = 32;
|
||||||
public static final int UC_MODE_V8 = 64;
|
public static final int UC_MODE_V8 = 64;
|
||||||
public static final int UC_MODE_MICRO = 16;
|
public static final int UC_MODE_MICRO = 16;
|
||||||
public static final int UC_MODE_MIPS3 = 32;
|
public static final int UC_MODE_MIPS3 = 32;
|
||||||
public static final int UC_MODE_MIPS32R6 = 64;
|
public static final int UC_MODE_MIPS32R6 = 64;
|
||||||
public static final int UC_MODE_V9 = 16;
|
|
||||||
public static final int UC_MODE_QPX = 16;
|
|
||||||
public static final int UC_MODE_BIG_ENDIAN = 1073741824;
|
|
||||||
public static final int UC_MODE_MIPS32 = 4;
|
public static final int UC_MODE_MIPS32 = 4;
|
||||||
public static final int UC_MODE_MIPS64 = 8;
|
public static final int UC_MODE_MIPS64 = 8;
|
||||||
|
public static final int UC_MODE_16 = 2;
|
||||||
|
public static final int UC_MODE_32 = 4;
|
||||||
|
public static final int UC_MODE_64 = 8;
|
||||||
|
public static final int UC_MODE_PPC32 = 4;
|
||||||
|
public static final int UC_MODE_PPC64 = 8;
|
||||||
|
public static final int UC_MODE_QPX = 16;
|
||||||
|
public static final int UC_MODE_SPARC32 = 4;
|
||||||
|
public static final int UC_MODE_SPARC64 = 8;
|
||||||
|
public static final int UC_MODE_V9 = 16;
|
||||||
|
|
||||||
public static final int UC_ERR_OK = 0;
|
public static final int UC_ERR_OK = 0;
|
||||||
public static final int UC_ERR_NOMEM = 1;
|
public static final int UC_ERR_NOMEM = 1;
|
||||||
|
@ -84,6 +88,8 @@ public interface UnicornConst {
|
||||||
public static final int UC_HOOK_MEM_WRITE_INVALID = 288;
|
public static final int UC_HOOK_MEM_WRITE_INVALID = 288;
|
||||||
public static final int UC_HOOK_MEM_FETCH_INVALID = 576;
|
public static final int UC_HOOK_MEM_FETCH_INVALID = 576;
|
||||||
public static final int UC_HOOK_MEM_INVALID = 1008;
|
public static final int UC_HOOK_MEM_INVALID = 1008;
|
||||||
|
public static final int UC_HOOK_MEM_VALID = 7168;
|
||||||
|
public static final int UC_QUERY_MODE = 1;
|
||||||
|
|
||||||
public static final int UC_PROT_NONE = 0;
|
public static final int UC_PROT_NONE = 0;
|
||||||
public static final int UC_PROT_READ = 1;
|
public static final int UC_PROT_READ = 1;
|
||||||
|
|
|
@ -75,7 +75,7 @@ int main(int argc, char **argv, char **envp)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Initialize emulator in MIPS 32bit little endian mode
|
// Initialize emulator in MIPS 32bit little endian mode
|
||||||
err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc);
|
err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32 | UC_MODE_LITTLE_ENDIAN, &uc);
|
||||||
if (err)
|
if (err)
|
||||||
{
|
{
|
||||||
printf("Failed on uc_open() with error returned: %u\n", err);
|
printf("Failed on uc_open() with error returned: %u\n", err);
|
||||||
|
|
|
@ -7,7 +7,6 @@ from unicorn import *
|
||||||
from unicorn.x86_const import *
|
from unicorn.x86_const import *
|
||||||
import struct
|
import struct
|
||||||
import uuid
|
import uuid
|
||||||
import random
|
|
||||||
|
|
||||||
SIZE_REG = 4
|
SIZE_REG = 4
|
||||||
SOCKETCALL_MAX_ARGS = 3
|
SOCKETCALL_MAX_ARGS = 3
|
||||||
|
@ -51,6 +50,7 @@ X86_REVERSE_TCP_2 = b"\x31\xc0\x31\xdb\x31\xc9\x31\xd2\xb0\x66\xb3\x01\x51\x6a\x
|
||||||
# memory address where emulation starts
|
# memory address where emulation starts
|
||||||
ADDRESS = 0x1000000
|
ADDRESS = 0x1000000
|
||||||
|
|
||||||
|
|
||||||
# supported classes
|
# supported classes
|
||||||
class IdGenerator:
|
class IdGenerator:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
|
@ -63,6 +63,7 @@ class IdGenerator:
|
||||||
|
|
||||||
return next_id
|
return next_id
|
||||||
|
|
||||||
|
|
||||||
class LogChain:
|
class LogChain:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.__chains = {}
|
self.__chains = {}
|
||||||
|
@ -72,11 +73,11 @@ class LogChain:
|
||||||
self.__chains = {}
|
self.__chains = {}
|
||||||
self.__linking_fds = {}
|
self.__linking_fds = {}
|
||||||
|
|
||||||
def create_chain(self, id):
|
def create_chain(self, my_id):
|
||||||
if not self.__chains.has_key(id):
|
if not my_id in self.__chains:
|
||||||
self.__chains[id] = []
|
self.__chains[my_id] = []
|
||||||
else:
|
else:
|
||||||
print("LogChain: id %d existed" % id)
|
print("LogChain: id %d existed" % my_id)
|
||||||
|
|
||||||
def add_log(self, id, msg):
|
def add_log(self, id, msg):
|
||||||
fd = self.get_original_fd(id)
|
fd = self.get_original_fd(id)
|
||||||
|
@ -87,16 +88,16 @@ class LogChain:
|
||||||
print("LogChain: id %d doesn't exist" % id)
|
print("LogChain: id %d doesn't exist" % id)
|
||||||
|
|
||||||
def link_fd(self, from_fd, to_fd):
|
def link_fd(self, from_fd, to_fd):
|
||||||
if not self.__linking_fds.has_key(to_fd):
|
if not to_fd in self.__linking_fds:
|
||||||
self.__linking_fds[to_fd] = []
|
self.__linking_fds[to_fd] = []
|
||||||
|
|
||||||
self.__linking_fds[to_fd].append(from_fd)
|
self.__linking_fds[to_fd].append(from_fd)
|
||||||
|
|
||||||
def get_original_fd(self, fd):
|
def get_original_fd(self, fd):
|
||||||
if self.__chains.has_key(fd):
|
if fd in self.__chains:
|
||||||
return fd
|
return fd
|
||||||
|
|
||||||
for orig_fd, links in self.__linking_fds.iteritems():
|
for orig_fd, links in self.__linking_fds.items():
|
||||||
if fd in links:
|
if fd in links:
|
||||||
return orig_fd
|
return orig_fd
|
||||||
|
|
||||||
|
@ -108,10 +109,11 @@ class LogChain:
|
||||||
| START REPORT |
|
| START REPORT |
|
||||||
----------------
|
----------------
|
||||||
""")
|
""")
|
||||||
for id, logs in self.__chains.iteritems():
|
|
||||||
print("---- START FD(%d) ----" % id)
|
for my_id, logs in self.__chains.items():
|
||||||
|
print("---- START FD(%d) ----" % my_id)
|
||||||
print("\n".join(logs))
|
print("\n".join(logs))
|
||||||
print("---- END FD(%d) ----" % id)
|
print("---- END FD(%d) ----" % my_id)
|
||||||
|
|
||||||
print("""
|
print("""
|
||||||
--------------
|
--------------
|
||||||
|
@ -119,10 +121,9 @@ class LogChain:
|
||||||
--------------
|
--------------
|
||||||
""")
|
""")
|
||||||
|
|
||||||
|
|
||||||
# end supported classes
|
# end supported classes
|
||||||
|
|
||||||
id_gen = IdGenerator()
|
|
||||||
fd_chains = LogChain()
|
|
||||||
|
|
||||||
# utilities
|
# utilities
|
||||||
def bin_to_ipv4(ip):
|
def bin_to_ipv4(ip):
|
||||||
|
@ -132,6 +133,7 @@ def bin_to_ipv4(ip):
|
||||||
(ip & 0xff00) >> 8,
|
(ip & 0xff00) >> 8,
|
||||||
(ip & 0xff))
|
(ip & 0xff))
|
||||||
|
|
||||||
|
|
||||||
def read_string(uc, addr):
|
def read_string(uc, addr):
|
||||||
ret = ""
|
ret = ""
|
||||||
|
|
||||||
|
@ -145,6 +147,7 @@ def read_string(uc, addr):
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
|
||||||
def parse_sock_address(sock_addr):
|
def parse_sock_address(sock_addr):
|
||||||
sin_family, = struct.unpack("<h", sock_addr[:2])
|
sin_family, = struct.unpack("<h", sock_addr[:2])
|
||||||
|
|
||||||
|
@ -154,8 +157,11 @@ def parse_sock_address(sock_addr):
|
||||||
elif sin_family == 6: # AF_INET6
|
elif sin_family == 6: # AF_INET6
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
|
|
||||||
def print_sockcall(msg):
|
def print_sockcall(msg):
|
||||||
print(">>> SOCKCALL %s" % msg)
|
print(">>> SOCKCALL %s" % msg)
|
||||||
|
|
||||||
|
|
||||||
# end utilities
|
# end utilities
|
||||||
|
|
||||||
# callback for tracing instructions
|
# callback for tracing instructions
|
||||||
|
@ -168,8 +174,11 @@ def hook_code(uc, address, size, user_data):
|
||||||
print(" %x" % i, end="")
|
print(" %x" % i, end="")
|
||||||
print("")
|
print("")
|
||||||
|
|
||||||
|
|
||||||
# callback for tracing Linux interrupt
|
# callback for tracing Linux interrupt
|
||||||
def hook_intr(uc, intno, user_data):
|
def hook_intr(uc, intno, user_data):
|
||||||
|
global id_gen
|
||||||
|
|
||||||
# only handle Linux syscall
|
# only handle Linux syscall
|
||||||
if intno != 0x80:
|
if intno != 0x80:
|
||||||
return
|
return
|
||||||
|
@ -350,8 +359,11 @@ def hook_intr(uc, intno, user_data):
|
||||||
fd_chains.add_log(fd, msg)
|
fd_chains.add_log(fd, msg)
|
||||||
print_sockcall(msg)
|
print_sockcall(msg)
|
||||||
|
|
||||||
|
|
||||||
# Test X86 32 bit
|
# Test X86 32 bit
|
||||||
def test_i386(code):
|
def test_i386(code):
|
||||||
|
global fd_chains
|
||||||
|
|
||||||
fd_chains.clean()
|
fd_chains.clean()
|
||||||
print("Emulate i386 code")
|
print("Emulate i386 code")
|
||||||
try:
|
try:
|
||||||
|
@ -384,9 +396,13 @@ def test_i386(code):
|
||||||
|
|
||||||
fd_chains.print_report()
|
fd_chains.print_report()
|
||||||
|
|
||||||
|
|
||||||
|
# Globals
|
||||||
|
fd_chains = LogChain()
|
||||||
|
id_gen = IdGenerator()
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
test_i386(X86_SEND_ETCPASSWD)
|
test_i386(X86_SEND_ETCPASSWD)
|
||||||
test_i386(X86_BIND_TCP)
|
test_i386(X86_BIND_TCP)
|
||||||
test_i386(X86_REVERSE_TCP)
|
test_i386(X86_REVERSE_TCP)
|
||||||
test_i386(X86_REVERSE_TCP_2)
|
test_i386(X86_REVERSE_TCP_2)
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ def test_sparc():
|
||||||
print("Emulate SPARC code")
|
print("Emulate SPARC code")
|
||||||
try:
|
try:
|
||||||
# Initialize emulator in SPARC EB mode
|
# Initialize emulator in SPARC EB mode
|
||||||
mu = Uc(UC_ARCH_SPARC, UC_MODE_32)
|
mu = Uc(UC_ARCH_SPARC, UC_MODE_SPARC32|UC_MODE_BIG_ENDIAN)
|
||||||
|
|
||||||
# map 2MB memory for this emulation
|
# map 2MB memory for this emulation
|
||||||
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||||
|
|
|
@ -314,25 +314,7 @@ class Uc(object):
|
||||||
self._callbacks[self._callback_count] = (callback, user_data)
|
self._callbacks[self._callback_count] = (callback, user_data)
|
||||||
cb = None
|
cb = None
|
||||||
|
|
||||||
if htype in (UC_HOOK_BLOCK, UC_HOOK_CODE):
|
if htype == UC_HOOK_INSN:
|
||||||
begin = ctypes.c_uint64(arg1)
|
|
||||||
end = ctypes.c_uint64(arg2)
|
|
||||||
# set callback with wrapper, so it can be called
|
|
||||||
# with this object as param
|
|
||||||
cb = ctypes.cast(UC_HOOK_CODE_CB(self._hookcode_cb), UC_HOOK_CODE_CB)
|
|
||||||
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, cb, \
|
|
||||||
ctypes.cast(self._callback_count, ctypes.c_void_p), begin, end)
|
|
||||||
elif htype & UC_HOOK_MEM_READ_UNMAPPED or htype & UC_HOOK_MEM_WRITE_UNMAPPED or \
|
|
||||||
htype & UC_HOOK_MEM_FETCH_UNMAPPED or htype & UC_HOOK_MEM_READ_PROT or \
|
|
||||||
htype & UC_HOOK_MEM_WRITE_PROT or htype & UC_HOOK_MEM_FETCH_PROT:
|
|
||||||
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 | 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))
|
|
||||||
elif htype == UC_HOOK_INSN:
|
|
||||||
insn = ctypes.c_int(arg1)
|
insn = ctypes.c_int(arg1)
|
||||||
if arg1 == x86_const.UC_X86_INS_IN: # IN instruction
|
if arg1 == x86_const.UC_X86_INS_IN: # IN instruction
|
||||||
cb = ctypes.cast(UC_HOOK_INSN_IN_CB(self._hook_insn_in_cb), UC_HOOK_INSN_IN_CB)
|
cb = ctypes.cast(UC_HOOK_INSN_IN_CB(self._hook_insn_in_cb), UC_HOOK_INSN_IN_CB)
|
||||||
|
@ -346,6 +328,25 @@ class Uc(object):
|
||||||
cb = ctypes.cast(UC_HOOK_INTR_CB(self._hook_intr_cb), UC_HOOK_INTR_CB)
|
cb = ctypes.cast(UC_HOOK_INTR_CB(self._hook_intr_cb), UC_HOOK_INTR_CB)
|
||||||
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
|
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
|
||||||
cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
|
cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
|
||||||
|
else:
|
||||||
|
begin = ctypes.c_uint64(arg1)
|
||||||
|
end = ctypes.c_uint64(arg2)
|
||||||
|
if htype in (UC_HOOK_BLOCK, UC_HOOK_CODE):
|
||||||
|
# set callback with wrapper, so it can be called
|
||||||
|
# with this object as param
|
||||||
|
cb = ctypes.cast(UC_HOOK_CODE_CB(self._hookcode_cb), UC_HOOK_CODE_CB)
|
||||||
|
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, cb, \
|
||||||
|
ctypes.cast(self._callback_count, ctypes.c_void_p), begin, end)
|
||||||
|
elif htype & UC_HOOK_MEM_READ_UNMAPPED or htype & UC_HOOK_MEM_WRITE_UNMAPPED or \
|
||||||
|
htype & UC_HOOK_MEM_FETCH_UNMAPPED or htype & UC_HOOK_MEM_READ_PROT or \
|
||||||
|
htype & UC_HOOK_MEM_WRITE_PROT or htype & UC_HOOK_MEM_FETCH_PROT:
|
||||||
|
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))
|
||||||
|
else:
|
||||||
|
cb = ctypes.cast(UC_HOOK_MEM_ACCESS_CB(self._hook_mem_access_cb), UC_HOOK_MEM_ACCESS_CB)
|
||||||
|
status = _uc.uc_hook_add(self._uch, ctypes.byref(_h2), htype, \
|
||||||
|
cb, ctypes.cast(self._callback_count, ctypes.c_void_p))
|
||||||
|
|
||||||
# save the ctype function so gc will leave it alone.
|
# save the ctype function so gc will leave it alone.
|
||||||
self._ctype_cbs[self._callback_count] = cb
|
self._ctype_cbs[self._callback_count] = cb
|
||||||
|
|
|
@ -14,22 +14,26 @@ UC_ARCH_M68K = 7
|
||||||
UC_ARCH_MAX = 8
|
UC_ARCH_MAX = 8
|
||||||
|
|
||||||
UC_MODE_LITTLE_ENDIAN = 0
|
UC_MODE_LITTLE_ENDIAN = 0
|
||||||
|
UC_MODE_BIG_ENDIAN = 1073741824
|
||||||
|
|
||||||
UC_MODE_ARM = 0
|
UC_MODE_ARM = 0
|
||||||
UC_MODE_16 = 2
|
|
||||||
UC_MODE_32 = 4
|
|
||||||
UC_MODE_64 = 8
|
|
||||||
UC_MODE_THUMB = 16
|
UC_MODE_THUMB = 16
|
||||||
UC_MODE_MCLASS = 32
|
UC_MODE_MCLASS = 32
|
||||||
UC_MODE_V8 = 64
|
UC_MODE_V8 = 64
|
||||||
UC_MODE_MICRO = 16
|
UC_MODE_MICRO = 16
|
||||||
UC_MODE_MIPS3 = 32
|
UC_MODE_MIPS3 = 32
|
||||||
UC_MODE_MIPS32R6 = 64
|
UC_MODE_MIPS32R6 = 64
|
||||||
UC_MODE_V9 = 16
|
|
||||||
UC_MODE_QPX = 16
|
|
||||||
UC_MODE_BIG_ENDIAN = 1073741824
|
|
||||||
UC_MODE_MIPS32 = 4
|
UC_MODE_MIPS32 = 4
|
||||||
UC_MODE_MIPS64 = 8
|
UC_MODE_MIPS64 = 8
|
||||||
|
UC_MODE_16 = 2
|
||||||
|
UC_MODE_32 = 4
|
||||||
|
UC_MODE_64 = 8
|
||||||
|
UC_MODE_PPC32 = 4
|
||||||
|
UC_MODE_PPC64 = 8
|
||||||
|
UC_MODE_QPX = 16
|
||||||
|
UC_MODE_SPARC32 = 4
|
||||||
|
UC_MODE_SPARC64 = 8
|
||||||
|
UC_MODE_V9 = 16
|
||||||
|
|
||||||
UC_ERR_OK = 0
|
UC_ERR_OK = 0
|
||||||
UC_ERR_NOMEM = 1
|
UC_ERR_NOMEM = 1
|
||||||
|
@ -80,6 +84,8 @@ UC_HOOK_MEM_READ_INVALID = 144
|
||||||
UC_HOOK_MEM_WRITE_INVALID = 288
|
UC_HOOK_MEM_WRITE_INVALID = 288
|
||||||
UC_HOOK_MEM_FETCH_INVALID = 576
|
UC_HOOK_MEM_FETCH_INVALID = 576
|
||||||
UC_HOOK_MEM_INVALID = 1008
|
UC_HOOK_MEM_INVALID = 1008
|
||||||
|
UC_HOOK_MEM_VALID = 7168
|
||||||
|
UC_QUERY_MODE = 1
|
||||||
|
|
||||||
UC_PROT_NONE = 0
|
UC_PROT_NONE = 0
|
||||||
UC_PROT_READ = 1
|
UC_PROT_READ = 1
|
||||||
|
|
279
hook.c
279
hook.c
|
@ -1,279 +0,0 @@
|
||||||
/* Unicorn Emulator Engine */
|
|
||||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
|
||||||
|
|
||||||
#include "uc_priv.h"
|
|
||||||
#include "hook.h"
|
|
||||||
|
|
||||||
|
|
||||||
// return index for a new hook entry in hook_callbacks[] array.
|
|
||||||
// this realloc memory if needed.
|
|
||||||
size_t hook_find_new(struct uc_struct *uc)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
struct hook_struct *new;
|
|
||||||
|
|
||||||
// find the first free slot. skip slot 0, so index > 0
|
|
||||||
for(i = 1; i < uc->hook_size; i++) {
|
|
||||||
if (uc->hook_callbacks[i].callback == NULL) {
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// not found, so the array is full.
|
|
||||||
// we have to realloc hook_callbacks[] to contain new hooks
|
|
||||||
new = realloc(uc->hook_callbacks,
|
|
||||||
(uc->hook_size + HOOK_SIZE) * sizeof(uc->hook_callbacks[0]));
|
|
||||||
if (!new) // OOM ?
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
// reset the newly added slots
|
|
||||||
memset(new + uc->hook_size, 0, HOOK_SIZE * sizeof(uc->hook_callbacks[0]));
|
|
||||||
|
|
||||||
uc->hook_callbacks = new;
|
|
||||||
uc->hook_size += HOOK_SIZE;
|
|
||||||
|
|
||||||
// return the first newly allocated slot
|
|
||||||
return uc->hook_size - HOOK_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return -1 on failure, index to hook_callbacks[] on success.
|
|
||||||
size_t hook_add(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, void *callback, void *user_data)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
// find the first free slot. skip slot 0, so index > 0
|
|
||||||
i = hook_find_new(uc);
|
|
||||||
if (i) {
|
|
||||||
uc->hook_callbacks[i].hook_type = type;
|
|
||||||
uc->hook_callbacks[i].begin = begin;
|
|
||||||
uc->hook_callbacks[i].end = end;
|
|
||||||
uc->hook_callbacks[i].callback = callback;
|
|
||||||
uc->hook_callbacks[i].user_data = user_data;
|
|
||||||
|
|
||||||
switch(type) {
|
|
||||||
default: break;
|
|
||||||
case UC_HOOK_BLOCK:
|
|
||||||
uc->hook_block = true;
|
|
||||||
if (begin > end)
|
|
||||||
uc->hook_block_idx = i;
|
|
||||||
break;
|
|
||||||
case UC_HOOK_CODE:
|
|
||||||
uc->hook_insn = true;
|
|
||||||
if (begin > end)
|
|
||||||
uc->hook_insn_idx = i;
|
|
||||||
break;
|
|
||||||
case UC_HOOK_MEM_READ:
|
|
||||||
uc->hook_mem_read = true;
|
|
||||||
if (begin > end)
|
|
||||||
uc->hook_read_idx = i;
|
|
||||||
break;
|
|
||||||
case UC_HOOK_MEM_WRITE:
|
|
||||||
uc->hook_mem_write = true;
|
|
||||||
if (begin > end)
|
|
||||||
uc->hook_write_idx = i;
|
|
||||||
break;
|
|
||||||
case UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE:
|
|
||||||
uc->hook_mem_read = true;
|
|
||||||
uc->hook_mem_write = true;
|
|
||||||
if (begin > end) {
|
|
||||||
uc->hook_read_idx = i;
|
|
||||||
uc->hook_write_idx = i;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
// not found
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return 0 on success, -1 on failure
|
|
||||||
uc_err hook_del(struct uc_struct *uc, uc_hook hh)
|
|
||||||
{
|
|
||||||
if (hh == uc->hook_block_idx) {
|
|
||||||
uc->hook_block_idx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hh == uc->hook_insn_idx) {
|
|
||||||
uc->hook_insn_idx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hh == uc->hook_read_idx) {
|
|
||||||
uc->hook_read_idx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hh == uc->hook_write_idx) {
|
|
||||||
uc->hook_write_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) {
|
|
||||||
uc->hook_intr_idx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hh == uc->hook_out_idx) {
|
|
||||||
uc->hook_out_idx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (hh == uc->hook_in_idx) {
|
|
||||||
uc->hook_in_idx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(hh == uc->hook_syscall_idx) {
|
|
||||||
uc->hook_syscall_idx = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
uc->hook_callbacks[hh].callback = NULL;
|
|
||||||
uc->hook_callbacks[hh].user_data = NULL;
|
|
||||||
uc->hook_callbacks[hh].hook_type = 0;
|
|
||||||
uc->hook_callbacks[hh].begin = 0;
|
|
||||||
uc->hook_callbacks[hh].end = 0;
|
|
||||||
|
|
||||||
return UC_ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// return NULL on failure
|
|
||||||
static struct hook_struct *_hook_find(struct uc_struct *uc, int type, uint64_t address)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
switch(type) {
|
|
||||||
default: break;
|
|
||||||
case UC_HOOK_BLOCK:
|
|
||||||
// already hooked all blocks?
|
|
||||||
if (uc->hook_block_idx)
|
|
||||||
return &uc->hook_callbacks[uc->hook_block_idx];
|
|
||||||
break;
|
|
||||||
case UC_HOOK_CODE:
|
|
||||||
// already hooked all the code?
|
|
||||||
if (uc->hook_insn_idx)
|
|
||||||
return &uc->hook_callbacks[uc->hook_insn_idx];
|
|
||||||
break;
|
|
||||||
case UC_HOOK_MEM_READ:
|
|
||||||
// already hooked all memory read?
|
|
||||||
if (uc->hook_read_idx) {
|
|
||||||
return &uc->hook_callbacks[uc->hook_read_idx];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case UC_HOOK_MEM_WRITE:
|
|
||||||
// already hooked all memory write?
|
|
||||||
if (uc->hook_write_idx)
|
|
||||||
return &uc->hook_callbacks[uc->hook_write_idx];
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// no trace-all callback
|
|
||||||
for(i = 1; i < uc->hook_size; i++) {
|
|
||||||
switch(type) {
|
|
||||||
default: break;
|
|
||||||
case UC_HOOK_BLOCK:
|
|
||||||
case UC_HOOK_CODE:
|
|
||||||
if (uc->hook_callbacks[i].hook_type == type) {
|
|
||||||
if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end)
|
|
||||||
return &uc->hook_callbacks[i];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case UC_HOOK_MEM_READ:
|
|
||||||
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) {
|
|
||||||
if (uc->hook_callbacks[i].begin <= address && address <= uc->hook_callbacks[i].end)
|
|
||||||
return &uc->hook_callbacks[i];
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// not found
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static void hook_count_cb(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data)
|
|
||||||
{
|
|
||||||
// count this instruction
|
|
||||||
uc->emu_counter++;
|
|
||||||
|
|
||||||
if (uc->emu_counter > uc->emu_count)
|
|
||||||
uc_emu_stop(uc);
|
|
||||||
else if (uc->hook_count_callback)
|
|
||||||
uc->hook_count_callback(uc, address, size, user_data);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct hook_struct *hook_find(struct uc_struct *uc, int type, uint64_t address)
|
|
||||||
{
|
|
||||||
// stop executing callbacks if we already got stop request
|
|
||||||
if (uc->stop_request)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
// UC_HOOK_CODE is special because we may need to count instructions
|
|
||||||
if (type == UC_HOOK_CODE && uc->emu_count > 0) {
|
|
||||||
struct hook_struct *st = _hook_find(uc, type, address);
|
|
||||||
if (st) {
|
|
||||||
// prepare this struct to pass back to caller
|
|
||||||
uc->hook_count.hook_type = UC_HOOK_CODE;
|
|
||||||
uc->hook_count.begin = st->begin;
|
|
||||||
uc->hook_count.end = st->end;
|
|
||||||
uc->hook_count.callback = hook_count_cb;
|
|
||||||
uc->hook_count.user_data = st->user_data;
|
|
||||||
// save this hook callback so we can call it later
|
|
||||||
uc->hook_count_callback = st->callback;
|
|
||||||
} else {
|
|
||||||
// there is no callback, but we still need to
|
|
||||||
// handle instruction count
|
|
||||||
uc->hook_count.hook_type = UC_HOOK_CODE;
|
|
||||||
uc->hook_count.begin = 1;
|
|
||||||
uc->hook_count.end = 0;
|
|
||||||
uc->hook_count.callback = hook_count_cb;
|
|
||||||
uc->hook_count.user_data = NULL;
|
|
||||||
uc->hook_count_callback = NULL; // no callback
|
|
||||||
}
|
|
||||||
|
|
||||||
return &(uc->hook_count);
|
|
||||||
} else
|
|
||||||
return _hook_find(uc, type, address);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// TCG helper
|
|
||||||
void helper_uc_tracecode(int32_t size, void *callback, void *handle, int64_t address, void *user_data);
|
|
||||||
void helper_uc_tracecode(int32_t size, void *callback, void *handle, int64_t address, void *user_data)
|
|
||||||
{
|
|
||||||
struct uc_struct *uc = handle;
|
|
||||||
|
|
||||||
// sync PC in CPUArchState with address
|
|
||||||
if (uc->set_pc) {
|
|
||||||
uc->set_pc(uc, address);
|
|
||||||
}
|
|
||||||
|
|
||||||
((uc_cb_hookcode_t)callback)(uc, address, size, user_data);
|
|
||||||
}
|
|
|
@ -1,20 +0,0 @@
|
||||||
/* Unicorn Emulator Engine */
|
|
||||||
/* By Nguyen Anh Quynh <aquynh@gmail.com>, 2015 */
|
|
||||||
|
|
||||||
#ifndef UC_HOOK_H
|
|
||||||
#define UC_HOOK_H
|
|
||||||
|
|
||||||
// return -1 on failure, index to traces[] on success.
|
|
||||||
size_t hook_add(struct uc_struct *uc, int type, uint64_t begin, uint64_t end, void *callback, void *user_data);
|
|
||||||
|
|
||||||
// return 0 on success, -1 on failure
|
|
||||||
uc_err hook_del(struct uc_struct *uc, uc_hook hh);
|
|
||||||
|
|
||||||
// return NULL on failure
|
|
||||||
struct hook_struct *hook_find(struct uc_struct *uc, int type, uint64_t address);
|
|
||||||
|
|
||||||
// return index of an free hook entry in hook_callbacks[] array.
|
|
||||||
// this realloc memory if needed.
|
|
||||||
size_t hook_find_new(struct uc_struct *uc);
|
|
||||||
|
|
||||||
#endif
|
|
20
include/list.h
Normal file
20
include/list.h
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef UC_LLIST_H
|
||||||
|
#define UC_LLIST_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
struct list_item {
|
||||||
|
struct list_item *next;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct list {
|
||||||
|
struct list_item *head, *tail;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct list *list_new(void);
|
||||||
|
void list_clear(struct list *list);
|
||||||
|
void *list_append(struct list *list, void *data);
|
||||||
|
bool list_remove(struct list *list, void *data);
|
||||||
|
|
||||||
|
#endif
|
|
@ -9,7 +9,16 @@
|
||||||
|
|
||||||
#include "qemu.h"
|
#include "qemu.h"
|
||||||
#include "unicorn/unicorn.h"
|
#include "unicorn/unicorn.h"
|
||||||
#include "hook.h"
|
#include "list.h"
|
||||||
|
|
||||||
|
// These are masks of supported modes for each cpu/arch.
|
||||||
|
// They should be updated when changes are made to the uc_mode enum typedef.
|
||||||
|
#define UC_MODE_ARM_MASK (UC_MODE_ARM|UC_MODE_THUMB|UC_MODE_LITTLE_ENDIAN)
|
||||||
|
#define UC_MODE_MIPS_MASK (UC_MODE_MIPS32|UC_MODE_MIPS64|UC_MODE_LITTLE_ENDIAN|UC_MODE_BIG_ENDIAN)
|
||||||
|
#define UC_MODE_X86_MASK (UC_MODE_16|UC_MODE_32|UC_MODE_64|UC_MODE_LITTLE_ENDIAN)
|
||||||
|
#define UC_MODE_PPC_MASK (UC_MODE_PPC64|UC_MODE_BIG_ENDIAN)
|
||||||
|
#define UC_MODE_SPARC_MASK (UC_MODE_SPARC32|UC_MODE_SPARC64|UC_MODE_BIG_ENDIAN)
|
||||||
|
#define UC_MODE_M68K_MASK (UC_MODE_BIG_ENDIAN)
|
||||||
|
|
||||||
#define ARR_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
#define ARR_SIZE(a) (sizeof(a)/sizeof(a[0]))
|
||||||
|
|
||||||
|
@ -23,6 +32,8 @@ typedef struct ModuleEntry {
|
||||||
|
|
||||||
typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
|
typedef QTAILQ_HEAD(, ModuleEntry) ModuleTypeList;
|
||||||
|
|
||||||
|
typedef uc_err (*query_t)(struct uc_struct *uc, uc_query_type type, size_t *result);
|
||||||
|
|
||||||
// return 0 on success, -1 on failure
|
// return 0 on success, -1 on failure
|
||||||
typedef int (*reg_read_t)(struct uc_struct *uc, unsigned int regid, void *value);
|
typedef int (*reg_read_t)(struct uc_struct *uc, unsigned int regid, void *value);
|
||||||
typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int regid, const void *value);
|
typedef int (*reg_write_t)(struct uc_struct *uc, unsigned int regid, const void *value);
|
||||||
|
@ -60,16 +71,62 @@ typedef bool (*uc_args_int_t)(int intno);
|
||||||
// some architecture redirect virtual memory to physical memory like Mips
|
// some architecture redirect virtual memory to physical memory like Mips
|
||||||
typedef uint64_t (*uc_mem_redirect_t)(uint64_t address);
|
typedef uint64_t (*uc_mem_redirect_t)(uint64_t address);
|
||||||
|
|
||||||
|
struct hook {
|
||||||
struct hook_struct {
|
int type; // UC_HOOK_*
|
||||||
int hook_type; // uc_tracecode_type & uc_tracemem_type
|
int insn; // instruction for HOOK_INSN
|
||||||
uint64_t begin, end; // range of address to be monitored
|
int refs; // reference count to free hook stored in multiple lists
|
||||||
void *callback; // either uc_cb_tracecode_t or uc_cb_tracemem_t
|
uint64_t begin, end; // only trigger if PC or memory access is in this address (depends on hook type)
|
||||||
|
void *callback; // a uc_cb_* type
|
||||||
void *user_data;
|
void *user_data;
|
||||||
};
|
};
|
||||||
|
|
||||||
// extend memory to keep 32 more hooks each time
|
// hook list offsets
|
||||||
#define HOOK_SIZE 32
|
// mirrors the order of uc_hook_type from include/unicorn/unicorn.h
|
||||||
|
enum uc_hook_idx {
|
||||||
|
UC_HOOK_INTR_IDX,
|
||||||
|
UC_HOOK_INSN_IDX,
|
||||||
|
UC_HOOK_CODE_IDX,
|
||||||
|
UC_HOOK_BLOCK_IDX,
|
||||||
|
UC_HOOK_MEM_READ_UNMAPPED_IDX,
|
||||||
|
UC_HOOK_MEM_WRITE_UNMAPPED_IDX,
|
||||||
|
UC_HOOK_MEM_FETCH_UNMAPPED_IDX,
|
||||||
|
UC_HOOK_MEM_READ_PROT_IDX,
|
||||||
|
UC_HOOK_MEM_WRITE_PROT_IDX,
|
||||||
|
UC_HOOK_MEM_FETCH_PROT_IDX,
|
||||||
|
UC_HOOK_MEM_READ_IDX,
|
||||||
|
UC_HOOK_MEM_WRITE_IDX,
|
||||||
|
UC_HOOK_MEM_FETCH_IDX,
|
||||||
|
|
||||||
|
UC_HOOK_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
|
// for loop macro to loop over hook lists
|
||||||
|
#define HOOK_FOREACH(uc, hh, idx) \
|
||||||
|
struct list_item *cur; \
|
||||||
|
for ( \
|
||||||
|
cur = (uc)->hook[idx##_IDX].head; \
|
||||||
|
cur != NULL && ((hh) = (struct hook *)cur->data) \
|
||||||
|
/* stop excuting callbacks on stop request */ \
|
||||||
|
&& !uc->stop_request; \
|
||||||
|
cur = cur->next)
|
||||||
|
|
||||||
|
// if statement to check hook bounds
|
||||||
|
#define HOOK_BOUND_CHECK(hh, addr) \
|
||||||
|
((((addr) >= (hh)->begin && (addr) <= (hh)->end) \
|
||||||
|
|| (hh)->begin > (hh)->end))
|
||||||
|
|
||||||
|
#define HOOK_EXISTS(uc, idx) ((uc)->hook[idx##_IDX].head != NULL)
|
||||||
|
#define HOOK_EXISTS_BOUNDED(uc, idx, addr) _hook_exists_bounded((uc)->hook[idx##_IDX].head, addr)
|
||||||
|
|
||||||
|
static inline bool _hook_exists_bounded(struct list_item *cur, uint64_t addr)
|
||||||
|
{
|
||||||
|
while (cur != NULL) {
|
||||||
|
if (HOOK_BOUND_CHECK((struct hook *)cur->data, addr))
|
||||||
|
return true;
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
//relloc increment, KEEP THIS A POWER OF 2!
|
//relloc increment, KEEP THIS A POWER OF 2!
|
||||||
#define MEM_BLOCK_INCR 32
|
#define MEM_BLOCK_INCR 32
|
||||||
|
@ -84,6 +141,7 @@ struct uc_struct {
|
||||||
struct CPUTailQ cpus; // qemu/cpu-exec.c
|
struct CPUTailQ cpus; // qemu/cpu-exec.c
|
||||||
uc_err errnum; // qemu/cpu-exec.c
|
uc_err errnum; // qemu/cpu-exec.c
|
||||||
AddressSpace as;
|
AddressSpace as;
|
||||||
|
query_t query;
|
||||||
reg_read_t reg_read;
|
reg_read_t reg_read;
|
||||||
reg_write_t reg_write;
|
reg_write_t reg_write;
|
||||||
reg_reset_t reg_reset;
|
reg_reset_t reg_reset;
|
||||||
|
@ -146,38 +204,20 @@ struct uc_struct {
|
||||||
bool apic_report_tpr_access;
|
bool apic_report_tpr_access;
|
||||||
CPUState *current_cpu;
|
CPUState *current_cpu;
|
||||||
|
|
||||||
// all the hook callbacks
|
// linked lists containing hooks per type
|
||||||
size_t hook_size;
|
struct list hook[UC_HOOK_MAX];
|
||||||
struct hook_struct *hook_callbacks;
|
|
||||||
|
|
||||||
// hook to count number of instructions for uc_emu_start()
|
// hook to count number of instructions for uc_emu_start()
|
||||||
struct hook_struct hook_count;
|
uc_hook count_hook;
|
||||||
uc_cb_hookcode_t hook_count_callback;
|
|
||||||
|
|
||||||
size_t emu_counter; // current counter of uc_emu_start()
|
size_t emu_counter; // current counter of uc_emu_start()
|
||||||
size_t emu_count; // save counter of uc_emu_start()
|
size_t emu_count; // save counter of uc_emu_start()
|
||||||
|
|
||||||
// indexes if hooking ALL block/code/read/write events
|
|
||||||
unsigned int hook_block_idx, hook_insn_idx, hook_read_idx, hook_write_idx;
|
|
||||||
// boolean variables for quick check on hooking block, code, memory accesses
|
|
||||||
bool hook_block, hook_insn, hook_mem_read, hook_mem_write;
|
|
||||||
uint64_t block_addr; // save the last block address we hooked
|
uint64_t block_addr; // save the last block address we hooked
|
||||||
// indexes to event callbacks
|
|
||||||
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)
|
|
||||||
int hook_syscall_idx; // for handling SYSCALL/SYSENTER (X86)
|
|
||||||
|
|
||||||
|
|
||||||
bool init_tcg; // already initialized local TCGv variables?
|
bool init_tcg; // already initialized local TCGv variables?
|
||||||
bool stop_request; // request to immediately stop emulation - for uc_emu_stop()
|
bool stop_request; // request to immediately stop emulation - for uc_emu_stop()
|
||||||
|
bool quit_request; // request to quit the current TB, but continue to emulate - for uc_mem_protect()
|
||||||
bool emulation_done; // emulation is done by uc_emu_start()
|
bool emulation_done; // emulation is done by uc_emu_start()
|
||||||
QemuThread timer; // timer for emulation timeout
|
QemuThread timer; // timer for emulation timeout
|
||||||
uint64_t timeout; // timeout for uc_emu_start()
|
uint64_t timeout; // timeout for uc_emu_start()
|
||||||
|
|
|
@ -60,8 +60,10 @@ typedef size_t uc_hook;
|
||||||
#define UC_API_MAJOR 0
|
#define UC_API_MAJOR 0
|
||||||
#define UC_API_MINOR 9
|
#define UC_API_MINOR 9
|
||||||
|
|
||||||
// Macro to create combined version which can be compared to
|
/*
|
||||||
// result of uc_version() API.
|
Macro to create combined version which can be compared to
|
||||||
|
result of uc_version() API.
|
||||||
|
*/
|
||||||
#define UC_MAKE_VERSION(major, minor) ((major << 8) + minor)
|
#define UC_MAKE_VERSION(major, minor) ((major << 8) + minor)
|
||||||
|
|
||||||
// Scales to calculate timeout on microsecond unit
|
// Scales to calculate timeout on microsecond unit
|
||||||
|
@ -76,7 +78,7 @@ typedef enum uc_arch {
|
||||||
UC_ARCH_ARM64, // ARM-64, also called AArch64
|
UC_ARCH_ARM64, // ARM-64, also called AArch64
|
||||||
UC_ARCH_MIPS, // Mips architecture
|
UC_ARCH_MIPS, // Mips architecture
|
||||||
UC_ARCH_X86, // X86 architecture (including x86 & x86-64)
|
UC_ARCH_X86, // X86 architecture (including x86 & x86-64)
|
||||||
UC_ARCH_PPC, // PowerPC architecture
|
UC_ARCH_PPC, // PowerPC architecture (currently unsupported)
|
||||||
UC_ARCH_SPARC, // Sparc architecture
|
UC_ARCH_SPARC, // Sparc architecture
|
||||||
UC_ARCH_M68K, // M68K architecture
|
UC_ARCH_M68K, // M68K architecture
|
||||||
UC_ARCH_MAX,
|
UC_ARCH_MAX,
|
||||||
|
@ -85,21 +87,31 @@ typedef enum uc_arch {
|
||||||
// Mode type
|
// Mode type
|
||||||
typedef enum uc_mode {
|
typedef enum uc_mode {
|
||||||
UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode)
|
UC_MODE_LITTLE_ENDIAN = 0, // little-endian mode (default mode)
|
||||||
UC_MODE_ARM = 0, // 32-bit ARM
|
|
||||||
UC_MODE_16 = 1 << 1, // 16-bit mode (X86)
|
|
||||||
UC_MODE_32 = 1 << 2, // 32-bit mode (X86)
|
|
||||||
UC_MODE_64 = 1 << 3, // 64-bit mode (X86, PPC)
|
|
||||||
UC_MODE_THUMB = 1 << 4, // ARM's Thumb mode, including Thumb-2
|
|
||||||
UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series
|
|
||||||
UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM
|
|
||||||
UC_MODE_MICRO = 1 << 4, // MicroMips mode (MIPS)
|
|
||||||
UC_MODE_MIPS3 = 1 << 5, // Mips III ISA
|
|
||||||
UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA
|
|
||||||
UC_MODE_V9 = 1 << 4, // SparcV9 mode (Sparc)
|
|
||||||
UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (PPC)
|
|
||||||
UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode
|
UC_MODE_BIG_ENDIAN = 1 << 30, // big-endian mode
|
||||||
UC_MODE_MIPS32 = UC_MODE_32, // Mips32 ISA (Mips)
|
// arm / arm64
|
||||||
UC_MODE_MIPS64 = UC_MODE_64, // Mips64 ISA (Mips)
|
UC_MODE_ARM = 0, // ARM mode
|
||||||
|
UC_MODE_THUMB = 1 << 4, // THUMB mode (including Thumb-2)
|
||||||
|
UC_MODE_MCLASS = 1 << 5, // ARM's Cortex-M series (currently unsupported)
|
||||||
|
UC_MODE_V8 = 1 << 6, // ARMv8 A32 encodings for ARM (currently unsupported)
|
||||||
|
// mips
|
||||||
|
UC_MODE_MICRO = 1 << 4, // MicroMips mode (currently unsupported)
|
||||||
|
UC_MODE_MIPS3 = 1 << 5, // Mips III ISA (currently unsupported)
|
||||||
|
UC_MODE_MIPS32R6 = 1 << 6, // Mips32r6 ISA (currently unsupported)
|
||||||
|
UC_MODE_MIPS32 = 1 << 2, // Mips32 ISA
|
||||||
|
UC_MODE_MIPS64 = 1 << 3, // Mips64 ISA
|
||||||
|
// x86 / x64
|
||||||
|
UC_MODE_16 = 1 << 1, // 16-bit mode
|
||||||
|
UC_MODE_32 = 1 << 2, // 32-bit mode
|
||||||
|
UC_MODE_64 = 1 << 3, // 64-bit mode
|
||||||
|
// ppc
|
||||||
|
UC_MODE_PPC32 = 1 << 2, // 32-bit mode (currently unsupported)
|
||||||
|
UC_MODE_PPC64 = 1 << 3, // 64-bit mode (currently unsupported)
|
||||||
|
UC_MODE_QPX = 1 << 4, // Quad Processing eXtensions mode (currently unsupported)
|
||||||
|
// sparc
|
||||||
|
UC_MODE_SPARC32 = 1 << 2, // 32-bit mode
|
||||||
|
UC_MODE_SPARC64 = 1 << 3, // 64-bit mode
|
||||||
|
UC_MODE_V9 = 1 << 4, // SparcV9 mode (currently unsupported)
|
||||||
|
// m68k
|
||||||
} uc_mode;
|
} uc_mode;
|
||||||
|
|
||||||
// All type of errors encountered by Unicorn API.
|
// All type of errors encountered by Unicorn API.
|
||||||
|
@ -129,27 +141,39 @@ typedef enum uc_err {
|
||||||
} uc_err;
|
} uc_err;
|
||||||
|
|
||||||
|
|
||||||
// Callback function for tracing code (UC_HOOK_CODE & UC_HOOK_BLOCK)
|
/*
|
||||||
// @address: address where the code is being executed
|
Callback function for tracing code (UC_HOOK_CODE & UC_HOOK_BLOCK)
|
||||||
// @size: size of machine instruction(s) being executed, or 0 when size is unknown
|
|
||||||
// @user_data: user data passed to tracing APIs.
|
@address: address where the code is being executed
|
||||||
|
@size: size of machine instruction(s) being executed, or 0 when size is unknown
|
||||||
|
@user_data: user data passed to tracing APIs.
|
||||||
|
*/
|
||||||
typedef void (*uc_cb_hookcode_t)(uc_engine *uc, uint64_t address, uint32_t size, void *user_data);
|
typedef void (*uc_cb_hookcode_t)(uc_engine *uc, uint64_t address, uint32_t size, void *user_data);
|
||||||
|
|
||||||
// Callback function for tracing interrupts (for uc_hook_intr())
|
/*
|
||||||
// @intno: interrupt number
|
Callback function for tracing interrupts (for uc_hook_intr())
|
||||||
// @user_data: user data passed to tracing APIs.
|
|
||||||
|
@intno: interrupt number
|
||||||
|
@user_data: user data passed to tracing APIs.
|
||||||
|
*/
|
||||||
typedef void (*uc_cb_hookintr_t)(uc_engine *uc, uint32_t intno, void *user_data);
|
typedef void (*uc_cb_hookintr_t)(uc_engine *uc, uint32_t intno, void *user_data);
|
||||||
|
|
||||||
// Callback function for tracing IN instruction of X86
|
/*
|
||||||
// @port: port number
|
Callback function for tracing IN instruction of X86
|
||||||
// @size: data size (1/2/4) to be read from this port
|
|
||||||
// @user_data: user data passed to tracing APIs.
|
@port: port number
|
||||||
|
@size: data size (1/2/4) to be read from this port
|
||||||
|
@user_data: user data passed to tracing APIs.
|
||||||
|
*/
|
||||||
typedef uint32_t (*uc_cb_insn_in_t)(uc_engine *uc, uint32_t port, int size, void *user_data);
|
typedef uint32_t (*uc_cb_insn_in_t)(uc_engine *uc, uint32_t port, int size, void *user_data);
|
||||||
|
|
||||||
// x86's handler for OUT
|
/*
|
||||||
// @port: port number
|
Callback function for OUT instruction of X86
|
||||||
// @size: data size (1/2/4) to be written to this port
|
|
||||||
// @value: data value to be written to this port
|
@port: port number
|
||||||
|
@size: data size (1/2/4) to be written to this port
|
||||||
|
@value: data value to be written to this port
|
||||||
|
*/
|
||||||
typedef void (*uc_cb_insn_out_t)(uc_engine *uc, uint32_t port, int size, uint32_t value, void *user_data);
|
typedef void (*uc_cb_insn_out_t)(uc_engine *uc, uint32_t port, int size, uint32_t value, void *user_data);
|
||||||
|
|
||||||
// All type of memory accesses for UC_HOOK_MEM_*
|
// All type of memory accesses for UC_HOOK_MEM_*
|
||||||
|
@ -194,27 +218,52 @@ typedef enum uc_hook_type {
|
||||||
#define UC_HOOK_MEM_FETCH_INVALID (UC_HOOK_MEM_FETCH_PROT + UC_HOOK_MEM_FETCH_UNMAPPED)
|
#define UC_HOOK_MEM_FETCH_INVALID (UC_HOOK_MEM_FETCH_PROT + UC_HOOK_MEM_FETCH_UNMAPPED)
|
||||||
// hook type for all events of illegal memory access
|
// hook type for all events of illegal memory access
|
||||||
#define UC_HOOK_MEM_INVALID (UC_HOOK_MEM_UNMAPPED + UC_HOOK_MEM_PROT)
|
#define UC_HOOK_MEM_INVALID (UC_HOOK_MEM_UNMAPPED + UC_HOOK_MEM_PROT)
|
||||||
|
// hook type for all events of valid memory access
|
||||||
|
#define UC_HOOK_MEM_VALID (UC_HOOK_MEM_READ + UC_HOOK_MEM_WRITE + UC_HOOK_MEM_FETCH)
|
||||||
|
|
||||||
// Callback function for hooking memory (UC_MEM_READ, UC_MEM_WRITE & UC_MEM_FETCH)
|
/*
|
||||||
// @type: this memory is being READ, or WRITE
|
Callback function for hooking memory (UC_MEM_READ, UC_MEM_WRITE & UC_MEM_FETCH)
|
||||||
// @address: address where the code is being executed
|
|
||||||
// @size: size of data being read or written
|
@type: this memory is being READ, or WRITE
|
||||||
// @value: value of data being written to memory, or irrelevant if type = READ.
|
@address: address where the code is being executed
|
||||||
// @user_data: user data passed to tracing APIs
|
@size: size of data being read or written
|
||||||
|
@value: value of data being written to memory, or irrelevant if type = READ.
|
||||||
|
@user_data: user data passed to tracing APIs
|
||||||
|
*/
|
||||||
typedef void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type,
|
typedef void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type,
|
||||||
uint64_t address, int size, int64_t value, void *user_data);
|
uint64_t address, int size, int64_t value, void *user_data);
|
||||||
|
|
||||||
// Callback function for handling invalid memory access events (UC_MEM_*_UNMAPPED and
|
/*
|
||||||
// UC_MEM_*PROT events)
|
Callback function for handling invalid memory access events (UC_MEM_*_UNMAPPED and
|
||||||
// @type: this memory is being READ, or WRITE
|
UC_MEM_*PROT events)
|
||||||
// @address: address where the code is being executed
|
|
||||||
// @size: size of data being read or written
|
@type: this memory is being READ, or WRITE
|
||||||
// @value: value of data being written to memory, or irrelevant if type = READ.
|
@address: address where the code is being executed
|
||||||
// @user_data: user data passed to tracing APIs
|
@size: size of data being read or written
|
||||||
// @return: return true to continue, or false to stop program (due to invalid memory).
|
@value: value of data being written to memory, or irrelevant if type = READ.
|
||||||
|
@user_data: user data passed to tracing APIs
|
||||||
|
|
||||||
|
@return: return true to continue, or false to stop program (due to invalid memory).
|
||||||
|
*/
|
||||||
typedef bool (*uc_cb_eventmem_t)(uc_engine *uc, uc_mem_type type,
|
typedef bool (*uc_cb_eventmem_t)(uc_engine *uc, uc_mem_type type,
|
||||||
uint64_t address, int size, int64_t value, void *user_data);
|
uint64_t address, int size, int64_t value, void *user_data);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Memory region mapped by uc_mem_map() and uc_mem_map_ptr()
|
||||||
|
Retrieve the list of memory regions with uc_mem_regions()
|
||||||
|
*/
|
||||||
|
typedef struct uc_mem_region {
|
||||||
|
uint64_t begin; // begin address of the region (inclusive)
|
||||||
|
uint64_t end; // end address of the region (inclusive)
|
||||||
|
uint32_t perms; // memory permissions of the region
|
||||||
|
} uc_mem_region;
|
||||||
|
|
||||||
|
// All type of queries for uc_query() API.
|
||||||
|
typedef enum uc_query_type {
|
||||||
|
// Dynamically query current hardware mode.
|
||||||
|
// For ARM, uc_query() return 1 for Thumb mode, and 0 for Arm mode
|
||||||
|
UC_QUERY_MODE = 1,
|
||||||
|
} uc_query_type;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Return combined API version & major and minor version numbers.
|
Return combined API version & major and minor version numbers.
|
||||||
|
@ -276,6 +325,19 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **uc);
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_close(uc_engine *uc);
|
uc_err uc_close(uc_engine *uc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Query internal status of engine.
|
||||||
|
|
||||||
|
@uc: handle returned by uc_open()
|
||||||
|
@type: query type. See uc_query_type
|
||||||
|
|
||||||
|
@result: save the internal status queried
|
||||||
|
|
||||||
|
@return: error code of uc_err enum type (UC_ERR_*, see above)
|
||||||
|
*/
|
||||||
|
UNICORN_EXPORT
|
||||||
|
uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Report the last error number when some API function fail.
|
Report the last error number when some API function fail.
|
||||||
Like glibc's errno, uc_errno might not retain its old value once accessed.
|
Like glibc's errno, uc_errno might not retain its old value once accessed.
|
||||||
|
@ -472,7 +534,7 @@ uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t per
|
||||||
Unmap a region of emulation memory.
|
Unmap a region of emulation memory.
|
||||||
This API deletes a memory mapping from the emulation memory space.
|
This API deletes a memory mapping from the emulation memory space.
|
||||||
|
|
||||||
@handle: handle returned by uc_open()
|
@uc: handle returned by uc_open()
|
||||||
@address: starting address of the memory region to be unmapped.
|
@address: starting address of the memory region to be unmapped.
|
||||||
This address must be aligned to 4KB, or this will return with UC_ERR_ARG error.
|
This address must be aligned to 4KB, or this will return with UC_ERR_ARG error.
|
||||||
@size: size of the memory region to be modified.
|
@size: size of the memory region to be modified.
|
||||||
|
@ -488,7 +550,7 @@ uc_err uc_mem_unmap(uc_engine *uc, uint64_t address, size_t size);
|
||||||
Set memory permissions for emulation memory.
|
Set memory permissions for emulation memory.
|
||||||
This API changes permissions on an existing memory region.
|
This API changes permissions on an existing memory region.
|
||||||
|
|
||||||
@handle: handle returned by uc_open()
|
@uc: handle returned by uc_open()
|
||||||
@address: starting address of the memory region to be modified.
|
@address: starting address of the memory region to be modified.
|
||||||
This address must be aligned to 4KB, or this will return with UC_ERR_ARG error.
|
This address must be aligned to 4KB, or this will return with UC_ERR_ARG error.
|
||||||
@size: size of the memory region to be modified.
|
@size: size of the memory region to be modified.
|
||||||
|
@ -503,6 +565,23 @@ uc_err uc_mem_unmap(uc_engine *uc, uint64_t address, size_t size);
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size, uint32_t perms);
|
uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size, uint32_t perms);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Retrieve all memory regions mapped by uc_mem_map() and uc_mem_map_ptr()
|
||||||
|
This API allocates memory for @regions, and user must free this memory later
|
||||||
|
by free() to avoid leaking memory.
|
||||||
|
NOTE: memory regions may be splitted by uc_mem_unmap()
|
||||||
|
|
||||||
|
@uc: handle returned by uc_open()
|
||||||
|
@regions: pointer to an array of uc_mem_region struct. This is allocated by
|
||||||
|
Unicorn, and must be freed by user later
|
||||||
|
@count: pointer to number of struct uc_mem_region contained in @regions
|
||||||
|
|
||||||
|
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||||
|
for detailed error).
|
||||||
|
*/
|
||||||
|
UNICORN_EXPORT
|
||||||
|
uc_err uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
68
list.c
Normal file
68
list.c
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
// simple linked list implementation
|
||||||
|
|
||||||
|
struct list *list_new(void)
|
||||||
|
{
|
||||||
|
return calloc(1, sizeof(struct list));
|
||||||
|
}
|
||||||
|
|
||||||
|
// removed linked list nodes but does not free their content
|
||||||
|
void list_clear(struct list *list)
|
||||||
|
{
|
||||||
|
struct list_item *next, *cur = list->head;
|
||||||
|
while (cur != NULL) {
|
||||||
|
next = cur->next;
|
||||||
|
free(cur);
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
list->head = NULL;
|
||||||
|
list->tail = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns generated linked list node, or NULL on failure
|
||||||
|
void *list_append(struct list *list, void *data)
|
||||||
|
{
|
||||||
|
struct list_item *item = malloc(sizeof(struct list_item));
|
||||||
|
if (item == NULL) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
item->next = NULL;
|
||||||
|
item->data = data;
|
||||||
|
if (list->head == NULL) {
|
||||||
|
list->head = item;
|
||||||
|
} else {
|
||||||
|
list->tail->next = item;
|
||||||
|
}
|
||||||
|
list->tail = item;
|
||||||
|
return item;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns true if entry was removed, false otherwise
|
||||||
|
bool list_remove(struct list *list, void *data)
|
||||||
|
{
|
||||||
|
struct list_item *next, *cur, *prev = NULL;
|
||||||
|
// is list empty?
|
||||||
|
if (list->head == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cur = list->head;
|
||||||
|
while (cur != NULL) {
|
||||||
|
next = cur->next;
|
||||||
|
if (cur->data == data) {
|
||||||
|
if (cur == list->head) {
|
||||||
|
list->head = next;
|
||||||
|
}
|
||||||
|
if (cur == list->tail) {
|
||||||
|
list->tail = prev;
|
||||||
|
}
|
||||||
|
free(cur);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
prev = cur;
|
||||||
|
cur = next;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
|
@ -6,7 +6,7 @@ util-obj-y = util/ qobject/ qapi/ qapi-types.o qapi-visit.o
|
||||||
# block-obj-y is code used by both qemu system emulation and qemu-img
|
# block-obj-y is code used by both qemu system emulation and qemu-img
|
||||||
|
|
||||||
block-obj-y =
|
block-obj-y =
|
||||||
block-obj-y += ../uc.o ../hook.o
|
block-obj-y += ../uc.o ../list.o
|
||||||
#block-obj-$(CONFIG_POSIX) += aio-posix.o
|
#block-obj-$(CONFIG_POSIX) += aio-posix.o
|
||||||
#block-obj-$(CONFIG_WIN32) += aio-win32.o
|
#block-obj-$(CONFIG_WIN32) += aio-win32.o
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||||
#ifndef UNICORN_AUTOGEN_AARCH64_H
|
#ifndef UNICORN_AUTOGEN_AARCH64_H
|
||||||
#define UNICORN_AUTOGEN_AARCH64_H
|
#define UNICORN_AUTOGEN_AARCH64_H
|
||||||
|
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_aarch64
|
||||||
|
#define use_idiv_instructions_rt use_idiv_instructions_rt_aarch64
|
||||||
|
#define tcg_target_deposit_valid tcg_target_deposit_valid_aarch64
|
||||||
#define helper_power_down helper_power_down_aarch64
|
#define helper_power_down helper_power_down_aarch64
|
||||||
#define check_exit_request check_exit_request_aarch64
|
#define check_exit_request check_exit_request_aarch64
|
||||||
#define address_space_unregister address_space_unregister_aarch64
|
#define address_space_unregister address_space_unregister_aarch64
|
||||||
|
@ -2806,7 +2809,6 @@
|
||||||
#define tb_phys_invalidate tb_phys_invalidate_aarch64
|
#define tb_phys_invalidate tb_phys_invalidate_aarch64
|
||||||
#define tb_reset_jump tb_reset_jump_aarch64
|
#define tb_reset_jump tb_reset_jump_aarch64
|
||||||
#define tb_set_jmp_target tb_set_jmp_target_aarch64
|
#define tb_set_jmp_target tb_set_jmp_target_aarch64
|
||||||
#define tb_set_jmp_target1 tb_set_jmp_target1_aarch64
|
|
||||||
#define tcg_accel_class_init tcg_accel_class_init_aarch64
|
#define tcg_accel_class_init tcg_accel_class_init_aarch64
|
||||||
#define tcg_accel_type tcg_accel_type_aarch64
|
#define tcg_accel_type tcg_accel_type_aarch64
|
||||||
#define tcg_add_param_i32 tcg_add_param_i32_aarch64
|
#define tcg_add_param_i32 tcg_add_param_i32_aarch64
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||||
#ifndef UNICORN_AUTOGEN_ARM_H
|
#ifndef UNICORN_AUTOGEN_ARM_H
|
||||||
#define UNICORN_AUTOGEN_ARM_H
|
#define UNICORN_AUTOGEN_ARM_H
|
||||||
|
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_arm
|
||||||
|
#define use_idiv_instructions_rt use_idiv_instructions_rt_arm
|
||||||
|
#define tcg_target_deposit_valid tcg_target_deposit_valid_arm
|
||||||
#define helper_power_down helper_power_down_arm
|
#define helper_power_down helper_power_down_arm
|
||||||
#define check_exit_request check_exit_request_arm
|
#define check_exit_request check_exit_request_arm
|
||||||
#define address_space_unregister address_space_unregister_arm
|
#define address_space_unregister address_space_unregister_arm
|
||||||
|
@ -2806,7 +2809,6 @@
|
||||||
#define tb_phys_invalidate tb_phys_invalidate_arm
|
#define tb_phys_invalidate tb_phys_invalidate_arm
|
||||||
#define tb_reset_jump tb_reset_jump_arm
|
#define tb_reset_jump tb_reset_jump_arm
|
||||||
#define tb_set_jmp_target tb_set_jmp_target_arm
|
#define tb_set_jmp_target tb_set_jmp_target_arm
|
||||||
#define tb_set_jmp_target1 tb_set_jmp_target1_arm
|
|
||||||
#define tcg_accel_class_init tcg_accel_class_init_arm
|
#define tcg_accel_class_init tcg_accel_class_init_arm
|
||||||
#define tcg_accel_type tcg_accel_type_arm
|
#define tcg_accel_type tcg_accel_type_arm
|
||||||
#define tcg_add_param_i32 tcg_add_param_i32_arm
|
#define tcg_add_param_i32 tcg_add_param_i32_arm
|
||||||
|
|
3
qemu/configure
vendored
3
qemu/configure
vendored
|
@ -1520,8 +1520,6 @@ echo "PIE $pie"
|
||||||
|
|
||||||
config_host_mak="config-host.mak"
|
config_host_mak="config-host.mak"
|
||||||
|
|
||||||
echo "# Automatically generated by configure - do not modify" >config-all-disas.mak
|
|
||||||
|
|
||||||
echo "# Automatically generated by configure - do not modify" > $config_host_mak
|
echo "# Automatically generated by configure - do not modify" > $config_host_mak
|
||||||
echo >> $config_host_mak
|
echo >> $config_host_mak
|
||||||
|
|
||||||
|
@ -1905,7 +1903,6 @@ ldflags=""
|
||||||
|
|
||||||
if test "$tcg_interpreter" = "yes" ; then
|
if test "$tcg_interpreter" = "yes" ; then
|
||||||
echo "CONFIG_TCI_DIS=y" >> $config_target_mak
|
echo "CONFIG_TCI_DIS=y" >> $config_target_mak
|
||||||
echo "CONFIG_TCI_DIS=y" >> config-all-disas.mak
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
case "$ARCH" in
|
case "$ARCH" in
|
||||||
|
|
|
@ -64,6 +64,8 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq
|
||||||
TranslationBlock *tb;
|
TranslationBlock *tb;
|
||||||
uint8_t *tc_ptr;
|
uint8_t *tc_ptr;
|
||||||
uintptr_t next_tb;
|
uintptr_t next_tb;
|
||||||
|
struct hook *hook;
|
||||||
|
|
||||||
|
|
||||||
/* This must be volatile so it is not trashed by longjmp() */
|
/* This must be volatile so it is not trashed by longjmp() */
|
||||||
volatile bool have_tb_lock = false;
|
volatile bool have_tb_lock = false;
|
||||||
|
@ -92,12 +94,14 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq
|
||||||
|
|
||||||
cc->cpu_exec_enter(cpu);
|
cc->cpu_exec_enter(cpu);
|
||||||
cpu->exception_index = -1;
|
cpu->exception_index = -1;
|
||||||
|
env->invalid_error = UC_ERR_OK;
|
||||||
|
|
||||||
/* prepare setjmp context for exception handling */
|
/* prepare setjmp context for exception handling */
|
||||||
for(;;) {
|
for(;;) {
|
||||||
if (sigsetjmp(cpu->jmp_env, 0) == 0) {
|
if (sigsetjmp(cpu->jmp_env, 0) == 0) {
|
||||||
if (uc->stop_request || uc->invalid_error)
|
if (uc->stop_request || uc->invalid_error)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* if an exception is pending, we execute it here */
|
/* if an exception is pending, we execute it here */
|
||||||
if (cpu->exception_index >= 0) {
|
if (cpu->exception_index >= 0) {
|
||||||
//printf(">>> GOT INTERRUPT. exception idx = %x\n", cpu->exception_index); // qq
|
//printf(">>> GOT INTERRUPT. exception idx = %x\n", cpu->exception_index); // qq
|
||||||
|
@ -126,11 +130,10 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq
|
||||||
ret = cpu->exception_index;
|
ret = cpu->exception_index;
|
||||||
break;
|
break;
|
||||||
#else
|
#else
|
||||||
// Unicorn: call interrupt callback if registered
|
// Unicorn: call registered interrupt callbacks
|
||||||
if (uc->hook_intr_idx)
|
HOOK_FOREACH(uc, hook, UC_HOOK_INTR) {
|
||||||
((uc_cb_hookintr_t)uc->hook_callbacks[uc->hook_intr_idx].callback)(
|
((uc_cb_hookintr_t)hook->callback)(uc, cpu->exception_index, hook->user_data);
|
||||||
uc, cpu->exception_index,
|
}
|
||||||
uc->hook_callbacks[uc->hook_intr_idx].user_data);
|
|
||||||
cpu->exception_index = -1;
|
cpu->exception_index = -1;
|
||||||
#if defined(TARGET_X86_64)
|
#if defined(TARGET_X86_64)
|
||||||
// point EIP to the next instruction after INT
|
// point EIP to the next instruction after INT
|
||||||
|
@ -233,6 +236,7 @@ int cpu_exec(struct uc_struct *uc, CPUArchState *env) // qq
|
||||||
tc_ptr = tb->tc_ptr;
|
tc_ptr = tb->tc_ptr;
|
||||||
/* execute the generated code */
|
/* execute the generated code */
|
||||||
next_tb = cpu_tb_exec(cpu, tc_ptr); // qq
|
next_tb = cpu_tb_exec(cpu, tc_ptr); // qq
|
||||||
|
|
||||||
switch (next_tb & TB_EXIT_MASK) {
|
switch (next_tb & TB_EXIT_MASK) {
|
||||||
case TB_EXIT_REQUESTED:
|
case TB_EXIT_REQUESTED:
|
||||||
/* Something asked us to stop executing
|
/* Something asked us to stop executing
|
||||||
|
@ -299,12 +303,13 @@ static tcg_target_ulong cpu_tb_exec(CPUState *cpu, uint8_t *tb_ptr)
|
||||||
TranslationBlock *tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
|
TranslationBlock *tb = (TranslationBlock *)(next_tb & ~TB_EXIT_MASK);
|
||||||
if (cc->synchronize_from_tb) {
|
if (cc->synchronize_from_tb) {
|
||||||
// avoid sync twice when helper_uc_tracecode() already did this.
|
// avoid sync twice when helper_uc_tracecode() already did this.
|
||||||
if (env->uc->emu_counter <= env->uc->emu_count && !env->uc->stop_request)
|
if (env->uc->emu_counter <= env->uc->emu_count &&
|
||||||
|
!env->uc->stop_request && !env->uc->quit_request)
|
||||||
cc->synchronize_from_tb(cpu, tb);
|
cc->synchronize_from_tb(cpu, tb);
|
||||||
} else {
|
} else {
|
||||||
assert(cc->set_pc);
|
assert(cc->set_pc);
|
||||||
// avoid sync twice when helper_uc_tracecode() already did this.
|
// avoid sync twice when helper_uc_tracecode() already did this.
|
||||||
if (env->uc->emu_counter <= env->uc->emu_count)
|
if (env->uc->emu_counter <= env->uc->emu_count && !env->uc->quit_request)
|
||||||
cc->set_pc(cpu, tb->pc);
|
cc->set_pc(cpu, tb->pc);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -230,8 +230,14 @@ static bool tcg_exec_all(struct uc_struct* uc)
|
||||||
//qemu_clock_enable(QEMU_CLOCK_VIRTUAL,
|
//qemu_clock_enable(QEMU_CLOCK_VIRTUAL,
|
||||||
// (cpu->singlestep_enabled & SSTEP_NOTIMER) == 0);
|
// (cpu->singlestep_enabled & SSTEP_NOTIMER) == 0);
|
||||||
if (cpu_can_run(cpu)) {
|
if (cpu_can_run(cpu)) {
|
||||||
|
uc->quit_request = false;
|
||||||
r = tcg_cpu_exec(uc, env);
|
r = tcg_cpu_exec(uc, env);
|
||||||
if (uc->stop_request) {
|
|
||||||
|
// quit current TB but continue emulating?
|
||||||
|
if (uc->quit_request) {
|
||||||
|
// reset stop_request
|
||||||
|
uc->stop_request = false;
|
||||||
|
} else if (uc->stop_request) {
|
||||||
//printf(">>> got STOP request!!!\n");
|
//printf(">>> got STOP request!!!\n");
|
||||||
finish = true;
|
finish = true;
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -7,6 +7,9 @@
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
symbols = (
|
symbols = (
|
||||||
|
'aarch64_tb_set_jmp_target',
|
||||||
|
'use_idiv_instructions_rt',
|
||||||
|
'tcg_target_deposit_valid',
|
||||||
'helper_power_down',
|
'helper_power_down',
|
||||||
'check_exit_request',
|
'check_exit_request',
|
||||||
'address_space_unregister',
|
'address_space_unregister',
|
||||||
|
@ -2812,7 +2815,6 @@ symbols = (
|
||||||
'tb_phys_invalidate',
|
'tb_phys_invalidate',
|
||||||
'tb_reset_jump',
|
'tb_reset_jump',
|
||||||
'tb_set_jmp_target',
|
'tb_set_jmp_target',
|
||||||
'tb_set_jmp_target1',
|
|
||||||
'tcg_accel_class_init',
|
'tcg_accel_class_init',
|
||||||
'tcg_accel_type',
|
'tcg_accel_type',
|
||||||
'tcg_add_param_i32',
|
'tcg_add_param_i32',
|
||||||
|
|
|
@ -66,39 +66,45 @@ const MemoryRegionOps unassigned_io_ops = {
|
||||||
void cpu_outb(struct uc_struct *uc, pio_addr_t addr, uint8_t val)
|
void cpu_outb(struct uc_struct *uc, pio_addr_t addr, uint8_t val)
|
||||||
{
|
{
|
||||||
//LOG_IOPORT("outb: %04"FMT_pioaddr" %02"PRIx8"\n", addr, val);
|
//LOG_IOPORT("outb: %04"FMT_pioaddr" %02"PRIx8"\n", addr, val);
|
||||||
// Unicorn: call interrupt callback if registered
|
// Unicorn: call registered OUT callbacks
|
||||||
if (uc->hook_out_idx)
|
struct hook *hook;
|
||||||
((uc_cb_insn_out_t)uc->hook_callbacks[uc->hook_out_idx].callback)(
|
HOOK_FOREACH(uc, hook, UC_HOOK_INSN) {
|
||||||
uc, addr, 1, val,
|
if (hook->insn == UC_X86_INS_OUT)
|
||||||
uc->hook_callbacks[uc->hook_out_idx].user_data);
|
((uc_cb_insn_out_t)hook->callback)(uc, addr, 1, val, hook->user_data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_outw(struct uc_struct *uc, pio_addr_t addr, uint16_t val)
|
void cpu_outw(struct uc_struct *uc, pio_addr_t addr, uint16_t val)
|
||||||
{
|
{
|
||||||
//LOG_IOPORT("outw: %04"FMT_pioaddr" %04"PRIx16"\n", addr, val);
|
//LOG_IOPORT("outw: %04"FMT_pioaddr" %04"PRIx16"\n", addr, val);
|
||||||
// Unicorn: call interrupt callback if registered
|
// Unicorn: call registered OUT callbacks
|
||||||
if (uc->hook_out_idx)
|
struct hook *hook;
|
||||||
((uc_cb_insn_out_t)uc->hook_callbacks[uc->hook_out_idx].callback)(
|
HOOK_FOREACH(uc, hook, UC_HOOK_INSN) {
|
||||||
uc, addr, 2, val,
|
if (hook->insn == UC_X86_INS_OUT)
|
||||||
uc->hook_callbacks[uc->hook_out_idx].user_data);
|
((uc_cb_insn_out_t)hook->callback)(uc, addr, 2, val, hook->user_data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_outl(struct uc_struct *uc, pio_addr_t addr, uint32_t val)
|
void cpu_outl(struct uc_struct *uc, pio_addr_t addr, uint32_t val)
|
||||||
{
|
{
|
||||||
//LOG_IOPORT("outl: %04"FMT_pioaddr" %08"PRIx32"\n", addr, val);
|
//LOG_IOPORT("outl: %04"FMT_pioaddr" %08"PRIx32"\n", addr, val);
|
||||||
if (uc->hook_out_idx)
|
// Unicorn: call registered OUT callbacks
|
||||||
((uc_cb_insn_out_t)uc->hook_callbacks[uc->hook_out_idx].callback)(
|
struct hook *hook;
|
||||||
uc, addr, 4, val,
|
HOOK_FOREACH(uc, hook, UC_HOOK_INSN) {
|
||||||
uc->hook_callbacks[uc->hook_out_idx].user_data);
|
if (hook->insn == UC_X86_INS_OUT)
|
||||||
|
((uc_cb_insn_out_t)hook->callback)(uc, addr, 4, val, hook->user_data);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t cpu_inb(struct uc_struct *uc, pio_addr_t addr)
|
uint8_t cpu_inb(struct uc_struct *uc, pio_addr_t addr)
|
||||||
{
|
{
|
||||||
//LOG_IOPORT("inb : %04"FMT_pioaddr" %02"PRIx8"\n", addr, val);
|
//LOG_IOPORT("inb : %04"FMT_pioaddr" %02"PRIx8"\n", addr, val);
|
||||||
if (uc->hook_in_idx)
|
// Unicorn: call registered IN callbacks
|
||||||
return ((uc_cb_insn_in_t)uc->hook_callbacks[uc->hook_in_idx].callback)(
|
struct hook *hook;
|
||||||
uc, addr, 1,
|
HOOK_FOREACH(uc, hook, UC_HOOK_INSN) {
|
||||||
uc->hook_callbacks[uc->hook_in_idx].user_data);
|
if (hook->insn == UC_X86_INS_IN)
|
||||||
|
return ((uc_cb_insn_in_t)hook->callback)(uc, addr, 1, hook->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -106,10 +112,12 @@ uint8_t cpu_inb(struct uc_struct *uc, pio_addr_t addr)
|
||||||
uint16_t cpu_inw(struct uc_struct *uc, pio_addr_t addr)
|
uint16_t cpu_inw(struct uc_struct *uc, pio_addr_t addr)
|
||||||
{
|
{
|
||||||
//LOG_IOPORT("inw : %04"FMT_pioaddr" %04"PRIx16"\n", addr, val);
|
//LOG_IOPORT("inw : %04"FMT_pioaddr" %04"PRIx16"\n", addr, val);
|
||||||
if (uc->hook_in_idx)
|
// Unicorn: call registered IN callbacks
|
||||||
return ((uc_cb_insn_in_t)uc->hook_callbacks[uc->hook_in_idx].callback)(
|
struct hook *hook;
|
||||||
uc, addr, 2,
|
HOOK_FOREACH(uc, hook, UC_HOOK_INSN) {
|
||||||
uc->hook_callbacks[uc->hook_in_idx].user_data);
|
if (hook->insn == UC_X86_INS_IN)
|
||||||
|
return ((uc_cb_insn_in_t)hook->callback)(uc, addr, 2, hook->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -117,10 +125,12 @@ uint16_t cpu_inw(struct uc_struct *uc, pio_addr_t addr)
|
||||||
uint32_t cpu_inl(struct uc_struct *uc, pio_addr_t addr)
|
uint32_t cpu_inl(struct uc_struct *uc, pio_addr_t addr)
|
||||||
{
|
{
|
||||||
//LOG_IOPORT("inl : %04"FMT_pioaddr" %08"PRIx32"\n", addr, val);
|
//LOG_IOPORT("inl : %04"FMT_pioaddr" %08"PRIx32"\n", addr, val);
|
||||||
if (uc->hook_in_idx)
|
// Unicorn: call registered IN callbacks
|
||||||
return ((uc_cb_insn_in_t)uc->hook_callbacks[uc->hook_in_idx].callback)(
|
struct hook *hook;
|
||||||
uc, addr, 4,
|
HOOK_FOREACH(uc, hook, UC_HOOK_INSN) {
|
||||||
uc->hook_callbacks[uc->hook_in_idx].user_data);
|
if (hook->insn == UC_X86_INS_IN)
|
||||||
|
return ((uc_cb_insn_in_t)hook->callback)(uc, addr, 4, hook->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||||
#ifndef UNICORN_AUTOGEN_M68K_H
|
#ifndef UNICORN_AUTOGEN_M68K_H
|
||||||
#define UNICORN_AUTOGEN_M68K_H
|
#define UNICORN_AUTOGEN_M68K_H
|
||||||
|
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_m68k
|
||||||
|
#define use_idiv_instructions_rt use_idiv_instructions_rt_m68k
|
||||||
|
#define tcg_target_deposit_valid tcg_target_deposit_valid_m68k
|
||||||
#define helper_power_down helper_power_down_m68k
|
#define helper_power_down helper_power_down_m68k
|
||||||
#define check_exit_request check_exit_request_m68k
|
#define check_exit_request check_exit_request_m68k
|
||||||
#define address_space_unregister address_space_unregister_m68k
|
#define address_space_unregister address_space_unregister_m68k
|
||||||
|
@ -2806,7 +2809,6 @@
|
||||||
#define tb_phys_invalidate tb_phys_invalidate_m68k
|
#define tb_phys_invalidate tb_phys_invalidate_m68k
|
||||||
#define tb_reset_jump tb_reset_jump_m68k
|
#define tb_reset_jump tb_reset_jump_m68k
|
||||||
#define tb_set_jmp_target tb_set_jmp_target_m68k
|
#define tb_set_jmp_target tb_set_jmp_target_m68k
|
||||||
#define tb_set_jmp_target1 tb_set_jmp_target1_m68k
|
|
||||||
#define tcg_accel_class_init tcg_accel_class_init_m68k
|
#define tcg_accel_class_init tcg_accel_class_init_m68k
|
||||||
#define tcg_accel_type tcg_accel_type_m68k
|
#define tcg_accel_type tcg_accel_type_m68k
|
||||||
#define tcg_add_param_i32 tcg_add_param_i32_m68k
|
#define tcg_add_param_i32 tcg_add_param_i32_m68k
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||||
#ifndef UNICORN_AUTOGEN_MIPS_H
|
#ifndef UNICORN_AUTOGEN_MIPS_H
|
||||||
#define UNICORN_AUTOGEN_MIPS_H
|
#define UNICORN_AUTOGEN_MIPS_H
|
||||||
|
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_mips
|
||||||
|
#define use_idiv_instructions_rt use_idiv_instructions_rt_mips
|
||||||
|
#define tcg_target_deposit_valid tcg_target_deposit_valid_mips
|
||||||
#define helper_power_down helper_power_down_mips
|
#define helper_power_down helper_power_down_mips
|
||||||
#define check_exit_request check_exit_request_mips
|
#define check_exit_request check_exit_request_mips
|
||||||
#define address_space_unregister address_space_unregister_mips
|
#define address_space_unregister address_space_unregister_mips
|
||||||
|
@ -2806,7 +2809,6 @@
|
||||||
#define tb_phys_invalidate tb_phys_invalidate_mips
|
#define tb_phys_invalidate tb_phys_invalidate_mips
|
||||||
#define tb_reset_jump tb_reset_jump_mips
|
#define tb_reset_jump tb_reset_jump_mips
|
||||||
#define tb_set_jmp_target tb_set_jmp_target_mips
|
#define tb_set_jmp_target tb_set_jmp_target_mips
|
||||||
#define tb_set_jmp_target1 tb_set_jmp_target1_mips
|
|
||||||
#define tcg_accel_class_init tcg_accel_class_init_mips
|
#define tcg_accel_class_init tcg_accel_class_init_mips
|
||||||
#define tcg_accel_type tcg_accel_type_mips
|
#define tcg_accel_type tcg_accel_type_mips
|
||||||
#define tcg_add_param_i32 tcg_add_param_i32_mips
|
#define tcg_add_param_i32 tcg_add_param_i32_mips
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||||
#ifndef UNICORN_AUTOGEN_MIPS64_H
|
#ifndef UNICORN_AUTOGEN_MIPS64_H
|
||||||
#define UNICORN_AUTOGEN_MIPS64_H
|
#define UNICORN_AUTOGEN_MIPS64_H
|
||||||
|
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_mips64
|
||||||
|
#define use_idiv_instructions_rt use_idiv_instructions_rt_mips64
|
||||||
|
#define tcg_target_deposit_valid tcg_target_deposit_valid_mips64
|
||||||
#define helper_power_down helper_power_down_mips64
|
#define helper_power_down helper_power_down_mips64
|
||||||
#define check_exit_request check_exit_request_mips64
|
#define check_exit_request check_exit_request_mips64
|
||||||
#define address_space_unregister address_space_unregister_mips64
|
#define address_space_unregister address_space_unregister_mips64
|
||||||
|
@ -2806,7 +2809,6 @@
|
||||||
#define tb_phys_invalidate tb_phys_invalidate_mips64
|
#define tb_phys_invalidate tb_phys_invalidate_mips64
|
||||||
#define tb_reset_jump tb_reset_jump_mips64
|
#define tb_reset_jump tb_reset_jump_mips64
|
||||||
#define tb_set_jmp_target tb_set_jmp_target_mips64
|
#define tb_set_jmp_target tb_set_jmp_target_mips64
|
||||||
#define tb_set_jmp_target1 tb_set_jmp_target1_mips64
|
|
||||||
#define tcg_accel_class_init tcg_accel_class_init_mips64
|
#define tcg_accel_class_init tcg_accel_class_init_mips64
|
||||||
#define tcg_accel_type tcg_accel_type_mips64
|
#define tcg_accel_type tcg_accel_type_mips64
|
||||||
#define tcg_add_param_i32 tcg_add_param_i32_mips64
|
#define tcg_add_param_i32 tcg_add_param_i32_mips64
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||||
#ifndef UNICORN_AUTOGEN_MIPS64EL_H
|
#ifndef UNICORN_AUTOGEN_MIPS64EL_H
|
||||||
#define UNICORN_AUTOGEN_MIPS64EL_H
|
#define UNICORN_AUTOGEN_MIPS64EL_H
|
||||||
|
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_mips64el
|
||||||
|
#define use_idiv_instructions_rt use_idiv_instructions_rt_mips64el
|
||||||
|
#define tcg_target_deposit_valid tcg_target_deposit_valid_mips64el
|
||||||
#define helper_power_down helper_power_down_mips64el
|
#define helper_power_down helper_power_down_mips64el
|
||||||
#define check_exit_request check_exit_request_mips64el
|
#define check_exit_request check_exit_request_mips64el
|
||||||
#define address_space_unregister address_space_unregister_mips64el
|
#define address_space_unregister address_space_unregister_mips64el
|
||||||
|
@ -2806,7 +2809,6 @@
|
||||||
#define tb_phys_invalidate tb_phys_invalidate_mips64el
|
#define tb_phys_invalidate tb_phys_invalidate_mips64el
|
||||||
#define tb_reset_jump tb_reset_jump_mips64el
|
#define tb_reset_jump tb_reset_jump_mips64el
|
||||||
#define tb_set_jmp_target tb_set_jmp_target_mips64el
|
#define tb_set_jmp_target tb_set_jmp_target_mips64el
|
||||||
#define tb_set_jmp_target1 tb_set_jmp_target1_mips64el
|
|
||||||
#define tcg_accel_class_init tcg_accel_class_init_mips64el
|
#define tcg_accel_class_init tcg_accel_class_init_mips64el
|
||||||
#define tcg_accel_type tcg_accel_type_mips64el
|
#define tcg_accel_type tcg_accel_type_mips64el
|
||||||
#define tcg_add_param_i32 tcg_add_param_i32_mips64el
|
#define tcg_add_param_i32 tcg_add_param_i32_mips64el
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||||
#ifndef UNICORN_AUTOGEN_MIPSEL_H
|
#ifndef UNICORN_AUTOGEN_MIPSEL_H
|
||||||
#define UNICORN_AUTOGEN_MIPSEL_H
|
#define UNICORN_AUTOGEN_MIPSEL_H
|
||||||
|
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_mipsel
|
||||||
|
#define use_idiv_instructions_rt use_idiv_instructions_rt_mipsel
|
||||||
|
#define tcg_target_deposit_valid tcg_target_deposit_valid_mipsel
|
||||||
#define helper_power_down helper_power_down_mipsel
|
#define helper_power_down helper_power_down_mipsel
|
||||||
#define check_exit_request check_exit_request_mipsel
|
#define check_exit_request check_exit_request_mipsel
|
||||||
#define address_space_unregister address_space_unregister_mipsel
|
#define address_space_unregister address_space_unregister_mipsel
|
||||||
|
@ -2806,7 +2809,6 @@
|
||||||
#define tb_phys_invalidate tb_phys_invalidate_mipsel
|
#define tb_phys_invalidate tb_phys_invalidate_mipsel
|
||||||
#define tb_reset_jump tb_reset_jump_mipsel
|
#define tb_reset_jump tb_reset_jump_mipsel
|
||||||
#define tb_set_jmp_target tb_set_jmp_target_mipsel
|
#define tb_set_jmp_target tb_set_jmp_target_mipsel
|
||||||
#define tb_set_jmp_target1 tb_set_jmp_target1_mipsel
|
|
||||||
#define tcg_accel_class_init tcg_accel_class_init_mipsel
|
#define tcg_accel_class_init tcg_accel_class_init_mipsel
|
||||||
#define tcg_accel_type tcg_accel_type_mipsel
|
#define tcg_accel_type tcg_accel_type_mipsel
|
||||||
#define tcg_add_param_i32 tcg_add_param_i32_mipsel
|
#define tcg_add_param_i32 tcg_add_param_i32_mipsel
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||||
#ifndef UNICORN_AUTOGEN_POWERPC_H
|
#ifndef UNICORN_AUTOGEN_POWERPC_H
|
||||||
#define UNICORN_AUTOGEN_POWERPC_H
|
#define UNICORN_AUTOGEN_POWERPC_H
|
||||||
|
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_powerpc
|
||||||
|
#define use_idiv_instructions_rt use_idiv_instructions_rt_powerpc
|
||||||
|
#define tcg_target_deposit_valid tcg_target_deposit_valid_powerpc
|
||||||
#define helper_power_down helper_power_down_powerpc
|
#define helper_power_down helper_power_down_powerpc
|
||||||
#define check_exit_request check_exit_request_powerpc
|
#define check_exit_request check_exit_request_powerpc
|
||||||
#define address_space_unregister address_space_unregister_powerpc
|
#define address_space_unregister address_space_unregister_powerpc
|
||||||
|
@ -2806,7 +2809,6 @@
|
||||||
#define tb_phys_invalidate tb_phys_invalidate_powerpc
|
#define tb_phys_invalidate tb_phys_invalidate_powerpc
|
||||||
#define tb_reset_jump tb_reset_jump_powerpc
|
#define tb_reset_jump tb_reset_jump_powerpc
|
||||||
#define tb_set_jmp_target tb_set_jmp_target_powerpc
|
#define tb_set_jmp_target tb_set_jmp_target_powerpc
|
||||||
#define tb_set_jmp_target1 tb_set_jmp_target1_powerpc
|
|
||||||
#define tcg_accel_class_init tcg_accel_class_init_powerpc
|
#define tcg_accel_class_init tcg_accel_class_init_powerpc
|
||||||
#define tcg_accel_type tcg_accel_type_powerpc
|
#define tcg_accel_type tcg_accel_type_powerpc
|
||||||
#define tcg_add_param_i32 tcg_add_param_i32_powerpc
|
#define tcg_add_param_i32 tcg_add_param_i32_powerpc
|
||||||
|
|
|
@ -178,23 +178,33 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
|
||||||
uintptr_t haddr;
|
uintptr_t haddr;
|
||||||
DATA_TYPE res;
|
DATA_TYPE res;
|
||||||
int error_code;
|
int error_code;
|
||||||
|
struct hook *hook;
|
||||||
|
bool handled;
|
||||||
|
|
||||||
struct uc_struct *uc = env->uc;
|
struct uc_struct *uc = env->uc;
|
||||||
MemoryRegion *mr = memory_mapping(uc, addr);
|
MemoryRegion *mr = memory_mapping(uc, addr);
|
||||||
|
|
||||||
// memory might be still unmapped while reading or fetching
|
// memory might be still unmapped while reading or fetching
|
||||||
if (mr == NULL) {
|
if (mr == NULL) {
|
||||||
|
handled = false;
|
||||||
#if defined(SOFTMMU_CODE_ACCESS)
|
#if defined(SOFTMMU_CODE_ACCESS)
|
||||||
error_code = UC_ERR_FETCH_UNMAPPED;
|
error_code = UC_ERR_FETCH_UNMAPPED;
|
||||||
if (uc->hook_mem_fetch_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_idx].callback)(
|
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_FETCH_UNMAPPED) {
|
||||||
uc, UC_MEM_FETCH_UNMAPPED, addr, DATA_SIZE, 0,
|
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||||
uc->hook_callbacks[uc->hook_mem_fetch_idx].user_data)) {
|
continue;
|
||||||
|
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_UNMAPPED, addr, DATA_SIZE, 0, hook->user_data)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
error_code = UC_ERR_READ_UNMAPPED;
|
error_code = UC_ERR_READ_UNMAPPED;
|
||||||
if (uc->hook_mem_read_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_idx].callback)(
|
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ_UNMAPPED) {
|
||||||
uc, UC_MEM_READ_UNMAPPED, addr, DATA_SIZE, 0,
|
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||||
uc->hook_callbacks[uc->hook_mem_read_idx].user_data)) {
|
continue;
|
||||||
|
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_UNMAPPED, addr, DATA_SIZE, 0, hook->user_data)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if (handled) {
|
||||||
env->invalid_error = UC_ERR_OK;
|
env->invalid_error = UC_ERR_OK;
|
||||||
mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time?
|
mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time?
|
||||||
} else {
|
} else {
|
||||||
|
@ -209,9 +219,15 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
|
||||||
#if defined(SOFTMMU_CODE_ACCESS)
|
#if defined(SOFTMMU_CODE_ACCESS)
|
||||||
// Unicorn: callback on fetch from NX
|
// Unicorn: callback on fetch from NX
|
||||||
if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable
|
if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable
|
||||||
if (uc->hook_mem_fetch_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].callback)(
|
handled = false;
|
||||||
uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0,
|
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_FETCH_PROT) {
|
||||||
uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].user_data)) {
|
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||||
|
continue;
|
||||||
|
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0, hook->user_data)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handled) {
|
||||||
env->invalid_error = UC_ERR_OK;
|
env->invalid_error = UC_ERR_OK;
|
||||||
} else {
|
} else {
|
||||||
env->invalid_addr = addr;
|
env->invalid_addr = addr;
|
||||||
|
@ -224,19 +240,25 @@ WORD_TYPE helper_le_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Unicorn: callback on memory read
|
// Unicorn: callback on memory read
|
||||||
if (READ_ACCESS_TYPE == MMU_DATA_LOAD && env->uc->hook_mem_read) {
|
if (READ_ACCESS_TYPE == MMU_DATA_LOAD) {
|
||||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_MEM_READ, addr);
|
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ) {
|
||||||
if (trace) {
|
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||||
((uc_cb_hookmem_t)trace->callback)(env->uc, UC_MEM_READ,
|
continue;
|
||||||
(uint64_t)addr, (int)DATA_SIZE, (int64_t)0, trace->user_data);
|
((uc_cb_hookmem_t)hook->callback)(env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, hook->user_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unicorn: callback on non-readable memory
|
// Unicorn: callback on non-readable memory
|
||||||
if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable
|
if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable
|
||||||
if (uc->hook_mem_read_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_prot_idx].callback)(
|
handled = false;
|
||||||
uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0,
|
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ_PROT) {
|
||||||
uc->hook_callbacks[uc->hook_mem_read_prot_idx].user_data)) {
|
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||||
|
continue;
|
||||||
|
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, hook->user_data)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handled) {
|
||||||
env->invalid_error = UC_ERR_OK;
|
env->invalid_error = UC_ERR_OK;
|
||||||
} else {
|
} else {
|
||||||
env->invalid_addr = addr;
|
env->invalid_addr = addr;
|
||||||
|
@ -368,23 +390,33 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
|
||||||
uintptr_t haddr;
|
uintptr_t haddr;
|
||||||
DATA_TYPE res;
|
DATA_TYPE res;
|
||||||
int error_code;
|
int error_code;
|
||||||
|
struct hook *hook;
|
||||||
|
bool handled;
|
||||||
|
|
||||||
struct uc_struct *uc = env->uc;
|
struct uc_struct *uc = env->uc;
|
||||||
MemoryRegion *mr = memory_mapping(uc, addr);
|
MemoryRegion *mr = memory_mapping(uc, addr);
|
||||||
|
|
||||||
// memory can be unmapped while reading or fetching
|
// memory can be unmapped while reading or fetching
|
||||||
if (mr == NULL) {
|
if (mr == NULL) {
|
||||||
|
handled = false;
|
||||||
#if defined(SOFTMMU_CODE_ACCESS)
|
#if defined(SOFTMMU_CODE_ACCESS)
|
||||||
error_code = UC_ERR_FETCH_UNMAPPED;
|
error_code = UC_ERR_FETCH_UNMAPPED;
|
||||||
if (uc->hook_mem_fetch_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_idx].callback)(
|
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_FETCH_UNMAPPED) {
|
||||||
uc, UC_MEM_FETCH_UNMAPPED, addr, DATA_SIZE, 0,
|
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||||
uc->hook_callbacks[uc->hook_mem_fetch_idx].user_data)) {
|
continue;
|
||||||
|
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_UNMAPPED, addr, DATA_SIZE, 0, hook->user_data)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
#else
|
#else
|
||||||
error_code = UC_ERR_READ_UNMAPPED;
|
error_code = UC_ERR_READ_UNMAPPED;
|
||||||
if (uc->hook_mem_read_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_idx].callback)(
|
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ_UNMAPPED) {
|
||||||
uc, UC_MEM_READ_UNMAPPED, addr, DATA_SIZE, 0,
|
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||||
uc->hook_callbacks[uc->hook_mem_read_idx].user_data)) {
|
continue;
|
||||||
|
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_UNMAPPED, addr, DATA_SIZE, 0, hook->user_data)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
if (handled) {
|
||||||
env->invalid_error = UC_ERR_OK;
|
env->invalid_error = UC_ERR_OK;
|
||||||
mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time?
|
mr = memory_mapping(uc, addr); // FIXME: what if mr is still NULL at this time?
|
||||||
} else {
|
} else {
|
||||||
|
@ -399,9 +431,15 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
|
||||||
#if defined(SOFTMMU_CODE_ACCESS)
|
#if defined(SOFTMMU_CODE_ACCESS)
|
||||||
// Unicorn: callback on fetch from NX
|
// Unicorn: callback on fetch from NX
|
||||||
if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable
|
if (mr != NULL && !(mr->perms & UC_PROT_EXEC)) { // non-executable
|
||||||
if (uc->hook_mem_fetch_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].callback)(
|
handled = false;
|
||||||
uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0,
|
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_FETCH_PROT) {
|
||||||
uc->hook_callbacks[uc->hook_mem_fetch_prot_idx].user_data)) {
|
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||||
|
continue;
|
||||||
|
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_FETCH_PROT, addr, DATA_SIZE, 0, hook->user_data)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handled) {
|
||||||
env->invalid_error = UC_ERR_OK;
|
env->invalid_error = UC_ERR_OK;
|
||||||
} else {
|
} else {
|
||||||
env->invalid_addr = addr;
|
env->invalid_addr = addr;
|
||||||
|
@ -414,19 +452,25 @@ WORD_TYPE helper_be_ld_name(CPUArchState *env, target_ulong addr, int mmu_idx,
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Unicorn: callback on memory read
|
// Unicorn: callback on memory read
|
||||||
if (READ_ACCESS_TYPE == MMU_DATA_LOAD && env->uc->hook_mem_read) {
|
if (READ_ACCESS_TYPE == MMU_DATA_LOAD) {
|
||||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_MEM_READ, addr);
|
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ) {
|
||||||
if (trace) {
|
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||||
((uc_cb_hookmem_t)trace->callback)(env->uc, UC_MEM_READ,
|
continue;
|
||||||
(uint64_t)addr, (int)DATA_SIZE, (int64_t)0, trace->user_data);
|
((uc_cb_hookmem_t)hook->callback)(env->uc, UC_MEM_READ, addr, DATA_SIZE, 0, hook->user_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unicorn: callback on non-readable memory
|
// Unicorn: callback on non-readable memory
|
||||||
if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable
|
if (READ_ACCESS_TYPE == MMU_DATA_LOAD && mr != NULL && !(mr->perms & UC_PROT_READ)) { //non-readable
|
||||||
if (uc->hook_mem_read_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_read_prot_idx].callback)(
|
handled = false;
|
||||||
uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0,
|
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_READ_PROT) {
|
||||||
uc->hook_callbacks[uc->hook_mem_read_prot_idx].user_data)) {
|
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||||
|
continue;
|
||||||
|
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_READ_PROT, addr, DATA_SIZE, 0, hook->user_data)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handled) {
|
||||||
env->invalid_error = UC_ERR_OK;
|
env->invalid_error = UC_ERR_OK;
|
||||||
} else {
|
} else {
|
||||||
env->invalid_addr = addr;
|
env->invalid_addr = addr;
|
||||||
|
@ -595,24 +639,30 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
|
||||||
int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||||
target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
|
target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
|
||||||
uintptr_t haddr;
|
uintptr_t haddr;
|
||||||
|
struct hook *hook;
|
||||||
|
bool handled;
|
||||||
|
|
||||||
struct uc_struct *uc = env->uc;
|
struct uc_struct *uc = env->uc;
|
||||||
MemoryRegion *mr = memory_mapping(uc, addr);
|
MemoryRegion *mr = memory_mapping(uc, addr);
|
||||||
|
|
||||||
// Unicorn: callback on memory write
|
// Unicorn: callback on memory write
|
||||||
if (uc->hook_mem_write) {
|
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE) {
|
||||||
struct hook_struct *trace = hook_find(uc, UC_HOOK_MEM_WRITE, addr);
|
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||||
if (trace) {
|
continue;
|
||||||
((uc_cb_hookmem_t)trace->callback)(uc, UC_MEM_WRITE,
|
((uc_cb_hookmem_t)hook->callback)(uc, UC_MEM_WRITE, addr, DATA_SIZE, val, hook->user_data);
|
||||||
(uint64_t)addr, (int)DATA_SIZE, (int64_t)val, trace->user_data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unicorn: callback on invalid memory
|
// Unicorn: callback on invalid memory
|
||||||
if (uc->hook_mem_write_idx && mr == NULL) {
|
if (mr == NULL) {
|
||||||
if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_idx].callback)(
|
handled = false;
|
||||||
uc, UC_MEM_WRITE_UNMAPPED, addr, DATA_SIZE, (int64_t)val,
|
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE_UNMAPPED) {
|
||||||
uc->hook_callbacks[uc->hook_mem_write_idx].user_data)) {
|
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||||
|
continue;
|
||||||
|
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_UNMAPPED, addr, DATA_SIZE, val, hook->user_data)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!handled) {
|
||||||
// save error & quit
|
// save error & quit
|
||||||
env->invalid_addr = addr;
|
env->invalid_addr = addr;
|
||||||
env->invalid_error = UC_ERR_WRITE_UNMAPPED;
|
env->invalid_error = UC_ERR_WRITE_UNMAPPED;
|
||||||
|
@ -627,12 +677,17 @@ void helper_le_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
|
||||||
|
|
||||||
// Unicorn: callback on non-writable memory
|
// Unicorn: callback on non-writable memory
|
||||||
if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable
|
if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable
|
||||||
if (uc->hook_mem_write_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_prot_idx].callback)(
|
handled = false;
|
||||||
uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val,
|
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE_PROT) {
|
||||||
uc->hook_callbacks[uc->hook_mem_write_prot_idx].user_data)) {
|
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||||
env->invalid_error = UC_ERR_OK;
|
continue;
|
||||||
|
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, val, hook->user_data)))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
if (handled) {
|
||||||
|
env->invalid_error = UC_ERR_OK;
|
||||||
|
} else {
|
||||||
env->invalid_addr = addr;
|
env->invalid_addr = addr;
|
||||||
env->invalid_error = UC_ERR_WRITE_PROT;
|
env->invalid_error = UC_ERR_WRITE_PROT;
|
||||||
// printf("***** Invalid memory write (ro) at " TARGET_FMT_lx "\n", addr);
|
// printf("***** Invalid memory write (ro) at " TARGET_FMT_lx "\n", addr);
|
||||||
|
@ -742,24 +797,30 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
|
||||||
int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
int index = (addr >> TARGET_PAGE_BITS) & (CPU_TLB_SIZE - 1);
|
||||||
target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
|
target_ulong tlb_addr = env->tlb_table[mmu_idx][index].addr_write;
|
||||||
uintptr_t haddr;
|
uintptr_t haddr;
|
||||||
|
struct hook *hook;
|
||||||
|
bool handled;
|
||||||
|
|
||||||
struct uc_struct *uc = env->uc;
|
struct uc_struct *uc = env->uc;
|
||||||
MemoryRegion *mr = memory_mapping(uc, addr);
|
MemoryRegion *mr = memory_mapping(uc, addr);
|
||||||
|
|
||||||
// Unicorn: callback on memory write
|
// Unicorn: callback on memory write
|
||||||
if (uc->hook_mem_write) {
|
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE) {
|
||||||
struct hook_struct *trace = hook_find(uc, UC_HOOK_MEM_WRITE, addr);
|
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||||
if (trace) {
|
continue;
|
||||||
((uc_cb_hookmem_t)trace->callback)(uc, UC_MEM_WRITE,
|
((uc_cb_hookmem_t)hook->callback)(uc, UC_MEM_WRITE, addr, DATA_SIZE, val, hook->user_data);
|
||||||
(uint64_t)addr, (int)DATA_SIZE, (int64_t)val, trace->user_data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unicorn: callback on invalid memory
|
// Unicorn: callback on invalid memory
|
||||||
if (uc->hook_mem_write_idx && mr == NULL) {
|
if (mr == NULL) {
|
||||||
if (!((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_idx].callback)(
|
handled = false;
|
||||||
uc, UC_MEM_WRITE_UNMAPPED, addr, DATA_SIZE, (int64_t)val,
|
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE_UNMAPPED) {
|
||||||
uc->hook_callbacks[uc->hook_mem_write_idx].user_data)) {
|
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||||
|
continue;
|
||||||
|
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_UNMAPPED, addr, DATA_SIZE, val, hook->user_data)))
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!handled) {
|
||||||
// save error & quit
|
// save error & quit
|
||||||
env->invalid_addr = addr;
|
env->invalid_addr = addr;
|
||||||
env->invalid_error = UC_ERR_WRITE_UNMAPPED;
|
env->invalid_error = UC_ERR_WRITE_UNMAPPED;
|
||||||
|
@ -774,12 +835,17 @@ void helper_be_st_name(CPUArchState *env, target_ulong addr, DATA_TYPE val,
|
||||||
|
|
||||||
// Unicorn: callback on non-writable memory
|
// Unicorn: callback on non-writable memory
|
||||||
if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable
|
if (mr != NULL && !(mr->perms & UC_PROT_WRITE)) { //non-writable
|
||||||
if (uc->hook_mem_write_prot_idx != 0 && ((uc_cb_eventmem_t)uc->hook_callbacks[uc->hook_mem_write_prot_idx].callback)(
|
handled = false;
|
||||||
uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, (int64_t)val,
|
HOOK_FOREACH(uc, hook, UC_HOOK_MEM_WRITE_PROT) {
|
||||||
uc->hook_callbacks[uc->hook_mem_write_prot_idx].user_data)) {
|
if (!HOOK_BOUND_CHECK(hook, addr))
|
||||||
env->invalid_error = UC_ERR_OK;
|
continue;
|
||||||
|
if ((handled = ((uc_cb_eventmem_t)hook->callback)(uc, UC_MEM_WRITE_PROT, addr, DATA_SIZE, val, hook->user_data)))
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
|
if (handled) {
|
||||||
|
env->invalid_error = UC_ERR_OK;
|
||||||
|
} else {
|
||||||
env->invalid_addr = addr;
|
env->invalid_addr = addr;
|
||||||
env->invalid_error = UC_ERR_WRITE_PROT;
|
env->invalid_error = UC_ERR_WRITE_PROT;
|
||||||
// printf("***** Invalid memory write (ro) at " TARGET_FMT_lx "\n", addr);
|
// printf("***** Invalid memory write (ro) at " TARGET_FMT_lx "\n", addr);
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||||
#ifndef UNICORN_AUTOGEN_SPARC_H
|
#ifndef UNICORN_AUTOGEN_SPARC_H
|
||||||
#define UNICORN_AUTOGEN_SPARC_H
|
#define UNICORN_AUTOGEN_SPARC_H
|
||||||
|
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_sparc
|
||||||
|
#define use_idiv_instructions_rt use_idiv_instructions_rt_sparc
|
||||||
|
#define tcg_target_deposit_valid tcg_target_deposit_valid_sparc
|
||||||
#define helper_power_down helper_power_down_sparc
|
#define helper_power_down helper_power_down_sparc
|
||||||
#define check_exit_request check_exit_request_sparc
|
#define check_exit_request check_exit_request_sparc
|
||||||
#define address_space_unregister address_space_unregister_sparc
|
#define address_space_unregister address_space_unregister_sparc
|
||||||
|
@ -2806,7 +2809,6 @@
|
||||||
#define tb_phys_invalidate tb_phys_invalidate_sparc
|
#define tb_phys_invalidate tb_phys_invalidate_sparc
|
||||||
#define tb_reset_jump tb_reset_jump_sparc
|
#define tb_reset_jump tb_reset_jump_sparc
|
||||||
#define tb_set_jmp_target tb_set_jmp_target_sparc
|
#define tb_set_jmp_target tb_set_jmp_target_sparc
|
||||||
#define tb_set_jmp_target1 tb_set_jmp_target1_sparc
|
|
||||||
#define tcg_accel_class_init tcg_accel_class_init_sparc
|
#define tcg_accel_class_init tcg_accel_class_init_sparc
|
||||||
#define tcg_accel_type tcg_accel_type_sparc
|
#define tcg_accel_type tcg_accel_type_sparc
|
||||||
#define tcg_add_param_i32 tcg_add_param_i32_sparc
|
#define tcg_add_param_i32 tcg_add_param_i32_sparc
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||||
#ifndef UNICORN_AUTOGEN_SPARC64_H
|
#ifndef UNICORN_AUTOGEN_SPARC64_H
|
||||||
#define UNICORN_AUTOGEN_SPARC64_H
|
#define UNICORN_AUTOGEN_SPARC64_H
|
||||||
|
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_sparc64
|
||||||
|
#define use_idiv_instructions_rt use_idiv_instructions_rt_sparc64
|
||||||
|
#define tcg_target_deposit_valid tcg_target_deposit_valid_sparc64
|
||||||
#define helper_power_down helper_power_down_sparc64
|
#define helper_power_down helper_power_down_sparc64
|
||||||
#define check_exit_request check_exit_request_sparc64
|
#define check_exit_request check_exit_request_sparc64
|
||||||
#define address_space_unregister address_space_unregister_sparc64
|
#define address_space_unregister address_space_unregister_sparc64
|
||||||
|
@ -2806,7 +2809,6 @@
|
||||||
#define tb_phys_invalidate tb_phys_invalidate_sparc64
|
#define tb_phys_invalidate tb_phys_invalidate_sparc64
|
||||||
#define tb_reset_jump tb_reset_jump_sparc64
|
#define tb_reset_jump tb_reset_jump_sparc64
|
||||||
#define tb_set_jmp_target tb_set_jmp_target_sparc64
|
#define tb_set_jmp_target tb_set_jmp_target_sparc64
|
||||||
#define tb_set_jmp_target1 tb_set_jmp_target1_sparc64
|
|
||||||
#define tcg_accel_class_init tcg_accel_class_init_sparc64
|
#define tcg_accel_class_init tcg_accel_class_init_sparc64
|
||||||
#define tcg_accel_type tcg_accel_type_sparc64
|
#define tcg_accel_type tcg_accel_type_sparc64
|
||||||
#define tcg_add_param_i32 tcg_add_param_i32_sparc64
|
#define tcg_add_param_i32 tcg_add_param_i32_sparc64
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr)
|
DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64)
|
||||||
|
|
||||||
DEF_HELPER_FLAGS_1(clz_arm, TCG_CALL_NO_RWG_SE, i32, i32)
|
DEF_HELPER_FLAGS_1(clz_arm, TCG_CALL_NO_RWG_SE, i32, i32)
|
||||||
|
|
||||||
|
|
|
@ -10984,10 +10984,8 @@ static void disas_a64_insn(CPUARMState *env, DisasContext *s)
|
||||||
s->pc += 4;
|
s->pc += 4;
|
||||||
|
|
||||||
// Unicorn: trace this instruction on request
|
// Unicorn: trace this instruction on request
|
||||||
if (env->uc->hook_insn) {
|
if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, s->pc - 4)) {
|
||||||
struct hook_struct *trace = hook_find(s->uc, UC_HOOK_CODE, s->pc - 4);
|
gen_uc_tracecode(tcg_ctx, 4, UC_HOOK_CODE_IDX, env->uc, s->pc - 4);
|
||||||
if (trace)
|
|
||||||
gen_uc_tracecode(tcg_ctx, 4, trace->callback, env->uc, s->pc - 4, trace->user_data);
|
|
||||||
// the callback might want to stop emulation immediately
|
// the callback might want to stop emulation immediately
|
||||||
check_exit_request(tcg_ctx);
|
check_exit_request(tcg_ctx);
|
||||||
}
|
}
|
||||||
|
@ -11114,13 +11112,10 @@ void gen_intermediate_code_internal_a64(ARMCPU *cpu,
|
||||||
// Unicorn: trace this block on request
|
// Unicorn: trace this block on request
|
||||||
// Only hook this block if it is not broken from previous translation due to
|
// Only hook this block if it is not broken from previous translation due to
|
||||||
// full translation cache
|
// full translation cache
|
||||||
if (env->uc->hook_block && !env->uc->block_full) {
|
if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) {
|
||||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start);
|
|
||||||
if (trace) {
|
|
||||||
// save block address to see if we need to patch block size later
|
// save block address to see if we need to patch block size later
|
||||||
env->uc->block_addr = pc_start;
|
env->uc->block_addr = pc_start;
|
||||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data);
|
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gen_tb_start(tcg_ctx);
|
gen_tb_start(tcg_ctx);
|
||||||
|
|
|
@ -7687,10 +7687,8 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn) // qq
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unicorn: trace this instruction on request
|
// Unicorn: trace this instruction on request
|
||||||
if (s->uc->hook_insn) {
|
if (HOOK_EXISTS_BOUNDED(s->uc, UC_HOOK_CODE, s->pc - 4)) {
|
||||||
struct hook_struct *trace = hook_find(s->uc, UC_HOOK_CODE, s->pc - 4);
|
gen_uc_tracecode(tcg_ctx, 4, UC_HOOK_CODE_IDX, s->uc, s->pc - 4);
|
||||||
if (trace)
|
|
||||||
gen_uc_tracecode(tcg_ctx, 4, trace->callback, s->uc, s->pc - 4, trace->user_data);
|
|
||||||
// the callback might want to stop emulation immediately
|
// the callback might want to stop emulation immediately
|
||||||
check_exit_request(tcg_ctx);
|
check_exit_request(tcg_ctx);
|
||||||
}
|
}
|
||||||
|
@ -10408,16 +10406,11 @@ static void disas_thumb_insn(CPUARMState *env, DisasContext *s) // qq
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unicorn: trace this instruction on request
|
// Unicorn: trace this instruction on request
|
||||||
if (env->uc->hook_insn) {
|
if (HOOK_EXISTS_BOUNDED(s->uc, UC_HOOK_CODE, s->pc)) {
|
||||||
struct hook_struct *trace = hook_find(s->uc, UC_HOOK_CODE, s->pc);
|
gen_uc_tracecode(tcg_ctx, 2, UC_HOOK_CODE_IDX, s->uc, s->pc);
|
||||||
if (trace)
|
// the callback might want to stop emulation immediately
|
||||||
gen_uc_tracecode(tcg_ctx, 2, trace->callback, env->uc, s->pc, trace->user_data);
|
|
||||||
// if requested to emulate only some instructions, check to see
|
|
||||||
// if we need to exit immediately
|
|
||||||
if (env->uc->emu_count > 0) {
|
|
||||||
check_exit_request(tcg_ctx);
|
check_exit_request(tcg_ctx);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
insn = arm_lduw_code(env, s->pc, s->bswap_code);
|
insn = arm_lduw_code(env, s->pc, s->bswap_code);
|
||||||
s->pc += 2;
|
s->pc += 2;
|
||||||
|
@ -11237,13 +11230,10 @@ static inline void gen_intermediate_code_internal(ARMCPU *cpu,
|
||||||
// Unicorn: trace this block on request
|
// Unicorn: trace this block on request
|
||||||
// Only hook this block if it is not broken from previous translation due to
|
// Only hook this block if it is not broken from previous translation due to
|
||||||
// full translation cache
|
// full translation cache
|
||||||
if (env->uc->hook_block && !env->uc->block_full) {
|
if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) {
|
||||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start);
|
|
||||||
if (trace) {
|
|
||||||
// save block address to see if we need to patch block size later
|
// save block address to see if we need to patch block size later
|
||||||
env->uc->block_addr = pc_start;
|
env->uc->block_addr = pc_start;
|
||||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data);
|
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gen_tb_start(tcg_ctx);
|
gen_tb_start(tcg_ctx);
|
||||||
|
|
|
@ -99,6 +99,9 @@ int arm64_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
||||||
break;
|
break;
|
||||||
case UC_ARM64_REG_PC:
|
case UC_ARM64_REG_PC:
|
||||||
ARM_CPU(uc, mycpu)->env.pc = *(uint64_t *)value;
|
ARM_CPU(uc, mycpu)->env.pc = *(uint64_t *)value;
|
||||||
|
// force to quit execution and flush TB
|
||||||
|
uc->quit_request = true;
|
||||||
|
uc_emu_stop(uc);
|
||||||
break;
|
break;
|
||||||
case UC_ARM64_REG_SP:
|
case UC_ARM64_REG_SP:
|
||||||
ARM_CPU(uc, mycpu)->env.xregs[31] = *(uint64_t *)value;
|
ARM_CPU(uc, mycpu)->env.xregs[31] = *(uint64_t *)value;
|
||||||
|
|
|
@ -59,11 +59,6 @@ int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
|
||||||
|
|
||||||
mycpu = first_cpu;
|
mycpu = first_cpu;
|
||||||
|
|
||||||
switch(uc->mode) {
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
case UC_MODE_ARM:
|
|
||||||
case UC_MODE_THUMB:
|
|
||||||
if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12)
|
if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12)
|
||||||
*(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0];
|
*(int32_t *)value = ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0];
|
||||||
else {
|
else {
|
||||||
|
@ -85,9 +80,6 @@ int arm_reg_read(struct uc_struct *uc, unsigned int regid, void *value)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -101,12 +93,6 @@ int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
||||||
{
|
{
|
||||||
CPUState *mycpu = first_cpu;
|
CPUState *mycpu = first_cpu;
|
||||||
|
|
||||||
switch(uc->mode) {
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UC_MODE_ARM:
|
|
||||||
case UC_MODE_THUMB:
|
|
||||||
if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12)
|
if (regid >= UC_ARM_REG_R0 && regid <= UC_ARM_REG_R12)
|
||||||
ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0] = *(uint32_t *)value;
|
ARM_CPU(uc, mycpu)->env.regs[regid - UC_ARM_REG_R0] = *(uint32_t *)value;
|
||||||
else {
|
else {
|
||||||
|
@ -121,12 +107,15 @@ int arm_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
||||||
break;
|
break;
|
||||||
//case UC_ARM_REG_PC:
|
//case UC_ARM_REG_PC:
|
||||||
case UC_ARM_REG_R15:
|
case UC_ARM_REG_R15:
|
||||||
|
ARM_CPU(uc, mycpu)->env.pc = *(uint32_t *)value;
|
||||||
ARM_CPU(uc, mycpu)->env.regs[15] = *(uint32_t *)value;
|
ARM_CPU(uc, mycpu)->env.regs[15] = *(uint32_t *)value;
|
||||||
|
// force to quit execution and flush TB
|
||||||
|
uc->quit_request = true;
|
||||||
|
uc_emu_stop(uc);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -141,6 +130,19 @@ static bool arm_stop_interrupt(int intno)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uc_err arm_query(struct uc_struct *uc, uc_query_type type, size_t *result)
|
||||||
|
{
|
||||||
|
CPUState *mycpu = first_cpu;
|
||||||
|
|
||||||
|
switch(type) {
|
||||||
|
case UC_QUERY_MODE:
|
||||||
|
*result = (ARM_CPU(uc, mycpu)->env.thumb != 0);
|
||||||
|
return UC_ERR_OK;
|
||||||
|
default:
|
||||||
|
return UC_ERR_ARG;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void arm_uc_init(struct uc_struct* uc)
|
void arm_uc_init(struct uc_struct* uc)
|
||||||
{
|
{
|
||||||
register_accel_types(uc);
|
register_accel_types(uc);
|
||||||
|
@ -152,5 +154,6 @@ void arm_uc_init(struct uc_struct* uc)
|
||||||
uc->set_pc = arm_set_pc;
|
uc->set_pc = arm_set_pc;
|
||||||
uc->stop_interrupt = arm_stop_interrupt;
|
uc->stop_interrupt = arm_stop_interrupt;
|
||||||
uc->release = arm_release;
|
uc->release = arm_release;
|
||||||
|
uc->query = arm_query;
|
||||||
uc_common_init(uc);
|
uc_common_init(uc);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr)
|
DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64)
|
||||||
|
|
||||||
DEF_HELPER_FLAGS_4(cc_compute_all, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int)
|
DEF_HELPER_FLAGS_4(cc_compute_all, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int)
|
||||||
DEF_HELPER_FLAGS_4(cc_compute_c, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int)
|
DEF_HELPER_FLAGS_4(cc_compute_c, TCG_CALL_NO_RWG_SE, tl, tl, tl, tl, int)
|
||||||
|
|
|
@ -945,14 +945,16 @@ void helper_syscall(CPUX86State *env, int next_eip_addend)
|
||||||
#else
|
#else
|
||||||
void helper_syscall(CPUX86State *env, int next_eip_addend)
|
void helper_syscall(CPUX86State *env, int next_eip_addend)
|
||||||
{
|
{
|
||||||
// Unicorn: call interrupt callback if registered
|
// Unicorn: call registered syscall hooks
|
||||||
struct uc_struct *uc = env->uc;
|
struct hook *hook;
|
||||||
if (uc->hook_syscall_idx) {
|
HOOK_FOREACH(env->uc, hook, UC_HOOK_INSN) {
|
||||||
((uc_cb_insn_syscall_t)uc->hook_callbacks[uc->hook_syscall_idx].callback)(
|
if (!HOOK_BOUND_CHECK(hook, env->eip))
|
||||||
uc, uc->hook_callbacks[uc->hook_syscall_idx].user_data);
|
continue;
|
||||||
|
if (hook->insn == UC_X86_INS_SYSCALL)
|
||||||
|
((uc_cb_insn_syscall_t)hook->callback)(env->uc, hook->user_data);
|
||||||
}
|
}
|
||||||
env->eip += next_eip_addend;
|
|
||||||
|
|
||||||
|
env->eip += next_eip_addend;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int selector;
|
int selector;
|
||||||
|
@ -2303,14 +2305,16 @@ void helper_lret_protected(CPUX86State *env, int shift, int addend)
|
||||||
|
|
||||||
void helper_sysenter(CPUX86State *env, int next_eip_addend)
|
void helper_sysenter(CPUX86State *env, int next_eip_addend)
|
||||||
{
|
{
|
||||||
// Unicorn: call interrupt callback if registered
|
// Unicorn: call registered SYSENTER hooks
|
||||||
struct uc_struct *uc = env->uc;
|
struct hook *hook;
|
||||||
if (uc->hook_syscall_idx) {
|
HOOK_FOREACH(env->uc, hook, UC_HOOK_INSN) {
|
||||||
((uc_cb_insn_syscall_t)uc->hook_callbacks[uc->hook_syscall_idx].callback)(
|
if (!HOOK_BOUND_CHECK(hook, env->eip))
|
||||||
uc, uc->hook_callbacks[uc->hook_syscall_idx].user_data);
|
continue;
|
||||||
|
if (hook->insn == UC_X86_INS_SYSENTER)
|
||||||
|
((uc_cb_insn_syscall_t)hook->callback)(env->uc, hook->user_data);
|
||||||
}
|
}
|
||||||
env->eip += next_eip_addend;
|
|
||||||
|
|
||||||
|
env->eip += next_eip_addend;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (env->sysenter_cs == 0) {
|
if (env->sysenter_cs == 0) {
|
||||||
|
|
|
@ -516,14 +516,14 @@ static inline void gen_op_addq_A0_reg_sN(TCGContext *s, int shift, int reg)
|
||||||
|
|
||||||
static inline void gen_op_ld_v(DisasContext *s, int idx, TCGv t0, TCGv a0)
|
static inline void gen_op_ld_v(DisasContext *s, int idx, TCGv t0, TCGv a0)
|
||||||
{
|
{
|
||||||
if (s->uc->hook_mem_read)
|
if (HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ))
|
||||||
gen_jmp_im(s, s->prev_pc); // Unicorn: sync EIP
|
gen_jmp_im(s, s->prev_pc); // Unicorn: sync EIP
|
||||||
tcg_gen_qemu_ld_tl(s->uc, t0, a0, s->mem_index, idx | MO_LE);
|
tcg_gen_qemu_ld_tl(s->uc, t0, a0, s->mem_index, idx | MO_LE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void gen_op_st_v(DisasContext *s, int idx, TCGv t0, TCGv a0)
|
static inline void gen_op_st_v(DisasContext *s, int idx, TCGv t0, TCGv a0)
|
||||||
{
|
{
|
||||||
if (s->uc->hook_mem_write)
|
if (HOOK_EXISTS(s->uc, UC_HOOK_MEM_WRITE))
|
||||||
gen_jmp_im(s, s->prev_pc); // Unicorn: sync EIP
|
gen_jmp_im(s, s->prev_pc); // Unicorn: sync EIP
|
||||||
tcg_gen_qemu_st_tl(s->uc, t0, a0, s->mem_index, idx | MO_LE);
|
tcg_gen_qemu_st_tl(s->uc, t0, a0, s->mem_index, idx | MO_LE);
|
||||||
}
|
}
|
||||||
|
@ -4745,12 +4745,10 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
||||||
TCGv cpu_tmp4 = *(TCGv *)tcg_ctx->cpu_tmp4;
|
TCGv cpu_tmp4 = *(TCGv *)tcg_ctx->cpu_tmp4;
|
||||||
TCGv **cpu_T = (TCGv **)tcg_ctx->cpu_T;
|
TCGv **cpu_T = (TCGv **)tcg_ctx->cpu_T;
|
||||||
TCGv **cpu_regs = (TCGv **)tcg_ctx->cpu_regs;
|
TCGv **cpu_regs = (TCGv **)tcg_ctx->cpu_regs;
|
||||||
struct hook_struct *trace = NULL;
|
|
||||||
TCGArg *save_opparam_ptr = tcg_ctx->gen_opparam_ptr;
|
TCGArg *save_opparam_ptr = tcg_ctx->gen_opparam_ptr;
|
||||||
bool cc_op_dirty = s->cc_op_dirty;
|
bool cc_op_dirty = s->cc_op_dirty;
|
||||||
bool changed_cc_op = false;
|
bool changed_cc_op = false;
|
||||||
|
|
||||||
|
|
||||||
s->pc = pc_start;
|
s->pc = pc_start;
|
||||||
|
|
||||||
// end address tells us to stop emulation
|
// end address tells us to stop emulation
|
||||||
|
@ -4768,20 +4766,16 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unicorn: trace this instruction on request
|
// Unicorn: trace this instruction on request
|
||||||
if (env->uc->hook_insn) {
|
if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, pc_start)) {
|
||||||
trace = hook_find(env->uc, UC_HOOK_CODE, pc_start);
|
|
||||||
if (trace) {
|
|
||||||
if (s->last_cc_op != s->cc_op) {
|
if (s->last_cc_op != s->cc_op) {
|
||||||
sync_eflags(s, tcg_ctx);
|
sync_eflags(s, tcg_ctx);
|
||||||
s->last_cc_op = s->cc_op;
|
s->last_cc_op = s->cc_op;
|
||||||
changed_cc_op = true;
|
changed_cc_op = true;
|
||||||
}
|
}
|
||||||
// generate code to call callback
|
gen_uc_tracecode(tcg_ctx, 0xf1f1f1f1, UC_HOOK_CODE_IDX, env->uc, pc_start);
|
||||||
gen_uc_tracecode(tcg_ctx, 0xf1f1f1f1, trace->callback, env->uc, pc_start, trace->user_data);
|
|
||||||
// the callback might want to stop emulation immediately
|
// the callback might want to stop emulation immediately
|
||||||
check_exit_request(tcg_ctx);
|
check_exit_request(tcg_ctx);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
prefixes = 0;
|
prefixes = 0;
|
||||||
s->override = -1;
|
s->override = -1;
|
||||||
|
@ -8173,7 +8167,7 @@ static target_ulong disas_insn(CPUX86State *env, DisasContext *s,
|
||||||
gen_helper_unlock(tcg_ctx, cpu_env);
|
gen_helper_unlock(tcg_ctx, cpu_env);
|
||||||
|
|
||||||
// Unicorn: patch the callback for the instruction size
|
// Unicorn: patch the callback for the instruction size
|
||||||
if (trace) {
|
if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, pc_start)) {
|
||||||
// int i;
|
// int i;
|
||||||
// for(i = 0; i < 20; i++)
|
// for(i = 0; i < 20; i++)
|
||||||
// printf("=== [%u] = %x\n", i, *(save_opparam_ptr + i));
|
// printf("=== [%u] = %x\n", i, *(save_opparam_ptr + i));
|
||||||
|
@ -8387,12 +8381,9 @@ static inline void gen_intermediate_code_internal(uint8_t *gen_opc_cc_op,
|
||||||
// Unicorn: trace this block on request
|
// Unicorn: trace this block on request
|
||||||
// Only hook this block if it is not broken from previous translation due to
|
// Only hook this block if it is not broken from previous translation due to
|
||||||
// full translation cache
|
// full translation cache
|
||||||
if (env->uc->hook_block && !env->uc->block_full) {
|
if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) {
|
||||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start);
|
|
||||||
if (trace) {
|
|
||||||
env->uc->block_addr = pc_start;
|
env->uc->block_addr = pc_start;
|
||||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data);
|
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gen_tb_start(tcg_ctx);
|
gen_tb_start(tcg_ctx);
|
||||||
|
|
|
@ -59,7 +59,6 @@ void x86_reg_reset(struct uc_struct *uc)
|
||||||
env->features[FEAT_8000_0001_ECX] = CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | CPUID_EXT3_SKINIT | CPUID_EXT3_CR8LEG;
|
env->features[FEAT_8000_0001_ECX] = CPUID_EXT3_LAHF_LM | CPUID_EXT3_ABM | CPUID_EXT3_SKINIT | CPUID_EXT3_CR8LEG;
|
||||||
env->features[FEAT_7_0_EBX] = CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP;
|
env->features[FEAT_7_0_EBX] = CPUID_7_0_EBX_BMI1 | CPUID_7_0_EBX_BMI2 | CPUID_7_0_EBX_ADX | CPUID_7_0_EBX_SMAP;
|
||||||
|
|
||||||
env->invalid_error = UC_ERR_OK; // no error
|
|
||||||
memset(env->regs, 0, sizeof(env->regs));
|
memset(env->regs, 0, sizeof(env->regs));
|
||||||
memset(env->segs, 0, sizeof(env->segs));
|
memset(env->segs, 0, sizeof(env->segs));
|
||||||
memset(env->cr, 0, sizeof(env->cr));
|
memset(env->cr, 0, sizeof(env->cr));
|
||||||
|
@ -658,9 +657,15 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_EIP:
|
case UC_X86_REG_EIP:
|
||||||
X86_CPU(uc, mycpu)->env.eip = *(uint32_t *)value;
|
X86_CPU(uc, mycpu)->env.eip = *(uint32_t *)value;
|
||||||
|
// force to quit execution and flush TB
|
||||||
|
uc->quit_request = true;
|
||||||
|
uc_emu_stop(uc);
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_IP:
|
case UC_X86_REG_IP:
|
||||||
WRITE_WORD(X86_CPU(uc, mycpu)->env.eip, *(uint16_t *)value);
|
WRITE_WORD(X86_CPU(uc, mycpu)->env.eip, *(uint16_t *)value);
|
||||||
|
// force to quit execution and flush TB
|
||||||
|
uc->quit_request = true;
|
||||||
|
uc_emu_stop(uc);
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_CS:
|
case UC_X86_REG_CS:
|
||||||
X86_CPU(uc, mycpu)->env.segs[R_CS].base = *(uint32_t *)value;
|
X86_CPU(uc, mycpu)->env.segs[R_CS].base = *(uint32_t *)value;
|
||||||
|
@ -808,12 +813,21 @@ int x86_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_RIP:
|
case UC_X86_REG_RIP:
|
||||||
X86_CPU(uc, mycpu)->env.eip = *(uint64_t *)value;
|
X86_CPU(uc, mycpu)->env.eip = *(uint64_t *)value;
|
||||||
|
// force to quit execution and flush TB
|
||||||
|
uc->quit_request = true;
|
||||||
|
uc_emu_stop(uc);
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_EIP:
|
case UC_X86_REG_EIP:
|
||||||
WRITE_DWORD(X86_CPU(uc, mycpu)->env.eip, *(uint32_t *)value);
|
WRITE_DWORD(X86_CPU(uc, mycpu)->env.eip, *(uint32_t *)value);
|
||||||
|
// force to quit execution and flush TB
|
||||||
|
uc->quit_request = true;
|
||||||
|
uc_emu_stop(uc);
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_IP:
|
case UC_X86_REG_IP:
|
||||||
WRITE_WORD(X86_CPU(uc, mycpu)->env.eip, *(uint16_t *)value);
|
WRITE_WORD(X86_CPU(uc, mycpu)->env.eip, *(uint16_t *)value);
|
||||||
|
// force to quit execution and flush TB
|
||||||
|
uc->quit_request = true;
|
||||||
|
uc_emu_stop(uc);
|
||||||
break;
|
break;
|
||||||
case UC_X86_REG_CS:
|
case UC_X86_REG_CS:
|
||||||
X86_CPU(uc, mycpu)->env.segs[R_CS].base = *(uint64_t *)value;
|
X86_CPU(uc, mycpu)->env.segs[R_CS].base = *(uint64_t *)value;
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr)
|
DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64)
|
||||||
|
|
||||||
DEF_HELPER_1(bitrev, i32, i32)
|
DEF_HELPER_1(bitrev, i32, i32)
|
||||||
DEF_HELPER_1(ff1, i32, i32)
|
DEF_HELPER_1(ff1, i32, i32)
|
||||||
|
|
|
@ -3043,11 +3043,8 @@ static void disas_m68k_insn(CPUM68KState * env, DisasContext *s)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unicorn: trace this instruction on request
|
// Unicorn: trace this instruction on request
|
||||||
if (env->uc->hook_insn) {
|
if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, s->pc)) {
|
||||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, s->pc);
|
gen_uc_tracecode(tcg_ctx, 2, UC_HOOK_CODE_IDX, env->uc, s->pc);
|
||||||
if (trace)
|
|
||||||
gen_uc_tracecode(tcg_ctx, 2, trace->callback, env->uc, s->pc, trace->user_data);
|
|
||||||
|
|
||||||
// the callback might want to stop emulation immediately
|
// the callback might want to stop emulation immediately
|
||||||
check_exit_request(tcg_ctx);
|
check_exit_request(tcg_ctx);
|
||||||
}
|
}
|
||||||
|
@ -3109,13 +3106,10 @@ gen_intermediate_code_internal(M68kCPU *cpu, TranslationBlock *tb,
|
||||||
// Unicorn: trace this block on request
|
// Unicorn: trace this block on request
|
||||||
// Only hook this block if it is not broken from previous translation due to
|
// Only hook this block if it is not broken from previous translation due to
|
||||||
// full translation cache
|
// full translation cache
|
||||||
if (env->uc->hook_block && !env->uc->block_full) {
|
if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) {
|
||||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start);
|
|
||||||
if (trace) {
|
|
||||||
// save block address to see if we need to patch block size later
|
// save block address to see if we need to patch block size later
|
||||||
env->uc->block_addr = pc_start;
|
env->uc->block_addr = pc_start;
|
||||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data);
|
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gen_tb_start(tcg_ctx);
|
gen_tb_start(tcg_ctx);
|
||||||
|
|
|
@ -70,6 +70,9 @@ int m68k_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
||||||
default: break;
|
default: break;
|
||||||
case UC_M68K_REG_PC:
|
case UC_M68K_REG_PC:
|
||||||
M68K_CPU(uc, mycpu)->env.pc = *(uint32_t *)value;
|
M68K_CPU(uc, mycpu)->env.pc = *(uint32_t *)value;
|
||||||
|
// force to quit execution and flush TB
|
||||||
|
uc->quit_request = true;
|
||||||
|
uc_emu_stop(uc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr)
|
DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64)
|
||||||
|
|
||||||
DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int)
|
DEF_HELPER_3(raise_exception_err, noreturn, env, i32, int)
|
||||||
DEF_HELPER_2(raise_exception, noreturn, env, i32)
|
DEF_HELPER_2(raise_exception, noreturn, env, i32)
|
||||||
|
|
|
@ -11343,12 +11343,9 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx, bool *insn_n
|
||||||
n_bytes = 2;
|
n_bytes = 2;
|
||||||
|
|
||||||
// Unicorn: trace this instruction on request
|
// Unicorn: trace this instruction on request
|
||||||
if (env->uc->hook_insn) {
|
if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, ctx->pc)) {
|
||||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc);
|
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_CODE_IDX, env->uc, ctx->pc);
|
||||||
if (trace) {
|
|
||||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data);
|
|
||||||
*insn_need_patch = true;
|
*insn_need_patch = true;
|
||||||
}
|
|
||||||
// the callback might want to stop emulation immediately
|
// the callback might want to stop emulation immediately
|
||||||
check_exit_request(tcg_ctx);
|
check_exit_request(tcg_ctx);
|
||||||
}
|
}
|
||||||
|
@ -13942,12 +13939,9 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx, bool *ins
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unicorn: trace this instruction on request
|
// Unicorn: trace this instruction on request
|
||||||
if (env->uc->hook_insn) {
|
if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, ctx->pc)) {
|
||||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc);
|
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_CODE_IDX, env->uc, ctx->pc);
|
||||||
if (trace) {
|
|
||||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data);
|
|
||||||
*insn_need_patch = true;
|
*insn_need_patch = true;
|
||||||
}
|
|
||||||
// the callback might want to stop emulation immediately
|
// the callback might want to stop emulation immediately
|
||||||
check_exit_request(tcg_ctx);
|
check_exit_request(tcg_ctx);
|
||||||
}
|
}
|
||||||
|
@ -18504,13 +18498,10 @@ static void gen_msa(CPUMIPSState *env, DisasContext *ctx)
|
||||||
// Unicorn: trace this instruction on request
|
// Unicorn: trace this instruction on request
|
||||||
static void hook_insn(CPUMIPSState *env, DisasContext *ctx, bool *insn_need_patch, int *insn_patch_offset, int offset_value)
|
static void hook_insn(CPUMIPSState *env, DisasContext *ctx, bool *insn_need_patch, int *insn_patch_offset, int offset_value)
|
||||||
{
|
{
|
||||||
if (env->uc->hook_insn) {
|
|
||||||
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
TCGContext *tcg_ctx = ctx->uc->tcg_ctx;
|
||||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_CODE, ctx->pc);
|
if (HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_CODE, ctx->pc)) {
|
||||||
if (trace) {
|
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_CODE_IDX, env->uc, ctx->pc);
|
||||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, ctx->pc, trace->user_data);
|
|
||||||
*insn_need_patch = true;
|
*insn_need_patch = true;
|
||||||
}
|
|
||||||
// the callback might want to stop emulation immediately
|
// the callback might want to stop emulation immediately
|
||||||
check_exit_request(tcg_ctx);
|
check_exit_request(tcg_ctx);
|
||||||
*insn_patch_offset = offset_value;
|
*insn_patch_offset = offset_value;
|
||||||
|
@ -19223,13 +19214,10 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
|
||||||
// Unicorn: trace this block on request
|
// Unicorn: trace this block on request
|
||||||
// Only hook this block if it is not broken from previous translation due to
|
// Only hook this block if it is not broken from previous translation due to
|
||||||
// full translation cache
|
// full translation cache
|
||||||
if (env->uc->hook_block && !env->uc->block_full) {
|
if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) {
|
||||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start);
|
|
||||||
if (trace) {
|
|
||||||
// save block address to see if we need to patch block size later
|
// save block address to see if we need to patch block size later
|
||||||
env->uc->block_addr = pc_start;
|
env->uc->block_addr = pc_start;
|
||||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data);
|
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gen_tb_start(tcg_ctx);
|
gen_tb_start(tcg_ctx);
|
||||||
|
@ -19275,7 +19263,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
|
||||||
int insn_patch_offset = 1;
|
int insn_patch_offset = 1;
|
||||||
|
|
||||||
// Unicorn: save param buffer
|
// Unicorn: save param buffer
|
||||||
if (env->uc->hook_insn)
|
if (HOOK_EXISTS(env->uc, UC_HOOK_CODE))
|
||||||
save_opparam_ptr = tcg_ctx->gen_opparam_ptr;
|
save_opparam_ptr = tcg_ctx->gen_opparam_ptr;
|
||||||
|
|
||||||
is_slot = ctx.hflags & MIPS_HFLAG_BMASK;
|
is_slot = ctx.hflags & MIPS_HFLAG_BMASK;
|
||||||
|
|
|
@ -81,6 +81,9 @@ int mips_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
||||||
default: break;
|
default: break;
|
||||||
case UC_MIPS_REG_PC:
|
case UC_MIPS_REG_PC:
|
||||||
MIPS_CPU(uc, mycpu)->env.active_tc.PC = *(uint32_t *)value;
|
MIPS_CPU(uc, mycpu)->env.active_tc.PC = *(uint32_t *)value;
|
||||||
|
// force to quit execution and flush TB
|
||||||
|
uc->quit_request = true;
|
||||||
|
uc_emu_stop(uc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
DEF_HELPER_5(uc_tracecode, void, i32, ptr, ptr, i64, ptr)
|
DEF_HELPER_4(uc_tracecode, void, i32, i32, ptr, i64)
|
||||||
DEF_HELPER_1(power_down, void, env)
|
DEF_HELPER_1(power_down, void, env)
|
||||||
|
|
||||||
#ifndef TARGET_SPARC64
|
#ifndef TARGET_SPARC64
|
||||||
|
|
|
@ -2637,11 +2637,8 @@ static void disas_sparc_insn(DisasContext * dc, unsigned int insn, bool hook_ins
|
||||||
}
|
}
|
||||||
|
|
||||||
// Unicorn: trace this instruction on request
|
// Unicorn: trace this instruction on request
|
||||||
if (hook_insn && dc->uc->hook_insn) {
|
if (hook_insn && HOOK_EXISTS_BOUNDED(dc->uc, UC_HOOK_CODE, dc->pc)) {
|
||||||
struct hook_struct *trace = hook_find(dc->uc, UC_HOOK_CODE, dc->pc);
|
gen_uc_tracecode(tcg_ctx, 4, UC_HOOK_CODE_IDX, dc->uc, dc->pc);
|
||||||
if (trace)
|
|
||||||
gen_uc_tracecode(tcg_ctx, 4, trace->callback, dc->uc, dc->pc, trace->user_data);
|
|
||||||
|
|
||||||
// the callback might want to stop emulation immediately
|
// the callback might want to stop emulation immediately
|
||||||
check_exit_request(tcg_ctx);
|
check_exit_request(tcg_ctx);
|
||||||
}
|
}
|
||||||
|
@ -5428,13 +5425,10 @@ static inline void gen_intermediate_code_internal(SPARCCPU *cpu,
|
||||||
// Unicorn: trace this block on request
|
// Unicorn: trace this block on request
|
||||||
// Only hook this block if it is not broken from previous translation due to
|
// Only hook this block if it is not broken from previous translation due to
|
||||||
// full translation cache
|
// full translation cache
|
||||||
if (env->uc->hook_block && !env->uc->block_full) {
|
if (!env->uc->block_full && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, pc_start)) {
|
||||||
struct hook_struct *trace = hook_find(env->uc, UC_HOOK_BLOCK, pc_start);
|
|
||||||
if (trace) {
|
|
||||||
// save block address to see if we need to patch block size later
|
// save block address to see if we need to patch block size later
|
||||||
env->uc->block_addr = pc_start;
|
env->uc->block_addr = pc_start;
|
||||||
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, trace->callback, env->uc, pc_start, trace->user_data);
|
gen_uc_tracecode(tcg_ctx, 0xf8f8f8f8, UC_HOOK_BLOCK_IDX, env->uc, pc_start);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
gen_tb_start(tcg_ctx);
|
gen_tb_start(tcg_ctx);
|
||||||
|
|
|
@ -87,6 +87,9 @@ int sparc_reg_write(struct uc_struct *uc, unsigned int regid, const void *value)
|
||||||
case UC_SPARC_REG_PC:
|
case UC_SPARC_REG_PC:
|
||||||
SPARC_CPU(uc, mycpu)->env.pc = *(uint32_t *)value;
|
SPARC_CPU(uc, mycpu)->env.pc = *(uint32_t *)value;
|
||||||
SPARC_CPU(uc, mycpu)->env.npc = *(uint32_t *)value + 4;
|
SPARC_CPU(uc, mycpu)->env.npc = *(uint32_t *)value + 4;
|
||||||
|
// force to quit execution and flush TB
|
||||||
|
uc->quit_request = true;
|
||||||
|
uc_emu_stop(uc);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1241,7 +1241,7 @@ static void tcg_out_op(TCGContext *s, TCGOpcode opc,
|
||||||
{
|
{
|
||||||
/* 99% of the time, we can signal the use of extension registers
|
/* 99% of the time, we can signal the use of extension registers
|
||||||
by looking to see if the opcode handles 64-bit data. */
|
by looking to see if the opcode handles 64-bit data. */
|
||||||
TCGType ext = (tcg_op_defs[opc].flags & TCG_OPF_64BIT) != 0;
|
TCGType ext = (s->tcg_op_defs[opc].flags & TCG_OPF_64BIT) != 0;
|
||||||
|
|
||||||
/* Hoist the loads of the most common arguments. */
|
/* Hoist the loads of the most common arguments. */
|
||||||
TCGArg a0 = args[0];
|
TCGArg a0 = args[0];
|
||||||
|
|
|
@ -56,8 +56,8 @@ static int arm_arch = __ARM_ARCH;
|
||||||
#define use_armv6_instructions (__ARM_ARCH >= 6 || arm_arch >= 6)
|
#define use_armv6_instructions (__ARM_ARCH >= 6 || arm_arch >= 6)
|
||||||
#define use_armv7_instructions (__ARM_ARCH >= 7 || arm_arch >= 7)
|
#define use_armv7_instructions (__ARM_ARCH >= 7 || arm_arch >= 7)
|
||||||
|
|
||||||
#ifndef use_idiv_instructions
|
#ifndef __ARM_ARCH_EXT_IDIV__
|
||||||
bool use_idiv_instructions;
|
bool use_idiv_instructions_rt;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* ??? Ought to think about changing CONFIG_SOFTMMU to always defined. */
|
/* ??? Ought to think about changing CONFIG_SOFTMMU to always defined. */
|
||||||
|
@ -1981,10 +1981,10 @@ static void tcg_target_init(TCGContext *s)
|
||||||
{
|
{
|
||||||
/* Only probe for the platform and capabilities if we havn't already
|
/* Only probe for the platform and capabilities if we havn't already
|
||||||
determined maximum values at compile time. */
|
determined maximum values at compile time. */
|
||||||
#ifndef use_idiv_instructions
|
#ifndef __ARM_ARCH_EXT_IDIV__
|
||||||
{
|
{
|
||||||
unsigned long hwcap = qemu_getauxval(AT_HWCAP);
|
unsigned long hwcap = qemu_getauxval(AT_HWCAP);
|
||||||
use_idiv_instructions = (hwcap & HWCAP_ARM_IDIVA) != 0;
|
use_idiv_instructions_rt = (hwcap & HWCAP_ARM_IDIVA) != 0;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (__ARM_ARCH < 7) {
|
if (__ARM_ARCH < 7) {
|
||||||
|
|
|
@ -52,7 +52,8 @@ typedef enum {
|
||||||
#ifdef __ARM_ARCH_EXT_IDIV__
|
#ifdef __ARM_ARCH_EXT_IDIV__
|
||||||
#define use_idiv_instructions 1
|
#define use_idiv_instructions 1
|
||||||
#else
|
#else
|
||||||
extern bool use_idiv_instructions;
|
extern bool use_idiv_instructions_rt;
|
||||||
|
#define use_idiv_instructions use_idiv_instructions_rt
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1209,7 +1209,7 @@ static inline void tcg_out_tlb_load(TCGContext *s, TCGReg addrlo, TCGReg addrhi,
|
||||||
tcg_out_mov(s, ttype, r1, addrlo);
|
tcg_out_mov(s, ttype, r1, addrlo);
|
||||||
|
|
||||||
// Unicorn: fast path if hookmem is not enable
|
// Unicorn: fast path if hookmem is not enable
|
||||||
if (!s->uc->hook_mem_read && !s->uc->hook_mem_write)
|
if (!HOOK_EXISTS(s->uc, UC_HOOK_MEM_READ) && !HOOK_EXISTS(s->uc, UC_HOOK_MEM_WRITE))
|
||||||
tcg_out_opc(s, OPC_JCC_long + JCC_JNE, 0, 0, 0);
|
tcg_out_opc(s, OPC_JCC_long + JCC_JNE, 0, 0, 0);
|
||||||
else
|
else
|
||||||
tcg_out_opc(s, OPC_JMP_long, 0, 0, 0); /* slow_path */
|
tcg_out_opc(s, OPC_JMP_long, 0, 0, 0); /* slow_path */
|
||||||
|
|
|
@ -27,14 +27,13 @@
|
||||||
|
|
||||||
int gen_new_label(TCGContext *);
|
int gen_new_label(TCGContext *);
|
||||||
|
|
||||||
static inline void gen_uc_tracecode(TCGContext *tcg_ctx, int32_t size, void *callback, void *uc, uint64_t pc, void *data)
|
static inline void gen_uc_tracecode(TCGContext *tcg_ctx, int32_t size, int32_t type, void *uc, uint64_t pc)
|
||||||
{
|
{
|
||||||
TCGv_i32 tsize = tcg_const_i32(tcg_ctx, size);
|
TCGv_i32 tsize = tcg_const_i32(tcg_ctx, size);
|
||||||
TCGv_ptr tcallback = tcg_const_ptr(tcg_ctx, callback);
|
TCGv_i32 ttype = tcg_const_i32(tcg_ctx, type);
|
||||||
TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, uc);
|
TCGv_ptr tuc = tcg_const_ptr(tcg_ctx, uc);
|
||||||
TCGv_i64 tpc = tcg_const_i64(tcg_ctx, pc);
|
TCGv_i64 tpc = tcg_const_i64(tcg_ctx, pc);
|
||||||
TCGv_ptr tdata = tcg_const_ptr(tcg_ctx, data);
|
gen_helper_uc_tracecode(tcg_ctx, tsize, ttype, tuc, tpc);
|
||||||
gen_helper_uc_tracecode(tcg_ctx, tsize, tcallback, tuc, tpc, tdata);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void tcg_gen_op0(TCGContext *s, TCGOpcode opc)
|
static inline void tcg_gen_op0(TCGContext *s, TCGOpcode opc)
|
||||||
|
|
|
@ -179,7 +179,7 @@ static int cpu_gen_code(CPUArchState *env, TranslationBlock *tb, int *gen_code_s
|
||||||
gen_intermediate_code(env, tb);
|
gen_intermediate_code(env, tb);
|
||||||
|
|
||||||
// Unicorn: when tracing block, patch 1st operand for block size
|
// Unicorn: when tracing block, patch 1st operand for block size
|
||||||
if (env->uc->hook_block && env->uc->block_addr == tb->pc) {
|
if (env->uc->block_addr == tb->pc && HOOK_EXISTS_BOUNDED(env->uc, UC_HOOK_BLOCK, tb->pc)) {
|
||||||
if (env->uc->block_full) // block size is unknown
|
if (env->uc->block_full) // block size is unknown
|
||||||
*(s->gen_opparam_buf + 1) = 0;
|
*(s->gen_opparam_buf + 1) = 0;
|
||||||
else
|
else
|
||||||
|
|
|
@ -8,3 +8,4 @@ util-obj-y += aes.o
|
||||||
util-obj-y += qemu-option.o
|
util-obj-y += qemu-option.o
|
||||||
util-obj-y += crc32c.o
|
util-obj-y += crc32c.o
|
||||||
util-obj-y += host-utils.o
|
util-obj-y += host-utils.o
|
||||||
|
util-obj-y += getauxval.o
|
||||||
|
|
109
qemu/util/getauxval.c
Normal file
109
qemu/util/getauxval.c
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
/*
|
||||||
|
* QEMU access to the auxiliary vector
|
||||||
|
*
|
||||||
|
* Copyright (C) 2013 Red Hat, Inc
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
* of this software and associated documentation files (the "Software"), to deal
|
||||||
|
* in the Software without restriction, including without limitation the rights
|
||||||
|
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
* copies of the Software, and to permit persons to whom the Software is
|
||||||
|
* furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included in
|
||||||
|
* all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
* THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "qemu-common.h"
|
||||||
|
#include "qemu/osdep.h"
|
||||||
|
|
||||||
|
#ifdef CONFIG_GETAUXVAL
|
||||||
|
/* Don't inline this in qemu/osdep.h, because pulling in <sys/auxv.h> for
|
||||||
|
the system declaration of getauxval pulls in the system <elf.h>, which
|
||||||
|
conflicts with qemu's version. */
|
||||||
|
|
||||||
|
#include <sys/auxv.h>
|
||||||
|
|
||||||
|
unsigned long qemu_getauxval(unsigned long key)
|
||||||
|
{
|
||||||
|
return getauxval(key);
|
||||||
|
}
|
||||||
|
#elif defined(__linux__)
|
||||||
|
#include "elf.h"
|
||||||
|
|
||||||
|
/* Our elf.h doesn't contain Elf32_auxv_t and Elf64_auxv_t, which is ok because
|
||||||
|
that just makes it easier to define it properly for the host here. */
|
||||||
|
typedef struct {
|
||||||
|
unsigned long a_type;
|
||||||
|
unsigned long a_val;
|
||||||
|
} ElfW_auxv_t;
|
||||||
|
|
||||||
|
static const ElfW_auxv_t *auxv;
|
||||||
|
|
||||||
|
static const ElfW_auxv_t *qemu_init_auxval(void)
|
||||||
|
{
|
||||||
|
ElfW_auxv_t *a;
|
||||||
|
ssize_t size = 512, r, ofs;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
/* Allocate some initial storage. Make sure the first entry is set
|
||||||
|
to end-of-list, so that we've got a valid list in case of error. */
|
||||||
|
auxv = a = g_malloc(size);
|
||||||
|
a[0].a_type = 0;
|
||||||
|
a[0].a_val = 0;
|
||||||
|
|
||||||
|
fd = open("/proc/self/auxv", O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read the first SIZE bytes. Hopefully, this covers everything. */
|
||||||
|
r = read(fd, a, size);
|
||||||
|
|
||||||
|
if (r == size) {
|
||||||
|
/* Continue to expand until we do get a partial read. */
|
||||||
|
do {
|
||||||
|
ofs = size;
|
||||||
|
size *= 2;
|
||||||
|
auxv = a = g_realloc(a, size);
|
||||||
|
r = read(fd, (char *)a + ofs, ofs);
|
||||||
|
} while (r == ofs);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fd);
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned long qemu_getauxval(unsigned long type)
|
||||||
|
{
|
||||||
|
const ElfW_auxv_t *a = auxv;
|
||||||
|
|
||||||
|
if (unlikely(a == NULL)) {
|
||||||
|
a = qemu_init_auxval();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (; a->a_type != 0; a++) {
|
||||||
|
if (a->a_type == type) {
|
||||||
|
return a->a_val;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
unsigned long qemu_getauxval(unsigned long type)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -29,8 +29,8 @@
|
||||||
|
|
||||||
static void error_exit(int err, const char *msg)
|
static void error_exit(int err, const char *msg)
|
||||||
{
|
{
|
||||||
// fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err));
|
fprintf(stderr, "qemu: %s: %s\n", msg, strerror(err));
|
||||||
// abort();
|
abort();
|
||||||
}
|
}
|
||||||
|
|
||||||
void qemu_mutex_init(QemuMutex *mutex)
|
void qemu_mutex_init(QemuMutex *mutex)
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
/* Autogen header for Unicorn Engine - DONOT MODIFY */
|
||||||
#ifndef UNICORN_AUTOGEN_X86_64_H
|
#ifndef UNICORN_AUTOGEN_X86_64_H
|
||||||
#define UNICORN_AUTOGEN_X86_64_H
|
#define UNICORN_AUTOGEN_X86_64_H
|
||||||
|
#define aarch64_tb_set_jmp_target aarch64_tb_set_jmp_target_x86_64
|
||||||
|
#define use_idiv_instructions_rt use_idiv_instructions_rt_x86_64
|
||||||
|
#define tcg_target_deposit_valid tcg_target_deposit_valid_x86_64
|
||||||
#define helper_power_down helper_power_down_x86_64
|
#define helper_power_down helper_power_down_x86_64
|
||||||
#define check_exit_request check_exit_request_x86_64
|
#define check_exit_request check_exit_request_x86_64
|
||||||
#define address_space_unregister address_space_unregister_x86_64
|
#define address_space_unregister address_space_unregister_x86_64
|
||||||
|
@ -2806,7 +2809,6 @@
|
||||||
#define tb_phys_invalidate tb_phys_invalidate_x86_64
|
#define tb_phys_invalidate tb_phys_invalidate_x86_64
|
||||||
#define tb_reset_jump tb_reset_jump_x86_64
|
#define tb_reset_jump tb_reset_jump_x86_64
|
||||||
#define tb_set_jmp_target tb_set_jmp_target_x86_64
|
#define tb_set_jmp_target tb_set_jmp_target_x86_64
|
||||||
#define tb_set_jmp_target1 tb_set_jmp_target1_x86_64
|
|
||||||
#define tcg_accel_class_init tcg_accel_class_init_x86_64
|
#define tcg_accel_class_init tcg_accel_class_init_x86_64
|
||||||
#define tcg_accel_type tcg_accel_type_x86_64
|
#define tcg_accel_type tcg_accel_type_x86_64
|
||||||
#define tcg_add_param_i32 tcg_add_param_i32_x86_64
|
#define tcg_add_param_i32 tcg_add_param_i32_x86_64
|
||||||
|
|
|
@ -27,7 +27,7 @@ LIBDIR = $(BUILDDIR)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
CFLAGS += -Wall -I$(INCDIR)
|
CFLAGS += -Wall -I$(INCDIR)
|
||||||
LDFLAGS += -L$(LIBDIR) -l$(LIBNAME)
|
LDFLAGS += -lpthread -L$(LIBDIR) -l$(LIBNAME)
|
||||||
LDFLAGS_STATIC += $(UNICORN_DEP_LIBS_STATIC)
|
LDFLAGS_STATIC += $(UNICORN_DEP_LIBS_STATIC)
|
||||||
|
|
||||||
ifeq ($(CROSS),)
|
ifeq ($(CROSS),)
|
||||||
|
|
|
@ -142,13 +142,13 @@ static void do_nx_demo(bool cause_fault)
|
||||||
|
|
||||||
/*
|
/*
|
||||||
bits 32
|
bits 32
|
||||||
page0:
|
page0: @0
|
||||||
times 4091 inc eax
|
times 4091 inc eax
|
||||||
jmp page2
|
jmp page2
|
||||||
page1:
|
page1: @1000
|
||||||
times 4095 inc eax
|
times 4095 inc eax (or INC ECX)
|
||||||
hlt
|
hlt
|
||||||
page2:
|
page2: @2000
|
||||||
jmp page1
|
jmp page1
|
||||||
*/
|
*/
|
||||||
memset(code_buf, 0x40, sizeof(code_buf)); // fill with inc eax
|
memset(code_buf, 0x40, sizeof(code_buf)); // fill with inc eax
|
||||||
|
@ -170,7 +170,7 @@ static void do_nx_demo(bool cause_fault)
|
||||||
// intercept code and invalid memory events
|
// intercept code and invalid memory events
|
||||||
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK ||
|
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK ||
|
||||||
uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID,
|
uc_hook_add(uc, &trace1, UC_HOOK_MEM_INVALID,
|
||||||
hook_mem_invalid, NULL) != UC_ERR_OK) {
|
hook_mem_invalid, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) {
|
||||||
printf("not ok - Failed to install hooks\n");
|
printf("not ok - Failed to install hooks\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -251,7 +251,7 @@ static void do_perms_demo(bool change_perms)
|
||||||
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK ||
|
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK ||
|
||||||
uc_hook_add(uc, &trace1,
|
uc_hook_add(uc, &trace1,
|
||||||
UC_HOOK_MEM_INVALID,
|
UC_HOOK_MEM_INVALID,
|
||||||
hook_mem_invalid, NULL) != UC_ERR_OK) {
|
hook_mem_invalid, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) {
|
||||||
printf("not ok - Failed to install hooks\n");
|
printf("not ok - Failed to install hooks\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -329,7 +329,7 @@ static void do_unmap_demo(bool do_unmap)
|
||||||
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK ||
|
if (uc_hook_add(uc, &trace2, UC_HOOK_CODE, hook_code, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK ||
|
||||||
uc_hook_add(uc, &trace1,
|
uc_hook_add(uc, &trace1,
|
||||||
UC_HOOK_MEM_INVALID,
|
UC_HOOK_MEM_INVALID,
|
||||||
hook_mem_invalid, NULL) != UC_ERR_OK) {
|
hook_mem_invalid, NULL, (uint64_t)1, (uint64_t)0) != UC_ERR_OK) {
|
||||||
printf("not ok - Failed to install hooks\n");
|
printf("not ok - Failed to install hooks\n");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -105,7 +105,7 @@ static void test_mips_el(void)
|
||||||
printf("Emulate MIPS code (little-endian)\n");
|
printf("Emulate MIPS code (little-endian)\n");
|
||||||
|
|
||||||
// Initialize emulator in MIPS mode
|
// Initialize emulator in MIPS mode
|
||||||
err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32, &uc);
|
err = uc_open(UC_ARCH_MIPS, UC_MODE_MIPS32 + UC_MODE_LITTLE_ENDIAN, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||||
err, uc_strerror(err));
|
err, uc_strerror(err));
|
||||||
|
|
|
@ -57,7 +57,7 @@ static void test_sparc(void)
|
||||||
printf("Emulate SPARC code\n");
|
printf("Emulate SPARC code\n");
|
||||||
|
|
||||||
// Initialize emulator in Sparc mode
|
// Initialize emulator in Sparc mode
|
||||||
err = uc_open(UC_ARCH_SPARC, UC_MODE_32, &uc);
|
err = uc_open(UC_ARCH_SPARC, UC_MODE_SPARC32|UC_MODE_BIG_ENDIAN, &uc);
|
||||||
if (err) {
|
if (err) {
|
||||||
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
printf("Failed on uc_open() with error returned: %u (%s)\n",
|
||||||
err, uc_strerror(err));
|
err, uc_strerror(err));
|
||||||
|
|
|
@ -36,6 +36,7 @@ TESTS += emu_stop_in_hook_overrun
|
||||||
TESTS += mips_branch_likely_issue
|
TESTS += mips_branch_likely_issue
|
||||||
TESTS += hook_extrainvoke
|
TESTS += hook_extrainvoke
|
||||||
TESTS += sysenter_hook_x86
|
TESTS += sysenter_hook_x86
|
||||||
|
TESTS += emu_clear_errors
|
||||||
|
|
||||||
TESTS += memleak_x86
|
TESTS += memleak_x86
|
||||||
TESTS += memleak_arm
|
TESTS += memleak_arm
|
||||||
|
|
18
tests/regress/arm_vldr_invalid.py
Executable file
18
tests/regress/arm_vldr_invalid.py
Executable file
|
@ -0,0 +1,18 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
from unicorn import *
|
||||||
|
from unicorn.arm_const import *
|
||||||
|
|
||||||
|
import regress
|
||||||
|
|
||||||
|
class VldrPcInsn(regress.RegressTest):
|
||||||
|
|
||||||
|
def runTest(self):
|
||||||
|
uc = Uc(UC_ARCH_ARM, UC_MODE_ARM)
|
||||||
|
uc.mem_map(0x1000, 0x1000)
|
||||||
|
uc.mem_write(0x1000, 'ed9f8a3d'.decode('hex')) # vldr s16, [pc, #244]
|
||||||
|
# this will raise invalid insn
|
||||||
|
uc.emu_start(0x1000, 0x1004)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
regress.main()
|
154
tests/regress/emu_clear_errors.c
Normal file
154
tests/regress/emu_clear_errors.c
Normal file
|
@ -0,0 +1,154 @@
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <unicorn/unicorn.h>
|
||||||
|
|
||||||
|
static int count = 1;
|
||||||
|
|
||||||
|
bool cb_hookunmapped(uc_engine *uc, uc_mem_type type, uint64_t address, uint32_t size, int64_t value, void *user_data) {
|
||||||
|
uint32_t pc = 0;
|
||||||
|
uc_reg_read(uc, UC_X86_REG_EIP, &pc);
|
||||||
|
fprintf(stderr, "mem unmapped: 0x%x type: %x address: 0x%"PRIx64" length: %x value: 0x%"PRIx64"\n",
|
||||||
|
pc, type, address, size, value);
|
||||||
|
|
||||||
|
uc_err err = UC_ERR_OK;
|
||||||
|
err = uc_emu_stop(uc);
|
||||||
|
if (err != UC_ERR_OK) {
|
||||||
|
fprintf(stderr, "stop not ok");
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// move esi, dword ptr [ecx + eax + 0x28]
|
||||||
|
// add esi, eax
|
||||||
|
// lea eax, dword ptr [ebp - 4]
|
||||||
|
// push eax
|
||||||
|
// push 0x40
|
||||||
|
// push 0x10
|
||||||
|
// push esi
|
||||||
|
// call some address
|
||||||
|
#define CODE "\x8B\x74\x01\x28" \
|
||||||
|
"\x0C\xF0" \
|
||||||
|
"\x8D\x45\xFC" \
|
||||||
|
"\x50" \
|
||||||
|
"\x6A\x40" \
|
||||||
|
"\x6A\x10" \
|
||||||
|
"\x56" \
|
||||||
|
"\xFF\x15\x20\x20\x00\x10"
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
uc_engine *uc;
|
||||||
|
|
||||||
|
uc_err err = uc_open(UC_ARCH_X86, UC_MODE_32, &uc);
|
||||||
|
if (err != UC_ERR_OK) {
|
||||||
|
fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "ok %d - uc_open\n", count++);
|
||||||
|
|
||||||
|
err = uc_mem_map(uc, 0x1000, 0x1000, UC_PROT_ALL);
|
||||||
|
if (err != UC_ERR_OK) {
|
||||||
|
fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "ok %d - uc_mem_map: code\n", count++);
|
||||||
|
|
||||||
|
uint8_t code[0x1000];
|
||||||
|
memset(code, 0x0, sizeof(code));
|
||||||
|
memcpy(code, CODE, sizeof(CODE));
|
||||||
|
|
||||||
|
err = uc_mem_write(uc, 0x1000, code, sizeof(code));
|
||||||
|
if (err != UC_ERR_OK) {
|
||||||
|
fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "ok %d - uc_mem_write: code\n", count++);
|
||||||
|
|
||||||
|
uint32_t eip = 0x1000;
|
||||||
|
err = uc_reg_write(uc, UC_X86_REG_EIP, &eip);
|
||||||
|
if (err != UC_ERR_OK) {
|
||||||
|
fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "ok %d - uc_reg_write: eip\n", count++);
|
||||||
|
|
||||||
|
err = uc_mem_map(uc, 0x4000, 0x4000, UC_PROT_ALL);
|
||||||
|
if (err != UC_ERR_OK) {
|
||||||
|
fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "ok %d - uc_mem_map: stack\n", count++);
|
||||||
|
|
||||||
|
uint8_t stack[0x4000];
|
||||||
|
memset(stack, 0x0, sizeof(stack));
|
||||||
|
|
||||||
|
err = uc_mem_write(uc, 0x4000, code, sizeof(code));
|
||||||
|
if (err != UC_ERR_OK) {
|
||||||
|
fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "ok %d - uc_mem_write: stack\n", count++);
|
||||||
|
|
||||||
|
uint32_t esp = 0x6000;
|
||||||
|
err = uc_reg_write(uc, UC_X86_REG_ESP, &esp);
|
||||||
|
if (err != UC_ERR_OK) {
|
||||||
|
fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "ok %d - uc_reg_write: esp\n", count++);
|
||||||
|
|
||||||
|
uint32_t ebp = 0x6000;
|
||||||
|
err = uc_reg_write(uc, UC_X86_REG_EBP, &ebp);
|
||||||
|
if (err != UC_ERR_OK) {
|
||||||
|
fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "ok %d - uc_reg_write: ebp\n", count++);
|
||||||
|
|
||||||
|
uc_hook h1;
|
||||||
|
|
||||||
|
err = uc_hook_add(uc, &h1, UC_HOOK_MEM_UNMAPPED, cb_hookunmapped, NULL);
|
||||||
|
if (err != UC_ERR_OK) {
|
||||||
|
fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "ok %d - uc_hook_add\n", count++);
|
||||||
|
|
||||||
|
// this should execute only a single instruction at 0x1000, because
|
||||||
|
// that instruction accesses invalid memory.
|
||||||
|
err = uc_emu_start(uc, 0x1000, 0x100F, 0, 0);
|
||||||
|
if (err != UC_ERR_OK) {
|
||||||
|
fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "ok %d - uc_emu_start\n", count++);
|
||||||
|
|
||||||
|
// yes, not necessary, but to demonstrate the UC API is working as expected
|
||||||
|
eip = 0x1004;
|
||||||
|
err = uc_reg_write(uc, UC_X86_REG_EIP, &eip);
|
||||||
|
if (err != UC_ERR_OK) {
|
||||||
|
fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "ok %d - uc_reg_write: eip\n", count++);
|
||||||
|
|
||||||
|
// this should execute the remaining instructions up to (but not includign) 0x100F.
|
||||||
|
// currently, it returns an error about an unmapped read.
|
||||||
|
// seems that this error should have been returned in the previous call
|
||||||
|
// to emu_start.
|
||||||
|
err = uc_emu_start(uc, 0x1004, 0x100F, 0, 0);
|
||||||
|
if (err != UC_ERR_OK) {
|
||||||
|
fprintf(stderr, "not ok %d - %s\n", count++, uc_strerror(err));
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "ok %d - uc_emu_start\n", count++);
|
||||||
|
|
||||||
|
fprintf(stderr, "ok %d - Done", count++);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
80
tests/regress/emu_clear_errors.py
Executable file
80
tests/regress/emu_clear_errors.py
Executable file
|
@ -0,0 +1,80 @@
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
import binascii
|
||||||
|
import regress
|
||||||
|
|
||||||
|
from unicorn import *
|
||||||
|
from unicorn.x86_const import *
|
||||||
|
|
||||||
|
|
||||||
|
CODE = binascii.unhexlify(b"".join([
|
||||||
|
b"8B 74 01 28", # mov esi, dword ptr [ecx + eax + 0x28] mapped: 0x1000
|
||||||
|
b"03 F0", # add esi, eax 0x1004
|
||||||
|
b"8D 45 FC", # lea eax, dword ptr [ebp - 4] 0x1006
|
||||||
|
b"50", # push eax 0x1009
|
||||||
|
b"6A 40", # push 0x40 0x100A
|
||||||
|
b"6A 10", # push 0x10 0x100C
|
||||||
|
b"56", # push esi 0x100E
|
||||||
|
b"FF 15 20 20 00 10" # call some address 0x100F
|
||||||
|
]).replace(" ", ""))
|
||||||
|
|
||||||
|
|
||||||
|
def showpc(mu):
|
||||||
|
pc = mu.reg_read(UC_X86_REG_EIP)
|
||||||
|
print("pc: 0x%x" % (pc))
|
||||||
|
|
||||||
|
|
||||||
|
class HookCodeStopEmuTest(regress.RegressTest):
|
||||||
|
def test_hook_code_stop_emu(self):
|
||||||
|
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||||
|
|
||||||
|
# base of CODE
|
||||||
|
mu.mem_map(0x1000, 0x1000)
|
||||||
|
mu.mem_write(0x1000, CODE)
|
||||||
|
mu.reg_write(UC_X86_REG_EIP, 0x1000)
|
||||||
|
|
||||||
|
# base of STACK
|
||||||
|
mu.mem_map(0x4000, 0x4000)
|
||||||
|
mu.mem_write(0x4000, "\x00" * 0x4000)
|
||||||
|
mu.reg_write(UC_X86_REG_ESP, 0x6000)
|
||||||
|
mu.reg_write(UC_X86_REG_EBP, 0x6000)
|
||||||
|
|
||||||
|
mu.reg_write(UC_X86_REG_ECX, 0x0)
|
||||||
|
mu.reg_write(UC_X86_REG_EAX, 0x0)
|
||||||
|
|
||||||
|
def _hook(_, access, address, length, value, context):
|
||||||
|
pc = mu.reg_read(UC_X86_REG_EIP)
|
||||||
|
print("mem unmapped: pc: %x access: %x address: %x length: %x value: %x" % (
|
||||||
|
pc, access, address, length, value))
|
||||||
|
mu.emu_stop()
|
||||||
|
return True
|
||||||
|
|
||||||
|
mu.hook_add(UC_HOOK_MEM_UNMAPPED, _hook)
|
||||||
|
|
||||||
|
# we only expect the following instruction to execute,
|
||||||
|
# and it will fail, because it accesses unmapped memory.
|
||||||
|
# mov esi, dword ptr [ecx + eax + 0x28] mapped: 0x1000
|
||||||
|
mu.emu_start(0x1000, 0x100F)
|
||||||
|
showpc(mu)
|
||||||
|
|
||||||
|
# now, we want to reuse the emulator, and keep executing
|
||||||
|
# from the next instruction
|
||||||
|
mu.reg_write(UC_X86_REG_EIP, 0x1004)
|
||||||
|
self.assertEqual(0x1004, mu.reg_read(UC_X86_REG_EIP))
|
||||||
|
|
||||||
|
# we expect the following instructions to execute
|
||||||
|
# add esi, eax 0x1004
|
||||||
|
# lea eax, dword ptr [ebp - 4] 0x1006
|
||||||
|
# push eax 0x1009
|
||||||
|
# push 0x40 0x100A
|
||||||
|
# push 0x10 0x100C
|
||||||
|
# push esi 0x100E
|
||||||
|
#
|
||||||
|
# currently, a UC_ERR_READ_UNMAPPED exception is raised here
|
||||||
|
mu.emu_start(0x1004, 0x100F)
|
||||||
|
showpc(mu)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
regress.main()
|
47
tests/regress/invalid_write.py
Executable file
47
tests/regress/invalid_write.py
Executable file
|
@ -0,0 +1,47 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
# Test callback that returns False to cancel emulation
|
||||||
|
|
||||||
|
from __future__ import print_function
|
||||||
|
from unicorn import *
|
||||||
|
from unicorn.x86_const import *
|
||||||
|
|
||||||
|
import regress
|
||||||
|
|
||||||
|
X86_CODE32_MEM_WRITE = b"\x89\x0D\xAA\xAA\xAA\xAA\x41\x4a" # mov [0xaaaaaaaa], ecx; INC ecx; DEC edx
|
||||||
|
|
||||||
|
|
||||||
|
# callback for tracing invalid memory access (READ or WRITE)
|
||||||
|
def hook_mem_invalid(uc, access, address, size, value, user_data):
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidWrite(regress.RegressTest):
|
||||||
|
def test(self):
|
||||||
|
# Initialize emulator in X86-32bit mode
|
||||||
|
mu = Uc(UC_ARCH_X86, UC_MODE_32)
|
||||||
|
|
||||||
|
# memory address where emulation starts
|
||||||
|
ADDRESS = 0x1000000
|
||||||
|
|
||||||
|
# map 2MB memory for this emulation
|
||||||
|
mu.mem_map(ADDRESS, 2 * 1024 * 1024)
|
||||||
|
|
||||||
|
# write machine code to be emulated to memory
|
||||||
|
mu.mem_write(ADDRESS, X86_CODE32_MEM_WRITE)
|
||||||
|
|
||||||
|
# initialize machine registers
|
||||||
|
mu.reg_write(UC_X86_REG_ECX, 0x1234)
|
||||||
|
mu.reg_write(UC_X86_REG_EDX, 0x7890)
|
||||||
|
|
||||||
|
# intercept invalid memory events
|
||||||
|
mu.hook_add(UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED, hook_mem_invalid)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# emulation should return with error UC_ERR_WRITE_UNMAPPED
|
||||||
|
mu.emu_start(ADDRESS, ADDRESS + len(X86_CODE32_MEM_WRITE))
|
||||||
|
except UcError as e:
|
||||||
|
self.assertEqual(e.errno, UC_ERR_WRITE_UNMAPPED)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
regress.main()
|
|
@ -5,7 +5,7 @@ from unicorn.sparc_const import *
|
||||||
|
|
||||||
PAGE_SIZE = 1 * 1024 * 1024
|
PAGE_SIZE = 1 * 1024 * 1024
|
||||||
|
|
||||||
uc = Uc(UC_ARCH_SPARC, UC_MODE_64)
|
uc = Uc(UC_ARCH_SPARC, UC_MODE_SPARC64|UC_MODE_BIG_ENDIAN)
|
||||||
uc.reg_write(UC_SPARC_REG_SP, 100)
|
uc.reg_write(UC_SPARC_REG_SP, 100)
|
||||||
print 'writing sp = 100'
|
print 'writing sp = 100'
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
#include <unicorn/unicorn.h>
|
#include <unicorn/unicorn.h>
|
||||||
|
|
||||||
#define HARDWARE_ARCHITECTURE UC_ARCH_SPARC
|
#define HARDWARE_ARCHITECTURE UC_ARCH_SPARC
|
||||||
#define HARDWARE_MODE UC_MODE_32
|
#define HARDWARE_MODE UC_MODE_SPARC32|UC_MODE_BIG_ENDIAN
|
||||||
|
|
||||||
#define MEMORY_STARTING_ADDRESS 0x1000000
|
#define MEMORY_STARTING_ADDRESS 0x1000000
|
||||||
#define MEMORY_SIZE 2 * 1024 * 1024
|
#define MEMORY_SIZE 2 * 1024 * 1024
|
||||||
|
|
|
@ -5,7 +5,7 @@ from unicorn.sparc_const import *
|
||||||
|
|
||||||
PAGE_SIZE = 1 * 1024 * 1024
|
PAGE_SIZE = 1 * 1024 * 1024
|
||||||
|
|
||||||
uc = Uc(UC_ARCH_SPARC, UC_MODE_32)
|
uc = Uc(UC_ARCH_SPARC, UC_MODE_SPARC32|UC_MODE_BIG_ENDIAN)
|
||||||
uc.reg_write(UC_SPARC_REG_SP, 100)
|
uc.reg_write(UC_SPARC_REG_SP, 100)
|
||||||
uc.reg_write(UC_SPARC_REG_FP, 200)
|
uc.reg_write(UC_SPARC_REG_FP, 200)
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,8 @@ CFLAGS += -L ../../
|
||||||
CFLAGS += -lcmocka -lunicorn
|
CFLAGS += -lcmocka -lunicorn
|
||||||
CFLAGS += -I ../../include
|
CFLAGS += -I ../../include
|
||||||
|
|
||||||
ALL_TESTS = test_sanity test_x86 test_mem_map test_mem_high test_mem_map_ptr
|
ALL_TESTS = test_sanity test_x86 test_mem_map test_mem_high test_mem_map_ptr \
|
||||||
|
test_tb_x86 test_multihook test_pc_change
|
||||||
|
|
||||||
.PHONY: all
|
.PHONY: all
|
||||||
all: ${ALL_TESTS}
|
all: ${ALL_TESTS}
|
||||||
|
@ -21,12 +22,18 @@ test: ${ALL_TESTS}
|
||||||
./test_mem_map
|
./test_mem_map
|
||||||
./test_mem_map_ptr
|
./test_mem_map_ptr
|
||||||
./test_mem_high
|
./test_mem_high
|
||||||
|
./test_tb_x86
|
||||||
|
./test_multihook
|
||||||
|
./test_pc_change
|
||||||
|
|
||||||
test_sanity: test_sanity.c
|
test_sanity: test_sanity.c
|
||||||
test_x86: test_x86.c
|
test_x86: test_x86.c
|
||||||
test_mem_map: test_mem_map.c
|
test_mem_map: test_mem_map.c
|
||||||
test_mem_map_ptr: test_mem_map_ptr.c
|
test_mem_map_ptr: test_mem_map_ptr.c
|
||||||
test_mem_high: test_mem_high.c
|
test_mem_high: test_mem_high.c
|
||||||
|
test_tb_x86: test_tb_x86.c
|
||||||
|
test_multihook: test_multihook.c
|
||||||
|
test_pc_change: test_pc_change.c
|
||||||
|
|
||||||
${ALL_TESTS}:
|
${ALL_TESTS}:
|
||||||
${CC} ${CFLAGS} -o $@ $^
|
${CC} ${CFLAGS} -o $@ $^
|
||||||
|
|
111
tests/unit/test_multihook.c
Normal file
111
tests/unit/test_multihook.c
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
#include "unicorn_test.h"
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#define OK(x) uc_assert_success(x)
|
||||||
|
|
||||||
|
/* Called before every test to set up a new instance */
|
||||||
|
static int setup32(void **state)
|
||||||
|
{
|
||||||
|
uc_engine *uc;
|
||||||
|
|
||||||
|
OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc));
|
||||||
|
|
||||||
|
*state = uc;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called after every test to clean up */
|
||||||
|
static int teardown(void **state)
|
||||||
|
{
|
||||||
|
uc_engine *uc = *state;
|
||||||
|
|
||||||
|
OK(uc_close(uc));
|
||||||
|
|
||||||
|
*state = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
struct bb {
|
||||||
|
uint64_t addr;
|
||||||
|
size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bbtest {
|
||||||
|
const struct bb *blocks;
|
||||||
|
unsigned int blocknum;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static void test_basic_blocks_hook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
||||||
|
{
|
||||||
|
struct bbtest *bbtest = user_data;
|
||||||
|
const struct bb *bb = &bbtest->blocks[bbtest->blocknum];
|
||||||
|
|
||||||
|
printf("block hook 1: %d == %zu\n", size, bb->size);
|
||||||
|
assert_int_equal(address, bb->addr);
|
||||||
|
assert_int_equal((size_t)size, bb->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_basic_blocks_hook2(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
||||||
|
{
|
||||||
|
struct bbtest *bbtest = user_data;
|
||||||
|
const struct bb *bb = &bbtest->blocks[bbtest->blocknum++];
|
||||||
|
|
||||||
|
printf("block hook 2: %d == %zu\n", size, bb->size);
|
||||||
|
assert_int_equal(address, bb->addr);
|
||||||
|
assert_int_equal((size_t)size, bb->size);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_basic_blocks(void **state)
|
||||||
|
{
|
||||||
|
uc_engine *uc = *state;
|
||||||
|
uc_hook trace1, trace2;
|
||||||
|
|
||||||
|
#define BASEADDR 0x1000000
|
||||||
|
|
||||||
|
uint64_t address = BASEADDR;
|
||||||
|
const uint8_t code[] = {
|
||||||
|
0x33, 0xC0, // xor eax, eax
|
||||||
|
0x90, // nop
|
||||||
|
0x90, // nop
|
||||||
|
0xEB, 0x00, // jmp $+2
|
||||||
|
0x90, // nop
|
||||||
|
0x90, // nop
|
||||||
|
0x90, // nop
|
||||||
|
};
|
||||||
|
|
||||||
|
static const struct bb blocks[] = {
|
||||||
|
{BASEADDR, 6},
|
||||||
|
{BASEADDR+ 6, 3},
|
||||||
|
};
|
||||||
|
|
||||||
|
struct bbtest bbtest = {
|
||||||
|
.blocks = blocks,
|
||||||
|
.blocknum = 0,
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#undef BASEADDR
|
||||||
|
|
||||||
|
// map 2MB memory for this emulation
|
||||||
|
OK(uc_mem_map(uc, address, 2 * 1024 * 1024, UC_PROT_ALL));
|
||||||
|
|
||||||
|
// write machine code to be emulated to memory
|
||||||
|
OK(uc_mem_write(uc, address, code, sizeof(code)));
|
||||||
|
|
||||||
|
// trace all basic blocks
|
||||||
|
OK(uc_hook_add(uc, &trace1, UC_HOOK_BLOCK, test_basic_blocks_hook, &bbtest, (uint64_t)1, (uint64_t)0));
|
||||||
|
OK(uc_hook_add(uc, &trace2, UC_HOOK_BLOCK, test_basic_blocks_hook2, &bbtest, (uint64_t)1, (uint64_t)0));
|
||||||
|
|
||||||
|
OK(uc_emu_start(uc, address, address+sizeof(code), 0, 0));
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
cmocka_unit_test_setup_teardown(test_basic_blocks, setup32, teardown),
|
||||||
|
};
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
104
tests/unit/test_pc_change.c
Normal file
104
tests/unit/test_pc_change.c
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
// Test PC change during the callback. by Nguyen Anh Quynh, 2016
|
||||||
|
#include "unicorn_test.h"
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#define OK(x) uc_assert_success(x)
|
||||||
|
|
||||||
|
/* Called before every test to set up a new instance */
|
||||||
|
static int setup32(void **state)
|
||||||
|
{
|
||||||
|
uc_engine *uc;
|
||||||
|
|
||||||
|
OK(uc_open(UC_ARCH_X86, UC_MODE_32, &uc));
|
||||||
|
|
||||||
|
*state = uc;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Called after every test to clean up */
|
||||||
|
static int teardown(void **state)
|
||||||
|
{
|
||||||
|
uc_engine *uc = *state;
|
||||||
|
|
||||||
|
OK(uc_close(uc));
|
||||||
|
|
||||||
|
*state = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
static void test_code_hook(uc_engine *uc, uint64_t address, uint32_t size, void *user_data)
|
||||||
|
{
|
||||||
|
uint8_t tmp[256];
|
||||||
|
int32_t r_eip = 0x1000006;
|
||||||
|
printf("instruction at 0x%"PRIx64": ", address);
|
||||||
|
|
||||||
|
if (!uc_mem_read(uc, address, tmp, size)) {
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
printf("0x%x ", tmp[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address == 0x1000003) {
|
||||||
|
// change the PC to "inc EDX"
|
||||||
|
uc_reg_write(uc, UC_X86_REG_EIP, &r_eip);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void test_pc_change(void **state)
|
||||||
|
{
|
||||||
|
uc_engine *uc = *state;
|
||||||
|
uc_hook trace1;
|
||||||
|
int32_t r_ecx = 3, r_edx = 15;
|
||||||
|
|
||||||
|
#define BASEADDR 0x1000000
|
||||||
|
|
||||||
|
uint64_t address = BASEADDR;
|
||||||
|
const uint8_t code[] = {
|
||||||
|
0x41, // inc ECX @0x1000000
|
||||||
|
0x41, // inc ECX
|
||||||
|
0x41, // inc ECX
|
||||||
|
0x41, // inc ECX @0x1000003
|
||||||
|
0x41, // inc ECX
|
||||||
|
0x41, // inc ECX
|
||||||
|
|
||||||
|
0x42, // inc EDX @0x1000006
|
||||||
|
0x42, // inc EDX
|
||||||
|
};
|
||||||
|
|
||||||
|
#undef BASEADDR
|
||||||
|
|
||||||
|
// map 2MB memory for this emulation
|
||||||
|
OK(uc_mem_map(uc, address, 2 * 1024 * 1024, UC_PROT_ALL));
|
||||||
|
|
||||||
|
// write machine code to be emulated to memory
|
||||||
|
OK(uc_mem_write(uc, address, code, sizeof(code)));
|
||||||
|
|
||||||
|
uc_reg_write(uc, UC_X86_REG_ECX, &r_ecx);
|
||||||
|
uc_reg_write(uc, UC_X86_REG_EDX, &r_edx);
|
||||||
|
printf("ECX = %u, EDX = %u\n", r_ecx, r_edx);
|
||||||
|
|
||||||
|
// trace all instructions
|
||||||
|
OK(uc_hook_add(uc, &trace1, UC_HOOK_CODE, test_code_hook, NULL, (uint64_t)1, (uint64_t)0));
|
||||||
|
|
||||||
|
OK(uc_emu_start(uc, address, address+sizeof(code), 0, 0));
|
||||||
|
|
||||||
|
uc_reg_read(uc, UC_X86_REG_ECX, &r_ecx);
|
||||||
|
uc_reg_read(uc, UC_X86_REG_EDX, &r_edx);
|
||||||
|
|
||||||
|
printf("ECX = %u, EDX = %u\n", r_ecx, r_edx);
|
||||||
|
assert_int_equal(r_ecx, 6);
|
||||||
|
assert_int_equal(r_edx, 17);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
cmocka_unit_test_setup_teardown(test_pc_change, setup32, teardown),
|
||||||
|
};
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
311
tests/unit/test_tb_x86.c
Normal file
311
tests/unit/test_tb_x86.c
Normal file
|
@ -0,0 +1,311 @@
|
||||||
|
/**
|
||||||
|
* Unicorn x86_32 self-modifying unit test
|
||||||
|
*
|
||||||
|
* This test demonstrates the flushing of instruction translation cache
|
||||||
|
* after a self-modification of Intel's x8's "IMUL Gv,Ev,Ib" instruction.
|
||||||
|
*/
|
||||||
|
#include "unicorn_test.h"
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#define RIP_NEXT_TO_THE_SELFMODIFY_OPCODE (1)
|
||||||
|
|
||||||
|
|
||||||
|
// Demostration of a self-modifying "IMUL eax,mem,Ib" opcode
|
||||||
|
// And the QEMU's ability to flush the translation buffer properly
|
||||||
|
|
||||||
|
#define MIN(a, b) (a < b? a: b)
|
||||||
|
|
||||||
|
#define CODE_SPACE (2 * 1024 * 1024)
|
||||||
|
#define PHY_STACK_REGION (0x60000000)
|
||||||
|
|
||||||
|
#define X86_CODE32_ALPHA_MIXED \
|
||||||
|
"\x89\xe1\xd9\xcd\xd9\x71\xf4\x5d\x55\x59\x49\x49\x49\x49\x49\x49" \
|
||||||
|
"\x49\x49\x49\x49\x43\x43\x43\x43\x43\x43\x37\x51\x5a\x6a\x41\x58" \
|
||||||
|
"\x50\x30\x41\x30\x41\x6b\x41\x41\x51\x32\x41\x42\x32\x42\x42\x30" \
|
||||||
|
"\x42\x42\x41\x42\x58\x50\x38\x41\x42\x75\x4a\x49\x51\x51\x51\x52" \
|
||||||
|
"\x47\x33\x47\x34\x51\x55\x51\x56\x50\x47\x47\x38\x47\x39\x50\x4a" \
|
||||||
|
"\x50\x4b\x50\x4c\x50\x4d\x50\x4e\x50\x4f\x50\x50\x50\x31\x47\x42" \
|
||||||
|
"\x47\x42\x50\x34\x50\x5a\x50\x45\x51\x52\x46\x32\x47\x31\x50\x4d" \
|
||||||
|
"\x51\x51\x50\x4e\x41\x41"
|
||||||
|
|
||||||
|
|
||||||
|
/* Called before every test to set up a new instance */
|
||||||
|
static int setup(void **state)
|
||||||
|
{
|
||||||
|
uc_engine *uc;
|
||||||
|
|
||||||
|
uc_assert_success(uc_open(UC_ARCH_X86, UC_MODE_64, &uc));
|
||||||
|
|
||||||
|
*state = uc;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Called after every test to clean up */
|
||||||
|
static int teardown(void **state)
|
||||||
|
{
|
||||||
|
uc_engine *uc = *state;
|
||||||
|
|
||||||
|
uc_assert_success(uc_close(uc));
|
||||||
|
|
||||||
|
*state = NULL;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void dump_stack_mem(uc_engine *uc)
|
||||||
|
{
|
||||||
|
uint8_t tmp[256];
|
||||||
|
uint32_t size;
|
||||||
|
|
||||||
|
size = sizeof(X86_CODE32_ALPHA_MIXED);
|
||||||
|
if (size > 255) size = 255;
|
||||||
|
if (!uc_mem_read(uc, PHY_STACK_REGION, tmp, size))
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
printf("Stack region dump");
|
||||||
|
for (i=0; i<size; i++) {
|
||||||
|
if ((i % 16) == 0) printf("\n%x: ", PHY_STACK_REGION+i);
|
||||||
|
printf("%x ", tmp[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void print_registers(uc_engine *uc)
|
||||||
|
{
|
||||||
|
int32_t eax, ecx, edx, ebx;
|
||||||
|
int32_t esp, ebp, esi, edi;
|
||||||
|
uc_reg_read(uc, UC_X86_REG_EAX, &eax);
|
||||||
|
uc_reg_read(uc, UC_X86_REG_ECX, &ecx);
|
||||||
|
uc_reg_read(uc, UC_X86_REG_EDX, &edx);
|
||||||
|
uc_reg_read(uc, UC_X86_REG_EBX, &ebx);
|
||||||
|
uc_reg_read(uc, UC_X86_REG_ESP, &esp);
|
||||||
|
uc_reg_read(uc, UC_X86_REG_EBP, &ebp);
|
||||||
|
uc_reg_read(uc, UC_X86_REG_ESI, &esi);
|
||||||
|
uc_reg_read(uc, UC_X86_REG_EDI, &edi);
|
||||||
|
|
||||||
|
printf("Register dump:\n");
|
||||||
|
printf("eax %8.8x ", eax);
|
||||||
|
printf("ecx %8.8x ", ecx);
|
||||||
|
printf("edx %8.8x ", edx);
|
||||||
|
printf("ebx %8.8x\n", ebx);
|
||||||
|
printf("esp %8.8x ", esp);
|
||||||
|
printf("ebp %8.8x ", ebp);
|
||||||
|
printf("esi %8.8x ", esi);
|
||||||
|
printf("edi %8.8x ", edi);
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void hook_code32(uc_engine *uc,
|
||||||
|
uint64_t address,
|
||||||
|
uint32_t size,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
//uint8_t opcode[256];
|
||||||
|
uint8_t tmp[16];
|
||||||
|
uint32_t tmp4[1];
|
||||||
|
uint32_t ecx;
|
||||||
|
|
||||||
|
printf("\nhook_code32: Address: %"PRIx64", Opcode Size: %d\n", address, size);
|
||||||
|
print_registers(uc);
|
||||||
|
size = MIN(sizeof(tmp), size);
|
||||||
|
if (!uc_mem_read(uc, address, tmp, size))
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
|
||||||
|
printf("Opcode: ");
|
||||||
|
for (i=0; i<size; i++) {
|
||||||
|
printf("%x ", tmp[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
}
|
||||||
|
dump_stack_mem(uc);
|
||||||
|
|
||||||
|
|
||||||
|
if (address == 0x60000025)
|
||||||
|
{
|
||||||
|
// double-check that opcode is
|
||||||
|
// IMUL aex,[eax+0x41],0x10
|
||||||
|
if ((tmp[0] != 0x6b) ||
|
||||||
|
(tmp[1] != 0x41) ||
|
||||||
|
(tmp[2] != 0x41) ||
|
||||||
|
(tmp[3] != 0x10))
|
||||||
|
{
|
||||||
|
printf("FAILED set-up of opcode\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
printf("IMUL eax,[ecx+0x41],0x10\n");
|
||||||
|
|
||||||
|
// double-check that memory operand points to 0x6000003a
|
||||||
|
uc_reg_read(uc, UC_X86_REG_ECX, &ecx);
|
||||||
|
if (ecx != 0x5ffffff9)
|
||||||
|
{
|
||||||
|
printf("FAILED EAX register not having 0x5ffffff9\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
printf("ECX = %8.8x\n", ecx);
|
||||||
|
|
||||||
|
printf("%8.8x + 0x41 = %8.8x\n", 0x5ffffff9, 0x5ffffff9 + 0x41);
|
||||||
|
|
||||||
|
// double-check that memory location 0x60000039
|
||||||
|
// contains 0x5151494a
|
||||||
|
if (!uc_mem_read(uc, 0x6000003a, tmp4, 4))
|
||||||
|
{
|
||||||
|
if (tmp4[0] != 0x5151494a)
|
||||||
|
{
|
||||||
|
printf("FAILED set-up\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
printf("Proved that 0x6000003a contains the proper 0x5151494a\n");
|
||||||
|
}
|
||||||
|
// dump_stack_mem(uc);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop after 'imul eax,[ecx+0x41],0x10
|
||||||
|
if (address == 0x60000029)
|
||||||
|
{
|
||||||
|
uint32_t eax;
|
||||||
|
// IMUL eax,mem,Ib
|
||||||
|
// mem = [ecx+0x41]
|
||||||
|
// ecx = 0x5ffffff9
|
||||||
|
// [6000003A] = 0x5151494a
|
||||||
|
// Stop after 'imul eax,[ecx+0x41],0x10
|
||||||
|
// This step basically shifts left 8-bit...elaborately.
|
||||||
|
// multiplying 0x5151494a x 0x10 = 0x151494a0
|
||||||
|
uc_reg_read(uc, UC_X86_REG_EAX, &eax);
|
||||||
|
if (eax != 0x151494a0)
|
||||||
|
{
|
||||||
|
fail_msg("FAIL: TB did not flush; eax is not the expected 0x151494a0\n");
|
||||||
|
print_registers(uc);
|
||||||
|
//dump_stack_mem(uc);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
printf("PASS\n");
|
||||||
|
}
|
||||||
|
print_registers(uc);
|
||||||
|
// dump_stack_mem(uc);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void hook_mem32(uc_engine *uc,
|
||||||
|
uc_mem_type type,
|
||||||
|
uint64_t address,
|
||||||
|
int size,
|
||||||
|
uint64_t value,
|
||||||
|
void *user_data)
|
||||||
|
{
|
||||||
|
char ctype;
|
||||||
|
//uint32_t tmp[1];
|
||||||
|
|
||||||
|
ctype = '?';
|
||||||
|
if (type == UC_MEM_READ) ctype = 'R';
|
||||||
|
if (type == UC_MEM_WRITE) ctype = 'W';
|
||||||
|
printf("hook_mem32(%c): Address: 0x%"PRIx64", Size: %d, Value:0x%"PRIx64"\n", ctype, address, size, value);
|
||||||
|
|
||||||
|
// if (!uc_mem_read(uc, 0x6000003a, tmp, 4))
|
||||||
|
// {
|
||||||
|
// printf(" hook_mem32 0x6000003a: %8.8x\n", tmp[0]);
|
||||||
|
// }
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void test_tb_x86_64_32_imul_Gv_Ev_Ib(void **state)
|
||||||
|
{
|
||||||
|
uc_engine *uc = *state;
|
||||||
|
uc_hook trace1, trace2;
|
||||||
|
void *mem;
|
||||||
|
#ifdef RIP_NEXT_TO_THE_SELFMODIFY_OPCODE
|
||||||
|
// These values assumes just before PC = 0x60000021
|
||||||
|
int64_t eax = 0x00000041;
|
||||||
|
int64_t ecx = 0x5ffffff8;
|
||||||
|
int64_t edx = 0x5ffffff8;
|
||||||
|
int64_t ebx = 0x034a129b;
|
||||||
|
int64_t esp = 0x6010229a;
|
||||||
|
int64_t ebp = 0x60000002;
|
||||||
|
int64_t esi = 0x1f350211;
|
||||||
|
int64_t edi = 0x488ac239;
|
||||||
|
#else
|
||||||
|
// These values assumes PC == 0x6000000
|
||||||
|
int64_t eax = 0x73952c43;
|
||||||
|
int64_t ecx = 0x6010229a;
|
||||||
|
int64_t edx = 0x2a500e50;
|
||||||
|
int64_t ebx = 0x034a1295;
|
||||||
|
int64_t esp = 0x6010229a;
|
||||||
|
int64_t ebp = 0x60000000;
|
||||||
|
int64_t esi = 0x1f350211;
|
||||||
|
int64_t edi = 0x488ac239;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mem = calloc(1, CODE_SPACE);
|
||||||
|
assert_int_not_equal(0, mem);
|
||||||
|
|
||||||
|
uc_assert_success(uc_open(UC_ARCH_X86,
|
||||||
|
UC_MODE_32,
|
||||||
|
&uc));
|
||||||
|
uc_assert_success(uc_mem_map(uc,
|
||||||
|
PHY_STACK_REGION,
|
||||||
|
CODE_SPACE,
|
||||||
|
UC_PROT_ALL));
|
||||||
|
uc_assert_success(uc_mem_write(uc,
|
||||||
|
PHY_STACK_REGION,
|
||||||
|
X86_CODE32_ALPHA_MIXED,
|
||||||
|
sizeof(X86_CODE32_ALPHA_MIXED) - 1));
|
||||||
|
uc_assert_success(uc_reg_write(uc, UC_X86_REG_EAX, &eax));
|
||||||
|
uc_assert_success(uc_reg_write(uc, UC_X86_REG_ECX, &ecx));
|
||||||
|
uc_assert_success(uc_reg_write(uc, UC_X86_REG_EDX, &edx));
|
||||||
|
uc_assert_success(uc_reg_write(uc, UC_X86_REG_EBX, &ebx));
|
||||||
|
uc_assert_success(uc_reg_write(uc, UC_X86_REG_ESP, &esp));
|
||||||
|
uc_assert_success(uc_reg_write(uc, UC_X86_REG_EBP, &ebp));
|
||||||
|
uc_assert_success(uc_reg_write(uc, UC_X86_REG_ESI, &esi));
|
||||||
|
uc_assert_success(uc_reg_write(uc, UC_X86_REG_EDI, &edi));
|
||||||
|
|
||||||
|
uc_assert_success(uc_hook_add(uc,
|
||||||
|
&trace1,
|
||||||
|
UC_HOOK_CODE,
|
||||||
|
hook_code32,
|
||||||
|
NULL,
|
||||||
|
(uint64_t)1,
|
||||||
|
(uint64_t)0));
|
||||||
|
|
||||||
|
uc_assert_success(uc_hook_add(uc,
|
||||||
|
&trace2,
|
||||||
|
UC_HOOK_MEM_VALID,
|
||||||
|
hook_mem32,
|
||||||
|
NULL,
|
||||||
|
(uint64_t)1,
|
||||||
|
(uint64_t)0));
|
||||||
|
|
||||||
|
uc_assert_success(uc_emu_start(uc,
|
||||||
|
#ifdef RIP_NEXT_TO_THE_SELFMODIFY_OPCODE
|
||||||
|
// Register set (before self-modifying IMUL opcode)
|
||||||
|
// Start at "0x00000021: xorb %al, 0x30(%ecx)
|
||||||
|
// Start at "0x00000021: xor byte ptr [ecx + 0x30], al
|
||||||
|
PHY_STACK_REGION+0x0021, // 0x0024 didn't work
|
||||||
|
#else
|
||||||
|
PHY_STACK_REGION+0x0000,
|
||||||
|
#endif
|
||||||
|
PHY_STACK_REGION+sizeof(X86_CODE32_ALPHA_MIXED) - 1,
|
||||||
|
0, 0));
|
||||||
|
|
||||||
|
uc_assert_success(uc_close(uc));
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(void)
|
||||||
|
{
|
||||||
|
#define test(x) cmocka_unit_test_setup_teardown(x, setup, teardown)
|
||||||
|
const struct CMUnitTest tests[] = {
|
||||||
|
test(test_tb_x86_64_32_imul_Gv_Ev_Ib)
|
||||||
|
};
|
||||||
|
#undef test
|
||||||
|
return cmocka_run_group_tests(tests, NULL, NULL);
|
||||||
|
}
|
496
uc.c
496
uc.c
|
@ -20,7 +20,6 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "uc_priv.h"
|
#include "uc_priv.h"
|
||||||
#include "hook.h"
|
|
||||||
|
|
||||||
// target specific headers
|
// target specific headers
|
||||||
#include "qemu/target-m68k/unicorn.h"
|
#include "qemu/target-m68k/unicorn.h"
|
||||||
|
@ -95,8 +94,6 @@ const char *uc_strerror(uc_err code)
|
||||||
return "Write to unaligned memory (UC_ERR_WRITE_UNALIGNED)";
|
return "Write to unaligned memory (UC_ERR_WRITE_UNALIGNED)";
|
||||||
case UC_ERR_FETCH_UNALIGNED:
|
case UC_ERR_FETCH_UNALIGNED:
|
||||||
return "Fetch from unaligned memory (UC_ERR_FETCH_UNALIGNED)";
|
return "Fetch from unaligned memory (UC_ERR_FETCH_UNALIGNED)";
|
||||||
case UC_ERR_HOOK_EXIST:
|
|
||||||
return "Hook for this type event already exists (UC_ERR_HOOK_EXIST)";
|
|
||||||
case UC_ERR_RESOURCE:
|
case UC_ERR_RESOURCE:
|
||||||
return "Insufficient resource (UC_ERR_RESOURCE)";
|
return "Insufficient resource (UC_ERR_RESOURCE)";
|
||||||
}
|
}
|
||||||
|
@ -171,36 +168,56 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
|
||||||
break;
|
break;
|
||||||
#ifdef UNICORN_HAS_M68K
|
#ifdef UNICORN_HAS_M68K
|
||||||
case UC_ARCH_M68K:
|
case UC_ARCH_M68K:
|
||||||
|
if ((mode & ~UC_MODE_M68K_MASK) ||
|
||||||
|
!(mode & UC_MODE_BIG_ENDIAN)) {
|
||||||
|
free(uc);
|
||||||
|
return UC_ERR_MODE;
|
||||||
|
}
|
||||||
uc->init_arch = m68k_uc_init;
|
uc->init_arch = m68k_uc_init;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef UNICORN_HAS_X86
|
#ifdef UNICORN_HAS_X86
|
||||||
case UC_ARCH_X86:
|
case UC_ARCH_X86:
|
||||||
|
if ((mode & ~UC_MODE_X86_MASK) ||
|
||||||
|
(mode & UC_MODE_BIG_ENDIAN) ||
|
||||||
|
!(mode & (UC_MODE_16|UC_MODE_32|UC_MODE_64))) {
|
||||||
|
free(uc);
|
||||||
|
return UC_ERR_MODE;
|
||||||
|
}
|
||||||
uc->init_arch = x86_uc_init;
|
uc->init_arch = x86_uc_init;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef UNICORN_HAS_ARM
|
#ifdef UNICORN_HAS_ARM
|
||||||
case UC_ARCH_ARM:
|
case UC_ARCH_ARM:
|
||||||
uc->init_arch = arm_uc_init;
|
if ((mode & ~UC_MODE_ARM_MASK) ||
|
||||||
|
(mode & UC_MODE_BIG_ENDIAN)) {
|
||||||
// verify mode
|
|
||||||
if (mode != UC_MODE_ARM && mode != UC_MODE_THUMB) {
|
|
||||||
free(uc);
|
free(uc);
|
||||||
return UC_ERR_MODE;
|
return UC_ERR_MODE;
|
||||||
}
|
}
|
||||||
|
uc->init_arch = arm_uc_init;
|
||||||
|
|
||||||
if (mode == UC_MODE_THUMB)
|
if (mode & UC_MODE_THUMB)
|
||||||
uc->thumb = 1;
|
uc->thumb = 1;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#ifdef UNICORN_HAS_ARM64
|
#ifdef UNICORN_HAS_ARM64
|
||||||
case UC_ARCH_ARM64:
|
case UC_ARCH_ARM64:
|
||||||
|
if ((mode & ~UC_MODE_ARM_MASK) ||
|
||||||
|
(mode & UC_MODE_BIG_ENDIAN)) {
|
||||||
|
free(uc);
|
||||||
|
return UC_ERR_MODE;
|
||||||
|
}
|
||||||
uc->init_arch = arm64_uc_init;
|
uc->init_arch = arm64_uc_init;
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(UNICORN_HAS_MIPS) || defined(UNICORN_HAS_MIPSEL) || defined(UNICORN_HAS_MIPS64) || defined(UNICORN_HAS_MIPS64EL)
|
#if defined(UNICORN_HAS_MIPS) || defined(UNICORN_HAS_MIPSEL) || defined(UNICORN_HAS_MIPS64) || defined(UNICORN_HAS_MIPS64EL)
|
||||||
case UC_ARCH_MIPS:
|
case UC_ARCH_MIPS:
|
||||||
|
if ((mode & ~UC_MODE_MIPS_MASK) ||
|
||||||
|
!(mode & (UC_MODE_MIPS32|UC_MODE_MIPS64))) {
|
||||||
|
free(uc);
|
||||||
|
return UC_ERR_MODE;
|
||||||
|
}
|
||||||
if (mode & UC_MODE_BIG_ENDIAN) {
|
if (mode & UC_MODE_BIG_ENDIAN) {
|
||||||
#ifdef UNICORN_HAS_MIPS
|
#ifdef UNICORN_HAS_MIPS
|
||||||
if (mode & UC_MODE_MIPS32)
|
if (mode & UC_MODE_MIPS32)
|
||||||
|
@ -225,7 +242,13 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
|
||||||
|
|
||||||
#ifdef UNICORN_HAS_SPARC
|
#ifdef UNICORN_HAS_SPARC
|
||||||
case UC_ARCH_SPARC:
|
case UC_ARCH_SPARC:
|
||||||
if (mode & UC_MODE_64)
|
if ((mode & ~UC_MODE_SPARC_MASK) ||
|
||||||
|
!(mode & UC_MODE_BIG_ENDIAN) ||
|
||||||
|
!(mode & (UC_MODE_SPARC32|UC_MODE_SPARC64))) {
|
||||||
|
free(uc);
|
||||||
|
return UC_ERR_MODE;
|
||||||
|
}
|
||||||
|
if (mode & UC_MODE_SPARC64)
|
||||||
uc->init_arch = sparc64_uc_init;
|
uc->init_arch = sparc64_uc_init;
|
||||||
else
|
else
|
||||||
uc->init_arch = sparc_uc_init;
|
uc->init_arch = sparc_uc_init;
|
||||||
|
@ -245,9 +268,6 @@ uc_err uc_open(uc_arch arch, uc_mode mode, uc_engine **result)
|
||||||
if (uc->reg_reset)
|
if (uc->reg_reset)
|
||||||
uc->reg_reset(uc);
|
uc->reg_reset(uc);
|
||||||
|
|
||||||
uc->hook_size = HOOK_SIZE;
|
|
||||||
uc->hook_callbacks = calloc(1, sizeof(uc->hook_callbacks[0]) * HOOK_SIZE);
|
|
||||||
|
|
||||||
return UC_ERR_OK;
|
return UC_ERR_OK;
|
||||||
} else {
|
} else {
|
||||||
return UC_ERR_ARCH;
|
return UC_ERR_ARCH;
|
||||||
|
@ -259,6 +279,8 @@ UNICORN_EXPORT
|
||||||
uc_err uc_close(uc_engine *uc)
|
uc_err uc_close(uc_engine *uc)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
struct list_item *cur;
|
||||||
|
struct hook *hook;
|
||||||
|
|
||||||
if (uc->release)
|
if (uc->release)
|
||||||
uc->release(uc->tcg_ctx);
|
uc->release(uc->tcg_ctx);
|
||||||
|
@ -277,7 +299,23 @@ uc_err uc_close(uc_engine *uc)
|
||||||
free(uc->ram_list.dirty_memory[i]);
|
free(uc->ram_list.dirty_memory[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(uc->hook_callbacks);
|
// TODO: remove uc->root (created with object_new())
|
||||||
|
uc->root->free(uc->root);
|
||||||
|
|
||||||
|
// free hooks and hook lists
|
||||||
|
for (i = 0; i < UC_HOOK_MAX; i++) {
|
||||||
|
cur = uc->hook[i].head;
|
||||||
|
// hook can be in more than one list
|
||||||
|
// so we refcount to know when to free
|
||||||
|
while (cur) {
|
||||||
|
hook = (struct hook *)cur->data;
|
||||||
|
if (--hook->refs == 0) {
|
||||||
|
free(hook);
|
||||||
|
}
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
list_clear(&uc->hook[i]);
|
||||||
|
}
|
||||||
|
|
||||||
free(uc->mapped_blocks);
|
free(uc->mapped_blocks);
|
||||||
|
|
||||||
|
@ -438,12 +476,20 @@ static void enable_emu_timer(uc_engine *uc, uint64_t timeout)
|
||||||
uc, QEMU_THREAD_JOINABLE);
|
uc, QEMU_THREAD_JOINABLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void hook_count_cb(struct uc_struct *uc, uint64_t address, uint32_t size, void *user_data)
|
||||||
|
{
|
||||||
|
// count this instruction. ah ah ah.
|
||||||
|
uc->emu_counter++;
|
||||||
|
|
||||||
|
if (uc->emu_counter > uc->emu_count)
|
||||||
|
uc_emu_stop(uc);
|
||||||
|
}
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count)
|
uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count)
|
||||||
{
|
{
|
||||||
// reset the counter
|
// reset the counter
|
||||||
uc->emu_counter = 0;
|
uc->emu_counter = 0;
|
||||||
uc->stop_request = false;
|
|
||||||
uc->invalid_error = UC_ERR_OK;
|
uc->invalid_error = UC_ERR_OK;
|
||||||
uc->block_full = false;
|
uc->block_full = false;
|
||||||
uc->emulation_done = false;
|
uc->emulation_done = false;
|
||||||
|
@ -473,15 +519,8 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case UC_ARCH_ARM:
|
case UC_ARCH_ARM:
|
||||||
switch(uc->mode) {
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
case UC_MODE_THUMB:
|
|
||||||
case UC_MODE_ARM:
|
|
||||||
uc_reg_write(uc, UC_ARM_REG_R15, &begin);
|
uc_reg_write(uc, UC_ARM_REG_R15, &begin);
|
||||||
break;
|
break;
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case UC_ARCH_ARM64:
|
case UC_ARCH_ARM64:
|
||||||
uc_reg_write(uc, UC_ARM64_REG_PC, &begin);
|
uc_reg_write(uc, UC_ARM64_REG_PC, &begin);
|
||||||
|
@ -498,9 +537,20 @@ uc_err uc_emu_start(uc_engine* uc, uint64_t begin, uint64_t until, uint64_t time
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uc->stop_request = false;
|
||||||
|
|
||||||
uc->emu_count = count;
|
uc->emu_count = count;
|
||||||
if (count > 0) {
|
// remove count hook if counting isn't necessary
|
||||||
uc->hook_insn = true;
|
if (count <= 0 && uc->count_hook != 0) {
|
||||||
|
uc_hook_del(uc, uc->count_hook);
|
||||||
|
uc->count_hook = 0;
|
||||||
|
}
|
||||||
|
// set up count hook to count instructions.
|
||||||
|
if (count > 0 && uc->count_hook == 0) {
|
||||||
|
uc_err err = uc_hook_add(uc, &uc->count_hook, UC_HOOK_CODE, hook_count_cb, NULL);
|
||||||
|
if (err != UC_ERR_OK) {
|
||||||
|
return err;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uc->addr_end = until;
|
uc->addr_end = until;
|
||||||
|
@ -539,37 +589,6 @@ uc_err uc_emu_stop(uc_engine *uc)
|
||||||
return UC_ERR_OK;
|
return UC_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static int _hook_code(uc_engine *uc, int type, uint64_t begin, uint64_t end,
|
|
||||||
void *callback, void *user_data, uc_hook *hh)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
i = hook_add(uc, type, begin, end, callback, user_data);
|
|
||||||
if (i == 0)
|
|
||||||
return UC_ERR_NOMEM;
|
|
||||||
|
|
||||||
*hh = i;
|
|
||||||
|
|
||||||
return UC_ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static uc_err _hook_mem_access(uc_engine *uc, uc_hook_type type,
|
|
||||||
uint64_t begin, uint64_t end,
|
|
||||||
void *callback, void *user_data, uc_hook *hh)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
|
|
||||||
i = hook_add(uc, type, begin, end, callback, user_data);
|
|
||||||
if (i == 0)
|
|
||||||
return UC_ERR_NOMEM;
|
|
||||||
|
|
||||||
*hh = i;
|
|
||||||
|
|
||||||
return UC_ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// find if a memory range overlaps with existing mapped regions
|
// find if a memory range overlaps with existing mapped regions
|
||||||
static bool memory_overlap(struct uc_struct *uc, uint64_t begin, size_t size)
|
static bool memory_overlap(struct uc_struct *uc, uint64_t begin, size_t size)
|
||||||
{
|
{
|
||||||
|
@ -599,26 +618,6 @@ static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t per
|
||||||
{
|
{
|
||||||
MemoryRegion **regions;
|
MemoryRegion **regions;
|
||||||
|
|
||||||
if (size == 0)
|
|
||||||
// invalid memory mapping
|
|
||||||
return UC_ERR_ARG;
|
|
||||||
|
|
||||||
// address cannot wrapp around
|
|
||||||
if (address + size - 1 < address)
|
|
||||||
return UC_ERR_ARG;
|
|
||||||
|
|
||||||
// address must be aligned to uc->target_page_size
|
|
||||||
if ((address & uc->target_page_align) != 0)
|
|
||||||
return UC_ERR_ARG;
|
|
||||||
|
|
||||||
// size must be multiple of uc->target_page_size
|
|
||||||
if ((size & uc->target_page_align) != 0)
|
|
||||||
return UC_ERR_ARG;
|
|
||||||
|
|
||||||
// check for only valid permissions
|
|
||||||
if ((perms & ~UC_PROT_ALL) != 0)
|
|
||||||
return UC_ERR_ARG;
|
|
||||||
|
|
||||||
// this area overlaps existing mapped regions?
|
// this area overlaps existing mapped regions?
|
||||||
if (memory_overlap(uc, address, size))
|
if (memory_overlap(uc, address, size))
|
||||||
return UC_ERR_MAP;
|
return UC_ERR_MAP;
|
||||||
|
@ -641,19 +640,52 @@ static uc_err mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t per
|
||||||
return UC_ERR_OK;
|
return UC_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static uc_err mem_map_check(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
|
||||||
|
{
|
||||||
|
if (size == 0)
|
||||||
|
// invalid memory mapping
|
||||||
|
return UC_ERR_ARG;
|
||||||
|
|
||||||
|
// address cannot wrapp around
|
||||||
|
if (address + size - 1 < address)
|
||||||
|
return UC_ERR_ARG;
|
||||||
|
|
||||||
|
// address must be aligned to uc->target_page_size
|
||||||
|
if ((address & uc->target_page_align) != 0)
|
||||||
|
return UC_ERR_ARG;
|
||||||
|
|
||||||
|
// size must be multiple of uc->target_page_size
|
||||||
|
if ((size & uc->target_page_align) != 0)
|
||||||
|
return UC_ERR_ARG;
|
||||||
|
|
||||||
|
// check for only valid permissions
|
||||||
|
if ((perms & ~UC_PROT_ALL) != 0)
|
||||||
|
return UC_ERR_ARG;
|
||||||
|
|
||||||
|
return UC_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
|
uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms)
|
||||||
{
|
{
|
||||||
|
uc_err res;
|
||||||
|
|
||||||
if (uc->mem_redirect) {
|
if (uc->mem_redirect) {
|
||||||
address = uc->mem_redirect(address);
|
address = uc->mem_redirect(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
res = mem_map_check(uc, address, size, perms);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
|
||||||
return mem_map(uc, address, size, perms, uc->memory_map(uc, address, size, perms));
|
return mem_map(uc, address, size, perms, uc->memory_map(uc, address, size, perms));
|
||||||
}
|
}
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr)
|
uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t perms, void *ptr)
|
||||||
{
|
{
|
||||||
|
uc_err res;
|
||||||
|
|
||||||
if (ptr == NULL)
|
if (ptr == NULL)
|
||||||
return UC_ERR_ARG;
|
return UC_ERR_ARG;
|
||||||
|
|
||||||
|
@ -661,6 +693,10 @@ uc_err uc_mem_map_ptr(uc_engine *uc, uint64_t address, size_t size, uint32_t per
|
||||||
address = uc->mem_redirect(address);
|
address = uc->mem_redirect(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
res = mem_map_check(uc, address, size, perms);
|
||||||
|
if (res)
|
||||||
|
return res;
|
||||||
|
|
||||||
return mem_map(uc, address, size, UC_PROT_ALL, uc->memory_map_ptr(uc, address, size, perms, ptr));
|
return mem_map(uc, address, size, UC_PROT_ALL, uc->memory_map_ptr(uc, address, size, perms, ptr));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -787,6 +823,7 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, uint3
|
||||||
MemoryRegion *mr;
|
MemoryRegion *mr;
|
||||||
uint64_t addr = address;
|
uint64_t addr = address;
|
||||||
size_t count, len;
|
size_t count, len;
|
||||||
|
bool remove_exec = false;
|
||||||
|
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
// trivial case, no change
|
// trivial case, no change
|
||||||
|
@ -823,12 +860,22 @@ uc_err uc_mem_protect(struct uc_struct *uc, uint64_t address, size_t size, uint3
|
||||||
return UC_ERR_NOMEM;
|
return UC_ERR_NOMEM;
|
||||||
|
|
||||||
mr = memory_mapping(uc, addr);
|
mr = memory_mapping(uc, addr);
|
||||||
|
// will this remove EXEC permission?
|
||||||
|
if (((mr->perms & UC_PROT_EXEC) != 0) && ((perms & UC_PROT_EXEC) == 0))
|
||||||
|
remove_exec = true;
|
||||||
mr->perms = perms;
|
mr->perms = perms;
|
||||||
uc->readonly_mem(mr, (perms & UC_PROT_WRITE) == 0);
|
uc->readonly_mem(mr, (perms & UC_PROT_WRITE) == 0);
|
||||||
|
|
||||||
count += len;
|
count += len;
|
||||||
addr += len;
|
addr += len;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if EXEC permission is removed, then quit TB and continue at the same place
|
||||||
|
if (remove_exec) {
|
||||||
|
uc->quit_request = true;
|
||||||
|
uc_emu_stop(uc);
|
||||||
|
}
|
||||||
|
|
||||||
return UC_ERR_OK;
|
return UC_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -911,206 +958,141 @@ MemoryRegion *memory_mapping(struct uc_struct* uc, uint64_t address)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uc_err _hook_mem_invalid(struct uc_struct* uc, int type, uc_cb_eventmem_t callback,
|
|
||||||
void *user_data, uc_hook *evh)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
// only one event handler at the same time
|
|
||||||
if ((type & UC_HOOK_MEM_READ_UNMAPPED) != 0 && (uc->hook_mem_read_idx != 0))
|
|
||||||
return UC_ERR_HOOK_EXIST;
|
|
||||||
|
|
||||||
if ((type & UC_HOOK_MEM_READ_PROT) != 0 && (uc->hook_mem_read_prot_idx != 0))
|
|
||||||
return UC_ERR_HOOK_EXIST;
|
|
||||||
|
|
||||||
if ((type & UC_HOOK_MEM_WRITE_UNMAPPED) != 0 && (uc->hook_mem_write_idx != 0))
|
|
||||||
return UC_ERR_HOOK_EXIST;
|
|
||||||
|
|
||||||
if ((type & UC_HOOK_MEM_WRITE_PROT) != 0 && (uc->hook_mem_write_prot_idx != 0))
|
|
||||||
return UC_ERR_HOOK_EXIST;
|
|
||||||
|
|
||||||
if ((type & UC_HOOK_MEM_FETCH_UNMAPPED) != 0 && (uc->hook_mem_fetch_idx != 0))
|
|
||||||
return UC_ERR_HOOK_EXIST;
|
|
||||||
|
|
||||||
if ((type & UC_HOOK_MEM_FETCH_PROT) != 0 && (uc->hook_mem_fetch_prot_idx != 0))
|
|
||||||
return UC_ERR_HOOK_EXIST;
|
|
||||||
|
|
||||||
i = hook_find_new(uc);
|
|
||||||
if (i) {
|
|
||||||
uc->hook_callbacks[i].callback = callback;
|
|
||||||
uc->hook_callbacks[i].user_data = user_data;
|
|
||||||
*evh = i;
|
|
||||||
if (type & UC_HOOK_MEM_READ_UNMAPPED)
|
|
||||||
uc->hook_mem_read_idx = i;
|
|
||||||
if (type & UC_HOOK_MEM_READ_PROT)
|
|
||||||
uc->hook_mem_read_prot_idx = i;
|
|
||||||
if (type & UC_HOOK_MEM_WRITE_UNMAPPED)
|
|
||||||
uc->hook_mem_write_idx = i;
|
|
||||||
if (type & UC_HOOK_MEM_WRITE_PROT)
|
|
||||||
uc->hook_mem_write_prot_idx = i;
|
|
||||||
if (type & UC_HOOK_MEM_FETCH_UNMAPPED)
|
|
||||||
uc->hook_mem_fetch_idx = i;
|
|
||||||
if (type & UC_HOOK_MEM_FETCH_PROT)
|
|
||||||
uc->hook_mem_fetch_prot_idx = i;
|
|
||||||
return UC_ERR_OK;
|
|
||||||
} else
|
|
||||||
return UC_ERR_NOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static uc_err _hook_intr(struct uc_struct* uc, void *callback,
|
|
||||||
void *user_data, uc_hook *evh)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
// only one event handler at the same time
|
|
||||||
if (uc->hook_intr_idx)
|
|
||||||
return UC_ERR_HOOK_EXIST;
|
|
||||||
|
|
||||||
i = hook_find_new(uc);
|
|
||||||
if (i) {
|
|
||||||
uc->hook_callbacks[i].callback = callback;
|
|
||||||
uc->hook_callbacks[i].user_data = user_data;
|
|
||||||
*evh = i;
|
|
||||||
uc->hook_intr_idx = i;
|
|
||||||
return UC_ERR_OK;
|
|
||||||
} else
|
|
||||||
return UC_ERR_NOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static uc_err _hook_insn(struct uc_struct *uc, unsigned int insn_id, void *callback,
|
|
||||||
void *user_data, uc_hook *evh)
|
|
||||||
{
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
switch(uc->arch) {
|
|
||||||
default: break;
|
|
||||||
case UC_ARCH_X86:
|
|
||||||
switch(insn_id) {
|
|
||||||
default: break;
|
|
||||||
case UC_X86_INS_OUT:
|
|
||||||
// only one event handler at the same time
|
|
||||||
if (uc->hook_out_idx)
|
|
||||||
return UC_ERR_HOOK_EXIST;
|
|
||||||
|
|
||||||
i = hook_find_new(uc);
|
|
||||||
if (i) {
|
|
||||||
uc->hook_callbacks[i].callback = callback;
|
|
||||||
uc->hook_callbacks[i].user_data = user_data;
|
|
||||||
*evh = i;
|
|
||||||
uc->hook_out_idx = i;
|
|
||||||
return UC_ERR_OK;
|
|
||||||
} else
|
|
||||||
return UC_ERR_NOMEM;
|
|
||||||
case UC_X86_INS_IN:
|
|
||||||
// only one event handler at the same time
|
|
||||||
if (uc->hook_in_idx)
|
|
||||||
return UC_ERR_HOOK_EXIST;
|
|
||||||
|
|
||||||
i = hook_find_new(uc);
|
|
||||||
if (i) {
|
|
||||||
uc->hook_callbacks[i].callback = callback;
|
|
||||||
uc->hook_callbacks[i].user_data = user_data;
|
|
||||||
*evh = i;
|
|
||||||
uc->hook_in_idx = i;
|
|
||||||
return UC_ERR_OK;
|
|
||||||
} else
|
|
||||||
return UC_ERR_NOMEM;
|
|
||||||
case UC_X86_INS_SYSCALL:
|
|
||||||
case UC_X86_INS_SYSENTER:
|
|
||||||
// only one event handler at the same time
|
|
||||||
if (uc->hook_syscall_idx)
|
|
||||||
return UC_ERR_HOOK_EXIST;
|
|
||||||
|
|
||||||
i = hook_find_new(uc);
|
|
||||||
if (i) {
|
|
||||||
uc->hook_callbacks[i].callback = callback;
|
|
||||||
uc->hook_callbacks[i].user_data = user_data;
|
|
||||||
*evh = i;
|
|
||||||
uc->hook_syscall_idx = i;
|
|
||||||
return UC_ERR_OK;
|
|
||||||
} else
|
|
||||||
return UC_ERR_NOMEM;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return UC_ERR_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...)
|
uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback, void *user_data, ...)
|
||||||
{
|
{
|
||||||
va_list valist;
|
va_list valist;
|
||||||
int ret = UC_ERR_OK;
|
int ret = UC_ERR_OK;
|
||||||
int id;
|
|
||||||
uint64_t begin, end;
|
|
||||||
|
|
||||||
va_start(valist, user_data);
|
va_start(valist, user_data);
|
||||||
|
|
||||||
if (type & UC_HOOK_MEM_READ_UNMAPPED)
|
struct hook *hook = calloc(1, sizeof(struct hook));
|
||||||
ret = _hook_mem_invalid(uc, UC_HOOK_MEM_READ_UNMAPPED, callback, user_data, hh);
|
if (hook == NULL) {
|
||||||
|
return UC_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
hook->type = type;
|
||||||
|
hook->callback = callback;
|
||||||
|
hook->user_data = user_data;
|
||||||
|
hook->refs = 0;
|
||||||
|
*hh = (uc_hook)hook;
|
||||||
|
|
||||||
if (type & UC_HOOK_MEM_WRITE_UNMAPPED)
|
// everybody but HOOK_INSN gets begin/end, so exit early here.
|
||||||
ret = _hook_mem_invalid(uc, UC_HOOK_MEM_WRITE_UNMAPPED, callback, user_data, hh);
|
if (type & UC_HOOK_INSN) {
|
||||||
|
hook->insn = va_arg(valist, int);
|
||||||
if (type & UC_HOOK_MEM_FETCH_UNMAPPED)
|
hook->begin = 1;
|
||||||
ret = _hook_mem_invalid(uc, UC_HOOK_MEM_FETCH_UNMAPPED, callback, user_data, hh);
|
hook->end = 0;
|
||||||
|
if (list_append(&uc->hook[UC_HOOK_INSN_IDX], hook) == NULL) {
|
||||||
if (type & UC_HOOK_MEM_READ_PROT)
|
free(hook);
|
||||||
ret = _hook_mem_invalid(uc, UC_HOOK_MEM_READ_PROT, callback, user_data, hh);
|
return UC_ERR_NOMEM;
|
||||||
|
}
|
||||||
if (type & UC_HOOK_MEM_WRITE_PROT)
|
hook->refs++;
|
||||||
ret = _hook_mem_invalid(uc, UC_HOOK_MEM_WRITE_PROT, callback, user_data, hh);
|
return UC_ERR_OK;
|
||||||
|
|
||||||
if (type & UC_HOOK_MEM_FETCH_PROT)
|
|
||||||
ret = _hook_mem_invalid(uc, UC_HOOK_MEM_FETCH_PROT, callback, user_data, hh);
|
|
||||||
|
|
||||||
switch(type) {
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
case UC_HOOK_INTR:
|
|
||||||
ret = _hook_intr(uc, callback, user_data, hh);
|
|
||||||
break;
|
|
||||||
case UC_HOOK_INSN:
|
|
||||||
id = va_arg(valist, int);
|
|
||||||
ret = _hook_insn(uc, id, callback, user_data, hh);
|
|
||||||
break;
|
|
||||||
case UC_HOOK_CODE:
|
|
||||||
begin = va_arg(valist, uint64_t);
|
|
||||||
end = va_arg(valist, uint64_t);
|
|
||||||
ret = _hook_code(uc, UC_HOOK_CODE, begin, end, callback, user_data, hh);
|
|
||||||
break;
|
|
||||||
case UC_HOOK_BLOCK:
|
|
||||||
begin = va_arg(valist, uint64_t);
|
|
||||||
end = va_arg(valist, uint64_t);
|
|
||||||
ret = _hook_code(uc, UC_HOOK_BLOCK, begin, end, callback, user_data, hh);
|
|
||||||
break;
|
|
||||||
case UC_HOOK_MEM_READ:
|
|
||||||
begin = va_arg(valist, uint64_t);
|
|
||||||
end = va_arg(valist, uint64_t);
|
|
||||||
ret = _hook_mem_access(uc, UC_HOOK_MEM_READ, begin, end, callback, user_data, hh);
|
|
||||||
break;
|
|
||||||
case UC_HOOK_MEM_WRITE:
|
|
||||||
begin = va_arg(valist, uint64_t);
|
|
||||||
end = va_arg(valist, uint64_t);
|
|
||||||
ret = _hook_mem_access(uc, UC_HOOK_MEM_WRITE, begin, end, callback, user_data, hh);
|
|
||||||
break;
|
|
||||||
case UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE:
|
|
||||||
begin = va_arg(valist, uint64_t);
|
|
||||||
end = va_arg(valist, uint64_t);
|
|
||||||
ret = _hook_mem_access(uc, UC_HOOK_MEM_READ | UC_HOOK_MEM_WRITE, begin, end, callback, user_data, hh);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hook->begin = va_arg(valist, uint64_t);
|
||||||
|
hook->end = va_arg(valist, uint64_t);
|
||||||
va_end(valist);
|
va_end(valist);
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
while ((type >> i) > 0) {
|
||||||
|
if ((type >> i) & 1) {
|
||||||
|
// TODO: invalid hook error?
|
||||||
|
if (i < UC_HOOK_MAX) {
|
||||||
|
if (list_append(&uc->hook[i], hook) == NULL) {
|
||||||
|
if (hook->refs == 0) {
|
||||||
|
free(hook);
|
||||||
|
}
|
||||||
|
return UC_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
hook->refs++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// we didn't use the hook
|
||||||
|
// TODO: return an error?
|
||||||
|
if (hook->refs == 0) {
|
||||||
|
free(hook);
|
||||||
|
}
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNICORN_EXPORT
|
UNICORN_EXPORT
|
||||||
uc_err uc_hook_del(uc_engine *uc, uc_hook hh)
|
uc_err uc_hook_del(uc_engine *uc, uc_hook hh)
|
||||||
{
|
{
|
||||||
return hook_del(uc, hh);
|
int i;
|
||||||
|
struct hook *hook;
|
||||||
|
for (i = 0; i < UC_HOOK_MAX; i++) {
|
||||||
|
if (list_remove(&uc->hook[i], (void *)hh)) {
|
||||||
|
hook = (struct hook *)hh;
|
||||||
|
if (--hook->refs == 0) {
|
||||||
|
free(hook);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return UC_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TCG helper
|
||||||
|
void helper_uc_tracecode(int32_t size, uc_hook_type type, void *handle, int64_t address);
|
||||||
|
void helper_uc_tracecode(int32_t size, uc_hook_type type, void *handle, int64_t address)
|
||||||
|
{
|
||||||
|
struct uc_struct *uc = handle;
|
||||||
|
struct list_item *cur = uc->hook[type].head;
|
||||||
|
struct hook *hook;
|
||||||
|
|
||||||
|
// sync PC in CPUArchState with address
|
||||||
|
if (uc->set_pc) {
|
||||||
|
uc->set_pc(uc, address);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (cur != NULL && !uc->stop_request) {
|
||||||
|
hook = (struct hook *)cur->data;
|
||||||
|
if (HOOK_BOUND_CHECK(hook, address)) {
|
||||||
|
((uc_cb_hookcode_t)hook->callback)(uc, address, size, hook->user_data);
|
||||||
|
}
|
||||||
|
cur = cur->next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UNICORN_EXPORT
|
||||||
|
uint32_t uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count)
|
||||||
|
{
|
||||||
|
uint32_t i;
|
||||||
|
uc_mem_region *r = NULL;
|
||||||
|
|
||||||
|
*count = uc->mapped_block_count;
|
||||||
|
|
||||||
|
if (*count) {
|
||||||
|
r = malloc(*count * sizeof(uc_mem_region));
|
||||||
|
if (r == NULL) {
|
||||||
|
// out of memory
|
||||||
|
return UC_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < *count; i++) {
|
||||||
|
r[i].begin = uc->mapped_blocks[i]->addr;
|
||||||
|
r[i].end = uc->mapped_blocks[i]->end - 1;
|
||||||
|
r[i].perms = uc->mapped_blocks[i]->perms;
|
||||||
|
}
|
||||||
|
|
||||||
|
*regions = r;
|
||||||
|
|
||||||
|
return UC_ERR_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
UNICORN_EXPORT
|
||||||
|
uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result)
|
||||||
|
{
|
||||||
|
switch(uc->arch) {
|
||||||
|
case UC_ARCH_ARM:
|
||||||
|
return uc->query(uc, type, result);
|
||||||
|
default:
|
||||||
|
return UC_ERR_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
return UC_ERR_OK;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue