add rust bindings for uc_ctl

This commit is contained in:
Kevin Schneider
2023-03-30 13:44:59 +02:00
parent 51a5b68b50
commit 5ff654c77b
3 changed files with 190 additions and 0 deletions

View File

@@ -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> {

View File

@@ -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<Mode, uc_error> {
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<u32, uc_error> {
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<Arch, uc_error> {
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<u64, uc_error> {
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<usize, uc_error> {
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<Vec<u64>, uc_error> {
let exits_count: libc::size_t = self.ctl_get_exits_count()?;
let mut exits: Vec<u64> = 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<i32, uc_error> {
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)
}
}
}

View File

@@ -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,
}