From 5318fcda33aa25dc5f0b3ce3a9e06d3aa3c0be07 Mon Sep 17 00:00:00 2001 From: Mark Giraud Date: Mon, 14 Aug 2023 13:38:13 +0200 Subject: [PATCH 1/4] fix: Make from handle function unsafe --- bindings/rust/src/lib.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 9e424e2df9..4de937229e 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -54,7 +54,6 @@ pub use crate::{ use alloc::{boxed::Box, rc::Rc, vec::Vec}; use core::{cell::UnsafeCell, ptr}; -use bitflags::Flags; use ffi::uc_handle; use libc::c_void; @@ -166,13 +165,14 @@ impl<'a> Unicorn<'a, ()> { pub fn new(arch: Arch, mode: Mode) -> Result, uc_error> { Self::new_with_data(arch, mode, ()) } -} - -impl<'a> TryFrom for Unicorn<'a, ()> { - type Error = uc_error; - #[allow(clippy::not_unsafe_ptr_arg_deref)] - fn try_from(handle: uc_handle) -> Result, uc_error> { + /// # Safety + /// The function has to be called with a valid uc_handle pointer + /// that was previously allocated by a call to uc_open. + /// Calling the function with a non null pointer value that + /// does not point to a unicorn instance will cause undefined + /// behavior. + pub unsafe fn from_handle(handle: uc_handle) -> Result, uc_error> { if handle.is_null() { return Err(uc_error::HANDLE); } From 5fd12af68a9cf1d773ffbb69ca72bb3146fa4669 Mon Sep 17 00:00:00 2001 From: Mark Giraud Date: Mon, 14 Aug 2023 13:55:24 +0200 Subject: [PATCH 2/4] formating: Use rustfmt style for rust bindings --- bindings/rust/src/lib.rs | 320 +++++++++++++++++++++++++-------------- 1 file changed, 209 insertions(+), 111 deletions(-) diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 4de937229e..2c8e1d48c5 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -32,6 +32,28 @@ extern crate alloc; extern crate std; +use alloc::boxed::Box; +use alloc::rc::Rc; +use alloc::vec::Vec; +use core::cell::UnsafeCell; +use core::ptr; + +use libc::c_void; + +use ffi::uc_handle; + +pub use crate::arm::*; +pub use crate::arm64::*; +pub use crate::m68k::*; +pub use crate::mips::*; +pub use crate::ppc::*; +pub use crate::riscv::*; +pub use crate::s390x::*; +pub use crate::sparc::*; +pub use crate::tricore::*; +pub use crate::unicorn_const::*; +pub use crate::x86::*; + #[macro_use] pub mod unicorn_const; pub mod ffi; // lets consumers call ffi if desired @@ -47,16 +69,6 @@ mod sparc; mod tricore; mod x86; -pub use crate::{ - arm::*, arm64::*, m68k::*, mips::*, ppc::*, riscv::*, s390x::*, sparc::*, tricore::*, - unicorn_const::*, x86::*, -}; - -use alloc::{boxed::Box, rc::Rc, vec::Vec}; -use core::{cell::UnsafeCell, ptr}; -use ffi::uc_handle; -use libc::c_void; - #[derive(Debug)] pub struct Context { context: ffi::uc_context, @@ -91,7 +103,11 @@ impl<'a> MmioCallbackScope<'a> { !self.regions.is_empty() } - fn unmap(&mut self, begin: u64, size: usize) { + fn unmap( + &mut self, + begin: u64, + size: usize, + ) { let end: u64 = begin + size as u64; self.regions = self .regions @@ -108,10 +124,7 @@ impl<'a> MmioCallbackScope<'a> { } else { // The unmapped region is in the middle of this region let second_b = end + 1; - vec![ - (*b, (begin - *b) as usize), - (second_b, (e - second_b) as usize), - ] + vec![(*b, (begin - *b) as usize), (second_b, (e - second_b) as usize)] } } else if end > *b { if end >= e { @@ -162,7 +175,10 @@ pub struct Unicorn<'a, D: 'a> { impl<'a> Unicorn<'a, ()> { /// Create a new instance of the unicorn engine for the specified architecture /// and hardware mode. - pub fn new(arch: Arch, mode: Mode) -> Result, uc_error> { + pub fn new( + arch: Arch, + mode: Mode, + ) -> Result, uc_error> { Self::new_with_data(arch, mode, ()) } @@ -200,7 +216,11 @@ 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> { + pub fn new_with_data( + arch: Arch, + mode: Mode, + data: D, + ) -> Result, uc_error> { let mut handle = core::ptr::null_mut(); let err = unsafe { ffi::uc_open(arch, mode, &mut handle) }; if err == uc_error::OK { @@ -221,7 +241,10 @@ where } impl<'a, D> core::fmt::Debug for Unicorn<'a, D> { - fn fmt(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { + fn fmt( + &self, + formatter: &mut core::fmt::Formatter, + ) -> core::fmt::Result { write!(formatter, "Unicorn {{ uc: {:p} }}", self.get_handle()) } } @@ -280,9 +303,12 @@ 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.get_handle(), address, buf.as_mut_ptr(), buf.len()) }; + pub fn mem_read( + &self, + address: u64, + buf: &mut [u8], + ) -> Result<(), uc_error> { + let err = unsafe { ffi::uc_mem_read(self.get_handle(), address, buf.as_mut_ptr(), buf.len()) }; if err == uc_error::OK { Ok(()) } else { @@ -291,7 +317,11 @@ 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> { + 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.get_handle(), address, buf.as_mut_ptr(), size) }; if err == uc_error::OK { @@ -301,9 +331,12 @@ 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.get_handle(), address, bytes.as_ptr(), bytes.len()) }; + pub fn mem_write( + &mut self, + address: u64, + bytes: &[u8], + ) -> Result<(), uc_error> { + let err = unsafe { ffi::uc_mem_write(self.get_handle(), address, bytes.as_ptr(), bytes.len()) }; if err == uc_error::OK { Ok(()) } else { @@ -437,12 +470,7 @@ impl<'a, D> Unicorn<'a, D> { where F: FnMut(&mut Unicorn, u64, usize) -> u64, { - self.mmio_map( - address, - size, - Some(callback), - None::, u64, usize, u64)>, - ) + self.mmio_map(address, size, Some(callback), None::, u64, usize, u64)>) } /// Map in a write-only MMIO region backed by a callback. @@ -458,19 +486,18 @@ impl<'a, D> Unicorn<'a, D> { where F: FnMut(&mut Unicorn, u64, usize, u64), { - self.mmio_map( - address, - size, - None::, u64, usize) -> u64>, - Some(callback), - ) + self.mmio_map(address, size, None::, u64, usize) -> u64>, Some(callback)) } /// Unmap a memory region. /// /// `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> { + pub fn mem_unmap( + &mut self, + address: u64, + size: libc::size_t, + ) -> Result<(), uc_error> { let err = unsafe { ffi::uc_mem_unmap(self.get_handle(), address, size) }; self.mmio_unmap(address, size); @@ -482,7 +509,11 @@ impl<'a, D> Unicorn<'a, D> { } } - fn mmio_unmap(&mut self, address: u64, size: libc::size_t) { + fn mmio_unmap( + &mut self, + address: u64, + size: libc::size_t, + ) { for scope in self.inner_mut().mmio_callbacks.iter_mut() { scope.unmap(address, size); } @@ -510,9 +541,12 @@ 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.get_handle(), regid.into(), &value as *const _ as _) }; + pub fn reg_write>( + &mut self, + regid: T, + value: u64, + ) -> Result<(), uc_error> { + let err = unsafe { ffi::uc_reg_write(self.get_handle(), regid.into(), &value as *const _ as _) }; if err == uc_error::OK { Ok(()) } else { @@ -524,9 +558,12 @@ 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 (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.get_handle(), regid.into(), value.as_ptr() as _) }; + pub fn reg_write_long>( + &self, + regid: T, + value: &[u8], + ) -> Result<(), uc_error> { + let err = unsafe { ffi::uc_reg_write(self.get_handle(), regid.into(), value.as_ptr() as _) }; if err == uc_error::OK { Ok(()) } else { @@ -537,11 +574,12 @@ impl<'a, D> Unicorn<'a, D> { /// Read an unsigned value from a register. /// /// Not to be used with registers larger than 64 bit. - pub fn reg_read>(&self, regid: T) -> Result { + pub fn reg_read>( + &self, + regid: T, + ) -> Result { let mut value: u64 = 0; - let err = unsafe { - ffi::uc_reg_read(self.get_handle(), regid.into(), &mut value as *mut u64 as _) - }; + let err = unsafe { ffi::uc_reg_read(self.get_handle(), regid.into(), &mut value as *mut u64 as _) }; if err == uc_error::OK { Ok(value) } else { @@ -552,39 +590,33 @@ impl<'a, D> Unicorn<'a, D> { /// Read 128, 256 or 512 bit register value into heap allocated byte array. /// /// This adds safe support for registers >64 bit (GDTR/IDTR, XMM, YMM, ZMM, ST (x86); Q, V (arm64)). - pub fn reg_read_long>(&self, regid: T) -> Result, uc_error> { + pub fn reg_read_long>( + &self, + regid: T, + ) -> Result, uc_error> { let boxed: Box<[u8]>; let mut value: Vec; let curr_reg_id = regid.into(); let curr_arch = self.get_arch(); if curr_arch == Arch::X86 { - if curr_reg_id >= x86::RegisterX86::XMM0 as i32 - && curr_reg_id <= x86::RegisterX86::XMM31 as i32 - { + if curr_reg_id >= x86::RegisterX86::XMM0 as i32 && curr_reg_id <= x86::RegisterX86::XMM31 as i32 { value = vec![0; 16]; - } else if curr_reg_id >= x86::RegisterX86::YMM0 as i32 - && curr_reg_id <= x86::RegisterX86::YMM31 as i32 - { + } else if curr_reg_id >= x86::RegisterX86::YMM0 as i32 && curr_reg_id <= x86::RegisterX86::YMM31 as i32 { value = vec![0; 32]; - } else if curr_reg_id >= x86::RegisterX86::ZMM0 as i32 - && curr_reg_id <= x86::RegisterX86::ZMM31 as i32 - { + } else if curr_reg_id >= x86::RegisterX86::ZMM0 as i32 && curr_reg_id <= x86::RegisterX86::ZMM31 as i32 { value = vec![0; 64]; } else if curr_reg_id == x86::RegisterX86::GDTR as i32 || curr_reg_id == x86::RegisterX86::IDTR as i32 - || (curr_reg_id >= x86::RegisterX86::ST0 as i32 - && curr_reg_id <= x86::RegisterX86::ST7 as i32) + || (curr_reg_id >= x86::RegisterX86::ST0 as i32 && curr_reg_id <= x86::RegisterX86::ST7 as i32) { value = vec![0; 10]; // 64 bit base address in IA-32e mode } else { return Err(uc_error::ARG); } } else if curr_arch == Arch::ARM64 { - 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) + 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 { @@ -594,8 +626,7 @@ impl<'a, D> Unicorn<'a, D> { 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 _) }; + let err: uc_error = unsafe { ffi::uc_reg_read(self.get_handle(), curr_reg_id, value.as_mut_ptr() as _) }; if err == uc_error::OK { boxed = value.into_boxed_slice(); @@ -606,11 +637,12 @@ impl<'a, D> Unicorn<'a, D> { } /// Read a signed 32-bit value from a register. - pub fn reg_read_i32>(&self, regid: T) -> Result { + pub fn reg_read_i32>( + &self, + regid: T, + ) -> Result { let mut value: i32 = 0; - let err = unsafe { - ffi::uc_reg_read(self.get_handle(), regid.into(), &mut value as *mut i32 as _) - }; + let err = unsafe { ffi::uc_reg_read(self.get_handle(), regid.into(), &mut value as *mut i32 as _) }; if err == uc_error::OK { Ok(value) } else { @@ -655,7 +687,10 @@ impl<'a, D> Unicorn<'a, D> { } /// Add a block hook. - pub fn add_block_hook(&mut self, callback: F) -> Result + pub fn add_block_hook( + &mut self, + callback: F, + ) -> Result where F: FnMut(&mut Unicorn, u64, u32), { @@ -729,7 +764,10 @@ impl<'a, D> Unicorn<'a, D> { } /// Add an interrupt hook. - pub fn add_intr_hook(&mut self, callback: F) -> Result + pub fn add_intr_hook( + &mut self, + callback: F, + ) -> Result where F: FnMut(&mut Unicorn, u32), { @@ -761,7 +799,10 @@ impl<'a, D> Unicorn<'a, D> { } /// Add hook for invalid instructions - pub fn add_insn_invalid_hook(&mut self, callback: F) -> Result + pub fn add_insn_invalid_hook( + &mut self, + callback: F, + ) -> Result where F: FnMut(&mut Unicorn) -> bool, { @@ -793,7 +834,10 @@ impl<'a, D> Unicorn<'a, D> { } /// Add hook for x86 IN instruction. - pub fn add_insn_in_hook(&mut self, callback: F) -> Result + pub fn add_insn_in_hook( + &mut self, + callback: F, + ) -> Result where F: FnMut(&mut Unicorn, u32, usize) -> u32, { @@ -826,7 +870,10 @@ impl<'a, D> Unicorn<'a, D> { } /// Add hook for x86 OUT instruction. - pub fn add_insn_out_hook(&mut self, callback: F) -> Result + pub fn add_insn_out_hook( + &mut self, + callback: F, + ) -> Result where F: FnMut(&mut Unicorn, u32, usize, u32), { @@ -897,7 +944,12 @@ impl<'a, D> Unicorn<'a, D> { } } - pub fn add_tlb_hook(&mut self, begin: u64, end: u64, callback: F) -> Result + pub fn add_tlb_hook( + &mut self, + begin: u64, + end: u64, + callback: F, + ) -> Result where F: FnMut(&mut crate::Unicorn, u64, MemType) -> Option + 'a, { @@ -907,13 +959,14 @@ impl<'a, D> Unicorn<'a, D> { uc: Rc::downgrade(&self.inner), }); let err = unsafe { - ffi::uc_hook_add(self.get_handle(), - &mut hook_id, - HookType::TLB, - ffi::tlb_lookup_hook_proxy:: as _, - user_data.as_mut() as *mut _ as _, - begin, - end, + ffi::uc_hook_add( + self.get_handle(), + &mut hook_id, + HookType::TLB, + ffi::tlb_lookup_hook_proxy:: as _, + user_data.as_mut() as *mut _ as _, + begin, + end, ) }; let hook_id = UcHookId(hook_id); @@ -928,12 +981,13 @@ impl<'a, D> Unicorn<'a, D> { /// Remove a hook. /// /// `hook_id` is the value returned by `add_*_hook` functions. - pub fn remove_hook(&mut self, hook_id: UcHookId) -> Result<(), uc_error> { + pub fn remove_hook( + &mut self, + hook_id: UcHookId, + ) -> Result<(), uc_error> { // drop the hook 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) }; @@ -951,16 +1005,17 @@ impl<'a, D> Unicorn<'a, D> { let mut empty_context: ffi::uc_context = ptr::null_mut(); let err = unsafe { ffi::uc_context_alloc(self.get_handle(), &mut empty_context) }; if err == uc_error::OK { - Ok(Context { - context: empty_context, - }) + Ok(Context { context: empty_context }) } else { Err(err) } } /// Save current Unicorn context to previously allocated Context struct. - pub fn context_save(&self, context: &mut Context) -> Result<(), uc_error> { + pub fn context_save( + &self, + context: &mut Context, + ) -> Result<(), uc_error> { let err = unsafe { ffi::uc_context_save(self.get_handle(), context.context) }; if err == uc_error::OK { Ok(()) @@ -982,9 +1037,7 @@ impl<'a, D> Unicorn<'a, D> { } let err = unsafe { ffi::uc_context_save(self.get_handle(), new_context) }; if err == uc_error::OK { - Ok(Context { - context: new_context, - }) + Ok(Context { context: new_context }) } else { unsafe { ffi::uc_context_free(new_context) }; Err(err) @@ -996,7 +1049,10 @@ impl<'a, D> Unicorn<'a, D> { /// Perform a quick rollback of the CPU context, including registers and some /// 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> { + pub fn context_restore( + &self, + context: &Context, + ) -> Result<(), uc_error> { let err = unsafe { ffi::uc_context_restore(self.get_handle(), context.context) }; if err == uc_error::OK { Ok(()) @@ -1044,7 +1100,10 @@ impl<'a, D> Unicorn<'a, D> { /// Query the internal status of the engine. /// /// supported: `MODE`, `PAGE_SIZE`, `ARCH` - pub fn query(&self, query: Query) -> Result { + pub fn query( + &self, + query: Query, + ) -> Result { let mut result: libc::size_t = Default::default(); let err = unsafe { ffi::uc_query(self.get_handle(), query, &mut result) }; if err == uc_error::OK { @@ -1076,7 +1135,10 @@ impl<'a, D> Unicorn<'a, D> { /// Sets the program counter for this `unicorn` instance. #[inline] - pub fn set_pc(&mut self, value: u64) -> Result<(), uc_error> { + pub fn set_pc( + &mut self, + value: u64, + ) -> Result<(), uc_error> { let arch = self.get_arch(); let reg = match arch { Arch::X86 => RegisterX86::RIP as i32, @@ -1106,7 +1168,8 @@ impl<'a, D> Unicorn<'a, D> { pub fn ctl_get_page_size(&self) -> Result { 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) }; + let err = + unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_PAGE_SIZE), &mut result) }; if err == uc_error::OK { Ok(result) } else { @@ -1114,7 +1177,10 @@ impl<'a, D> Unicorn<'a, D> { } } - pub fn ctl_set_page_size(&self, page_size: u32) -> Result<(), uc_error> { + pub fn ctl_set_page_size( + &self, + page_size: u32, + ) -> Result<(), uc_error> { let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_PAGE_SIZE), page_size) }; if err == uc_error::OK { Ok(()) @@ -1163,7 +1229,8 @@ impl<'a, D> Unicorn<'a, D> { pub fn ctl_get_exits_count(&self) -> Result { let mut result: libc::size_t = Default::default(); - let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_EXITS_CNT), &mut result) }; + let err = + unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_EXITS_CNT), &mut result) }; if err == uc_error::OK { Ok(result) } else { @@ -1174,17 +1241,31 @@ impl<'a, D> Unicorn<'a, D> { pub fn ctl_get_exits(&self) -> Result, uc_error> { let exits_count: libc::size_t = self.ctl_get_exits_count()?; let mut exits: Vec = Vec::with_capacity(exits_count); - let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_EXITS), exits.as_mut_ptr(), exits_count) }; + let err = unsafe { + 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); } + unsafe { + exits.set_len(exits_count); + } Ok(exits) } else { Err(err) } } - pub fn ctl_set_exits(&self, exits: &[u64]) -> Result<(), uc_error> { - let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_EXITS), exits.as_ptr(), exits.len() as libc::size_t) }; + pub fn ctl_set_exits( + &self, + exits: &[u64], + ) -> Result<(), uc_error> { + let err = unsafe { + ffi::uc_ctl( + self.get_handle(), + UC_CTL_WRITE!(ControlType::UC_CTL_UC_EXITS), + exits.as_ptr(), + exits.len() as libc::size_t, + ) + }; if err == uc_error::OK { Ok(()) } else { @@ -1202,7 +1283,10 @@ impl<'a, D> Unicorn<'a, D> { } } - pub fn ctl_set_cpu_model(&self, cpu_model: i32) -> Result<(), uc_error> { + pub fn ctl_set_cpu_model( + &self, + cpu_model: i32, + ) -> Result<(), uc_error> { let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_CPU_MODEL), cpu_model) }; if err == uc_error::OK { Ok(()) @@ -1211,8 +1295,13 @@ impl<'a, D> Unicorn<'a, D> { } } - pub fn ctl_remove_cache(&self, address: u64, end: u64) -> Result<(), uc_error> { - let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TB_REMOVE_CACHE), address, end) }; + pub fn ctl_remove_cache( + &self, + address: u64, + end: u64, + ) -> Result<(), uc_error> { + let err = + unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TB_REMOVE_CACHE), address, end) }; if err == uc_error::OK { Ok(()) } else { @@ -1220,8 +1309,14 @@ impl<'a, D> Unicorn<'a, D> { } } - pub fn ctl_request_cache(&self, address: u64, tb: &mut TranslationBlock) -> Result<(), uc_error> { - let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ_WRITE!(ControlType::UC_CTL_TB_REQUEST_CACHE), address, tb) }; + pub fn ctl_request_cache( + &self, + address: u64, + tb: &mut TranslationBlock, + ) -> Result<(), uc_error> { + let err = unsafe { + ffi::uc_ctl(self.get_handle(), UC_CTL_READ_WRITE!(ControlType::UC_CTL_TB_REQUEST_CACHE), address, tb) + }; if err == uc_error::OK { Ok(()) } else { @@ -1247,7 +1342,10 @@ impl<'a, D> Unicorn<'a, D> { } } - pub fn ctl_tlb_type(&self, t: TlbType) -> Result<(), uc_error> { + pub fn ctl_tlb_type( + &self, + t: TlbType, + ) -> Result<(), uc_error> { let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TLB_TYPE), t as i32) }; if err == uc_error::OK { Ok(()) From fd3b7082b413399a938d4b6617a1fc72cc7eec75 Mon Sep 17 00:00:00 2001 From: Mark Giraud Date: Tue, 15 Aug 2023 11:04:50 +0200 Subject: [PATCH 3/4] refactor: Make rust bindings more rusty --- bindings/rust/src/lib.rs | 530 +++++++++-------------------- bindings/rust/src/unicorn_const.rs | 145 +++++--- 2 files changed, 253 insertions(+), 422 deletions(-) diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 2c8e1d48c5..b39a45a790 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -35,6 +35,7 @@ extern crate std; use alloc::boxed::Box; use alloc::rc::Rc; use alloc::vec::Vec; +use bitflags::Flags; use core::cell::UnsafeCell; use core::ptr; @@ -221,9 +222,8 @@ where mode: Mode, data: D, ) -> Result, uc_error> { - let mut handle = core::ptr::null_mut(); - let err = unsafe { ffi::uc_open(arch, mode, &mut handle) }; - if err == uc_error::OK { + let mut handle = ptr::null_mut(); + unsafe { ffi::uc_open(arch, mode, &mut handle) }.and_then(|| { Ok(Unicorn { inner: Rc::new(UnsafeCell::from(UnicornInner { handle, @@ -234,9 +234,7 @@ where 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. pub fn mem_regions(&self) -> Result, uc_error> { let mut nb_regions: u32 = 0; - let p_regions: *const MemRegion = core::ptr::null_mut(); - let err = unsafe { ffi::uc_mem_regions(self.get_handle(), &p_regions, &mut nb_regions) }; - if err == uc_error::OK { + let p_regions: *const MemRegion = ptr::null_mut(); + unsafe { ffi::uc_mem_regions(self.get_handle(), &p_regions, &mut nb_regions) }.and_then(|| { let mut regions = Vec::new(); for i in 0..nb_regions { regions.push(unsafe { core::mem::transmute_copy(&*p_regions.add(i as usize)) }); } unsafe { libc::free(p_regions as _) }; 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( &self, address: u64, buf: &mut [u8], ) -> Result<(), uc_error> { - let err = unsafe { ffi::uc_mem_read(self.get_handle(), address, buf.as_mut_ptr(), buf.len()) }; - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + unsafe { ffi::uc_mem_read(self.get_handle(), address, buf.as_mut_ptr(), buf.len()) }.into() } - /// 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( &self, address: u64, size: usize, ) -> Result, uc_error> { let mut buf = vec![0; size]; - let err = unsafe { ffi::uc_mem_read(self.get_handle(), address, buf.as_mut_ptr(), size) }; - if err == uc_error::OK { - Ok(buf) - } else { - Err(err) - } + unsafe { ffi::uc_mem_read(self.get_handle(), address, buf.as_mut_ptr(), size) }.and(Ok(buf)) } + /// Write the data in `bytes` to the emulated physical address `address` pub fn mem_write( &mut self, address: u64, bytes: &[u8], ) -> Result<(), uc_error> { - let err = unsafe { ffi::uc_mem_write(self.get_handle(), address, bytes.as_ptr(), bytes.len()) }; - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + unsafe { ffi::uc_mem_write(self.get_handle(), address, bytes.as_ptr(), bytes.len()) }.into() } /// Map an existing memory region in the emulator at the specified address. @@ -364,12 +345,7 @@ impl<'a, D> Unicorn<'a, D> { perms: Permission, ptr: *mut c_void, ) -> Result<(), uc_error> { - let err = ffi::uc_mem_map_ptr(self.get_handle(), address, size, perms.bits(), ptr); - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + ffi::uc_mem_map_ptr(self.get_handle(), address, size, perms.bits(), ptr).into() } /// 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, perms: Permission, ) -> Result<(), uc_error> { - let err = unsafe { ffi::uc_mem_map(self.get_handle(), address, size, perms.bits()) }; - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + unsafe { ffi::uc_mem_map(self.get_handle(), address, size, perms.bits()) }.into() } /// 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( self.get_handle(), address, @@ -440,9 +411,8 @@ impl<'a, D> Unicorn<'a, D> { None => ptr::null_mut(), }, ) - }; - - if err == uc_error::OK { + } + .and_then(|| { let rd = read_data.map(|c| c as Box); let wd = write_data.map(|c| c as Box); self.inner_mut().mmio_callbacks.push(MmioCallbackScope { @@ -452,9 +422,7 @@ impl<'a, D> Unicorn<'a, D> { }); Ok(()) - } else { - Err(err) - } + }) } /// 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, ) -> Result<(), uc_error> { let err = unsafe { ffi::uc_mem_unmap(self.get_handle(), address, size) }; - self.mmio_unmap(address, size); - - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + err.into() } fn mmio_unmap( @@ -532,12 +494,7 @@ impl<'a, D> Unicorn<'a, D> { size: libc::size_t, perms: Permission, ) -> Result<(), uc_error> { - let err = unsafe { ffi::uc_mem_protect(self.get_handle(), address, size, perms.bits()) }; - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + unsafe { ffi::uc_mem_protect(self.get_handle(), address, size, perms.bits()) }.into() } /// Write an unsigned value from a register. @@ -546,12 +503,7 @@ impl<'a, D> Unicorn<'a, D> { regid: T, value: u64, ) -> Result<(), uc_error> { - let err = unsafe { ffi::uc_reg_write(self.get_handle(), regid.into(), &value as *const _ as _) }; - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + unsafe { ffi::uc_reg_write(self.get_handle(), regid.into(), &value as *const _ as _) }.into() } /// Write variable sized values into registers. @@ -563,12 +515,7 @@ impl<'a, D> Unicorn<'a, D> { regid: T, value: &[u8], ) -> Result<(), uc_error> { - let err = unsafe { ffi::uc_reg_write(self.get_handle(), regid.into(), value.as_ptr() as _) }; - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + unsafe { ffi::uc_reg_write(self.get_handle(), regid.into(), value.as_ptr() as _) }.into() } /// Read an unsigned value from a register. @@ -579,12 +526,7 @@ impl<'a, D> Unicorn<'a, D> { regid: T, ) -> Result { let mut value: u64 = 0; - let err = unsafe { ffi::uc_reg_read(self.get_handle(), regid.into(), &mut value as *mut u64 as _) }; - if err == uc_error::OK { - Ok(value) - } else { - Err(err) - } + unsafe { ffi::uc_reg_read(self.get_handle(), regid.into(), &mut value as *mut u64 as _) }.and(Ok(value)) } /// Read 128, 256 or 512 bit register value into heap allocated byte array. @@ -594,45 +536,42 @@ impl<'a, D> Unicorn<'a, D> { &self, regid: T, ) -> Result, uc_error> { - let boxed: Box<[u8]>; - let mut value: Vec; let curr_reg_id = regid.into(); let curr_arch = self.get_arch(); - if curr_arch == Arch::X86 { - if curr_reg_id >= x86::RegisterX86::XMM0 as i32 && curr_reg_id <= x86::RegisterX86::XMM31 as i32 { - value = vec![0; 16]; - } else if curr_reg_id >= x86::RegisterX86::YMM0 as i32 && curr_reg_id <= x86::RegisterX86::YMM31 as i32 { - value = vec![0; 32]; - } else if curr_reg_id >= x86::RegisterX86::ZMM0 as i32 && curr_reg_id <= x86::RegisterX86::ZMM31 as i32 { - value = vec![0; 64]; - } else if curr_reg_id == x86::RegisterX86::GDTR as i32 - || curr_reg_id == x86::RegisterX86::IDTR as i32 - || (curr_reg_id >= x86::RegisterX86::ST0 as i32 && curr_reg_id <= x86::RegisterX86::ST7 as i32) - { - value = vec![0; 10]; // 64 bit base address in IA-32e mode - } else { - return Err(uc_error::ARG); - } - } else if curr_arch == Arch::ARM64 { - 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) + let value_size = match curr_arch { + Arch::X86 => Self::value_size_x86(curr_reg_id)?, + Arch::ARM64 => Self::value_size_arm64(curr_reg_id)?, + _ => Err(uc_error::ARCH)?, + }; + let mut value = vec![0; value_size]; + unsafe { ffi::uc_reg_read(self.get_handle(), curr_reg_id, value.as_mut_ptr() as _) } + .and_then(|| Ok(value.into_boxed_slice())) + } + + fn value_size_arm64(curr_reg_id: i32) -> Result { + 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; 16]; - } else { - return Err(uc_error::ARG); + Ok(16) } - } else { - return Err(uc_error::ARCH); + _ => Err(uc_error::ARG), } + } - let err: uc_error = unsafe { ffi::uc_reg_read(self.get_handle(), curr_reg_id, value.as_mut_ptr() as _) }; - - if err == uc_error::OK { - boxed = value.into_boxed_slice(); - Ok(boxed) - } else { - Err(err) + fn value_size_x86(curr_reg_id: i32) -> Result { + match curr_reg_id { + r if (RegisterX86::XMM0 as i32..=RegisterX86::XMM31 as i32).contains(&r) => Ok(16), + r if (RegisterX86::YMM0 as i32..=RegisterX86::YMM31 as i32).contains(&r) => Ok(32), + r if (RegisterX86::ZMM0 as i32..=RegisterX86::ZMM31 as i32).contains(&r) => Ok(64), + r if r == RegisterX86::GDTR as i32 + || 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, ) -> Result { let mut value: i32 = 0; - let err = unsafe { ffi::uc_reg_read(self.get_handle(), regid.into(), &mut value as *mut i32 as _) }; - if err == uc_error::OK { - Ok(value) - } else { - Err(err) - } + unsafe { ffi::uc_reg_read(self.get_handle(), regid.into(), &mut value as *mut i32 as _) }.and(Ok(value)) } /// Add a code hook. @@ -658,7 +592,7 @@ impl<'a, D> Unicorn<'a, D> { callback: F, ) -> Result where - F: FnMut(&mut crate::Unicorn, u64, u32) + 'a, + F: FnMut(&mut Unicorn, u64, u32) + 'a, { let mut hook_id = ptr::null_mut(); let mut user_data = Box::new(ffi::UcHook { @@ -666,7 +600,7 @@ impl<'a, D> Unicorn<'a, D> { uc: Rc::downgrade(&self.inner), }); - let err = unsafe { + unsafe { ffi::uc_hook_add( self.get_handle(), &mut hook_id, @@ -676,14 +610,12 @@ impl<'a, D> Unicorn<'a, D> { begin, end, ) - }; - let hook_id = UcHookId(hook_id); - if err == uc_error::OK { + } + .and_then(|| { + let hook_id = UcHookId(hook_id); self.inner_mut().hooks.push((hook_id, user_data)); Ok(hook_id) - } else { - Err(err) - } + }) } /// Add a block hook. @@ -694,13 +626,13 @@ impl<'a, D> Unicorn<'a, D> { where F: FnMut(&mut Unicorn, 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 { callback, uc: Rc::downgrade(&self.inner), }); - let err = unsafe { + unsafe { ffi::uc_hook_add( self.get_handle(), &mut hook_id, @@ -710,15 +642,12 @@ impl<'a, D> Unicorn<'a, D> { 1, 0, ) - }; - let hook_id = UcHookId(hook_id); - if err == uc_error::OK { + } + .and_then(|| { + let hook_id = UcHookId(hook_id); self.inner_mut().hooks.push((hook_id, user_data)); - Ok(hook_id) - } else { - Err(err) - } + }) } /// Add a memory hook. @@ -736,13 +665,13 @@ impl<'a, D> Unicorn<'a, D> { 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 { callback, uc: Rc::downgrade(&self.inner), }); - let err = unsafe { + unsafe { ffi::uc_hook_add( self.get_handle(), &mut hook_id, @@ -752,15 +681,12 @@ impl<'a, D> Unicorn<'a, D> { begin, end, ) - }; - let hook_id = UcHookId(hook_id); - if err == uc_error::OK { + } + .and_then(|| { + let hook_id = UcHookId(hook_id); self.inner_mut().hooks.push((hook_id, user_data)); - Ok(hook_id) - } else { - Err(err) - } + }) } /// Add an interrupt hook. @@ -771,13 +697,13 @@ impl<'a, D> Unicorn<'a, D> { where F: FnMut(&mut Unicorn, u32), { - let mut hook_id = core::ptr::null_mut(); + let mut hook_id = ptr::null_mut(); let mut user_data = Box::new(ffi::UcHook { callback, uc: Rc::downgrade(&self.inner), }); - let err = unsafe { + unsafe { ffi::uc_hook_add( self.get_handle(), &mut hook_id, @@ -787,15 +713,12 @@ impl<'a, D> Unicorn<'a, D> { 0, 0, ) - }; - let hook_id = UcHookId(hook_id); - if err == uc_error::OK { + } + .and_then(|| { + let hook_id = UcHookId(hook_id); self.inner_mut().hooks.push((hook_id, user_data)); - Ok(hook_id) - } else { - Err(err) - } + }) } /// Add hook for invalid instructions @@ -806,13 +729,13 @@ impl<'a, D> Unicorn<'a, D> { where F: FnMut(&mut Unicorn) -> bool, { - let mut hook_id = core::ptr::null_mut(); + let mut hook_id = ptr::null_mut(); let mut user_data = Box::new(ffi::UcHook { callback, uc: Rc::downgrade(&self.inner), }); - let err = unsafe { + unsafe { ffi::uc_hook_add( self.get_handle(), &mut hook_id, @@ -822,15 +745,12 @@ impl<'a, D> Unicorn<'a, D> { 0, 0, ) - }; - let hook_id = UcHookId(hook_id); - if err == uc_error::OK { + } + .and_then(|| { + let hook_id = UcHookId(hook_id); self.inner_mut().hooks.push((hook_id, user_data)); - Ok(hook_id) - } else { - Err(err) - } + }) } /// Add hook for x86 IN instruction. @@ -841,13 +761,13 @@ impl<'a, D> Unicorn<'a, D> { where F: FnMut(&mut Unicorn, 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 { callback, uc: Rc::downgrade(&self.inner), }); - let err = unsafe { + unsafe { ffi::uc_hook_add( self.get_handle(), &mut hook_id, @@ -856,17 +776,14 @@ impl<'a, D> Unicorn<'a, D> { user_data.as_mut() as *mut _ as _, 0, 0, - x86::InsnX86::IN, + InsnX86::IN, ) - }; - let hook_id = UcHookId(hook_id); - if err == uc_error::OK { + } + .and_then(|| { + let hook_id = UcHookId(hook_id); self.inner_mut().hooks.push((hook_id, user_data)); - Ok(hook_id) - } else { - Err(err) - } + }) } /// Add hook for x86 OUT instruction. @@ -877,13 +794,13 @@ impl<'a, D> Unicorn<'a, D> { where F: FnMut(&mut Unicorn, 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 { callback, uc: Rc::downgrade(&self.inner), }); - let err = unsafe { + unsafe { ffi::uc_hook_add( self.get_handle(), &mut hook_id, @@ -892,23 +809,20 @@ impl<'a, D> Unicorn<'a, D> { user_data.as_mut() as *mut _ as _, 0, 0, - x86::InsnX86::OUT, + InsnX86::OUT, ) - }; - let hook_id = UcHookId(hook_id); - if err == uc_error::OK { + } + .and_then(|| { + let hook_id = UcHookId(hook_id); self.inner_mut().hooks.push((hook_id, user_data)); - Ok(hook_id) - } else { - Err(err) - } + }) } /// Add hook for x86 SYSCALL or SYSENTER. pub fn add_insn_sys_hook( &mut self, - insn_type: x86::InsnSysX86, + insn_type: InsnSysX86, begin: u64, end: u64, callback: F, @@ -916,13 +830,13 @@ impl<'a, D> Unicorn<'a, D> { where F: FnMut(&mut Unicorn) + 'a, { - let mut hook_id = core::ptr::null_mut(); + let mut hook_id = ptr::null_mut(); let mut user_data = Box::new(ffi::UcHook { callback, uc: Rc::downgrade(&self.inner), }); - let err = unsafe { + unsafe { ffi::uc_hook_add( self.get_handle(), &mut hook_id, @@ -933,15 +847,12 @@ impl<'a, D> Unicorn<'a, D> { end, insn_type, ) - }; - let hook_id = UcHookId(hook_id); - if err == uc_error::OK { + } + .and_then(|| { + let hook_id = UcHookId(hook_id); self.inner_mut().hooks.push((hook_id, user_data)); - Ok(hook_id) - } else { - Err(err) - } + }) } pub fn add_tlb_hook( @@ -951,14 +862,15 @@ impl<'a, D> Unicorn<'a, D> { callback: F, ) -> Result where - F: FnMut(&mut crate::Unicorn, u64, MemType) -> Option + 'a, + F: FnMut(&mut Unicorn, u64, MemType) -> Option + 'a, { - let mut hook_id = core::ptr::null_mut(); + let mut hook_id = ptr::null_mut(); let mut user_data = Box::new(ffi::UcHook { callback, uc: Rc::downgrade(&self.inner), }); - let err = unsafe { + + unsafe { ffi::uc_hook_add( self.get_handle(), &mut hook_id, @@ -968,14 +880,12 @@ impl<'a, D> Unicorn<'a, D> { begin, end, ) - }; - let hook_id = UcHookId(hook_id); - if err == uc_error::OK { + } + .and_then(|| { + let hook_id = UcHookId(hook_id); self.inner_mut().hooks.push((hook_id, user_data)); Ok(hook_id) - } else { - Err(err) - } + }) } /// Remove a hook. @@ -989,13 +899,7 @@ impl<'a, D> Unicorn<'a, D> { let inner = self.inner_mut(); inner.hooks.retain(|(id, _)| id != &hook_id); - let err: uc_error = unsafe { ffi::uc_hook_del(inner.handle, hook_id.0) }; - - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + unsafe { ffi::uc_hook_del(inner.handle, hook_id.0) }.into() } /// Allocate and return an empty Unicorn context. @@ -1003,12 +907,8 @@ 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.get_handle(), &mut empty_context) }; - if err == uc_error::OK { - Ok(Context { context: empty_context }) - } else { - Err(err) - } + unsafe { ffi::uc_context_alloc(self.get_handle(), &mut empty_context) } + .and(Ok(Context { context: empty_context })) } /// Save current Unicorn context to previously allocated Context struct. @@ -1016,12 +916,7 @@ impl<'a, D> Unicorn<'a, D> { &self, context: &mut Context, ) -> Result<(), uc_error> { - let err = unsafe { ffi::uc_context_save(self.get_handle(), context.context) }; - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + unsafe { ffi::uc_context_save(self.get_handle(), context.context) }.into() } /// 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. pub fn context_init(&self) -> Result { let mut new_context: ffi::uc_context = ptr::null_mut(); - let err = unsafe { ffi::uc_context_alloc(self.get_handle(), &mut new_context) }; - if err != uc_error::OK { - return Err(err); - } - let err = unsafe { ffi::uc_context_save(self.get_handle(), new_context) }; - if err == uc_error::OK { - Ok(Context { context: new_context }) - } else { - unsafe { ffi::uc_context_free(new_context) }; - Err(err) + unsafe { + ffi::uc_context_alloc(self.get_handle(), &mut new_context).and_then(|| { + ffi::uc_context_save(self.get_handle(), new_context) + .and(Ok(Context { context: new_context })) + .map_err(|e| { + ffi::uc_context_free(new_context); + e + }) + }) } } @@ -1053,12 +947,7 @@ impl<'a, D> Unicorn<'a, D> { &self, context: &Context, ) -> Result<(), uc_error> { - let err = unsafe { ffi::uc_context_restore(self.get_handle(), context.context) }; - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + unsafe { ffi::uc_context_restore(self.get_handle(), context.context) }.into() } /// Emulate machine code for a specified duration. @@ -1074,14 +963,7 @@ impl<'a, D> Unicorn<'a, D> { timeout: u64, count: usize, ) -> Result<(), uc_error> { - unsafe { - let err = ffi::uc_emu_start(self.get_handle(), begin, until, timeout, count as _); - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } - } + unsafe { ffi::uc_emu_start(self.get_handle(), begin, until, timeout, count as _) }.into() } /// Stop the emulation. @@ -1089,12 +971,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.get_handle()) }; - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + unsafe { ffi::uc_emu_stop(self.get_handle()).into() } } /// Query the internal status of the engine. @@ -1105,12 +982,7 @@ impl<'a, D> Unicorn<'a, D> { query: Query, ) -> Result { let mut result: libc::size_t = Default::default(); - let err = unsafe { ffi::uc_query(self.get_handle(), query, &mut result) }; - if err == uc_error::OK { - Ok(result) - } else { - Err(err) - } + unsafe { ffi::uc_query(self.get_handle(), query, &mut result) }.and(Ok(result)) } /// 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 { 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) }; - if err == uc_error::OK { - Ok(Mode::from_bits_truncate(result)) - } else { - Err(err) - } + unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_MODE), &mut result) } + .and_then(|| Ok(Mode::from_bits_truncate(result))) } pub fn ctl_get_page_size(&self) -> Result { 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) }; - if err == uc_error::OK { - Ok(result) - } else { - Err(err) - } + unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_PAGE_SIZE), &mut result) } + .and_then(|| Ok(result)) } pub fn ctl_set_page_size( &self, page_size: u32, ) -> Result<(), uc_error> { - let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_PAGE_SIZE), page_size) }; - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_PAGE_SIZE), page_size) }.into() } pub fn ctl_get_arch(&self) -> Result { 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) }; - if err == uc_error::OK { - Arch::try_from(result as usize) - } else { - Err(err) - } + unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_ARCH), &mut result) } + .and_then(|| Arch::try_from(result as usize)) } pub fn ctl_get_timeout(&self) -> Result { 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) }; - if err == uc_error::OK { - Ok(result) - } else { - Err(err) - } + unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_TIMEOUT), &mut result) } + .and(Ok(result)) } 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) }; - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_USE_EXITS), 1) }.into() } 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) }; - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_USE_EXITS), 0) }.into() } pub fn ctl_get_exits_count(&self) -> Result { - let mut result: libc::size_t = Default::default(); - let err = - unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_EXITS_CNT), &mut result) }; - if err == uc_error::OK { - Ok(result) - } else { - Err(err) - } + let mut result: libc::size_t = 0usize; + unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_EXITS_CNT), &mut result) } + .and(Ok(result)) } pub fn ctl_get_exits(&self) -> Result, uc_error> { let exits_count: libc::size_t = self.ctl_get_exits_count()?; let mut exits: Vec = 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) - }; - 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( &self, exits: &[u64], ) -> Result<(), uc_error> { - let err = unsafe { + unsafe { ffi::uc_ctl( self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_EXITS), exits.as_ptr(), exits.len() as libc::size_t, ) - }; - if err == uc_error::OK { - Ok(()) - } else { - Err(err) } + .into() } pub fn ctl_get_cpu_model(&self) -> Result { 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) }; - if err == uc_error::OK { - Ok(result) - } else { - Err(err) - } + unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_CPU_MODEL), &mut result) } + .and(Ok(result)) } pub fn ctl_set_cpu_model( &self, cpu_model: i32, ) -> Result<(), uc_error> { - let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_CPU_MODEL), cpu_model) }; - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_CPU_MODEL), cpu_model) }.into() } pub fn ctl_remove_cache( @@ -1300,13 +1118,8 @@ impl<'a, D> Unicorn<'a, D> { address: u64, end: u64, ) -> Result<(), uc_error> { - let err = - unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TB_REMOVE_CACHE), address, end) }; - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TB_REMOVE_CACHE), address, end) } + .into() } pub fn ctl_request_cache( @@ -1314,43 +1127,22 @@ impl<'a, D> Unicorn<'a, D> { address: u64, tb: &mut TranslationBlock, ) -> Result<(), uc_error> { - let err = unsafe { - ffi::uc_ctl(self.get_handle(), UC_CTL_READ_WRITE!(ControlType::UC_CTL_TB_REQUEST_CACHE), address, tb) - }; - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ_WRITE!(ControlType::UC_CTL_TB_REQUEST_CACHE), address, tb) } + .into() } 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)) }; - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TB_FLUSH)) }.into() } 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)) }; - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TLB_FLUSH)) }.into() } pub fn ctl_tlb_type( &self, t: TlbType, ) -> Result<(), uc_error> { - let err = unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TLB_TYPE), t as i32) }; - if err == uc_error::OK { - Ok(()) - } else { - Err(err) - } + unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TLB_TYPE), t as i32) }.into() } } diff --git a/bindings/rust/src/unicorn_const.rs b/bindings/rust/src/unicorn_const.rs index c9c5f6b93e..a27c044225 100644 --- a/bindings/rust/src/unicorn_const.rs +++ b/bindings/rust/src/unicorn_const.rs @@ -14,49 +14,88 @@ pub const MILISECOND_SCALE: u64 = 1_000; #[derive(PartialEq, Debug, Clone, Copy)] #[allow(clippy::upper_case_acronyms)] pub enum uc_error { - OK = 0, - NOMEM = 1, - ARCH = 2, - HANDLE = 3, - MODE = 4, - VERSION = 5, - READ_UNMAPPED = 6, - WRITE_UNMAPPED = 7, - FETCH_UNMAPPED = 8, - HOOK = 9, - INSN_INVALID = 10, - MAP = 11, - WRITE_PROT = 12, - READ_PROT = 13, - FETCH_PROT = 14, - ARG = 15, - READ_UNALIGNED = 16, + OK = 0, + NOMEM = 1, + ARCH = 2, + HANDLE = 3, + MODE = 4, + VERSION = 5, + READ_UNMAPPED = 6, + WRITE_UNMAPPED = 7, + FETCH_UNMAPPED = 8, + HOOK = 9, + INSN_INVALID = 10, + MAP = 11, + WRITE_PROT = 12, + READ_PROT = 13, + FETCH_PROT = 14, + ARG = 15, + READ_UNALIGNED = 16, WRITE_UNALIGNED = 17, FETCH_UNALIGNED = 18, - HOOK_EXIST = 19, - RESOURCE = 20, - EXCEPTION = 21, + HOOK_EXIST = 19, + RESOURCE = 20, + 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 Result>( + self, + op: F, + ) -> Result { + 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( + self, + res: Result, + ) -> Result { + if let Self::OK = self { + res + } else { + Err(self) + } + } +} + +impl From for Result<(), uc_error> { + fn from(value: uc_error) -> Self { + if let uc_error::OK = value { + Ok(()) + } else { + Err(value) + } + } } #[repr(C)] #[derive(PartialEq, Debug, Clone, Copy)] pub enum MemType { - READ = 16, - WRITE = 17, - FETCH = 18, - READ_UNMAPPED = 19, + READ = 16, + WRITE = 17, + FETCH = 18, + READ_UNMAPPED = 19, WRITE_UNMAPPED = 20, FETCH_UNMAPPED = 21, - WRITE_PROT = 22, - READ_PROT = 23, - FETCH_PROT = 24, - READ_AFTER = 25, + WRITE_PROT = 22, + READ_PROT = 23, + FETCH_PROT = 24, + READ_AFTER = 25, } #[repr(C)] #[derive(PartialEq, Debug, Clone, Copy)] pub enum TlbType { - CPU = 0, + CPU = 0, VIRTUAL = 1, } @@ -103,10 +142,10 @@ bitflags! { #[derive(PartialEq, Debug, Clone, Copy)] #[allow(clippy::upper_case_acronyms)] pub enum Query { - MODE = 1, + MODE = 1, PAGE_SIZE = 2, - ARCH = 3, - TIMEOUT = 4, + ARCH = 3, + TIMEOUT = 4, } bitflags! { @@ -132,17 +171,17 @@ pub struct MemRegion { #[repr(C)] #[derive(PartialEq, Debug, Clone, Copy)] pub enum Arch { - ARM = 1, - ARM64 = 2, - MIPS = 3, - X86 = 4, - PPC = 5, - SPARC = 6, - M68K = 7, - RISCV = 8, - S390X = 9, + ARM = 1, + ARM64 = 2, + MIPS = 3, + X86 = 4, + PPC = 5, + SPARC = 6, + M68K = 7, + RISCV = 8, + S390X = 9, TRICORE = 10, - MAX = 11, + MAX = 11, } impl TryFrom for Arch { @@ -205,7 +244,7 @@ bitflags! { pub struct TranslationBlock { pub pc: u64, pub icount: u16, - pub size: u16 + pub size: u16, } macro_rules! UC_CTL_READ { @@ -229,21 +268,21 @@ macro_rules! UC_CTL_READ_WRITE { #[allow(clippy::upper_case_acronyms)] #[repr(u64)] pub enum ControlType { - UC_CTL_UC_MODE = 0, + UC_CTL_UC_MODE = 0, UC_CTL_UC_PAGE_SIZE = 1, - UC_CTL_UC_ARCH = 2, - UC_CTL_UC_TIMEOUT = 3, + UC_CTL_UC_ARCH = 2, + UC_CTL_UC_TIMEOUT = 3, UC_CTL_UC_USE_EXITS = 4, UC_CTL_UC_EXITS_CNT = 5, - UC_CTL_UC_EXITS = 6, - UC_CTL_CPU_MODEL = 7, + UC_CTL_UC_EXITS = 6, + UC_CTL_CPU_MODEL = 7, UC_CTL_TB_REQUEST_CACHE = 8, UC_CTL_TB_REMOVE_CACHE = 9, - UC_CTL_TB_FLUSH = 10, - UC_CTL_TLB_FLUSH = 11, - UC_CTL_TLB_TYPE = 12, - UC_CTL_IO_READ = 1<<31, - UC_CTL_IO_WRITE = 1<<30, + UC_CTL_TB_FLUSH = 10, + UC_CTL_TLB_FLUSH = 11, + UC_CTL_TLB_TYPE = 12, + UC_CTL_IO_READ = 1 << 31, + UC_CTL_IO_WRITE = 1 << 30, } #[repr(C)] From fbe1b4421a8666fc7ceeb4893faafc4323a8a59c Mon Sep 17 00:00:00 2001 From: Mark Giraud Date: Wed, 16 Aug 2023 13:48:53 +0200 Subject: [PATCH 4/4] feat: Add ctl_context_mode to rust bindings --- bindings/rust/src/lib.rs | 7 +++++++ bindings/rust/src/unicorn_const.rs | 11 +++++++++++ 2 files changed, 18 insertions(+) diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index b39a45a790..264494a051 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -1139,6 +1139,13 @@ impl<'a, D> Unicorn<'a, D> { unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TLB_FLUSH)) }.into() } + pub fn ctl_context_mode( + &self, + mode: ContextMode, + ) -> Result<(), uc_error> { + unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_CONTEXT_MODE), mode) }.into() + } + pub fn ctl_tlb_type( &self, t: TlbType, diff --git a/bindings/rust/src/unicorn_const.rs b/bindings/rust/src/unicorn_const.rs index a27c044225..5f8c80fd4a 100644 --- a/bindings/rust/src/unicorn_const.rs +++ b/bindings/rust/src/unicorn_const.rs @@ -281,10 +281,21 @@ pub enum ControlType { UC_CTL_TB_FLUSH = 10, UC_CTL_TLB_FLUSH = 11, UC_CTL_TLB_TYPE = 12, + UC_CTL_TCG_BUFFER_SIZE = 13, + UC_CTL_CONTEXT_MODE = 14, UC_CTL_IO_READ = 1 << 31, UC_CTL_IO_WRITE = 1 << 30, } +bitflags! { + #[derive(Debug, Copy, Clone)] + #[repr(C)] + pub struct ContextMode : u32 { + const CPU = 1; + const Memory = 2; + } +} + #[repr(C)] #[derive(Debug, Clone, Copy)] pub struct TlbEntry {