refactor: Make rust bindings more rusty
This commit is contained in:
@@ -35,6 +35,7 @@ extern crate std;
|
|||||||
use alloc::boxed::Box;
|
use alloc::boxed::Box;
|
||||||
use alloc::rc::Rc;
|
use alloc::rc::Rc;
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
|
use bitflags::Flags;
|
||||||
use core::cell::UnsafeCell;
|
use core::cell::UnsafeCell;
|
||||||
use core::ptr;
|
use core::ptr;
|
||||||
|
|
||||||
@@ -221,9 +222,8 @@ where
|
|||||||
mode: Mode,
|
mode: Mode,
|
||||||
data: D,
|
data: D,
|
||||||
) -> Result<Unicorn<'a, D>, uc_error> {
|
) -> Result<Unicorn<'a, D>, uc_error> {
|
||||||
let mut handle = core::ptr::null_mut();
|
let mut handle = ptr::null_mut();
|
||||||
let err = unsafe { ffi::uc_open(arch, mode, &mut handle) };
|
unsafe { ffi::uc_open(arch, mode, &mut handle) }.and_then(|| {
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(Unicorn {
|
Ok(Unicorn {
|
||||||
inner: Rc::new(UnsafeCell::from(UnicornInner {
|
inner: Rc::new(UnsafeCell::from(UnicornInner {
|
||||||
handle,
|
handle,
|
||||||
@@ -234,9 +234,7 @@ where
|
|||||||
mmio_callbacks: vec![],
|
mmio_callbacks: vec![],
|
||||||
})),
|
})),
|
||||||
})
|
})
|
||||||
} else {
|
})
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,60 +286,43 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
/// Returns a vector with the memory regions that are mapped in the emulator.
|
/// Returns a vector with the memory regions that are mapped in the emulator.
|
||||||
pub fn mem_regions(&self) -> Result<Vec<MemRegion>, uc_error> {
|
pub fn mem_regions(&self) -> Result<Vec<MemRegion>, uc_error> {
|
||||||
let mut nb_regions: u32 = 0;
|
let mut nb_regions: u32 = 0;
|
||||||
let p_regions: *const MemRegion = core::ptr::null_mut();
|
let p_regions: *const MemRegion = ptr::null_mut();
|
||||||
let err = unsafe { ffi::uc_mem_regions(self.get_handle(), &p_regions, &mut nb_regions) };
|
unsafe { ffi::uc_mem_regions(self.get_handle(), &p_regions, &mut nb_regions) }.and_then(|| {
|
||||||
if err == uc_error::OK {
|
|
||||||
let mut regions = Vec::new();
|
let mut regions = Vec::new();
|
||||||
for i in 0..nb_regions {
|
for i in 0..nb_regions {
|
||||||
regions.push(unsafe { core::mem::transmute_copy(&*p_regions.add(i as usize)) });
|
regions.push(unsafe { core::mem::transmute_copy(&*p_regions.add(i as usize)) });
|
||||||
}
|
}
|
||||||
unsafe { libc::free(p_regions as _) };
|
unsafe { libc::free(p_regions as _) };
|
||||||
Ok(regions)
|
Ok(regions)
|
||||||
} else {
|
})
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read a range of bytes from memory at the specified address.
|
/// Read a range of bytes from memory at the specified emulated physical address.
|
||||||
pub fn mem_read(
|
pub fn mem_read(
|
||||||
&self,
|
&self,
|
||||||
address: u64,
|
address: u64,
|
||||||
buf: &mut [u8],
|
buf: &mut [u8],
|
||||||
) -> Result<(), uc_error> {
|
) -> Result<(), uc_error> {
|
||||||
let err = unsafe { ffi::uc_mem_read(self.get_handle(), address, buf.as_mut_ptr(), buf.len()) };
|
unsafe { ffi::uc_mem_read(self.get_handle(), address, buf.as_mut_ptr(), buf.len()) }.into()
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a range of bytes from memory at the specified address as vector.
|
/// Return a range of bytes from memory at the specified emulated physical address as vector.
|
||||||
pub fn mem_read_as_vec(
|
pub fn mem_read_as_vec(
|
||||||
&self,
|
&self,
|
||||||
address: u64,
|
address: u64,
|
||||||
size: usize,
|
size: usize,
|
||||||
) -> Result<Vec<u8>, uc_error> {
|
) -> Result<Vec<u8>, uc_error> {
|
||||||
let mut buf = vec![0; size];
|
let mut buf = vec![0; size];
|
||||||
let err = unsafe { ffi::uc_mem_read(self.get_handle(), address, buf.as_mut_ptr(), size) };
|
unsafe { ffi::uc_mem_read(self.get_handle(), address, buf.as_mut_ptr(), size) }.and(Ok(buf))
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(buf)
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Write the data in `bytes` to the emulated physical address `address`
|
||||||
pub fn mem_write(
|
pub fn mem_write(
|
||||||
&mut self,
|
&mut self,
|
||||||
address: u64,
|
address: u64,
|
||||||
bytes: &[u8],
|
bytes: &[u8],
|
||||||
) -> Result<(), uc_error> {
|
) -> Result<(), uc_error> {
|
||||||
let err = unsafe { ffi::uc_mem_write(self.get_handle(), address, bytes.as_ptr(), bytes.len()) };
|
unsafe { ffi::uc_mem_write(self.get_handle(), address, bytes.as_ptr(), bytes.len()) }.into()
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map an existing memory region in the emulator at the specified address.
|
/// Map an existing memory region in the emulator at the specified address.
|
||||||
@@ -364,12 +345,7 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
perms: Permission,
|
perms: Permission,
|
||||||
ptr: *mut c_void,
|
ptr: *mut c_void,
|
||||||
) -> Result<(), uc_error> {
|
) -> Result<(), uc_error> {
|
||||||
let err = ffi::uc_mem_map_ptr(self.get_handle(), address, size, perms.bits(), ptr);
|
ffi::uc_mem_map_ptr(self.get_handle(), address, size, perms.bits(), ptr).into()
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map a memory region in the emulator at the specified address.
|
/// Map a memory region in the emulator at the specified address.
|
||||||
@@ -382,12 +358,7 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
size: libc::size_t,
|
size: libc::size_t,
|
||||||
perms: Permission,
|
perms: Permission,
|
||||||
) -> Result<(), uc_error> {
|
) -> Result<(), uc_error> {
|
||||||
let err = unsafe { ffi::uc_mem_map(self.get_handle(), address, size, perms.bits()) };
|
unsafe { ffi::uc_mem_map(self.get_handle(), address, size, perms.bits()) }.into()
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map in am MMIO region backed by callbacks.
|
/// Map in am MMIO region backed by callbacks.
|
||||||
@@ -418,7 +389,7 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
})
|
})
|
||||||
});
|
});
|
||||||
|
|
||||||
let err = unsafe {
|
unsafe {
|
||||||
ffi::uc_mmio_map(
|
ffi::uc_mmio_map(
|
||||||
self.get_handle(),
|
self.get_handle(),
|
||||||
address,
|
address,
|
||||||
@@ -440,9 +411,8 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
None => ptr::null_mut(),
|
None => ptr::null_mut(),
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
};
|
}
|
||||||
|
.and_then(|| {
|
||||||
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 {
|
||||||
@@ -452,9 +422,7 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
})
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Map in a read-only MMIO region backed by a callback.
|
/// Map in a read-only MMIO region backed by a callback.
|
||||||
@@ -499,14 +467,8 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
size: libc::size_t,
|
size: libc::size_t,
|
||||||
) -> Result<(), uc_error> {
|
) -> Result<(), uc_error> {
|
||||||
let err = unsafe { ffi::uc_mem_unmap(self.get_handle(), address, size) };
|
let err = unsafe { ffi::uc_mem_unmap(self.get_handle(), address, size) };
|
||||||
|
|
||||||
self.mmio_unmap(address, size);
|
self.mmio_unmap(address, size);
|
||||||
|
err.into()
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mmio_unmap(
|
fn mmio_unmap(
|
||||||
@@ -532,12 +494,7 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
size: libc::size_t,
|
size: libc::size_t,
|
||||||
perms: Permission,
|
perms: Permission,
|
||||||
) -> Result<(), uc_error> {
|
) -> Result<(), uc_error> {
|
||||||
let err = unsafe { ffi::uc_mem_protect(self.get_handle(), address, size, perms.bits()) };
|
unsafe { ffi::uc_mem_protect(self.get_handle(), address, size, perms.bits()) }.into()
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write an unsigned value from a register.
|
/// Write an unsigned value from a register.
|
||||||
@@ -546,12 +503,7 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
regid: T,
|
regid: T,
|
||||||
value: u64,
|
value: u64,
|
||||||
) -> Result<(), uc_error> {
|
) -> Result<(), uc_error> {
|
||||||
let err = unsafe { ffi::uc_reg_write(self.get_handle(), regid.into(), &value as *const _ as _) };
|
unsafe { ffi::uc_reg_write(self.get_handle(), regid.into(), &value as *const _ as _) }.into()
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Write variable sized values into registers.
|
/// Write variable sized values into registers.
|
||||||
@@ -563,12 +515,7 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
regid: T,
|
regid: T,
|
||||||
value: &[u8],
|
value: &[u8],
|
||||||
) -> Result<(), uc_error> {
|
) -> Result<(), uc_error> {
|
||||||
let err = unsafe { ffi::uc_reg_write(self.get_handle(), regid.into(), value.as_ptr() as _) };
|
unsafe { ffi::uc_reg_write(self.get_handle(), regid.into(), value.as_ptr() as _) }.into()
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read an unsigned value from a register.
|
/// Read an unsigned value from a register.
|
||||||
@@ -579,12 +526,7 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
regid: T,
|
regid: T,
|
||||||
) -> Result<u64, uc_error> {
|
) -> Result<u64, uc_error> {
|
||||||
let mut value: u64 = 0;
|
let mut value: u64 = 0;
|
||||||
let err = unsafe { ffi::uc_reg_read(self.get_handle(), regid.into(), &mut value as *mut u64 as _) };
|
unsafe { ffi::uc_reg_read(self.get_handle(), regid.into(), &mut value as *mut u64 as _) }.and(Ok(value))
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(value)
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Read 128, 256 or 512 bit register value into heap allocated byte array.
|
/// Read 128, 256 or 512 bit register value into heap allocated byte array.
|
||||||
@@ -594,45 +536,42 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
&self,
|
&self,
|
||||||
regid: T,
|
regid: T,
|
||||||
) -> Result<Box<[u8]>, uc_error> {
|
) -> Result<Box<[u8]>, uc_error> {
|
||||||
let boxed: Box<[u8]>;
|
|
||||||
let mut value: Vec<u8>;
|
|
||||||
let curr_reg_id = regid.into();
|
let curr_reg_id = regid.into();
|
||||||
let curr_arch = self.get_arch();
|
let curr_arch = self.get_arch();
|
||||||
|
|
||||||
if curr_arch == Arch::X86 {
|
let value_size = match curr_arch {
|
||||||
if curr_reg_id >= x86::RegisterX86::XMM0 as i32 && curr_reg_id <= x86::RegisterX86::XMM31 as i32 {
|
Arch::X86 => Self::value_size_x86(curr_reg_id)?,
|
||||||
value = vec![0; 16];
|
Arch::ARM64 => Self::value_size_arm64(curr_reg_id)?,
|
||||||
} else if curr_reg_id >= x86::RegisterX86::YMM0 as i32 && curr_reg_id <= x86::RegisterX86::YMM31 as i32 {
|
_ => Err(uc_error::ARCH)?,
|
||||||
value = vec![0; 32];
|
};
|
||||||
} else if curr_reg_id >= x86::RegisterX86::ZMM0 as i32 && curr_reg_id <= x86::RegisterX86::ZMM31 as i32 {
|
let mut value = vec![0; value_size];
|
||||||
value = vec![0; 64];
|
unsafe { ffi::uc_reg_read(self.get_handle(), curr_reg_id, value.as_mut_ptr() as _) }
|
||||||
} else if curr_reg_id == x86::RegisterX86::GDTR as i32
|
.and_then(|| Ok(value.into_boxed_slice()))
|
||||||
|| curr_reg_id == x86::RegisterX86::IDTR as i32
|
}
|
||||||
|| (curr_reg_id >= x86::RegisterX86::ST0 as i32 && curr_reg_id <= x86::RegisterX86::ST7 as i32)
|
|
||||||
|
fn value_size_arm64(curr_reg_id: i32) -> Result<usize, uc_error> {
|
||||||
|
match curr_reg_id {
|
||||||
|
r if (RegisterARM64::Q0 as i32..=RegisterARM64::Q31 as i32).contains(&r)
|
||||||
|
|| (RegisterARM64::V0 as i32..=RegisterARM64::V31 as i32).contains(&r) =>
|
||||||
{
|
{
|
||||||
value = vec![0; 10]; // 64 bit base address in IA-32e mode
|
Ok(16)
|
||||||
} else {
|
|
||||||
return Err(uc_error::ARG);
|
|
||||||
}
|
}
|
||||||
} else if curr_arch == Arch::ARM64 {
|
_ => Err(uc_error::ARG),
|
||||||
if (curr_reg_id >= arm64::RegisterARM64::Q0 as i32 && curr_reg_id <= arm64::RegisterARM64::Q31 as i32)
|
|
||||||
|| (curr_reg_id >= arm64::RegisterARM64::V0 as i32 && curr_reg_id <= arm64::RegisterARM64::V31 as i32)
|
|
||||||
{
|
|
||||||
value = vec![0; 16];
|
|
||||||
} else {
|
|
||||||
return Err(uc_error::ARG);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(uc_error::ARCH);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let err: uc_error = unsafe { ffi::uc_reg_read(self.get_handle(), curr_reg_id, value.as_mut_ptr() as _) };
|
fn value_size_x86(curr_reg_id: i32) -> Result<usize, uc_error> {
|
||||||
|
match curr_reg_id {
|
||||||
if err == uc_error::OK {
|
r if (RegisterX86::XMM0 as i32..=RegisterX86::XMM31 as i32).contains(&r) => Ok(16),
|
||||||
boxed = value.into_boxed_slice();
|
r if (RegisterX86::YMM0 as i32..=RegisterX86::YMM31 as i32).contains(&r) => Ok(32),
|
||||||
Ok(boxed)
|
r if (RegisterX86::ZMM0 as i32..=RegisterX86::ZMM31 as i32).contains(&r) => Ok(64),
|
||||||
} else {
|
r if r == RegisterX86::GDTR as i32
|
||||||
Err(err)
|
|| r == RegisterX86::IDTR as i32
|
||||||
|
|| (RegisterX86::ST0 as i32..=RegisterX86::ST7 as i32).contains(&r) =>
|
||||||
|
{
|
||||||
|
Ok(10)
|
||||||
|
}
|
||||||
|
_ => Err(uc_error::ARG),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -642,12 +581,7 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
regid: T,
|
regid: T,
|
||||||
) -> Result<i32, uc_error> {
|
) -> Result<i32, uc_error> {
|
||||||
let mut value: i32 = 0;
|
let mut value: i32 = 0;
|
||||||
let err = unsafe { ffi::uc_reg_read(self.get_handle(), regid.into(), &mut value as *mut i32 as _) };
|
unsafe { ffi::uc_reg_read(self.get_handle(), regid.into(), &mut value as *mut i32 as _) }.and(Ok(value))
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(value)
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a code hook.
|
/// Add a code hook.
|
||||||
@@ -658,7 +592,7 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
callback: F,
|
callback: F,
|
||||||
) -> Result<UcHookId, uc_error>
|
) -> Result<UcHookId, uc_error>
|
||||||
where
|
where
|
||||||
F: FnMut(&mut crate::Unicorn<D>, u64, u32) + 'a,
|
F: FnMut(&mut Unicorn<D>, u64, u32) + 'a,
|
||||||
{
|
{
|
||||||
let mut hook_id = ptr::null_mut();
|
let mut hook_id = ptr::null_mut();
|
||||||
let mut user_data = Box::new(ffi::UcHook {
|
let mut user_data = Box::new(ffi::UcHook {
|
||||||
@@ -666,7 +600,7 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
uc: Rc::downgrade(&self.inner),
|
uc: Rc::downgrade(&self.inner),
|
||||||
});
|
});
|
||||||
|
|
||||||
let err = unsafe {
|
unsafe {
|
||||||
ffi::uc_hook_add(
|
ffi::uc_hook_add(
|
||||||
self.get_handle(),
|
self.get_handle(),
|
||||||
&mut hook_id,
|
&mut hook_id,
|
||||||
@@ -676,14 +610,12 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
begin,
|
begin,
|
||||||
end,
|
end,
|
||||||
)
|
)
|
||||||
};
|
}
|
||||||
let hook_id = UcHookId(hook_id);
|
.and_then(|| {
|
||||||
if err == uc_error::OK {
|
let hook_id = UcHookId(hook_id);
|
||||||
self.inner_mut().hooks.push((hook_id, user_data));
|
self.inner_mut().hooks.push((hook_id, user_data));
|
||||||
Ok(hook_id)
|
Ok(hook_id)
|
||||||
} else {
|
})
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a block hook.
|
/// Add a block hook.
|
||||||
@@ -694,13 +626,13 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
where
|
where
|
||||||
F: FnMut(&mut Unicorn<D>, u64, u32),
|
F: FnMut(&mut Unicorn<D>, u64, u32),
|
||||||
{
|
{
|
||||||
let mut hook_id = core::ptr::null_mut();
|
let mut hook_id = ptr::null_mut();
|
||||||
let mut user_data = Box::new(ffi::UcHook {
|
let mut user_data = Box::new(ffi::UcHook {
|
||||||
callback,
|
callback,
|
||||||
uc: Rc::downgrade(&self.inner),
|
uc: Rc::downgrade(&self.inner),
|
||||||
});
|
});
|
||||||
|
|
||||||
let err = unsafe {
|
unsafe {
|
||||||
ffi::uc_hook_add(
|
ffi::uc_hook_add(
|
||||||
self.get_handle(),
|
self.get_handle(),
|
||||||
&mut hook_id,
|
&mut hook_id,
|
||||||
@@ -710,15 +642,12 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
1,
|
1,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
};
|
|
||||||
let hook_id = UcHookId(hook_id);
|
|
||||||
if err == uc_error::OK {
|
|
||||||
self.inner_mut().hooks.push((hook_id, user_data));
|
|
||||||
|
|
||||||
Ok(hook_id)
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
}
|
||||||
|
.and_then(|| {
|
||||||
|
let hook_id = UcHookId(hook_id);
|
||||||
|
self.inner_mut().hooks.push((hook_id, user_data));
|
||||||
|
Ok(hook_id)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a memory hook.
|
/// Add a memory hook.
|
||||||
@@ -736,13 +665,13 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
return Err(uc_error::ARG);
|
return Err(uc_error::ARG);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut hook_id = core::ptr::null_mut();
|
let mut hook_id = ptr::null_mut();
|
||||||
let mut user_data = Box::new(ffi::UcHook {
|
let mut user_data = Box::new(ffi::UcHook {
|
||||||
callback,
|
callback,
|
||||||
uc: Rc::downgrade(&self.inner),
|
uc: Rc::downgrade(&self.inner),
|
||||||
});
|
});
|
||||||
|
|
||||||
let err = unsafe {
|
unsafe {
|
||||||
ffi::uc_hook_add(
|
ffi::uc_hook_add(
|
||||||
self.get_handle(),
|
self.get_handle(),
|
||||||
&mut hook_id,
|
&mut hook_id,
|
||||||
@@ -752,15 +681,12 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
begin,
|
begin,
|
||||||
end,
|
end,
|
||||||
)
|
)
|
||||||
};
|
|
||||||
let hook_id = UcHookId(hook_id);
|
|
||||||
if err == uc_error::OK {
|
|
||||||
self.inner_mut().hooks.push((hook_id, user_data));
|
|
||||||
|
|
||||||
Ok(hook_id)
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
}
|
||||||
|
.and_then(|| {
|
||||||
|
let hook_id = UcHookId(hook_id);
|
||||||
|
self.inner_mut().hooks.push((hook_id, user_data));
|
||||||
|
Ok(hook_id)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add an interrupt hook.
|
/// Add an interrupt hook.
|
||||||
@@ -771,13 +697,13 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
where
|
where
|
||||||
F: FnMut(&mut Unicorn<D>, u32),
|
F: FnMut(&mut Unicorn<D>, u32),
|
||||||
{
|
{
|
||||||
let mut hook_id = core::ptr::null_mut();
|
let mut hook_id = ptr::null_mut();
|
||||||
let mut user_data = Box::new(ffi::UcHook {
|
let mut user_data = Box::new(ffi::UcHook {
|
||||||
callback,
|
callback,
|
||||||
uc: Rc::downgrade(&self.inner),
|
uc: Rc::downgrade(&self.inner),
|
||||||
});
|
});
|
||||||
|
|
||||||
let err = unsafe {
|
unsafe {
|
||||||
ffi::uc_hook_add(
|
ffi::uc_hook_add(
|
||||||
self.get_handle(),
|
self.get_handle(),
|
||||||
&mut hook_id,
|
&mut hook_id,
|
||||||
@@ -787,15 +713,12 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
};
|
|
||||||
let hook_id = UcHookId(hook_id);
|
|
||||||
if err == uc_error::OK {
|
|
||||||
self.inner_mut().hooks.push((hook_id, user_data));
|
|
||||||
|
|
||||||
Ok(hook_id)
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
}
|
||||||
|
.and_then(|| {
|
||||||
|
let hook_id = UcHookId(hook_id);
|
||||||
|
self.inner_mut().hooks.push((hook_id, user_data));
|
||||||
|
Ok(hook_id)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add hook for invalid instructions
|
/// Add hook for invalid instructions
|
||||||
@@ -806,13 +729,13 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
where
|
where
|
||||||
F: FnMut(&mut Unicorn<D>) -> bool,
|
F: FnMut(&mut Unicorn<D>) -> bool,
|
||||||
{
|
{
|
||||||
let mut hook_id = core::ptr::null_mut();
|
let mut hook_id = ptr::null_mut();
|
||||||
let mut user_data = Box::new(ffi::UcHook {
|
let mut user_data = Box::new(ffi::UcHook {
|
||||||
callback,
|
callback,
|
||||||
uc: Rc::downgrade(&self.inner),
|
uc: Rc::downgrade(&self.inner),
|
||||||
});
|
});
|
||||||
|
|
||||||
let err = unsafe {
|
unsafe {
|
||||||
ffi::uc_hook_add(
|
ffi::uc_hook_add(
|
||||||
self.get_handle(),
|
self.get_handle(),
|
||||||
&mut hook_id,
|
&mut hook_id,
|
||||||
@@ -822,15 +745,12 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
)
|
)
|
||||||
};
|
|
||||||
let hook_id = UcHookId(hook_id);
|
|
||||||
if err == uc_error::OK {
|
|
||||||
self.inner_mut().hooks.push((hook_id, user_data));
|
|
||||||
|
|
||||||
Ok(hook_id)
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
}
|
||||||
|
.and_then(|| {
|
||||||
|
let hook_id = UcHookId(hook_id);
|
||||||
|
self.inner_mut().hooks.push((hook_id, user_data));
|
||||||
|
Ok(hook_id)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add hook for x86 IN instruction.
|
/// Add hook for x86 IN instruction.
|
||||||
@@ -841,13 +761,13 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
where
|
where
|
||||||
F: FnMut(&mut Unicorn<D>, u32, usize) -> u32,
|
F: FnMut(&mut Unicorn<D>, u32, usize) -> u32,
|
||||||
{
|
{
|
||||||
let mut hook_id = core::ptr::null_mut();
|
let mut hook_id = ptr::null_mut();
|
||||||
let mut user_data = Box::new(ffi::UcHook {
|
let mut user_data = Box::new(ffi::UcHook {
|
||||||
callback,
|
callback,
|
||||||
uc: Rc::downgrade(&self.inner),
|
uc: Rc::downgrade(&self.inner),
|
||||||
});
|
});
|
||||||
|
|
||||||
let err = unsafe {
|
unsafe {
|
||||||
ffi::uc_hook_add(
|
ffi::uc_hook_add(
|
||||||
self.get_handle(),
|
self.get_handle(),
|
||||||
&mut hook_id,
|
&mut hook_id,
|
||||||
@@ -856,17 +776,14 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
user_data.as_mut() as *mut _ as _,
|
user_data.as_mut() as *mut _ as _,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
x86::InsnX86::IN,
|
InsnX86::IN,
|
||||||
)
|
)
|
||||||
};
|
|
||||||
let hook_id = UcHookId(hook_id);
|
|
||||||
if err == uc_error::OK {
|
|
||||||
self.inner_mut().hooks.push((hook_id, user_data));
|
|
||||||
|
|
||||||
Ok(hook_id)
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
}
|
||||||
|
.and_then(|| {
|
||||||
|
let hook_id = UcHookId(hook_id);
|
||||||
|
self.inner_mut().hooks.push((hook_id, user_data));
|
||||||
|
Ok(hook_id)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add hook for x86 OUT instruction.
|
/// Add hook for x86 OUT instruction.
|
||||||
@@ -877,13 +794,13 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
where
|
where
|
||||||
F: FnMut(&mut Unicorn<D>, u32, usize, u32),
|
F: FnMut(&mut Unicorn<D>, u32, usize, u32),
|
||||||
{
|
{
|
||||||
let mut hook_id = core::ptr::null_mut();
|
let mut hook_id = ptr::null_mut();
|
||||||
let mut user_data = Box::new(ffi::UcHook {
|
let mut user_data = Box::new(ffi::UcHook {
|
||||||
callback,
|
callback,
|
||||||
uc: Rc::downgrade(&self.inner),
|
uc: Rc::downgrade(&self.inner),
|
||||||
});
|
});
|
||||||
|
|
||||||
let err = unsafe {
|
unsafe {
|
||||||
ffi::uc_hook_add(
|
ffi::uc_hook_add(
|
||||||
self.get_handle(),
|
self.get_handle(),
|
||||||
&mut hook_id,
|
&mut hook_id,
|
||||||
@@ -892,23 +809,20 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
user_data.as_mut() as *mut _ as _,
|
user_data.as_mut() as *mut _ as _,
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
x86::InsnX86::OUT,
|
InsnX86::OUT,
|
||||||
)
|
)
|
||||||
};
|
|
||||||
let hook_id = UcHookId(hook_id);
|
|
||||||
if err == uc_error::OK {
|
|
||||||
self.inner_mut().hooks.push((hook_id, user_data));
|
|
||||||
|
|
||||||
Ok(hook_id)
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
}
|
||||||
|
.and_then(|| {
|
||||||
|
let hook_id = UcHookId(hook_id);
|
||||||
|
self.inner_mut().hooks.push((hook_id, user_data));
|
||||||
|
Ok(hook_id)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add hook for x86 SYSCALL or SYSENTER.
|
/// Add hook for x86 SYSCALL or SYSENTER.
|
||||||
pub fn add_insn_sys_hook<F>(
|
pub fn add_insn_sys_hook<F>(
|
||||||
&mut self,
|
&mut self,
|
||||||
insn_type: x86::InsnSysX86,
|
insn_type: InsnSysX86,
|
||||||
begin: u64,
|
begin: u64,
|
||||||
end: u64,
|
end: u64,
|
||||||
callback: F,
|
callback: F,
|
||||||
@@ -916,13 +830,13 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
where
|
where
|
||||||
F: FnMut(&mut Unicorn<D>) + 'a,
|
F: FnMut(&mut Unicorn<D>) + 'a,
|
||||||
{
|
{
|
||||||
let mut hook_id = core::ptr::null_mut();
|
let mut hook_id = ptr::null_mut();
|
||||||
let mut user_data = Box::new(ffi::UcHook {
|
let mut user_data = Box::new(ffi::UcHook {
|
||||||
callback,
|
callback,
|
||||||
uc: Rc::downgrade(&self.inner),
|
uc: Rc::downgrade(&self.inner),
|
||||||
});
|
});
|
||||||
|
|
||||||
let err = unsafe {
|
unsafe {
|
||||||
ffi::uc_hook_add(
|
ffi::uc_hook_add(
|
||||||
self.get_handle(),
|
self.get_handle(),
|
||||||
&mut hook_id,
|
&mut hook_id,
|
||||||
@@ -933,15 +847,12 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
end,
|
end,
|
||||||
insn_type,
|
insn_type,
|
||||||
)
|
)
|
||||||
};
|
|
||||||
let hook_id = UcHookId(hook_id);
|
|
||||||
if err == uc_error::OK {
|
|
||||||
self.inner_mut().hooks.push((hook_id, user_data));
|
|
||||||
|
|
||||||
Ok(hook_id)
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
}
|
||||||
|
.and_then(|| {
|
||||||
|
let hook_id = UcHookId(hook_id);
|
||||||
|
self.inner_mut().hooks.push((hook_id, user_data));
|
||||||
|
Ok(hook_id)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn add_tlb_hook<F>(
|
pub fn add_tlb_hook<F>(
|
||||||
@@ -951,14 +862,15 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
callback: F,
|
callback: F,
|
||||||
) -> Result<UcHookId, uc_error>
|
) -> Result<UcHookId, uc_error>
|
||||||
where
|
where
|
||||||
F: FnMut(&mut crate::Unicorn<D>, u64, MemType) -> Option<TlbEntry> + 'a,
|
F: FnMut(&mut Unicorn<D>, u64, MemType) -> Option<TlbEntry> + 'a,
|
||||||
{
|
{
|
||||||
let mut hook_id = core::ptr::null_mut();
|
let mut hook_id = ptr::null_mut();
|
||||||
let mut user_data = Box::new(ffi::UcHook {
|
let mut user_data = Box::new(ffi::UcHook {
|
||||||
callback,
|
callback,
|
||||||
uc: Rc::downgrade(&self.inner),
|
uc: Rc::downgrade(&self.inner),
|
||||||
});
|
});
|
||||||
let err = unsafe {
|
|
||||||
|
unsafe {
|
||||||
ffi::uc_hook_add(
|
ffi::uc_hook_add(
|
||||||
self.get_handle(),
|
self.get_handle(),
|
||||||
&mut hook_id,
|
&mut hook_id,
|
||||||
@@ -968,14 +880,12 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
begin,
|
begin,
|
||||||
end,
|
end,
|
||||||
)
|
)
|
||||||
};
|
}
|
||||||
let hook_id = UcHookId(hook_id);
|
.and_then(|| {
|
||||||
if err == uc_error::OK {
|
let hook_id = UcHookId(hook_id);
|
||||||
self.inner_mut().hooks.push((hook_id, user_data));
|
self.inner_mut().hooks.push((hook_id, user_data));
|
||||||
Ok(hook_id)
|
Ok(hook_id)
|
||||||
} else {
|
})
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove a hook.
|
/// Remove a hook.
|
||||||
@@ -989,13 +899,7 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
let inner = self.inner_mut();
|
let inner = self.inner_mut();
|
||||||
inner.hooks.retain(|(id, _)| id != &hook_id);
|
inner.hooks.retain(|(id, _)| id != &hook_id);
|
||||||
|
|
||||||
let err: uc_error = unsafe { ffi::uc_hook_del(inner.handle, hook_id.0) };
|
unsafe { ffi::uc_hook_del(inner.handle, hook_id.0) }.into()
|
||||||
|
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocate and return an empty Unicorn context.
|
/// Allocate and return an empty Unicorn context.
|
||||||
@@ -1003,12 +907,8 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
/// To be populated via `context_save`.
|
/// To be populated via `context_save`.
|
||||||
pub fn context_alloc(&self) -> Result<Context, uc_error> {
|
pub fn context_alloc(&self) -> Result<Context, uc_error> {
|
||||||
let mut empty_context: ffi::uc_context = ptr::null_mut();
|
let mut empty_context: ffi::uc_context = ptr::null_mut();
|
||||||
let err = unsafe { ffi::uc_context_alloc(self.get_handle(), &mut empty_context) };
|
unsafe { ffi::uc_context_alloc(self.get_handle(), &mut empty_context) }
|
||||||
if err == uc_error::OK {
|
.and(Ok(Context { context: empty_context }))
|
||||||
Ok(Context { context: empty_context })
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Save current Unicorn context to previously allocated Context struct.
|
/// Save current Unicorn context to previously allocated Context struct.
|
||||||
@@ -1016,12 +916,7 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
&self,
|
&self,
|
||||||
context: &mut Context,
|
context: &mut Context,
|
||||||
) -> Result<(), uc_error> {
|
) -> Result<(), uc_error> {
|
||||||
let err = unsafe { ffi::uc_context_save(self.get_handle(), context.context) };
|
unsafe { ffi::uc_context_save(self.get_handle(), context.context) }.into()
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allocate and return a Context struct initialized with the current CPU context.
|
/// Allocate and return a Context struct initialized with the current CPU context.
|
||||||
@@ -1031,16 +926,15 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
/// individually to avoid unnecessary allocations.
|
/// individually to avoid unnecessary allocations.
|
||||||
pub fn context_init(&self) -> Result<Context, uc_error> {
|
pub fn context_init(&self) -> Result<Context, uc_error> {
|
||||||
let mut new_context: ffi::uc_context = ptr::null_mut();
|
let mut new_context: ffi::uc_context = ptr::null_mut();
|
||||||
let err = unsafe { ffi::uc_context_alloc(self.get_handle(), &mut new_context) };
|
unsafe {
|
||||||
if err != uc_error::OK {
|
ffi::uc_context_alloc(self.get_handle(), &mut new_context).and_then(|| {
|
||||||
return Err(err);
|
ffi::uc_context_save(self.get_handle(), new_context)
|
||||||
}
|
.and(Ok(Context { context: new_context }))
|
||||||
let err = unsafe { ffi::uc_context_save(self.get_handle(), new_context) };
|
.map_err(|e| {
|
||||||
if err == uc_error::OK {
|
ffi::uc_context_free(new_context);
|
||||||
Ok(Context { context: new_context })
|
e
|
||||||
} else {
|
})
|
||||||
unsafe { ffi::uc_context_free(new_context) };
|
})
|
||||||
Err(err)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1053,12 +947,7 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
&self,
|
&self,
|
||||||
context: &Context,
|
context: &Context,
|
||||||
) -> Result<(), uc_error> {
|
) -> Result<(), uc_error> {
|
||||||
let err = unsafe { ffi::uc_context_restore(self.get_handle(), context.context) };
|
unsafe { ffi::uc_context_restore(self.get_handle(), context.context) }.into()
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Emulate machine code for a specified duration.
|
/// Emulate machine code for a specified duration.
|
||||||
@@ -1074,14 +963,7 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
timeout: u64,
|
timeout: u64,
|
||||||
count: usize,
|
count: usize,
|
||||||
) -> Result<(), uc_error> {
|
) -> Result<(), uc_error> {
|
||||||
unsafe {
|
unsafe { ffi::uc_emu_start(self.get_handle(), begin, until, timeout, count as _) }.into()
|
||||||
let err = ffi::uc_emu_start(self.get_handle(), begin, until, timeout, count as _);
|
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Stop the emulation.
|
/// Stop the emulation.
|
||||||
@@ -1089,12 +971,7 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
/// This is usually called from callback function in hooks.
|
/// This is usually called from callback function in hooks.
|
||||||
/// NOTE: For now, this will stop the execution only after the current block.
|
/// NOTE: For now, this will stop the execution only after the current block.
|
||||||
pub fn emu_stop(&mut self) -> Result<(), uc_error> {
|
pub fn emu_stop(&mut self) -> Result<(), uc_error> {
|
||||||
let err = unsafe { ffi::uc_emu_stop(self.get_handle()) };
|
unsafe { ffi::uc_emu_stop(self.get_handle()).into() }
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Query the internal status of the engine.
|
/// Query the internal status of the engine.
|
||||||
@@ -1105,12 +982,7 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
query: Query,
|
query: Query,
|
||||||
) -> Result<usize, uc_error> {
|
) -> Result<usize, uc_error> {
|
||||||
let mut result: libc::size_t = Default::default();
|
let mut result: libc::size_t = Default::default();
|
||||||
let err = unsafe { ffi::uc_query(self.get_handle(), query, &mut result) };
|
unsafe { ffi::uc_query(self.get_handle(), query, &mut result) }.and(Ok(result))
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(result)
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Gets the current program counter for this `unicorn` instance.
|
/// Gets the current program counter for this `unicorn` instance.
|
||||||
@@ -1158,141 +1030,87 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
|
|
||||||
pub fn ctl_get_mode(&self) -> Result<Mode, uc_error> {
|
pub fn ctl_get_mode(&self) -> Result<Mode, uc_error> {
|
||||||
let mut result: i32 = Default::default();
|
let mut result: i32 = Default::default();
|
||||||
let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_MODE), &mut result) };
|
unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_MODE), &mut result) }
|
||||||
if err == uc_error::OK {
|
.and_then(|| Ok(Mode::from_bits_truncate(result)))
|
||||||
Ok(Mode::from_bits_truncate(result))
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ctl_get_page_size(&self) -> Result<u32, uc_error> {
|
pub fn ctl_get_page_size(&self) -> Result<u32, uc_error> {
|
||||||
let mut result: u32 = Default::default();
|
let mut result: u32 = Default::default();
|
||||||
let err =
|
unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_PAGE_SIZE), &mut result) }
|
||||||
unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_PAGE_SIZE), &mut result) };
|
.and_then(|| Ok(result))
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(result)
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ctl_set_page_size(
|
pub fn ctl_set_page_size(
|
||||||
&self,
|
&self,
|
||||||
page_size: u32,
|
page_size: u32,
|
||||||
) -> Result<(), uc_error> {
|
) -> Result<(), uc_error> {
|
||||||
let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_PAGE_SIZE), page_size) };
|
unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_PAGE_SIZE), page_size) }.into()
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ctl_get_arch(&self) -> Result<Arch, uc_error> {
|
pub fn ctl_get_arch(&self) -> Result<Arch, uc_error> {
|
||||||
let mut result: i32 = Default::default();
|
let mut result: i32 = Default::default();
|
||||||
let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_ARCH), &mut result) };
|
unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_ARCH), &mut result) }
|
||||||
if err == uc_error::OK {
|
.and_then(|| Arch::try_from(result as usize))
|
||||||
Arch::try_from(result as usize)
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ctl_get_timeout(&self) -> Result<u64, uc_error> {
|
pub fn ctl_get_timeout(&self) -> Result<u64, uc_error> {
|
||||||
let mut result: u64 = Default::default();
|
let mut result: u64 = Default::default();
|
||||||
let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_TIMEOUT), &mut result) };
|
unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_TIMEOUT), &mut result) }
|
||||||
if err == uc_error::OK {
|
.and(Ok(result))
|
||||||
Ok(result)
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ctl_exits_enable(&self) -> Result<(), uc_error> {
|
pub fn ctl_exits_enable(&self) -> Result<(), uc_error> {
|
||||||
let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_USE_EXITS), 1) };
|
unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_USE_EXITS), 1) }.into()
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ctl_exits_disable(&self) -> Result<(), uc_error> {
|
pub fn ctl_exits_disable(&self) -> Result<(), uc_error> {
|
||||||
let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_USE_EXITS), 0) };
|
unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_USE_EXITS), 0) }.into()
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ctl_get_exits_count(&self) -> Result<usize, uc_error> {
|
pub fn ctl_get_exits_count(&self) -> Result<usize, uc_error> {
|
||||||
let mut result: libc::size_t = Default::default();
|
let mut result: libc::size_t = 0usize;
|
||||||
let err =
|
unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_EXITS_CNT), &mut result) }
|
||||||
unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_EXITS_CNT), &mut result) };
|
.and(Ok(result))
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(result)
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ctl_get_exits(&self) -> Result<Vec<u64>, uc_error> {
|
pub fn ctl_get_exits(&self) -> Result<Vec<u64>, uc_error> {
|
||||||
let exits_count: libc::size_t = self.ctl_get_exits_count()?;
|
let exits_count: libc::size_t = self.ctl_get_exits_count()?;
|
||||||
let mut exits: Vec<u64> = Vec::with_capacity(exits_count);
|
let mut exits: Vec<u64> = Vec::with_capacity(exits_count);
|
||||||
let err = unsafe {
|
unsafe {
|
||||||
ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_EXITS), exits.as_mut_ptr(), exits_count)
|
ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_EXITS), exits.as_mut_ptr(), exits_count)
|
||||||
};
|
|
||||||
if err == uc_error::OK {
|
|
||||||
unsafe {
|
|
||||||
exits.set_len(exits_count);
|
|
||||||
}
|
|
||||||
Ok(exits)
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
}
|
||||||
|
.and_then(|| unsafe {
|
||||||
|
exits.set_len(exits_count);
|
||||||
|
Ok(exits)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ctl_set_exits(
|
pub fn ctl_set_exits(
|
||||||
&self,
|
&self,
|
||||||
exits: &[u64],
|
exits: &[u64],
|
||||||
) -> Result<(), uc_error> {
|
) -> Result<(), uc_error> {
|
||||||
let err = unsafe {
|
unsafe {
|
||||||
ffi::uc_ctl(
|
ffi::uc_ctl(
|
||||||
self.get_handle(),
|
self.get_handle(),
|
||||||
UC_CTL_WRITE!(ControlType::UC_CTL_UC_EXITS),
|
UC_CTL_WRITE!(ControlType::UC_CTL_UC_EXITS),
|
||||||
exits.as_ptr(),
|
exits.as_ptr(),
|
||||||
exits.len() as libc::size_t,
|
exits.len() as libc::size_t,
|
||||||
)
|
)
|
||||||
};
|
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
}
|
||||||
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ctl_get_cpu_model(&self) -> Result<i32, uc_error> {
|
pub fn ctl_get_cpu_model(&self) -> Result<i32, uc_error> {
|
||||||
let mut result: i32 = Default::default();
|
let mut result: i32 = Default::default();
|
||||||
let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_CPU_MODEL), &mut result) };
|
unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_CPU_MODEL), &mut result) }
|
||||||
if err == uc_error::OK {
|
.and(Ok(result))
|
||||||
Ok(result)
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ctl_set_cpu_model(
|
pub fn ctl_set_cpu_model(
|
||||||
&self,
|
&self,
|
||||||
cpu_model: i32,
|
cpu_model: i32,
|
||||||
) -> Result<(), uc_error> {
|
) -> Result<(), uc_error> {
|
||||||
let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_CPU_MODEL), cpu_model) };
|
unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_CPU_MODEL), cpu_model) }.into()
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ctl_remove_cache(
|
pub fn ctl_remove_cache(
|
||||||
@@ -1300,13 +1118,8 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
address: u64,
|
address: u64,
|
||||||
end: u64,
|
end: u64,
|
||||||
) -> Result<(), uc_error> {
|
) -> Result<(), uc_error> {
|
||||||
let err =
|
unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TB_REMOVE_CACHE), address, end) }
|
||||||
unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TB_REMOVE_CACHE), address, end) };
|
.into()
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ctl_request_cache(
|
pub fn ctl_request_cache(
|
||||||
@@ -1314,43 +1127,22 @@ impl<'a, D> Unicorn<'a, D> {
|
|||||||
address: u64,
|
address: u64,
|
||||||
tb: &mut TranslationBlock,
|
tb: &mut TranslationBlock,
|
||||||
) -> Result<(), uc_error> {
|
) -> Result<(), uc_error> {
|
||||||
let err = unsafe {
|
unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ_WRITE!(ControlType::UC_CTL_TB_REQUEST_CACHE), address, tb) }
|
||||||
ffi::uc_ctl(self.get_handle(), UC_CTL_READ_WRITE!(ControlType::UC_CTL_TB_REQUEST_CACHE), address, tb)
|
.into()
|
||||||
};
|
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ctl_flush_tb(&self) -> Result<(), uc_error> {
|
pub fn ctl_flush_tb(&self) -> Result<(), uc_error> {
|
||||||
let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TB_FLUSH)) };
|
unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TB_FLUSH)) }.into()
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ctl_flush_tlb(&self) -> Result<(), uc_error> {
|
pub fn ctl_flush_tlb(&self) -> Result<(), uc_error> {
|
||||||
let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TLB_FLUSH)) };
|
unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TLB_FLUSH)) }.into()
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn ctl_tlb_type(
|
pub fn ctl_tlb_type(
|
||||||
&self,
|
&self,
|
||||||
t: TlbType,
|
t: TlbType,
|
||||||
) -> Result<(), uc_error> {
|
) -> Result<(), uc_error> {
|
||||||
let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TLB_TYPE), t as i32) };
|
unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TLB_TYPE), t as i32) }.into()
|
||||||
if err == uc_error::OK {
|
|
||||||
Ok(())
|
|
||||||
} else {
|
|
||||||
Err(err)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,49 +14,88 @@ pub const MILISECOND_SCALE: u64 = 1_000;
|
|||||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
pub enum uc_error {
|
pub enum uc_error {
|
||||||
OK = 0,
|
OK = 0,
|
||||||
NOMEM = 1,
|
NOMEM = 1,
|
||||||
ARCH = 2,
|
ARCH = 2,
|
||||||
HANDLE = 3,
|
HANDLE = 3,
|
||||||
MODE = 4,
|
MODE = 4,
|
||||||
VERSION = 5,
|
VERSION = 5,
|
||||||
READ_UNMAPPED = 6,
|
READ_UNMAPPED = 6,
|
||||||
WRITE_UNMAPPED = 7,
|
WRITE_UNMAPPED = 7,
|
||||||
FETCH_UNMAPPED = 8,
|
FETCH_UNMAPPED = 8,
|
||||||
HOOK = 9,
|
HOOK = 9,
|
||||||
INSN_INVALID = 10,
|
INSN_INVALID = 10,
|
||||||
MAP = 11,
|
MAP = 11,
|
||||||
WRITE_PROT = 12,
|
WRITE_PROT = 12,
|
||||||
READ_PROT = 13,
|
READ_PROT = 13,
|
||||||
FETCH_PROT = 14,
|
FETCH_PROT = 14,
|
||||||
ARG = 15,
|
ARG = 15,
|
||||||
READ_UNALIGNED = 16,
|
READ_UNALIGNED = 16,
|
||||||
WRITE_UNALIGNED = 17,
|
WRITE_UNALIGNED = 17,
|
||||||
FETCH_UNALIGNED = 18,
|
FETCH_UNALIGNED = 18,
|
||||||
HOOK_EXIST = 19,
|
HOOK_EXIST = 19,
|
||||||
RESOURCE = 20,
|
RESOURCE = 20,
|
||||||
EXCEPTION = 21,
|
EXCEPTION = 21,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl uc_error {
|
||||||
|
/// Calls op if the result is Ok, otherwise returns the Err value of self.
|
||||||
|
/// This function can be used for control flow based on Result values.
|
||||||
|
pub fn and_then<U, F: FnOnce() -> Result<U, uc_error>>(
|
||||||
|
self,
|
||||||
|
op: F,
|
||||||
|
) -> Result<U, uc_error> {
|
||||||
|
if let Self::OK = self {
|
||||||
|
op()
|
||||||
|
} else {
|
||||||
|
Err(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns res if the result is Ok, otherwise returns the Err value of self.
|
||||||
|
/// Arguments passed to and are eagerly evaluated; if you are passing the result
|
||||||
|
/// of a function call, it is recommended to use and_then, which is lazily evaluated.
|
||||||
|
pub fn and<U>(
|
||||||
|
self,
|
||||||
|
res: Result<U, uc_error>,
|
||||||
|
) -> Result<U, uc_error> {
|
||||||
|
if let Self::OK = self {
|
||||||
|
res
|
||||||
|
} else {
|
||||||
|
Err(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<uc_error> for Result<(), uc_error> {
|
||||||
|
fn from(value: uc_error) -> Self {
|
||||||
|
if let uc_error::OK = value {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||||
pub enum MemType {
|
pub enum MemType {
|
||||||
READ = 16,
|
READ = 16,
|
||||||
WRITE = 17,
|
WRITE = 17,
|
||||||
FETCH = 18,
|
FETCH = 18,
|
||||||
READ_UNMAPPED = 19,
|
READ_UNMAPPED = 19,
|
||||||
WRITE_UNMAPPED = 20,
|
WRITE_UNMAPPED = 20,
|
||||||
FETCH_UNMAPPED = 21,
|
FETCH_UNMAPPED = 21,
|
||||||
WRITE_PROT = 22,
|
WRITE_PROT = 22,
|
||||||
READ_PROT = 23,
|
READ_PROT = 23,
|
||||||
FETCH_PROT = 24,
|
FETCH_PROT = 24,
|
||||||
READ_AFTER = 25,
|
READ_AFTER = 25,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||||
pub enum TlbType {
|
pub enum TlbType {
|
||||||
CPU = 0,
|
CPU = 0,
|
||||||
VIRTUAL = 1,
|
VIRTUAL = 1,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,10 +142,10 @@ bitflags! {
|
|||||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||||
#[allow(clippy::upper_case_acronyms)]
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
pub enum Query {
|
pub enum Query {
|
||||||
MODE = 1,
|
MODE = 1,
|
||||||
PAGE_SIZE = 2,
|
PAGE_SIZE = 2,
|
||||||
ARCH = 3,
|
ARCH = 3,
|
||||||
TIMEOUT = 4,
|
TIMEOUT = 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
@@ -132,17 +171,17 @@ pub struct MemRegion {
|
|||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(PartialEq, Debug, Clone, Copy)]
|
#[derive(PartialEq, Debug, Clone, Copy)]
|
||||||
pub enum Arch {
|
pub enum Arch {
|
||||||
ARM = 1,
|
ARM = 1,
|
||||||
ARM64 = 2,
|
ARM64 = 2,
|
||||||
MIPS = 3,
|
MIPS = 3,
|
||||||
X86 = 4,
|
X86 = 4,
|
||||||
PPC = 5,
|
PPC = 5,
|
||||||
SPARC = 6,
|
SPARC = 6,
|
||||||
M68K = 7,
|
M68K = 7,
|
||||||
RISCV = 8,
|
RISCV = 8,
|
||||||
S390X = 9,
|
S390X = 9,
|
||||||
TRICORE = 10,
|
TRICORE = 10,
|
||||||
MAX = 11,
|
MAX = 11,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<usize> for Arch {
|
impl TryFrom<usize> for Arch {
|
||||||
@@ -205,7 +244,7 @@ bitflags! {
|
|||||||
pub struct TranslationBlock {
|
pub struct TranslationBlock {
|
||||||
pub pc: u64,
|
pub pc: u64,
|
||||||
pub icount: u16,
|
pub icount: u16,
|
||||||
pub size: u16
|
pub size: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
macro_rules! UC_CTL_READ {
|
macro_rules! UC_CTL_READ {
|
||||||
@@ -229,21 +268,21 @@ macro_rules! UC_CTL_READ_WRITE {
|
|||||||
#[allow(clippy::upper_case_acronyms)]
|
#[allow(clippy::upper_case_acronyms)]
|
||||||
#[repr(u64)]
|
#[repr(u64)]
|
||||||
pub enum ControlType {
|
pub enum ControlType {
|
||||||
UC_CTL_UC_MODE = 0,
|
UC_CTL_UC_MODE = 0,
|
||||||
UC_CTL_UC_PAGE_SIZE = 1,
|
UC_CTL_UC_PAGE_SIZE = 1,
|
||||||
UC_CTL_UC_ARCH = 2,
|
UC_CTL_UC_ARCH = 2,
|
||||||
UC_CTL_UC_TIMEOUT = 3,
|
UC_CTL_UC_TIMEOUT = 3,
|
||||||
UC_CTL_UC_USE_EXITS = 4,
|
UC_CTL_UC_USE_EXITS = 4,
|
||||||
UC_CTL_UC_EXITS_CNT = 5,
|
UC_CTL_UC_EXITS_CNT = 5,
|
||||||
UC_CTL_UC_EXITS = 6,
|
UC_CTL_UC_EXITS = 6,
|
||||||
UC_CTL_CPU_MODEL = 7,
|
UC_CTL_CPU_MODEL = 7,
|
||||||
UC_CTL_TB_REQUEST_CACHE = 8,
|
UC_CTL_TB_REQUEST_CACHE = 8,
|
||||||
UC_CTL_TB_REMOVE_CACHE = 9,
|
UC_CTL_TB_REMOVE_CACHE = 9,
|
||||||
UC_CTL_TB_FLUSH = 10,
|
UC_CTL_TB_FLUSH = 10,
|
||||||
UC_CTL_TLB_FLUSH = 11,
|
UC_CTL_TLB_FLUSH = 11,
|
||||||
UC_CTL_TLB_TYPE = 12,
|
UC_CTL_TLB_TYPE = 12,
|
||||||
UC_CTL_IO_READ = 1<<31,
|
UC_CTL_IO_READ = 1 << 31,
|
||||||
UC_CTL_IO_WRITE = 1<<30,
|
UC_CTL_IO_WRITE = 1 << 30,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
|
|||||||
Reference in New Issue
Block a user