diff --git a/bindings/rust/Cargo.toml b/bindings/rust/Cargo.toml index 23482b93..7aa9ca73 100644 --- a/bindings/rust/Cargo.toml +++ b/bindings/rust/Cargo.toml @@ -3,7 +3,7 @@ name = "unicorn-engine" version = "2.0.0-rc3" authors = ["Ziqiao Kong", "Lukas Seidel"] documentation = "https://github.com/unicorn-engine/unicorn/wiki" -edition = "2018" +edition = "2021" include = [ "/.gitmodules", "/COPYING", diff --git a/bindings/rust/build.rs b/bindings/rust/build.rs index 195e9e0d..8efb1887 100644 --- a/bindings/rust/build.rs +++ b/bindings/rust/build.rs @@ -18,7 +18,12 @@ fn find_unicorn(unicorn_dir: &Path) -> Option { None } -fn download_unicorn() -> Option { +fn out_dir() -> PathBuf { + let out_dir = env::var("OUT_DIR").unwrap(); + Path::new(&out_dir).to_path_buf() +} + +fn download_unicorn() -> PathBuf { // https://docs.github.com/en/rest/reference/repos#download-a-repository-archive-tar let pkg_version; if let Ok(unicorn_version) = env::var("UNICORN_VERSION") { @@ -26,7 +31,7 @@ fn download_unicorn() -> Option { } else { pkg_version = env::var("CARGO_PKG_VERSION").unwrap(); } - let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); + let out_dir = out_dir(); let client = reqwest::blocking::Client::new(); let resp = client .get(format!( @@ -43,85 +48,107 @@ fn download_unicorn() -> Option { let mut archive = Archive::new(tar); archive.unpack(&out_dir).unwrap(); - match find_unicorn(&out_dir) { - Some(dir) => Some(String::from(out_dir.join(dir).to_str()?)), - None => None, - } + find_unicorn(&out_dir).unwrap() } -#[allow(clippy::branches_sharing_code)] +#[allow(clippy::too_many_lines)] fn main() { let profile = env::var("PROFILE").unwrap(); - let unicorn_dir = download_unicorn().unwrap(); - - println!("cargo:rerun-if-changed={}", &unicorn_dir); - - // We don't use TARGET since we can't cross-build. - if env::consts::OS == "windows" { - // Windows - let mut cmd = Command::new("cmake"); - cmd.current_dir(&unicorn_dir) - .arg("-B") - .arg("rust_build") - .arg("-DUNICORN_BUILD_SHARED=off") - .arg("-G") - .arg("Visual Studio 16 2019"); - - if profile == "debug" { - cmd.arg("-DCMAKE_BUILD_TYPE=Debug"); - } else { - cmd.arg("-DCMAKE_BUILD_TYPE=Release"); - } - - cmd.output() - .expect("Fail to create build directory on Windows."); - - let mut platform = "x64"; - let mut conf = "Release"; - if std::mem::size_of::() == 4 { - platform = "Win32"; - } - if profile == "debug" { - conf = "Debug"; - } - - Command::new("msbuild") - .current_dir(format!("{}/rust_build", &unicorn_dir)) - .arg("unicorn.sln") - .arg("-m") - .arg("-p:Platform=".to_owned() + platform) - .arg("-p:Configuration=".to_owned() + conf) - .output() - .expect("Fail to build unicorn on Win32."); + if let Some(unicorn_dir) = find_unicorn(&out_dir()) { + let rust_build_path = unicorn_dir.join("rust_build"); println!( - "cargo:rustc-link-search={}/rust_build/{}", - unicorn_dir, conf + "cargo:rustc-link-search={}", + rust_build_path.to_str().unwrap() + ); + println!( + "cargo:rustc-link-search={}", + rust_build_path.join("Debug").to_str().unwrap() + ); + println!( + "cargo:rustc-link-search={}", + rust_build_path.join("Release").to_str().unwrap() ); } else { - // Most Unix-like systems - let mut cmd = Command::new("cmake"); - cmd.current_dir(&unicorn_dir) - .arg("-B") - .arg("rust_build") - .arg("-DUNICORN_BUILD_SHARED=off"); - - if profile == "debug" { - cmd.arg("-DCMAKE_BUILD_TYPE=Debug"); + let unicorn_dir = if env::var("CI").is_ok() { + Path::new("..").join("..") } else { - cmd.arg("-DCMAKE_BUILD_TYPE=Release"); + println!("cargo:warning=Unicorn not found. Downloading..."); + download_unicorn() + }; + + let rust_build_path = unicorn_dir.join("rust_build"); + + let mut cmd = Command::new("cmake"); + + // We don't use TARGET since we can't cross-build. + if env::consts::OS == "windows" { + // Windows + cmd.current_dir(&unicorn_dir) + .arg("-B") + .arg("rust_build") + .arg("-DUNICORN_BUILD_SHARED=off") + .arg("-G") + .arg("Visual Studio 16 2019"); + + if profile == "debug" { + cmd.arg("-DCMAKE_BUILD_TYPE=Debug"); + } else { + cmd.arg("-DCMAKE_BUILD_TYPE=Release"); + } + + cmd.output() + .expect("Fail to create build directory on Windows."); + + let mut platform = "x64"; + let mut conf = "Release"; + if std::mem::size_of::() == 4 { + platform = "Win32"; + } + if profile == "debug" { + conf = "Debug"; + } + + Command::new("msbuild") + .current_dir(&rust_build_path) + .arg("unicorn.sln") + .arg("-m") + .arg("-p:Platform=".to_owned() + platform) + .arg("-p:Configuration=".to_owned() + conf) + .output() + .expect("Fail to build unicorn on Win32."); + println!( + "cargo:rustc-link-search={}", + rust_build_path.join(conf).to_str().unwrap() + ); + } else { + // Most Unix-like systems + let mut cmd = Command::new("cmake"); + cmd.current_dir(&unicorn_dir) + .arg("-B") + .arg("rust_build") + .arg("-DUNICORN_BUILD_SHARED=off"); + + if profile == "debug" { + cmd.arg("-DCMAKE_BUILD_TYPE=Debug"); + } else { + cmd.arg("-DCMAKE_BUILD_TYPE=Release"); + } + + cmd.output() + .expect("Fail to create build directory on *nix."); + + Command::new("make") + .current_dir(&rust_build_path) + .arg("-j6") + .output() + .expect("Fail to build unicorn on *nix."); + + println!( + "cargo:rustc-link-search={}", + rust_build_path.to_str().unwrap() + ); } - - cmd.output() - .expect("Fail to create build directory on *nix."); - - Command::new("make") - .current_dir(format!("{}/rust_build", &unicorn_dir)) - .arg("-j6") - .output() - .expect("Fail to build unicorn on *nix."); - - println!("cargo:rustc-link-search={}/rust_build", unicorn_dir); } // This is a workaround for Unicorn static link since libunicorn.a is also linked again lib*-softmmu.a. @@ -130,7 +157,7 @@ fn main() { // // Lazymio(@wtdcode): Why do I stick to static link? See: https://github.com/rust-lang/cargo/issues/5077 println!("cargo:rustc-link-lib=unicorn"); - for arch in [ + for arch in &[ "x86_64", "arm", "armeb", @@ -147,10 +174,11 @@ fn main() { "m68k", "ppc", "ppc64", - ] - .iter() - { + ] { println!("cargo:rustc-link-lib={}-softmmu", arch); } println!("cargo:rustc-link-lib=unicorn-common"); + + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=src"); } diff --git a/bindings/rust/src/ffi.rs b/bindings/rust/src/ffi.rs index 9c2b0bd1..300e1220 100644 --- a/bindings/rust/src/ffi.rs +++ b/bindings/rust/src/ffi.rs @@ -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( uc: uc_handle, address: u64, @@ -108,10 +95,9 @@ pub extern "C" fn code_hook_proxy( ) where F: FnMut(&mut crate::Unicorn, 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( @@ -122,10 +108,9 @@ pub extern "C" fn block_hook_proxy( ) where F: FnMut(&mut crate::Unicorn, 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( @@ -139,20 +124,18 @@ pub extern "C" fn mem_hook_proxy( where F: FnMut(&mut crate::Unicorn, 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(uc: uc_handle, value: u32, user_data: *mut UcHook) where F: FnMut(&mut crate::Unicorn, 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( @@ -163,10 +146,9 @@ pub extern "C" fn insn_in_hook_proxy( ) where F: FnMut(&mut crate::Unicorn, 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( @@ -178,18 +160,16 @@ pub extern "C" fn insn_out_hook_proxy( ) where F: FnMut(&mut crate::Unicorn, 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(uc: uc_handle, user_data: *mut UcHook) where F: FnMut(&mut crate::Unicorn), { - 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); } diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 0a1df998..7b5c35c6 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -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>>, +} + 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, 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, 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, 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>(&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>(&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>(&self, regid: T) -> Result { 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>(&self, regid: T) -> Result { 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, 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:: 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, 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:: 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:: 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, 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:: 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(&mut self, callback: F) -> Result where - F: FnMut(&mut Unicorn, u32, usize) + 'a, + F: FnMut(&mut Unicorn, 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:: 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(&mut self, callback: F) -> Result where - F: FnMut(&mut Unicorn, u32, usize, u32) + 'a, + F: FnMut(&mut Unicorn, 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:: 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) + '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:: 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 { 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 { 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 { 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) } diff --git a/bindings/rust/tests/unicorn.rs b/bindings/rust/tests/unicorn.rs index 039569bc..98ca78e1 100644 --- a/bindings/rust/tests/unicorn.rs +++ b/bindings/rust/tests/unicorn.rs @@ -1,9 +1,11 @@ -use std::cell::RefCell; -use std::rc::Rc; +extern crate alloc; + +use alloc::rc::Rc; +use core::cell::RefCell; use unicorn_engine::unicorn_const::{ uc_error, Arch, HookType, MemType, Mode, Permission, SECOND_SCALE, }; -use unicorn_engine::{InsnSysX86, RegisterARM, RegisterMIPS, RegisterPPC, RegisterX86}; +use unicorn_engine::{InsnSysX86, RegisterARM, RegisterMIPS, RegisterPPC, RegisterX86, Unicorn}; pub static X86_REGISTERS: [RegisterX86; 125] = [ RegisterX86::AH, @@ -32,7 +34,6 @@ pub static X86_REGISTERS: [RegisterX86; 125] = [ RegisterX86::EDX, RegisterX86::EFLAGS, RegisterX86::EIP, - RegisterX86::EIZ, RegisterX86::ES, RegisterX86::ESI, RegisterX86::ESP, @@ -47,7 +48,6 @@ pub static X86_REGISTERS: [RegisterX86; 125] = [ RegisterX86::RDI, RegisterX86::RDX, RegisterX86::RIP, - RegisterX86::RIZ, RegisterX86::RSI, RegisterX86::RSP, RegisterX86::SI, @@ -60,17 +60,7 @@ pub static X86_REGISTERS: [RegisterX86; 125] = [ RegisterX86::CR2, RegisterX86::CR3, RegisterX86::CR4, - RegisterX86::CR5, - RegisterX86::CR6, - RegisterX86::CR7, RegisterX86::CR8, - RegisterX86::CR9, - RegisterX86::CR10, - RegisterX86::CR11, - RegisterX86::CR12, - RegisterX86::CR13, - RegisterX86::CR14, - RegisterX86::CR15, RegisterX86::DR0, RegisterX86::DR1, RegisterX86::DR2, @@ -79,14 +69,6 @@ pub static X86_REGISTERS: [RegisterX86; 125] = [ RegisterX86::DR5, RegisterX86::DR6, RegisterX86::DR7, - RegisterX86::DR8, - RegisterX86::DR9, - RegisterX86::DR10, - RegisterX86::DR11, - RegisterX86::DR12, - RegisterX86::DR13, - RegisterX86::DR14, - RegisterX86::DR15, RegisterX86::FP0, RegisterX86::FP1, RegisterX86::FP2, @@ -159,8 +141,8 @@ fn emulate_x86() { let mut emu = unicorn_engine::Unicorn::new(Arch::X86, Mode::MODE_32) .expect("failed to initialize unicorn instance"); - assert_eq!(emu.reg_write(RegisterX86::EAX as i32, 123), Ok(())); - assert_eq!(emu.reg_read(RegisterX86::EAX as i32), Ok(123)); + assert_eq!(emu.reg_write(RegisterX86::EAX, 123), Ok(())); + assert_eq!(emu.reg_read(RegisterX86::EAX), Ok(123)); // Attempt to write to memory before mapping it. assert_eq!( @@ -175,8 +157,8 @@ fn emulate_x86() { Ok(x86_code32.clone()) ); - assert_eq!(emu.reg_write(RegisterX86::ECX as i32, 10), Ok(())); - assert_eq!(emu.reg_write(RegisterX86::EDX as i32, 50), Ok(())); + assert_eq!(emu.reg_write(RegisterX86::ECX, 10), Ok(())); + assert_eq!(emu.reg_write(RegisterX86::EDX, 50), Ok(())); assert_eq!( emu.emu_start( @@ -187,8 +169,8 @@ fn emulate_x86() { ), Ok(()) ); - assert_eq!(emu.reg_read(RegisterX86::ECX as i32), Ok(11)); - assert_eq!(emu.reg_read(RegisterX86::EDX as i32), Ok(49)); + assert_eq!(emu.reg_read(RegisterX86::ECX), Ok(11)); + assert_eq!(emu.reg_read(RegisterX86::EDX), Ok(49)); } #[test] @@ -266,17 +248,26 @@ fn x86_mem_callback() { let expects = vec![ MemExpectation(MemType::WRITE, 0x2000, 4, 0xdeadbeef), MemExpectation(MemType::READ_UNMAPPED, 0x10000, 4, 0), + MemExpectation(MemType::READ, 0x10000, 4, 0), ]; let mems: Vec = Vec::new(); let mems_cell = Rc::new(RefCell::new(mems)); let callback_mems = mems_cell.clone(); - let callback = - move |_: &mut Unicorn<'_, ()>, mem_type: MemType, address: u64, size: usize, value: i64| { - let mut mems = callback_mems.borrow_mut(); - mems.push(MemExpectation(mem_type, address, size, value)); - true - }; + let callback = move |uc: &mut Unicorn<'_, ()>, + mem_type: MemType, + address: u64, + size: usize, + value: i64| { + let mut mems = callback_mems.borrow_mut(); + + mems.push(MemExpectation(mem_type, address, size, value)); + + if mem_type == MemType::READ_UNMAPPED { + uc.mem_map(address, 0x1000, Permission::ALL).unwrap(); + } + true + }; // mov eax, 0xdeadbeef; // mov [0x2000], eax; @@ -291,9 +282,9 @@ fn x86_mem_callback() { assert_eq!(emu.mem_write(0x1000, &x86_code32), Ok(())); let hook = emu - .add_mem_hook(HookType::MEM_ALL, 0, std::u64::MAX, callback) + .add_mem_hook(HookType::MEM_ALL, 0, u64::MAX, callback) .expect("failed to add memory hook"); - assert_eq!(emu.reg_write(RegisterX86::EAX as i32, 0x123), Ok(())); + assert_eq!(emu.reg_write(RegisterX86::EAX, 0x123), Ok(())); assert_eq!( emu.emu_start( 0x1000, @@ -301,7 +292,7 @@ fn x86_mem_callback() { 10 * SECOND_SCALE, 0x1000 ), - Err(uc_error::READ_UNMAPPED) + Ok(()) ); assert_eq!(expects, *mems_cell.borrow()); @@ -316,7 +307,7 @@ fn x86_insn_in_callback() { let insn_cell = Rc::new(RefCell::new(InsnInExpectation(0, 0))); let callback_insn = insn_cell.clone(); - let callback = move |_: &mut Unicorn<'_, ()>, port: u32, size: usize| { + let callback = move |_: &mut Unicorn<()>, port: u32, size: usize| { *callback_insn.borrow_mut() = InsnInExpectation(port, size); }; @@ -390,7 +381,7 @@ fn x86_insn_sys_callback() { let callback_insn = insn_cell.clone(); let callback = move |uc: &mut Unicorn<'_, ()>| { println!("!!!!"); - let rax = uc.reg_read(RegisterX86::RAX as i32).unwrap(); + let rax = uc.reg_read(RegisterX86::RAX).unwrap(); *callback_insn.borrow_mut() = InsnSysExpectation(rax); }; @@ -427,8 +418,8 @@ fn emulate_arm() { let mut emu = unicorn_engine::Unicorn::new(Arch::ARM, Mode::THUMB) .expect("failed to initialize unicorn instance"); - assert_eq!(emu.reg_write(RegisterARM::R1 as i32, 123), Ok(())); - assert_eq!(emu.reg_read(RegisterARM::R1 as i32), Ok(123)); + assert_eq!(emu.reg_write(RegisterARM::R1, 123), Ok(())); + assert_eq!(emu.reg_read(RegisterARM::R1), Ok(123)); // Attempt to write to memory before mapping it. assert_eq!( @@ -443,8 +434,8 @@ fn emulate_arm() { Ok(arm_code32.clone()) ); - assert_eq!(emu.reg_write(RegisterARM::SP as i32, 12), Ok(())); - assert_eq!(emu.reg_write(RegisterARM::R0 as i32, 10), Ok(())); + assert_eq!(emu.reg_write(RegisterARM::SP, 12), Ok(())); + assert_eq!(emu.reg_write(RegisterARM::R0, 10), Ok(())); // ARM checks the least significant bit of the address to know // if the code is in Thumb mode. @@ -457,8 +448,8 @@ fn emulate_arm() { ), Ok(()) ); - assert_eq!(emu.reg_read(RegisterARM::SP as i32), Ok(0)); - assert_eq!(emu.reg_read(RegisterARM::R0 as i32), Ok(10)); + assert_eq!(emu.reg_read(RegisterARM::SP), Ok(0)); + assert_eq!(emu.reg_read(RegisterARM::R0), Ok(10)); } #[test] @@ -473,7 +464,7 @@ fn emulate_mips() { emu.mem_read_as_vec(0x1000, mips_code32.len()), Ok(mips_code32.clone()) ); - assert_eq!(emu.reg_write(RegisterMIPS::AT as i32, 0), Ok(())); + assert_eq!(emu.reg_write(RegisterMIPS::AT, 0), Ok(())); assert_eq!( emu.emu_start( 0x1000, @@ -483,14 +474,14 @@ fn emulate_mips() { ), Ok(()) ); - assert_eq!(emu.reg_read(RegisterMIPS::AT as i32), Ok(0x3456)); + assert_eq!(emu.reg_read(RegisterMIPS::AT), Ok(0x3456)); } #[test] fn emulate_ppc() { let ppc_code32 = vec![0x7F, 0x46, 0x1A, 0x14]; // add 26, 6, 3 - let mut emu = unicorn_engine::Unicorn::new(Arch::PPC, Mode::PPC32) + let mut emu = unicorn_engine::Unicorn::new(Arch::PPC, Mode::PPC32 | Mode::BIG_ENDIAN) .expect("failed to initialize unicorn instance"); assert_eq!(emu.mem_map(0x1000, 0x4000, Permission::ALL), Ok(())); assert_eq!(emu.mem_write(0x1000, &ppc_code32), Ok(())); @@ -498,8 +489,8 @@ fn emulate_ppc() { emu.mem_read_as_vec(0x1000, ppc_code32.len()), Ok(ppc_code32.clone()) ); - assert_eq!(emu.reg_write(RegisterPPC::GPR3 as i32, 42), Ok(())); - assert_eq!(emu.reg_write(RegisterPPC::GPR6 as i32, 1337), Ok(())); + assert_eq!(emu.reg_write(RegisterPPC::GPR3, 42), Ok(())); + assert_eq!(emu.reg_write(RegisterPPC::GPR6, 1337), Ok(())); assert_eq!( emu.emu_start( 0x1000, @@ -509,7 +500,7 @@ fn emulate_ppc() { ), Ok(()) ); - assert_eq!(emu.reg_read(RegisterPPC::GPR26 as i32), Ok(1379)); + assert_eq!(emu.reg_read(RegisterPPC::GPR26), Ok(1379)); } #[test] @@ -545,8 +536,8 @@ fn mem_map_ptr() { Ok(x86_code32.clone()) ); - assert_eq!(emu.reg_write(RegisterX86::ECX as i32, 10), Ok(())); - assert_eq!(emu.reg_write(RegisterX86::EDX as i32, 50), Ok(())); + assert_eq!(emu.reg_write(RegisterX86::ECX, 10), Ok(())); + assert_eq!(emu.reg_write(RegisterX86::EDX, 50), Ok(())); assert_eq!( emu.emu_start( @@ -557,8 +548,8 @@ fn mem_map_ptr() { ), Ok(()) ); - assert_eq!(emu.reg_read(RegisterX86::ECX as i32), Ok(11)); - assert_eq!(emu.reg_read(RegisterX86::EDX as i32), Ok(49)); + assert_eq!(emu.reg_read(RegisterX86::ECX), Ok(11)); + assert_eq!(emu.reg_read(RegisterX86::EDX), Ok(49)); assert_eq!(emu.mem_unmap(0x1000, 0x4000), Ok(())); // Use a Vec for the emulator memory. @@ -581,8 +572,8 @@ fn mem_map_ptr() { Ok(x86_code32.clone()) ); - assert_eq!(emu.reg_write(RegisterX86::ECX as i32, 10), Ok(())); - assert_eq!(emu.reg_write(RegisterX86::EDX as i32, 50), Ok(())); + assert_eq!(emu.reg_write(RegisterX86::ECX, 10), Ok(())); + assert_eq!(emu.reg_write(RegisterX86::EDX, 50), Ok(())); assert_eq!( emu.emu_start( @@ -593,18 +584,18 @@ fn mem_map_ptr() { ), Ok(()) ); - assert_eq!(emu.reg_read(RegisterX86::ECX as i32), Ok(11)); - assert_eq!(emu.reg_read(RegisterX86::EDX as i32), Ok(49)); + assert_eq!(emu.reg_read(RegisterX86::ECX), Ok(11)); + assert_eq!(emu.reg_read(RegisterX86::EDX), Ok(49)); assert_eq!(emu.mem_unmap(0x1000, 0x4000), Ok(())); } #[test] fn x86_context_save_and_restore() { - for mode in &[Mode::MODE_32, Mode::MODE_64] { - let x86_code: Vec = vec![ + for mode in [Mode::MODE_32, Mode::MODE_64] { + let x86_code = [ 0x48, 0xB8, 0xEF, 0xBE, 0xAD, 0xDE, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x05, ]; - let mut emu = unicorn_engine::Unicorn::new(Arch::X86, *mode) + let mut emu = unicorn_engine::Unicorn::new(Arch::X86, mode) .expect("failed to initialize unicorn instance"); assert_eq!(emu.mem_map(0x1000, 0x4000, Permission::ALL), Ok(())); assert_eq!(emu.mem_write(0x1000, &x86_code), Ok(())); @@ -620,15 +611,12 @@ fn x86_context_save_and_restore() { let context = context.unwrap(); /* and create a new emulator, into which we will "restore" that context */ - let emu2 = unicorn_engine::Unicorn::new(Arch::X86, *mode) + let emu2 = unicorn_engine::Unicorn::new(Arch::X86, mode) .expect("failed to initialize unicorn instance"); assert_eq!(emu2.context_restore(&context), Ok(())); for register in X86_REGISTERS.iter() { println!("Testing register {:?}", register); - assert_eq!( - emu2.reg_read(*register as i32), - emu.reg_read(*register as i32) - ); + assert_eq!(emu2.reg_read(*register), emu.reg_read(*register)); } } } diff --git a/uc.c b/uc.c index e40901c2..ecb954cc 100644 --- a/uc.c +++ b/uc.c @@ -686,27 +686,6 @@ static void clear_deleted_hooks(uc_engine *uc) list_clear(&uc->hooks_to_del); } -// set a data ptr (for use in bindings) -UNICORN_EXPORT -uc_err uc_emu_set_data_ptr(uc_engine *uc, void *data) -{ - if (uc == NULL) { - return UC_ERR_ARG; - } - uc->data_ptr = data; -} - -// get a data ptr (for use in bindings) -UNICORN_EXPORT -void *uc_emu_get_data_ptr(uc_engine *uc, void *data) -{ - if (uc == NULL) { - return NULL; - } - return uc->data_ptr; -} - - UNICORN_EXPORT uc_err uc_emu_start(uc_engine *uc, uint64_t begin, uint64_t until, uint64_t timeout, size_t count)