pub(crate) mod cpuid_table;
pub(crate) mod enums;
pub(crate) mod factory;
pub(crate) mod info_table;
pub(crate) mod rflags_table;
#[cfg(test)]
mod tests;
pub use self::factory::*;
use super::iced_constants::IcedConstants;
use super::*;
#[cfg(not(feature = "std"))]
use alloc::vec::Vec;
use core::fmt;
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
pub struct UsedRegister {
register: Register,
access: OpAccess,
}
#[cfg_attr(feature = "cargo-clippy", allow(clippy::trivially_copy_pass_by_ref))]
impl UsedRegister {
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn new(register: Register, access: OpAccess) -> Self {
Self { register, access }
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn register(&self) -> Register {
self.register
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn access(&self) -> OpAccess {
self.access
}
}
impl fmt::Debug for UsedRegister {
#[cfg_attr(feature = "cargo-clippy", allow(clippy::missing_inline_in_public_items))]
fn fmt<'a>(&self, f: &mut fmt::Formatter<'a>) -> fmt::Result {
write!(f, "{:?}:{:?}", self.register(), self.access())?;
Ok(())
}
}
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash)]
pub struct UsedMemory {
displacement: u64,
segment: Register,
base: Register,
index: Register,
scale: u8,
memory_size: MemorySize,
access: OpAccess,
_pad: u16,
}
impl UsedMemory {
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn new(segment: Register, base: Register, index: Register, scale: u32, displacement: u64, memory_size: MemorySize, access: OpAccess) -> Self {
Self { segment, base, index, scale: scale as u8, displacement, memory_size, access, _pad: 0 }
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn segment(&self) -> Register {
self.segment
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn base(&self) -> Register {
self.base
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn index(&self) -> Register {
self.index
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn scale(&self) -> u32 {
self.scale as u32
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn displacement(&self) -> u64 {
self.displacement
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn memory_size(&self) -> MemorySize {
self.memory_size
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn access(&self) -> OpAccess {
self.access
}
}
impl fmt::Debug for UsedMemory {
#[cfg_attr(feature = "cargo-clippy", allow(clippy::missing_inline_in_public_items))]
fn fmt<'a>(&self, f: &mut fmt::Formatter<'a>) -> fmt::Result {
write!(f, "[{:?}:", self.segment())?;
let mut need_plus = if self.base() != Register::None {
write!(f, "{:?}", self.base())?;
true
} else {
false
};
if self.index() != Register::None {
if need_plus {
write!(f, "+")?;
}
need_plus = true;
write!(f, "{:?}", self.index())?;
if self.scale() != 1 {
write!(f, "*{}", self.scale())?;
}
}
if self.displacement() != 0 || !need_plus {
if need_plus {
write!(f, "+")?;
}
if self.displacement() <= 9 {
write!(f, "{}", self.displacement())?;
} else {
write!(f, "0x{:X}", self.displacement())?;
}
}
write!(f, ";{:?};{:?}]", self.memory_size(), self.access())?;
Ok(())
}
}
struct IIFlags;
impl IIFlags {
const SAVE_RESTORE: u8 = 0x20;
const STACK_INSTRUCTION: u8 = 0x40;
const PRIVILEGED: u8 = 0x80;
}
#[derive(Debug, Clone)]
pub struct InstructionInfo {
used_registers: Vec<UsedRegister>,
used_memory_locations: Vec<UsedMemory>,
cpuid_feature_internal: usize,
rflags_info: usize,
flow_control: FlowControl,
op_accesses: [OpAccess; IcedConstants::MAX_OP_COUNT],
encoding: EncodingKind,
flags: u8,
}
impl InstructionInfo {
#[cfg_attr(has_must_use, must_use)]
#[inline(always)]
fn new(options: u32) -> Self {
use self::enums::InstrInfoConstants;
Self {
used_registers: if (options & InstructionInfoOptions::NO_REGISTER_USAGE) == 0 {
Vec::with_capacity(InstrInfoConstants::DEFAULT_USED_REGISTER_COLL_CAPACITY)
} else {
Vec::new()
},
used_memory_locations: if (options & InstructionInfoOptions::NO_MEMORY_USAGE) == 0 {
Vec::with_capacity(InstrInfoConstants::DEFAULT_USED_MEMORY_COLL_CAPACITY)
} else {
Vec::new()
},
cpuid_feature_internal: 0,
rflags_info: 0,
flow_control: FlowControl::default(),
op_accesses: [OpAccess::default(); IcedConstants::MAX_OP_COUNT],
encoding: EncodingKind::default(),
flags: 0,
}
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn used_registers(&self) -> &[UsedRegister] {
self.used_registers.as_slice()
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn used_memory(&self) -> &[UsedMemory] {
self.used_memory_locations.as_slice()
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn is_privileged(&self) -> bool {
(self.flags & IIFlags::PRIVILEGED) != 0
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn is_stack_instruction(&self) -> bool {
(self.flags & IIFlags::STACK_INSTRUCTION) != 0
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn is_save_restore_instruction(&self) -> bool {
(self.flags & IIFlags::SAVE_RESTORE) != 0
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn encoding(&self) -> EncodingKind {
self.encoding
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn cpuid_features(&self) -> &'static [CpuidFeature] {
unsafe { *self::cpuid_table::CPUID.get_unchecked(self.cpuid_feature_internal) }
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn flow_control(&self) -> FlowControl {
self.flow_control
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn op0_access(&self) -> OpAccess {
self.op_accesses[0]
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn op1_access(&self) -> OpAccess {
self.op_accesses[1]
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn op2_access(&self) -> OpAccess {
self.op_accesses[2]
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn op3_access(&self) -> OpAccess {
self.op_accesses[3]
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn op4_access(&self) -> OpAccess {
self.op_accesses[4]
}
#[cfg_attr(has_must_use, must_use)]
#[cfg_attr(feature = "cargo-clippy", allow(clippy::missing_inline_in_public_items))]
pub fn op_access(&self, operand: u32) -> OpAccess {
self.op_accesses[operand as usize]
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn rflags_read(&self) -> u32 {
unsafe { *super::info::rflags_table::FLAGS_READ.get_unchecked(self.rflags_info) as u32 }
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn rflags_written(&self) -> u32 {
unsafe { *super::info::rflags_table::FLAGS_WRITTEN.get_unchecked(self.rflags_info) as u32 }
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn rflags_cleared(&self) -> u32 {
unsafe { *super::info::rflags_table::FLAGS_CLEARED.get_unchecked(self.rflags_info) as u32 }
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn rflags_set(&self) -> u32 {
unsafe { *super::info::rflags_table::FLAGS_SET.get_unchecked(self.rflags_info) as u32 }
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn rflags_undefined(&self) -> u32 {
unsafe { *super::info::rflags_table::FLAGS_UNDEFINED.get_unchecked(self.rflags_info) as u32 }
}
#[cfg_attr(has_must_use, must_use)]
#[inline]
pub fn rflags_modified(&self) -> u32 {
unsafe { *super::info::rflags_table::FLAGS_MODIFIED.get_unchecked(self.rflags_info) as u32 }
}
}