feat(rust): improve ARM CP register ergonomics (#2160)

This commit is contained in:
Amaan Qureshi
2025-04-12 22:36:24 -04:00
committed by GitHub
parent 1b98fec009
commit f0bdeb5a74
7 changed files with 184 additions and 51 deletions

View File

@@ -215,11 +215,11 @@ where
pub unsafe extern "C" fn insn_sys_hook_proxy_arm64<D, F>(
uc: *mut uc_engine,
reg: sys::RegisterARM64,
cp_reg: *const sys::RegisterARM64_CP,
cp_reg: *const sys::RegisterARM64CP,
user_data: *mut UcHook<D, F>,
) -> bool
where
F: FnMut(&mut crate::Unicorn<D>, sys::RegisterARM64, &sys::RegisterARM64_CP) -> bool,
F: FnMut(&mut crate::Unicorn<D>, sys::RegisterARM64, &sys::RegisterARM64CP) -> bool,
{
let user_data = unsafe { &mut *user_data };
let mut user_data_uc = Unicorn {

View File

@@ -573,7 +573,7 @@ impl<'a, D> Unicorn<'a, D> {
}
/// Read ARM Coprocessor register
pub fn reg_read_arm_coproc(&self, reg: &mut RegisterARM_CP) -> Result<(), uc_error> {
pub fn reg_read_arm_coproc(&self, reg: &mut RegisterARMCP) -> Result<(), uc_error> {
let curr_arch = self.get_arch();
match curr_arch {
#[cfg(feature = "arch_arm")]
@@ -585,14 +585,33 @@ impl<'a, D> Unicorn<'a, D> {
uc_reg_read(
self.get_handle(),
RegisterARM::CP_REG.into(),
core::ptr::from_mut::<RegisterARM_CP>(reg).cast(),
core::ptr::from_mut(reg).cast(),
)
}
.into()
}
/// Write ARM Coprocessor register
pub fn reg_write_arm_coproc(&mut self, reg: &RegisterARMCP) -> Result<(), uc_error> {
let curr_arch = self.get_arch();
match curr_arch {
#[cfg(feature = "arch_arm")]
Arch::ARM => {}
_ => return Err(uc_error::ARCH),
}
unsafe {
uc_reg_write(
self.get_handle(),
RegisterARM::CP_REG.into(),
core::ptr::from_ref(reg).cast(),
)
}
.into()
}
/// Read ARM64 Coprocessor register
pub fn reg_read_arm64_coproc(&self) -> Result<RegisterARM64_CP, uc_error> {
pub fn reg_read_arm64_coproc(&self, reg: &mut RegisterARM64CP) -> Result<(), uc_error> {
let curr_arch = self.get_arch();
match curr_arch {
#[cfg(feature = "arch_aarch64")]
@@ -600,17 +619,33 @@ impl<'a, D> Unicorn<'a, D> {
_ => return Err(uc_error::ARCH),
}
let regid = RegisterARM64::CP_REG;
let mut reg = RegisterARM64_CP {
crn: 0,
crm: 0,
op0: 0,
op1: 0,
op2: 0,
val: 0,
};
unsafe {
uc_reg_read(
self.get_handle(),
RegisterARM64::CP_REG.into(),
core::ptr::from_mut(reg).cast(),
)
}
.and(Ok(()))
}
unsafe { uc_reg_read(self.get_handle(), regid as i32, (&raw mut reg).cast()) }.and(Ok(reg))
/// Write ARM64 Coprocessor register
pub fn reg_write_arm64_coproc(&mut self, reg: &RegisterARM64CP) -> Result<(), uc_error> {
let curr_arch = self.get_arch();
match curr_arch {
#[cfg(feature = "arch_aarch64")]
Arch::ARM64 => {}
_ => return Err(uc_error::ARCH),
}
unsafe {
uc_reg_write(
self.get_handle(),
RegisterARM64::CP_REG.into(),
core::ptr::from_ref(reg).cast(),
)
}
.and(Ok(()))
}
#[cfg(feature = "arch_arm")]
@@ -925,7 +960,7 @@ impl<'a, D> Unicorn<'a, D> {
callback: F,
) -> Result<UcHookId, uc_error>
where
F: FnMut(&mut Unicorn<D>, RegisterARM64, &RegisterARM64_CP) -> bool + 'a,
F: FnMut(&mut Unicorn<D>, RegisterARM64, &RegisterARM64CP) -> bool + 'a,
{
let mut hook_id = 0;
let mut user_data = Box::new(hook::UcHook {

View File

@@ -1,5 +1,5 @@
use super::*;
use crate::{ArmCpuModel, RegisterARM, RegisterARM_CP, TcgOpCode, TcgOpFlag, uc_error};
use crate::{ArmCpuModel, RegisterARM, RegisterARMCP, TcgOpCode, TcgOpFlag, uc_error};
#[test]
fn test_arm_nop() {
@@ -600,16 +600,7 @@ fn test_arm_mem_access_abort() {
#[test]
fn test_arm_read_sctlr() {
let uc = Unicorn::new(Arch::ARM, Mode::ARM).unwrap();
let mut reg = RegisterARM_CP {
cp: 15,
is64: 0,
sec: 0,
crn: 1,
crm: 0,
opc1: 0,
opc2: 0,
val: 0,
};
let mut reg = RegisterARMCP::new().cp(15).crn(1);
uc.reg_read_arm_coproc(&mut reg).unwrap();
assert_eq!((reg.val >> 31) & 1, 0);
}
@@ -620,16 +611,7 @@ fn test_arm_be_cpsr_sctlr() {
uc.ctl_set_cpu_model(ArmCpuModel::Model_1176 as i32)
.unwrap();
let mut reg = RegisterARM_CP {
cp: 15,
is64: 0,
sec: 0,
crn: 1,
crm: 0,
opc1: 0,
opc2: 0,
val: 0,
};
let mut reg = RegisterARMCP::new().cp(15).crn(1);
uc.reg_read_arm_coproc(&mut reg).unwrap();
let cpsr = uc.reg_read(RegisterARM::CPSR).unwrap();
@@ -640,16 +622,7 @@ fn test_arm_be_cpsr_sctlr() {
uc.ctl_set_cpu_model(ArmCpuModel::CORTEX_A15 as i32)
.unwrap();
let mut reg = RegisterARM_CP {
cp: 15,
is64: 0,
sec: 0,
crn: 1,
crm: 0,
opc1: 0,
opc2: 0,
val: 0,
};
let mut reg = RegisterARMCP::new().cp(15).crn(1);
uc.reg_read_arm_coproc(&mut reg).unwrap();
let cpsr = uc.reg_read(RegisterARM::CPSR).unwrap();

View File

@@ -1,4 +1,4 @@
use unicorn_engine_sys::{Arm64CpuModel, Arm64Insn, RegisterARM64};
use unicorn_engine_sys::{Arm64CpuModel, Arm64Insn, RegisterARM64, RegisterARM64CP};
use super::*;
@@ -142,7 +142,8 @@ fn test_arm64_v8_pac() {
fn test_arm64_read_sctlr() {
let uc = Unicorn::new(Arch::ARM64, Mode::ARM | Mode::LITTLE_ENDIAN).unwrap();
let reg = uc.reg_read_arm64_coproc().unwrap();
let mut reg = RegisterARM64CP::new().crn(1).op0(0b11);
uc.reg_read_arm64_coproc(&mut reg).unwrap();
assert_eq!(reg.val >> 58, 0);
}

View File

@@ -25,7 +25,6 @@ fn test_ppc32_add() {
// https://www.ibm.com/docs/en/aix/7.2?topic=set-fadd-fa-floating-add-instruction
#[test]
// #[ignore = "Crashes on Windows & some Linux distros"]
fn test_ppc32_fadd() {
let code = [
0xfc, 0xc4, 0x28, 0x2a, // fadd 6, 4, 5

View File

@@ -227,7 +227,7 @@ impl ParseCallbacks for Renamer {
return original_item_name
.strip_prefix("uc_")
.and_then(|suffix| suffix.strip_suffix("_reg"))
.map(|suffix| format!("Register{}", suffix.to_uppercase()));
.map(|suffix| format!("Register{}", suffix.replace('_', "").to_uppercase()));
}
if original_item_name.ends_with("_insn") {

View File

@@ -113,6 +113,131 @@ impl ControlType {
pub const IO_WRITE: Self = Self(1 << 30);
}
impl Default for RegisterARMCP {
fn default() -> Self {
Self::new()
}
}
impl RegisterARMCP {
#[must_use]
pub const fn new() -> Self {
Self {
cp: 0,
is64: 0,
sec: 0,
crn: 0,
crm: 0,
opc1: 0,
opc2: 0,
val: 0,
}
}
#[must_use]
pub const fn cp(mut self, cp: u32) -> Self {
self.cp = cp;
self
}
#[must_use]
pub const fn is64(mut self, is64: u32) -> Self {
self.is64 = is64;
self
}
#[must_use]
pub const fn sec(mut self, sec: u32) -> Self {
self.sec = sec;
self
}
#[must_use]
pub const fn crn(mut self, crn: u32) -> Self {
self.crn = crn;
self
}
#[must_use]
pub const fn crm(mut self, crm: u32) -> Self {
self.crm = crm;
self
}
#[must_use]
pub const fn opc1(mut self, opc1: u32) -> Self {
self.opc1 = opc1;
self
}
#[must_use]
pub const fn opc2(mut self, opc2: u32) -> Self {
self.opc2 = opc2;
self
}
#[must_use]
pub const fn val(mut self, val: u64) -> Self {
self.val = val;
self
}
}
impl Default for RegisterARM64CP {
fn default() -> Self {
Self::new()
}
}
impl RegisterARM64CP {
#[must_use]
pub const fn new() -> Self {
Self {
crn: 0,
crm: 0,
op0: 0,
op1: 0,
op2: 0,
val: 0,
}
}
#[must_use]
pub const fn crn(mut self, crn: u32) -> Self {
self.crn = crn;
self
}
#[must_use]
pub const fn crm(mut self, crm: u32) -> Self {
self.crm = crm;
self
}
#[must_use]
pub const fn op0(mut self, op0: u32) -> Self {
self.op0 = op0;
self
}
#[must_use]
pub const fn op1(mut self, op1: u32) -> Self {
self.op1 = op1;
self
}
#[must_use]
pub const fn op2(mut self, op2: u32) -> Self {
self.op2 = op2;
self
}
#[must_use]
pub const fn val(mut self, val: u64) -> Self {
self.val = val;
self
}
}
impl From<M68kCpuModel> for i32 {
fn from(value: M68kCpuModel) -> Self {
value as Self