Merge branch 'dev' into systemz
This commit is contained in:
commit
7095605607
2
.gitmodules
vendored
2
.gitmodules
vendored
@ -1,3 +1,3 @@
|
|||||||
[submodule "docs/Unicorn_Engine_Documentation"]
|
[submodule "docs/Unicorn_Engine_Documentation"]
|
||||||
path = 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
|
||||||
|
@ -20,6 +20,8 @@ if (NOT UNICORN_ARCH)
|
|||||||
set(UNICORN_ARCH "x86 arm aarch64 riscv mips sparc m68k ppc s390x")
|
set(UNICORN_ARCH "x86 arm aarch64 riscv mips sparc m68k ppc s390x")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
option(UNICORN_TRACER "Trace unicorn execution" OFF)
|
||||||
|
|
||||||
string(TOUPPER ${UNICORN_ARCH} UNICORN_ARCH)
|
string(TOUPPER ${UNICORN_ARCH} UNICORN_ARCH)
|
||||||
string(REPLACE " " ";" UNICORN_ARCH_LIST ${UNICORN_ARCH})
|
string(REPLACE " " ";" UNICORN_ARCH_LIST ${UNICORN_ARCH})
|
||||||
|
|
||||||
@ -210,6 +212,9 @@ else()
|
|||||||
if (UNICORN_FUZZ)
|
if (UNICORN_FUZZ)
|
||||||
set (EXTRA_CFLAGS "${EXTRA_CFLAGS} ${CMAKE_C_FLAGS}")
|
set (EXTRA_CFLAGS "${EXTRA_CFLAGS} ${CMAKE_C_FLAGS}")
|
||||||
endif()
|
endif()
|
||||||
|
if(UNICORN_TRACER)
|
||||||
|
set (EXTRA_CFLAGS "${EXTRA_CFLAGS} -DUNICORN_TRACER")
|
||||||
|
endif()
|
||||||
|
|
||||||
set(TARGET_LIST "--target-list=")
|
set(TARGET_LIST "--target-list=")
|
||||||
if (UNICORN_HAS_X86)
|
if (UNICORN_HAS_X86)
|
||||||
@ -426,6 +431,11 @@ else()
|
|||||||
# Log and pow
|
# Log and pow
|
||||||
target_link_libraries(x86_64-softmmu m)
|
target_link_libraries(x86_64-softmmu m)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNICORN_TRACER)
|
||||||
|
target_compile_options(x86_64-softmmu PRIVATE -DUNICORN_TRACER)
|
||||||
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (UNICORN_HAS_ARM)
|
if (UNICORN_HAS_ARM)
|
||||||
@ -464,6 +474,10 @@ else()
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNICORN_TRACER)
|
||||||
|
target_compile_options(arm-softmmu PRIVATE -DUNICORN_TRACER)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(armeb-softmmu
|
add_library(armeb-softmmu
|
||||||
${UNICORN_ARCH_COMMON}
|
${UNICORN_ARCH_COMMON}
|
||||||
|
|
||||||
@ -498,6 +512,11 @@ else()
|
|||||||
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/arm
|
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/arm
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNICORN_TRACER)
|
||||||
|
target_compile_options(armeb-softmmu PRIVATE -DUNICORN_TRACER)
|
||||||
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (UNICORN_HAS_AARCH64)
|
if (UNICORN_HAS_AARCH64)
|
||||||
@ -542,6 +561,10 @@ else()
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNICORN_TRACER)
|
||||||
|
target_compile_options(aarch64-softmmu PRIVATE -DUNICORN_TRACER)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(aarch64eb-softmmu
|
add_library(aarch64eb-softmmu
|
||||||
${UNICORN_ARCH_COMMON}
|
${UNICORN_ARCH_COMMON}
|
||||||
|
|
||||||
@ -582,6 +605,11 @@ else()
|
|||||||
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/arm
|
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/arm
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNICORN_TRACER)
|
||||||
|
target_compile_options(aarch64eb-softmmu PRIVATE -DUNICORN_TRACER)
|
||||||
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (UNICORN_HAS_M68K)
|
if (UNICORN_HAS_M68K)
|
||||||
@ -612,6 +640,11 @@ else()
|
|||||||
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/m68k
|
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/m68k
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNICORN_TRACER)
|
||||||
|
target_compile_options(m68k-softmmu PRIVATE -DUNICORN_TRACER)
|
||||||
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (UNICORN_HAS_MIPS)
|
if (UNICORN_HAS_MIPS)
|
||||||
@ -647,6 +680,10 @@ else()
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNICORN_TRACER)
|
||||||
|
target_compile_options(mips-softmmu PRIVATE -DUNICORN_TRACER)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(mipsel-softmmu
|
add_library(mipsel-softmmu
|
||||||
${UNICORN_ARCH_COMMON}
|
${UNICORN_ARCH_COMMON}
|
||||||
|
|
||||||
@ -679,6 +716,10 @@ else()
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNICORN_TRACER)
|
||||||
|
target_compile_options(mipsel-softmmu PRIVATE -DUNICORN_TRACER)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(mips64-softmmu
|
add_library(mips64-softmmu
|
||||||
${UNICORN_ARCH_COMMON}
|
${UNICORN_ARCH_COMMON}
|
||||||
|
|
||||||
@ -711,6 +752,10 @@ else()
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNICORN_TRACER)
|
||||||
|
target_compile_options(mips64-softmmu PRIVATE -DUNICORN_TRACER)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(mips64el-softmmu
|
add_library(mips64el-softmmu
|
||||||
${UNICORN_ARCH_COMMON}
|
${UNICORN_ARCH_COMMON}
|
||||||
|
|
||||||
@ -742,6 +787,11 @@ else()
|
|||||||
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/mips
|
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/mips
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNICORN_TRACER)
|
||||||
|
target_compile_options(mips64el-softmmu PRIVATE -DUNICORN_TRACER)
|
||||||
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (UNICORN_HAS_SPARC)
|
if (UNICORN_HAS_SPARC)
|
||||||
@ -776,6 +826,10 @@ else()
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNICORN_TRACER)
|
||||||
|
target_compile_options(sparc-softmmu PRIVATE -DUNICORN_TRACER)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(sparc64-softmmu
|
add_library(sparc64-softmmu
|
||||||
${UNICORN_ARCH_COMMON}
|
${UNICORN_ARCH_COMMON}
|
||||||
|
|
||||||
@ -807,6 +861,11 @@ else()
|
|||||||
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/sparc
|
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/sparc
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNICORN_TRACER)
|
||||||
|
target_compile_options(sparc64-softmmu PRIVATE -DUNICORN_TRACER)
|
||||||
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (UNICORN_HAS_PPC)
|
if (UNICORN_HAS_PPC)
|
||||||
@ -854,6 +913,10 @@ else()
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNICORN_TRACER)
|
||||||
|
target_compile_options(ppc-softmmu PRIVATE -DUNICORN_TRACER)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(ppc64-softmmu
|
add_library(ppc64-softmmu
|
||||||
${UNICORN_ARCH_COMMON}
|
${UNICORN_ARCH_COMMON}
|
||||||
|
|
||||||
@ -901,6 +964,11 @@ else()
|
|||||||
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/ppc
|
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/ppc
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNICORN_TRACER)
|
||||||
|
target_compile_options(ppc64-softmmu PRIVATE -DUNICORN_TRACER)
|
||||||
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (UNICORN_HAS_RISCV)
|
if (UNICORN_HAS_RISCV)
|
||||||
@ -933,6 +1001,10 @@ else()
|
|||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNICORN_TRACER)
|
||||||
|
target_compile_options(riscv32-softmmu PRIVATE -DUNICORN_TRACER)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_library(riscv64-softmmu
|
add_library(riscv64-softmmu
|
||||||
${UNICORN_ARCH_COMMON}
|
${UNICORN_ARCH_COMMON}
|
||||||
|
|
||||||
@ -961,6 +1033,11 @@ else()
|
|||||||
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/riscv
|
-I${CMAKE_CURRENT_SOURCE_DIR}/qemu/target/riscv
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if(UNICORN_TRACER)
|
||||||
|
target_compile_options(riscv64-softmmu PRIVATE -DUNICORN_TRACER)
|
||||||
|
endif()
|
||||||
|
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (UNICORN_HAS_S390X)
|
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_TEST_FILE ${UNICORN_TEST_FILE} test_ctl)
|
||||||
set(UNICORN_SAMPLE_FILE ${UNICORN_SAMPLE_FILE} sample_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
|
target_compile_options(unicorn PRIVATE
|
||||||
${UNICORN_COMPILE_OPTIONS}
|
${UNICORN_COMPILE_OPTIONS}
|
||||||
)
|
)
|
||||||
|
@ -27,7 +27,7 @@ LIBS_DIR = os.path.join(ROOT_DIR, 'unicorn', 'lib')
|
|||||||
HEADERS_DIR = os.path.join(ROOT_DIR, 'unicorn', 'include')
|
HEADERS_DIR = os.path.join(ROOT_DIR, 'unicorn', 'include')
|
||||||
SRC_DIR = os.path.join(ROOT_DIR, 'src')
|
SRC_DIR = os.path.join(ROOT_DIR, 'src')
|
||||||
UC_DIR = os.path.join(ROOT_DIR, '../..')
|
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"
|
VERSION = "2.0.0rc5.post1"
|
||||||
|
|
||||||
@ -131,7 +131,10 @@ def build_libraries():
|
|||||||
os.mkdir(BUILD_DIR)
|
os.mkdir(BUILD_DIR)
|
||||||
conf = 'Debug' if os.getenv('DEBUG', '') else 'Release'
|
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)
|
os.chdir(BUILD_DIR)
|
||||||
threads = os.getenv("THREADS", "4")
|
threads = os.getenv("THREADS", "4")
|
||||||
subprocess.check_call(["cmake", "--build", ".", "-j" + threads])
|
subprocess.check_call(["cmake", "--build", ".", "-j" + threads])
|
||||||
|
@ -460,6 +460,7 @@ class Uc(object):
|
|||||||
|
|
||||||
# emulate from @begin, and stop when reaching address @until
|
# emulate from @begin, and stop when reaching address @until
|
||||||
def emu_start(self, begin, until, timeout=0, count=0):
|
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)
|
status = _uc.uc_emu_start(self._uch, begin, until, timeout, count)
|
||||||
if status != uc.UC_ERR_OK:
|
if status != uc.UC_ERR_OK:
|
||||||
raise UcError(status)
|
raise UcError(status)
|
||||||
|
@ -96,12 +96,13 @@ pub trait IsUcHook<'a> {}
|
|||||||
|
|
||||||
impl<'a, D, F> IsUcHook<'a> for UcHook<'a, D, F> {}
|
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,
|
uc: uc_handle,
|
||||||
offset: u64,
|
offset: u64,
|
||||||
size: usize,
|
size: usize,
|
||||||
user_data: *mut UcHook<D, F>,
|
user_data: *mut UcHook<D, F>,
|
||||||
) -> u64 where
|
) -> u64
|
||||||
|
where
|
||||||
F: FnMut(&mut crate::Unicorn<D>, u64, usize) -> u64,
|
F: FnMut(&mut crate::Unicorn<D>, u64, usize) -> u64,
|
||||||
{
|
{
|
||||||
let user_data = unsafe { &mut *user_data };
|
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)
|
(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,
|
uc: uc_handle,
|
||||||
offset: u64,
|
offset: u64,
|
||||||
size: usize,
|
size: usize,
|
||||||
|
@ -84,29 +84,32 @@ pub struct MmioCallbackScope<'a> {
|
|||||||
|
|
||||||
impl<'a> MmioCallbackScope<'a> {
|
impl<'a> MmioCallbackScope<'a> {
|
||||||
fn has_regions(&self) -> bool {
|
fn has_regions(&self) -> bool {
|
||||||
self.regions.len() > 0
|
!self.regions.is_empty()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unmap(&mut self, begin: u64, size: usize) {
|
fn unmap(&mut self, begin: u64, size: usize) {
|
||||||
let end: u64 = begin + size as u64;
|
let end: u64 = begin + size as u64;
|
||||||
self.regions = self.regions.iter().flat_map( |(b, s)| {
|
self.regions = self
|
||||||
let e: u64 = b + *s as u64;
|
.regions
|
||||||
if begin > *b {
|
.iter()
|
||||||
if begin >= e {
|
.flat_map(|(b, s)| {
|
||||||
// The unmapped region is completely after this region
|
let e: u64 = b + *s as u64;
|
||||||
vec![(*b, *s)]
|
if begin > *b {
|
||||||
} else {
|
if begin >= e {
|
||||||
if end >= 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
|
// The unmapped region overlaps with the end of this region
|
||||||
vec![(*b, (begin - *b) as usize)]
|
vec![(*b, (begin - *b) as usize)]
|
||||||
} else {
|
} else {
|
||||||
// The unmapped region is in the middle of this region
|
// The unmapped region is in the middle of this region
|
||||||
let second_b = end + 1;
|
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 {
|
if end >= e {
|
||||||
// The unmapped region completely contains this region
|
// The unmapped region completely contains this region
|
||||||
vec![]
|
vec![]
|
||||||
@ -118,8 +121,8 @@ impl<'a> MmioCallbackScope<'a> {
|
|||||||
// The unmapped region is completely before this region
|
// The unmapped region is completely before this region
|
||||||
vec![(*b, *s)]
|
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`.
|
/// `size` must be a multiple of 4kb or this will return `Error::ARG`.
|
||||||
pub fn mmio_map<R: 'a, W: 'a>(
|
pub fn mmio_map<R: 'a, W: 'a>(
|
||||||
&mut self,
|
&mut self,
|
||||||
address: u64,
|
address: u64,
|
||||||
size: libc::size_t,
|
size: libc::size_t,
|
||||||
read_callback: Option<R>,
|
read_callback: Option<R>,
|
||||||
write_callback: Option<W>,
|
write_callback: Option<W>,
|
||||||
@ -327,7 +330,7 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
R: FnMut(&mut Unicorn<D>, u64, usize) -> u64,
|
R: FnMut(&mut Unicorn<D>, u64, usize) -> u64,
|
||||||
W: 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 {
|
Box::new(ffi::UcHook {
|
||||||
callback: c,
|
callback: c,
|
||||||
uc: Unicorn {
|
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 {
|
Box::new(ffi::UcHook {
|
||||||
callback: c,
|
callback: c,
|
||||||
uc: Unicorn {
|
uc: Unicorn {
|
||||||
@ -363,9 +366,9 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if err == uc_error::OK {
|
if err == uc_error::OK {
|
||||||
let rd = read_data.map( |c| c as Box<dyn ffi::IsUcHook> );
|
let rd = read_data.map(|c| c as Box<dyn ffi::IsUcHook>);
|
||||||
let wd = write_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{
|
self.inner_mut().mmio_callbacks.push(MmioCallbackScope {
|
||||||
regions: vec![(address, size)],
|
regions: vec![(address, size)],
|
||||||
read_callback: rd,
|
read_callback: rd,
|
||||||
write_callback: wd,
|
write_callback: wd,
|
||||||
@ -390,7 +393,12 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
where
|
where
|
||||||
F: FnMut(&mut Unicorn<D>, u64, usize) -> u64,
|
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.
|
/// Map in a write-only MMIO region backed by a callback.
|
||||||
@ -406,7 +414,12 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
where
|
where
|
||||||
F: FnMut(&mut Unicorn<D>, u64, usize, u64),
|
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.
|
/// Unmap a memory region.
|
||||||
@ -429,7 +442,9 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
for scope in self.inner_mut().mmio_callbacks.iter_mut() {
|
for scope in self.inner_mut().mmio_callbacks.iter_mut() {
|
||||||
scope.unmap(address, size);
|
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.
|
/// Set the memory permissions for an existing memory region.
|
||||||
@ -817,11 +832,12 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
let err: uc_error;
|
let err: uc_error;
|
||||||
|
|
||||||
// drop the hook
|
// drop the hook
|
||||||
self.inner_mut()
|
let inner = self.inner_mut();
|
||||||
|
inner
|
||||||
.hooks
|
.hooks
|
||||||
.retain(|(hook_ptr, _hook_impl)| hook_ptr != &hook);
|
.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 {
|
if err == uc_error::OK {
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -427,7 +427,10 @@ fn x86_mmio() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
// MOV eax, [0x2004]; MOV [0x2008], ax;
|
// 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 read_cell = Rc::new(RefCell::new(MmioReadExpectation(0, 0)));
|
||||||
let cb_read_cell = read_cell.clone();
|
let cb_read_cell = read_cell.clone();
|
||||||
@ -436,7 +439,7 @@ fn x86_mmio() {
|
|||||||
42
|
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 cb_write_cell = write_cell.clone();
|
||||||
let write_callback = move |_: &mut Unicorn<'_, ()>, offset, size, value| {
|
let write_callback = move |_: &mut Unicorn<'_, ()>, offset, size, value| {
|
||||||
*cb_write_cell.borrow_mut() = MmioWriteExpectation(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.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!(
|
assert_eq!(
|
||||||
emu.emu_start(
|
emu.emu_start(
|
||||||
@ -494,9 +500,11 @@ fn x86_mmio() {
|
|||||||
|
|
||||||
{
|
{
|
||||||
// MOV ax, 42; MOV [0x2008], ax;
|
// 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 cb_write_cell = write_cell.clone();
|
||||||
let write_callback = move |_: &mut Unicorn<'_, ()>, offset, size, value| {
|
let write_callback = move |_: &mut Unicorn<'_, ()>, offset, size, value| {
|
||||||
*cb_write_cell.borrow_mut() = MmioWriteExpectation(offset, size, value);
|
*cb_write_cell.borrow_mut() = MmioWriteExpectation(offset, size, value);
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit e1111e1b8b253bf7292ad911f43c125808a95f1e
|
Subproject commit db5434ad4e40c6657766aa6a54eafd92af38192e
|
@ -369,6 +369,8 @@ struct uc_struct {
|
|||||||
int nested_level; // Current nested_level
|
int nested_level; // Current nested_level
|
||||||
|
|
||||||
struct TranslationBlock *last_tb; // The real last tb we executed.
|
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_*()
|
// 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;
|
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
|
#endif
|
||||||
/* vim: set ts=4 noet: */
|
/* vim: set ts=4 noet: */
|
||||||
|
@ -55,9 +55,12 @@ static inline tcg_target_ulong cpu_tb_exec(CPUState *cpu, TranslationBlock *itb)
|
|||||||
int tb_exit;
|
int tb_exit;
|
||||||
uint8_t *tb_ptr = itb->tc.ptr;
|
uint8_t *tb_ptr = itb->tc.ptr;
|
||||||
|
|
||||||
|
UC_TRACE_START(UC_TRACE_TB_EXEC);
|
||||||
tb_exec_lock(cpu->uc->tcg_ctx);
|
tb_exec_lock(cpu->uc->tcg_ctx);
|
||||||
ret = tcg_qemu_tb_exec(env, tb_ptr);
|
ret = tcg_qemu_tb_exec(env, tb_ptr);
|
||||||
tb_exec_unlock(cpu->uc->tcg_ctx);
|
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;
|
cpu->can_do_io = 1;
|
||||||
last_tb = (TranslationBlock *)(ret & ~TB_EXIT_MASK);
|
last_tb = (TranslationBlock *)(ret & ~TB_EXIT_MASK);
|
||||||
tb_exit = ret & TB_EXIT_MASK;
|
tb_exit = ret & TB_EXIT_MASK;
|
||||||
|
@ -1619,7 +1619,9 @@ TranslationBlock *tb_gen_code(CPUState *cpu,
|
|||||||
tcg_func_start(tcg_ctx);
|
tcg_func_start(tcg_ctx);
|
||||||
|
|
||||||
tcg_ctx->cpu = env_cpu(env);
|
tcg_ctx->cpu = env_cpu(env);
|
||||||
|
UC_TRACE_START(UC_TRACE_TB_TRANS);
|
||||||
gen_intermediate_code(cpu, tb, max_insns);
|
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;
|
tcg_ctx->cpu = NULL;
|
||||||
|
|
||||||
/* generate machine code */
|
/* generate machine code */
|
||||||
|
@ -119,18 +119,13 @@ struct uc_struct;
|
|||||||
* Only allow MAP_JIT for Mojave or later.
|
* Only allow MAP_JIT for Mojave or later.
|
||||||
*
|
*
|
||||||
* Source: https://github.com/moby/hyperkit/pull/259/files#diff-e6b5417230ff2daff9155d9b15aefae12e89410ec2dca1f59d04be511f6737fcR41
|
* 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(__APPLE__) && defined(HAVE_PTHREAD_JIT_PROTECT) && defined(__arm__)
|
||||||
#if defined(HAVE_PTHREAD_JIT_PROTECT)
|
#define USE_MAP_JIT
|
||||||
#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
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <glib_compat.h>
|
#include <glib_compat.h>
|
||||||
|
@ -783,8 +783,6 @@ static void address_space_update_topology_pass(AddressSpace *as,
|
|||||||
|
|
||||||
static void flatviews_init(struct uc_struct *uc)
|
static void flatviews_init(struct uc_struct *uc)
|
||||||
{
|
{
|
||||||
static FlatView *empty_view;
|
|
||||||
|
|
||||||
if (uc->flat_views) {
|
if (uc->flat_views) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -792,13 +790,13 @@ static void flatviews_init(struct uc_struct *uc)
|
|||||||
uc->flat_views = g_hash_table_new_full(NULL, NULL, NULL,
|
uc->flat_views = g_hash_table_new_full(NULL, NULL, NULL,
|
||||||
(GDestroyNotify) flatview_unref);
|
(GDestroyNotify) flatview_unref);
|
||||||
|
|
||||||
if (!empty_view) {
|
if (!uc->empty_view) {
|
||||||
empty_view = generate_memory_topology(uc, NULL);
|
uc->empty_view = generate_memory_topology(uc, NULL);
|
||||||
/* We keep it alive forever in the global variable. */
|
/* We keep it alive forever in the global variable. */
|
||||||
flatview_ref(empty_view);
|
flatview_ref(uc->empty_view);
|
||||||
} else {
|
} else {
|
||||||
g_hash_table_replace(uc->flat_views, NULL, empty_view);
|
g_hash_table_replace(uc->flat_views, NULL, uc->empty_view);
|
||||||
flatview_ref(empty_view);
|
flatview_ref(uc->empty_view);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -11432,6 +11432,21 @@ static void arm_tr_translate_insn(DisasContextBase *dcbase, CPUState *cpu)
|
|||||||
dc->pc_curr = dc->base.pc_next;
|
dc->pc_curr = dc->base.pc_next;
|
||||||
insn = arm_ldl_code(env, dc->base.pc_next, dc->sctlr_b);
|
insn = arm_ldl_code(env, dc->base.pc_next, dc->sctlr_b);
|
||||||
dc->insn = insn;
|
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;
|
dc->base.pc_next += 4;
|
||||||
disas_arm_insn(dc, insn);
|
disas_arm_insn(dc, insn);
|
||||||
|
|
||||||
|
@ -529,6 +529,69 @@ static void test_arm_hflags_rebuilt()
|
|||||||
OK(uc_close(uc));
|
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_LIST = {{"test_arm_nop", test_arm_nop},
|
||||||
{"test_arm_thumb_sub", test_arm_thumb_sub},
|
{"test_arm_thumb_sub", test_arm_thumb_sub},
|
||||||
{"test_armeb_sub", test_armeb_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_not_allow_privilege_escalation},
|
||||||
{"test_arm_mrc", test_arm_mrc},
|
{"test_arm_mrc", test_arm_mrc},
|
||||||
{"test_arm_hflags_rebuilt", test_arm_hflags_rebuilt},
|
{"test_arm_hflags_rebuilt", test_arm_hflags_rebuilt},
|
||||||
|
{"test_arm_mem_access_abort", test_arm_mem_access_abort},
|
||||||
{NULL, NULL}};
|
{NULL, NULL}};
|
28
uc.c
28
uc.c
@ -2221,3 +2221,31 @@ uc_err uc_ctl(uc_engine *uc, uc_control_type control, ...)
|
|||||||
|
|
||||||
return err;
|
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
|
Loading…
Reference in New Issue
Block a user