aboutsummaryrefslogtreecommitdiff
path: root/src/real_mode
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2024-06-23 13:16:06 -0700
committeriximeow <me@iximeow.net>2024-06-23 13:16:06 -0700
commitdc500de235361284017e917f28d09c3304973b9c (patch)
tree8125cabdaad318182b961a5bc5408f10a5471901 /src/real_mode
parentf70232d2bc7703eb062820be8896daf06d94d032 (diff)
adapt protected-mode display to real mode
Diffstat (limited to 'src/real_mode')
-rw-r--r--src/real_mode/display.rs1111
1 files changed, 764 insertions, 347 deletions
diff --git a/src/real_mode/display.rs b/src/real_mode/display.rs
index 3e3f524..f574499 100644
--- a/src/real_mode/display.rs
+++ b/src/real_mode/display.rs
@@ -8,6 +8,102 @@ use crate::real_mode::{RegSpec, Opcode, Operand, MergeMode, InstDecoder, Instruc
use yaxpeax_arch::display::DisplaySink;
use yaxpeax_arch::safer_unchecked::GetSaferUnchecked as _;
+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() {
@@ -90,6 +186,19 @@ impl fmt::Display for PrefixVex {
}
}
+impl Segment {
+ fn name(&self) -> &'static [u8; 2] {
+ match self {
+ Segment::CS => b"cs",
+ Segment::DS => b"ds",
+ Segment::ES => b"es",
+ Segment::FS => b"fs",
+ Segment::GS => b"gs",
+ Segment::SS => b"ss",
+ }
+ }
+}
+
impl fmt::Display for Segment {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
@@ -130,6 +239,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))
@@ -144,201 +257,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> super::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(())
}
}
@@ -3365,155 +3640,140 @@ impl Instruction {
}
}
-fn contextualize_intel<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors: &Y, _address: u32, _context: Option<&NoContext>, out: &mut T) -> fmt::Result {
+pub(crate) fn contextualize_intel<T: DisplaySink>(instr: &Instruction, out: &mut T) -> fmt::Result {
if instr.xacquire() {
- out.write_str("xacquire ")?;
+ out.write_fixed_size("xacquire ")?;
}
if instr.xrelease() {
- out.write_str("xrelease ")?;
+ out.write_fixed_size("xrelease ")?;
}
if instr.prefixes.lock() {
- out.write_str("lock ")?;
+ out.write_fixed_size("lock ")?;
}
if instr.prefixes.rep_any() {
if instr.opcode.can_rep() {
if instr.prefixes.rep() {
- write!(out, "rep ")?;
+ out.write_fixed_size("rep ")?;
} else if instr.prefixes.repnz() {
- write!(out, "repnz ")?;
+ out.write_fixed_size("repnz ")?;
}
}
}
- out.write_str(instr.opcode.name())?;
-
- if instr.opcode == Opcode::XBEGIN {
- if (instr.imm as i32) >= 0 {
- return write!(out, " $+{}", colors.number(signed_i32_hex(instr.imm as i32)));
- } else {
- return write!(out, " ${}", colors.number(signed_i32_hex(instr.imm as i32)));
- }
- }
+ out.write_opcode(instr.opcode)?;
if instr.operand_count > 0 {
- out.write_str(" ")?;
-
- let x = Operand::from_spec(instr, instr.operands[0]);
-
- const RELATIVE_BRANCHES: [Opcode; 21] = [
- Opcode::JMP, Opcode::JCXZ,
- Opcode::LOOP, Opcode::LOOPZ, Opcode::LOOPNZ,
- Opcode::JO, Opcode::JNO,
- Opcode::JB, Opcode::JNB,
- Opcode::JZ, Opcode::JNZ,
- Opcode::JNA, Opcode::JA,
- Opcode::JS, Opcode::JNS,
- Opcode::JP, Opcode::JNP,
- Opcode::JL, Opcode::JGE,
- Opcode::JLE, Opcode::JG,
- ];
-
- if instr.operands[0] == OperandSpec::ImmI8 || instr.operands[0] == OperandSpec::ImmI32 {
- if RELATIVE_BRANCHES.contains(&instr.opcode) {
- return match x {
- Operand::ImmediateI8(rel) => {
- if rel >= 0 {
- write!(out, "$+{}", colors.number(signed_i32_hex(rel as i32)))
- } else {
- write!(out, "${}", colors.number(signed_i32_hex(rel as i32)))
- }
- }
- Operand::ImmediateI32(rel) => {
- if rel >= 0 {
- write!(out, "$+{}", colors.number(signed_i32_hex(rel)))
- } else {
- write!(out, "${}", colors.number(signed_i32_hex(rel)))
- }
- }
- _ => { unreachable!() }
- };
- }
- }
+ out.write_fixed_size(" ")?;
- if x.is_memory() {
- out.write_str(MEM_SIZE_STRINGS[instr.mem_size as usize])?;
- out.write_str(" ")?;
+ if instr.visit_operand(0, &mut RelativeBranchPrinter {
+ inst: instr,
+ out,
+ })? {
+ return Ok(());
}
- if let Some(prefix) = instr.segment_override_for_op(0) {
- write!(out, "{}:", prefix)?;
+ if instr.operands[0 as usize].is_memory() {
+ out.write_mem_size_label(instr.mem_size)?;
+ if let Some(prefix) = instr.segment_override_for_op(0) {
+ let name = prefix.name();
+ out.write_char(' ')?;
+ out.write_char(name[0] as char)?;
+ out.write_char(name[1] as char)?;
+ out.write_fixed_size(":")?;
+ } else {
+ out.write_fixed_size(" ")?;
+ }
}
- x.colorize(colors, out)?;
+
+ let mut displayer = DisplayingOperandVisitor {
+ f: out,
+ };
+ instr.visit_operand(0 as u8, &mut displayer)?;
for i in 1..instr.operand_count {
- match instr.opcode {
- _ => {
- match &instr.operands[i as usize] {
- &OperandSpec::Nothing => {
- return Ok(());
- },
- _ => {
- out.write_str(", ")?;
- let x = Operand::from_spec(instr, instr.operands[i as usize]);
- if x.is_memory() {
- out.write_str(MEM_SIZE_STRINGS[instr.mem_size as usize])?;
- out.write_str(" ")?;
+ // don't worry about checking for `instr.operands[i] != Nothing`, it would be a bug to
+ // reach that while iterating only to `operand_count`..
+ out.write_fixed_size(", ")?;
+ if i >= 4 {
+ unsafe { core::hint::unreachable_unchecked(); }
+ }
+
+ if instr.operands[i as usize].is_memory() {
+ out.write_mem_size_label(instr.mem_size)?;
+ if i >= 4 {
+ unsafe { core::hint::unreachable_unchecked(); }
+ }
+ if let Some(prefix) = instr.segment_override_for_op(i) {
+ let name = prefix.name();
+ out.write_char(' ')?;
+ out.write_char(name[0] as char)?;
+ out.write_char(name[1] as char)?;
+ out.write_fixed_size(":")?;
+ } else {
+ out.write_fixed_size(" ")?;
+ }
+ }
+
+ let mut displayer = DisplayingOperandVisitor {
+ f: out,
+ };
+
+ instr.visit_operand(i as u8, &mut displayer)?;
+ if let Some(evex) = instr.prefixes.evex() {
+ if evex.broadcast() && instr.operands[i as usize].is_memory() {
+ let scale = if instr.opcode == Opcode::VCVTPD2PS || instr.opcode == Opcode::VCVTTPD2UDQ || instr.opcode == Opcode::VCVTPD2UDQ || instr.opcode == Opcode::VCVTUDQ2PD || instr.opcode == Opcode::VCVTPS2PD || instr.opcode == Opcode::VCVTQQ2PS || instr.opcode == Opcode::VCVTDQ2PD || instr.opcode == Opcode::VCVTTPD2DQ || instr.opcode == Opcode::VFPCLASSPS || instr.opcode == Opcode::VFPCLASSPD || instr.opcode == Opcode::VCVTNEPS2BF16 || instr.opcode == Opcode::VCVTUQQ2PS || instr.opcode == Opcode::VCVTPD2DQ || instr.opcode == Opcode::VCVTTPS2UQQ || instr.opcode == Opcode::VCVTPS2UQQ || instr.opcode == Opcode::VCVTTPS2QQ || instr.opcode == Opcode::VCVTPS2QQ {
+ if instr.opcode == Opcode::VFPCLASSPS || instr.opcode == Opcode::VCVTNEPS2BF16 {
+ if evex.vex().l() {
+ 8
+ } else if evex.lp() {
+ 16
+ } else {
+ 4
}
- if let Some(prefix) = instr.segment_override_for_op(i) {
- write!(out, "{}:", prefix)?;
+ } else if instr.opcode == Opcode::VFPCLASSPD {
+ if evex.vex().l() {
+ 4
+ } else if evex.lp() {
+ 8
+ } else {
+ 2
}
- x.colorize(colors, out)?;
- if let Some(evex) = instr.prefixes.evex() {
- if evex.broadcast() && x.is_memory() {
- let scale = if instr.opcode == Opcode::VCVTPD2PS || instr.opcode == Opcode::VCVTTPD2UDQ || instr.opcode == Opcode::VCVTPD2UDQ || instr.opcode == Opcode::VCVTUDQ2PD || instr.opcode == Opcode::VCVTPS2PD || instr.opcode == Opcode::VCVTQQ2PS || instr.opcode == Opcode::VCVTDQ2PD || instr.opcode == Opcode::VCVTTPD2DQ || instr.opcode == Opcode::VFPCLASSPS || instr.opcode == Opcode::VFPCLASSPD || instr.opcode == Opcode::VCVTNEPS2BF16 || instr.opcode == Opcode::VCVTUQQ2PS || instr.opcode == Opcode::VCVTPD2DQ || instr.opcode == Opcode::VCVTTPS2UQQ || instr.opcode == Opcode::VCVTPS2UQQ || instr.opcode == Opcode::VCVTTPS2QQ || instr.opcode == Opcode::VCVTPS2QQ {
- if instr.opcode == Opcode::VFPCLASSPS || instr.opcode == Opcode::VCVTNEPS2BF16 {
- if evex.vex().l() {
- 8
- } else if evex.lp() {
- 16
- } else {
- 4
- }
- } else if instr.opcode == Opcode::VFPCLASSPD {
- if evex.vex().l() {
- 4
- } else if evex.lp() {
- 8
- } else {
- 2
- }
- } else {
- // vcvtpd2ps is "cool": in broadcast mode, it can read a
- // double-precision float (qword), resize to single-precision,
- // then broadcast that to the whole destination register. this
- // means we need to show `xmm, qword [addr]{1to4}` if vector
- // size is 256. likewise, scale of 8 for the same truncation
- // reason if vector size is 512.
- // vcvtudq2pd is the same story.
- // vfpclassp{s,d} is a mystery to me.
- if evex.vex().l() {
- 4
- } else if evex.lp() {
- 8
- } else {
- 2
- }
- }
- } else {
- // this should never be `None` - that would imply two
- // memory operands for a broadcasted operation.
- if let Some(width) = Operand::from_spec(instr, instr.operands[i as usize - 1]).width() {
- width / instr.mem_size
- } else {
- 0
- }
- };
- write!(out, "{{1to{}}}", scale)?;
- }
+ } else {
+ // vcvtpd2ps is "cool": in broadcast mode, it can read a
+ // double-precision float (qword), resize to single-precision,
+ // then broadcast that to the whole destination register. this
+ // means we need to show `xmm, qword [addr]{1to4}` if vector
+ // size is 256. likewise, scale of 8 for the same truncation
+ // reason if vector size is 512.
+ // vcvtudq2pd is the same story.
+ // vfpclassp{s,d} is a mystery to me.
+ if evex.vex().l() {
+ 4
+ } else if evex.lp() {
+ 8
+ } else {
+ 2
}
}
+ } else {
+ // this should never be `None` - that would imply two
+ // memory operands for a broadcasted operation.
+ if let Some(width) = Operand::from_spec(instr, instr.operands[i as usize - 1]).width() {
+ width / instr.mem_size
+ } else {
+ 0
+ }
+ };
+ out.write_fixed_size("{1to")?;
+ static STRING_LUT: &'static [&'static str] = &[
+ "0", "1", "2", "3", "4", "5", "6", "7", "8",
+ "9", "10", "11", "12", "13", "14", "15", "16",
+ ];
+ unsafe {
+ out.write_lt_16(STRING_LUT.get_kinda_unchecked(scale as usize))?;
}
+ out.write_char('}')?;
}
}
}
@@ -3521,7 +3781,7 @@ fn contextualize_intel<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors:
Ok(())
}
-fn contextualize_c<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors: &Y, _address: u32, _context: Option<&NoContext>, out: &mut T) -> fmt::Result {
+pub(crate) fn contextualize_c<T: DisplaySink>(instr: &Instruction, out: &mut T) -> fmt::Result {
let mut brace_count = 0;
let mut prefixed = false;
@@ -3545,7 +3805,7 @@ fn contextualize_c<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors: &Y,
}
if instr.prefixes.rep_any() {
- if [Opcode::MOVS, Opcode::CMPS, Opcode::LODS, Opcode::STOS, Opcode::INS, Opcode::OUTS].contains(&instr.opcode) {
+ if instr.opcode.can_rep() {
let word_str = match instr.mem_size {
1 => "byte",
2 => "word",
@@ -3567,21 +3827,29 @@ fn contextualize_c<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors: &Y,
}
}
- fn write_jmp_operand<T: fmt::Write, Y: YaxColors>(op: Operand, colors: &Y, out: &mut T) -> fmt::Result {
+ fn write_jmp_operand<T: fmt::Write>(op: Operand, out: &mut T) -> fmt::Result {
+ let mut out = yaxpeax_arch::display::FmtSink::new(out);
+ use core::fmt::Write;
match op {
Operand::ImmediateI8(rel) => {
- if rel >= 0 {
- write!(out, "$+{}", colors.number(signed_i32_hex(rel as i32)))
+ let rel = if rel >= 0 {
+ out.write_str("$+")?;
+ rel as u8
} else {
- write!(out, "${}", colors.number(signed_i32_hex(rel as i32)))
- }
+ out.write_str("$-")?;
+ rel.unsigned_abs()
+ };
+ out.write_prefixed_u8(rel)
}
Operand::ImmediateI32(rel) => {
- if rel >= 0 {
- write!(out, "$+{}", colors.number(signed_i32_hex(rel)))
+ let rel = if rel >= 0 {
+ out.write_str("$+")?;
+ rel as u32
} else {
- write!(out, "${}", colors.number(signed_i32_hex(rel)))
- }
+ out.write_str("$-")?;
+ rel.unsigned_abs()
+ };
+ out.write_prefixed_u32(rel)
}
other => {
write!(out, "{}", other)
@@ -3744,87 +4012,87 @@ fn contextualize_c<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors: &Y,
}
Opcode::JMP => {
out.write_str("jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::JCXZ => {
out.write_str("if cx == 0 then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::LOOP => {
out.write_str("cx--; if cx != 0 then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::LOOPZ => {
out.write_str("cx--; if cx != 0 and zero(rflags) then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::LOOPNZ => {
out.write_str("cx--; if cx != 0 and !zero(rflags) then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::JO => {
out.write_str("if _(rflags) then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::JNO => {
out.write_str("if _(rflags) then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::JB => {
out.write_str("if /* unsigned */ below(rflags) then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::JNB => {
out.write_str("if /* unsigned */ above_or_equal(rflags) then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::JZ => {
out.write_str("if zero(rflags) then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::JNZ => {
out.write_str("if !zero(rflags) then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::JNA => {
out.write_str("if /* unsigned */ below_or_equal(rflags) then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::JA => {
out.write_str("if /* unsigned */ above(rflags) then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::JS => {
out.write_str("if signed(rflags) then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::JNS => {
out.write_str("if !signed(rflags) then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::JP => {
out.write_str("if parity(rflags) then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::JNP => {
out.write_str("if !parity(rflags) then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::JL => {
out.write_str("if /* signed */ less(rflags) then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::JGE => {
out.write_str("if /* signed */ greater_or_equal(rflags) then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::JLE => {
out.write_str("if /* signed */ less_or_equal(rflags) then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::JG => {
out.write_str("if /* signed */ greater(rflags) then jmp ")?;
- write_jmp_operand(instr.operand(0), colors, out)?;
+ write_jmp_operand(instr.operand(0), out)?;
},
Opcode::NOP => {
write!(out, "nop")?;
@@ -3856,18 +4124,20 @@ fn contextualize_c<T: fmt::Write, Y: YaxColors>(instr: &Instruction, colors: &Y,
}
impl <'instr, T: fmt::Write, Y: YaxColors> ShowContextual<u32, NoContext, T, Y> for InstructionDisplayer<'instr> {
- fn contextualize(&self, colors: &Y, address: u32, context: Option<&NoContext>, out: &mut T) -> fmt::Result {
+ fn contextualize(&self, _colors: &Y, _address: u32, _context: Option<&NoContext>, out: &mut T) -> fmt::Result {
let InstructionDisplayer {
instr,
style,
} = self;
+ let mut out = yaxpeax_arch::display::FmtSink::new(out);
+
match style {
DisplayStyle::Intel => {
- contextualize_intel(instr, colors, address, context, out)
+ contextualize_intel(instr, &mut out)
}
DisplayStyle::C => {
- contextualize_c(instr, colors, address, context, out)
+ contextualize_c(instr, &mut out)
}
}
}
@@ -3933,3 +4203,150 @@ impl <T: fmt::Write, Y: YaxColors> ShowContextual<u64, [Option<alloc::string::St
Ok(())
}
}
+
+// TODO: should include CALL
+static RELATIVE_BRANCHES: [Opcode; 21] = [
+ Opcode::JMP, Opcode::JCXZ,
+ Opcode::LOOP, Opcode::LOOPZ, Opcode::LOOPNZ,
+ Opcode::JO, Opcode::JNO,
+ Opcode::JB, Opcode::JNB,
+ Opcode::JZ, Opcode::JNZ,
+ Opcode::JNA, Opcode::JA,
+ Opcode::JS, Opcode::JNS,
+ Opcode::JP, Opcode::JNP,
+ Opcode::JL, Opcode::JGE,
+ Opcode::JLE, Opcode::JG,
+];
+
+struct RelativeBranchPrinter<'a, F: DisplaySink> {
+ inst: &'a Instruction,
+ out: &'a mut F,
+}
+
+impl<'a, F: DisplaySink> super::OperandVisitor for RelativeBranchPrinter<'a, F> {
+ // return true if we printed a relative branch offset, false otherwise
+ type Ok = bool;
+ // but errors are errors
+ type Error = fmt::Error;
+
+ fn visit_reg(&mut self, _reg: RegSpec) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_deref(&mut self, _reg: RegSpec) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_disp(&mut self, _reg: RegSpec, _disp: i32) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ #[cfg_attr(feature="profiling", inline(never))]
+ fn visit_i8(&mut self, rel: i8) -> Result<Self::Ok, Self::Error> {
+ if RELATIVE_BRANCHES.contains(&self.inst.opcode) {
+ self.out.write_char('$')?;
+ // danger_anguished_string_write(self.out, "$");
+ let mut v = rel as u8;
+ if rel < 0 {
+ self.out.write_char('-')?;
+ //danger_anguished_string_write(&mut self.out, "-");
+ v = -rel as u8;
+ } else {
+ self.out.write_char('+')?;
+ // danger_anguished_string_write(&mut self.out, "+");
+ }
+ self.out.write_fixed_size("0x")?;
+ self.out.write_u8(v)?;
+ Ok(true)
+ } else {
+ Ok(false)
+ }
+ }
+ #[cfg_attr(feature="profiling", inline(never))]
+ fn visit_i32(&mut self, rel: i32) -> Result<Self::Ok, Self::Error> {
+ if RELATIVE_BRANCHES.contains(&self.inst.opcode) || self.inst.opcode == Opcode::XBEGIN {
+ self.out.write_char('$')?;
+ // danger_anguished_string_write(self.out, "$");
+ let mut v = rel as u32;
+ if rel < 0 {
+ self.out.write_char('-')?;
+ // danger_anguished_string_write(&mut self.out, "-");
+ v = -rel as u32;
+ } else {
+ self.out.write_char('+')?;
+ // danger_anguished_string_write(&mut self.out, "+");
+ }
+ self.out.write_fixed_size("0x")?;
+ self.out.write_u32(v)?;
+ Ok(true)
+ } else {
+ Ok(false)
+ }
+ }
+ fn visit_u8(&mut self, _imm: u8) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_i16(&mut self, _imm: i16) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_u16(&mut self, _imm: u16) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_u32(&mut self, _imm: u32) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_abs_u16(&mut self, _imm: u16) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_abs_u32(&mut self, _imm: u32) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_reg_scale(&mut self, _reg: RegSpec, _scale: u8) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_index_base_scale(&mut self, _base: RegSpec, _index: RegSpec, _scale: u8) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_reg_scale_disp(&mut self, _reg: RegSpec, _scale: u8, _disp: i32) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_index_base_scale_disp(&mut self, _base: RegSpec, _index: RegSpec, _scale: u8, _disp: i32) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_other(&mut self) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_reg_mask_merge(&mut self, _spec: RegSpec, _mask: RegSpec, _merge_mode: MergeMode) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_reg_mask_merge_sae(&mut self, _spec: RegSpec, _mask: RegSpec, _merge_mode: MergeMode, _sae_mode: super::SaeMode) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_reg_mask_merge_sae_noround(&mut self, _spec: RegSpec, _mask: RegSpec, _merge_mode: MergeMode) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_reg_disp_masked(&mut self, _spec: RegSpec, _disp: i32, _mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_reg_deref_masked(&mut self, _spec: RegSpec, _mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_reg_scale_masked(&mut self, _spec: RegSpec, _scale: u8, _mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_reg_scale_disp_masked(&mut self, _spec: RegSpec, _scale: u8, _disp: i32, _mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_index_base_masked(&mut self, _base: RegSpec, _index: RegSpec, _mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_index_base_disp_masked(&mut self, _base: RegSpec, _index: RegSpec, _disp: i32, _mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ fn visit_index_base_scale_masked(&mut self, _base: RegSpec, _index: RegSpec, _scale: u8, _mask_reg: RegSpec) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+ 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> {
+ Ok(false)
+ }
+ fn visit_absolute_far_address(&mut self, _segment: u16, _address: u32) -> Result<Self::Ok, Self::Error> {
+ Ok(false)
+ }
+}