From 30b99601d2ad4c4ac581a1fb5a3e610cab66b3d0 Mon Sep 17 00:00:00 2001 From: lockbox Date: Wed, 27 Mar 2024 16:54:51 -0400 Subject: [PATCH 1/2] apply default rust 2021 formatting --- bindings/rust/src/ffi.rs | 74 ++---- bindings/rust/src/lib.rs | 369 ++++++++++++++++------------- bindings/rust/src/unicorn_const.rs | 114 +++++---- 3 files changed, 269 insertions(+), 288 deletions(-) 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..4f61d6b90f 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -103,11 +103,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 +120,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 +174,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 +212,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 +230,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 +275,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 +416,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 +437,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,44 +478,32 @@ 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(); @@ -575,12 +544,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 +658,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 +687,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 +716,7 @@ 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, { @@ -788,10 +746,7 @@ 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), { @@ -892,10 +847,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 +860,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 +880,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 +896,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,10 +927,7 @@ 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)) } @@ -1008,10 +954,7 @@ 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, @@ -1031,54 +974,107 @@ impl<'a, D> Unicorn<'a, D> { 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 +1082,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 +1096,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 +1134,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! { From c850db112501ac6d2efcede98092039327b54ada Mon Sep 17 00:00:00 2001 From: lockbox Date: Wed, 27 Mar 2024 17:30:53 -0400 Subject: [PATCH 2/2] Inherit architecture support from cfg features While the bindings conditionally compile code based on the cfg flags, we still include the architecture support in emitted rust code. This patch removes the ability to refer to architectures that cannot possibly be supported. --- bindings/rust/src/lib.rs | 135 +++++++++++++++++++++++++++------------ 1 file changed, 95 insertions(+), 40 deletions(-) diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index 4f61d6b90f..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 { @@ -508,7 +548,9 @@ impl<'a, D> Unicorn<'a, D> { 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)?, }; @@ -517,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) @@ -528,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), @@ -716,6 +760,7 @@ impl<'a, D> Unicorn<'a, D> { } /// Add hook for x86 IN instruction. + #[cfg(feature = "arch_x86")] pub fn add_insn_in_hook(&mut self, callback: F) -> Result where F: FnMut(&mut Unicorn, u32, usize) -> u32, @@ -746,6 +791,7 @@ impl<'a, D> Unicorn<'a, D> { } /// Add hook for x86 OUT instruction. + #[cfg(feature = "arch_x86")] pub fn add_insn_out_hook(&mut self, callback: F) -> Result where F: FnMut(&mut Unicorn, u32, usize, u32), @@ -776,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, @@ -932,44 +979,52 @@ impl<'a, D> Unicorn<'a, D> { 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> { 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 {