1use std::fmt;
2
3use crate::cpu::Segment;
4use crate::cpu::Op;
5use crate::cpu::{Parameter, ParameterSet};
6use crate::cpu::{OperandSize, AddressSize};
7use crate::hex::hex_bytes;
8use crate::string::right_pad;
9
10#[derive(Clone, Debug, PartialEq)]
11pub struct Instruction {
12 pub command: Op,
13 pub params: ParameterSet,
14 pub length: u8,
15 pub segment_prefix: Segment, pub repeat: RepeatMode, pub lock: bool, pub op_size: OperandSize, pub address_size: AddressSize, }
22
23impl fmt::Display for Instruction {
24 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
25 let instr = self.describe_instruction();
26 if self.segment_prefix == Segment::Default || self.hide_segment_prefix() {
27 write!(f, "{}", instr)
28 } else {
29 write!(f, "{} {}", self.segment_prefix.as_str(), instr)
30 }
31 }
32}
33
34impl Instruction {
35 pub fn new(op: Op) -> Self {
36 Instruction::new3(op, Parameter::None, Parameter::None, Parameter::None)
37 }
38
39 pub fn new1(op: Op, dst: Parameter) -> Self {
40 Instruction::new3(op, dst, Parameter::None, Parameter::None)
41 }
42
43 pub fn new2(op: Op, dst: Parameter, src: Parameter) -> Self {
44 Instruction::new3(op, dst, src, Parameter::None)
45 }
46
47 pub fn new3(op: Op, dst: Parameter, src: Parameter, src2: Parameter) -> Self {
48 let op_size = Instruction::op_size_from_op(&op);
49 Instruction {
50 command: op,
51 segment_prefix: Segment::Default,
52 params: ParameterSet {dst, src, src2},
53 lock: false,
54 repeat: RepeatMode::None,
55 op_size,
56 address_size: AddressSize::_16bit,
57 length: 0,
58 }
59 }
60
61 pub fn is_ret(&self) -> bool {
63 self.command == Op::Retn || self.command == Op::Retf || self.command == Op::RetImm16
64 }
65
66 pub fn is_loop(&self) -> bool {
68 self.command == Op::Loop || self.command == Op::Loope || self.command == Op::Loopne
69 }
70
71 pub fn is_unconditional_jmp(&self) -> bool {
73 self.command == Op::JmpShort || self.command == Op::JmpNear || self.command == Op::JmpFar
74 }
75
76 fn op_size_from_op(op: &Op) -> OperandSize {
77 match *op {
78 Op::Mov32 | Op::Inc32 | Op::Dec32 => OperandSize::_32bit,
79 _ => OperandSize::_16bit,
80 }
81 }
82
83 fn hide_segment_prefix(&self) -> bool {
84 self.command == Op::Add8 || self.command == Op::Add16 || self.command == Op::Add32 ||
85 self.command == Op::Adc8 || self.command == Op::Adc16 || self.command == Op::Adc32 ||
86 self.command == Op::Sub8 || self.command == Op::Sub16 || self.command == Op::Sub32 ||
87 self.command == Op::Sbb8 || self.command == Op::Sbb16 || self.command == Op::Sbb32 ||
88 self.command == Op::Inc8 || self.command == Op::Inc16 || self.command == Op::Inc32 ||
89 self.command == Op::Dec8 || self.command == Op::Dec16 || self.command == Op::Dec32 ||
90 self.command == Op::Mul8 || self.command == Op::Mul16 || self.command == Op::Mul32 ||
91 self.command == Op::Div8 || self.command == Op::Div16 || self.command == Op::Div32 ||
92 self.command == Op::Imul8 || self.command == Op::Imul16 || self.command == Op::Imul32 ||
93 self.command == Op::Idiv8 || self.command == Op::Idiv16 || self.command == Op::Idiv32 ||
94 self.command == Op::And8 || self.command == Op::And16 || self.command == Op::And32 ||
95 self.command == Op::Or8 || self.command == Op::Or16 || self.command == Op::Or32 ||
96 self.command == Op::Xor8 || self.command == Op::Xor16 || self.command == Op::Xor32 ||
97 self.command == Op::Cmp8 || self.command == Op::Cmp16 || self.command == Op::Cmp32 ||
98 self.command == Op::Test8 || self.command == Op::Test16 || self.command == Op::Test32 ||
99 self.command == Op::Xchg8 || self.command == Op::Xchg16 || self.command == Op::Xchg32 ||
100 self.command == Op::Mov8 || self.command == Op::Mov16 || self.command == Op::Mov32 ||
101 self.command == Op::Movsx16 || self.command == Op::Movsx32 || self.command == Op::Movzx16
102 }
103
104 fn describe_instruction(&self) -> String {
105 let op_space = 9;
106 let mut prefix = self.repeat.as_str().to_owned();
107 if prefix != "" {
108 prefix = right_pad(&prefix, op_space);
109 }
110
111 match self.params.dst {
112 Parameter::None => format!("{}{}", prefix, self.command),
113 _ => {
114 let cmd = right_pad(&format!("{}{}", prefix, self.command), op_space);
115
116 match self.params.src2 {
117 Parameter::None => match self.params.src {
118 Parameter::None => format!("{}{}", cmd, self.params.dst),
119 _ => format!("{}{}, {}", cmd, self.params.dst, self.params.src),
120 },
121 _ => format!(
122 "{}{}, {}, {}",
123 cmd,
124 self.params.dst,
125 self.params.src,
126 self.params.src2
127 ),
128 }
129 }
130 }
131 }
132}
133
134#[derive(Debug, PartialEq)]
135pub struct InstructionInfo {
136 pub segment: usize,
137 pub offset: usize,
138 pub bytes: Vec<u8>,
139 pub instruction: Instruction,
140}
141
142impl fmt::Display for InstructionInfo {
143 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
144 write!(
145 f,
146 "[{:04X}:{:04X}] {} {}",
147 self.segment,
148 self.offset,
149 right_pad(&hex_bytes(&self.bytes), 16),
150 format!("{}", self.instruction),
151 )
152 }
153}
154
155#[derive(Copy, Clone, Debug, PartialEq)]
156pub enum RepeatMode {
157 None,
158 Rep,
159 Repe, Repne, }
162
163impl RepeatMode {
164 fn as_str(&self) -> &str {
165 match *self {
166 RepeatMode::None => "",
167 RepeatMode::Rep => "Rep",
168 RepeatMode::Repe => "Repe",
169 RepeatMode::Repne => "Repne",
170 }
171 }
172}
173
174#[derive(Debug)]
175pub struct ModRegRm {
176 pub md: u8, pub reg: u8,
178 pub rm: u8,
179}
180
181impl ModRegRm {
182 pub fn u8(&self) -> u8 {
183 (self.md << 6) | (self.reg << 3) | self.rm }
187
188 pub fn rm_reg(rm: u8, reg: u8) -> u8 {
189 ModRegRm{md: 3, rm, reg}.u8()
192 }
193}