Merge branch 'dev' into systemz

This commit is contained in:
mio 2022-01-18 21:10:55 +01:00
commit 7095605607
No known key found for this signature in database
GPG Key ID: DFF27E34A47CB873
16 changed files with 304 additions and 56 deletions

2
.gitmodules vendored
View File

@ -1,3 +1,3 @@
[submodule "docs/Unicorn_Engine_Documentation"]
path = docs/Unicorn_Engine_Documentation
url = git@github.com:kabeor/Unicorn-Engine-Documentation
url = https://github.com/kabeor/Unicorn-Engine-Documentation

View File

@ -20,6 +20,8 @@ if (NOT UNICORN_ARCH)
set(UNICORN_ARCH "x86 arm aarch64 riscv mips sparc m68k ppc s390x")
endif()
option(UNICORN_TRACER "Trace unicorn execution" OFF)
string(TOUPPER ${UNICORN_ARCH} UNICORN_ARCH)
string(REPLACE " " ";" UNICORN_ARCH_LIST ${UNICORN_ARCH})
@ -210,6 +212,9 @@ else()
if (UNICORN_FUZZ)
set (EXTRA_CFLAGS "${EXTRA_CFLAGS} ${CMAKE_C_FLAGS}")
endif()
if(UNICORN_TRACER)
set (EXTRA_CFLAGS "${EXTRA_CFLAGS} -DUNICORN_TRACER")
endif()
set(TARGET_LIST "--target-list=")
if (UNICORN_HAS_X86)
@ -426,6 +431,11 @@ else()
# Log and pow
target_link_libraries(x86_64-softmmu m)
endif()
if(UNICORN_TRACER)
target_compile_options(x86_64-softmmu PRIVATE -DUNICORN_TRACER)
endif()
endif()
if (UNICORN_HAS_ARM)
@ -464,6 +474,10 @@ else()
)
endif()
if(UNICORN_TRACER)
target_compile_options(arm-softmmu PRIVATE -DUNICORN_TRACER)
endif()
add_library(armeb-softmmu
${UNICORN_ARCH_COMMON}
@ -498,6 +512,11 @@ else()
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/arm
)
endif()
if(UNICORN_TRACER)
target_compile_options(armeb-softmmu PRIVATE -DUNICORN_TRACER)
endif()
endif()
if (UNICORN_HAS_AARCH64)
@ -542,6 +561,10 @@ else()
)
endif()
if(UNICORN_TRACER)
target_compile_options(aarch64-softmmu PRIVATE -DUNICORN_TRACER)
endif()
add_library(aarch64eb-softmmu
${UNICORN_ARCH_COMMON}
@ -582,6 +605,11 @@ else()
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/arm
)
endif()
if(UNICORN_TRACER)
target_compile_options(aarch64eb-softmmu PRIVATE -DUNICORN_TRACER)
endif()
endif()
if (UNICORN_HAS_M68K)
@ -612,6 +640,11 @@ else()
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/m68k
)
endif()
if(UNICORN_TRACER)
target_compile_options(m68k-softmmu PRIVATE -DUNICORN_TRACER)
endif()
endif()
if (UNICORN_HAS_MIPS)
@ -647,6 +680,10 @@ else()
)
endif()
if(UNICORN_TRACER)
target_compile_options(mips-softmmu PRIVATE -DUNICORN_TRACER)
endif()
add_library(mipsel-softmmu
${UNICORN_ARCH_COMMON}
@ -679,6 +716,10 @@ else()
)
endif()
if(UNICORN_TRACER)
target_compile_options(mipsel-softmmu PRIVATE -DUNICORN_TRACER)
endif()
add_library(mips64-softmmu
${UNICORN_ARCH_COMMON}
@ -711,6 +752,10 @@ else()
)
endif()
if(UNICORN_TRACER)
target_compile_options(mips64-softmmu PRIVATE -DUNICORN_TRACER)
endif()
add_library(mips64el-softmmu
${UNICORN_ARCH_COMMON}
@ -742,6 +787,11 @@ else()
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/mips
)
endif()
if(UNICORN_TRACER)
target_compile_options(mips64el-softmmu PRIVATE -DUNICORN_TRACER)
endif()
endif()
if (UNICORN_HAS_SPARC)
@ -776,6 +826,10 @@ else()
)
endif()
if(UNICORN_TRACER)
target_compile_options(sparc-softmmu PRIVATE -DUNICORN_TRACER)
endif()
add_library(sparc64-softmmu
${UNICORN_ARCH_COMMON}
@ -807,6 +861,11 @@ else()
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/sparc
)
endif()
if(UNICORN_TRACER)
target_compile_options(sparc64-softmmu PRIVATE -DUNICORN_TRACER)
endif()
endif()
if (UNICORN_HAS_PPC)
@ -854,6 +913,10 @@ else()
)
endif()
if(UNICORN_TRACER)
target_compile_options(ppc-softmmu PRIVATE -DUNICORN_TRACER)
endif()
add_library(ppc64-softmmu
${UNICORN_ARCH_COMMON}
@ -901,6 +964,11 @@ else()
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/ppc
)
endif()
if(UNICORN_TRACER)
target_compile_options(ppc64-softmmu PRIVATE -DUNICORN_TRACER)
endif()
endif()
if (UNICORN_HAS_RISCV)
@ -933,6 +1001,10 @@ else()
)
endif()
if(UNICORN_TRACER)
target_compile_options(riscv32-softmmu PRIVATE -DUNICORN_TRACER)
endif()
add_library(riscv64-softmmu
${UNICORN_ARCH_COMMON}
@ -961,6 +1033,11 @@ else()
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/riscv
)
endif()
if(UNICORN_TRACER)
target_compile_options(riscv64-softmmu PRIVATE -DUNICORN_TRACER)
endif()
endif()
if (UNICORN_HAS_S390X)
@ -1179,6 +1256,15 @@ set(UNICORN_TEST_FILE ${UNICORN_TEST_FILE} test_mem)
set(UNICORN_TEST_FILE ${UNICORN_TEST_FILE} test_ctl)
set(UNICORN_SAMPLE_FILE ${UNICORN_SAMPLE_FILE} sample_ctl)
if(UNICORN_TRACER)
target_compile_options(unicorn-common PRIVATE -DUNICORN_TRACER)
target_compile_options(unicorn PRIVATE -DUNICORN_TRACER)
endif()
target_compile_options(unicorn-common PRIVATE
${UNICORN_COMPILE_OPTIONS}
)
target_compile_options(unicorn PRIVATE
${UNICORN_COMPILE_OPTIONS}
)

