removed need for extra api; no_std

This commit is contained in:
Dominik Maier
2021-11-10 04:11:14 +01:00
parent 492779d7d4
commit 177b21c2af
6 changed files with 311 additions and 293 deletions

View File

@@ -4,8 +4,8 @@
use crate::Unicorn;
use super::unicorn_const::{uc_error, Arch, HookType, MemRegion, MemType, Mode, Query};
use core::ffi::c_void;
use libc::{c_char, c_int};
use std::{ffi::c_void, marker::PhantomData};
pub type uc_handle = *mut c_void;
pub type uc_hook = *mut c_void;
@@ -76,30 +76,17 @@ extern "C" {
pub fn uc_context_alloc(engine: uc_handle, context: *mut uc_context) -> uc_error;
pub fn uc_context_save(engine: uc_handle, context: uc_context) -> uc_error;
pub fn uc_context_restore(engine: uc_handle, context: uc_context) -> uc_error;
pub fn uc_set_data_ptr(engine: uc_handle, ptr: *mut c_void) -> uc_error;
pub fn uc_get_data_ptr(engine: uc_handle) -> *mut c_void;
}
pub struct UcHook<'a, D: 'a, F: 'a> {
pub callback: F,
pub phantom: PhantomData<&'a D>,
pub uc: Unicorn<'a, D>,
}
pub trait IsUcHook<'a> {}
impl<'a, D, F> IsUcHook<'a> for UcHook<'a, D, F> {}
fn read_uc_from_uc_handle<'a, D>(uc: uc_handle) -> &'a mut crate::Unicorn<'a, D>
where
D: 'a,
{
unsafe {
(uc_get_data_ptr(uc) as *mut Unicorn<'a, D>)
.as_mut()
.unwrap()
}
}
pub extern "C" fn code_hook_proxy<D, F>(
uc: uc_handle,
address: u64,
@@ -108,10 +95,9 @@ pub extern "C" fn code_hook_proxy<D, F>(
) where
F: FnMut(&mut crate::Unicorn<D>, u64, u32),
{
let unicorn = read_uc_from_uc_handle(uc);
let callback = unsafe { &mut (*user_data).callback };
assert_eq!(uc, unicorn.uc);
callback(unicorn, address, size);
let user_data = unsafe { &mut *user_data };
debug_assert_eq!(uc, user_data.uc.inner().uc);
(user_data.callback)(&mut user_data.uc, address, size);
}
pub extern "C" fn block_hook_proxy<D, F>(
@@ -122,10 +108,9 @@ pub extern "C" fn block_hook_proxy<D, F>(
) where
F: FnMut(&mut crate::Unicorn<D>, u64, u32),
{
let unicorn = read_uc_from_uc_handle(uc);
let callback = unsafe { &mut (*user_data).callback };
assert_eq!(uc, unicorn.uc);
callback(unicorn, address, size);
let user_data = unsafe { &mut *user_data };
debug_assert_eq!(uc, user_data.uc.inner().uc);
(user_data.callback)(&mut user_data.uc, address, size);
}
pub extern "C" fn mem_hook_proxy<D, F>(
@@ -139,20 +124,18 @@ pub extern "C" fn mem_hook_proxy<D, F>(
where
F: FnMut(&mut crate::Unicorn<D>, MemType, u64, usize, i64) -> bool,
{
let unicorn = read_uc_from_uc_handle(uc);
let callback = unsafe { &mut (*user_data).callback };
assert_eq!(uc, unicorn.uc);
callback(unicorn, mem_type, address, size as usize, value)
let user_data = unsafe { &mut *user_data };
debug_assert_eq!(uc, user_data.uc.inner().uc);
(user_data.callback)(&mut user_data.uc, mem_type, address, size as usize, value)
}
pub extern "C" fn intr_hook_proxy<D, F>(uc: uc_handle, value: u32, user_data: *mut UcHook<D, F>)
where
F: FnMut(&mut crate::Unicorn<D>, u32),
{
let unicorn = read_uc_from_uc_handle(uc);
let callback = unsafe { &mut (*user_data).callback };
assert_eq!(uc, unicorn.uc);
callback(unicorn, value);
let user_data = unsafe { &mut *user_data };
debug_assert_eq!(uc, user_data.uc.inner().uc);
(user_data.callback)(&mut user_data.uc, value);
}
pub extern "C" fn insn_in_hook_proxy<D, F>(
@@ -163,10 +146,9 @@ pub extern "C" fn insn_in_hook_proxy<D, F>(
) where
F: FnMut(&mut crate::Unicorn<D>, u32, usize),
{
let unicorn = read_uc_from_uc_handle(uc);
let callback = unsafe { &mut (*user_data).callback };
assert_eq!(uc, unicorn.uc);
callback(unicorn, port, size);
let user_data = unsafe { &mut *user_data };
debug_assert_eq!(uc, user_data.uc.inner().uc);
(user_data.callback)(&mut user_data.uc, port, size);
}
pub extern "C" fn insn_out_hook_proxy<D, F>(
@@ -178,18 +160,16 @@ pub extern "C" fn insn_out_hook_proxy<D, F>(
) where
F: FnMut(&mut crate::Unicorn<D>, u32, usize, u32),
{
let unicorn = read_uc_from_uc_handle(uc);
let callback = unsafe { &mut (*user_data).callback };
assert_eq!(uc, unicorn.uc);
callback(unicorn, port, size, value);
let user_data = unsafe { &mut *user_data };
debug_assert_eq!(uc, user_data.uc.inner().uc);
(user_data.callback)(&mut user_data.uc, port, size, value);
}
pub extern "C" fn insn_sys_hook_proxy<D, F>(uc: uc_handle, user_data: *mut UcHook<D, F>)
where
F: FnMut(&mut crate::Unicorn<D>),
{
let unicorn = read_uc_from_uc_handle(uc);
assert_eq!(uc, unicorn.uc);
let callback = unsafe { &mut (*user_data).callback };
callback(unicorn);
let user_data = unsafe { &mut *user_data };
debug_assert_eq!(uc, user_data.uc.inner().uc);
(user_data.callback)(&mut user_data.uc);
}

View File

@@ -27,21 +27,29 @@
//! ```
//!
mod ffi;
#![no_std]
#[macro_use]
extern crate alloc;
pub mod unicorn_const;
mod arm;
mod arm64;
mod ffi;
mod m68k;
mod mips;
mod ppc;
mod riscv;
mod sparc;
mod x86;
use std::{marker::PhantomData, ptr};
pub use crate::{arm::*, arm64::*, m68k::*, mips::*, ppc::*, riscv::*, sparc::*, x86::*};
pub use crate::{
arm::*, arm64::*, m68k::*, mips::*, ppc::*, riscv::*, sparc::*, unicorn_const::*, x86::*,
};
use alloc::{boxed::Box, rc::Rc, vec::Vec};
use core::{cell::UnsafeCell, ptr};
use ffi::uc_handle;
use libc::c_void;
use unicorn_const::{uc_error, Arch, HookType, MemRegion, MemType, Mode, Permission, Query};
@@ -69,8 +77,7 @@ impl Drop for Context {
}
}
/// A Unicorn emulator instance.
pub struct Unicorn<'a, D: 'a> {
pub struct UnicornInner<'a, D> {
pub uc: uc_handle,
pub arch: Arch,
/// to keep ownership over the hook for this uc instance's lifetime
@@ -78,6 +85,21 @@ pub struct Unicorn<'a, D: 'a> {
pub data: D,
}
/// Drop UC
impl<'a, D> Drop for UnicornInner<'a, D> {
fn drop(&mut self) {
if !self.uc.is_null() {
unsafe { ffi::uc_close(self.uc) };
}
self.uc = ptr::null_mut();
}
}
/// A Unicorn emulator instance.
pub struct Unicorn<'a, D: 'a> {
inner: Rc<UnsafeCell<UnicornInner<'a, D>>>,
}
impl<'a> Unicorn<'a, ()> {
/// Create a new instance of the unicorn engine for the specified architecture
/// and hardware mode.
@@ -93,14 +115,16 @@ where
/// Create a new instance of the unicorn engine for the specified architecture
/// and hardware mode.
pub fn new_with_data(arch: Arch, mode: Mode, data: D) -> Result<Unicorn<'a, D>, uc_error> {
let mut handle = std::ptr::null_mut();
let mut handle = core::ptr::null_mut();
let err = unsafe { ffi::uc_open(arch, mode, &mut handle) };
if err == uc_error::OK {
Ok(Unicorn {
uc: handle,
arch,
data,
hooks: vec![],
inner: Rc::new(UnsafeCell::from(UnicornInner {
uc: handle,
arch,
data,
hooks: vec![],
})),
})
} else {
Err(err)
@@ -108,50 +132,51 @@ where
}
}
/// Drop UC
impl<'a, D> Drop for Unicorn<'a, D> {
fn drop(&mut self) {
if !self.uc.is_null() {
unsafe { ffi::uc_close(self.uc) };
}
self.uc = ptr::null_mut();
}
}
impl<'a, D> std::fmt::Debug for Unicorn<'a, D> {
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(formatter, "Unicorn {{ uc: {:p} }}", self.uc)
impl<'a, D> core::fmt::Debug for Unicorn<'a, D> {
fn fmt(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(formatter, "Unicorn {{ uc: {:p} }}", self.inner().uc)
}
}
impl<'a, D> Unicorn<'a, D> {
fn inner(&self) -> &UnicornInner<'a, D> {
unsafe { self.inner.get().as_ref().unwrap() }
}
fn inner_mut(&mut self) -> &mut UnicornInner<'a, D> {
unsafe { self.inner.get().as_mut().unwrap() }
}
/// Return whatever data was passed during initialization.
///
/// For an example, have a look at `utils::init_emu_with_heap` where
/// a struct is passed which is used for a custom allocator.
#[must_use]
pub fn get_data(&self) -> &D {
&self.data
&self.inner().data
}
/// Return a mutable reference to whatever data was passed during initialization.
#[must_use]
pub fn get_data_mut(&mut self) -> &mut D {
&mut self.data
&mut self.inner_mut().data
}
/// Return the architecture of the current emulator.
#[must_use]
pub fn get_arch(&self) -> Arch {
self.arch
self.inner().arch
}
/// Returns a vector with the memory regions that are mapped in the emulator.
pub fn mem_regions(&self) -> Result<Vec<MemRegion>, uc_error> {
let mut nb_regions: u32 = 0;
let p_regions: *const MemRegion = std::ptr::null_mut();
let err = unsafe { ffi::uc_mem_regions(self.uc, &p_regions, &mut nb_regions) };
let p_regions: *const MemRegion = core::ptr::null_mut();
let err = unsafe { ffi::uc_mem_regions(self.inner().uc, &p_regions, &mut nb_regions) };
if err == uc_error::OK {
let mut regions = Vec::new();
for i in 0..nb_regions {
regions.push(unsafe { std::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 _) };
Ok(regions)
@@ -162,7 +187,8 @@ impl<'a, D> Unicorn<'a, D> {
/// Read a range of bytes from memory at the specified address.
pub fn mem_read(&self, address: u64, buf: &mut [u8]) -> Result<(), uc_error> {
let err = unsafe { ffi::uc_mem_read(self.uc, address, buf.as_mut_ptr(), buf.len()) };
let err =
unsafe { ffi::uc_mem_read(self.inner().uc, address, buf.as_mut_ptr(), buf.len()) };
if err == uc_error::OK {
Ok(())
} else {
@@ -173,7 +199,7 @@ impl<'a, D> Unicorn<'a, D> {
/// Return a range of bytes from memory at the specified address as vector.
pub fn mem_read_as_vec(&self, address: u64, size: usize) -> Result<Vec<u8>, uc_error> {
let mut buf = vec![0; size];
let err = unsafe { ffi::uc_mem_read(self.uc, address, buf.as_mut_ptr(), size) };
let err = unsafe { ffi::uc_mem_read(self.inner().uc, address, buf.as_mut_ptr(), size) };
if err == uc_error::OK {
Ok(buf)
} else {
@@ -182,7 +208,8 @@ impl<'a, D> Unicorn<'a, D> {
}
pub fn mem_write(&mut self, address: u64, bytes: &[u8]) -> Result<(), uc_error> {
let err = unsafe { ffi::uc_mem_write(self.uc, address, bytes.as_ptr(), bytes.len()) };
let err =
unsafe { ffi::uc_mem_write(self.inner().uc, address, bytes.as_ptr(), bytes.len()) };
if err == uc_error::OK {
Ok(())
} else {
@@ -210,7 +237,7 @@ impl<'a, D> Unicorn<'a, D> {
perms: Permission,
ptr: *mut c_void,
) -> Result<(), uc_error> {
let err = ffi::uc_mem_map_ptr(self.uc, address, size, perms.bits(), ptr);
let err = ffi::uc_mem_map_ptr(self.inner().uc, address, size, perms.bits(), ptr);
if err == uc_error::OK {
Ok(())
} else {
@@ -228,7 +255,7 @@ impl<'a, D> Unicorn<'a, D> {
size: libc::size_t,
perms: Permission,
) -> Result<(), uc_error> {
let err = unsafe { ffi::uc_mem_map(self.uc, address, size, perms.bits()) };
let err = unsafe { ffi::uc_mem_map(self.inner().uc, address, size, perms.bits()) };
if err == uc_error::OK {
Ok(())
} else {
@@ -241,7 +268,7 @@ impl<'a, D> Unicorn<'a, D> {
/// `address` must be aligned to 4kb or this will return `Error::ARG`.
/// `size` must be a multiple of 4kb or this will return `Error::ARG`.
pub fn mem_unmap(&mut self, address: u64, size: libc::size_t) -> Result<(), uc_error> {
let err = unsafe { ffi::uc_mem_unmap(self.uc, address, size) };
let err = unsafe { ffi::uc_mem_unmap(self.inner().uc, address, size) };
if err == uc_error::OK {
Ok(())
} else {
@@ -259,7 +286,7 @@ impl<'a, D> Unicorn<'a, D> {
size: libc::size_t,
perms: Permission,
) -> Result<(), uc_error> {
let err = unsafe { ffi::uc_mem_protect(self.uc, address, size, perms.bits()) };
let err = unsafe { ffi::uc_mem_protect(self.inner().uc, address, size, perms.bits()) };
if err == uc_error::OK {
Ok(())
} else {
@@ -269,7 +296,8 @@ impl<'a, D> Unicorn<'a, D> {
/// Write an unsigned value from a register.
pub fn reg_write<T: Into<i32>>(&mut self, regid: T, value: u64) -> Result<(), uc_error> {
let err = unsafe { ffi::uc_reg_write(self.uc, regid.into(), &value as *const _ as _) };
let err =
unsafe { ffi::uc_reg_write(self.inner().uc, regid.into(), &value as *const _ as _) };
if err == uc_error::OK {
Ok(())
} else {
@@ -282,7 +310,7 @@ impl<'a, D> Unicorn<'a, D> {
/// The user has to make sure that the buffer length matches the register size.
/// This adds support for registers >64 bit (GDTR/IDTR, XMM, YMM, ZMM, ST (x86); Q, V (arm64)).
pub fn reg_write_long<T: Into<i32>>(&self, regid: T, value: &[u8]) -> Result<(), uc_error> {
let err = unsafe { ffi::uc_reg_write(self.uc, regid.into(), value.as_ptr() as _) };
let err = unsafe { ffi::uc_reg_write(self.inner().uc, regid.into(), value.as_ptr() as _) };
if err == uc_error::OK {
Ok(())
} else {
@@ -295,7 +323,8 @@ impl<'a, D> Unicorn<'a, D> {
/// Not to be used with registers larger than 64 bit.
pub fn reg_read<T: Into<i32>>(&self, regid: T) -> Result<u64, uc_error> {
let mut value: u64 = 0;
let err = unsafe { ffi::uc_reg_read(self.uc, regid.into(), &mut value as *mut u64 as _) };
let err =
unsafe { ffi::uc_reg_read(self.inner().uc, regid.into(), &mut value as *mut u64 as _) };
if err == uc_error::OK {
Ok(value)
} else {
@@ -349,7 +378,7 @@ impl<'a, D> Unicorn<'a, D> {
return Err(uc_error::ARCH);
}
err = unsafe { ffi::uc_reg_read(self.uc, curr_reg_id, value.as_mut_ptr() as _) };
err = unsafe { ffi::uc_reg_read(self.inner().uc, curr_reg_id, value.as_mut_ptr() as _) };
if err == uc_error::OK {
boxed = value.into_boxed_slice();
@@ -362,7 +391,8 @@ impl<'a, D> Unicorn<'a, D> {
/// Read a signed 32-bit value from a register.
pub fn reg_read_i32<T: Into<i32>>(&self, regid: T) -> Result<i32, uc_error> {
let mut value: i32 = 0;
let err = unsafe { ffi::uc_reg_read(self.uc, regid.into(), &mut value as *mut i32 as _) };
let err =
unsafe { ffi::uc_reg_read(self.inner().uc, regid.into(), &mut value as *mut i32 as _) };
if err == uc_error::OK {
Ok(value)
} else {
@@ -380,15 +410,17 @@ impl<'a, D> Unicorn<'a, D> {
where
F: FnMut(&mut crate::Unicorn<D>, u64, u32) + 'a,
{
let mut hook_ptr = std::ptr::null_mut();
let mut hook_ptr = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
phantom: PhantomData::<&D>,
uc: Unicorn {
inner: self.inner.clone(),
},
});
let err = unsafe {
ffi::uc_hook_add(
self.uc,
self.inner().uc,
&mut hook_ptr,
HookType::CODE,
ffi::code_hook_proxy::<D, F> as _,
@@ -398,7 +430,7 @@ impl<'a, D> Unicorn<'a, D> {
)
};
if err == uc_error::OK {
self.hooks.push((hook_ptr, user_data));
self.inner_mut().hooks.push((hook_ptr, user_data));
Ok(hook_ptr)
} else {
Err(err)
@@ -410,15 +442,17 @@ impl<'a, D> Unicorn<'a, D> {
where
F: FnMut(&mut Unicorn<D>, u64, u32),
{
let mut hook_ptr = std::ptr::null_mut();
let mut hook_ptr = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
phantom: PhantomData::<&D>,
uc: Unicorn {
inner: self.inner.clone(),
},
});
let err = unsafe {
ffi::uc_hook_add(
self.uc,
self.inner().uc,
&mut hook_ptr,
HookType::BLOCK,
ffi::block_hook_proxy::<D, F> as _,
@@ -428,7 +462,7 @@ impl<'a, D> Unicorn<'a, D> {
)
};
if err == uc_error::OK {
self.hooks.push((hook_ptr, user_data));
self.inner_mut().hooks.push((hook_ptr, user_data));
Ok(hook_ptr)
} else {
@@ -451,15 +485,17 @@ impl<'a, D> Unicorn<'a, D> {
return Err(uc_error::ARG);
}
let mut hook_ptr = std::ptr::null_mut();
let mut hook_ptr = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
phantom: PhantomData::<&D>,
uc: Unicorn {
inner: self.inner.clone(),
},
});
let err = unsafe {
ffi::uc_hook_add(
self.uc,
self.inner().uc,
&mut hook_ptr,
hook_type,
ffi::mem_hook_proxy::<D, F> as _,
@@ -469,7 +505,7 @@ impl<'a, D> Unicorn<'a, D> {
)
};
if err == uc_error::OK {
self.hooks.push((hook_ptr, user_data));
self.inner_mut().hooks.push((hook_ptr, user_data));
Ok(hook_ptr)
} else {
@@ -482,15 +518,17 @@ impl<'a, D> Unicorn<'a, D> {
where
F: FnMut(&mut Unicorn<D>, u32),
{
let mut hook_ptr = std::ptr::null_mut();
let mut hook_ptr = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
phantom: PhantomData::<&D>,
uc: Unicorn {
inner: self.inner.clone(),
},
});
let err = unsafe {
ffi::uc_hook_add(
self.uc,
self.inner().uc,
&mut hook_ptr,
HookType::INTR,
ffi::intr_hook_proxy::<D, F> as _,
@@ -500,7 +538,7 @@ impl<'a, D> Unicorn<'a, D> {
)
};
if err == uc_error::OK {
self.hooks.push((hook_ptr, user_data));
self.inner_mut().hooks.push((hook_ptr, user_data));
Ok(hook_ptr)
} else {
@@ -511,17 +549,19 @@ impl<'a, D> Unicorn<'a, D> {
/// Add hook for x86 IN instruction.
pub fn add_insn_in_hook<F: 'a>(&mut self, callback: F) -> Result<ffi::uc_hook, uc_error>
where
F: FnMut(&mut Unicorn<D>, u32, usize) + 'a,
F: FnMut(&mut Unicorn<D>, u32, usize),
{
let mut hook_ptr = std::ptr::null_mut();
let mut hook_ptr = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
phantom: PhantomData::<&D>,
uc: Unicorn {
inner: self.inner.clone(),
},
});
let err = unsafe {
ffi::uc_hook_add(
self.uc,
self.inner().uc,
&mut hook_ptr,
HookType::INSN,
ffi::insn_in_hook_proxy::<D, F> as _,
@@ -532,7 +572,7 @@ impl<'a, D> Unicorn<'a, D> {
)
};
if err == uc_error::OK {
self.hooks.push((hook_ptr, user_data));
self.inner_mut().hooks.push((hook_ptr, user_data));
Ok(hook_ptr)
} else {
@@ -543,17 +583,19 @@ impl<'a, D> Unicorn<'a, D> {
/// Add hook for x86 OUT instruction.
pub fn add_insn_out_hook<F: 'a>(&mut self, callback: F) -> Result<ffi::uc_hook, uc_error>
where
F: FnMut(&mut Unicorn<D>, u32, usize, u32) + 'a,
F: FnMut(&mut Unicorn<D>, u32, usize, u32),
{
let mut hook_ptr = std::ptr::null_mut();
let mut hook_ptr = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
phantom: PhantomData::<&D>,
uc: Unicorn {
inner: self.inner.clone(),
},
});
let err = unsafe {
ffi::uc_hook_add(
self.uc,
self.inner().uc,
&mut hook_ptr,
HookType::INSN,
ffi::insn_out_hook_proxy::<D, F> as _,
@@ -564,7 +606,7 @@ impl<'a, D> Unicorn<'a, D> {
)
};
if err == uc_error::OK {
self.hooks.push((hook_ptr, user_data));
self.inner_mut().hooks.push((hook_ptr, user_data));
Ok(hook_ptr)
} else {
@@ -583,15 +625,17 @@ impl<'a, D> Unicorn<'a, D> {
where
F: FnMut(&mut Unicorn<D>) + 'a,
{
let mut hook_ptr = std::ptr::null_mut();
let mut hook_ptr = core::ptr::null_mut();
let mut user_data = Box::new(ffi::UcHook {
callback,
phantom: PhantomData::<&D>,
uc: Unicorn {
inner: self.inner.clone(),
},
});
let err = unsafe {
ffi::uc_hook_add(
self.uc,
self.inner().uc,
&mut hook_ptr,
HookType::INSN,
ffi::insn_sys_hook_proxy::<D, F> as _,
@@ -602,7 +646,7 @@ impl<'a, D> Unicorn<'a, D> {
)
};
if err == uc_error::OK {
self.hooks.push((hook_ptr, user_data));
self.inner_mut().hooks.push((hook_ptr, user_data));
Ok(hook_ptr)
} else {
@@ -617,10 +661,11 @@ impl<'a, D> Unicorn<'a, D> {
let err: uc_error;
// drop the hook
self.hooks
self.inner_mut()
.hooks
.retain(|(hook_ptr, _hook_impl)| hook_ptr != &hook);
err = unsafe { ffi::uc_hook_del(self.uc, hook) };
err = unsafe { ffi::uc_hook_del(self.inner().uc, hook) };
if err == uc_error::OK {
Ok(())
@@ -634,7 +679,7 @@ impl<'a, D> Unicorn<'a, D> {
/// To be populated via `context_save`.
pub fn context_alloc(&self) -> Result<Context, uc_error> {
let mut empty_context: ffi::uc_context = ptr::null_mut();
let err = unsafe { ffi::uc_context_alloc(self.uc, &mut empty_context) };
let err = unsafe { ffi::uc_context_alloc(self.inner().uc, &mut empty_context) };
if err == uc_error::OK {
Ok(Context {
context: empty_context,
@@ -646,7 +691,7 @@ impl<'a, D> Unicorn<'a, D> {
/// Save current Unicorn context to previously allocated Context struct.
pub fn context_save(&self, context: &mut Context) -> Result<(), uc_error> {
let err = unsafe { ffi::uc_context_save(self.uc, context.context) };
let err = unsafe { ffi::uc_context_save(self.inner().uc, context.context) };
if err == uc_error::OK {
Ok(())
} else {
@@ -661,11 +706,11 @@ impl<'a, D> Unicorn<'a, D> {
/// individually to avoid unnecessary allocations.
pub fn context_init(&self) -> Result<Context, uc_error> {
let mut new_context: ffi::uc_context = ptr::null_mut();
let err = unsafe { ffi::uc_context_alloc(self.uc, &mut new_context) };
let err = unsafe { ffi::uc_context_alloc(self.inner().uc, &mut new_context) };
if err != uc_error::OK {
return Err(err);
}
let err = unsafe { ffi::uc_context_save(self.uc, new_context) };
let err = unsafe { ffi::uc_context_save(self.inner().uc, new_context) };
if err == uc_error::OK {
Ok(Context {
context: new_context,
@@ -682,7 +727,7 @@ impl<'a, D> Unicorn<'a, D> {
/// internal metadata. Contexts may not be shared across engine instances with
/// differing arches or modes. Memory has to be restored manually, if needed.
pub fn context_restore(&self, context: &Context) -> Result<(), uc_error> {
let err = unsafe { ffi::uc_context_restore(self.uc, context.context) };
let err = unsafe { ffi::uc_context_restore(self.inner().uc, context.context) };
if err == uc_error::OK {
Ok(())
} else {
@@ -704,9 +749,7 @@ impl<'a, D> Unicorn<'a, D> {
count: usize,
) -> Result<(), uc_error> {
unsafe {
ffi::uc_set_data_ptr(self.uc, self as *mut _ as *mut _);
let err = ffi::uc_emu_start(self.uc, begin, until, timeout, count as _);
ffi::uc_set_data_ptr(self.uc, ptr::null_mut());
let err = ffi::uc_emu_start(self.inner().uc, begin, until, timeout, count as _);
if err == uc_error::OK {
Ok(())
} else {
@@ -720,7 +763,7 @@ impl<'a, D> Unicorn<'a, D> {
/// This is usually called from callback function in hooks.
/// NOTE: For now, this will stop the execution only after the current block.
pub fn emu_stop(&mut self) -> Result<(), uc_error> {
let err = unsafe { ffi::uc_emu_stop(self.uc) };
let err = unsafe { ffi::uc_emu_stop(self.inner().uc) };
if err == uc_error::OK {
Ok(())
} else {
@@ -733,7 +776,7 @@ impl<'a, D> Unicorn<'a, D> {
/// supported: `MODE`, `PAGE_SIZE`, `ARCH`
pub fn query(&self, query: Query) -> Result<usize, uc_error> {
let mut result: libc::size_t = Default::default();
let err = unsafe { ffi::uc_query(self.uc, query, &mut result) };
let err = unsafe { ffi::uc_query(self.inner().uc, query, &mut result) };
if err == uc_error::OK {
Ok(result)
} else {
@@ -754,7 +797,7 @@ impl<'a, D> Unicorn<'a, D> {
Arch::M68K => RegisterM68K::PC as i32,
Arch::PPC => RegisterPPC::PC as i32,
Arch::RISCV => RegisterRISCV::PC as i32,
_ => panic!("Arch pc not yet know to the unicorn rust bindings"),
Arch::MAX => panic!("Illegal Arch specified"),
};
self.reg_read(reg)
}
@@ -772,7 +815,7 @@ impl<'a, D> Unicorn<'a, D> {
Arch::M68K => RegisterM68K::PC as i32,
Arch::PPC => RegisterPPC::PC as i32,
Arch::RISCV => RegisterRISCV::PC as i32,
_ => panic!("Arch not yet known to the unicorn rust bindings"),
Arch::MAX => panic!("Illegal Arch specified"),
};
self.reg_write(reg, value)
}