Merge pull request #1458 from bet4it/patch
Port some patches from Unicorn1 to Unicorn2
This commit is contained in:
commit
6b5529fcb7
@ -1001,7 +1001,15 @@ if (MSVC)
|
|||||||
qemu/util/qemu-thread-win32.c
|
qemu/util/qemu-thread-win32.c
|
||||||
)
|
)
|
||||||
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
if (CMAKE_SIZEOF_VOID_P EQUAL 8)
|
||||||
|
if (MSVC_VERSION LESS 1600 AND MSVC_IDE)
|
||||||
|
add_custom_command(OUTPUT "${CMAKE_CURRENT_SOURCE_DIR}/build/setjmp-wrapper-win32.dir/setjmp-wrapper-win32.obj"
|
||||||
|
COMMAND ml64 /c /nologo /Fo"${CMAKE_CURRENT_SOURCE_DIR}/build/setjmp-wrapper-win32.dir/setjmp-wrapper-win32.obj" /W3 /errorReport:prompt /Ta"${CMAKE_CURRENT_SOURCE_DIR}/qemu/util/setjmp-wrapper-win32.asm"
|
||||||
|
DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/qemu/util/setjmp-wrapper-win32.asm"
|
||||||
|
)
|
||||||
|
set(UNICORN_SRCS ${UNICORN_SRCS} "${CMAKE_CURRENT_SOURCE_DIR}/build/setjmp-wrapper-win32.dir/setjmp-wrapper-win32.obj")
|
||||||
|
else()
|
||||||
enable_language(ASM_MASM)
|
enable_language(ASM_MASM)
|
||||||
|
endif()
|
||||||
set(UNICORN_COMMON_SRCS ${UNICORN_COMMON_SRCS} qemu/util/setjmp-wrapper-win32.asm)
|
set(UNICORN_COMMON_SRCS ${UNICORN_COMMON_SRCS} qemu/util/setjmp-wrapper-win32.asm)
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
|
@ -78,4 +78,5 @@ Kevin Foo (chfl4gs): Travis-CI migration
|
|||||||
Simon Gorchakov: PowerPC target
|
Simon Gorchakov: PowerPC target
|
||||||
Stuart Dootson (studoot): MSVC compatibility with PowerPC target support
|
Stuart Dootson (studoot): MSVC compatibility with PowerPC target support
|
||||||
Ziqiao Kong (lazymio): uc_context_free() API and various bug fix & improvement.
|
Ziqiao Kong (lazymio): uc_context_free() API and various bug fix & improvement.
|
||||||
|
Sven Almgren (blindmatrix): bug fix
|
||||||
Chenxu Wu (kabeor): Documentation
|
Chenxu Wu (kabeor): Documentation
|
@ -33,3 +33,6 @@ More bindings created & maintained externally by community are available as foll
|
|||||||
|
|
||||||
- pharo-unicorn: Pharo binding (by Guille Polito)
|
- pharo-unicorn: Pharo binding (by Guille Polito)
|
||||||
https://github.com/guillep/pharo-unicorn
|
https://github.com/guillep/pharo-unicorn
|
||||||
|
|
||||||
|
- Unicorn.js: JavaScript binding (by Alexandro Sanchez)
|
||||||
|
https://github.com/AlexAltea/unicorn.js
|
||||||
|
@ -108,7 +108,7 @@ type
|
|||||||
@user_data: user data passed to tracing APIs
|
@user_data: user data passed to tracing APIs
|
||||||
|
|
||||||
@return: return true to continue, or false to stop program (due to invalid memory).
|
@return: return true to continue, or false to stop program (due to invalid memory).
|
||||||
NOTE: returning true to continue execution will only work if if the accessed
|
NOTE: returning true to continue execution will only work if the accessed
|
||||||
memory is made accessible with the correct permissions during the hook.
|
memory is made accessible with the correct permissions during the hook.
|
||||||
|
|
||||||
In the event of a UC_MEM_READ_UNMAPPED or UC_MEM_WRITE_UNMAPPED callback,
|
In the event of a UC_MEM_READ_UNMAPPED or UC_MEM_WRITE_UNMAPPED callback,
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
import ctypes
|
import ctypes
|
||||||
import ctypes.util
|
import ctypes.util
|
||||||
import distutils.sysconfig
|
import distutils.sysconfig
|
||||||
|
from functools import wraps
|
||||||
import pkg_resources
|
import pkg_resources
|
||||||
import inspect
|
import inspect
|
||||||
import os.path
|
import os.path
|
||||||
@ -307,6 +308,27 @@ def reg_write(reg_write_func, arch, reg_id, value):
|
|||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def _catch_hook_exception(func):
|
||||||
|
@wraps(func)
|
||||||
|
def wrapper(self, *args, **kwargs):
|
||||||
|
"""Catches exceptions raised in hook functions.
|
||||||
|
|
||||||
|
If an exception is raised, it is saved to the Uc object and a call to stop
|
||||||
|
emulation is issued.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return func(self, *args, **kwargs)
|
||||||
|
except Exception as e:
|
||||||
|
# If multiple hooks raise exceptions, just use the first one
|
||||||
|
if self._hook_exception is None:
|
||||||
|
self._hook_exception = e
|
||||||
|
|
||||||
|
self.emu_stop()
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class uc_x86_mmr(ctypes.Structure):
|
class uc_x86_mmr(ctypes.Structure):
|
||||||
"""Memory-Management Register for instructions IDTR, GDTR, LDTR, TR."""
|
"""Memory-Management Register for instructions IDTR, GDTR, LDTR, TR."""
|
||||||
_fields_ = [
|
_fields_ = [
|
||||||
@ -410,6 +432,7 @@ class Uc(object):
|
|||||||
self._ctype_cbs = []
|
self._ctype_cbs = []
|
||||||
self._callback_count = 0
|
self._callback_count = 0
|
||||||
self._cleanup.register(self)
|
self._cleanup.register(self)
|
||||||
|
self._hook_exception = None # The exception raised in a hook
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def release_handle(uch):
|
def release_handle(uch):
|
||||||
@ -427,6 +450,9 @@ class Uc(object):
|
|||||||
if status != uc.UC_ERR_OK:
|
if status != uc.UC_ERR_OK:
|
||||||
raise UcError(status)
|
raise UcError(status)
|
||||||
|
|
||||||
|
if self._hook_exception is not None:
|
||||||
|
raise self._hook_exception
|
||||||
|
|
||||||
# stop emulation
|
# stop emulation
|
||||||
def emu_stop(self):
|
def emu_stop(self):
|
||||||
status = _uc.uc_emu_stop(self._uch)
|
status = _uc.uc_emu_stop(self._uch)
|
||||||
@ -522,41 +548,49 @@ class Uc(object):
|
|||||||
raise UcError(status)
|
raise UcError(status)
|
||||||
return result.value
|
return result.value
|
||||||
|
|
||||||
|
@_catch_hook_exception
|
||||||
def _hookcode_cb(self, handle, address, size, user_data):
|
def _hookcode_cb(self, handle, address, size, user_data):
|
||||||
# call user's callback with self object
|
# call user's callback with self object
|
||||||
(cb, data) = self._callbacks[user_data]
|
(cb, data) = self._callbacks[user_data]
|
||||||
cb(self, address, size, data)
|
cb(self, address, size, data)
|
||||||
|
|
||||||
|
@_catch_hook_exception
|
||||||
def _hook_mem_invalid_cb(self, handle, access, address, size, value, user_data):
|
def _hook_mem_invalid_cb(self, handle, access, address, size, value, user_data):
|
||||||
# call user's callback with self object
|
# call user's callback with self object
|
||||||
(cb, data) = self._callbacks[user_data]
|
(cb, data) = self._callbacks[user_data]
|
||||||
return cb(self, access, address, size, value, data)
|
return cb(self, access, address, size, value, data)
|
||||||
|
|
||||||
|
@_catch_hook_exception
|
||||||
def _hook_mem_access_cb(self, handle, access, address, size, value, user_data):
|
def _hook_mem_access_cb(self, handle, access, address, size, value, user_data):
|
||||||
# call user's callback with self object
|
# call user's callback with self object
|
||||||
(cb, data) = self._callbacks[user_data]
|
(cb, data) = self._callbacks[user_data]
|
||||||
cb(self, access, address, size, value, data)
|
cb(self, access, address, size, value, data)
|
||||||
|
|
||||||
|
@_catch_hook_exception
|
||||||
def _hook_intr_cb(self, handle, intno, user_data):
|
def _hook_intr_cb(self, handle, intno, user_data):
|
||||||
# call user's callback with self object
|
# call user's callback with self object
|
||||||
(cb, data) = self._callbacks[user_data]
|
(cb, data) = self._callbacks[user_data]
|
||||||
cb(self, intno, data)
|
cb(self, intno, data)
|
||||||
|
|
||||||
|
@_catch_hook_exception
|
||||||
def _hook_insn_invalid_cb(self, handle, user_data):
|
def _hook_insn_invalid_cb(self, handle, user_data):
|
||||||
# call user's callback with self object
|
# call user's callback with self object
|
||||||
(cb, data) = self._callbacks[user_data]
|
(cb, data) = self._callbacks[user_data]
|
||||||
return cb(self, data)
|
return cb(self, data)
|
||||||
|
|
||||||
|
@_catch_hook_exception
|
||||||
def _hook_insn_in_cb(self, handle, port, size, user_data):
|
def _hook_insn_in_cb(self, handle, port, size, user_data):
|
||||||
# call user's callback with self object
|
# call user's callback with self object
|
||||||
(cb, data) = self._callbacks[user_data]
|
(cb, data) = self._callbacks[user_data]
|
||||||
return cb(self, port, size, data)
|
return cb(self, port, size, data)
|
||||||
|
|
||||||
|
@_catch_hook_exception
|
||||||
def _hook_insn_out_cb(self, handle, port, size, value, user_data):
|
def _hook_insn_out_cb(self, handle, port, size, value, user_data):
|
||||||
# call user's callback with self object
|
# call user's callback with self object
|
||||||
(cb, data) = self._callbacks[user_data]
|
(cb, data) = self._callbacks[user_data]
|
||||||
cb(self, port, size, value, data)
|
cb(self, port, size, value, data)
|
||||||
|
|
||||||
|
@_catch_hook_exception
|
||||||
def _hook_insn_syscall_cb(self, handle, user_data):
|
def _hook_insn_syscall_cb(self, handle, user_data):
|
||||||
# call user's callback with self object
|
# call user's callback with self object
|
||||||
(cb, data) = self._callbacks[user_data]
|
(cb, data) = self._callbacks[user_data]
|
||||||
|
@ -67,6 +67,23 @@ typedef unsigned int uint32_t;
|
|||||||
typedef signed long long int64_t;
|
typedef signed long long int64_t;
|
||||||
typedef unsigned long long uint64_t;
|
typedef unsigned long long uint64_t;
|
||||||
|
|
||||||
|
typedef signed char int_fast8_t;
|
||||||
|
typedef int int_fast16_t;
|
||||||
|
typedef int int_fast32_t;
|
||||||
|
typedef long long int_fast64_t;
|
||||||
|
typedef unsigned char uint_fast8_t;
|
||||||
|
typedef unsigned int uint_fast16_t;
|
||||||
|
typedef unsigned int uint_fast32_t;
|
||||||
|
typedef unsigned long long uint_fast64_t;
|
||||||
|
|
||||||
|
#if !defined(_W64)
|
||||||
|
#if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
|
||||||
|
#define _W64 __w64
|
||||||
|
#else
|
||||||
|
#define _W64
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef _INTPTR_T_DEFINED
|
#ifndef _INTPTR_T_DEFINED
|
||||||
#define _INTPTR_T_DEFINED
|
#define _INTPTR_T_DEFINED
|
||||||
#ifdef _WIN64
|
#ifdef _WIN64
|
||||||
@ -97,7 +114,36 @@ typedef _W64 unsigned int uintptr_t;
|
|||||||
#define UINT16_MAX 0xffffui16
|
#define UINT16_MAX 0xffffui16
|
||||||
#define UINT32_MAX 0xffffffffui32
|
#define UINT32_MAX 0xffffffffui32
|
||||||
#define UINT64_MAX 0xffffffffffffffffui64
|
#define UINT64_MAX 0xffffffffffffffffui64
|
||||||
|
|
||||||
|
#define INT_FAST8_MIN INT8_MIN
|
||||||
|
#define INT_FAST16_MIN INT32_MIN
|
||||||
|
#define INT_FAST32_MIN INT32_MIN
|
||||||
|
#define INT_FAST64_MIN INT64_MIN
|
||||||
|
#define INT_FAST8_MAX INT8_MAX
|
||||||
|
#define INT_FAST16_MAX INT32_MAX
|
||||||
|
#define INT_FAST32_MAX INT32_MAX
|
||||||
|
#define INT_FAST64_MAX INT64_MAX
|
||||||
|
#define UINT_FAST8_MAX UINT8_MAX
|
||||||
|
#define UINT_FAST16_MAX UINT32_MAX
|
||||||
|
#define UINT_FAST32_MAX UINT32_MAX
|
||||||
|
#define UINT_FAST64_MAX UINT64_MAX
|
||||||
|
|
||||||
|
#ifdef _WIN64
|
||||||
|
#define INTPTR_MIN INT64_MIN
|
||||||
|
#define INTPTR_MAX INT64_MAX
|
||||||
|
#define UINTPTR_MAX UINT64_MAX
|
||||||
|
#else /* _WIN64 */
|
||||||
|
#define INTPTR_MIN INT32_MIN
|
||||||
|
#define INTPTR_MAX INT32_MAX
|
||||||
|
#define UINTPTR_MAX UINT32_MAX
|
||||||
|
#endif /* _WIN64 */
|
||||||
|
|
||||||
#else // this system has stdint.h
|
#else // this system has stdint.h
|
||||||
|
|
||||||
|
#if defined(_MSC_VER) && (_MSC_VER == MSC_VER_VS2010)
|
||||||
|
#define _INTPTR 2
|
||||||
|
#endif
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#endif // (defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2010)) ||
|
#endif // (defined(_MSC_VER) && (_MSC_VER < MSC_VER_VS2010)) ||
|
||||||
// defined(_KERNEL_MODE)
|
// defined(_KERNEL_MODE)
|
||||||
|
@ -408,7 +408,7 @@ typedef void (*uc_cb_hookmem_t)(uc_engine *uc, uc_mem_type type,
|
|||||||
@user_data: user data passed to tracing APIs
|
@user_data: user data passed to tracing APIs
|
||||||
|
|
||||||
@return: return true to continue, or false to stop program (due to invalid
|
@return: return true to continue, or false to stop program (due to invalid
|
||||||
memory). NOTE: returning true to continue execution will only work if if the
|
memory). NOTE: returning true to continue execution will only work if the
|
||||||
accessed memory is made accessible with the correct permissions during the
|
accessed memory is made accessible with the correct permissions during the
|
||||||
hook.
|
hook.
|
||||||
|
|
||||||
@ -642,7 +642,7 @@ UNICORN_EXPORT
|
|||||||
uc_err uc_ctl(uc_engine *uc, uc_control_type option, ...);
|
uc_err uc_ctl(uc_engine *uc, uc_control_type option, ...);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Report the last error number when some API function fail.
|
Report the last error number when some API function fails.
|
||||||
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.
|
||||||
|
|
||||||
@uc: handle returned by uc_open()
|
@uc: handle returned by uc_open()
|
||||||
@ -756,7 +756,7 @@ uc_err uc_mem_read(uc_engine *uc, uint64_t address, void *bytes, size_t size);
|
|||||||
|
|
||||||
@uc: handle returned by uc_open()
|
@uc: handle returned by uc_open()
|
||||||
@begin: address where emulation starts
|
@begin: address where emulation starts
|
||||||
@until: address where emulation stops (i.e when this address is hit)
|
@until: address where emulation stops (i.e. when this address is hit)
|
||||||
@timeout: duration to emulate the code (in microseconds). When this value is 0,
|
@timeout: duration to emulate the code (in microseconds). When this value is 0,
|
||||||
we will emulate the code in infinite time, until the code is finished.
|
we will emulate the code in infinite time, until the code is finished.
|
||||||
@count: the number of instructions to be emulated. When this value is 0,
|
@count: the number of instructions to be emulated. When this value is 0,
|
||||||
@ -792,12 +792,12 @@ uc_err uc_emu_stop(uc_engine *uc);
|
|||||||
@uc: handle returned by uc_open()
|
@uc: handle returned by uc_open()
|
||||||
@hh: hook handle returned from this registration. To be used in uc_hook_del()
|
@hh: hook handle returned from this registration. To be used in uc_hook_del()
|
||||||
API
|
API
|
||||||
@type: hook type
|
@type: hook type, refer to uc_hook_type enum
|
||||||
@callback: callback to be run when instruction is hit
|
@callback: callback to be run when instruction is hit
|
||||||
@user_data: user-defined data. This will be passed to callback function in its
|
@user_data: user-defined data. This will be passed to callback function in its
|
||||||
last argument @user_data
|
last argument @user_data
|
||||||
@begin: start address of the area where the callback is effect (inclusive)
|
@begin: start address of the area where the callback is in effect (inclusive)
|
||||||
@end: end address of the area where the callback is effect (inclusive)
|
@end: end address of the area where the callback is in effect (inclusive)
|
||||||
NOTE 1: the callback is called only if related address is in range [@begin,
|
NOTE 1: the callback is called only if related address is in range [@begin,
|
||||||
@end] NOTE 2: if @begin > @end, callback is called whenever this hook type is
|
@end] NOTE 2: if @begin > @end, callback is called whenever this hook type is
|
||||||
triggered
|
triggered
|
||||||
@ -818,7 +818,7 @@ uc_err uc_hook_add(uc_engine *uc, uc_hook *hh, int type, void *callback,
|
|||||||
Unregister (remove) a hook callback.
|
Unregister (remove) a hook callback.
|
||||||
This API removes the hook callback registered by uc_hook_add().
|
This API removes the hook callback registered by uc_hook_add().
|
||||||
NOTE: this should be called only when you no longer want to trace.
|
NOTE: this should be called only when you no longer want to trace.
|
||||||
After this, @hh is invalid, and nolonger usable.
|
After this, @hh is invalid, and no longer usable.
|
||||||
|
|
||||||
@uc: handle returned by uc_open()
|
@uc: handle returned by uc_open()
|
||||||
@hh: handle returned by uc_hook_add()
|
@hh: handle returned by uc_hook_add()
|
||||||
@ -846,7 +846,7 @@ typedef enum uc_prot {
|
|||||||
This address must be aligned to 4KB, or this will return with UC_ERR_ARG
|
This address must be aligned to 4KB, or this will return with UC_ERR_ARG
|
||||||
error.
|
error.
|
||||||
@size: size of the new memory region to be mapped in.
|
@size: size of the new memory region to be mapped in.
|
||||||
This size must be multiple of 4KB, or this will return with UC_ERR_ARG
|
This size must be a multiple of 4KB, or this will return with UC_ERR_ARG
|
||||||
error.
|
error.
|
||||||
@perms: Permissions for the newly mapped region.
|
@perms: Permissions for the newly mapped region.
|
||||||
This must be some combination of UC_PROT_READ | UC_PROT_WRITE |
|
This must be some combination of UC_PROT_READ | UC_PROT_WRITE |
|
||||||
@ -867,7 +867,7 @@ uc_err uc_mem_map(uc_engine *uc, uint64_t address, size_t size, uint32_t perms);
|
|||||||
This address must be aligned to 4KB, or this will return with UC_ERR_ARG
|
This address must be aligned to 4KB, or this will return with UC_ERR_ARG
|
||||||
error.
|
error.
|
||||||
@size: size of the new memory region to be mapped in.
|
@size: size of the new memory region to be mapped in.
|
||||||
This size must be multiple of 4KB, or this will return with UC_ERR_ARG
|
This size must be a multiple of 4KB, or this will return with UC_ERR_ARG
|
||||||
error.
|
error.
|
||||||
@perms: Permissions for the newly mapped region.
|
@perms: Permissions for the newly mapped region.
|
||||||
This must be some combination of UC_PROT_READ | UC_PROT_WRITE |
|
This must be some combination of UC_PROT_READ | UC_PROT_WRITE |
|
||||||
@ -917,7 +917,7 @@ uc_err uc_mmio_map(uc_engine *uc, uint64_t address, size_t size,
|
|||||||
This address must be aligned to 4KB, or this will return with UC_ERR_ARG
|
This address must be aligned to 4KB, or this will return with UC_ERR_ARG
|
||||||
error.
|
error.
|
||||||
@size: size of the memory region to be modified.
|
@size: size of the memory region to be modified.
|
||||||
This size must be multiple of 4KB, or this will return with UC_ERR_ARG
|
This size must be a multiple of 4KB, or this will return with UC_ERR_ARG
|
||||||
error.
|
error.
|
||||||
|
|
||||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||||
@ -935,7 +935,7 @@ uc_err uc_mem_unmap(uc_engine *uc, uint64_t address, size_t size);
|
|||||||
This address must be aligned to 4KB, or this will return with UC_ERR_ARG
|
This address must be aligned to 4KB, or this will return with UC_ERR_ARG
|
||||||
error.
|
error.
|
||||||
@size: size of the memory region to be modified.
|
@size: size of the memory region to be modified.
|
||||||
This size must be multiple of 4KB, or this will return with UC_ERR_ARG
|
This size must be a multiple of 4KB, or this will return with UC_ERR_ARG
|
||||||
error.
|
error.
|
||||||
@perms: New permissions for the mapped region.
|
@perms: New permissions for the mapped region.
|
||||||
This must be some combination of UC_PROT_READ | UC_PROT_WRITE |
|
This must be some combination of UC_PROT_READ | UC_PROT_WRITE |
|
||||||
@ -951,8 +951,8 @@ uc_err uc_mem_protect(uc_engine *uc, uint64_t address, size_t size,
|
|||||||
/*
|
/*
|
||||||
Retrieve all memory regions mapped by uc_mem_map() and uc_mem_map_ptr()
|
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
|
This API allocates memory for @regions, and user must free this memory later
|
||||||
by free() to avoid leaking memory.
|
by uc_free() to avoid leaking memory.
|
||||||
NOTE: memory regions may be splitted by uc_mem_unmap()
|
NOTE: memory regions may be split by uc_mem_unmap()
|
||||||
|
|
||||||
@uc: handle returned by uc_open()
|
@uc: handle returned by uc_open()
|
||||||
@regions: pointer to an array of uc_mem_region struct. This is allocated by
|
@regions: pointer to an array of uc_mem_region struct. This is allocated by
|
||||||
@ -972,9 +972,9 @@ uc_err uc_mem_regions(uc_engine *uc, uc_mem_region **regions, uint32_t *count);
|
|||||||
differing arches or modes.
|
differing arches or modes.
|
||||||
|
|
||||||
@uc: handle returned by uc_open()
|
@uc: handle returned by uc_open()
|
||||||
@context: pointer to a uc_engine*. This will be updated with the pointer to
|
@context: pointer to a uc_context*. This will be updated with the pointer to
|
||||||
the new context on successful return of this function.
|
the new context on successful return of this function.
|
||||||
Later, this allocated memory must be freed with uc_free().
|
Later, this allocated memory must be freed with uc_context_free().
|
||||||
|
|
||||||
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
@return UC_ERR_OK on success, or other value on failure (refer to uc_err enum
|
||||||
for detailed error).
|
for detailed error).
|
||||||
@ -985,7 +985,7 @@ uc_err uc_context_alloc(uc_engine *uc, uc_context **context);
|
|||||||
/*
|
/*
|
||||||
Free the memory allocated by uc_mem_regions.
|
Free the memory allocated by uc_mem_regions.
|
||||||
WARNING: After Unicorn 1.0.1rc5, the memory allocated by uc_context_alloc
|
WARNING: After Unicorn 1.0.1rc5, the memory allocated by uc_context_alloc
|
||||||
should be free-ed by uc_context_free(). Calling uc_free() may still work, but
|
should be freed by uc_context_free(). Calling uc_free() may still work, but
|
||||||
the result is **undefined**.
|
the result is **undefined**.
|
||||||
|
|
||||||
@mem: memory allocated by uc_mem_regions (returned in *regions).
|
@mem: memory allocated by uc_mem_regions (returned in *regions).
|
||||||
|
@ -468,7 +468,7 @@ static uc_err arm_query(struct uc_struct *uc, uc_query_type type,
|
|||||||
// zero out ARM/THUMB mode
|
// zero out ARM/THUMB mode
|
||||||
mode = uc->mode & ~(UC_MODE_ARM | UC_MODE_THUMB);
|
mode = uc->mode & ~(UC_MODE_ARM | UC_MODE_THUMB);
|
||||||
// THUMB mode or ARM MOde
|
// THUMB mode or ARM MOde
|
||||||
mode +=
|
mode |=
|
||||||
((ARM_CPU(mycpu)->env.thumb != 0) ? UC_MODE_THUMB : UC_MODE_ARM);
|
((ARM_CPU(mycpu)->env.thumb != 0) ? UC_MODE_THUMB : UC_MODE_ARM);
|
||||||
*result = mode;
|
*result = mode;
|
||||||
return UC_ERR_OK;
|
return UC_ERR_OK;
|
||||||
|
@ -570,7 +570,7 @@ void helper_fldz_FT0(CPUX86State *env)
|
|||||||
{
|
{
|
||||||
//FT0 = floatx80_zero;
|
//FT0 = floatx80_zero;
|
||||||
floatx80 zero = { 0x0000000000000000LL, 0x0000 };
|
floatx80 zero = { 0x0000000000000000LL, 0x0000 };
|
||||||
ST0 = zero;
|
FT0 = zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t helper_fnstsw(CPUX86State *env)
|
uint32_t helper_fnstsw(CPUX86State *env)
|
||||||
|
@ -98,6 +98,16 @@ unsigned long qemu_getauxval(unsigned long type)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
#include <sys/auxv.h>
|
||||||
|
|
||||||
|
unsigned long qemu_getauxval(unsigned long type)
|
||||||
|
{
|
||||||
|
unsigned long aux = 0;
|
||||||
|
elf_aux_info(type, &aux, sizeof(aux));
|
||||||
|
return aux;
|
||||||
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
unsigned long qemu_getauxval(unsigned long type)
|
unsigned long qemu_getauxval(unsigned long type)
|
||||||
|
39
tests/regress/hook_raises_exception.py
Normal file
39
tests/regress/hook_raises_exception.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
import regress
|
||||||
|
from unicorn import Uc, UC_ARCH_X86, UC_MODE_64, UC_HOOK_CODE
|
||||||
|
|
||||||
|
CODE = b"\x90" * 3
|
||||||
|
CODE_ADDR = 0x1000
|
||||||
|
|
||||||
|
|
||||||
|
class HookCounter(object):
|
||||||
|
"""Counts number of hook calls."""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.hook_calls = 0
|
||||||
|
|
||||||
|
def bad_code_hook(self, uc, address, size, data):
|
||||||
|
self.hook_calls += 1
|
||||||
|
raise ValueError("Something went wrong")
|
||||||
|
|
||||||
|
def good_code_hook(self, uc, address, size, data):
|
||||||
|
self.hook_calls += 1
|
||||||
|
|
||||||
|
|
||||||
|
class TestExceptionInHook(regress.RegressTest):
|
||||||
|
|
||||||
|
def test_exception_in_hook(self):
|
||||||
|
uc = Uc(UC_ARCH_X86, UC_MODE_64)
|
||||||
|
uc.mem_map(CODE_ADDR, 0x1000)
|
||||||
|
uc.mem_write(CODE_ADDR, CODE)
|
||||||
|
|
||||||
|
counter = HookCounter()
|
||||||
|
uc.hook_add(UC_HOOK_CODE, counter.good_code_hook, begin=CODE_ADDR, end=CODE_ADDR + len(CODE))
|
||||||
|
uc.hook_add(UC_HOOK_CODE, counter.bad_code_hook, begin=CODE_ADDR, end=CODE_ADDR + len(CODE))
|
||||||
|
|
||||||
|
self.assertRaises(ValueError, uc.emu_start, CODE_ADDR, CODE_ADDR + len(CODE))
|
||||||
|
# Make sure hooks calls finish before raising (hook_calls == 2)
|
||||||
|
self.assertEqual(counter.hook_calls, 2)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
regress.main()
|
3
uc.c
3
uc.c
@ -1596,7 +1596,8 @@ uc_err uc_query(uc_engine *uc, uc_query_type type, size_t *result)
|
|||||||
return uc->query(uc, type, result);
|
return uc->query(uc, type, result);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
return UC_ERR_ARG;
|
*result = uc->mode;
|
||||||
|
break;
|
||||||
|
|
||||||
case UC_QUERY_TIMEOUT:
|
case UC_QUERY_TIMEOUT:
|
||||||
*result = uc->timed_out;
|
*result = uc->timed_out;
|
||||||
|
Loading…
Reference in New Issue
Block a user