diff --git a/bindings/rust/src/ffi.rs b/bindings/rust/src/ffi.rs index 866ee82620..742e22412c 100644 --- a/bindings/rust/src/ffi.rs +++ b/bindings/rust/src/ffi.rs @@ -15,30 +15,15 @@ pub type uc_hook = *mut c_void; pub type uc_context = *mut c_void; extern "C" { - pub fn uc_version( - major: *mut u32, - minor: *mut u32, - ) -> u32; + pub fn uc_version(major: *mut u32, minor: *mut u32) -> u32; pub fn uc_arch_supported(arch: Arch) -> bool; - pub fn uc_open( - arch: Arch, - mode: Mode, - engine: *mut uc_handle, - ) -> uc_error; + pub fn uc_open(arch: Arch, mode: Mode, engine: *mut uc_handle) -> uc_error; pub fn uc_close(engine: uc_handle) -> uc_error; pub fn uc_context_free(mem: uc_context) -> uc_error; pub fn uc_errno(engine: uc_handle) -> uc_error; pub fn uc_strerror(error_code: uc_error) -> *const c_char; - pub fn uc_reg_write( - engine: uc_handle, - regid: c_int, - value: *const c_void, - ) -> uc_error; - pub fn uc_reg_read( - engine: uc_handle, - regid: c_int, - value: *mut c_void, - ) -> uc_error; + pub fn uc_reg_write(engine: uc_handle, regid: c_int, value: *const c_void) -> uc_error; + pub fn uc_reg_read(engine: uc_handle, regid: c_int, value: *mut c_void) -> uc_error; pub fn uc_mem_write( engine: uc_handle, address: u64, @@ -51,12 +36,7 @@ extern "C" { bytes: *mut u8, size: libc::size_t, ) -> uc_error; - pub fn uc_mem_map( - engine: uc_handle, - address: u64, - size: libc::size_t, - perms: u32, - ) -> uc_error; + pub fn uc_mem_map(engine: uc_handle, address: u64, size: libc::size_t, perms: u32) -> uc_error; pub fn uc_mem_map_ptr( engine: uc_handle, address: u64, @@ -73,11 +53,7 @@ extern "C" { write_cb: *mut c_void, user_data_write: *mut c_void, ) -> uc_error; - pub fn uc_mem_unmap( - engine: uc_handle, - address: u64, - size: libc::size_t, - ) -> uc_error; + pub fn uc_mem_unmap(engine: uc_handle, address: u64, size: libc::size_t) -> uc_error; pub fn uc_mem_protect( engine: uc_handle, address: u64, @@ -107,32 +83,12 @@ extern "C" { end: u64, ... ) -> uc_error; - pub fn uc_hook_del( - engine: uc_handle, - hook: uc_hook, - ) -> uc_error; - pub fn uc_query( - engine: uc_handle, - query_type: Query, - result: *mut libc::size_t, - ) -> uc_error; - 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_ctl( - engine: uc_handle, - control: u32, - ... - ) -> uc_error; + pub fn uc_hook_del(engine: uc_handle, hook: uc_hook) -> uc_error; + pub fn uc_query(engine: uc_handle, query_type: Query, result: *mut libc::size_t) -> uc_error; + 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_ctl(engine: uc_handle, control: u32, ...) -> uc_error; } pub struct UcHook<'a, D: 'a, F: 'a> { @@ -293,10 +249,8 @@ pub unsafe extern "C" fn insn_out_hook_proxy( (user_data.callback)(&mut user_data_uc, port, size, value); } -pub unsafe extern "C" fn insn_sys_hook_proxy( - uc: uc_handle, - user_data: *mut UcHook, -) where +pub unsafe extern "C" fn insn_sys_hook_proxy(uc: uc_handle, user_data: *mut UcHook) +where F: FnMut(&mut crate::Unicorn), { let user_data = &mut *user_data; diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 51e86e5a75..a1e7b16925 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -42,32 +42,72 @@ 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 use unicorn_const::*; pub mod ffi; // lets consumers call ffi if desired +// include arm support if conditionally compiled in +#[cfg(feature = "arch_arm")] mod arm; +#[cfg(feature = "arch_arm")] +pub use crate::arm::*; + +// include arm64 support if conditionally compiled in +// NOTE: unicorn-c only separates on top-level arch name, +// not on the bit-length, so we include both +#[cfg(feature = "arch_arm")] mod arm64; +#[cfg(feature = "arch_arm")] +pub use crate::arm64::*; + +// include m68k support if conditionally compiled in +#[cfg(feature = "arch_m68k")] mod m68k; +#[cfg(feature = "arch_m68k")] +pub use crate::m68k::*; + +// include mips support if conditionally compiled in +#[cfg(feature = "arch_mips")] mod mips; +#[cfg(feature = "arch_mips")] +pub use crate::mips::*; + +// include ppc support if conditionally compiled in +#[cfg(feature = "arch_ppc")] mod ppc; +#[cfg(feature = "arch_ppc")] +pub use crate::ppc::*; + +// include riscv support if conditionally compiled in +#[cfg(feature = "arch_riscv")] mod riscv; +#[cfg(feature = "arch_riscv")] +pub use crate::riscv::*; + +// include s390x support if conditionally compiled in +#[cfg(feature = "arch_s390x")] mod s390x; +#[cfg(feature = "arch_s390x")] +pub use crate::s390x::*; + +// include sparc support if conditionally compiled in +#[cfg(feature = "arch_sparc")] mod sparc; +#[cfg(feature = "arch_sparc")] +pub use crate::sparc::*; + +// include tricore support if conditionally compiled in +#[cfg(feature = "arch_tricore")] mod tricore; +#[cfg(feature = "arch_tricore")] +pub use crate::tricore::*; + +// include x86 support if conditionally compiled in +#[cfg(feature = "arch_x86")] mod x86; +#[cfg(feature = "arch_x86")] +pub use crate::x86::*; #[derive(Debug)] pub struct Context { @@ -103,11 +143,7 @@ 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 @@ -124,7 +160,10 @@ 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 { @@ -175,10 +214,7 @@ 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, ()) } @@ -216,11 +252,7 @@ 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 = ptr::null_mut(); unsafe { ffi::uc_open(arch, mode, &mut handle) }.and_then(|| { Ok(Unicorn { @@ -238,10 +270,7 @@ 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()) } } @@ -286,41 +315,31 @@ impl<'a, D> Unicorn<'a, D> { pub fn mem_regions(&self) -> Result, uc_error> { let mut nb_regions: u32 = 0; 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) - }) + 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) + }, + ) } /// 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> { + pub fn mem_read(&self, address: u64, buf: &mut [u8]) -> Result<(), uc_error> { 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 emulated physical 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]; 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> { + pub fn mem_write(&mut self, address: u64, bytes: &[u8]) -> Result<(), uc_error> { unsafe { ffi::uc_mem_write(self.get_handle(), address, bytes.as_ptr(), bytes.len()) }.into() } @@ -437,7 +456,12 @@ 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. @@ -453,28 +477,25 @@ 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); err.into() } - 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); } @@ -497,49 +518,39 @@ 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> { - unsafe { ffi::uc_reg_write(self.get_handle(), regid.into(), &value as *const _ as _) }.into() + pub fn reg_write>(&mut self, regid: T, value: u64) -> Result<(), uc_error> { + unsafe { ffi::uc_reg_write(self.get_handle(), regid.into(), &value as *const _ as _) } + .into() } /// Write variable sized values into registers. /// /// 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> { + pub fn reg_write_long>(&self, regid: T, value: &[u8]) -> Result<(), uc_error> { unsafe { ffi::uc_reg_write(self.get_handle(), regid.into(), value.as_ptr() as _) }.into() } /// 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; - unsafe { ffi::uc_reg_read(self.get_handle(), regid.into(), &mut value as *mut u64 as _) }.and(Ok(value)) + 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. /// /// 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 curr_reg_id = regid.into(); let curr_arch = self.get_arch(); let value_size = match curr_arch { + #[cfg(feature = "arch_x86")] Arch::X86 => Self::value_size_x86(curr_reg_id)?, + #[cfg(feature = "arch_arm")] Arch::ARM64 => Self::value_size_arm64(curr_reg_id)?, _ => Err(uc_error::ARCH)?, }; @@ -548,6 +559,7 @@ impl<'a, D> Unicorn<'a, D> { .and_then(|| Ok(value.into_boxed_slice())) } + #[cfg(feature = "arch_arm")] 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) @@ -559,6 +571,7 @@ impl<'a, D> Unicorn<'a, D> { } } + #[cfg(feature = "arch_x86")] 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), @@ -575,12 +588,10 @@ 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; - unsafe { ffi::uc_reg_read(self.get_handle(), regid.into(), &mut value as *mut i32 as _) }.and(Ok(value)) + unsafe { ffi::uc_reg_read(self.get_handle(), regid.into(), &mut value as *mut i32 as _) } + .and(Ok(value)) } /// Add a code hook. @@ -691,10 +702,7 @@ 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), { @@ -723,10 +731,7 @@ 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, { @@ -755,10 +760,8 @@ impl<'a, D> Unicorn<'a, D> { } /// Add hook for x86 IN instruction. - pub fn add_insn_in_hook( - &mut self, - callback: F, - ) -> Result + #[cfg(feature = "arch_x86")] + pub fn add_insn_in_hook(&mut self, callback: F) -> Result where F: FnMut(&mut Unicorn, u32, usize) -> u32, { @@ -788,10 +791,8 @@ impl<'a, D> Unicorn<'a, D> { } /// Add hook for x86 OUT instruction. - pub fn add_insn_out_hook( - &mut self, - callback: F, - ) -> Result + #[cfg(feature = "arch_x86")] + pub fn add_insn_out_hook(&mut self, callback: F) -> Result where F: FnMut(&mut Unicorn, u32, usize, u32), { @@ -821,6 +822,7 @@ impl<'a, D> Unicorn<'a, D> { } /// Add hook for x86 SYSCALL or SYSENTER. + #[cfg(feature = "arch_x86")] pub fn add_insn_sys_hook( &mut self, insn_type: InsnSysX86, @@ -892,10 +894,7 @@ 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); @@ -908,15 +907,13 @@ 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(); - unsafe { ffi::uc_context_alloc(self.get_handle(), &mut empty_context) } - .and(Ok(Context { context: empty_context })) + 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. - pub fn context_save( - &self, - context: &mut Context, - ) -> Result<(), uc_error> { + pub fn context_save(&self, context: &mut Context) -> Result<(), uc_error> { unsafe { ffi::uc_context_save(self.get_handle(), context.context) }.into() } @@ -930,7 +927,9 @@ impl<'a, D> Unicorn<'a, D> { 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 })) + .and(Ok(Context { + context: new_context, + })) .map_err(|e| { ffi::uc_context_free(new_context); e @@ -944,10 +943,7 @@ 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> { unsafe { ffi::uc_context_restore(self.get_handle(), context.context) }.into() } @@ -978,107 +974,162 @@ 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(); unsafe { ffi::uc_query(self.get_handle(), query, &mut result) }.and(Ok(result)) } + /// Get the `i32` register value for the program counter for the specified architecture. + /// + /// If an architecture is not compiled in, this function will return `uc_error::ARCH`. + #[inline] + fn arch_to_pc_register(arch: Arch) -> Result { + match arch { + #[cfg(feature = "arch_x86")] + Arch::X86 => Ok(RegisterX86::RIP as i32), + #[cfg(feature = "arch_arm")] + Arch::ARM => Ok(RegisterARM::PC as i32), + #[cfg(feature = "arch_arm")] + Arch::ARM64 => Ok(RegisterARM64::PC as i32), + #[cfg(feature = "arch_mips")] + Arch::MIPS => Ok(RegisterMIPS::PC as i32), + #[cfg(feature = "arch_sparc")] + Arch::SPARC => Ok(RegisterSPARC::PC as i32), + #[cfg(feature = "arch_m68k")] + Arch::M68K => Ok(RegisterM68K::PC as i32), + #[cfg(feature = "arch_ppc")] + Arch::PPC => Ok(RegisterPPC::PC as i32), + #[cfg(feature = "arch_riscv")] + Arch::RISCV => Ok(RegisterRISCV::PC as i32), + #[cfg(feature = "arch_s390x")] + Arch::S390X => Ok(RegisterS390X::PC as i32), + #[cfg(feature = "arch_tricore")] + Arch::TRICORE => Ok(RegisterTRICORE::PC as i32), + // returns `uc_error::ARCH` for `Arch::MAX`, and any + // other architecture that are not compiled in + _ => Err(uc_error::ARCH), + } + } + /// Gets the current program counter for this `unicorn` instance. #[inline] pub fn pc_read(&self) -> Result { let arch = self.get_arch(); - let reg = match arch { - Arch::X86 => RegisterX86::RIP as i32, - Arch::ARM => RegisterARM::PC as i32, - Arch::ARM64 => RegisterARM64::PC as i32, - Arch::MIPS => RegisterMIPS::PC as i32, - Arch::SPARC => RegisterSPARC::PC as i32, - Arch::M68K => RegisterM68K::PC as i32, - Arch::PPC => RegisterPPC::PC as i32, - Arch::RISCV => RegisterRISCV::PC as i32, - Arch::S390X => RegisterS390X::PC as i32, - Arch::TRICORE => RegisterTRICORE::PC as i32, - Arch::MAX => panic!("Illegal Arch specified"), - }; - self.reg_read(reg) + + self.reg_read(Self::arch_to_pc_register(arch)?) } /// 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, - Arch::ARM => RegisterARM::PC as i32, - Arch::ARM64 => RegisterARM64::PC as i32, - Arch::MIPS => RegisterMIPS::PC as i32, - Arch::SPARC => RegisterSPARC::PC as i32, - Arch::M68K => RegisterM68K::PC as i32, - Arch::PPC => RegisterPPC::PC as i32, - Arch::RISCV => RegisterRISCV::PC as i32, - Arch::S390X => RegisterS390X::PC as i32, - Arch::TRICORE => RegisterTRICORE::PC as i32, - Arch::MAX => panic!("Illegal Arch specified"), - }; - self.reg_write(reg, value) + + self.reg_write(Self::arch_to_pc_register(arch)?, value) } pub fn ctl_get_mode(&self) -> Result { let mut result: i32 = Default::default(); - 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))) + 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(); - unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_PAGE_SIZE), &mut result) } - .and_then(|| Ok(result)) + 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> { - unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_PAGE_SIZE), page_size) }.into() + pub fn ctl_set_page_size(&self, page_size: u32) -> Result<(), uc_error> { + 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(); - 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)) + 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(); - unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_TIMEOUT), &mut result) } - .and(Ok(result)) + 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> { - unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_USE_EXITS), 1) }.into() + 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> { - unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_UC_USE_EXITS), 0) }.into() + 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 = 0usize; - unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_EXITS_CNT), &mut result) } - .and(Ok(result)) + 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); unsafe { - ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_UC_EXITS), exits.as_mut_ptr(), exits_count) + ffi::uc_ctl( + self.get_handle(), + UC_CTL_READ!(ControlType::UC_CTL_UC_EXITS), + exits.as_mut_ptr(), + exits_count, + ) } .and_then(|| unsafe { exits.set_len(exits_count); @@ -1086,10 +1137,7 @@ impl<'a, D> Unicorn<'a, D> { }) } - pub fn ctl_set_exits( - &self, - exits: &[u64], - ) -> Result<(), uc_error> { + pub fn ctl_set_exits(&self, exits: &[u64]) -> Result<(), uc_error> { unsafe { ffi::uc_ctl( self.get_handle(), @@ -1103,24 +1151,37 @@ impl<'a, D> Unicorn<'a, D> { pub fn ctl_get_cpu_model(&self) -> Result { let mut result: i32 = Default::default(); - unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ!(ControlType::UC_CTL_CPU_MODEL), &mut result) } - .and(Ok(result)) + 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> { - unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_CPU_MODEL), cpu_model) }.into() + pub fn ctl_set_cpu_model(&self, cpu_model: i32) -> Result<(), uc_error> { + unsafe { + ffi::uc_ctl( + self.get_handle(), + UC_CTL_WRITE!(ControlType::UC_CTL_CPU_MODEL), + cpu_model, + ) + } + .into() } - pub fn ctl_remove_cache( - &self, - address: u64, - end: u64, - ) -> Result<(), uc_error> { - unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TB_REMOVE_CACHE), address, end) } - .into() + pub fn ctl_remove_cache(&self, address: u64, end: u64) -> Result<(), uc_error> { + unsafe { + ffi::uc_ctl( + self.get_handle(), + UC_CTL_WRITE!(ControlType::UC_CTL_TB_REMOVE_CACHE), + address, + end, + ) + } + .into() } pub fn ctl_request_cache( @@ -1128,29 +1189,56 @@ impl<'a, D> Unicorn<'a, D> { address: u64, tb: &mut TranslationBlock, ) -> Result<(), uc_error> { - unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_READ_WRITE!(ControlType::UC_CTL_TB_REQUEST_CACHE), address, tb) } - .into() + 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> { - unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TB_FLUSH)) }.into() + 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> { - unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TLB_FLUSH)) }.into() + 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_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, - ) -> Result<(), uc_error> { - unsafe { ffi::uc_ctl(self.get_handle(), UC_CTL_WRITE!(ControlType::UC_CTL_TLB_TYPE), t as i32) }.into() + pub fn ctl_tlb_type(&self, t: TlbType) -> Result<(), uc_error> { + 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 5f8c80fd4a..6d122e14c2 100644 --- a/bindings/rust/src/unicorn_const.rs +++ b/bindings/rust/src/unicorn_const.rs @@ -14,37 +14,34 @@ 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 { + pub fn and_then Result>(self, op: F) -> Result { if let Self::OK = self { op() } else { @@ -55,10 +52,7 @@ impl uc_error { /// 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 { + pub fn and(self, res: Result) -> Result { if let Self::OK = self { res } else { @@ -80,22 +74,22 @@ impl From for Result<(), uc_error> { #[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, } @@ -142,10 +136,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! { @@ -171,17 +165,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 { @@ -268,23 +262,23 @@ 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_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, + UC_CTL_IO_READ = 1 << 31, + UC_CTL_IO_WRITE = 1 << 30, } bitflags! {