diff options
author | iximeow <me@iximeow.net> | 2019-03-20 14:55:53 -0700 |
---|---|---|
committer | iximeow <me@iximeow.net> | 2020-01-12 16:10:13 -0800 |
commit | 0adc1ba0b88e4afd55bb080bb8134a56f302ead7 (patch) | |
tree | 387e6e9d3a0df3acd84c2a8cc5cf4a3dbed9528f | |
parent | 9e5fd6103b8213376b83b2bc427fc15a1213ba5a (diff) |
factor out display for x86, implement colorization... a bit
-rw-r--r-- | src/display.rs | 471 | ||||
-rw-r--r-- | src/lib.rs | 444 |
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) + } + } + /* + } + } + */ + } + } + } +} @@ -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 { |