Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add op access for OpCodeInfo and Code #614

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ protected override void Generate((InstructionDef def, uint dword1, uint dword2)[
using (var writer = new FileWriter(TargetLanguage.Rust, FileUtils.OpenWrite(filename))) {
writer.WriteFileHeader();
writer.WriteLine(RustConstants.AttributeNoRustFmt);
writer.WriteLine($"pub(crate) static TABLE: [(u32, u32); {infos.Length}] = [");
writer.WriteLine($"pub(crate) const TABLE: [(u32, u32); {infos.Length}] = [");
using (writer.Indent()) {
foreach (var info in infos)
writer.WriteLine($"({NumberFormatter.FormatHexUInt32WithSep(info.dword1)}, {NumberFormatter.FormatHexUInt32WithSep(info.dword2)}),// {info.def.Code.Name(idConverter)}");
Expand Down Expand Up @@ -119,7 +119,7 @@ void GenerateOpAccesses(FileWriter writer) {
var opInfo = opInfos[index];
writer.WriteLine(RustConstants.AttributeNoRustFmt);
var name = idConverter.Constant($"OpAccess_{index}");
writer.WriteLine($"pub(super) static {name}: [{opAccessTypeStr}; {opInfo.Values.Length}] = [");
writer.WriteLine($"pub(super) const {name}: [{opAccessTypeStr}; {opInfo.Values.Length}] = [");
using (writer.Indent()) {
foreach (var value in opInfo.Values) {
var v = ToOpAccess(value);
Expand Down
69 changes: 69 additions & 0 deletions src/rust/iced-x86/src/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use crate::iced_constants::IcedConstants;
use crate::iced_error::IcedError;
#[cfg(feature = "instr_info")]
use crate::info::enums::*;
#[cfg(feature = "instr_info")]
use crate::info::info_flags::{code_info_flags, InfoFlags1 as InfoFlags1Type, InfoFlags2 as InfoFlags2Type, OpAccessOptions};
use crate::mnemonics;
use crate::*;
use core::iter::{ExactSizeIterator, FusedIterator, Iterator};
Expand Down Expand Up @@ -45142,3 +45144,70 @@ impl Code {
}
}
}

#[cfg(feature = "instr_info")]
impl Code {
pub(crate) const fn info_flags(&self) -> &(InfoFlags1Type, InfoFlags2Type) {
code_info_flags(*self)
}

pub(crate) const fn info_flags1(&self) -> &InfoFlags1Type {
&self.info_flags().0
}

pub(crate) const fn op0_info(&self) -> OpInfo0 {
self.info_flags1().op0_info()
}

/// Gets operand #0's OpAccess
#[must_use]
#[inline]
pub const fn op0_access(&self, options: OpAccessOptions) -> OpAccess {
self.info_flags1().op0_access(options)
}

/// Gets operand #1's OpAccess
#[must_use]
#[inline]
pub const fn op1_access(&self, _options: OpAccessOptions) -> OpAccess {
self.info_flags1().op1_access()
}

/// Gets operand #2's OpAccess
#[must_use]
#[inline]
pub const fn op2_access(&self, _options: OpAccessOptions) -> OpAccess {
self.info_flags1().op2_access()
}

/// Gets operand #3's OpAccess
#[must_use]
#[inline]
pub const fn op3_access(&self, _options: OpAccessOptions) -> OpAccess {
self.info_flags1().op3_access()
}

/// Gets operand #4's OpAccess
#[must_use]
#[inline]
pub const fn op4_access(&self, _options: OpAccessOptions) -> OpAccess {
self.info_flags1().op4_access()
}

/// Gets an operand's [`OpAccess`]
/// # Arguments
///
/// * `operand`: Operand number. If the operand does not exist the function will return `OpAccess::None`
#[must_use]
#[inline]
pub const fn op_access(&self, operand: u32, options: OpAccessOptions) -> OpAccess {
match operand {
0 => self.op0_access(options),
1 => self.op1_access(options),
2 => self.op2_access(options),
3 => self.op3_access(options),
4 => self.op4_access(options),
_ => OpAccess::None,
}
}
}
4 changes: 2 additions & 2 deletions src/rust/iced-x86/src/info/enums.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use core::fmt;
// GENERATOR-BEGIN: OpAccesses
// ⚠️This was generated by GENERATOR!🦹‍♂️
#[rustfmt::skip]
pub(super) static OP_ACCESS_1: [OpAccess; 7] = [
pub(super) const OP_ACCESS_1: [OpAccess; 7] = [
OpAccess::None,
OpAccess::CondRead,
OpAccess::NoMemAccess,
Expand All @@ -17,7 +17,7 @@ pub(super) static OP_ACCESS_1: [OpAccess; 7] = [
OpAccess::Write,
];
#[rustfmt::skip]
pub(super) static OP_ACCESS_2: [OpAccess; 3] = [
pub(super) const OP_ACCESS_2: [OpAccess; 3] = [
OpAccess::None,
OpAccess::Read,
OpAccess::ReadWrite,
Expand Down
60 changes: 29 additions & 31 deletions src/rust/iced-x86/src/info/factory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,23 @@ impl InstructionInfoFactory {
/// assert_eq!(regs[2].register(), Register::ESI);
/// assert_eq!(regs[2].access(), OpAccess::Read);
/// ```
///
/// Compared to [`Code::op_access`], the operand accesses are specified based on the operands. For example
/// `xor rax, rax` will have a single operand write and no operand reads, since it always sets
/// `rax` to zero.
/// ```
/// use iced_x86::*;
/// // xor rax, rax
/// let bytes = b"\x48\x31\xc0";
/// let mut decoder = Decoder::new(64, bytes, DecoderOptions::NONE);
/// let mut info_factory = InstructionInfoFactory::new();
///
/// let instr = decoder.decode();
/// let info = info_factory.info(&instr);
///
/// assert_eq!(info.op0_access(), OpAccess::Write);
/// assert_eq!(info.op1_access(), OpAccess::None);
/// ```
#[must_use]
#[inline]
pub fn info(&mut self, instruction: &Instruction) -> &InstructionInfo {
Expand Down Expand Up @@ -159,9 +176,7 @@ impl InstructionInfoFactory {
info.used_registers.clear();
info.used_memory_locations.clear();

let (flags1, flags2) = crate::info::info_table::TABLE[instruction.code() as usize];

// SAFETY: the transmutes on the generated data (flags1,flags2) are safe since we only generate valid enum variants
let (flags1, flags2) = *instruction.code().info_flags();

let code_size = instruction.code_size();
const _: () = assert!(InstructionInfoOptions::NO_MEMORY_USAGE == Flags::NO_MEMORY_USAGE);
Expand All @@ -170,12 +185,11 @@ impl InstructionInfoFactory {
if code_size == CodeSize::Code64 || code_size == CodeSize::Unknown {
flags |= Flags::IS_64BIT;
}
let encoding = (flags2 >> InfoFlags2::ENCODING_SHIFT) & InfoFlags2::ENCODING_MASK;
if encoding != EncodingKind::Legacy as u32 {
if flags2.encoding_kind() != EncodingKind::Legacy {
flags |= Flags::ZERO_EXT_VEC_REGS;
}

let op0_info = unsafe { mem::transmute(((flags1 >> InfoFlags1::OP_INFO0_SHIFT) & InfoFlags1::OP_INFO0_MASK) as u8) };
let op0_info = instruction.code().op0_info();
let op0_access = match op0_info {
OpInfo0::None => OpAccess::None,
OpInfo0::Read => OpAccess::Read,
Expand Down Expand Up @@ -255,23 +269,12 @@ impl InstructionInfoFactory {

debug_assert!(instruction.op_count() as usize <= IcedConstants::MAX_OP_COUNT);
info.op_accesses[0] = op0_access;
let op1_info: OpInfo1 = unsafe { mem::transmute(((flags1 >> InfoFlags1::OP_INFO1_SHIFT) & InfoFlags1::OP_INFO1_MASK) as u8) };
info.op_accesses[1] = OP_ACCESS_1[op1_info as usize];
let op2_info: OpInfo2 = unsafe { mem::transmute(((flags1 >> InfoFlags1::OP_INFO2_SHIFT) & InfoFlags1::OP_INFO2_MASK) as u8) };
info.op_accesses[2] = OP_ACCESS_2[op2_info as usize];
info.op_accesses[3] = if (flags1 & ((InfoFlags1::OP_INFO3_MASK) << InfoFlags1::OP_INFO3_SHIFT)) != 0 {
const _: () = assert!(InstrInfoConstants::OP_INFO3_COUNT == 2);
OpAccess::Read
} else {
OpAccess::None
};
info.op_accesses[4] = if (flags1 & ((InfoFlags1::OP_INFO4_MASK) << InfoFlags1::OP_INFO4_SHIFT)) != 0 {
const _: () = assert!(InstrInfoConstants::OP_INFO4_COUNT == 2);
OpAccess::Read
} else {
OpAccess::None
};
info.op_accesses[1] = flags1.op1_access();
info.op_accesses[2] = flags1.op2_access();
info.op_accesses[3] = flags1.op3_access();
info.op_accesses[4] = flags1.op4_access();
const _: () = assert!(IcedConstants::MAX_OP_COUNT == 5);
let op1_info = flags1.op1_info();

for i in 0..(instruction.op_count() as usize) {
// SAFETY: valid index since i < instruction.op_count() (<= MAX_OP_COUNT) and op_accesses.len() (== MAX_OP_COUNT)
Expand Down Expand Up @@ -321,7 +324,7 @@ impl InstructionInfoFactory {
const _: () = assert!(InfoFlags1::IGNORES_SEGMENT == 1 << 31);
const _: () = assert!(Register::None as u32 == 0);
let segment_register =
unsafe { mem::transmute((instruction.memory_segment() as u32 & !((flags1 as i32 >> 31) as u32)) as RegisterUnderlyingType) };
unsafe { mem::transmute((instruction.memory_segment() as u32 & !flags1.sign_mask()) as RegisterUnderlyingType) };
let base_register = instruction.memory_base();
if base_register == Register::RIP {
if (flags & Flags::NO_MEMORY_USAGE) == 0 {
Expand Down Expand Up @@ -360,7 +363,7 @@ impl InstructionInfoFactory {
Self::add_memory_segment_register(flags, info, segment_register, OpAccess::Read);
}
} else {
let (index_register, scale) = if (flags1 & InfoFlags1::IGNORES_INDEX_VA) != 0 {
let (index_register, scale) = if flags1.ignores_index_va() {
let index = instruction.memory_index();
if (flags & Flags::NO_REGISTER_USAGE) == 0 && index != Register::None {
Self::add_register(flags, info, index, OpAccess::Read);
Expand Down Expand Up @@ -427,18 +430,13 @@ impl InstructionInfoFactory {
}
}

let implied_access = unsafe { mem::transmute(((flags1 >> InfoFlags1::IMPLIED_ACCESS_SHIFT) & InfoFlags1::IMPLIED_ACCESS_MASK) as u8) };
let implied_access = flags1.implied_access();
if implied_access != ImpliedAccess::None {
Self::add_implied_accesses(implied_access, instruction, info, flags);
}

if instruction.has_op_mask() && (flags & Flags::NO_REGISTER_USAGE) == 0 {
Self::add_register(
flags,
info,
instruction.op_mask(),
if (flags1 & InfoFlags1::OP_MASK_READ_WRITE) != 0 { OpAccess::ReadWrite } else { OpAccess::Read },
);
Self::add_register(flags, info, instruction.op_mask(), if flags1.op_mask_read_write() { OpAccess::ReadWrite } else { OpAccess::Read });
}
info
}
Expand Down
Loading
Loading