use crate::encoder::iced_constants::IcedConstants;
use crate::encoder::instruction_fmt::*;
use crate::encoder::op_code_fmt::*;
use crate::encoder::op_kind_tables::*;
#[cfg(feature = "mvex")]
use crate::mvex::get_mvex_info;
use crate::*;
use alloc::string::String;
use core::{fmt, mem};
#[cfg(feature = "decoder")]
#[rustfmt::skip]
static TO_DECODER_OPTIONS: [u32; 18] = [
DecoderOptions::NONE,
DecoderOptions::ALTINST,
DecoderOptions::CL1INVMB,
DecoderOptions::CMPXCHG486A,
DecoderOptions::CYRIX,
DecoderOptions::CYRIX_DMI,
DecoderOptions::CYRIX_SMINT_0F7E,
DecoderOptions::JMPE,
DecoderOptions::LOADALL286,
DecoderOptions::LOADALL386,
DecoderOptions::MOV_TR,
DecoderOptions::MPX,
DecoderOptions::OLD_FPU,
DecoderOptions::PCOMMIT,
DecoderOptions::UMOV,
DecoderOptions::XBTS,
DecoderOptions::UDBG,
DecoderOptions::KNC,
];
struct Flags;
impl Flags {
pub const NONE: u16 = 0;
pub const IGNORES_ROUNDING_CONTROL: u16 = 0x0001;
pub const AMD_LOCK_REG_BIT: u16 = 0x0002;
pub const LIG: u16 = 0x0004;
pub const W: u16 = 0x0008;
pub const WIG: u16 = 0x0010;
pub const WIG32: u16 = 0x0020;
pub const CPL0: u16 = 0x0040;
pub const CPL1: u16 = 0x0080;
pub const CPL2: u16 = 0x0100;
pub const CPL3: u16 = 0x0200;
}
#[derive(Debug, Clone)]
pub struct OpCodeInfo {
op_code_string: String,
instruction_string: String,
enc_flags2: u32,
enc_flags3: u32,
opc_flags1: u32,
opc_flags2: u32,
code: Code,
op_code: u16,
flags: u16,
encoding: EncodingKind,
operand_size: u8,
address_size: u8,
l: u8,
tuple_type: TupleType,
table: OpCodeTableKind,
mandatory_prefix: MandatoryPrefix,
group_index: i8,
rm_group_index: i8,
op_kinds: [OpCodeOperandKind; IcedConstants::MAX_OP_COUNT],
}
impl OpCodeInfo {
#[allow(unused_mut)]
pub(super) fn new(code: Code, enc_flags1: u32, enc_flags2: u32, enc_flags3: u32, opc_flags1: u32, opc_flags2: u32, sb: &mut String) -> Self {
let mut flags = Flags::NONE;
let op_code = (enc_flags2 >> EncFlags2::OP_CODE_SHIFT) as u16;
if (enc_flags1 & EncFlags1::IGNORES_ROUNDING_CONTROL) != 0 {
flags |= Flags::IGNORES_ROUNDING_CONTROL;
}
if (enc_flags1 & EncFlags1::AMD_LOCK_REG_BIT) != 0 {
flags |= Flags::AMD_LOCK_REG_BIT;
}
match opc_flags1 & (OpCodeInfoFlags1::CPL0_ONLY | OpCodeInfoFlags1::CPL3_ONLY) {
OpCodeInfoFlags1::CPL0_ONLY => flags |= Flags::CPL0,
OpCodeInfoFlags1::CPL3_ONLY => flags |= Flags::CPL3,
_ => flags |= Flags::CPL0 | Flags::CPL1 | Flags::CPL2 | Flags::CPL3,
}
let op0_kind;
let op1_kind;
let op2_kind;
let op3_kind;
let op4_kind;
let mut l;
let mandatory_prefix;
let table;
let group_index;
let rm_group_index;
let tuple_type;
let operand_size;
let address_size;
let lkind;
let encoding = unsafe { mem::transmute(((enc_flags3 >> EncFlags3::ENCODING_SHIFT) & EncFlags3::ENCODING_MASK) as u8) };
mandatory_prefix =
match unsafe { mem::transmute(((enc_flags2 >> EncFlags2::MANDATORY_PREFIX_SHIFT) & EncFlags2::MANDATORY_PREFIX_MASK) as u8) } {
MandatoryPrefixByte::None => {
if (enc_flags2 & EncFlags2::HAS_MANDATORY_PREFIX) != 0 {
MandatoryPrefix::PNP
} else {
MandatoryPrefix::None
}
}
MandatoryPrefixByte::P66 => MandatoryPrefix::P66,
MandatoryPrefixByte::PF3 => MandatoryPrefix::PF3,
MandatoryPrefixByte::PF2 => MandatoryPrefix::PF2,
};
operand_size = match unsafe { mem::transmute(((enc_flags3 >> EncFlags3::OPERAND_SIZE_SHIFT) & EncFlags3::OPERAND_SIZE_MASK) as u8) } {
CodeSize::Unknown => 0,
CodeSize::Code16 => 16,
CodeSize::Code32 => 32,
CodeSize::Code64 => 64,
};
address_size = match unsafe { mem::transmute(((enc_flags3 >> EncFlags3::ADDRESS_SIZE_SHIFT) & EncFlags3::ADDRESS_SIZE_MASK) as u8) } {
CodeSize::Unknown => 0,
CodeSize::Code16 => 16,
CodeSize::Code32 => 32,
CodeSize::Code64 => 64,
};
group_index = if (enc_flags2 & EncFlags2::HAS_GROUP_INDEX) == 0 { -1 } else { ((enc_flags2 >> EncFlags2::GROUP_INDEX_SHIFT) & 7) as i8 };
rm_group_index =
if (enc_flags3 & EncFlags3::HAS_RM_GROUP_INDEX) == 0 { -1 } else { ((enc_flags2 >> EncFlags2::GROUP_INDEX_SHIFT) & 7) as i8 };
tuple_type = unsafe { mem::transmute(((enc_flags3 >> EncFlags3::TUPLE_TYPE_SHIFT) & EncFlags3::TUPLE_TYPE_MASK) as u8) };
#[cfg(not(any(not(feature = "no_vex"), not(feature = "no_xop"), not(feature = "no_evex"))))]
{
lkind = LKind::LZ;
l = 0;
}
#[cfg(any(not(feature = "no_vex"), not(feature = "no_xop"), not(feature = "no_evex")))]
match unsafe { mem::transmute(((enc_flags2 >> EncFlags2::LBIT_SHIFT) & EncFlags2::LBIT_MASK) as u8) } {
LBit::LZ => {
lkind = LKind::LZ;
l = 0;
}
LBit::L0 => {
lkind = LKind::L0;
l = 0;
}
LBit::L1 => {
lkind = LKind::L0;
l = 1;
}
LBit::L128 => {
lkind = LKind::L128;
l = 0;
}
LBit::L256 => {
lkind = LKind::L128;
l = 1;
}
LBit::L512 => {
lkind = LKind::L128;
l = 2;
}
LBit::LIG => {
lkind = LKind::None;
l = 0;
flags |= Flags::LIG;
}
}
#[cfg(any(not(feature = "no_vex"), not(feature = "no_xop"), not(feature = "no_evex")))]
match unsafe { mem::transmute(((enc_flags2 >> EncFlags2::WBIT_SHIFT) & EncFlags2::WBIT_MASK) as u8) } {
WBit::W0 => {}
WBit::W1 => flags |= Flags::W,
WBit::WIG => flags |= Flags::WIG,
WBit::WIG32 => flags |= Flags::WIG32,
}
let mut string_format = true;
match encoding {
EncodingKind::Legacy => {
op0_kind = LEGACY_OP_KINDS[((enc_flags1 >> EncFlags1::LEGACY_OP0_SHIFT) & EncFlags1::LEGACY_OP_MASK) as usize];
op1_kind = LEGACY_OP_KINDS[((enc_flags1 >> EncFlags1::LEGACY_OP1_SHIFT) & EncFlags1::LEGACY_OP_MASK) as usize];
op2_kind = LEGACY_OP_KINDS[((enc_flags1 >> EncFlags1::LEGACY_OP2_SHIFT) & EncFlags1::LEGACY_OP_MASK) as usize];
op3_kind = LEGACY_OP_KINDS[((enc_flags1 >> EncFlags1::LEGACY_OP3_SHIFT) & EncFlags1::LEGACY_OP_MASK) as usize];
op4_kind = OpCodeOperandKind::None;
table = match unsafe { mem::transmute(((enc_flags2 >> EncFlags2::TABLE_SHIFT) & EncFlags2::TABLE_MASK) as u8) } {
LegacyOpCodeTable::MAP0 => OpCodeTableKind::Normal,
LegacyOpCodeTable::MAP0F => OpCodeTableKind::T0F,
LegacyOpCodeTable::MAP0F38 => OpCodeTableKind::T0F38,
LegacyOpCodeTable::MAP0F3A => OpCodeTableKind::T0F3A,
};
}
#[cfg(feature = "no_vex")]
EncodingKind::VEX => {
op0_kind = OpCodeOperandKind::None;
op1_kind = OpCodeOperandKind::None;
op2_kind = OpCodeOperandKind::None;
op3_kind = OpCodeOperandKind::None;
op4_kind = OpCodeOperandKind::None;
table = OpCodeTableKind::Normal;
string_format = false;
}
#[cfg(not(feature = "no_vex"))]
EncodingKind::VEX => {
op0_kind = VEX_OP_KINDS[((enc_flags1 >> EncFlags1::VEX_OP0_SHIFT) & EncFlags1::VEX_OP_MASK) as usize];
op1_kind = VEX_OP_KINDS[((enc_flags1 >> EncFlags1::VEX_OP1_SHIFT) & EncFlags1::VEX_OP_MASK) as usize];
op2_kind = VEX_OP_KINDS[((enc_flags1 >> EncFlags1::VEX_OP2_SHIFT) & EncFlags1::VEX_OP_MASK) as usize];
op3_kind = VEX_OP_KINDS[((enc_flags1 >> EncFlags1::VEX_OP3_SHIFT) & EncFlags1::VEX_OP_MASK) as usize];
op4_kind = VEX_OP_KINDS[((enc_flags1 >> EncFlags1::VEX_OP4_SHIFT) & EncFlags1::VEX_OP_MASK) as usize];
table = match unsafe { mem::transmute(((enc_flags2 >> EncFlags2::TABLE_SHIFT) & EncFlags2::TABLE_MASK) as u8) } {
VexOpCodeTable::MAP0 => OpCodeTableKind::Normal,
VexOpCodeTable::MAP0F => OpCodeTableKind::T0F,
VexOpCodeTable::MAP0F38 => OpCodeTableKind::T0F38,
VexOpCodeTable::MAP0F3A => OpCodeTableKind::T0F3A,
};
}
#[cfg(feature = "no_evex")]
EncodingKind::EVEX => {
op0_kind = OpCodeOperandKind::None;
op1_kind = OpCodeOperandKind::None;
op2_kind = OpCodeOperandKind::None;
op3_kind = OpCodeOperandKind::None;
op4_kind = OpCodeOperandKind::None;
table = OpCodeTableKind::Normal;
string_format = false;
}
#[cfg(not(feature = "no_evex"))]
EncodingKind::EVEX => {
op0_kind = EVEX_OP_KINDS[((enc_flags1 >> EncFlags1::EVEX_OP0_SHIFT) & EncFlags1::EVEX_OP_MASK) as usize];
op1_kind = EVEX_OP_KINDS[((enc_flags1 >> EncFlags1::EVEX_OP1_SHIFT) & EncFlags1::EVEX_OP_MASK) as usize];
op2_kind = EVEX_OP_KINDS[((enc_flags1 >> EncFlags1::EVEX_OP2_SHIFT) & EncFlags1::EVEX_OP_MASK) as usize];
op3_kind = EVEX_OP_KINDS[((enc_flags1 >> EncFlags1::EVEX_OP3_SHIFT) & EncFlags1::EVEX_OP_MASK) as usize];
op4_kind = OpCodeOperandKind::None;
table = match unsafe { mem::transmute(((enc_flags2 >> EncFlags2::TABLE_SHIFT) & EncFlags2::TABLE_MASK) as u8) } {
EvexOpCodeTable::MAP0F => OpCodeTableKind::T0F,
EvexOpCodeTable::MAP0F38 => OpCodeTableKind::T0F38,
EvexOpCodeTable::MAP0F3A => OpCodeTableKind::T0F3A,
EvexOpCodeTable::MAP5 => OpCodeTableKind::MAP5,
EvexOpCodeTable::MAP6 => OpCodeTableKind::MAP6,
};
}
#[cfg(feature = "no_xop")]
EncodingKind::XOP => {
op0_kind = OpCodeOperandKind::None;
op1_kind = OpCodeOperandKind::None;
op2_kind = OpCodeOperandKind::None;
op3_kind = OpCodeOperandKind::None;
op4_kind = OpCodeOperandKind::None;
table = OpCodeTableKind::Normal;
string_format = false;
}
#[cfg(not(feature = "no_xop"))]
EncodingKind::XOP => {
op0_kind = XOP_OP_KINDS[((enc_flags1 >> EncFlags1::XOP_OP0_SHIFT) & EncFlags1::XOP_OP_MASK) as usize];
op1_kind = XOP_OP_KINDS[((enc_flags1 >> EncFlags1::XOP_OP1_SHIFT) & EncFlags1::XOP_OP_MASK) as usize];
op2_kind = XOP_OP_KINDS[((enc_flags1 >> EncFlags1::XOP_OP2_SHIFT) & EncFlags1::XOP_OP_MASK) as usize];
op3_kind = XOP_OP_KINDS[((enc_flags1 >> EncFlags1::XOP_OP3_SHIFT) & EncFlags1::XOP_OP_MASK) as usize];
op4_kind = OpCodeOperandKind::None;
table = match unsafe { mem::transmute(((enc_flags2 >> EncFlags2::TABLE_SHIFT) & EncFlags2::TABLE_MASK) as u8) } {
XopOpCodeTable::MAP8 => OpCodeTableKind::MAP8,
XopOpCodeTable::MAP9 => OpCodeTableKind::MAP9,
XopOpCodeTable::MAP10 => OpCodeTableKind::MAP10,
};
}
#[cfg(feature = "no_d3now")]
EncodingKind::D3NOW => {
op0_kind = OpCodeOperandKind::None;
op1_kind = OpCodeOperandKind::None;
op2_kind = OpCodeOperandKind::None;
op3_kind = OpCodeOperandKind::None;
op4_kind = OpCodeOperandKind::None;
table = OpCodeTableKind::Normal;
string_format = false;
}
#[cfg(not(feature = "no_d3now"))]
EncodingKind::D3NOW => {
op0_kind = OpCodeOperandKind::mm_reg;
op1_kind = OpCodeOperandKind::mm_or_mem;
op2_kind = OpCodeOperandKind::None;
op3_kind = OpCodeOperandKind::None;
op4_kind = OpCodeOperandKind::None;
table = OpCodeTableKind::T0F;
}
#[cfg(not(feature = "mvex"))]
EncodingKind::MVEX => {
op0_kind = OpCodeOperandKind::None;
op1_kind = OpCodeOperandKind::None;
op2_kind = OpCodeOperandKind::None;
op3_kind = OpCodeOperandKind::None;
op4_kind = OpCodeOperandKind::None;
table = OpCodeTableKind::Normal;
string_format = false;
}
#[cfg(feature = "mvex")]
EncodingKind::MVEX => {
op0_kind = MVEX_OP_KINDS[((enc_flags1 >> EncFlags1::MVEX_OP0_SHIFT) & EncFlags1::MVEX_OP_MASK) as usize];
op1_kind = MVEX_OP_KINDS[((enc_flags1 >> EncFlags1::MVEX_OP1_SHIFT) & EncFlags1::MVEX_OP_MASK) as usize];
op2_kind = MVEX_OP_KINDS[((enc_flags1 >> EncFlags1::MVEX_OP2_SHIFT) & EncFlags1::MVEX_OP_MASK) as usize];
op3_kind = MVEX_OP_KINDS[((enc_flags1 >> EncFlags1::MVEX_OP3_SHIFT) & EncFlags1::MVEX_OP_MASK) as usize];
op4_kind = OpCodeOperandKind::None;
table = match unsafe { mem::transmute(((enc_flags2 >> EncFlags2::TABLE_SHIFT) & EncFlags2::TABLE_MASK) as u8) } {
MvexOpCodeTable::MAP0F => OpCodeTableKind::T0F,
MvexOpCodeTable::MAP0F38 => OpCodeTableKind::T0F38,
MvexOpCodeTable::MAP0F3A => OpCodeTableKind::T0F3A,
};
}
}
let mut result = Self {
op_code_string: String::new(),
instruction_string: String::new(),
enc_flags2,
enc_flags3,
opc_flags1,
opc_flags2,
code,
op_code,
flags,
encoding,
operand_size,
address_size,
l,
tuple_type,
table,
mandatory_prefix,
group_index,
rm_group_index,
op_kinds: [op0_kind, op1_kind, op2_kind, op3_kind, op4_kind],
};
if string_format {
let op_code_string = OpCodeFormatter::new(&result, sb, lkind, (opc_flags1 & OpCodeInfoFlags1::MOD_REG_RM_STRING) != 0).format();
result.op_code_string = op_code_string;
let fmt_opt = unsafe {
mem::transmute(((opc_flags2 >> OpCodeInfoFlags2::INSTR_STR_FMT_OPTION_SHIFT) & OpCodeInfoFlags2::INSTR_STR_FMT_OPTION_MASK) as u8)
};
let instruction_string = InstructionFormatter::new(&result, fmt_opt, sb).format();
result.instruction_string = instruction_string;
}
result
}
#[must_use]
#[inline]
pub const fn code(&self) -> Code {
self.code
}
#[must_use]
#[inline]
pub fn mnemonic(&self) -> Mnemonic {
self.code.mnemonic()
}
#[must_use]
#[inline]
pub const fn encoding(&self) -> EncodingKind {
self.encoding
}
#[must_use]
#[inline]
pub fn is_instruction(&self) -> bool {
!(self.code <= Code::DeclareQword || self.code == Code::Zero_bytes)
}
#[must_use]
#[inline]
pub const fn mode16(&self) -> bool {
(self.enc_flags3 & EncFlags3::BIT16OR32) != 0
}
#[must_use]
#[inline]
pub const fn mode32(&self) -> bool {
(self.enc_flags3 & EncFlags3::BIT16OR32) != 0
}
#[must_use]
#[inline]
pub const fn mode64(&self) -> bool {
(self.enc_flags3 & EncFlags3::BIT64) != 0
}
#[must_use]
#[inline]
pub const fn fwait(&self) -> bool {
(self.enc_flags3 & EncFlags3::FWAIT) != 0
}
#[must_use]
#[inline]
pub const fn operand_size(&self) -> u32 {
self.operand_size as u32
}
#[must_use]
#[inline]
pub const fn address_size(&self) -> u32 {
self.address_size as u32
}
#[must_use]
#[inline]
pub const fn l(&self) -> u32 {
self.l as u32
}
#[must_use]
#[inline]
pub const fn w(&self) -> u32 {
((self.flags & Flags::W) != 0) as u32
}
#[must_use]
#[inline]
pub const fn is_lig(&self) -> bool {
(self.flags & Flags::LIG) != 0
}
#[must_use]
#[inline]
pub const fn is_wig(&self) -> bool {
(self.flags & Flags::WIG) != 0
}
#[must_use]
#[inline]
pub const fn is_wig32(&self) -> bool {
(self.flags & Flags::WIG32) != 0
}
#[must_use]
#[inline]
pub const fn tuple_type(&self) -> TupleType {
self.tuple_type
}
#[cfg(feature = "mvex")]
#[must_use]
#[inline]
pub fn mvex_eh_bit(&self) -> MvexEHBit {
if self.encoding() == EncodingKind::MVEX {
get_mvex_info(self.code()).eh_bit
} else {
MvexEHBit::None
}
}
#[cfg(feature = "mvex")]
#[must_use]
#[inline]
pub fn mvex_can_use_eviction_hint(&self) -> bool {
if self.encoding() == EncodingKind::MVEX {
get_mvex_info(self.code()).can_use_eviction_hint()
} else {
false
}
}
#[cfg(feature = "mvex")]
#[must_use]
#[inline]
pub fn mvex_can_use_imm_rounding_control(&self) -> bool {
if self.encoding() == EncodingKind::MVEX {
get_mvex_info(self.code()).can_use_imm_rounding_control()
} else {
false
}
}
#[cfg(feature = "mvex")]
#[must_use]
#[inline]
pub fn mvex_ignores_op_mask_register(&self) -> bool {
if self.encoding() == EncodingKind::MVEX {
get_mvex_info(self.code()).ignores_op_mask_register()
} else {
false
}
}
#[cfg(feature = "mvex")]
#[must_use]
#[inline]
pub fn mvex_no_sae_rc(&self) -> bool {
if self.encoding() == EncodingKind::MVEX {
get_mvex_info(self.code()).no_sae_rc()
} else {
false
}
}
#[cfg(feature = "mvex")]
#[must_use]
#[inline]
pub fn mvex_tuple_type_lut_kind(&self) -> MvexTupleTypeLutKind {
if self.encoding() == EncodingKind::MVEX {
get_mvex_info(self.code()).tuple_type_lut_kind
} else {
MvexTupleTypeLutKind::default()
}
}
#[cfg(feature = "mvex")]
#[must_use]
#[inline]
pub fn mvex_conversion_func(&self) -> MvexConvFn {
if self.encoding() == EncodingKind::MVEX {
get_mvex_info(self.code()).conv_fn
} else {
MvexConvFn::None
}
}
#[cfg(feature = "mvex")]
#[must_use]
#[inline]
pub fn mvex_valid_conversion_funcs_mask(&self) -> u8 {
if self.encoding() == EncodingKind::MVEX {
!get_mvex_info(self.code()).invalid_conv_fns
} else {
0
}
}
#[cfg(feature = "mvex")]
#[must_use]
#[inline]
pub fn mvex_valid_swizzle_funcs_mask(&self) -> u8 {
if self.encoding() == EncodingKind::MVEX {
!get_mvex_info(self.code()).invalid_swizzle_fns
} else {
0
}
}
#[must_use]
#[inline]
pub fn memory_size(&self) -> MemorySize {
instruction_memory_sizes::SIZES_NORMAL[self.code() as usize]
}
#[must_use]
#[inline]
pub fn broadcast_memory_size(&self) -> MemorySize {
instruction_memory_sizes::SIZES_BCST[self.code() as usize]
}
#[must_use]
#[inline]
pub const fn can_broadcast(&self) -> bool {
(self.enc_flags3 & EncFlags3::BROADCAST) != 0
}
#[must_use]
#[inline]
pub const fn can_use_rounding_control(&self) -> bool {
(self.enc_flags3 & EncFlags3::ROUNDING_CONTROL) != 0
}
#[must_use]
#[inline]
pub const fn can_suppress_all_exceptions(&self) -> bool {
(self.enc_flags3 & EncFlags3::SUPPRESS_ALL_EXCEPTIONS) != 0
}
#[must_use]
#[inline]
pub const fn can_use_op_mask_register(&self) -> bool {
(self.enc_flags3 & EncFlags3::OP_MASK_REGISTER) != 0
}
#[must_use]
#[inline]
pub const fn require_op_mask_register(&self) -> bool {
(self.enc_flags3 & EncFlags3::REQUIRE_OP_MASK_REGISTER) != 0
}
#[must_use]
#[inline]
pub const fn can_use_zeroing_masking(&self) -> bool {
(self.enc_flags3 & EncFlags3::ZEROING_MASKING) != 0
}
#[must_use]
#[inline]
pub const fn can_use_lock_prefix(&self) -> bool {
(self.enc_flags3 & EncFlags3::LOCK) != 0
}
#[must_use]
#[inline]
pub const fn can_use_xacquire_prefix(&self) -> bool {
(self.enc_flags3 & EncFlags3::XACQUIRE) != 0
}
#[must_use]
#[inline]
pub const fn can_use_xrelease_prefix(&self) -> bool {
(self.enc_flags3 & EncFlags3::XRELEASE) != 0
}
#[must_use]
#[inline]
pub const fn can_use_rep_prefix(&self) -> bool {
(self.enc_flags3 & EncFlags3::REP) != 0
}
#[must_use]
#[inline]
pub const fn can_use_repne_prefix(&self) -> bool {
(self.enc_flags3 & EncFlags3::REPNE) != 0
}
#[must_use]
#[inline]
pub const fn can_use_bnd_prefix(&self) -> bool {
(self.enc_flags3 & EncFlags3::BND) != 0
}
#[must_use]
#[inline]
pub const fn can_use_hint_taken_prefix(&self) -> bool {
(self.enc_flags3 & EncFlags3::HINT_TAKEN) != 0
}
#[must_use]
#[inline]
pub const fn can_use_notrack_prefix(&self) -> bool {
(self.enc_flags3 & EncFlags3::NOTRACK) != 0
}
#[must_use]
#[inline]
pub const fn ignores_rounding_control(&self) -> bool {
(self.flags & Flags::IGNORES_ROUNDING_CONTROL) != 0
}
#[must_use]
#[inline]
pub const fn amd_lock_reg_bit(&self) -> bool {
(self.flags & Flags::AMD_LOCK_REG_BIT) != 0
}
#[must_use]
#[inline]
pub const fn default_op_size64(&self) -> bool {
(self.enc_flags3 & EncFlags3::DEFAULT_OP_SIZE64) != 0
}
#[must_use]
#[inline]
pub const fn force_op_size64(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::FORCE_OP_SIZE64) != 0
}
#[must_use]
#[inline]
pub const fn intel_force_op_size64(&self) -> bool {
(self.enc_flags3 & EncFlags3::INTEL_FORCE_OP_SIZE64) != 0
}
#[must_use]
#[inline]
pub const fn must_be_cpl0(&self) -> bool {
(self.flags & (Flags::CPL0 | Flags::CPL1 | Flags::CPL2 | Flags::CPL3)) == Flags::CPL0
}
#[must_use]
#[inline]
pub const fn cpl0(&self) -> bool {
(self.flags & Flags::CPL0) != 0
}
#[must_use]
#[inline]
pub const fn cpl1(&self) -> bool {
(self.flags & Flags::CPL1) != 0
}
#[must_use]
#[inline]
pub const fn cpl2(&self) -> bool {
(self.flags & Flags::CPL2) != 0
}
#[must_use]
#[inline]
pub const fn cpl3(&self) -> bool {
(self.flags & Flags::CPL3) != 0
}
#[must_use]
#[inline]
pub const fn is_input_output(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::INPUT_OUTPUT) != 0
}
#[must_use]
#[inline]
pub const fn is_nop(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::NOP) != 0
}
#[must_use]
#[inline]
pub const fn is_reserved_nop(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::RESERVED_NOP) != 0
}
#[must_use]
#[inline]
pub const fn is_serializing_intel(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::SERIALIZING_INTEL) != 0
}
#[must_use]
#[inline]
pub const fn is_serializing_amd(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::SERIALIZING_AMD) != 0
}
#[must_use]
#[inline]
pub const fn may_require_cpl0(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::MAY_REQUIRE_CPL0) != 0
}
#[must_use]
#[inline]
pub const fn is_cet_tracked(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::CET_TRACKED) != 0
}
#[must_use]
#[inline]
pub const fn is_non_temporal(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::NON_TEMPORAL) != 0
}
#[must_use]
#[inline]
pub const fn is_fpu_no_wait(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::FPU_NO_WAIT) != 0
}
#[must_use]
#[inline]
pub const fn ignores_mod_bits(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::IGNORES_MOD_BITS) != 0
}
#[must_use]
#[inline]
pub const fn no66(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::NO66) != 0
}
#[must_use]
#[inline]
pub const fn nfx(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::NFX) != 0
}
#[must_use]
#[inline]
pub const fn requires_unique_reg_nums(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::REQUIRES_UNIQUE_REG_NUMS) != 0
}
#[must_use]
#[inline]
pub const fn requires_unique_dest_reg_num(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::REQUIRES_UNIQUE_DEST_REG_NUM) != 0
}
#[must_use]
#[inline]
pub const fn is_privileged(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::PRIVILEGED) != 0
}
#[must_use]
#[inline]
pub const fn is_save_restore(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::SAVE_RESTORE) != 0
}
#[must_use]
#[inline]
pub const fn is_stack_instruction(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::STACK_INSTRUCTION) != 0
}
#[must_use]
#[inline]
pub const fn ignores_segment(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::IGNORES_SEGMENT) != 0
}
#[must_use]
#[inline]
pub const fn is_op_mask_read_write(&self) -> bool {
(self.opc_flags1 & OpCodeInfoFlags1::OP_MASK_READ_WRITE) != 0
}
#[must_use]
#[inline]
pub const fn real_mode(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::REAL_MODE) != 0
}
#[must_use]
#[inline]
pub const fn protected_mode(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::PROTECTED_MODE) != 0
}
#[must_use]
#[inline]
pub const fn virtual8086_mode(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::VIRTUAL8086_MODE) != 0
}
#[must_use]
#[inline]
pub const fn compatibility_mode(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::COMPATIBILITY_MODE) != 0
}
#[must_use]
#[inline]
pub const fn long_mode(&self) -> bool {
(self.enc_flags3 & EncFlags3::BIT64) != 0
}
#[must_use]
#[inline]
pub const fn use_outside_smm(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::USE_OUTSIDE_SMM) != 0
}
#[must_use]
#[inline]
pub const fn use_in_smm(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::USE_IN_SMM) != 0
}
#[must_use]
#[inline]
pub const fn use_outside_enclave_sgx(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::USE_OUTSIDE_ENCLAVE_SGX) != 0
}
#[must_use]
#[inline]
pub const fn use_in_enclave_sgx1(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::USE_IN_ENCLAVE_SGX1) != 0
}
#[must_use]
#[inline]
pub const fn use_in_enclave_sgx2(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::USE_IN_ENCLAVE_SGX2) != 0
}
#[must_use]
#[inline]
pub const fn use_outside_vmx_op(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::USE_OUTSIDE_VMX_OP) != 0
}
#[must_use]
#[inline]
pub const fn use_in_vmx_root_op(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::USE_IN_VMX_ROOT_OP) != 0
}
#[must_use]
#[inline]
pub const fn use_in_vmx_non_root_op(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::USE_IN_VMX_NON_ROOT_OP) != 0
}
#[must_use]
#[inline]
pub const fn use_outside_seam(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::USE_OUTSIDE_SEAM) != 0
}
#[must_use]
#[inline]
pub const fn use_in_seam(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::USE_IN_SEAM) != 0
}
#[must_use]
#[inline]
pub const fn tdx_non_root_gen_ud(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::TDX_NON_ROOT_GEN_UD) != 0
}
#[must_use]
#[inline]
pub const fn tdx_non_root_gen_ve(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::TDX_NON_ROOT_GEN_VE) != 0
}
#[must_use]
#[inline]
pub const fn tdx_non_root_may_gen_ex(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::TDX_NON_ROOT_MAY_GEN_EX) != 0
}
#[must_use]
#[inline]
pub const fn intel_vm_exit(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::INTEL_VM_EXIT) != 0
}
#[must_use]
#[inline]
pub const fn intel_may_vm_exit(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::INTEL_MAY_VM_EXIT) != 0
}
#[must_use]
#[inline]
pub const fn intel_smm_vm_exit(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::INTEL_SMM_VM_EXIT) != 0
}
#[must_use]
#[inline]
pub const fn amd_vm_exit(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::AMD_VM_EXIT) != 0
}
#[must_use]
#[inline]
pub const fn amd_may_vm_exit(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::AMD_MAY_VM_EXIT) != 0
}
#[must_use]
#[inline]
pub const fn tsx_abort(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::TSX_ABORT) != 0
}
#[must_use]
#[inline]
pub const fn tsx_impl_abort(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::TSX_IMPL_ABORT) != 0
}
#[must_use]
#[inline]
pub const fn tsx_may_abort(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::TSX_MAY_ABORT) != 0
}
#[must_use]
#[inline]
pub const fn intel_decoder16(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::INTEL_DECODER16OR32) != 0
}
#[must_use]
#[inline]
pub const fn intel_decoder32(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::INTEL_DECODER16OR32) != 0
}
#[must_use]
#[inline]
pub const fn intel_decoder64(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::INTEL_DECODER64) != 0
}
#[must_use]
#[inline]
pub const fn amd_decoder16(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::AMD_DECODER16OR32) != 0
}
#[must_use]
#[inline]
pub const fn amd_decoder32(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::AMD_DECODER16OR32) != 0
}
#[must_use]
#[inline]
pub const fn amd_decoder64(&self) -> bool {
(self.opc_flags2 & OpCodeInfoFlags2::AMD_DECODER64) != 0
}
#[cfg(feature = "decoder")]
#[must_use]
#[inline]
pub fn decoder_option(&self) -> u32 {
let dec_opt_value: DecOptionValue = unsafe {
mem::transmute(((self.opc_flags1 >> OpCodeInfoFlags1::DEC_OPTION_VALUE_SHIFT) & OpCodeInfoFlags1::DEC_OPTION_VALUE_MASK) as u8)
};
TO_DECODER_OPTIONS[dec_opt_value as usize]
}
#[must_use]
#[inline]
pub const fn table(&self) -> OpCodeTableKind {
self.table
}
#[must_use]
#[inline]
pub const fn mandatory_prefix(&self) -> MandatoryPrefix {
self.mandatory_prefix
}
#[must_use]
#[inline]
pub const fn op_code(&self) -> u32 {
self.op_code as u32
}
#[must_use]
#[inline]
pub const fn op_code_len(&self) -> u32 {
if (self.enc_flags2 & EncFlags2::OP_CODE_IS2_BYTES) != 0 {
2
} else {
1
}
}
#[must_use]
#[inline]
pub const fn is_group(&self) -> bool {
self.group_index >= 0
}
#[must_use]
#[inline]
pub const fn group_index(&self) -> i32 {
self.group_index as i32
}
#[must_use]
#[inline]
pub const fn is_rm_group(&self) -> bool {
self.rm_group_index >= 0
}
#[must_use]
#[inline]
pub const fn rm_group_index(&self) -> i32 {
self.rm_group_index as i32
}
#[must_use]
#[inline]
pub fn op_count(&self) -> u32 {
instruction_op_counts::OP_COUNT[self.code() as usize] as u32
}
#[must_use]
#[inline]
pub const fn op0_kind(&self) -> OpCodeOperandKind {
self.op_kinds[0]
}
#[must_use]
#[inline]
pub const fn op1_kind(&self) -> OpCodeOperandKind {
self.op_kinds[1]
}
#[must_use]
#[inline]
pub const fn op2_kind(&self) -> OpCodeOperandKind {
self.op_kinds[2]
}
#[must_use]
#[inline]
pub const fn op3_kind(&self) -> OpCodeOperandKind {
self.op_kinds[3]
}
#[must_use]
#[inline]
pub const fn op4_kind(&self) -> OpCodeOperandKind {
self.op_kinds[4]
}
#[must_use]
#[inline]
pub fn op_kind(&self, operand: u32) -> OpCodeOperandKind {
match self.op_kinds.get(operand as usize) {
Some(&op_access) => op_access,
None => {
debug_assert!(false, "Invalid operand: {}", operand);
OpCodeOperandKind::default()
}
}
}
#[inline]
#[allow(clippy::missing_inline_in_public_items)]
#[doc(hidden)]
pub fn try_op_kind(&self, operand: u32) -> Result<OpCodeOperandKind, IcedError> {
match self.op_kinds.get(operand as usize) {
Some(&op_access) => Ok(op_access),
None => Err(IcedError::new("Invalid operand")),
}
}
#[must_use]
#[inline]
pub fn op_kinds(&self) -> &[OpCodeOperandKind] {
&self.op_kinds[0..self.op_count() as usize]
}
#[must_use]
#[allow(clippy::missing_inline_in_public_items)]
pub const fn is_available_in_mode(&self, bitness: u32) -> bool {
match bitness {
16 => self.mode16(),
32 => self.mode32(),
64 => self.mode64(),
_ => false,
}
}
#[must_use]
#[inline]
pub fn op_code_string(&self) -> &str {
self.op_code_string.as_str()
}
#[must_use]
#[inline]
pub fn instruction_string(&self) -> &str {
self.instruction_string.as_str()
}
}
impl fmt::Display for OpCodeInfo {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.instruction_string)
}
}