diff --git a/.gitmodules b/.gitmodules index 5284170e..4e459e71 100644 --- a/.gitmodules +++ b/.gitmodules @@ -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 diff --git a/CMakeLists.txt b/CMakeLists.txt index d1d9d8a7..dbd652ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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} ) diff --git a/bindings/python/setup.py b/bindings/python/setup.py index 9a855a27..fd2604e8 100755 --- a/bindings/python/setup.py +++ b/bindings/python/setup.py @@ -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]) diff --git a/bindings/python/unicorn/unicorn.py b/bindings/python/unicorn/unicorn.py index c929c23c..dcbd2cf3 100644 --- a/bindings/python/unicorn/unicorn.py +++ b/bindings/python/unicorn/unicorn.py @@ -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) diff --git a/bindings/rust/src/ffi.rs b/bindings/rust/src/ffi.rs index e2b7c078..47240b43 100644 --- a/bindings/rust/src/ffi.rs +++ b/bindings/rust/src/ffi.rs @@ -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 ( +pub extern "C" fn mmio_read_callback_proxy( uc: uc_handle, offset: u64, size: usize, user_data: *mut UcHook, -) -> u64 where +) -> u64 +where F: FnMut(&mut crate::Unicorn, u64, usize) -> u64, { let user_data = unsafe { &mut *user_data }; @@ -109,7 +110,7 @@ pub extern "C" fn mmio_read_callback_proxy ( (user_data.callback)(&mut user_data.uc, offset, size) } -pub extern "C" fn mmio_write_callback_proxy ( +pub extern "C" fn mmio_write_callback_proxy( uc: uc_handle, offset: u64, size: usize, diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 9ec402e0..203b6e0d 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -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)| { - 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 { + 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 { // 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(); } } @@ -318,7 +321,7 @@ impl<'a, D> Unicorn<'a, D> { /// `size` must be a multiple of 4kb or this will return `Error::ARG`. pub fn mmio_map( &mut self, - address: u64, + address: u64, size: libc::size_t, read_callback: Option, write_callback: Option, @@ -327,7 +330,7 @@ impl<'a, D> Unicorn<'a, D> { R: FnMut(&mut Unicorn, u64, usize) -> u64, W: FnMut(&mut Unicorn, 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 ); - let wd = write_data.map( |c| c as Box ); - self.inner_mut().mmio_callbacks.push(MmioCallbackScope{ + let rd = read_data.map(|c| c as Box); + let wd = write_data.map(|c| c as Box); + 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, u64, usize) -> u64, { - self.mmio_map(address, size, Some(callback), None::, u64, usize, u64)>) + self.mmio_map( + address, + size, + Some(callback), + None::, 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, u64, usize, u64), { - self.mmio_map(address, size, None::, u64, usize) -> u64>, Some(callback)) + self.mmio_map( + address, + size, + None::, 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(()) diff --git a/bindings/rust/tests/unicorn.rs b/bindings/rust/tests/unicorn.rs index 79f659aa..dba25c49 100644 --- a/bindings/rust/tests/unicorn.rs +++ b/bindings/rust/tests/unicorn.rs @@ -427,7 +427,10 @@ fn x86_mmio() { { // MOV eax, [0x2004]; MOV [0x2008], ax; - let x86_code: Vec = vec![0x8B, 0x04, 0x25, 0x04, 0x20, 0x00, 0x00, 0x66, 0x89, 0x04, 0x25, 0x08, 0x20, 0x00, 0x00]; + let x86_code: Vec = 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 = vec![0x66, 0xB8, 0x2A, 0x00, 0x66, 0x89, 0x04, 0x25, 0x08, 0x20, 0x00, 0x00]; + let x86_code: Vec = 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); diff --git a/docs/Unicorn_Engine_Documentation b/docs/Unicorn_Engine_Documentation index e1111e1b..db5434ad 160000 --- a/docs/Unicorn_Engine_Documentation +++ b/docs/Unicorn_Engine_Documentation @@ -1 +1 @@ -Subproject commit e1111e1b8b253bf7292ad911f43c125808a95f1e +Subproject commit db5434ad4e40c6657766aa6a54eafd92af38192e diff --git a/include/uc_priv.h b/include/uc_priv.h index 9b91e66f..65fb2c62 100644 --- a/include/uc_priv.h +++ b/include/uc_priv.h @@ -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: */ diff --git a/qemu/accel/tcg/cpu-exec.c b/qemu/accel/tcg/cpu-exec.c index cb70582c..6c228f94 100644 --- a/qemu/accel/tcg/cpu-exec.c +++ b/qemu/accel/tcg/cpu-exec.c @@ -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; diff --git a/qemu/accel/tcg/translate-all.c b/qemu/accel/tcg/translate-all.c index e48670eb..918a7979 100644 --- a/qemu/accel/tcg/translate-all.c +++ b/qemu/accel/tcg/translate-all.c @@ -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 */ diff --git a/qemu/include/qemu/osdep.h b/qemu/include/qemu/osdep.h index c0ff0aa5..cf0c94bb 100644 --- a/qemu/include/qemu/osdep.h +++ b/qemu/include/qemu/osdep.h @@ -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 - #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 diff --git a/qemu/softmmu/memory.c b/qemu/softmmu/memory.c index c62e272f..3fe3467b 100644 --- a/qemu/softmmu/memory.c +++ b/qemu/softmmu/memory.c @@ -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); } } diff --git a/qemu/target/arm/translate.c b/qemu/target/arm/translate.c index 9de036cd..426995e4 100644 --- a/qemu/target/arm/translate.c +++ b/qemu/target/arm/translate.c @@ -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); diff --git a/tests/unit/test_arm.c b/tests/unit/test_arm.c index 072d130f..b9dbfc52 100644 --- a/tests/unit/test_arm.c +++ b/tests/unit/test_arm.c @@ -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}}; \ No newline at end of file diff --git a/uc.c b/uc.c index d4552585..a6a88199 100644 --- a/uc.c +++ b/uc.c @@ -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 \ No newline at end of file