From 347042c45ced56b37a665a2c4b042b7f7aae8e03 Mon Sep 17 00:00:00 2001 From: iximeow Date: Sat, 22 Jun 2024 00:25:01 -0700 Subject: extract reusable display bits into yaxpeax-arch, add a visitor fn to Operand comes with deleting the body of impl Colorize for Operand, because we can reuse the normal operand formatting code --- src/long_mode/display.rs | 285 +++++++++-------------------------------------- src/long_mode/mod.rs | 46 ++++++++ 2 files changed, 98 insertions(+), 233 deletions(-) (limited to 'src/long_mode') diff --git a/src/long_mode/display.rs b/src/long_mode/display.rs index 3615538..18314ab 100644 --- a/src/long_mode/display.rs +++ b/src/long_mode/display.rs @@ -1,14 +1,12 @@ use core::fmt; use yaxpeax_arch::{Colorize, ShowContextual, NoColors, YaxColors}; -use yaxpeax_arch::display::*; use crate::safer_unchecked::GetSaferUnchecked as _; use crate::MEM_SIZE_STRINGS; use crate::long_mode::{RegSpec, Opcode, Operand, MergeMode, InstDecoder, Instruction, Segment, PrefixRex, OperandSpec}; -use crate::display::DisplaySink; -use crate::display::TokenType; +use yaxpeax_arch::display::DisplaySink; impl fmt::Display for InstDecoder { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -166,202 +164,13 @@ impl fmt::Display for Operand { impl Colorize 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::ImmediateU64(imm) => { - write!(f, "{}", colors.number(u64_hex(imm))) - } - &Operand::ImmediateI64(imm) => { - write!(f, "{}", - colors.number(signed_i64_hex(imm))) - }, - &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::DisplacementU32(imm) => { - write!(f, "[{}]", colors.address(u32_hex(imm))) - } - &Operand::DisplacementU64(imm) => { - write!(f, "[{}]", colors.address(u64_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) - ) - } - &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)) - } - &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)) - } - &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(()) }, - } + let mut f = yaxpeax_arch::display::NoColorsSink { + out: f + }; + let mut visitor = ColorizingOperandVisitor { + f: &mut f + }; + self.visit(&mut visitor) } } @@ -375,15 +184,15 @@ impl crate::long_mode::OperandVisitor for ColorizingOperandVisi #[cfg_attr(feature="profiling", inline(never))] fn visit_u8(&mut self, imm: u8) -> Result { - self.f.span_start(TokenType::Immediate); + self.f.span_start_immediate(); self.f.write_fixed_size("0x")?; self.f.write_u8(imm)?; - self.f.span_end(TokenType::Immediate); + self.f.span_end_immediate(); Ok(()) } #[cfg_attr(feature="profiling", inline(never))] fn visit_i8(&mut self, imm: i8) -> Result { - self.f.span_start(TokenType::Immediate); + self.f.span_start_immediate(); let mut v = imm as u8; if imm < 0 { self.f.write_char('-')?; @@ -391,20 +200,20 @@ impl crate::long_mode::OperandVisitor for ColorizingOperandVisi } self.f.write_fixed_size("0x")?; self.f.write_u8(v)?; - self.f.span_end(TokenType::Immediate); + self.f.span_end_immediate(); Ok(()) } #[cfg_attr(feature="profiling", inline(never))] fn visit_u16(&mut self, imm: u16) -> Result { - self.f.span_start(TokenType::Immediate); + self.f.span_start_immediate(); self.f.write_fixed_size("0x")?; self.f.write_u16(imm)?; - self.f.span_end(TokenType::Immediate); + self.f.span_end_immediate(); Ok(()) } #[cfg_attr(feature="profiling", inline(never))] fn visit_i16(&mut self, imm: i16) -> Result { - self.f.span_start(TokenType::Immediate); + self.f.span_start_immediate(); let mut v = imm as u16; if imm < 0 { self.f.write_char('-')?; @@ -412,19 +221,19 @@ impl crate::long_mode::OperandVisitor for ColorizingOperandVisi } self.f.write_fixed_size("0x")?; self.f.write_u16(v)?; - self.f.span_end(TokenType::Immediate); + self.f.span_end_immediate(); Ok(()) } #[cfg_attr(feature="profiling", inline(never))] fn visit_u32(&mut self, imm: u32) -> Result { - self.f.span_start(TokenType::Immediate); + self.f.span_start_immediate(); self.f.write_fixed_size("0x")?; self.f.write_u32(imm)?; - self.f.span_end(TokenType::Immediate); + self.f.span_end_immediate(); Ok(()) } fn visit_i32(&mut self, imm: i32) -> Result { - self.f.span_start(TokenType::Immediate); + self.f.span_start_immediate(); let mut v = imm as u32; if imm < 0 { self.f.write_char('-')?; @@ -432,20 +241,20 @@ impl crate::long_mode::OperandVisitor for ColorizingOperandVisi } self.f.write_fixed_size("0x")?; self.f.write_u32(v)?; - self.f.span_end(TokenType::Immediate); + self.f.span_end_immediate(); Ok(()) } #[cfg_attr(feature="profiling", inline(never))] fn visit_u64(&mut self, imm: u64) -> Result { - self.f.span_start(TokenType::Immediate); + self.f.span_start_immediate(); self.f.write_fixed_size("0x")?; self.f.write_u64(imm)?; - self.f.span_end(TokenType::Immediate); + self.f.span_end_immediate(); Ok(()) } #[cfg_attr(feature="profiling", inline(never))] fn visit_i64(&mut self, imm: i64) -> Result { - self.f.span_start(TokenType::Immediate); + self.f.span_start_immediate(); let mut v = imm as u64; if imm < 0 { self.f.write_char('-')?; @@ -453,25 +262,25 @@ impl crate::long_mode::OperandVisitor for ColorizingOperandVisi } self.f.write_fixed_size("0x")?; self.f.write_u64(v)?; - self.f.span_end(TokenType::Immediate); + self.f.span_end_immediate(); Ok(()) } #[cfg_attr(feature="profiling", inline(never))] fn visit_reg(&mut self, reg: RegSpec) -> Result { - self.f.span_start(TokenType::Register); + self.f.span_start_register(); unsafe { self.f.write_lt_8(regspec_label(®))?; } - self.f.span_end(TokenType::Register); + self.f.span_end_register(); Ok(()) } fn visit_reg_mask_merge(&mut self, spec: RegSpec, mask: RegSpec, merge_mode: MergeMode) -> Result { - self.f.span_start(TokenType::Register); + self.f.span_start_register(); unsafe { self.f.write_lt_8(regspec_label(&spec))?; } - self.f.span_end(TokenType::Register); + self.f.span_end_register(); if mask.num != 0 { self.f.write_fixed_size("{")?; - self.f.span_start(TokenType::Register); + self.f.span_start_register(); unsafe { self.f.write_lt_8(regspec_label(&mask))?; } - self.f.span_end(TokenType::Register); + self.f.span_end_register(); self.f.write_fixed_size("}")?; } if let MergeMode::Zero = merge_mode { @@ -3923,20 +3732,30 @@ pub(crate) fn contextualize_c(instr: &Instruction, out: &mut T) } fn write_jmp_operand(op: Operand, out: &mut T) -> fmt::Result { + let mut out = yaxpeax_arch::display::NoColorsSink { + out, + }; + use core::fmt::Write; match op { Operand::ImmediateI8(rel) => { - if rel >= 0 { - write!(out, "$+{}", (signed_i32_hex(rel as i32))) + let rel = if rel >= 0 { + out.write_str("$+")?; + rel as u8 } else { - write!(out, "${}", (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, "$+{}", (signed_i32_hex(rel))) + let rel = if rel >= 0 { + out.write_str("$+")?; + rel as u32 } else { - write!(out, "${}", (signed_i32_hex(rel))) - } + out.write_str("$-")?; + rel.unsigned_abs() + }; + out.write_prefixed_u32(rel) } other => { write!(out, "{}", other) @@ -4217,7 +4036,7 @@ impl <'instr, T: fmt::Write, Y: YaxColors> ShowContextual style, } = self; - let mut out = crate::display::NoColorsSink { + let mut out = yaxpeax_arch::display::NoColorsSink { out: out, }; @@ -4235,7 +4054,7 @@ impl <'instr, T: fmt::Write, Y: YaxColors> ShowContextual #[cfg(feature="std")] impl ShowContextual], T, Y> for Instruction { fn contextualize(&self, colors: &Y, _address: u64, context: Option<&[Option]>, out: &mut T) -> fmt::Result { - let mut out = crate::display::NoColorsSink { + let mut out = yaxpeax_arch::display::NoColorsSink { out, }; let out = &mut out; @@ -4539,11 +4358,11 @@ impl InstructionTextBuffer { /// into. /// /// SAFETY: callers must print at most one instruction into this handle. - unsafe fn write_handle(&mut self) -> crate::display::InstructionTextSink { + unsafe fn write_handle(&mut self) -> yaxpeax_arch::display::InstructionTextSink { self.content.clear(); // Safety: `content` was just cleared, so writing begins at the start of the buffer. // `content`is large enough to hold a fully-formatted instruction (see // `InstructionTextBuffer::new`). - crate::display::InstructionTextSink::new(&mut self.content) + yaxpeax_arch::display::InstructionTextSink::new(&mut self.content) } } diff --git a/src/long_mode/mod.rs b/src/long_mode/mod.rs index 9aeacdc..d66f59a 100644 --- a/src/long_mode/mod.rs +++ b/src/long_mode/mod.rs @@ -802,6 +802,52 @@ 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(&self, visitor: &mut T) -> Result { + 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::ImmediateI64(imm) => visitor.visit_i64(*imm), + Operand::ImmediateU64(imm) => visitor.visit_u64(*imm), + Operand::DisplacementU32(disp) => visitor.visit_abs_u32(*disp), + Operand::DisplacementU64(disp) => visitor.visit_abs_u64(*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), + } + } } #[test] -- cgit v1.1