use core::convert::From;
use core::convert::TryInto;
use core::{cmp, fmt, slice};
use capstone_sys::{
cs_ac_type, cs_x86, cs_x86_op, cs_x86_op__bindgen_ty_1, x86_op_mem, x86_op_type,
};
pub use capstone_sys::x86_insn_group as X86InsnGroup;
pub use capstone_sys::x86_insn as X86Insn;
pub use capstone_sys::x86_reg as X86Reg;
pub use capstone_sys::x86_prefix as X86Prefix;
pub use capstone_sys::x86_avx_bcast as X86AvxBcast;
pub use capstone_sys::x86_sse_cc as X86SseCC;
pub use capstone_sys::x86_avx_cc as X86AvxCC;
pub use capstone_sys::x86_xop_cc as X86XopCC;
pub use capstone_sys::x86_avx_rm as X86AvxRm;
pub use crate::arch::arch_builder::x86::*;
use crate::arch::DetailsArchInsn;
use crate::instruction::{RegAccessType, RegId, RegIdInt};
pub struct X86InsnDetail<'a>(pub(crate) &'a cs_x86);
impl X86OperandType {
fn new(op_type: x86_op_type, value: cs_x86_op__bindgen_ty_1) -> X86OperandType {
use self::x86_op_type::*;
use self::X86OperandType::*;
match op_type {
X86_OP_REG => Reg(RegId(unsafe { value.reg } as RegIdInt)),
X86_OP_IMM => Imm(unsafe { value.imm }),
X86_OP_MEM => Mem(X86OpMem(unsafe { value.mem })),
X86_OP_INVALID => Invalid,
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct X86Operand {
pub size: u8,
pub access: Option<RegAccessType>,
pub avx_bcast: X86AvxBcast,
pub avx_zero_opmask: bool,
pub op_type: X86OperandType,
}
#[derive(Clone, Debug, PartialEq)]
pub enum X86OperandType {
Reg(RegId),
Imm(i64),
Mem(X86OpMem),
Invalid,
}
#[derive(Debug, Copy, Clone)]
pub struct X86OpMem(pub(crate) x86_op_mem);
impl<'a> X86InsnDetail<'a> {
pub fn prefix(&self) -> &[u8; 4] {
&self.0.prefix
}
pub fn opcode(&self) -> &[u8; 4] {
&self.0.opcode
}
pub fn rex(&self) -> u8 {
self.0.rex
}
pub fn addr_size(&self) -> u8 {
self.0.addr_size
}
pub fn modrm(&self) -> u8 {
self.0.modrm
}
pub fn sib(&self) -> u8 {
self.0.sib
}
pub fn disp(&self) -> i64 {
self.0.disp
}
pub fn sib_index(&self) -> RegId {
RegId(self.0.sib_index as RegIdInt)
}
pub fn sib_scale(&self) -> i8 {
self.0.sib_scale
}
pub fn sib_base(&self) -> RegId {
RegId(self.0.sib_base as RegIdInt)
}
pub fn xop_cc(&self) -> X86XopCC {
self.0.xop_cc
}
pub fn sse_cc(&self) -> X86SseCC {
self.0.sse_cc
}
pub fn avx_cc(&self) -> X86AvxCC {
self.0.avx_cc
}
pub fn avx_sae(&self) -> bool {
self.0.avx_sae
}
pub fn avx_rm(&self) -> X86AvxRm {
self.0.avx_rm
}
}
impl_PartialEq_repr_fields!(X86InsnDetail<'a> [ 'a ];
prefix, opcode, rex, addr_size, modrm, sib, disp, sib_index, sib_scale, sib_base, sse_cc,
avx_cc, avx_sae, avx_rm, operands
);
impl X86OpMem {
pub fn segment(&self) -> RegId {
RegId(self.0.segment as RegIdInt)
}
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) -> i64 {
self.0.disp
}
}
impl_PartialEq_repr_fields!(X86OpMem;
segment, base, index, scale, disp
);
impl cmp::Eq for X86OpMem {}
impl Default for X86Operand {
fn default() -> Self {
X86Operand {
size: 0,
access: None,
avx_bcast: X86AvxBcast::X86_AVX_BCAST_INVALID,
avx_zero_opmask: false,
op_type: X86OperandType::Invalid,
}
}
}
impl<'a> From<&'a cs_x86_op> for X86Operand {
fn from(op: &cs_x86_op) -> X86Operand {
let op_type = X86OperandType::new(op.type_, op.__bindgen_anon_1);
X86Operand {
size: op.size,
access: cs_ac_type(op.access as _).try_into().ok(),
avx_bcast: op.avx_bcast,
avx_zero_opmask: op.avx_zero_opmask,
op_type,
}
}
}
def_arch_details_struct!(
InsnDetail = X86InsnDetail;
Operand = X86Operand;
OperandIterator = X86OperandIterator;
OperandIteratorLife = X86OperandIterator<'a>;
[ pub struct X86OperandIterator<'a>(slice::Iter<'a, cs_x86_op>); ]
cs_arch_op = cs_x86_op;
cs_arch = cs_x86;
);
#[cfg(test)]
mod test {
use super::*;
use capstone_sys::*;
#[test]
fn test_x86_op_type() {
use super::x86_op_type::*;
use super::X86OperandType::*;
fn t(
op_type_value: (x86_op_type, cs_x86_op__bindgen_ty_1),
expected_op_type: X86OperandType,
) {
let (op_type, op_value) = op_type_value;
let op_type = X86OperandType::new(op_type, op_value);
assert_eq!(expected_op_type, op_type);
}
t(
(X86_OP_INVALID, cs_x86_op__bindgen_ty_1 { reg: 0 }),
Invalid,
);
t(
(X86_OP_REG, cs_x86_op__bindgen_ty_1 { reg: 0 }),
Reg(RegId(0)),
);
}
#[test]
fn test_x86_op_eq() {
let a1 = X86Operand {
op_type: X86OperandType::Imm(0),
..Default::default()
};
let a2 = X86Operand {
op_type: X86OperandType::Imm(-100),
..Default::default()
};
assert_eq!(a1, a1.clone());
assert_ne!(a1, a2.clone());
}
#[test]
fn test_x86_insn_eq() {
fn t_eq(a: &cs_x86, b: &cs_x86) {
assert_eq!(X86InsnDetail(a), X86InsnDetail(b))
}
fn t_ne(a: &cs_x86, b: &cs_x86) {
assert_ne!(X86InsnDetail(a), X86InsnDetail(b))
}
let a1 = cs_x86 {
prefix: [0, 0, 0, 0],
opcode: [0, 0, 0, 0],
rex: 0,
addr_size: 0,
modrm: 0,
sib: 0,
disp: 0,
sib_index: x86_reg::X86_REG_INVALID,
sib_scale: 0,
sib_base: x86_reg::X86_REG_INVALID,
sse_cc: x86_sse_cc::X86_SSE_CC_INVALID,
avx_cc: x86_avx_cc::X86_AVX_CC_INVALID,
avx_sae: false,
avx_rm: x86_avx_rm::X86_AVX_RM_INVALID,
op_count: 0,
__bindgen_anon_1: cs_x86__bindgen_ty_1 {
eflags: 0,
},
encoding: cs_x86_encoding {
modrm_offset: 0,
disp_offset: 0,
disp_size: 0,
imm_offset: 0,
imm_size: 0,
},
xop_cc: x86_xop_cc::X86_XOP_CC_INVALID,
operands: [ cs_x86_op {
type_: x86_op_type::X86_OP_INVALID,
__bindgen_anon_1: cs_x86_op__bindgen_ty_1 { reg: x86_reg::X86_REG_INVALID },
size: 0,
avx_bcast: x86_avx_bcast::X86_AVX_BCAST_INVALID,
avx_zero_opmask: false,
access: 0,
}
; 8],
};
let mut a2 = a1.clone();
a2.operands[1].type_ = x86_op_type::X86_OP_REG;
let a1_clone = cs_x86 {
..a1
};
let a3 = cs_x86 {
rex: 1,
..a1
};
let op_count_differ = cs_x86 {
op_count: 1,
..a1
};
let mut op1_differ = op_count_differ.clone();
op1_differ.operands[0].avx_bcast = x86_avx_bcast::X86_AVX_BCAST_2;
t_eq(&a1, &a1);
t_eq(&a1, &a2);
t_eq(&a1, &a1_clone);
t_ne(&a1, &a3);
t_ne(&a1, &op_count_differ);
t_ne(&op_count_differ, &op1_differ);
}
}