use core::convert::From;
use core::{cmp, fmt, slice};
use capstone_sys::{
arm_op_mem, arm_op_type, cs_arm, cs_arm_op, arm_shifter,
cs_arm_op__bindgen_ty_2};
use libc::c_uint;
pub use crate::arch::arch_builder::arm::*;
use crate::arch::DetailsArchInsn;
use crate::instruction::{RegId, RegIdInt};
pub use capstone_sys::arm_insn_group as ArmInsnGroup;
pub use capstone_sys::arm_insn as ArmInsn;
pub use capstone_sys::arm_reg as ArmReg;
pub use capstone_sys::arm_vectordata_type as ArmVectorData;
pub use capstone_sys::arm_cpsmode_type as ArmCPSMode;
pub use capstone_sys::arm_cpsflag_type as ArmCPSFlag;
pub use capstone_sys::arm_cc as ArmCC;
pub use capstone_sys::arm_mem_barrier as ArmMemBarrier;
pub use capstone_sys::arm_setend_type as ArmSetendType;
pub struct ArmInsnDetail<'a>(pub(crate) &'a cs_arm);
#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
pub enum ArmShift {
Invalid,
Asr(u32),
Lsl(u32),
Lsr(u32),
Ror(u32),
Rrx(u32),
AsrReg(RegId),
LslReg(RegId),
LsrReg(RegId),
RorReg(RegId),
RrxReg(RegId),
}
impl ArmShift {
fn new(type_: arm_shifter, value: c_uint) -> ArmShift {
use self::arm_shifter::*;
use self::ArmShift::*;
macro_rules! arm_shift_match {
(
imm = [ $( $imm_r_enum:ident = $imm_c_enum:ident, )* ]
reg = [ $( $reg_r_enum:ident = $reg_c_enum:ident, )* ]
) => {
match type_ {
ARM_SFT_INVALID => Invalid,
$(
$imm_c_enum => $imm_r_enum(value as u32) ,
)*
$(
$reg_c_enum => $reg_r_enum(RegId(value as RegIdInt)) ,
)*
}
}
}
arm_shift_match!(
imm = [
Asr = ARM_SFT_ASR, Lsl = ARM_SFT_LSL, Lsr = ARM_SFT_LSR,
Ror = ARM_SFT_ROR, Rrx = ARM_SFT_RRX,
]
reg = [
AsrReg = ARM_SFT_ASR_REG, LslReg = ARM_SFT_LSL_REG, LsrReg = ARM_SFT_LSR_REG,
RorReg = ARM_SFT_ROR_REG, RrxReg = ARM_SFT_RRX_REG,
]
)
}
}
impl ArmOperandType {
fn new(op_type: arm_op_type, value: cs_arm_op__bindgen_ty_2) -> ArmOperandType {
use self::arm_op_type::*;
use self::ArmOperandType::*;
match op_type {
ARM_OP_INVALID => Invalid,
ARM_OP_REG => Reg(RegId(unsafe { value.reg } as RegIdInt)),
ARM_OP_IMM => Imm(unsafe { value.imm }),
ARM_OP_MEM => Mem(ArmOpMem(unsafe { value.mem })),
ARM_OP_FP => Fp(unsafe { value.fp }),
ARM_OP_CIMM => Cimm(unsafe { value.imm }),
ARM_OP_PIMM => Pimm(unsafe { value.imm }),
ARM_OP_SETEND => Setend(unsafe { value.setend }),
ARM_OP_SYSREG => SysReg(RegId(unsafe { value.reg } as RegIdInt)),
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct ArmOperand {
pub vector_index: Option<u32>,
pub subtracted: bool,
pub shift: ArmShift,
pub op_type: ArmOperandType,
}
#[derive(Clone, Debug, PartialEq)]
pub enum ArmOperandType {
Reg(RegId),
Imm(i32),
Mem(ArmOpMem),
Fp(f64),
Cimm(i32),
Pimm(i32),
Setend(ArmSetendType),
SysReg(RegId),
Invalid,
}
#[derive(Debug, Copy, Clone)]
pub struct ArmOpMem(pub(crate) arm_op_mem);
impl<'a> ArmInsnDetail<'a> {
pub fn usermode(&self) -> bool {
self.0.usermode
}
pub fn vector_size(&self) -> i32 {
self.0.vector_size as i32
}
pub fn vector_data(&self) -> ArmVectorData {
self.0.vector_data
}
pub fn cps_mode(&self) -> ArmCPSMode {
self.0.cps_mode
}
pub fn cps_flag(&self) -> ArmCPSFlag {
self.0.cps_flag
}
pub fn cc(&self) -> ArmCC {
self.0.cc
}
pub fn update_flags(&self) -> bool {
self.0.update_flags
}
pub fn writeback(&self) -> bool {
self.0.writeback
}
pub fn mem_barrier(&self) -> ArmMemBarrier {
self.0.mem_barrier
}
}
impl_PartialEq_repr_fields!(ArmInsnDetail<'a> [ 'a ];
usermode, vector_size, vector_data, cps_mode, cps_flag, cc, update_flags, writeback,
mem_barrier, operands
);
impl ArmOpMem {
pub fn base(&self) -> RegId {
RegId(self.0.base as RegIdInt)
}
pub fn index(&self) -> RegId {
RegId(self.0.index as RegIdInt)
}
pub fn scale(&self) -> i32 {
self.0.scale as i32
}
pub fn disp(&self) -> i32 {
self.0.disp as i32
}
}
impl_PartialEq_repr_fields!(ArmOpMem;
base, index, scale, disp
);
impl cmp::Eq for ArmOpMem {}
impl Default for ArmOperand {
fn default() -> Self {
ArmOperand {
vector_index: None,
subtracted: false,
shift: ArmShift::Invalid,
op_type: ArmOperandType::Invalid
}
}
}
impl<'a> From<&'a cs_arm_op> for ArmOperand {
fn from(op: &cs_arm_op) -> ArmOperand {
let shift = ArmShift::new(op.shift.type_, op.shift.value);
let op_type = ArmOperandType::new(op.type_, op.__bindgen_anon_1);
let vector_index = if op.vector_index >= 0 {
Some(op.vector_index as u32)
} else {
None
};
ArmOperand {
vector_index,
shift,
op_type,
subtracted: op.subtracted,
}
}
}
def_arch_details_struct!(
InsnDetail = ArmInsnDetail;
Operand = ArmOperand;
OperandIterator = ArmOperandIterator;
OperandIteratorLife = ArmOperandIterator<'a>;
[ pub struct ArmOperandIterator<'a>(slice::Iter<'a, cs_arm_op>); ]
cs_arch_op = cs_arm_op;
cs_arch = cs_arm;
);
#[cfg(test)]
mod test {
use super::*;
use capstone_sys::*;
#[test]
fn test_armshift() {
use super::arm_shifter::*;
use super::ArmShift::*;
use libc::c_uint;
fn t(shift_type_value: (arm_shifter, c_uint), arm_shift: ArmShift) {
let (shift_type, value) = shift_type_value;
assert_eq!(arm_shift, ArmShift::new(shift_type, value));
}
t((ARM_SFT_INVALID, 0), Invalid);
t((ARM_SFT_ASR, 0), Asr(0));
t((ARM_SFT_ASR_REG, 42), AsrReg(RegId(42)));
t((ARM_SFT_RRX_REG, 42), RrxReg(RegId(42)));
}
#[test]
fn test_arm_op_type() {
use super::arm_op_type::*;
use super::ArmOperandType::*;
fn t(
op_type_value: (arm_op_type, cs_arm_op__bindgen_ty_2),
expected_op_type: ArmOperandType,
) {
let (op_type, op_value) = op_type_value;
let op_type = ArmOperandType::new(op_type, op_value);
assert_eq!(expected_op_type, op_type);
}
t(
(ARM_OP_INVALID, cs_arm_op__bindgen_ty_2 { reg: 0 }),
Invalid,
);
t(
(ARM_OP_REG, cs_arm_op__bindgen_ty_2 { reg: 0 }),
Reg(RegId(0)),
);
}
#[test]
fn test_arm_insn_detail_eq() {
let a1 = cs_arm {
usermode: false,
vector_size: 0,
vector_data: arm_vectordata_type::ARM_VECTORDATA_INVALID,
cps_mode: arm_cpsmode_type::ARM_CPSMODE_INVALID,
cps_flag: arm_cpsflag_type::ARM_CPSFLAG_INVALID,
cc: arm_cc::ARM_CC_INVALID,
update_flags: false,
writeback: false,
mem_barrier: arm_mem_barrier::ARM_MB_INVALID,
op_count: 0,
operands: [
cs_arm_op {
vector_index: 0,
shift: cs_arm_op__bindgen_ty_1 {
type_: arm_shifter::ARM_SFT_INVALID,
value: 0
},
type_: arm_op_type::ARM_OP_INVALID,
__bindgen_anon_1: cs_arm_op__bindgen_ty_2 { imm: 0 },
subtracted: false,
access: 0,
neon_lane: 0,
}
; 36]
};
let a2 = cs_arm {
usermode: true,
..a1
};
let a3 = cs_arm {
op_count: 20,
..a1
};
let a4 = cs_arm {
op_count: 19,
..a1
};
let a4_clone = a4.clone();
assert_eq!(ArmInsnDetail(&a1), ArmInsnDetail(&a1));
assert_ne!(ArmInsnDetail(&a1), ArmInsnDetail(&a2));
assert_ne!(ArmInsnDetail(&a1), ArmInsnDetail(&a3));
assert_ne!(ArmInsnDetail(&a3), ArmInsnDetail(&a4));
assert_eq!(ArmInsnDetail(&a4), ArmInsnDetail(&a4_clone));
}
}