aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2024-06-23 12:30:16 -0700
committeriximeow <me@iximeow.net>2024-06-23 12:30:16 -0700
commit22a7e97f2119d1a3facf6b1f2d95f0ed1ee10bee (patch)
treeba42fc78ba624cfb20ae5b83edde42f32db9296f /src
parentf951ccb3b97c88265b5a1978dacf462c1d6db697 (diff)
adapt OperandVisitor to protected mode too
Diffstat (limited to 'src')
-rw-r--r--src/protected_mode/display.rs646
-rw-r--r--src/protected_mode/mod.rs85
2 files changed, 538 insertions, 193 deletions
diff --git a/src/protected_mode/display.rs b/src/protected_mode/display.rs
index 9cc949d..635893c 100644
--- a/src/protected_mode/display.rs
+++ b/src/protected_mode/display.rs
@@ -7,6 +7,104 @@ use yaxpeax_arch::display::*;
use crate::MEM_SIZE_STRINGS;
use crate::protected_mode::{RegSpec, Opcode, Operand, MergeMode, InstDecoder, Instruction, Segment, PrefixVex, OperandSpec};
+use yaxpeax_arch::display::DisplaySink;
+
+trait DisplaySinkExt {
+ // `write_opcode` depends on all mnemonics being less than 32 bytes long. check that here, at
+ // compile time. referenced later to force evaluation of this const.
+ const MNEMONIC_LT_32: () = {
+ let mut i = 0;
+ while i < MNEMONICS.len() {
+ let name = &MNEMONICS[i];
+ if name.len() >= 32 {
+ panic!("mnemonic too long");
+ }
+ i += 1;
+ }
+ };
+
+ // `write_reg` depends on all register names being less than 8 bytes long. check that here, at
+ // compile time. referenced later to force evaluation of this const.
+ const REG_LABEL_LT_8: () = {
+ let mut i = 0;
+ while i < REG_NAMES.len() {
+ let name = &REG_NAMES[i];
+ if name.len() >= 8 {
+ panic!("register name too long");
+ }
+ i += 1;
+ }
+ };
+
+ // `write_mem_size_label` depends on all memory size labels being less than 8 bytes long. check
+ // that here, at compile time. referenced later to force evaluation of this const.
+ const MEM_SIZE_LABEL_LT_8: () = {
+ let mut i = 0;
+ while i < crate::MEM_SIZE_STRINGS.len() {
+ let name = &MEM_SIZE_STRINGS[i];
+ if name.len() >= 8 {
+ panic!("memory label name too long");
+ }
+ i += 1;
+ }
+ };
+
+ // `write_sae_mode` depends on all sae mode labels being less than 16 bytes long. check that
+ // here, at compile time. referenced later to force evaluation of this const.
+ const SAE_LABEL_LT_16: () = {
+ let mut i = 0;
+ while i < super::SAE_MODES.len() {
+ let mode = &super::SAE_MODES[i];
+ if mode.label().len() >= 16 {
+ panic!("sae mode label too long");
+ }
+ i += 1;
+ }
+ };
+
+ fn write_opcode(&mut self, opcode: super::Opcode) -> Result<(), core::fmt::Error>;
+ fn write_reg(&mut self, reg: RegSpec) -> Result<(), core::fmt::Error>;
+ fn write_mem_size_label(&mut self, mem_size: u8) -> Result<(), core::fmt::Error>;
+ fn write_sae_mode(&mut self, sae: super::SaeMode) -> Result<(), core::fmt::Error>;
+}
+
+impl<T: DisplaySink> DisplaySinkExt for T {
+ #[inline(always)]
+ fn write_opcode(&mut self, opcode: super::Opcode) -> Result<(), core::fmt::Error> {
+ let name = opcode.name();
+
+ let _ = Self::MNEMONIC_LT_32;
+ // Safety: all opcode mnemonics are 31 bytes or fewer.
+ unsafe { self.write_lt_32(name) }
+ }
+
+ #[inline(always)]
+ fn write_reg(&mut self, reg: RegSpec) -> Result<(), core::fmt::Error> {
+ let label = regspec_label(&reg);
+
+ let _ = Self::REG_LABEL_LT_8;
+ // Safety: all register labels are 7 bytes or fewer.
+ unsafe { self.write_lt_8(label) }
+ }
+
+ #[inline(always)]
+ fn write_mem_size_label(&mut self, mem_size: u8) -> Result<(), core::fmt::Error> {
+ let label = mem_size_label(mem_size);
+ let _ = Self::MEM_SIZE_LABEL_LT_8;
+ // Safety: all memory size labels are 7 bytes or fewer
+ unsafe { self.write_lt_8(label) }
+ }
+
+ #[inline(always)]
+ fn write_sae_mode(&mut self, sae_mode: super::SaeMode) -> Result<(), core::fmt::Error> {
+ let label = sae_mode.label();
+
+ let _ = Self::SAE_LABEL_LT_16;
+ // Safety: all sae labels are 15 bytes or fewer.
+ unsafe { self.write_lt_16(label) }
+ }
+}
+
impl fmt::Display for InstDecoder {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
if self == &InstDecoder::default() {
@@ -129,6 +227,10 @@ pub(crate) fn regspec_label(spec: &RegSpec) -> &'static str {
unsafe { REG_NAMES.get_kinda_unchecked((spec.num as u16 + ((spec.bank as u16) << 3)) as usize) }
}
+pub(crate) fn mem_size_label(size: u8) -> &'static str {
+ unsafe { MEM_SIZE_STRINGS.get_kinda_unchecked(size as usize) }
+}
+
impl fmt::Display for RegSpec {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.write_str(regspec_label(self))
@@ -143,201 +245,363 @@ impl fmt::Display for Operand {
impl <T: fmt::Write, Y: YaxColors> Colorize<T, Y> for Operand {
fn colorize(&self, colors: &Y, f: &mut T) -> fmt::Result {
- match self {
- &Operand::ImmediateU8(imm) => {
- write!(f, "{}", colors.number(u8_hex(imm)))
- }
- &Operand::ImmediateI8(imm) => {
- write!(f, "{}",
- colors.number(signed_i8_hex(imm)))
- },
- &Operand::ImmediateU16(imm) => {
- write!(f, "{}", colors.number(u16_hex(imm)))
- }
- &Operand::ImmediateI16(imm) => {
- write!(f, "{}",
- colors.number(signed_i16_hex(imm)))
- },
- &Operand::ImmediateU32(imm) => {
- write!(f, "{}", colors.number(u32_hex(imm)))
- }
- &Operand::ImmediateI32(imm) => {
- write!(f, "{}",
- colors.number(signed_i32_hex(imm)))
- },
- &Operand::AbsoluteFarAddress { segment, address } => {
- write!(f, "{}:{}",
- colors.number(u16_hex(segment as u16)),
- colors.number(u32_hex(address as u32)),
- )
- },
- &Operand::Register(ref spec) => {
- f.write_str(regspec_label(spec))
- }
- &Operand::RegisterMaskMerge(ref spec, ref mask, merge_mode) => {
- f.write_str(regspec_label(spec))?;
- if mask.num != 0 {
- f.write_str("{")?;
- f.write_str(regspec_label(mask))?;
- f.write_str("}")?;
- }
- if let MergeMode::Zero = merge_mode {
- f.write_str("{z}")?;
- }
- Ok(())
- }
- &Operand::RegisterMaskMergeSae(ref spec, ref mask, merge_mode, sae_mode) => {
- f.write_str(regspec_label(spec))?;
- if mask.num != 0 {
- f.write_str("{")?;
- f.write_str(regspec_label(mask))?;
- f.write_str("}")?;
- }
- if let MergeMode::Zero = merge_mode {
- f.write_str("{z}")?;
- }
- f.write_str(sae_mode.label())?;
- Ok(())
- }
- &Operand::RegisterMaskMergeSaeNoround(ref spec, ref mask, merge_mode) => {
- f.write_str(regspec_label(spec))?;
- if mask.num != 0 {
- f.write_str("{")?;
- f.write_str(regspec_label(mask))?;
- f.write_str("}")?;
- }
- if let MergeMode::Zero = merge_mode {
- f.write_str("{z}")?;
- }
- f.write_str("{sae}")?;
- Ok(())
- }
- &Operand::DisplacementU16(imm) => {
- write!(f, "[{}]", colors.address(u16_hex(imm)))
- }
- &Operand::DisplacementU32(imm) => {
- write!(f, "[{}]", colors.address(u32_hex(imm)))
- }
- &Operand::RegDisp(ref spec, disp) => {
- write!(f, "[{} ", regspec_label(spec))?;
- format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?;
- write!(f, "]")
- },
- &Operand::RegDeref(ref spec) => {
- f.write_str("[")?;
- f.write_str(regspec_label(spec))?;
- f.write_str("]")
- },
- &Operand::RegScale(ref spec, scale) => {
- write!(f, "[{} * {}]",
- regspec_label(spec),
- colors.number(scale)
- )
- },
- &Operand::RegScaleDisp(ref spec, scale, disp) => {
- write!(f, "[{} * {} ",
- regspec_label(spec),
- colors.number(scale),
- )?;
- format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?;
- write!(f, "]")
- },
- &Operand::RegIndexBase(ref base, ref index) => {
- f.write_str("[")?;
- f.write_str(regspec_label(base))?;
- f.write_str(" + ")?;
- f.write_str(regspec_label(index))?;
- f.write_str("]")
- }
- &Operand::RegIndexBaseDisp(ref base, ref index, disp) => {
- write!(f, "[{} + {} ",
- regspec_label(base),
- regspec_label(index),
- )?;
- format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?;
- write!(f, "]")
- },
- &Operand::RegIndexBaseScale(ref base, ref index, scale) => {
- write!(f, "[{} + {} * {}]",
- regspec_label(base),
- regspec_label(index),
- colors.number(scale)
- )
+ let mut f = yaxpeax_arch::display::FmtSink::new(f);
+ let mut visitor = DisplayingOperandVisitor {
+ f: &mut f
+ };
+ self.visit(&mut visitor)
+ }
+}
+
+struct DisplayingOperandVisitor<'a, T> {
+ f: &'a mut T,
+}
+
+impl <T: DisplaySink> crate::protected_mode::OperandVisitor for DisplayingOperandVisitor<'_, T> {
+ type Ok = ();
+ type Error = core::fmt::Error;
+
+ #[cfg_attr(feature="profiling", inline(never))]
+ fn visit_u8(&mut self, imm: u8) -> Result<Self::Ok, Self::Error> {
+ self.f.span_start_immediate();
+ self.f.write_fixed_size("0x")?;
+ self.f.write_u8(imm)?;
+ self.f.span_end_immediate();
+ Ok(())
+ }
+ #[cfg_attr(feature="profiling", inline(never))]
+ fn visit_i8(&mut self, imm: i8) -> Result<Self::Ok, Self::Error> {
+ self.f.span_start_immediate();
+ let mut v = imm as u8;
+ if imm < 0 {
+ self.f.write_char('-')?;
+ v = -imm as u8;
+ }
+ self.f.write_fixed_size("0x")?;
+ self.f.write_u8(v)?;
+ self.f.span_end_immediate();
+ Ok(())
+ }
+ #[cfg_attr(feature="profiling", inline(never))]
+ fn visit_u16(&mut self, imm: u16) -> Result<Self::Ok, Self::Error> {
+ self.f.span_start_immediate();
+ self.f.write_fixed_size("0x")?;
+ self.f.write_u16(imm)?;
+ self.f.span_end_immediate();
+ Ok(())
+ }
+ #[cfg_attr(feature="profiling", inline(never))]
+ fn visit_i16(&mut self, imm: i16) -> Result<Self::Ok, Self::Error> {
+ self.f.span_start_immediate();
+ let mut v = imm as u16;
+ if imm < 0 {
+ self.f.write_char('-')?;
+ v = -imm as u16;
+ }
+ self.f.write_fixed_size("0x")?;
+ self.f.write_u16(v)?;
+ self.f.span_end_immediate();
+ Ok(())
+ }
+ #[cfg_attr(feature="profiling", inline(never))]
+ fn visit_u32(&mut self, imm: u32) -> Result<Self::Ok, Self::Error> {
+ self.f.span_start_immediate();
+ self.f.write_fixed_size("0x")?;
+ self.f.write_u32(imm)?;
+ self.f.span_end_immediate();
+ Ok(())
+ }
+ fn visit_i32(&mut self, imm: i32) -> Result<Self::Ok, Self::Error> {
+ self.f.span_start_immediate();
+ let mut v = imm as u32;
+ if imm < 0 {
+ self.f.write_char('-')?;
+ v = -imm as u32;
+ }
+ self.f.write_fixed_size("0x")?;
+ self.f.write_u32(v)?;
+ self.f.span_end_immediate();
+ Ok(())
+ }
+ #[cfg_attr(feature="profiling", inline(never))]
+ fn visit_reg(&mut self, reg: RegSpec) -> Result<Self::Ok, Self::Error> {
+ self.f.span_start_register();
+ self.f.write_reg(reg)?;
+ self.f.span_end_register();
+ Ok(())
+ }
+ fn visit_reg_mask_merge(&mut self, spec: RegSpec, mask: RegSpec, merge_mode: MergeMode) -> Result<Self::Ok, Self::Error> {
+ self.f.span_start_register();
+ self.f.write_reg(spec)?;
+ self.f.span_end_register();
+ if mask.num != 0 {
+ self.f.write_fixed_size("{")?;
+ self.f.span_start_register();
+ self.f.write_reg(mask)?;
+ self.f.span_end_register();
+ self.f.write_fixed_size("}")?;
+ }
+ if let MergeMode::Zero = merge_mode {
+ self.f.write_fixed_size("{z}")?;
+ }
+ Ok(())
+ }
+ fn visit_reg_mask_merge_sae(&mut self, spec: RegSpec, mask: RegSpec, merge_mode: MergeMode, sae_mode: super::SaeMode) -> Result<Self::Ok, Self::Error> {
+ self.f.write_reg(spec)?;
+ if mask.num != 0 {
+ self.f.write_fixed_size("{")?;
+ self.f.write_reg(mask)?;
+ self.f.write_fixed_size("}")?;
+ }
+ if let MergeMode::Zero = merge_mode {
+ self.f.write_fixed_size("{z}")?;
+ }
+ self.f.write_sae_mode(sae_mode)?;
+ Ok(())
+ }
+ fn visit_reg_mask_merge_sae_noround(&mut self, spec: RegSpec, mask: RegSpec, merge_mode: MergeMode) -> Result<Self::Ok, Self::Error> {
+ self.f.write_reg(spec)?;
+ if mask.num != 0 {
+ self.f.write_fixed_size("{")?;
+ self.f.write_reg(mask)?;
+ self.f.write_fixed_size("}")?;
+ }
+ if let MergeMode::Zero = merge_mode {
+ self.f.write_fixed_size("{z}")?;
+ }
+ self.f.write_fixed_size("{sae}")?;
+ Ok(())
+ }
+ fn visit_abs_u16(&mut self, imm: u16) -> Result<Self::Ok, Self::Error> {
+ self.f.write_fixed_size("[")?;
+ self.f.write_fixed_size("0x")?;
+ self.f.write_u16(imm)?;
+ self.f.write_fixed_size("]")?;
+ Ok(())
+ }
+ fn visit_abs_u32(&mut self, imm: u32) -> Result<Self::Ok, Self::Error> {
+ self.f.write_fixed_size("[")?;
+ self.f.write_fixed_size("0x")?;
+ self.f.write_u32(imm)?;
+ self.f.write_fixed_size("]")?;
+ Ok(())
+ }
+ #[cfg_attr(not(feature="profiling"), inline(always))]
+ #[cfg_attr(feature="profiling", inline(never))]
+ fn visit_disp(&mut self, reg: RegSpec, disp: i32) -> Result<Self::Ok, Self::Error> {
+ self.f.write_char('[')?;
+ self.f.write_reg(reg)?;
+ self.f.write_fixed_size(" ")?;
+
+ {
+ let mut v = disp as u32;
+ if disp < 0 {
+ self.f.write_fixed_size("- 0x")?;
+ v = -disp as u32;
+ } else {
+ self.f.write_fixed_size("+ 0x")?;
}
- &Operand::RegIndexBaseScaleDisp(ref base, ref index, scale, disp) => {
- write!(f, "[{} + {} * {} ",
- regspec_label(base),
- regspec_label(index),
- colors.number(scale),
- )?;
- format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?;
- write!(f, "]")
- },
- &Operand::RegDispMasked(ref spec, disp, ref mask_reg) => {
- write!(f, "[{} ", regspec_label(spec))?;
- format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?;
- write!(f, "]")?;
- write!(f, "{{{}}}", regspec_label(mask_reg))
- },
- &Operand::RegDerefMasked(ref spec, ref mask_reg) => {
- f.write_str("[")?;
- f.write_str(regspec_label(spec))?;
- f.write_str("]")?;
- write!(f, "{{{}}}", regspec_label(mask_reg))
- },
- &Operand::RegScaleMasked(ref spec, scale, ref mask_reg) => {
- write!(f, "[{} * {}]",
- regspec_label(spec),
- colors.number(scale)
- )?;
- write!(f, "{{{}}}", regspec_label(mask_reg))
- },
- &Operand::RegScaleDispMasked(ref spec, scale, disp, ref mask_reg) => {
- write!(f, "[{} * {} ",
- regspec_label(spec),
- colors.number(scale),
- )?;
- format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?;
- write!(f, "]")?;
- write!(f, "{{{}}}", regspec_label(mask_reg))
- },
- &Operand::RegIndexBaseMasked(ref base, ref index, ref mask_reg) => {
- f.write_str("[")?;
- f.write_str(regspec_label(base))?;
- f.write_str(" + ")?;
- f.write_str(regspec_label(index))?;
- f.write_str("]")?;
- write!(f, "{{{}}}", regspec_label(mask_reg))
+ self.f.write_u32(v)?;
+ }
+ self.f.write_fixed_size("]")
+ }
+ fn visit_deref(&mut self, reg: RegSpec) -> Result<Self::Ok, Self::Error> {
+ self.f.write_fixed_size("[")?;
+ self.f.write_reg(reg)?;
+ self.f.write_fixed_size("]")
+ }
+ fn visit_reg_scale(&mut self, reg: RegSpec, scale: u8) -> Result<Self::Ok, Self::Error> {
+ self.f.write_fixed_size("[")?;
+ self.f.write_reg(reg)?;
+ self.f.write_fixed_size(" * ")?;
+ self.f.write_char((0x30 + scale) as char)?; // translate scale=1 to '1', scale=2 to '2', etc
+ self.f.write_fixed_size("]")?;
+
+ Ok(())
+ }
+ fn visit_reg_scale_disp(&mut self, reg: RegSpec, scale: u8, disp: i32) -> Result<Self::Ok, Self::Error> {
+ self.f.write_fixed_size("[")?;
+ self.f.write_reg(reg)?;
+ self.f.write_fixed_size(" * ")?;
+ self.f.write_char((0x30 + scale) as char)?; // translate scale=1 to '1', scale=2 to '2', etc
+ self.f.write_fixed_size(" ")?;
+
+ {
+ let mut v = disp as u32;
+ if disp < 0 {
+ self.f.write_fixed_size("- 0x")?;
+ v = -disp as u32;
+ } else {
+ self.f.write_fixed_size("+ 0x")?;
}
- &Operand::RegIndexBaseDispMasked(ref base, ref index, disp, ref mask_reg) => {
- write!(f, "[{} + {} ",
- regspec_label(base),
- regspec_label(index),
- )?;
- format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?;
- write!(f, "]")?;
- write!(f, "{{{}}}", regspec_label(mask_reg))
- },
- &Operand::RegIndexBaseScaleMasked(ref base, ref index, scale, ref mask_reg) => {
- write!(f, "[{} + {} * {}]",
- regspec_label(base),
- regspec_label(index),
- colors.number(scale)
- )?;
- write!(f, "{{{}}}", regspec_label(mask_reg))
+ self.f.write_u32(v)?;
+ }
+ self.f.write_char(']')
+ }
+ fn visit_index_base_scale(&mut self, base: RegSpec, index: RegSpec, scale: u8) -> Result<Self::Ok, Self::Error> {
+ self.f.write_fixed_size("[")?;
+ self.f.write_reg(base)?;
+ self.f.write_fixed_size(" + ")?;
+ self.f.write_reg(index)?;
+ self.f.write_fixed_size(" * ")?;
+ self.f.write_char((0x30 + scale) as char)?; // translate scale=1 to '1', scale=2 to '2', etc
+ self.f.write_fixed_size("]")
+ }
+ fn visit_index_base_scale_disp(&mut self, base: RegSpec, index: RegSpec, scale: u8, disp: i32) -> Result<Self::Ok, Self::Error> {
+ self.f.write_fixed_size("[")?;
+ self.f.write_reg(base)?;
+ self.f.write_fixed_size(" + ")?;
+ self.f.write_reg(index)?;
+ self.f.write_fixed_size(" * ")?;
+ self.f.write_char((0x30 + scale) as char)?; // translate scale=1 to '1', scale=2 to '2', etc
+ self.f.write_fixed_size(" ")?;
+
+ {
+ let mut v = disp as u32;
+ if disp < 0 {
+ self.f.write_fixed_size("- 0x")?;
+ v = -disp as u32;
+ } else {
+ self.f.write_fixed_size("+ 0x")?;
}
- &Operand::RegIndexBaseScaleDispMasked(ref base, ref index, scale, disp, ref mask_reg) => {
- write!(f, "[{} + {} * {} ",
- regspec_label(base),
- regspec_label(index),
- colors.number(scale),
- )?;
- format_number_i32(colors, f, disp, NumberStyleHint::HexSignedWithSignSplit)?;
- write!(f, "]")?;
- write!(f, "{{{}}}", regspec_label(mask_reg))
- },
- &Operand::Nothing => { Ok(()) },
+ self.f.write_u32(v)?;
+ }
+ self.f.write_fixed_size("]")
+ }
+ fn visit_reg_disp_masked(&mut self, spec: RegSpec, disp: i32, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> {
+ self.f.write_char('[')?;
+ self.f.write_reg(spec)?;
+ self.f.write_char(' ')?;
+ let mut v = disp as u32;
+ if disp < 0 {
+ self.f.write_fixed_size("- 0x")?;
+ v = -disp as u32;
+ } else {
+ self.f.write_fixed_size("+ 0x")?;
+ }
+ self.f.write_u32(v)?;
+ self.f.write_char(']')?;
+ self.f.write_char('{')?;
+ self.f.write_reg(mask_reg)?;
+ self.f.write_char('}')?;
+ Ok(())
+ }
+ fn visit_reg_deref_masked(&mut self, spec: RegSpec, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> {
+ self.f.write_fixed_size("[")?;
+ self.f.write_reg(spec)?;
+ self.f.write_fixed_size("]")?;
+ self.f.write_char('{')?;
+ self.f.write_reg(mask_reg)?;
+ self.f.write_char('}')?;
+ Ok(())
+ }
+ fn visit_reg_scale_masked(&mut self, spec: RegSpec, scale: u8, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> {
+ self.f.write_fixed_size("[")?;
+ self.f.write_reg(spec)?;
+ self.f.write_fixed_size(" * ")?;
+ self.f.write_char((0x30 + scale) as char)?; // translate scale=1 to '1', scale=2 to '2', etc
+ self.f.write_fixed_size("]")?;
+ self.f.write_char('{')?;
+ self.f.write_reg(mask_reg)?;
+ self.f.write_char('}')?;
+ Ok(())
+ }
+ fn visit_reg_scale_disp_masked(&mut self, spec: RegSpec, scale: u8, disp: i32, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> {
+ self.f.write_fixed_size("[")?;
+ self.f.write_reg(spec)?;
+ self.f.write_fixed_size(" * ")?;
+ self.f.write_char((0x30 + scale) as char)?; // translate scale=1 to '1', scale=2 to '2', etc
+ self.f.write_fixed_size(" ")?;
+ let mut v = disp as u32;
+ if disp < 0 {
+ self.f.write_fixed_size("- 0x")?;
+ v = -disp as u32;
+ } else {
+ self.f.write_fixed_size("+ 0x")?;
+ }
+ self.f.write_u32(v)?;
+ self.f.write_char(']')?;
+ self.f.write_char('{')?;
+ self.f.write_reg(mask_reg)?;
+ self.f.write_char('}')?;
+ Ok(())
+ }
+ fn visit_index_base_masked(&mut self, base: RegSpec, index: RegSpec, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> {
+ self.f.write_fixed_size("[")?;
+ self.f.write_reg(base)?;
+ self.f.write_fixed_size(" + ")?;
+ self.f.write_reg(index)?;
+ self.f.write_fixed_size("]")?;
+ self.f.write_char('{')?;
+ self.f.write_reg(mask_reg)?;
+ self.f.write_char('}')?;
+ Ok(())
+ }
+ fn visit_index_base_disp_masked(&mut self, base: RegSpec, index: RegSpec, disp: i32, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> {
+ self.f.write_fixed_size("[")?;
+ self.f.write_reg(base)?;
+ self.f.write_fixed_size(" + ")?;
+ self.f.write_reg(index)?;
+ self.f.write_fixed_size(" ")?;
+ let mut v = disp as u32;
+ if disp < 0 {
+ self.f.write_fixed_size("- 0x")?;
+ v = -disp as u32;
+ } else {
+ self.f.write_fixed_size("+ 0x")?;
+ }
+ self.f.write_u32(v)?;
+ self.f.write_char(']')?;
+ self.f.write_char('{')?;
+ self.f.write_reg(mask_reg)?;
+ self.f.write_char('}')?;
+ Ok(())
+ }
+ fn visit_index_base_scale_masked(&mut self, base: RegSpec, index: RegSpec, scale: u8, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> {
+ self.f.write_fixed_size("[")?;
+ self.f.write_reg(base)?;
+ self.f.write_fixed_size(" + ")?;
+ self.f.write_reg(index)?;
+ self.f.write_fixed_size(" * ")?;
+ self.f.write_char((0x30 + scale) as char)?; // translate scale=1 to '1', scale=2 to '2', etc
+ self.f.write_fixed_size("]")?;
+ self.f.write_char('{')?;
+ self.f.write_reg(mask_reg)?;
+ self.f.write_char('}')?;
+ Ok(())
+ }
+ fn visit_index_base_scale_disp_masked(&mut self, base: RegSpec, index: RegSpec, scale: u8, disp: i32, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> {
+ self.f.write_fixed_size("[")?;
+ self.f.write_reg(base)?;
+ self.f.write_fixed_size(" + ")?;
+ self.f.write_reg(index)?;
+ self.f.write_fixed_size(" * ")?;
+ self.f.write_char((0x30 + scale) as char)?; // translate scale=1 to '1', scale=2 to '2', etc
+ self.f.write_char(' ')?;
+ let mut v = disp as u32;
+ if disp < 0 {
+ self.f.write_fixed_size("- 0x")?;
+ v = -disp as u32;
+ } else {
+ self.f.write_fixed_size("+ 0x")?;
}
+ self.f.write_u32(v)?;
+ self.f.write_char(']')?;
+ self.f.write_char('{')?;
+ self.f.write_reg(mask_reg)?;
+ self.f.write_char('}')?;
+ Ok(())
+ }
+ fn visit_absolute_far_address(&mut self, segment: u16, address: u32) -> Result<Self::Ok, Self::Error> {
+ self.f.write_prefixed_u16(segment)?;
+ self.f.write_fixed_size(":")?;
+ self.f.write_prefixed_u32(address)?;
+ Ok(())
+ }
+
+
+ fn visit_other(&mut self) -> Result<Self::Ok, Self::Error> {
+ Ok(())
}
}
diff --git a/src/protected_mode/mod.rs b/src/protected_mode/mod.rs
index 2403a8a..b0a3f62 100644
--- a/src/protected_mode/mod.rs
+++ b/src/protected_mode/mod.rs
@@ -450,14 +450,14 @@ impl SaeMode {
/// a human-friendly label for this `SaeMode`:
///
/// ```
- /// use yaxpeax_x86::long_mode::SaeMode;
+ /// use yaxpeax_x86::protected_mode::SaeMode;
///
/// assert_eq!(SaeMode::RoundNearest.label(), "{rne-sae}");
/// assert_eq!(SaeMode::RoundDown.label(), "{rd-sae}");
/// assert_eq!(SaeMode::RoundUp.label(), "{ru-sae}");
/// assert_eq!(SaeMode::RoundZero.label(), "{rz-sae}");
/// ```
- pub fn label(&self) -> &'static str {
+ pub const fn label(&self) -> &'static str {
match self {
SaeMode::RoundNearest => "{rne-sae}",
SaeMode::RoundDown => "{rd-sae}",
@@ -477,6 +477,42 @@ impl SaeMode {
SAE_MODES[idx]
}
}
+
+pub trait OperandVisitor {
+ type Ok;
+ type Error;
+
+ fn visit_reg(&mut self, reg: RegSpec) -> Result<Self::Ok, Self::Error>;
+ fn visit_deref(&mut self, reg: RegSpec) -> Result<Self::Ok, Self::Error>;
+ fn visit_disp(&mut self, reg: RegSpec, disp: i32) -> Result<Self::Ok, Self::Error>;
+ fn visit_reg_scale(&mut self, reg: RegSpec, scale: u8) -> Result<Self::Ok, Self::Error>;
+ fn visit_index_base_scale(&mut self, base: RegSpec, index: RegSpec, scale: u8) -> Result<Self::Ok, Self::Error>;
+ fn visit_index_base_scale_disp(&mut self, base: RegSpec, index: RegSpec, scale: u8, disp: i32) -> Result<Self::Ok, Self::Error>;
+ fn visit_reg_scale_disp(&mut self, reg: RegSpec, scale: u8, disp: i32) -> Result<Self::Ok, Self::Error>;
+ fn visit_i8(&mut self, imm: i8) -> Result<Self::Ok, Self::Error>;
+ fn visit_u8(&mut self, imm: u8) -> Result<Self::Ok, Self::Error>;
+ fn visit_i16(&mut self, imm: i16) -> Result<Self::Ok, Self::Error>;
+ fn visit_u16(&mut self, imm: u16) -> Result<Self::Ok, Self::Error>;
+ fn visit_i32(&mut self, imm: i32) -> Result<Self::Ok, Self::Error>;
+ fn visit_u32(&mut self, imm: u32) -> Result<Self::Ok, Self::Error>;
+ fn visit_abs_u16(&mut self, imm: u16) -> Result<Self::Ok, Self::Error>;
+ fn visit_abs_u32(&mut self, imm: u32) -> Result<Self::Ok, Self::Error>;
+ fn visit_reg_mask_merge(&mut self, base: RegSpec, mask: RegSpec, merge_mode: MergeMode) -> Result<Self::Ok, Self::Error>;
+ fn visit_reg_mask_merge_sae(&mut self, base: RegSpec, mask: RegSpec, merge_mode: MergeMode, sae_mode: SaeMode) -> Result<Self::Ok, Self::Error>;
+ fn visit_reg_mask_merge_sae_noround(&mut self, base: RegSpec, mask: RegSpec, merge_mode: MergeMode) -> Result<Self::Ok, Self::Error>;
+ fn visit_reg_disp_masked(&mut self, base: RegSpec, disp: i32, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error>;
+ fn visit_reg_deref_masked(&mut self, base: RegSpec, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error>;
+ fn visit_reg_scale_masked(&mut self, base: RegSpec, scale: u8, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error>;
+ fn visit_reg_scale_disp_masked(&mut self, base: RegSpec, scale: u8, disp: i32, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error>;
+ fn visit_index_base_masked(&mut self, base: RegSpec, index: RegSpec, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error>;
+ fn visit_index_base_disp_masked(&mut self, base: RegSpec, index: RegSpec, disp: i32, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error>;
+ fn visit_index_base_scale_masked(&mut self, base: RegSpec, index: RegSpec, scale: u8, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error>;
+ fn visit_index_base_scale_disp_masked(&mut self, base: RegSpec, index: RegSpec, scale: u8, disp: i32, mask_reg: RegSpec) -> Result<Self::Ok, Self::Error>;
+ fn visit_absolute_far_address(&mut self, segment: u16, address: u32) -> Result<Self::Ok, Self::Error>;
+
+ fn visit_other(&mut self) -> Result<Self::Ok, Self::Error>;
+}
+
impl Operand {
fn from_spec(inst: &Instruction, spec: OperandSpec) -> Operand {
match spec {
@@ -700,6 +736,51 @@ impl Operand {
}
}
}
+
+ /// provided for parity with [`Instruction::visit_operand`]. this has little utility other than
+ /// to reuse an `OperandVisitor` on an `Operand` directly.
+ pub fn visit<T: OperandVisitor>(&self, visitor: &mut T) -> Result<T::Ok, T::Error> {
+ match self {
+ Operand::Nothing => {
+ visitor.visit_other()
+ }
+ Operand::Register(reg) => {
+ visitor.visit_reg(*reg)
+ }
+ Operand::RegDeref(reg) => {
+ visitor.visit_deref(*reg)
+ }
+ Operand::RegDisp(reg, disp) => {
+ visitor.visit_disp(*reg, *disp)
+ }
+ Operand::ImmediateI8(imm) => visitor.visit_i8(*imm),
+ Operand::ImmediateU8(imm) => visitor.visit_u8(*imm),
+ Operand::ImmediateI16(imm) => visitor.visit_i16(*imm),
+ Operand::ImmediateU16(imm) => visitor.visit_u16(*imm),
+ Operand::ImmediateI32(imm) => visitor.visit_i32(*imm),
+ Operand::ImmediateU32(imm) => visitor.visit_u32(*imm),
+ Operand::DisplacementU16(disp) => visitor.visit_abs_u16(*disp),
+ Operand::DisplacementU32(disp) => visitor.visit_abs_u32(*disp),
+ Operand::RegScale(reg, scale) => visitor.visit_reg_scale(*reg, *scale),
+ Operand::RegScaleDisp(reg, scale, disp) => visitor.visit_reg_scale_disp(*reg, *scale, *disp),
+ Operand::RegIndexBase(_, _) => { /* not actually reachable anymore */ visitor.visit_other() },
+ Operand::RegIndexBaseDisp(_, _, _) => { /* not actually reachable anymore */ visitor.visit_other() },
+ Operand::RegIndexBaseScale(base, index, scale) => visitor.visit_index_base_scale(*base, *index, *scale),
+ Operand::RegIndexBaseScaleDisp(base, index, scale, disp) => visitor.visit_index_base_scale_disp(*base, *index, *scale, *disp),
+ Operand::RegisterMaskMerge(reg, mask, merge) => visitor.visit_reg_mask_merge(*reg, *mask, *merge),
+ Operand::RegisterMaskMergeSae(reg, mask, merge, sae) => visitor.visit_reg_mask_merge_sae(*reg, *mask, *merge, *sae),
+ Operand::RegisterMaskMergeSaeNoround(reg, mask, merge) => visitor.visit_reg_mask_merge_sae_noround(*reg, *mask, *merge),
+ Operand::RegDerefMasked(reg, mask) => visitor.visit_reg_deref_masked(*reg, *mask),
+ Operand::RegDispMasked(reg, disp, mask) => visitor.visit_reg_disp_masked(*reg, *disp, *mask),
+ Operand::RegScaleMasked(reg, scale, mask) => visitor.visit_reg_scale_masked(*reg, *scale, *mask),
+ Operand::RegIndexBaseMasked(_, _, _) => { /* not actually reachable anymore */ visitor.visit_other() },
+ Operand::RegIndexBaseDispMasked(_, _, _, _) => { /* not actually reachable anymore */ visitor.visit_other() },
+ Operand::RegScaleDispMasked(base, scale, disp, mask) => visitor.visit_reg_scale_disp_masked(*base, *scale, *disp, *mask),
+ Operand::RegIndexBaseScaleMasked(base, index, scale, mask) => visitor.visit_index_base_scale_masked(*base, *index, *scale, *mask),
+ Operand::RegIndexBaseScaleDispMasked(base, index, scale, disp, mask) => visitor.visit_index_base_scale_disp_masked(*base, *index, *scale, *disp, *mask),
+ Operand::AbsoluteFarAddress { segment, address } => visitor.visit_absolute_far_address(*segment, *address),
+ }
+ }
}
#[test]