1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
use std::fmt;

#[derive(Clone, Debug, PartialEq)]
pub enum Op {
    /// ASCII Adjust After Addition
    Aaa,

    /// ASCII Adjust AX Before Division
    Aad,

    /// ASCII Adjust AX After Multiply
    Aam,

    /// ASCII Adjust AL After Subtraction
    Aas,

    Adc8, Adc16, Adc32,
    Add8, Add16, Add32,
    And8, And16, And32,

    /// Adjust RPL Field of Segment Selector
    Arpl,

    /// Check Array Index Against Bounds
    Bound,

    /// Bit Scan Forward
    Bsf,

    /// Bit Test
    Bt,

    Bts,
    CallNear, CallFar,

    /// Convert Byte to Word
    Cbw,

    /// Clear Carry Flag
    Clc,

    /// Clear Direction Flag
    Cld,

    /// Clear Interrupt Flag
    Cli,

    /// Complement Carry Flag
    Cmc,

    Cmp8, Cmp16, Cmp32,
    Cmpsb, Cmpsw,

    /// Convert Word to Doubleword
    Cwd16, Cwde32,

    /// Decimal Adjust AL after Addition
    Daa,

    /// Decimal Adjust AL after Subtraction
    Das,

    Dec8, Dec16, Dec32,
    Div8, Div16, Div32,

    Enter,
    Hlt,

    Idiv8, Idiv16, Idiv32,
    Imul8, Imul16, Imul32,

    /// Input from Port
    In8, In16,

    Inc8, Inc16, Inc32,

    /// Input from Port to String
    Insb, Insw,

    Int,
    Into,
    Iret,

    /// Jump if above (CF=0 and ZF=0).    (alias: jnbe)
    Ja,

    /// Jump if carry (CF=1).    (alias: jb, jnae)
    Jc,

    /// Jump if CX register is 0.
    Jcxz,

    /// Jump if greater (ZF=0 and SF=OF).    (alias: jnle)
    Jg,

    /// Jump if less (SF ≠ OF).    (alias: jnge)
    Jl,

    JmpShort, JmpNear, JmpFar,

    /// Jump if not above (CF=1 or ZF=1).    (alias: jbe)
    Jna,

    /// Jump if not carry (CF=0).    (alias: jae, jnb)
    Jnc,

    /// Jump if not greater (ZF=1 or SF ≠ OF).    (alias: jle)
    Jng,

    /// Jump if not less (SF=OF).    (alias: jge)
    Jnl,

    /// Jump if not overflow (OF=0).
    Jno,

    /// Jump if not sign (SF=0).
    Jns,

    /// Jump if not zero (ZF=0).    (alias: jne)
    Jnz,

    /// Jump if overflow (OF=1).
    Jo,

    /// Jump short if parity even (PF=1)
    Jpe,

    /// Jump short if parity odd (PF=0).
    Jpo,

    /// Jump if sign (SF=1).
    Js,

    /// Jump if zero (ZF ← 1).    (alias: je)
    Jz,

    /// Load Status Flags into AH Register
    Lahf,

    Lds,

    /// Load Effective Address
    Lea16,

    Leave,

    Les,

    Lodsb, Lodsw, Lodsd,

    Loop, Loope, Loopne,

    Mov8, Mov16, Mov32,
    Movsb, Movsw, Movsd,

    /// Move with Sign-Extension
    Movsx16, Movsx32,

    /// Move with Zero-Extend
    Movzx16, Movzx32,

    Mul8, Mul16, Mul32,
    Neg8, Neg16, Neg32,
    Nop,
    Not8, Not16, Not32,
    Or8, Or16, Or32,
    Out8, Out16,
    Outsb, Outsw,
    Pop16, Pop32,

    /// Pop DI, SI, BP, BX, DX, CX, and AX.
    Popa16,

    /// Pop EDI, ESI, EBP, EBX, EDX, ECX, and EAX.
    Popad32,

