aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoriximeow <me@iximeow.net>2019-03-20 14:55:53 -0700
committeriximeow <me@iximeow.net>2020-01-12 16:10:13 -0800
commit0adc1ba0b88e4afd55bb080bb8134a56f302ead7 (patch)
tree387e6e9d3a0df3acd84c2a8cc5cf4a3dbed9528f
parent9e5fd6103b8213376b83b2bc427fc15a1213ba5a (diff)
factor out display for x86, implement colorization... a bit
-rw-r--r--src/display.rs471
-rw-r--r--src/lib.rs444
2 files changed, 474 insertions, 441 deletions
diff --git a/src/display.rs b/src/display.rs
new file mode 100644
index 0000000..0c75342
--- /dev/null
+++ b/src/display.rs
@@ -0,0 +1,471 @@
+extern crate yaxpeax_arch;
+extern crate termion;
+
+use termion::color;
+
+use std::fmt;
+
+use std::hint::unreachable_unchecked;
+
+use yaxpeax_arch::{Arch, Colorize, ColorSettings, Decodable, LengthedInstruction, ShowContextual};
+
+use ::{RegSpec, RegisterBank, Opcode, Operand, Instruction};
+
+impl fmt::Display for RegSpec {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let name = match self.bank {
+ RegisterBank::Q => {
+ ["rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"][self.num as usize]
+ },
+ RegisterBank::D => {
+ ["eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d"][self.num as usize]
+ },
+ RegisterBank::W => {
+ ["ax", "cx", "dx", "bx", "sp", "bp", "si", "di", "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w"][self.num as usize]
+ },
+ RegisterBank::B => {
+ ["al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"][self.num as usize]
+ },
+ RegisterBank::rB => {
+ ["al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b"][self.num as usize]
+ },
+ RegisterBank::EIP => { "eip" },
+ RegisterBank::RIP => { "rip" },
+ _ => panic!("unnamable register")
+ };
+ write!(f, "{}", name)
+ }
+}
+
+impl fmt::Display for Operand {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ self.colorize(None, fmt)
+ }
+}
+
+impl <T: std::fmt::Write> Colorize<T> for Operand {
+ fn colorize(&self, colors: Option<&ColorSettings>, f: &mut T) -> std::fmt::Result {
+ match self {
+ &Operand::ImmediateI16(imm) => write!(f, "0x{:x}", imm),
+ &Operand::ImmediateU16(imm) => write!(f, "0x{:x}", imm),
+ &Operand::ImmediateU32(imm) => write!(f, "0x{:x}", imm),
+ &Operand::ImmediateI32(imm) => write!(f, "0x{:x}", imm),
+ &Operand::ImmediateU64(imm) => write!(f, "0x{:x}", imm),
+ &Operand::ImmediateI64(imm) => write!(f, "0x{:x}", imm),
+ &Operand::Register(ref spec) => write!(f, "{}", spec),
+ &Operand::ImmediateI8(imm) => write!(f, "0x{:x}", imm),
+ &Operand::ImmediateU8(imm) => write!(f, "0x{:x}", imm),
+ &Operand::DisplacementU32(imm) => write!(f, "[0x{:x}]", imm),
+ &Operand::DisplacementU64(imm) => write!(f, "[0x{:x}]", imm),
+ &Operand::RegDisp(ref spec, ref disp) => {
+ if *disp < 0 {
+ write!(f, "[{} - 0x{:x}]", spec, -disp)
+ } else {
+ write!(f, "[{} + 0x{:x}]", spec, disp)
+ }
+ },
+ &Operand::RegDeref(ref spec) => write!(f, "[{}]", spec),
+ &Operand::RegScale(ref spec, scale) => write!(f, "[{} * {}]", spec, scale),
+ &Operand::RegScaleDisp(ref spec, scale, disp) => {
+ write!(f, "[{} * {} + 0x{:x}]", spec, scale, disp)
+ },
+ &Operand::RegIndexBase(ref base, ref index) => {
+ write!(f, "[{} + {}]", base, index)
+ }
+ &Operand::RegIndexBaseDisp(ref base, ref index, disp) => {
+ write!(f, "[{} + {} + 0x{:x}]", base, index, disp)
+ },
+ &Operand::RegIndexBaseScale(ref base, ref index, scale) => {
+ if scale == 1 {
+ write!(f, "[{} + {}]", base, index)
+ } else {
+ write!(f, "[{} + {} * {}]", base, index, scale)
+ }
+ }
+ &Operand::RegIndexBaseScaleDisp(ref base, ref index, scale, disp) => {
+ if scale == 1 {
+ write!(f, "[{} + {} + {:#x}]", base, index, disp)
+ } else {
+ write!(f, "[{} + {} * {} + {:#x}]", base, index, scale, disp)
+ }
+ },
+ &Operand::Nothing => { Ok(()) },
+ &Operand::Many(_) => { panic!("many not covered"); }
+ }
+ }
+}
+
+impl fmt::Display for Opcode {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ &Opcode::INC => write!(f, "{}", "inc"),
+ &Opcode::DEC => write!(f, "{}", "dec"),
+ &Opcode::HLT => write!(f, "{}", "hlt"),
+ &Opcode::SBB => write!(f, "{}", "sbb"),
+ &Opcode::AND => write!(f, "{}", "and"),
+ &Opcode::XOR => write!(f, "{}", "xor"),
+ &Opcode::OR => write!(f, "{}", "or"),
+ &Opcode::PUSH => write!(f, "{}", "push"),
+ &Opcode::POP => write!(f, "{}", "pop"),
+ &Opcode::LEA => write!(f, "{}", "lea"),
+ &Opcode::NOP => write!(f, "{}", "nop"),
+ &Opcode::XCHG => write!(f, "{}", "xchg"),
+ &Opcode::POPF => write!(f, "{}", "popf"),
+ &Opcode::ADD => write!(f, "{}", "add"),
+ &Opcode::ADC => write!(f, "{}", "adc"),
+ &Opcode::SUB => write!(f, "{}", "sub"),
+ &Opcode::INT => write!(f, "{}", "int"),
+ &Opcode::INTO => write!(f, "{}", "into"),
+ &Opcode::IRET => write!(f, "{}", "iret"),
+ &Opcode::RETF => write!(f, "{}", "retf"),
+ &Opcode::ENTER => write!(f, "{}", "enter"),
+ &Opcode::LEAVE => write!(f, "{}", "leave"),
+ &Opcode::MOV => write!(f, "{}", "mov"),
+ &Opcode::RETURN => write!(f, "{}", "ret"),
+ &Opcode::PUSHF => write!(f, "{}", "pushf"),
+ &Opcode::WAIT => write!(f, "{}", "wait"),
+ &Opcode::CBW => write!(f, "{}", "cbw"),
+ &Opcode::CDW => write!(f, "{}", "cdw"),
+ &Opcode::LODS => write!(f, "{}", "lods"),
+ &Opcode::STOS => write!(f, "{}", "stos"),
+ &Opcode::LAHF => write!(f, "{}", "lahf"),
+ &Opcode::SAHF => write!(f, "{}", "sahf"),
+ &Opcode::CMPS => write!(f, "{}", "cmps"),
+ &Opcode::SCAS => write!(f, "{}", "scas"),
+ &Opcode::MOVS => write!(f, "{}", "movs"),
+ &Opcode::TEST => write!(f, "{}", "test"),
+ &Opcode::CMP => write!(f, "{}", "cmp"),
+ &Opcode::INS => write!(f, "{}", "ins"),
+ &Opcode::OUTS => write!(f, "{}", "outs"),
+ &Opcode::IMUL => write!(f, "{}", "imul"),
+ &Opcode::JO => write!(f, "{}", "jo"),
+ &Opcode::JNO => write!(f, "{}", "jno"),
+ &Opcode::JB => write!(f, "{}", "jb"),
+ &Opcode::JNB => write!(f, "{}", "jnb"),
+ &Opcode::JZ => write!(f, "{}", "jz"),
+ &Opcode::JNZ => write!(f, "{}", "jnz"),
+ &Opcode::JA => write!(f, "{}", "ja"),
+ &Opcode::JNA => write!(f, "{}", "jna"),
+ &Opcode::JS => write!(f, "{}", "js"),
+ &Opcode::JNS => write!(f, "{}", "jns"),
+ &Opcode::JP => write!(f, "{}", "jp"),
+ &Opcode::JNP => write!(f, "{}", "jnp"),
+ &Opcode::JL => write!(f, "{}", "jl"),
+ &Opcode::JGE => write!(f, "{}", "jge"),
+ &Opcode::JLE => write!(f, "{}", "jle"),
+ &Opcode::JG => write!(f, "{}", "jg"),
+ &Opcode::CALL => write!(f, "{}", "call"),
+ &Opcode::JMP => write!(f, "{}", "jmp"),
+ &Opcode::CALLF => write!(f, "{}", "callf"),
+ &Opcode::JMPF => write!(f, "{}", "jmpf"),
+ &Opcode::SAR => write!(f, "{}", "sar"),
+ &Opcode::SAL => write!(f, "{}", "sal"),
+ &Opcode::SHR => write!(f, "{}", "shr"),
+ &Opcode::SHL => write!(f, "{}", "shl"),
+ &Opcode::RCR => write!(f, "{}", "rcr"),
+ &Opcode::RCL => write!(f, "{}", "rcl"),
+ &Opcode::ROR => write!(f, "{}", "ror"),
+ &Opcode::ROL => write!(f, "{}", "rol"),
+ &Opcode::CMOVA => write!(f, "{}", "cmova"),
+ &Opcode::CMOVB => write!(f, "{}", "cmovb"),
+ &Opcode::CMOVG => write!(f, "{}", "cmovg"),
+ &Opcode::CMOVGE => write!(f, "{}", "cmovge"),
+ &Opcode::CMOVL => write!(f, "{}", "cmovl"),
+ &Opcode::CMOVLE => write!(f, "{}", "cmovle"),
+ &Opcode::CMOVNA => write!(f, "{}", "cmovna"),
+ &Opcode::CMOVNB => write!(f, "{}", "cmovnb"),
+ &Opcode::CMOVNO => write!(f, "{}", "cmovno"),
+ &Opcode::CMOVNP => write!(f, "{}", "cmovnp"),
+ &Opcode::CMOVNS => write!(f, "{}", "cmovns"),
+ &Opcode::CMOVNZ => write!(f, "{}", "cmovnz"),
+ &Opcode::CMOVO => write!(f, "{}", "cmovo"),
+ &Opcode::CMOVP => write!(f, "{}", "cmovp"),
+ &Opcode::CMOVS => write!(f, "{}", "cmovs"),
+ &Opcode::CMOVZ => write!(f, "{}", "cmovz"),
+ &Opcode::NEG => write!(f, "{}", "neg"),
+ &Opcode::NOT => write!(f, "{}", "not"),
+ &Opcode::MUL => write!(f, "{}", "mul"),
+ &Opcode::DIV => write!(f, "{}", "div"),
+ &Opcode::IDIV => write!(f, "{}", "idiv"),
+ &Opcode::CMPXCHG => write!(f, "{}", "cmpxchg"),
+ &Opcode::MOVZX_b => write!(f, "{}", "movzx"),
+ &Opcode::MOVZX_w => write!(f, "{}", "movzx"),
+ &Opcode::MOVSX => write!(f, "{}", "movsx"),
+ &Opcode::SETO => write!(f, "{}", "seto"),
+ &Opcode::SETNO => write!(f, "{}", "setno"),
+ &Opcode::SETB => write!(f, "{}", "setb"),
+ &Opcode::SETAE => write!(f, "{}", "setae"),
+ &Opcode::SETZ => write!(f, "{}", "setz"),
+ &Opcode::SETNZ => write!(f, "{}", "setnz"),
+ &Opcode::SETBE => write!(f, "{}", "setbe"),
+ &Opcode::SETA => write!(f, "{}", "seta"),
+ &Opcode::SETS => write!(f, "{}", "sets"),
+ &Opcode::SETNS => write!(f, "{}", "setns"),
+ &Opcode::SETP => write!(f, "{}", "setp"),
+ &Opcode::SETNP => write!(f, "{}", "setnp"),
+ &Opcode::SETL => write!(f, "{}", "setl"),
+ &Opcode::SETGE => write!(f, "{}", "setge"),
+ &Opcode::SETLE => write!(f, "{}", "setle"),
+ &Opcode::SETG => write!(f, "{}", "setg"),
+ &Opcode::Invalid => write!(f, "{}", "invalid")
+ }
+ }
+}
+
+impl <T: std::fmt::Write> Colorize<T> for Opcode {
+ fn colorize(&self, colors: Option<&ColorSettings>, out: &mut T) -> std::fmt::Result {
+ match colors {
+ Some(colors) => {
+ write!(out, "{}{}{}", color_for(*self, colors), self, color::Fg(&color::Reset as &color::Color))
+ },
+ None => {
+ write!(out, "{}", self)
+ }
+ }
+ }
+}
+
+fn color_for(opcode: Opcode, colors: &ColorSettings) -> &color::Fg<&'static color::Color> {
+ match opcode {
+ Opcode::DIV |
+ Opcode::IDIV |
+ Opcode::MUL |
+ Opcode::NEG |
+ Opcode::NOT |
+ Opcode::SAR |
+ Opcode::SAL |
+ Opcode::SHR |
+ Opcode::SHL |
+ Opcode::RCR |
+ Opcode::RCL |
+ Opcode::ROR |
+ Opcode::ROL |
+ Opcode::INC |
+ Opcode::DEC |
+ Opcode::SBB |
+ Opcode::AND |
+ Opcode::XOR |
+ Opcode::OR |
+ Opcode::LEA |
+ Opcode::ADD |
+ Opcode::ADC |
+ Opcode::SUB |
+ Opcode::IMUL => { colors.arithmetic_op() }
+ Opcode::POPF |
+ Opcode::PUSHF |
+ Opcode::ENTER |
+ Opcode::LEAVE |
+ Opcode::PUSH |
+ Opcode::POP => { colors.stack_op() }
+ Opcode::WAIT |
+ Opcode::NOP => { colors.nop_op() }
+
+ /* Control flow */
+ Opcode::HLT |
+ Opcode::INT |
+ Opcode::INTO |
+ Opcode::IRET |
+ Opcode::RETF |
+ Opcode::RETURN => { colors.stop_op() }
+ Opcode::CALL |
+ Opcode::CALLF |
+ Opcode::JMP |
+ Opcode::JMPF |
+ Opcode::JO |
+ Opcode::JNO |
+ Opcode::JB |
+ Opcode::JNB |
+ Opcode::JZ |
+ Opcode::JNZ |
+ Opcode::JA |
+ Opcode::JNA |
+ Opcode::JS |
+ Opcode::JNS |
+ Opcode::JP |
+ Opcode::JNP |
+ Opcode::JL |
+ Opcode::JGE |
+ Opcode::JLE |
+ Opcode::JG => { colors.control_flow_op() }
+
+ /* Data transfer */
+ Opcode::MOV |
+ Opcode::CBW |
+ Opcode::CDW |
+ Opcode::LODS |
+ Opcode::STOS |
+ Opcode::LAHF |
+ Opcode::SAHF |
+ Opcode::MOVS |
+ Opcode::INS |
+ Opcode::OUTS |
+ Opcode::MOVZX_b |
+ Opcode::MOVZX_w |
+ Opcode::MOVSX |
+ Opcode::XCHG |
+ Opcode::CMOVA |
+ Opcode::CMOVB |
+ Opcode::CMOVG |
+ Opcode::CMOVGE |
+ Opcode::CMOVL |
+ Opcode::CMOVLE |
+ Opcode::CMOVNA |
+ Opcode::CMOVNB |
+ Opcode::CMOVNO |
+ Opcode::CMOVNP |
+ Opcode::CMOVNS |
+ Opcode::CMOVNZ |
+ Opcode::CMOVO |
+ Opcode::CMOVP |
+ Opcode::CMOVS |
+ Opcode::CMOVZ |
+ Opcode::SETO |
+ Opcode::SETNO |
+ Opcode::SETB |
+ Opcode::SETAE |
+ Opcode::SETZ |
+ Opcode::SETNZ |
+ Opcode::SETBE |
+ Opcode::SETA |
+ Opcode::SETS |
+ Opcode::SETNS |
+ Opcode::SETP |
+ Opcode::SETNP |
+ Opcode::SETL |
+ Opcode::SETGE |
+ Opcode::SETLE |
+ Opcode::SETG => { colors.data_op() }
+
+ Opcode::CMPS |
+ Opcode::SCAS |
+ Opcode::TEST |
+ Opcode::CMP |
+ Opcode::CMPXCHG => { colors.comparison_op() }
+
+ Opcode::Invalid => { colors.invalid_op() }
+ }
+}
+
+impl fmt::Display for Instruction {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ self.colorize(None, fmt)
+ }
+}
+
+/*
+ * Can't implement this as accepting a formatter because rust
+ * doesn't let me build one outside println! or write! or whatever.
+ *
+ * can't write this as an intermediate struct because i refuse to copy
+ * all data into the struct, and having a function producing a struct with
+ * some lifetimes gets really hairy if it's from a trait - same GAT kind
+ * of nonsense as i saw with ContextRead, because someone could hold onto
+ * the dang intermediate struct forever.
+ *
+ * so write to some Write thing i guess. bite me. i really just want to
+ * stop thinking about how to support printing instructions...
+ */
+impl <T: std::fmt::Write> Colorize<T> for Instruction {
+ fn colorize(&self, colors: Option<&ColorSettings>, out: &mut T) -> std::fmt::Result {
+ // TODO: I DONT LIKE THIS, there is no address i can give contextualize here,
+ // the address operand maybe should be optional..
+ self.contextualize(colors, 0, None, out)
+ }
+}
+
+impl <T: std::fmt::Write> ShowContextual<u64, [Option<String>], T> for Instruction {
+ fn contextualize(&self, colors: Option<&ColorSettings>, address: u64, context: Option<&[Option<String>]>, out: &mut T) -> std::fmt::Result {
+ if self.prefixes.lock {
+ write!(out, "lock ")?;
+ }
+ colors.map(|c| { write!(out, "{}{}{}", color_for(self.opcode, c), self.opcode, color::Fg(&color::Reset as &color::Color)) })
+ .unwrap_or_else(|| { write!(out, "{}", self.opcode) })?;
+ /* For when contextualization is a thing we can do?
+ match self.0.opers.as_ref().and_then(|xs| xs[0].as_ref()) {
+ Some(s) => { write!(out, " {}", s)?; },
+ None => {
+ */
+ match self.operands[0] {
+ Operand::Nothing => {
+ return Ok(());
+ },
+ ref x @ _ => {
+ write!(out, " ")?;
+ x.colorize(colors, out)?;
+ }
+ }
+ /*
+ }
+ }*/;
+ match self.opcode {
+ Opcode::MOVZX_b => {
+ /*
+ match self.0.opers.as_ref().and_then(|xs| xs[1].as_ref()) {
+ Some(s) => { write!(out, ", {}", s) }
+ None => {
+ */
+ match &self.operands[1] {
+ &Operand::Nothing => {
+ return Ok(());
+ },
+ x @ &Operand::Register(_) => {
+ write!(out, ", ")?;
+ x.colorize(colors, out)
+ }
+ x @ _ => {
+ write!(out, ", byte ")?;
+ x.colorize(colors, out)
+ }
+ }
+ /*
+ }
+ }
+ */
+ },
+ Opcode::MOVZX_w => {
+ /*
+ match self.0.opers.as_ref().and_then(|xs| xs[1].as_ref()) {
+ Some(s) => { write!(out, ", {}", s) }
+ None => {
+ */
+ match &self.operands[1] {
+ &Operand::Nothing => {
+ return Ok(());
+ },
+ x @ &Operand::Register(_) => {
+ write!(out, ", ")?;
+ x.colorize(colors, out)
+ }
+ x @ _ => {
+ write!(out, ", word ")?;
+ x.colorize(colors, out)
+ }
+ }
+ /*
+ }
+ }
+ */
+ },
+ _ => {
+ /*
+ match self.0.opers.as_ref().and_then(|xs| xs[1].as_ref()) {
+ Some(s) => { write!(out, ", {}", s) }
+ None => {
+ */
+ match &self.operands[1] {
+ &Operand::Nothing => {
+ return Ok(());
+ },
+ x @ _ => {
+ write!(out, ", ")?;
+ x.colorize(colors, out)
+ }
+ }
+ /*
+ }
+ }
+ */
+ }
+ }
+ }
+}
diff --git a/src/lib.rs b/src/lib.rs
index 6c406ac..cead4df 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1,13 +1,15 @@
extern crate yaxpeax_arch;
extern crate termion;
+mod display;
+
use termion::color;
use std::fmt;
use std::hint::unreachable_unchecked;
-use yaxpeax_arch::{Arch, Colorize, ColorSettings, Decodable, LengthedInstruction};
+use yaxpeax_arch::{Arch, ColorSettings, Decodable, LengthedInstruction};
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct RegSpec {
@@ -51,32 +53,6 @@ impl RegSpec {
}
}
-impl fmt::Display for RegSpec {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let name = match self.bank {
- RegisterBank::Q => {
- ["rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"][self.num as usize]
- },
- RegisterBank::D => {
- ["eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi", "r8d", "r9d", "r10d", "r11d", "r12d", "r13d", "r14d", "r15d"][self.num as usize]
- },
- RegisterBank::W => {
- ["ax", "cx", "dx", "bx", "sp", "bp", "si", "di", "r8w", "r9w", "r10w", "r11w", "r12w", "r13w", "r14w", "r15w"][self.num as usize]
- },
- RegisterBank::B => {
- ["al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"][self.num as usize]
- },
- RegisterBank::rB => {
- ["al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", "r8b", "r9b", "r10b", "r11b", "r12b", "r13b", "r14b", "r15b"][self.num as usize]
- },
- RegisterBank::EIP => { "eip" },
- RegisterBank::RIP => { "rip" },
- _ => panic!("unnamable register")
- };
- write!(f, "{}", name)
- }
-}
-
#[allow(non_camel_case_types)]
enum SizeCode {
b,
@@ -85,64 +61,6 @@ enum SizeCode {
vqp
}
-impl fmt::Display for Operand {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- self.colorize(None, fmt)
- }
-}
-
-impl <T: std::fmt::Write> Colorize<T> for Operand {
- fn colorize(&self, colors: Option<&ColorSettings>, f: &mut T) -> std::fmt::Result {
- match self {
- &Operand::ImmediateI16(imm) => write!(f, "0x{:x}", imm),
- &Operand::ImmediateU16(imm) => write!(f, "0x{:x}", imm),
- &Operand::ImmediateU32(imm) => write!(f, "0x{:x}", imm),
- &Operand::ImmediateI32(imm) => write!(f, "0x{:x}", imm),
- &Operand::ImmediateU64(imm) => write!(f, "0x{:x}", imm),
- &Operand::ImmediateI64(imm) => write!(f, "0x{:x}", imm),
- &Operand::Register(ref spec) => write!(f, "{}", spec),
- &Operand::ImmediateI8(imm) => write!(f, "0x{:x}", imm),
- &Operand::ImmediateU8(imm) => write!(f, "0x{:x}", imm),
- &Operand::DisplacementU32(imm) => write!(f, "[0x{:x}]", imm),
- &Operand::DisplacementU64(imm) => write!(f, "[0x{:x}]", imm),
- &Operand::RegDisp(ref spec, ref disp) => {
- if *disp < 0 {
- write!(f, "[{} - 0x{:x}]", spec, -disp)
- } else {
- write!(f, "[{} + 0x{:x}]", spec, disp)
- }
- },
- &Operand::RegDeref(ref spec) => write!(f, "[{}]", spec),
- &Operand::RegScale(ref spec, scale) => write!(f, "[{} * {}]", spec, scale),
- &Operand::RegScaleDisp(ref spec, scale, disp) => {
- write!(f, "[{} * {} + 0x{:x}]", spec, scale, disp)
- },
- &Operand::RegIndexBase(ref base, ref index) => {
- write!(f, "[{} + {}]", base, index)
- }
- &Operand::RegIndexBaseDisp(ref base, ref index, disp) => {
- write!(f, "[{} + {} + 0x{:x}]", base, index, disp)
- },
- &Operand::RegIndexBaseScale(ref base, ref index, scale) => {
- if scale == 1 {
- write!(f, "[{} + {}]", base, index)
- } else {
- write!(f, "[{} + {} * {}]", base, index, scale)
- }
- }
- &Operand::RegIndexBaseScaleDisp(ref base, ref index, scale, disp) => {
- if scale == 1 {
- write!(f, "[{} + {} + {:#x}]", base, index, disp)
- } else {
- write!(f, "[{} + {} * {} + {:#x}]", base, index, scale, disp)
- }
- },
- &Operand::Nothing => { Ok(()) },
- &Operand::Many(_) => { panic!("many not covered"); }
- }
- }
-}
-
#[derive(Clone, Debug)]
pub enum Operand {
ImmediateI8(i8),
@@ -181,123 +99,6 @@ pub enum Segment {
CS, DS, ES, FS, GS, SS
}
-impl fmt::Display for Opcode {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- match self {
- &Opcode::INC => write!(f, "{}", "inc"),
- &Opcode::DEC => write!(f, "{}", "dec"),
- &Opcode::HLT => write!(f, "{}", "hlt"),
- &Opcode::SBB => write!(f, "{}", "sbb"),
- &Opcode::AND => write!(f, "{}", "and"),
- &Opcode::XOR => write!(f, "{}", "xor"),
- &Opcode::OR => write!(f, "{}", "or"),
- &Opcode::PUSH => write!(f, "{}", "push"),
- &Opcode::POP => write!(f, "{}", "pop"),
- &Opcode::LEA => write!(f, "{}", "lea"),
- &Opcode::NOP => write!(f, "{}", "nop"),
- &Opcode::XCHG => write!(f, "{}", "xchg"),
- &Opcode::POPF => write!(f, "{}", "popf"),
- &Opcode::ADD => write!(f, "{}", "add"),
- &Opcode::ADC => write!(f, "{}", "adc"),
- &Opcode::SUB => write!(f, "{}", "sub"),
- &Opcode::INT => write!(f, "{}", "int"),
- &Opcode::INTO => write!(f, "{}", "into"),
- &Opcode::IRET => write!(f, "{}", "iret"),
- &Opcode::RETF => write!(f, "{}", "retf"),
- &Opcode::ENTER => write!(f, "{}", "enter"),
- &Opcode::LEAVE => write!(f, "{}", "leave"),
- &Opcode::MOV => write!(f, "{}", "mov"),
- &Opcode::RETURN => write!(f, "{}", "ret"),
- &Opcode::PUSHF => write!(f, "{}", "pushf"),
- &Opcode::WAIT => write!(f, "{}", "wait"),
- &Opcode::CBW => write!(f, "{}", "cbw"),
- &Opcode::CDW => write!(f, "{}", "cdw"),
- &Opcode::LODS => write!(f, "{}", "lods"),
- &Opcode::STOS => write!(f, "{}", "stos"),
- &Opcode::LAHF => write!(f, "{}", "lahf"),
- &Opcode::SAHF => write!(f, "{}", "sahf"),
- &Opcode::CMPS => write!(f, "{}", "cmps"),
- &Opcode::SCAS => write!(f, "{}", "scas"),
- &Opcode::MOVS => write!(f, "{}", "movs"),
- &Opcode::TEST => write!(f, "{}", "test"),
- &Opcode::CMP => write!(f, "{}", "cmp"),
- &Opcode::INS => write!(f, "{}", "ins"),
- &Opcode::OUTS => write!(f, "{}", "outs"),
- &Opcode::IMUL => write!(f, "{}", "imul"),
- &Opcode::JO => write!(f, "{}", "jo"),
- &Opcode::JNO => write!(f, "{}", "jno"),
- &Opcode::JB => write!(f, "{}", "jb"),
- &Opcode::JNB => write!(f, "{}", "jnb"),
- &Opcode::JZ => write!(f, "{}", "jz"),
- &Opcode::JNZ => write!(f, "{}", "jnz"),
- &Opcode::JA => write!(f, "{}", "ja"),
- &Opcode::JNA => write!(f, "{}", "jna"),
- &Opcode::JS => write!(f, "{}", "js"),
- &Opcode::JNS => write!(f, "{}", "jns"),
- &Opcode::JP => write!(f, "{}", "jp"),
- &Opcode::JNP => write!(f, "{}", "jnp"),
- &Opcode::JL => write!(f, "{}", "jl"),
- &Opcode::JGE => write!(f, "{}", "jge"),
- &Opcode::JLE => write!(f, "{}", "jle"),
- &Opcode::JG => write!(f, "{}", "jg"),
- &Opcode::CALL => write!(f, "{}", "call"),
- &Opcode::JMP => write!(f, "{}", "jmp"),
- &Opcode::CALLF => write!(f, "{}", "callf"),
- &Opcode::JMPF => write!(f, "{}", "jmpf"),
- &Opcode::SAR => write!(f, "{}", "sar"),
- &Opcode::SAL => write!(f, "{}", "sal"),
- &Opcode::SHR => write!(f, "{}", "shr"),
- &Opcode::SHL => write!(f, "{}", "shl"),
- &Opcode::RCR => write!(f, "{}", "rcr"),
- &Opcode::RCL => write!(f, "{}", "rcl"),
- &Opcode::ROR => write!(f, "{}", "ror"),
- &Opcode::ROL => write!(f, "{}", "rol"),
- &Opcode::CMOVA => write!(f, "{}", "cmova"),
- &Opcode::CMOVB => write!(f, "{}", "cmovb"),
- &Opcode::CMOVG => write!(f, "{}", "cmovg"),
- &Opcode::CMOVGE => write!(f, "{}", "cmovge"),
- &Opcode::CMOVL => write!(f, "{}", "cmovl"),
- &Opcode::CMOVLE => write!(f, "{}", "cmovle"),
- &Opcode::CMOVNA => write!(f, "{}", "cmovna"),
- &Opcode::CMOVNB => write!(f, "{}", "cmovnb"),
- &Opcode::CMOVNO => write!(f, "{}", "cmovno"),
- &Opcode::CMOVNP => write!(f, "{}", "cmovnp"),
- &Opcode::CMOVNS => write!(f, "{}", "cmovns"),
- &Opcode::CMOVNZ => write!(f, "{}", "cmovnz"),
- &Opcode::CMOVO => write!(f, "{}", "cmovo"),
- &Opcode::CMOVP => write!(f, "{}", "cmovp"),
- &Opcode::CMOVS => write!(f, "{}", "cmovs"),
- &Opcode::CMOVZ => write!(f, "{}", "cmovz"),
- &Opcode::NEG => write!(f, "{}", "neg"),
- &Opcode::NOT => write!(f, "{}", "not"),
- &Opcode::MUL => write!(f, "{}", "mul"),
- &Opcode::DIV => write!(f, "{}", "div"),
- &Opcode::IDIV => write!(f, "{}", "idiv"),
- &Opcode::CMPXCHG => write!(f, "{}", "cmpxchg"),
- &Opcode::MOVZX_b => write!(f, "{}", "movzx"),
- &Opcode::MOVZX_w => write!(f, "{}", "movzx"),
- &Opcode::MOVSX => write!(f, "{}", "movsx"),
- &Opcode::SETO => write!(f, "{}", "seto"),
- &Opcode::SETNO => write!(f, "{}", "setno"),
- &Opcode::SETB => write!(f, "{}", "setb"),
- &Opcode::SETAE => write!(f, "{}", "setae"),
- &Opcode::SETZ => write!(f, "{}", "setz"),
- &Opcode::SETNZ => write!(f, "{}", "setnz"),
- &Opcode::SETBE => write!(f, "{}", "setbe"),
- &Opcode::SETA => write!(f, "{}", "seta"),
- &Opcode::SETS => write!(f, "{}", "sets"),
- &Opcode::SETNS => write!(f, "{}", "setns"),
- &Opcode::SETP => write!(f, "{}", "setp"),
- &Opcode::SETNP => write!(f, "{}", "setnp"),
- &Opcode::SETL => write!(f, "{}", "setl"),
- &Opcode::SETGE => write!(f, "{}", "setge"),
- &Opcode::SETLE => write!(f, "{}", "setle"),
- &Opcode::SETG => write!(f, "{}", "setg"),
- &Opcode::Invalid => write!(f, "{}", "invalid")
- }
- }
-}
-
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub enum Opcode {
@@ -566,245 +367,6 @@ impl PrefixRex {
}
}
-fn color_for(opcode: Opcode, colors: &ColorSettings) -> &'static color::Fg<&'static color::Color> {
- match opcode {
- Opcode::DIV |
- Opcode::IDIV |
- Opcode::MUL |
- Opcode::NEG |
- Opcode::NOT |
- Opcode::SAR |
- Opcode::SAL |
- Opcode::SHR |
- Opcode::SHL |
- Opcode::RCR |
- Opcode::RCL |
- Opcode::ROR |
- Opcode::ROL |
- Opcode::INC |
- Opcode::DEC |
- Opcode::SBB |
- Opcode::AND |
- Opcode::XOR |
- Opcode::OR |
- Opcode::LEA |
- Opcode::ADD |
- Opcode::ADC |
- Opcode::SUB |
- Opcode::IMUL |
- Opcode::PUSH |
- Opcode::POP |
- Opcode::NOP |
- Opcode::XCHG |
- Opcode::POPF |
- Opcode::ENTER |
- Opcode::LEAVE |
- Opcode::PUSHF |
- Opcode::WAIT |
- Opcode::CMPS |
- Opcode::SCAS |
- Opcode::TEST |
- Opcode::CMP |
-
- /* Control flow */
- Opcode::HLT |
- Opcode::CALL |
- Opcode::CALLF |
- Opcode::JMP |
- Opcode::JMPF |
- Opcode::INT |
- Opcode::INTO |
- Opcode::IRET |
- Opcode::RETF |
- Opcode::RETURN |
- Opcode::JO |
- Opcode::JNO |
- Opcode::JB |
- Opcode::JNB |
- Opcode::JZ |
- Opcode::JNZ |
- Opcode::JA |
- Opcode::JNA |
- Opcode::JS |
- Opcode::JNS |
- Opcode::JP |
- Opcode::JNP |
- Opcode::JL |
- Opcode::JGE |
- Opcode::JLE |
- Opcode::JG |
-
- /* Data transfer */
- Opcode::MOV |
- Opcode::CBW |
- Opcode::CDW |
- Opcode::LODS |
- Opcode::STOS |
- Opcode::LAHF |
- Opcode::SAHF |
- Opcode::MOVS |
- Opcode::INS |
- Opcode::OUTS |
- Opcode::MOVZX_b |
- Opcode::MOVZX_w |
- Opcode::MOVSX |
- Opcode::CMOVA |
- Opcode::CMOVB |
- Opcode::CMOVG |
- Opcode::CMOVGE |
- Opcode::CMOVL |
- Opcode::CMOVLE |
- Opcode::CMOVNA |
- Opcode::CMOVNB |
- Opcode::CMOVNO |
- Opcode::CMOVNP |
- Opcode::CMOVNS |
- Opcode::CMOVNZ |
- Opcode::CMOVO |
- Opcode::CMOVP |
- Opcode::CMOVS |
- Opcode::CMOVZ |
-
- Opcode::CMPXCHG |
- Opcode::SETO |
- Opcode::SETNO |
- Opcode::SETB |
- Opcode::SETAE |
- Opcode::SETZ |
- Opcode::SETNZ |
- Opcode::SETBE |
- Opcode::SETA |
- Opcode::SETS |
- Opcode::SETNS |
- Opcode::SETP |
- Opcode::SETNP |
- Opcode::SETL |
- Opcode::SETGE |
- Opcode::SETLE |
- Opcode::SETG |
-
- Opcode::Invalid => {
- &color::Fg(&color::Red)
- }
- }
-}
-
-impl fmt::Display for Instruction {
- fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
- self.colorize(None, fmt)
- }
-}
-
-/*
- * Can't implement this as accepting a formatter because rust
- * doesn't let me build one outside println! or write! or whatever.
- *
- * can't write this as an intermediate struct because i refuse to copy
- * all data into the struct, and having a function producing a struct with
- * some lifetimes gets really hairy if it's from a trait - same GAT kind
- * of nonsense as i saw with ContextRead, because someone could hold onto
- * the dang intermediate struct forever.
- *
- * so write to some Write thing i guess. bite me. i really just want to
- * stop thinking about how to support printing instructions...
- */
-impl <T: std::fmt::Write> Colorize<T> for Instruction {
- fn colorize(&self, colors: Option<&ColorSettings>, f: &mut T) -> std::fmt::Result {
- if self.prefixes.lock {
- write!(f, "lock ")?;
- }
- colors.map(|c| { write!(f, "{}{}{}", color_for(self.opcode, c), self.opcode, color::Fg(&color::Reset as &color::Color)) })
- .unwrap_or_else(|| { write!(f, "{}", self.opcode) })?;
- /* For when contextualization is a thing we can do?
- match self.0.opers.as_ref().and_then(|xs| xs[0].as_ref()) {
- Some(s) => { write!(f, " {}", s)?; },
- None => {
- */
- match self.operands[0] {
- Operand::Nothing => {
- return Ok(());
- },
- ref x @ _ => {
- write!(f, " ")?;
- x.colorize(colors, f)?;
- }
- }
- /*
- }
- }*/;
- match self.opcode {
- Opcode::MOVZX_b => {
- /*
- match self.0.opers.as_ref().and_then(|xs| xs[1].as_ref()) {
- Some(s) => { write!(f, ", {}", s) }
- None => {
- */
- match &self.operands[1] {
- &Operand::Nothing => {
- return Ok(());
- },
- x @ &Operand::Register(_) => {
- write!(f, ", ")?;
- x.colorize(colors, f)
- }
- x @ _ => {
- write!(f, ", byte ")?;
- x.colorize(colors, f)
- }
- }
- /*
- }
- }
- */
- },
- Opcode::MOVZX_w => {
- /*
- match self.0.opers.as_ref().and_then(|xs| xs[1].as_ref()) {
- Some(s) => { write!(f, ", {}", s) }
- None => {
- */
- match &self.operands[1] {
- &Operand::Nothing => {
- return Ok(());
- },
- x @ &Operand::Register(_) => {
- write!(f, ", ")?;
- x.colorize(colors, f)
- }
- x @ _ => {
- write!(f, ", word ")?;
- x.colorize(colors, f)
- }
- }
- /*
- }
- }
- */
- },
- _ => {
- /*
- match self.0.opers.as_ref().and_then(|xs| xs[1].as_ref()) {
- Some(s) => { write!(f, ", {}", s) }
- None => {
- */
- match &self.operands[1] {
- &Operand::Nothing => {
- return Ok(());
- },
- x @ _ => {
- write!(f, ", ")?;
- x.colorize(colors, f)
- }
- }
- /*
- }
- }
- */
- }
- }
- }
-}
-
#[allow(non_camel_case_types)]
#[derive(Copy, Clone, Debug)]
pub enum OperandCode {