diff --git a/bindings/rust/src/ffi.rs b/bindings/rust/src/ffi.rs index b1c04f57..37602392 100644 --- a/bindings/rust/src/ffi.rs +++ b/bindings/rust/src/ffi.rs @@ -86,6 +86,7 @@ extern "C" { pub fn uc_context_alloc(engine: uc_handle, context: *mut uc_context) -> uc_error; pub fn uc_context_save(engine: uc_handle, context: uc_context) -> uc_error; pub fn uc_context_restore(engine: uc_handle, context: uc_context) -> uc_error; + pub fn uc_ctl(engine: uc_handle, control: u32, ...) -> uc_error; } pub struct UcHook<'a, D: 'a, F: 'a> { diff --git a/bindings/rust/src/lib.rs b/bindings/rust/src/lib.rs index cb8497c7..0f1c7049 100644 --- a/bindings/rust/src/lib.rs +++ b/bindings/rust/src/lib.rs @@ -30,7 +30,9 @@ #[macro_use] extern crate alloc; +extern crate std; +#[macro_use] pub mod unicorn_const; mod arm; @@ -1051,4 +1053,148 @@ impl<'a, D> Unicorn<'a, D> { }; self.reg_write(reg, value) } + + 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) + } + } + + 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) + } + } + + 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) + } + } + + 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) + } + } + + 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) + } + } + + 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) + } + } + + 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) + } + } + + 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) + } + } + + 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) }; + if err == uc_error::OK { + 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) }; + if err == uc_error::OK { + Ok(()) + } else { + Err(err) + } + } + + 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) + } + } + + 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) + } + } + + 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 { + Err(err) + } + } + + 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 { + Err(err) + } + } + + pub fn ctl_flush_tlb(&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) + } + } } diff --git a/bindings/rust/src/unicorn_const.rs b/bindings/rust/src/unicorn_const.rs index 7e8185d2..b0b440c4 100644 --- a/bindings/rust/src/unicorn_const.rs +++ b/bindings/rust/src/unicorn_const.rs @@ -187,3 +187,46 @@ bitflags! { const RISCV64 = Self::MIPS64.bits; } } + +// Represent a TranslationBlock. +#[repr(C)] +pub struct TranslationBlock { + pub pc: u64, + pub icount: u16, + pub size: u16 +} + +macro_rules! UC_CTL_READ { + ($expr:expr) => { + $expr as u32 | ControlType::UC_CTL_IO_READ as u32 + }; +} + +macro_rules! UC_CTL_WRITE { + ($expr:expr) => { + $expr as u32 | ControlType::UC_CTL_IO_WRITE as u32 + }; +} + +macro_rules! UC_CTL_READ_WRITE { + ($expr:expr) => { + $expr as u32 | ControlType::UC_CTL_IO_WRITE as u32 | ControlType::UC_CTL_IO_READ as u32 + }; +} + +#[allow(clippy::upper_case_acronyms)] +pub enum ControlType { + UC_CTL_UC_MODE = 0, + UC_CTL_UC_PAGE_SIZE = 1, + 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_TB_REQUEST_CACHE = 8, + UC_CTL_TB_REMOVE_CACHE = 9, + UC_CTL_TB_FLUSH = 10, + UC_CTL_IO_READ = 1<<31, + UC_CTL_IO_WRITE = 1<<30, +}