    /// Pop top of stack into lower 16 bits of EFLAGS.
    Popf,

    Push16, Push32,

    /// Push AX, CX, DX, BX, original SP, BP, SI, and DI.
    Pusha16,

    /// Push EAX, ECX, EDX, EBX, original ESP, EBP, ESI, and EDI.
    Pushad32,

    /// push 16 bit FLAGS register onto stack
    Pushf,

    Rcl8, Rcl16, Rcl32,
    Rcr8, Rcr16, Rcr32,

    Retn, Retf, RetImm16,

    Rol8, Rol16, Rol32,
    Ror8, Ror16, Ror32,

    /// Store AH into Flags
    Sahf,

    /// "salc", or "setalc" is a undocumented Intel instruction
    /// http://ref.x86asm.net/coder32.html#gen_note_u_SALC_D6
    /// http://www.rcollins.org/secrets/opcodes/SALC.html
    /// used by dos-software-decoding/demo-256/luminous/luminous.com
    Salc,

    Sar8, Sar16, Sar32,

    /// Integer Subtraction with Borrow
    Sbb8, Sbb16, Sbb32,

    Scasb, Scasw,

    /// setc: Set byte if carry (CF=1).
    /// alias setb: Set byte if below (CF=1).
    Setc,

    /// setg: Set byte if greater (ZF=0 and SF=OF).
    /// alias setnle: Set byte if not less or equal (ZF=0 and SF=OF).
    Setg,

    /// setnz: Set byte if not zero (ZF=0).
    /// alias setne: Set byte if not equal (ZF=0).
    Setnz,

    Shl8, Shl16, Shl32,

    /// Double Precision Shift Left
    Shld,

    Shr8, Shr16, Shr32,

    /// Double Precision Shift Right
    Shrd,

    Sldt,

    // Set Carry Flag
    Stc,

    /// Set Direction Flag
    Std,

    /// Set Interrupt Flag
    Sti,

    Stosb, Stosw, Stosd,
    Sub8, Sub16, Sub32,
    Test8, Test16, Test32,

    /// Exchange Register/Memory with Register
    Xchg8, Xchg16, Xchg32,

    Xlatb,

    Xor8, Xor16, Xor32,

    Uninitialized,
    Invalid(Vec<u8>, Invalid),
}

impl fmt::Display for Op {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Op::Invalid(bytes, _) => {
                let mut x = Vec::new();
                for b in bytes {
                    x.push(format!("{:02X}", b));
                }
                write!(f, "INVALID {}", x.join(", "))
            }
            _ => write!(f, "{:?}", self),
        }
    }
}

impl Op {
    pub fn is_valid(&self) -> bool {
        match *self {
            Op::Uninitialized | Op::Invalid(_, _) => false,
            _ => true,
        }
    }

    /// used by encoder
    pub fn f6_index(&self) -> u8 {
        match *self {
            Op::Test8 => 0,
            Op::Not8  => 2,
            Op::Neg8  => 3,
            Op::Mul8  => 4,
            Op::Imul8 => 5,
            Op::Div8  => 6,
            Op::Idiv8 => 7,
            _ => panic!("f6_index {:?}", self),
        }
    }

    /// used by encoder
    pub fn feff_index(&self) -> u8 {
        match *self {
            Op::Inc8 | Op::Inc16 | Op::Inc32 => 0,
            Op::Dec8 | Op::Dec16 | Op::Dec32 => 1,
            Op::CallNear => 2,
            // 3 => call far
            Op::JmpNear => 4,
            // 5 => jmp far
            Op::Push16 => 6,
            _ => panic!("feff_index {:?}", self),
        }
    }
}

/// the class of instruction decode error that occured
#[derive(Clone, Debug, PartialEq)]
pub enum Invalid {
    /// a reg value was unhandled / invalid
    Reg(u8),

    /// unimplemented / invalid CPU instr
    Op,

    /// unimplemented / invalid FPU instr
    FPUOp,
}