View File

@ -27,7 +27,7 @@ LIBS_DIR = os.path.join(ROOT_DIR, 'unicorn', 'lib')
HEADERS_DIR = os.path.join(ROOT_DIR, 'unicorn', 'include')
SRC_DIR = os.path.join(ROOT_DIR, 'src')
UC_DIR = os.path.join(ROOT_DIR, '../..')
BUILD_DIR = os.path.join(UC_DIR, 'build')
BUILD_DIR = os.path.join(UC_DIR, 'build_python')
VERSION = "2.0.0rc5.post1"
@ -131,7 +131,10 @@ def build_libraries():
os.mkdir(BUILD_DIR)
conf = 'Debug' if os.getenv('DEBUG', '') else 'Release'
subprocess.check_call(["cmake", '-B', BUILD_DIR, "-DCMAKE_BUILD_TYPE=" + conf])
cmake_args = ["cmake", '-B', BUILD_DIR, "-DCMAKE_BUILD_TYPE=" + conf]
if os.getenv("TRACE", ""):
cmake_args += ["-DUNICORN_TRACER=on"]
subprocess.check_call(cmake_args)
os.chdir(BUILD_DIR)
threads = os.getenv("THREADS", "4")
subprocess.check_call(["cmake", "--build", ".", "-j" + threads])

View File

@ -460,6 +460,7 @@ class Uc(object):
# emulate from @begin, and stop when reaching address @until
def emu_start(self, begin, until, timeout=0, count=0):
self._hook_exception = None
status = _uc.uc_emu_start(self._uch, begin, until, timeout, count)
if status != uc.UC_ERR_OK:
raise UcError(status)

View File

@ -96,12 +96,13 @@ pub trait IsUcHook<'a> {}
impl<'a, D, F> IsUcHook<'a> for UcHook<'a, D, F> {}
pub extern "C" fn mmio_read_callback_proxy<D, F> (
pub extern "C" fn mmio_read_callback_proxy<D, F>(
uc: uc_handle,
offset: u64,
size: usize,
user_data: *mut UcHook<D, F>,
) -> u64 where
) -> u64
where
F: FnMut(&mut crate::Unicorn<D>, u64, usize) -> u64,
{
let user_data = unsafe { &mut *user_data };
@ -109,7 +110,7 @@ pub extern "C" fn mmio_read_callback_proxy<D, F> (
(user_data.callback)(&mut user_data.uc, offset, size)
}
pub extern "C" fn mmio_write_callback_proxy<D, F> (
pub extern "C" fn mmio_write_callback_proxy<D, F>(
uc: uc_handle,
offset: u64,
size: usize,

View File

@ -84,29 +84,32 @@ pub struct MmioCallbackScope<'a> {
impl<'a> MmioCallbackScope<'a> {
fn has_regions(&self) -> bool {
self.regions.len() > 0
!self.regions.is_empty()
}
fn unmap(&mut self, begin: u64, size: usize) {
let end: u64 = begin + size as u64;
self.regions = self.regions.iter().flat_map( |(b, s)| {
self.regions = self
.regions
.iter()
.flat_map(|(b, s)| {
let e: u64 = b + *s as u64;
if begin > *b {
if begin >= e {
// The unmapped region is completely after this region
vec![(*b, *s)]
} else {
if end >= e {
} else if end >= e {
// The unmapped region overlaps with the end of this region
vec![(*b, (begin - *b) as usize)]
} else {
// The unmapped region is in the middle of this region
let second_b = end + 1;
vec![(*b, (begin - *b) as usize), (second_b, (e - second_b) as usize)]
vec![
(*b, (begin - *b) as usize),
(second_b, (e - second_b) as usize),
]
}
}
} else {
if end > *b {
} else if end > *b {
if end >= e {
// The unmapped region completely contains this region
vec![]
@ -118,8 +121,8 @@ impl<'a> MmioCallbackScope<'a> {
// The unmapped region is completely before this region
vec![(*b, *s)]
}
}
}).collect();
})
.collect();
}
}
@ -327,7 +330,7 @@ impl<'a, D> Unicorn<'a, D> {
R: FnMut(&mut Unicorn<D>, u64, usize) -> u64,
W: FnMut(&mut Unicorn<D>, u64, usize, u64),
{
let mut read_data = read_callback.map( |c| {
let mut read_data = read_callback.map(|c| {
Box::new(ffi::UcHook {
callback: c,
uc: Unicorn {
@ -335,7 +338,7 @@ impl<'a, D> Unicorn<'a, D> {
},
})
});
let mut write_data = write_callback.map( |c| {
let mut write_data = write_callback.map(|c| {
Box::new(ffi::UcHook {
callback: c,
uc: Unicorn {
@ -363,9 +366,9 @@ impl<'a, D> Unicorn<'a, D> {
};
if err == uc_error::OK {
let rd = read_data.map( |c| c as Box<dyn ffi::IsUcHook> );
let wd = write_data.map( |c| c as Box<dyn ffi::IsUcHook> );
self.inner_mut().mmio_callbacks.push(MmioCallbackScope{
let rd = read_data.map(|c| c as Box<dyn ffi::IsUcHook>);
let wd = write_data.map(|c| c as Box<dyn ffi::IsUcHook>);
self.inner_mut().mmio_callbacks.push(MmioCallbackScope {
regions: vec![(address, size)],
read_callback: rd,
write_callback: wd,
@ -390,7 +393,12 @@ impl<'a, D> Unicorn<'a, D> {
where
F: FnMut(&mut Unicorn<D>, u64, usize) -> u64,
{
self.mmio_map(address, size, Some(callback), None::<fn(&mut Unicorn<D>, u64, usize, u64)>)
self.mmio_map(
address,
size,
Some(callback),
None::<fn(&mut Unicorn<D>, u64, usize, u64)>,
)
}
/// Map in a write-only MMIO region backed by a callback.
@ -406,7 +414,12 @@ impl<'a, D> Unicorn<'a, D> {
where
F: FnMut(&mut Unicorn<D>, u64, usize, u64),
{
self.mmio_map(address, size, None::<fn(&mut Unicorn<D>, u64, usize) -> u64>, Some(callback))
self.mmio_map(
address,
size,
None::<fn(&mut Unicorn<D>, u64, usize) -> u64>,
Some(callback),
)
}
/// Unmap a memory region.
@ -429,7 +442,9 @@ impl<'a, D> Unicorn<'a, D> {
for scope in self.inner_mut().mmio_callbacks.iter_mut() {
scope.unmap(address, size);
}
self.inner_mut().mmio_callbacks.retain( |scope| scope.has_regions() );
self.inner_mut()
.mmio_callbacks
.retain(|scope| scope.has_regions());
}
/// Set the memory permissions for an existing memory region.
@ -817,11 +832,12 @@ impl<'a, D> Unicorn<'a, D> {
let err: uc_error;
// drop the hook
self.inner_mut()
let inner = self.inner_mut();
inner
.hooks
.retain(|(hook_ptr, _hook_impl)| hook_ptr != &hook);
err = unsafe { ffi::uc_hook_del(self.inner().uc, hook) };
err = unsafe { ffi::uc_hook_del(inner.uc, hook) };
if err == uc_error::OK {
Ok(())

View File

@ -427,7 +427,10 @@ fn x86_mmio() {
{
// MOV eax, [0x2004]; MOV [0x2008], ax;
let x86_code: Vec<u8> = vec![0x8B, 0x04, 0x25, 0x04, 0x20, 0x00, 0x00, 0x66, 0x89, 0x04, 0x25, 0x08, 0x20, 0x00, 0x00];
let x86_code: Vec<u8> = vec![
0x8B, 0x04, 0x25, 0x04, 0x20, 0x00, 0x00, 0x66, 0x89, 0x04, 0x25, 0x08, 0x20, 0x00,
0x00,
];
let read_cell = Rc::new(RefCell::new(MmioReadExpectation(0, 0)));
let cb_read_cell = read_cell.clone();
@ -436,7 +439,7 @@ fn x86_mmio() {
42
};
let write_cell = Rc::new(RefCell::new(MmioWriteExpectation(0,0,0)));
let write_cell = Rc::new(RefCell::new(MmioWriteExpectation(0, 0, 0)));
let cb_write_cell = write_cell.clone();
let write_callback = move |_: &mut Unicorn<'_, ()>, offset, size, value| {
*cb_write_cell.borrow_mut() = MmioWriteExpectation(offset, size, value);
@ -444,7 +447,10 @@ fn x86_mmio() {
assert_eq!(emu.mem_write(0x1000, &x86_code), Ok(()));
assert_eq!(emu.mmio_map(0x2000, 0x1000, Some(read_callback), Some(write_callback)), Ok(()));
assert_eq!(
emu.mmio_map(0x2000, 0x1000, Some(read_callback), Some(write_callback)),
Ok(())
);
assert_eq!(
emu.emu_start(
@ -494,9 +500,11 @@ fn x86_mmio() {
{
// MOV ax, 42; MOV [0x2008], ax;
let x86_code: Vec<u8> = vec![0x66, 0xB8, 0x2A, 0x00, 0x66, 0x89, 0x04, 0x25, 0x08, 0x20, 0x00, 0x00];
let x86_code: Vec<u8> = vec![
0x66, 0xB8, 0x2A, 0x00, 0x66, 0x89, 0x04, 0x25, 0x08, 0x20, 0x00, 0x00,
];
let write_cell = Rc::new(RefCell::new(MmioWriteExpectation(0,0,0)));
let write_cell = Rc::new(RefCell::new(MmioWriteExpectation(0, 0, 0)));
let cb_write_cell = write_cell.clone();
let write_callback = move |_: &mut Unicorn<'_, ()>, offset, size, value| {
*cb_write_cell.borrow_mut() = MmioWriteExpectation(offset, size, value);

@ -1 +1 @@
Subproject commit e1111e1b8b253bf7292ad911f43c125808a95f1e
Subproject commit db5434ad4e40c6657766aa6a54eafd92af38192e

View File

@ -369,6 +369,8 @@ struct uc_struct {
int nested_level; // Current nested_level
struct TranslationBlock *last_tb; // The real last tb we executed.
FlatView *empty_view; // Static function variable moved from flatviews_init
};
// Metadata stub for the variable-size cpu context used with uc_context_*()
@ -397,5 +399,31 @@ static inline int uc_addr_is_exit(uc_engine *uc, uint64_t addr)
return g_tree_lookup(uc->exits, (gpointer)(&addr)) == (gpointer)1;
}
#ifdef UNICORN_TRACER
#define UC_TRACE_START(loc) trace_start(get_tracer(), loc)
#define UC_TRACE_END(loc, fmt, ...) \
trace_end(get_tracer(), loc, fmt, __VA_ARGS__)
typedef enum trace_loc {
UC_TRACE_TB_EXEC = 0,
UC_TRACE_TB_TRANS,
UC_TRACER_MAX
} trace_loc;
typedef struct uc_tracer {
int64_t starts[UC_TRACER_MAX];
} uc_tracer;
uc_tracer *get_tracer();
void trace_start(uc_tracer *tracer, trace_loc loc);
void trace_end(uc_tracer *tracer, trace_loc loc, const char *fmt, ...);
#else
#define UC_TRACE_START(loc)
#define UC_TRACE_END(loc, fmt, ...)
#endif
#endif
/* vim: set ts=4 noet: */

View File

@ -55,9 +55,12 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
int tb_exit;
uint8_t *tb_ptr = itb->tc.ptr;
UC_TRACE_START(UC_TRACE_TB_EXEC);
tb_exec_lock(cpu->uc->tcg_ctx);
ret = tcg_qemu_tb_exec(env, tb_ptr);
tb_exec_unlock(cpu->uc->tcg_ctx);
UC_TRACE_END(UC_TRACE_TB_EXEC, "[uc] exec tb 0x%" PRIx64 ": ", itb->pc);
cpu->can_do_io = 1;
last_tb = (TranslationBlock *)(ret & ~TB_EXIT_MASK);
tb_exit = ret & TB_EXIT_MASK;

View File

@ -1619,7 +1619,9 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
tcg_func_start(tcg_ctx);
tcg_ctx->cpu = env_cpu(env);
UC_TRACE_START(UC_TRACE_TB_TRANS);
gen_intermediate_code(cpu, tb, max_insns);
UC_TRACE_END(UC_TRACE_TB_TRANS, "[uc] translate tb 0x%" PRIx64 ": ", tb->pc);
tcg_ctx->cpu = NULL;
/* generate machine code */

View File

@ -119,18 +119,13 @@ struct uc_struct;
* Only allow MAP_JIT for Mojave or later.
*
* Source: https://github.com/moby/hyperkit/pull/259/files#diff-e6b5417230ff2daff9155d9b15aefae12e89410ec2dca1f59d04be511f6737fcR41
*
* But using MAP_JIT causes performance regression for fork() so we only use MAP_JIT on Apple M1.
*
* Issue: https://github.com/desktop/desktop/issues/12978
*/
#if defined(__APPLE__)
#if defined(HAVE_PTHREAD_JIT_PROTECT)
#define USE_MAP_JIT
#else
#include <Availability.h>
#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 101400 && defined(MAP_JIT)
#define USE_MAP_JIT
#endif
#endif
#endif
#if defined(__APPLE__) && defined(HAVE_PTHREAD_JIT_PROTECT) && defined(__arm__)
#define USE_MAP_JIT
#endif
#include <glib_compat.h>

View File

@ -783,8 +783,6 @@ static void address_space_update_topology_pass(AddressSpace *as,
static void flatviews_init(struct uc_struct *uc)
{
static FlatView *empty_view;
if (uc->flat_views) {
return;
}
@ -792,13 +790,13 @@ static void flatviews_init(struct uc_struct *uc)
uc->flat_views = g_hash_table_new_full(NULL, NULL, NULL,
(GDestroyNotify) flatview_unref);
if (!empty_view) {
empty_view = generate_memory_topology(uc, NULL);
if (!uc->empty_view) {
uc->empty_view = generate_memory_topology(uc, NULL);
/* We keep it alive forever in the global variable. */
flatview_ref(empty_view);
flatview_ref(uc->empty_view);
} else {
g_hash_table_replace(uc->flat_views, NULL, empty_view);
flatview_ref(empty_view);
g_hash_table_replace(uc->flat_views, NULL, uc->empty_view);
flatview_ref(uc->empty_view);
}
}

View File

@ -11432,6 +11432,21 @@ static void arm_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
dc->pc_curr = dc->base.pc_next;
insn = arm_ldl_code(env, dc->base.pc_next, dc->sctlr_b);
dc->insn = insn;
// Unicorn:
//
// If we get an error during fetching code, we have to skip the instruction decoding
// to ensure the PC remains unchanged.
//
// This is to keep the same behavior with Unicorn1, though, it's inconsistent with
// official arm documents.
//
// See discussion here: https://github.com/unicorn-engine/unicorn/issues/1536
if (dc->uc->invalid_error) {
dcbase->is_jmp = DISAS_WFI;
return;
}
dc->base.pc_next += 4;
disas_arm_insn(dc, insn);

View File

@ -529,6 +529,69 @@ static void test_arm_hflags_rebuilt()
OK(uc_close(uc));
}
static bool test_arm_mem_access_abort_hook_mem(uc_engine *uc, uc_mem_type type,
uint64_t addr, int size,
int64_t val, void *data)
{
OK(uc_reg_read(uc, UC_ARM_REG_PC, data));
return false;
}
static bool test_arm_mem_access_abort_hook_insn_invalid(uc_engine *uc,
void *data)
{
OK(uc_reg_read(uc, UC_ARM_REG_PC, data));
return false;
}
static void test_arm_mem_access_abort()
{
// LDR r0, [r0]
// Undefined instruction
char code[] = "\x00\x00\x90\xe5\x00\xa0\xf0\xf7";
uc_engine *uc;
uint32_t r_pc, r_r0, r_pc_in_hook;
uc_hook hk, hkk;
uc_common_setup(&uc, UC_ARCH_ARM, UC_MODE_ARM, code, sizeof(code) - 1,
UC_CPU_ARM_CORTEX_A9);
r_r0 = 0x990000;
OK(uc_reg_write(uc, UC_ARM_REG_R0, &r_r0));
OK(uc_hook_add(uc, &hk,
UC_HOOK_MEM_READ_UNMAPPED | UC_HOOK_MEM_WRITE_UNMAPPED |
UC_HOOK_MEM_FETCH_UNMAPPED,
test_arm_mem_access_abort_hook_mem, (void *)&r_pc_in_hook, 1,
0));
OK(uc_hook_add(uc, &hkk, UC_HOOK_INSN_INVALID,
test_arm_mem_access_abort_hook_insn_invalid,
(void *)&r_pc_in_hook, 1, 0));
uc_assert_err(UC_ERR_READ_UNMAPPED,
uc_emu_start(uc, code_start, code_start + 4, 0, 0));
OK(uc_reg_read(uc, UC_ARM_REG_PC, &r_pc));
TEST_CHECK(r_pc == r_pc_in_hook);
uc_assert_err(UC_ERR_INSN_INVALID,
uc_emu_start(uc, code_start + 4, code_start + 8, 0, 0));
OK(uc_reg_read(uc, UC_ARM_REG_PC, &r_pc));
TEST_CHECK(r_pc == r_pc_in_hook);
uc_assert_err(UC_ERR_FETCH_UNMAPPED,
uc_emu_start(uc, 0x900000, 0x900000 + 8, 0, 0));
OK(uc_reg_read(uc, UC_ARM_REG_PC, &r_pc));
TEST_CHECK(r_pc == r_pc_in_hook);
OK(uc_close(uc));
}
TEST_LIST = {{"test_arm_nop", test_arm_nop},
{"test_arm_thumb_sub", test_arm_thumb_sub},
{"test_armeb_sub", test_armeb_sub},
@ -545,4 +608,5 @@ TEST_LIST = {{"test_arm_nop", test_arm_nop},
test_arm_not_allow_privilege_escalation},
{"test_arm_mrc", test_arm_mrc},
{"test_arm_hflags_rebuilt", test_arm_hflags_rebuilt},
{"test_arm_mem_access_abort", test_arm_mem_access_abort},
{NULL, NULL}};

28
uc.c
View File

@ -2221,3 +2221,31 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...)
return err;
}
#ifdef UNICORN_TRACER
uc_tracer *get_tracer()
{
static uc_tracer tracer;
return &tracer;
}
void trace_start(uc_tracer *tracer, trace_loc loc)
{
tracer->starts[loc] = get_clock();
}
void trace_end(uc_tracer *tracer, trace_loc loc, const char *fmt, ...)
{
va_list args;
int64_t end = get_clock();
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
fprintf(stderr, "%.6fus\n",
(double)(end - tracer->starts[loc]) / (double)(1000));
}
#endif