1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <assert.h>
6 #include <stdarg.h>
7 #include <stdio.h>
8
9 #if V8_TARGET_ARCH_IA32
10
11 #include "src/base/compiler-specific.h"
12 #include "src/base/strings.h"
13 #include "src/codegen/ia32/fma-instr.h"
14 #include "src/codegen/ia32/sse-instr.h"
15 #include "src/diagnostics/disasm.h"
16
17 namespace disasm {
18
19 enum OperandOrder { UNSET_OP_ORDER = 0, REG_OPER_OP_ORDER, OPER_REG_OP_ORDER };
20
21 //------------------------------------------------------------------
22 // Tables
23 //------------------------------------------------------------------
24 struct ByteMnemonic {
25 int b; // -1 terminates, otherwise must be in range (0..255)
26 const char* mnem;
27 OperandOrder op_order_;
28 };
29
30 static const ByteMnemonic two_operands_instr[] = {
31 {0x01, "add", OPER_REG_OP_ORDER}, {0x03, "add", REG_OPER_OP_ORDER},
32 {0x09, "or", OPER_REG_OP_ORDER}, {0x0B, "or", REG_OPER_OP_ORDER},
33 {0x13, "adc", REG_OPER_OP_ORDER}, {0x1B, "sbb", REG_OPER_OP_ORDER},
34 {0x21, "and", OPER_REG_OP_ORDER}, {0x23, "and", REG_OPER_OP_ORDER},
35 {0x29, "sub", OPER_REG_OP_ORDER}, {0x2A, "subb", REG_OPER_OP_ORDER},
36 {0x2B, "sub", REG_OPER_OP_ORDER}, {0x31, "xor", OPER_REG_OP_ORDER},
37 {0x33, "xor", REG_OPER_OP_ORDER}, {0x38, "cmpb", OPER_REG_OP_ORDER},
38 {0x39, "cmp", OPER_REG_OP_ORDER}, {0x3A, "cmpb", REG_OPER_OP_ORDER},
39 {0x3B, "cmp", REG_OPER_OP_ORDER}, {0x84, "test_b", REG_OPER_OP_ORDER},
40 {0x85, "test", REG_OPER_OP_ORDER}, {0x86, "xchg_b", REG_OPER_OP_ORDER},
41 {0x87, "xchg", REG_OPER_OP_ORDER}, {0x8A, "mov_b", REG_OPER_OP_ORDER},
42 {0x8B, "mov", REG_OPER_OP_ORDER}, {0x8D, "lea", REG_OPER_OP_ORDER},
43 {-1, "", UNSET_OP_ORDER}};
44
45 static const ByteMnemonic zero_operands_instr[] = {
46 {0xC3, "ret", UNSET_OP_ORDER}, {0xC9, "leave", UNSET_OP_ORDER},
47 {0x90, "nop", UNSET_OP_ORDER}, {0xF4, "hlt", UNSET_OP_ORDER},
48 {0xCC, "int3", UNSET_OP_ORDER}, {0x60, "pushad", UNSET_OP_ORDER},
49 {0x61, "popad", UNSET_OP_ORDER}, {0x9C, "pushfd", UNSET_OP_ORDER},
50 {0x9D, "popfd", UNSET_OP_ORDER}, {0x9E, "sahf", UNSET_OP_ORDER},
51 {0x99, "cdq", UNSET_OP_ORDER}, {0x9B, "fwait", UNSET_OP_ORDER},
52 {0xFC, "cld", UNSET_OP_ORDER}, {0xAB, "stos", UNSET_OP_ORDER},
53 {-1, "", UNSET_OP_ORDER}};
54
55 static const ByteMnemonic call_jump_instr[] = {{0xE8, "call", UNSET_OP_ORDER},
56 {0xE9, "jmp", UNSET_OP_ORDER},
57 {-1, "", UNSET_OP_ORDER}};
58
59 static const ByteMnemonic short_immediate_instr[] = {
60 {0x05, "add", UNSET_OP_ORDER}, {0x0D, "or", UNSET_OP_ORDER},
61 {0x15, "adc", UNSET_OP_ORDER}, {0x25, "and", UNSET_OP_ORDER},
62 {0x2D, "sub", UNSET_OP_ORDER}, {0x35, "xor", UNSET_OP_ORDER},
63 {0x3D, "cmp", UNSET_OP_ORDER}, {-1, "", UNSET_OP_ORDER}};
64
65 // Generally we don't want to generate these because they are subject to partial
66 // register stalls. They are included for completeness and because the cmp
67 // variant is used by the RecordWrite stub. Because it does not update the
68 // register it is not subject to partial register stalls.
69 static ByteMnemonic byte_immediate_instr[] = {{0x0C, "or", UNSET_OP_ORDER},
70 {0x24, "and", UNSET_OP_ORDER},
71 {0x34, "xor", UNSET_OP_ORDER},
72 {0x3C, "cmp", UNSET_OP_ORDER},
73 {-1, "", UNSET_OP_ORDER}};
74
75 static const char* const jump_conditional_mnem[] = {
76 /*0*/ "jo", "jno", "jc", "jnc",
77 /*4*/ "jz", "jnz", "jna", "ja",
78 /*8*/ "js", "jns", "jpe", "jpo",
79 /*12*/ "jl", "jnl", "jng", "jg"};
80
81 static const char* const set_conditional_mnem[] = {
82 /*0*/ "seto", "setno", "setc", "setnc",
83 /*4*/ "setz", "setnz", "setna", "seta",
84 /*8*/ "sets", "setns", "setpe", "setpo",
85 /*12*/ "setl", "setnl", "setng", "setg"};
86
87 static const char* const conditional_move_mnem[] = {
88 /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc",
89 /*4*/ "cmovz", "cmovnz", "cmovna", "cmova",
90 /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo",
91 /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg"};
92
93 static const char* const cmp_pseudo_op[16] = {
94 "eq", "lt", "le", "unord", "neq", "nlt", "nle", "ord",
95 "eq_uq", "nge", "ngt", "false", "neq_oq", "ge", "gt", "true"};
96
97 enum InstructionType {
98 NO_INSTR,
99 ZERO_OPERANDS_INSTR,
100 TWO_OPERANDS_INSTR,
101 JUMP_CONDITIONAL_SHORT_INSTR,
102 REGISTER_INSTR,
103 MOVE_REG_INSTR,
104 CALL_JUMP_INSTR,
105 SHORT_IMMEDIATE_INSTR,
106 BYTE_IMMEDIATE_INSTR
107 };
108
109 struct InstructionDesc {
110 const char* mnem;
111 InstructionType type;
112 OperandOrder op_order_;
113 };
114
115 class InstructionTable {
116 public:
117 InstructionTable();
Get(byte x) const118 const InstructionDesc& Get(byte x) const { return instructions_[x]; }
get_instance()119 static InstructionTable* get_instance() {
120 static InstructionTable table;
121 return &table;
122 }
123
124 private:
125 InstructionDesc instructions_[256];
126 void Clear();
127 void Init();
128 void CopyTable(const ByteMnemonic bm[], InstructionType type);
129 void SetTableRange(InstructionType type, byte start, byte end,
130 const char* mnem);
131 void AddJumpConditionalShort();
132 };
133
InstructionTable()134 InstructionTable::InstructionTable() {
135 Clear();
136 Init();
137 }
138
Clear()139 void InstructionTable::Clear() {
140 for (int i = 0; i < 256; i++) {
141 instructions_[i].mnem = "";
142 instructions_[i].type = NO_INSTR;
143 instructions_[i].op_order_ = UNSET_OP_ORDER;
144 }
145 }
146
Init()147 void InstructionTable::Init() {
148 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
149 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
150 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
151 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
152 CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR);
153 AddJumpConditionalShort();
154 SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
155 SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
156 SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
157 SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
158 SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop.
159 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
160 }
161
CopyTable(const ByteMnemonic bm[],InstructionType type)162 void InstructionTable::CopyTable(const ByteMnemonic bm[],
163 InstructionType type) {
164 for (int i = 0; bm[i].b >= 0; i++) {
165 InstructionDesc* id = &instructions_[bm[i].b];
166 id->mnem = bm[i].mnem;
167 id->op_order_ = bm[i].op_order_;
168 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
169 id->type = type;
170 }
171 }
172
SetTableRange(InstructionType type,byte start,byte end,const char * mnem)173 void InstructionTable::SetTableRange(InstructionType type, byte start, byte end,
174 const char* mnem) {
175 for (byte b = start; b <= end; b++) {
176 InstructionDesc* id = &instructions_[b];
177 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
178 id->mnem = mnem;
179 id->type = type;
180 }
181 }
182
AddJumpConditionalShort()183 void InstructionTable::AddJumpConditionalShort() {
184 for (byte b = 0x70; b <= 0x7F; b++) {
185 InstructionDesc* id = &instructions_[b];
186 DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
187 id->mnem = jump_conditional_mnem[b & 0x0F];
188 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
189 }
190 }
191
192 namespace {
Imm8(const uint8_t * data)193 int8_t Imm8(const uint8_t* data) {
194 return *reinterpret_cast<const int8_t*>(data);
195 }
Imm8_U(const uint8_t * data)196 uint8_t Imm8_U(const uint8_t* data) {
197 return *reinterpret_cast<const uint8_t*>(data);
198 }
Imm16(const uint8_t * data)199 int16_t Imm16(const uint8_t* data) {
200 return *reinterpret_cast<const int16_t*>(data);
201 }
Imm16_U(const uint8_t * data)202 uint16_t Imm16_U(const uint8_t* data) {
203 return *reinterpret_cast<const uint16_t*>(data);
204 }
Imm32(const uint8_t * data)205 int32_t Imm32(const uint8_t* data) {
206 return *reinterpret_cast<const int32_t*>(data);
207 }
208 } // namespace
209
210 // The IA32 disassembler implementation.
211 class DisassemblerIA32 {
212 public:
DisassemblerIA32(const NameConverter & converter,Disassembler::UnimplementedOpcodeAction unimplemented_opcode_action)213 DisassemblerIA32(
214 const NameConverter& converter,
215 Disassembler::UnimplementedOpcodeAction unimplemented_opcode_action)
216 : converter_(converter),
217 vex_byte0_(0),
218 vex_byte1_(0),
219 vex_byte2_(0),
220 instruction_table_(InstructionTable::get_instance()),
221 tmp_buffer_pos_(0),
222 unimplemented_opcode_action_(unimplemented_opcode_action) {
223 tmp_buffer_[0] = '\0';
224 }
225
~DisassemblerIA32()226 virtual ~DisassemblerIA32() {}
227
228 // Writes one disassembled instruction into 'buffer' (0-terminated).
229 // Returns the length of the disassembled machine instruction in bytes.
230 int InstructionDecode(v8::base::Vector<char> buffer, byte* instruction);
231
232 private:
233 const NameConverter& converter_;
234 byte vex_byte0_; // 0xC4 or 0xC5
235 byte vex_byte1_;
236 byte vex_byte2_; // only for 3 bytes vex prefix
237 InstructionTable* instruction_table_;
238 v8::base::EmbeddedVector<char, 128> tmp_buffer_;
239 unsigned int tmp_buffer_pos_;
240 Disassembler::UnimplementedOpcodeAction unimplemented_opcode_action_;
241
242 enum {
243 eax = 0,
244 ecx = 1,
245 edx = 2,
246 ebx = 3,
247 esp = 4,
248 ebp = 5,
249 esi = 6,
250 edi = 7
251 };
252
253 enum ShiftOpcodeExtension {
254 kROL = 0,
255 kROR = 1,
256 kRCL = 2,
257 kRCR = 3,
258 kSHL = 4,
259 KSHR = 5,
260 kSAR = 7
261 };
262
vex_128()263 bool vex_128() {
264 DCHECK(vex_byte0_ == 0xC4 || vex_byte0_ == 0xC5);
265 byte checked = vex_byte0_ == 0xC4 ? vex_byte2_ : vex_byte1_;
266 return (checked & 4) == 0;
267 }
268
vex_none()269 bool vex_none() {
270 DCHECK(vex_byte0_ == 0xC4 || vex_byte0_ == 0xC5);
271 byte checked = vex_byte0_ == 0xC4 ? vex_byte2_ : vex_byte1_;
272 return (checked & 3) == 0;
273 }
274
vex_66()275 bool vex_66() {
276 DCHECK(vex_byte0_ == 0xC4 || vex_byte0_ == 0xC5);
277 byte checked = vex_byte0_ == 0xC4 ? vex_byte2_ : vex_byte1_;
278 return (checked & 3) == 1;
279 }
280
vex_f3()281 bool vex_f3() {
282 DCHECK(vex_byte0_ == 0xC4 || vex_byte0_ == 0xC5);
283 byte checked = vex_byte0_ == 0xC4 ? vex_byte2_ : vex_byte1_;
284 return (checked & 3) == 2;
285 }
286
vex_f2()287 bool vex_f2() {
288 DCHECK(vex_byte0_ == 0xC4 || vex_byte0_ == 0xC5);
289 byte checked = vex_byte0_ == 0xC4 ? vex_byte2_ : vex_byte1_;
290 return (checked & 3) == 3;
291 }
292
vex_w()293 bool vex_w() {
294 if (vex_byte0_ == 0xC5) return false;
295 return (vex_byte2_ & 0x80) != 0;
296 }
297
vex_0f()298 bool vex_0f() {
299 if (vex_byte0_ == 0xC5) return true;
300 return (vex_byte1_ & 3) == 1;
301 }
302
vex_0f38()303 bool vex_0f38() {
304 if (vex_byte0_ == 0xC5) return false;
305 return (vex_byte1_ & 3) == 2;
306 }
307
vex_0f3a()308 bool vex_0f3a() {
309 if (vex_byte0_ == 0xC5) return false;
310 return (vex_byte1_ & 3) == 3;
311 }
312
vex_vreg()313 int vex_vreg() {
314 DCHECK(vex_byte0_ == 0xC4 || vex_byte0_ == 0xC5);
315 byte checked = vex_byte0_ == 0xC4 ? vex_byte2_ : vex_byte1_;
316 return ~(checked >> 3) & 0xF;
317 }
318
float_size_code()319 char float_size_code() { return "sd"[vex_w()]; }
320
NameOfCPURegister(int reg) const321 const char* NameOfCPURegister(int reg) const {
322 return converter_.NameOfCPURegister(reg);
323 }
324
NameOfByteCPURegister(int reg) const325 const char* NameOfByteCPURegister(int reg) const {
326 return converter_.NameOfByteCPURegister(reg);
327 }
328
NameOfXMMRegister(int reg) const329 const char* NameOfXMMRegister(int reg) const {
330 return converter_.NameOfXMMRegister(reg);
331 }
332
NameOfAddress(byte * addr) const333 const char* NameOfAddress(byte* addr) const {
334 return converter_.NameOfAddress(addr);
335 }
336
337 // Disassembler helper functions.
get_modrm(byte data,int * mod,int * regop,int * rm)338 static void get_modrm(byte data, int* mod, int* regop, int* rm) {
339 *mod = (data >> 6) & 3;
340 *regop = (data & 0x38) >> 3;
341 *rm = data & 7;
342 }
343
get_sib(byte data,int * scale,int * index,int * base)344 static void get_sib(byte data, int* scale, int* index, int* base) {
345 *scale = (data >> 6) & 3;
346 *index = (data >> 3) & 7;
347 *base = data & 7;
348 }
349
350 using RegisterNameMapping = const char* (DisassemblerIA32::*)(int reg) const;
351
352 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
353 int PrintRightOperand(byte* modrmp);
354 int PrintRightByteOperand(byte* modrmp);
355 int PrintRightXMMOperand(byte* modrmp);
356 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
357 int PrintImmediateOp(byte* data);
358 int F7Instruction(byte* data);
359 int D1D3C1Instruction(byte* data);
360 int JumpShort(byte* data);
361 int JumpConditional(byte* data, const char* comment);
362 int JumpConditionalShort(byte* data, const char* comment);
363 int SetCC(byte* data);
364 int CMov(byte* data);
365 int FPUInstruction(byte* data);
366 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
367 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
368 int AVXInstruction(byte* data);
369 PRINTF_FORMAT(2, 3) void AppendToBuffer(const char* format, ...);
370
UnimplementedInstruction()371 void UnimplementedInstruction() {
372 if (unimplemented_opcode_action_ ==
373 Disassembler::kAbortOnUnimplementedOpcode) {
374 FATAL("Unimplemented instruction in disassembler");
375 } else {
376 AppendToBuffer("'Unimplemented instruction'");
377 }
378 }
379 };
380
AppendToBuffer(const char * format,...)381 void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
382 v8::base::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
383 va_list args;
384 va_start(args, format);
385 int result = v8::base::VSNPrintF(buf, format, args);
386 va_end(args);
387 tmp_buffer_pos_ += result;
388 }
389
PrintRightOperandHelper(byte * modrmp,RegisterNameMapping direct_register_name)390 int DisassemblerIA32::PrintRightOperandHelper(
391 byte* modrmp, RegisterNameMapping direct_register_name) {
392 int mod, regop, rm;
393 get_modrm(*modrmp, &mod, ®op, &rm);
394 RegisterNameMapping register_name =
395 (mod == 3) ? direct_register_name : &DisassemblerIA32::NameOfCPURegister;
396 switch (mod) {
397 case 0:
398 if (rm == ebp) {
399 AppendToBuffer("[0x%x]", Imm32(modrmp + 1));
400 return 5;
401 } else if (rm == esp) {
402 byte sib = *(modrmp + 1);
403 int scale, index, base;
404 get_sib(sib, &scale, &index, &base);
405 if (index == esp && base == esp && scale == 0 /*times_1*/) {
406 AppendToBuffer("[%s]", (this->*register_name)(rm));
407 return 2;
408 } else if (base == ebp) {
409 int32_t disp = Imm32(modrmp + 2);
410 AppendToBuffer("[%s*%d%s0x%x]", (this->*register_name)(index),
411 1 << scale, disp < 0 ? "-" : "+",
412 disp < 0 ? -disp : disp);
413 return 6;
414 } else if (index != esp && base != ebp) {
415 // [base+index*scale]
416 AppendToBuffer("[%s+%s*%d]", (this->*register_name)(base),
417 (this->*register_name)(index), 1 << scale);
418 return 2;
419 } else {
420 UnimplementedInstruction();
421 return 1;
422 }
423 }
424 AppendToBuffer("[%s]", (this->*register_name)(rm));
425 return 1;
426 case 1: // fall through
427 case 2: {
428 if (rm == esp) {
429 byte sib = *(modrmp + 1);
430 int scale, index, base;
431 get_sib(sib, &scale, &index, &base);
432 int disp = mod == 2 ? Imm32(modrmp + 2) : Imm8(modrmp + 2);
433 if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
434 AppendToBuffer("[%s%s0x%x]", (this->*register_name)(rm),
435 disp < 0 ? "-" : "+", disp < 0 ? -disp : disp);
436 } else {
437 AppendToBuffer("[%s+%s*%d%s0x%x]", (this->*register_name)(base),
438 (this->*register_name)(index), 1 << scale,
439 disp < 0 ? "-" : "+", disp < 0 ? -disp : disp);
440 }
441 return mod == 2 ? 6 : 3;
442 }
443 // No sib.
444 int disp = mod == 2 ? Imm32(modrmp + 1) : Imm8(modrmp + 1);
445 AppendToBuffer("[%s%s0x%x]", (this->*register_name)(rm),
446 disp < 0 ? "-" : "+", disp < 0 ? -disp : disp);
447 return mod == 2 ? 5 : 2;
448 }
449 case 3:
450 AppendToBuffer("%s", (this->*register_name)(rm));
451 return 1;
452 default:
453 UnimplementedInstruction();
454 return 1;
455 }
456 UNREACHABLE();
457 }
458
PrintRightOperand(byte * modrmp)459 int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
460 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
461 }
462
PrintRightByteOperand(byte * modrmp)463 int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
464 return PrintRightOperandHelper(modrmp,
465 &DisassemblerIA32::NameOfByteCPURegister);
466 }
467
PrintRightXMMOperand(byte * modrmp)468 int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
469 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfXMMRegister);
470 }
471
472 // Returns number of bytes used including the current *data.
473 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
PrintOperands(const char * mnem,OperandOrder op_order,byte * data)474 int DisassemblerIA32::PrintOperands(const char* mnem, OperandOrder op_order,
475 byte* data) {
476 byte modrm = *data;
477 int mod, regop, rm;
478 get_modrm(modrm, &mod, ®op, &rm);
479 int advance = 0;
480 switch (op_order) {
481 case REG_OPER_OP_ORDER: {
482 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
483 advance = PrintRightOperand(data);
484 break;
485 }
486 case OPER_REG_OP_ORDER: {
487 AppendToBuffer("%s ", mnem);
488 advance = PrintRightOperand(data);
489 AppendToBuffer(",%s", NameOfCPURegister(regop));
490 break;
491 }
492 default:
493 UNREACHABLE();
494 }
495 return advance;
496 }
497
498 // Returns number of bytes used by machine instruction, including *data byte.
499 // Writes immediate instructions to 'tmp_buffer_'.
PrintImmediateOp(byte * data)500 int DisassemblerIA32::PrintImmediateOp(byte* data) {
501 bool sign_extension_bit = (*data & 0x02) != 0;
502 byte modrm = *(data + 1);
503 int mod, regop, rm;
504 get_modrm(modrm, &mod, ®op, &rm);
505 const char* mnem = "Imm???";
506 switch (regop) {
507 case 0:
508 mnem = "add";
509 break;
510 case 1:
511 mnem = "or";
512 break;
513 case 2:
514 mnem = "adc";
515 break;
516 case 4:
517 mnem = "and";
518 break;
519 case 5:
520 mnem = "sub";
521 break;
522 case 6:
523 mnem = "xor";
524 break;
525 case 7:
526 mnem = "cmp";
527 break;
528 default:
529 UnimplementedInstruction();
530 }
531 AppendToBuffer("%s ", mnem);
532 int count = PrintRightOperand(data + 1);
533 if (sign_extension_bit) {
534 AppendToBuffer(",0x%x", *(data + 1 + count));
535 return 1 + count + 1 /*int8*/;
536 } else {
537 AppendToBuffer(",0x%x", Imm32(data + 1 + count));
538 return 1 + count + 4 /*int32_t*/;
539 }
540 }
541
542 // Returns number of bytes used, including *data.
F7Instruction(byte * data)543 int DisassemblerIA32::F7Instruction(byte* data) {
544 DCHECK_EQ(0xF7, *data);
545 byte modrm = *++data;
546 int mod, regop, rm;
547 get_modrm(modrm, &mod, ®op, &rm);
548 const char* mnem = nullptr;
549 switch (regop) {
550 case 0:
551 mnem = "test";
552 break;
553 case 2:
554 mnem = "not";
555 break;
556 case 3:
557 mnem = "neg";
558 break;
559 case 4:
560 mnem = "mul";
561 break;
562 case 5:
563 mnem = "imul";
564 break;
565 case 6:
566 mnem = "div";
567 break;
568 case 7:
569 mnem = "idiv";
570 break;
571 default:
572 UnimplementedInstruction();
573 }
574 AppendToBuffer("%s ", mnem);
575 int count = PrintRightOperand(data);
576 if (regop == 0) {
577 AppendToBuffer(",0x%x", Imm32(data + count));
578 count += 4;
579 }
580 return 1 + count;
581 }
582
D1D3C1Instruction(byte * data)583 int DisassemblerIA32::D1D3C1Instruction(byte* data) {
584 byte op = *data;
585 DCHECK(op == 0xD1 || op == 0xD3 || op == 0xC1);
586 byte modrm = *++data;
587 int mod, regop, rm;
588 get_modrm(modrm, &mod, ®op, &rm);
589 int imm8 = -1;
590 const char* mnem = nullptr;
591 switch (regop) {
592 case kROL:
593 mnem = "rol";
594 break;
595 case kROR:
596 mnem = "ror";
597 break;
598 case kRCL:
599 mnem = "rcl";
600 break;
601 case kRCR:
602 mnem = "rcr";
603 break;
604 case kSHL:
605 mnem = "shl";
606 break;
607 case KSHR:
608 mnem = "shr";
609 break;
610 case kSAR:
611 mnem = "sar";
612 break;
613 default:
614 UnimplementedInstruction();
615 }
616 AppendToBuffer("%s ", mnem);
617 int count = PrintRightOperand(data);
618 if (op == 0xD1) {
619 imm8 = 1;
620 } else if (op == 0xC1) {
621 imm8 = *(data + 1);
622 count++;
623 } else if (op == 0xD3) {
624 // Shift/rotate by cl.
625 }
626 if (imm8 >= 0) {
627 AppendToBuffer(",%d", imm8);
628 } else {
629 AppendToBuffer(",cl");
630 }
631 return 1 + count;
632 }
633
634 // Returns number of bytes used, including *data.
JumpShort(byte * data)635 int DisassemblerIA32::JumpShort(byte* data) {
636 DCHECK_EQ(0xEB, *data);
637 byte b = *(data + 1);
638 byte* dest = data + static_cast<int8_t>(b) + 2;
639 AppendToBuffer("jmp %s", NameOfAddress(dest));
640 return 2;
641 }
642
643 // Returns number of bytes used, including *data.
JumpConditional(byte * data,const char * comment)644 int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
645 DCHECK_EQ(0x0F, *data);
646 byte cond = *(data + 1) & 0x0F;
647 byte* dest = data + Imm32(data + 2) + 6;
648 const char* mnem = jump_conditional_mnem[cond];
649 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
650 if (comment != nullptr) {
651 AppendToBuffer(", %s", comment);
652 }
653 return 6; // includes 0x0F
654 }
655
656 // Returns number of bytes used, including *data.
JumpConditionalShort(byte * data,const char * comment)657 int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
658 byte cond = *data & 0x0F;
659 byte b = *(data + 1);
660 byte* dest = data + static_cast<int8_t>(b) + 2;
661 const char* mnem = jump_conditional_mnem[cond];
662 AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
663 if (comment != nullptr) {
664 AppendToBuffer(", %s", comment);
665 }
666 return 2;
667 }
668
669 // Returns number of bytes used, including *data.
SetCC(byte * data)670 int DisassemblerIA32::SetCC(byte* data) {
671 DCHECK_EQ(0x0F, *data);
672 byte cond = *(data + 1) & 0x0F;
673 const char* mnem = set_conditional_mnem[cond];
674 AppendToBuffer("%s ", mnem);
675 PrintRightByteOperand(data + 2);
676 return 3; // Includes 0x0F.
677 }
678
679 // Returns number of bytes used, including *data.
CMov(byte * data)680 int DisassemblerIA32::CMov(byte* data) {
681 DCHECK_EQ(0x0F, *data);
682 byte cond = *(data + 1) & 0x0F;
683 const char* mnem = conditional_move_mnem[cond];
684 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
685 return 2 + op_size; // includes 0x0F
686 }
687
688 const char* sf_str[4] = {"", "rl", "ra", "ll"};
689
AVXInstruction(byte * data)690 int DisassemblerIA32::AVXInstruction(byte* data) {
691 byte opcode = *data;
692 byte* current = data + 1;
693 if (vex_66() && vex_0f38()) {
694 int mod, regop, rm, vvvv = vex_vreg();
695 get_modrm(*current, &mod, ®op, &rm);
696 switch (opcode) {
697 case 0x18:
698 AppendToBuffer("vbroadcastss %s,", NameOfXMMRegister(regop));
699 current += PrintRightXMMOperand(current);
700 break;
701 case 0x37:
702 AppendToBuffer("vpcmpgtq %s,%s,", NameOfXMMRegister(regop),
703 NameOfXMMRegister(vvvv));
704 current += PrintRightXMMOperand(current);
705 break;
706 case 0xF7:
707 AppendToBuffer("shlx %s,", NameOfCPURegister(regop));
708 current += PrintRightOperand(current);
709 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
710 break;
711 #define DECLARE_SSE_AVX_DIS_CASE(instruction, notUsed1, notUsed2, notUsed3, \
712 opcode) \
713 case 0x##opcode: { \
714 AppendToBuffer("v" #instruction " %s,%s,", NameOfXMMRegister(regop), \
715 NameOfXMMRegister(vvvv)); \
716 current += PrintRightXMMOperand(current); \
717 break; \
718 }
719
720 SSSE3_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE)
721 SSE4_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE)
722 #undef DECLARE_SSE_AVX_DIS_CASE
723 #define DECLARE_SSE_AVX_RM_DIS_CASE(instruction, notUsed1, notUsed2, notUsed3, \
724 opcode) \
725 case 0x##opcode: { \
726 AppendToBuffer("v" #instruction " %s,", NameOfXMMRegister(regop)); \
727 current += PrintRightXMMOperand(current); \
728 break; \
729 }
730
731 SSSE3_UNOP_INSTRUCTION_LIST(DECLARE_SSE_AVX_RM_DIS_CASE)
732 SSE4_RM_INSTRUCTION_LIST(DECLARE_SSE_AVX_RM_DIS_CASE)
733 #undef DECLARE_SSE_AVX_RM_DIS_CASE
734
735 #define DISASSEMBLE_AVX2_BROADCAST(instruction, _1, _2, _3, code) \
736 case 0x##code: \
737 AppendToBuffer("" #instruction " %s,", NameOfXMMRegister(regop)); \
738 current += PrintRightXMMOperand(current); \
739 break;
740 AVX2_BROADCAST_LIST(DISASSEMBLE_AVX2_BROADCAST)
741 #undef DISASSEMBLE_AVX2_BROADCAST
742
743 default: {
744 #define DECLARE_FMA_DISASM(instruction, _1, _2, _3, _4, _5, code) \
745 case 0x##code: { \
746 AppendToBuffer(#instruction " %s,%s,", NameOfXMMRegister(regop), \
747 NameOfXMMRegister(vvvv)); \
748 current += PrintRightXMMOperand(current); \
749 break; \
750 }
751 // Handle all the fma instructions here in the default branch since they
752 // have the same opcodes but differ by rex_w.
753 if (vex_w()) {
754 switch (opcode) {
755 FMA_SS_INSTRUCTION_LIST(DECLARE_FMA_DISASM)
756 FMA_PS_INSTRUCTION_LIST(DECLARE_FMA_DISASM)
757 default: {
758 UnimplementedInstruction();
759 }
760 }
761 } else {
762 switch (opcode) {
763 FMA_SD_INSTRUCTION_LIST(DECLARE_FMA_DISASM)
764 FMA_PD_INSTRUCTION_LIST(DECLARE_FMA_DISASM)
765 default: {
766 UnimplementedInstruction();
767 }
768 }
769 }
770 #undef DECLARE_FMA_DISASM
771 }
772 }
773 } else if (vex_66() && vex_0f3a()) {
774 int mod, regop, rm, vvvv = vex_vreg();
775 get_modrm(*current, &mod, ®op, &rm);
776 switch (opcode) {
777 case 0x08:
778 AppendToBuffer("vroundps %s,", NameOfXMMRegister(regop));
779 current += PrintRightXMMOperand(current);
780 AppendToBuffer(",%d", Imm8_U(current));
781 current++;
782 break;
783 case 0x09:
784 AppendToBuffer("vroundpd %s,", NameOfXMMRegister(regop));
785 current += PrintRightXMMOperand(current);
786 AppendToBuffer(",%d", Imm8_U(current));
787 current++;
788 break;
789 case 0x0a:
790 AppendToBuffer("vroundss %s,%s,", NameOfXMMRegister(regop),
791 NameOfXMMRegister(vvvv));
792 current += PrintRightXMMOperand(current);
793 AppendToBuffer(",%d", Imm8_U(current));
794 current++;
795 break;
796 case 0x0b:
797 AppendToBuffer("vroundsd %s,%s,", NameOfXMMRegister(regop),
798 NameOfXMMRegister(vvvv));
799 current += PrintRightXMMOperand(current);
800 AppendToBuffer(",%d", Imm8_U(current));
801 current++;
802 break;
803 case 0x0E:
804 AppendToBuffer("vpblendw %s,%s,", NameOfXMMRegister(regop),
805 NameOfXMMRegister(vvvv));
806 current += PrintRightXMMOperand(current);
807 AppendToBuffer(",%d", Imm8_U(current));
808 current++;
809 break;
810 case 0x0F:
811 AppendToBuffer("vpalignr %s,%s,", NameOfXMMRegister(regop),
812 NameOfXMMRegister(vvvv));
813 current += PrintRightXMMOperand(current);
814 AppendToBuffer(",%d", Imm8_U(current));
815 current++;
816 break;
817 case 0x14:
818 AppendToBuffer("vpextrb ");
819 current += PrintRightOperand(current);
820 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(current));
821 current++;
822 break;
823 case 0x15:
824 AppendToBuffer("vpextrw ");
825 current += PrintRightOperand(current);
826 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(current));
827 current++;
828 break;
829 case 0x16:
830 AppendToBuffer("vpextrd ");
831 current += PrintRightOperand(current);
832 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(current));
833 current++;
834 break;
835 case 0x20:
836 AppendToBuffer("vpinsrb %s,%s,", NameOfXMMRegister(regop),
837 NameOfXMMRegister(vvvv));
838 current += PrintRightOperand(current);
839 AppendToBuffer(",%d", Imm8(current));
840 current++;
841 break;
842 case 0x21:
843 AppendToBuffer("vinsertps %s,%s,", NameOfXMMRegister(regop),
844 NameOfXMMRegister(vvvv));
845 current += PrintRightXMMOperand(current);
846 AppendToBuffer(",%d", Imm8(current));
847 current++;
848 break;
849 case 0x22:
850 AppendToBuffer("vpinsrd %s,%s,", NameOfXMMRegister(regop),
851 NameOfXMMRegister(vvvv));
852 current += PrintRightOperand(current);
853 AppendToBuffer(",%d", Imm8(current));
854 current++;
855 break;
856 case 0x4A:
857 AppendToBuffer("vblendvps %s,%s,", NameOfXMMRegister(regop),
858 NameOfXMMRegister(vvvv));
859 current += PrintRightXMMOperand(current);
860 AppendToBuffer(",%s", NameOfXMMRegister(*current >> 4));
861 break;
862 case 0x4B:
863 AppendToBuffer("vblendvps %s,%s,", NameOfXMMRegister(regop),
864 NameOfXMMRegister(vvvv));
865 current += PrintRightXMMOperand(current);
866 AppendToBuffer(",%s", NameOfXMMRegister(*current >> 4));
867 break;
868 case 0x4C:
869 AppendToBuffer("vpblendvb %s,%s,", NameOfXMMRegister(regop),
870 NameOfXMMRegister(vvvv));
871 current += PrintRightXMMOperand(current);
872 AppendToBuffer(",%s", NameOfXMMRegister(*current >> 4));
873 break;
874 default:
875 UnimplementedInstruction();
876 }
877 } else if (vex_f2() && vex_0f()) {
878 int mod, regop, rm, vvvv = vex_vreg();
879 get_modrm(*current, &mod, ®op, &rm);
880 switch (opcode) {
881 case 0x10:
882 AppendToBuffer("vmovsd %s,%s,", NameOfXMMRegister(regop),
883 NameOfXMMRegister(vvvv));
884 current += PrintRightXMMOperand(current);
885 break;
886 case 0x11:
887 AppendToBuffer("vmovsd ");
888 current += PrintRightXMMOperand(current);
889 AppendToBuffer(",%s", NameOfXMMRegister(regop));
890 break;
891 case 0x12:
892 AppendToBuffer("vmovddup %s,", NameOfXMMRegister(regop));
893 current += PrintRightXMMOperand(current);
894 break;
895 case 0x2c:
896 AppendToBuffer("vcvttsd2si %s,", NameOfXMMRegister(regop));
897 current += PrintRightXMMOperand(current);
898 break;
899 case 0x70:
900 AppendToBuffer("vpshuflw %s,", NameOfXMMRegister(regop));
901 current += PrintRightXMMOperand(current);
902 AppendToBuffer(",%d", Imm8(current));
903 current++;
904 break;
905 case 0x7C:
906 AppendToBuffer("vhaddps %s,%s,", NameOfXMMRegister(regop),
907 NameOfXMMRegister(vvvv));
908 current += PrintRightXMMOperand(current);
909 break;
910 #define DISASM_SSE2_INSTRUCTION_LIST_SD(instruction, _1, _2, opcode) \
911 case 0x##opcode: \
912 AppendToBuffer("v" #instruction " %s,%s,", NameOfXMMRegister(regop), \
913 NameOfXMMRegister(vvvv)); \
914 current += PrintRightXMMOperand(current); \
915 break;
916 SSE2_INSTRUCTION_LIST_SD(DISASM_SSE2_INSTRUCTION_LIST_SD)
917 #undef DISASM_SSE2_INSTRUCTION_LIST_SD
918 default:
919 UnimplementedInstruction();
920 }
921 } else if (vex_f3() && vex_0f()) {
922 int mod, regop, rm, vvvv = vex_vreg();
923 get_modrm(*current, &mod, ®op, &rm);
924 switch (opcode) {
925 case 0x10:
926 AppendToBuffer("vmovss %s,%s,", NameOfXMMRegister(regop),
927 NameOfXMMRegister(vvvv));
928 current += PrintRightXMMOperand(current);
929 break;
930 case 0x11:
931 AppendToBuffer("vmovss ");
932 current += PrintRightXMMOperand(current);
933 AppendToBuffer(",%s", NameOfXMMRegister(regop));
934 break;
935 case 0x16:
936 AppendToBuffer("vmovshdup %s,", NameOfXMMRegister(regop));
937 current += PrintRightXMMOperand(current);
938 break;
939 case 0x2c:
940 AppendToBuffer("vcvttss2si %s,", NameOfXMMRegister(regop));
941 current += PrintRightXMMOperand(current);
942 break;
943 case 0x51:
944 AppendToBuffer("vsqrtss %s,%s,", NameOfXMMRegister(regop),
945 NameOfXMMRegister(vvvv));
946 current += PrintRightXMMOperand(current);
947 break;
948 case 0x58:
949 AppendToBuffer("vaddss %s,%s,", NameOfXMMRegister(regop),
950 NameOfXMMRegister(vvvv));
951 current += PrintRightXMMOperand(current);
952 break;
953 case 0x59:
954 AppendToBuffer("vmulss %s,%s,", NameOfXMMRegister(regop),
955 NameOfXMMRegister(vvvv));
956 current += PrintRightXMMOperand(current);
957 break;
958 case 0x5a:
959 AppendToBuffer("vcvtss2sd %s,%s,", NameOfXMMRegister(regop),
960 NameOfXMMRegister(vvvv));
961 current += PrintRightXMMOperand(current);
962 break;
963 case 0x5B:
964 AppendToBuffer("vcvttps2dq %s,", NameOfXMMRegister(regop));
965 current += PrintRightXMMOperand(current);
966 break;
967 case 0x5C:
968 AppendToBuffer("vsubss %s,%s,", NameOfXMMRegister(regop),
969 NameOfXMMRegister(vvvv));
970 current += PrintRightXMMOperand(current);
971 break;
972 case 0x5D:
973 AppendToBuffer("vminss %s,%s,", NameOfXMMRegister(regop),
974 NameOfXMMRegister(vvvv));
975 current += PrintRightXMMOperand(current);
976 break;
977 case 0x5E:
978 AppendToBuffer("vdivss %s,%s,", NameOfXMMRegister(regop),
979 NameOfXMMRegister(vvvv));
980 current += PrintRightXMMOperand(current);
981 break;
982 case 0x5F:
983 AppendToBuffer("vmaxss %s,%s,", NameOfXMMRegister(regop),
984 NameOfXMMRegister(vvvv));
985 current += PrintRightXMMOperand(current);
986 break;
987 case 0x6f:
988 AppendToBuffer("vmovdqu %s,", NameOfXMMRegister(regop));
989 current += PrintRightOperand(current);
990 break;
991 case 0x70:
992 AppendToBuffer("vpshufhw %s,", NameOfXMMRegister(regop));
993 current += PrintRightXMMOperand(current);
994 AppendToBuffer(",%d", Imm8(current));
995 current++;
996 break;
997 case 0x7f:
998 AppendToBuffer("vmovdqu ");
999 current += PrintRightOperand(current);
1000 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1001 break;
1002 case 0xE6:
1003 AppendToBuffer("vcvtdq2pd %s,", NameOfXMMRegister(regop));
1004 current += PrintRightXMMOperand(current);
1005 break;
1006 default:
1007 UnimplementedInstruction();
1008 }
1009 } else if (vex_none() && vex_0f38()) {
1010 int mod, regop, rm, vvvv = vex_vreg();
1011 get_modrm(*current, &mod, ®op, &rm);
1012 const char* mnem = "?";
1013 switch (opcode) {
1014 case 0xF2:
1015 AppendToBuffer("andn %s,%s,", NameOfCPURegister(regop),
1016 NameOfCPURegister(vvvv));
1017 current += PrintRightOperand(current);
1018 break;
1019 case 0xF5:
1020 AppendToBuffer("bzhi %s,", NameOfCPURegister(regop));
1021 current += PrintRightOperand(current);
1022 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1023 break;
1024 case 0xF7:
1025 AppendToBuffer("bextr %s,", NameOfCPURegister(regop));
1026 current += PrintRightOperand(current);
1027 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1028 break;
1029 case 0xF3:
1030 switch (regop) {
1031 case 1:
1032 mnem = "blsr";
1033 break;
1034 case 2:
1035 mnem = "blsmsk";
1036 break;
1037 case 3:
1038 mnem = "blsi";
1039 break;
1040 default:
1041 UnimplementedInstruction();
1042 }
1043 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(vvvv));
1044 current += PrintRightOperand(current);
1045 mnem = "?";
1046 break;
1047 default:
1048 UnimplementedInstruction();
1049 }
1050 } else if (vex_f2() && vex_0f38()) {
1051 int mod, regop, rm, vvvv = vex_vreg();
1052 get_modrm(*current, &mod, ®op, &rm);
1053 switch (opcode) {
1054 case 0xF5:
1055 AppendToBuffer("pdep %s,%s,", NameOfCPURegister(regop),
1056 NameOfCPURegister(vvvv));
1057 current += PrintRightOperand(current);
1058 break;
1059 case 0xF6:
1060 AppendToBuffer("mulx %s,%s,", NameOfCPURegister(regop),
1061 NameOfCPURegister(vvvv));
1062 current += PrintRightOperand(current);
1063 break;
1064 case 0xF7:
1065 AppendToBuffer("shrx %s,", NameOfCPURegister(regop));
1066 current += PrintRightOperand(current);
1067 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1068 break;
1069 default:
1070 UnimplementedInstruction();
1071 }
1072 } else if (vex_f3() && vex_0f38()) {
1073 int mod, regop, rm, vvvv = vex_vreg();
1074 get_modrm(*current, &mod, ®op, &rm);
1075 switch (opcode) {
1076 case 0xF5:
1077 AppendToBuffer("pext %s,%s,", NameOfCPURegister(regop),
1078 NameOfCPURegister(vvvv));
1079 current += PrintRightOperand(current);
1080 break;
1081 case 0xF7:
1082 AppendToBuffer("sarx %s,", NameOfCPURegister(regop));
1083 current += PrintRightOperand(current);
1084 AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1085 break;
1086 default:
1087 UnimplementedInstruction();
1088 }
1089 } else if (vex_f2() && vex_0f3a()) {
1090 int mod, regop, rm;
1091 get_modrm(*current, &mod, ®op, &rm);
1092 switch (opcode) {
1093 case 0xF0:
1094 AppendToBuffer("rorx %s,", NameOfCPURegister(regop));
1095 current += PrintRightOperand(current);
1096 AppendToBuffer(",%d", *current & 0x1F);
1097 current += 1;
1098 break;
1099 default:
1100 UnimplementedInstruction();
1101 }
1102 } else if (vex_none() && vex_0f()) {
1103 int mod, regop, rm, vvvv = vex_vreg();
1104 get_modrm(*current, &mod, ®op, &rm);
1105 switch (opcode) {
1106 case 0x10:
1107 AppendToBuffer("vmovups %s,", NameOfXMMRegister(regop));
1108 current += PrintRightXMMOperand(current);
1109 break;
1110 case 0x11:
1111 AppendToBuffer("vmovups ");
1112 current += PrintRightXMMOperand(current);
1113 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1114 break;
1115 case 0x12:
1116 if (mod == 0b11) {
1117 AppendToBuffer("vmovhlps %s,%s,", NameOfXMMRegister(regop),
1118 NameOfXMMRegister(vvvv));
1119 } else {
1120 AppendToBuffer("vmovlps %s,%s,", NameOfXMMRegister(regop),
1121 NameOfXMMRegister(vvvv));
1122 }
1123 current += PrintRightXMMOperand(current);
1124 break;
1125 case 0x13:
1126 AppendToBuffer("vmovlps ");
1127 current += PrintRightXMMOperand(current);
1128 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1129 break;
1130 case 0x14:
1131 AppendToBuffer("vunpcklps %s,%s,", NameOfXMMRegister(regop),
1132 NameOfXMMRegister(vvvv));
1133 current += PrintRightXMMOperand(current);
1134 break;
1135 case 0x16:
1136 AppendToBuffer("vmovhps %s,", NameOfXMMRegister(regop));
1137 current += PrintRightXMMOperand(current);
1138 break;
1139 case 0x17:
1140 AppendToBuffer("vmovhps ");
1141 current += PrintRightXMMOperand(current);
1142 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1143 break;
1144 case 0x28:
1145 AppendToBuffer("vmovaps %s,", NameOfXMMRegister(regop));
1146 current += PrintRightXMMOperand(current);
1147 break;
1148 case 0x2e:
1149 AppendToBuffer("vucomiss %s,", NameOfXMMRegister(regop));
1150 current += PrintRightXMMOperand(current);
1151 break;
1152 case 0x50:
1153 AppendToBuffer("vmovmskps %s,%s", NameOfCPURegister(regop),
1154 NameOfXMMRegister(rm));
1155 current++;
1156 break;
1157 case 0x51:
1158 AppendToBuffer("vsqrtps %s,", NameOfXMMRegister(regop));
1159 current += PrintRightXMMOperand(current);
1160 break;
1161 case 0x52:
1162 AppendToBuffer("vrsqrtps %s,", NameOfXMMRegister(regop));
1163 current += PrintRightXMMOperand(current);
1164 break;
1165 case 0x53:
1166 AppendToBuffer("vrcpps %s,", NameOfXMMRegister(regop));
1167 current += PrintRightXMMOperand(current);
1168 break;
1169 case 0x54:
1170 AppendToBuffer("vandps %s,%s,", NameOfXMMRegister(regop),
1171 NameOfXMMRegister(vvvv));
1172 current += PrintRightXMMOperand(current);
1173 break;
1174 case 0x55:
1175 AppendToBuffer("vandnps %s,%s,", NameOfXMMRegister(regop),
1176 NameOfXMMRegister(vvvv));
1177 current += PrintRightXMMOperand(current);
1178 break;
1179 case 0x56:
1180 AppendToBuffer("vorps %s,%s,", NameOfXMMRegister(regop),
1181 NameOfXMMRegister(vvvv));
1182 current += PrintRightXMMOperand(current);
1183 break;
1184 case 0x57:
1185 AppendToBuffer("vxorps %s,%s,", NameOfXMMRegister(regop),
1186 NameOfXMMRegister(vvvv));
1187 current += PrintRightXMMOperand(current);
1188 break;
1189 case 0x58:
1190 AppendToBuffer("vaddps %s,%s,", NameOfXMMRegister(regop),
1191 NameOfXMMRegister(vvvv));
1192 current += PrintRightXMMOperand(current);
1193 break;
1194 case 0x59:
1195 AppendToBuffer("vmulps %s,%s,", NameOfXMMRegister(regop),
1196 NameOfXMMRegister(vvvv));
1197 current += PrintRightXMMOperand(current);
1198 break;
1199 case 0x5A:
1200 AppendToBuffer("vcvtps2pd %s,", NameOfXMMRegister(regop));
1201 current += PrintRightXMMOperand(current);
1202 break;
1203 case 0x5B:
1204 AppendToBuffer("vcvtdq2ps %s,", NameOfXMMRegister(regop));
1205 current += PrintRightXMMOperand(current);
1206 break;
1207 case 0x5C:
1208 AppendToBuffer("vsubps %s,%s,", NameOfXMMRegister(regop),
1209 NameOfXMMRegister(vvvv));
1210 current += PrintRightXMMOperand(current);
1211 break;
1212 case 0x5D:
1213 AppendToBuffer("vminps %s,%s,", NameOfXMMRegister(regop),
1214 NameOfXMMRegister(vvvv));
1215 current += PrintRightXMMOperand(current);
1216 break;
1217 case 0x5E:
1218 AppendToBuffer("vdivps %s,%s,", NameOfXMMRegister(regop),
1219 NameOfXMMRegister(vvvv));
1220 current += PrintRightXMMOperand(current);
1221 break;
1222 case 0x5F:
1223 AppendToBuffer("vmaxps %s,%s,", NameOfXMMRegister(regop),
1224 NameOfXMMRegister(vvvv));
1225 current += PrintRightXMMOperand(current);
1226 break;
1227 case 0xC2: {
1228 AppendToBuffer("vcmpps %s,%s,", NameOfXMMRegister(regop),
1229 NameOfXMMRegister(vvvv));
1230 current += PrintRightXMMOperand(current);
1231 AppendToBuffer(", (%s)", cmp_pseudo_op[*current]);
1232 current++;
1233 break;
1234 }
1235 case 0xC6:
1236 AppendToBuffer("vshufps %s,%s,", NameOfXMMRegister(regop),
1237 NameOfXMMRegister(vvvv));
1238 current += PrintRightXMMOperand(current);
1239 AppendToBuffer(", %d", (*current) & 3);
1240 current += 1;
1241 break;
1242 default:
1243 UnimplementedInstruction();
1244 }
1245 } else if (vex_66() && vex_0f()) {
1246 int mod, regop, rm, vvvv = vex_vreg();
1247 get_modrm(*current, &mod, ®op, &rm);
1248 switch (opcode) {
1249 case 0x10:
1250 AppendToBuffer("vmovupd %s,", NameOfXMMRegister(regop));
1251 current += PrintRightXMMOperand(current);
1252 break;
1253 case 0x28:
1254 AppendToBuffer("vmovapd %s,", NameOfXMMRegister(regop));
1255 current += PrintRightXMMOperand(current);
1256 break;
1257 case 0x2e:
1258 AppendToBuffer("vucomisd %s,", NameOfXMMRegister(regop));
1259 current += PrintRightXMMOperand(current);
1260 break;
1261 case 0x50:
1262 AppendToBuffer("vmovmskpd %s,%s", NameOfCPURegister(regop),
1263 NameOfXMMRegister(rm));
1264 current++;
1265 break;
1266 case 0x54:
1267 AppendToBuffer("vandpd %s,%s,", NameOfXMMRegister(regop),
1268 NameOfXMMRegister(vvvv));
1269 current += PrintRightXMMOperand(current);
1270 break;
1271 case 0x55:
1272 AppendToBuffer("vandnpd %s,%s,", NameOfXMMRegister(regop),
1273 NameOfXMMRegister(vvvv));
1274 current += PrintRightXMMOperand(current);
1275 break;
1276 case 0x56:
1277 AppendToBuffer("vorpd %s,%s,", NameOfXMMRegister(regop),
1278 NameOfXMMRegister(vvvv));
1279 current += PrintRightXMMOperand(current);
1280 break;
1281 case 0x57:
1282 AppendToBuffer("vxorpd %s,%s,", NameOfXMMRegister(regop),
1283 NameOfXMMRegister(vvvv));
1284 current += PrintRightXMMOperand(current);
1285 break;
1286 case 0x58:
1287 AppendToBuffer("vaddpd %s,%s,", NameOfXMMRegister(regop),
1288 NameOfXMMRegister(vvvv));
1289 current += PrintRightXMMOperand(current);
1290 break;
1291 case 0x59:
1292 AppendToBuffer("vmulpd %s,%s,", NameOfXMMRegister(regop),
1293 NameOfXMMRegister(vvvv));
1294 current += PrintRightXMMOperand(current);
1295 break;
1296 case 0x5A:
1297 AppendToBuffer("vcvtpd2ps %s,", NameOfXMMRegister(regop));
1298 current += PrintRightXMMOperand(current);
1299 break;
1300 case 0x5C:
1301 AppendToBuffer("vsubpd %s,%s,", NameOfXMMRegister(regop),
1302 NameOfXMMRegister(vvvv));
1303 current += PrintRightXMMOperand(current);
1304 break;
1305 case 0x5D:
1306 AppendToBuffer("vminpd %s,%s,", NameOfXMMRegister(regop),
1307 NameOfXMMRegister(vvvv));
1308 current += PrintRightXMMOperand(current);
1309 break;
1310 case 0x5E:
1311 AppendToBuffer("vdivpd %s,%s,", NameOfXMMRegister(regop),
1312 NameOfXMMRegister(vvvv));
1313 current += PrintRightXMMOperand(current);
1314 break;
1315 case 0x5F:
1316 AppendToBuffer("vmaxpd %s,%s,", NameOfXMMRegister(regop),
1317 NameOfXMMRegister(vvvv));
1318 current += PrintRightXMMOperand(current);
1319 break;
1320 case 0x6E:
1321 AppendToBuffer("vmovd %s,", NameOfXMMRegister(regop));
1322 current += PrintRightOperand(current);
1323 break;
1324 case 0x6f:
1325 AppendToBuffer("vmovdqa %s,", NameOfXMMRegister(regop));
1326 current += PrintRightOperand(current);
1327 break;
1328 case 0x70:
1329 AppendToBuffer("vpshufd %s,", NameOfXMMRegister(regop));
1330 current += PrintRightXMMOperand(current);
1331 AppendToBuffer(",%d", Imm8(current));
1332 current++;
1333 break;
1334 case 0x71:
1335 AppendToBuffer("vps%sw %s,%s", sf_str[regop / 2],
1336 NameOfXMMRegister(vvvv), NameOfXMMRegister(rm));
1337 current++;
1338 AppendToBuffer(",%u", *current++);
1339 break;
1340 case 0x72:
1341 AppendToBuffer("vps%sd %s,%s", sf_str[regop / 2],
1342 NameOfXMMRegister(vvvv), NameOfXMMRegister(rm));
1343 current++;
1344 AppendToBuffer(",%u", *current++);
1345 break;
1346 case 0x73:
1347 AppendToBuffer("vps%sq %s,%s", sf_str[regop / 2],
1348 NameOfXMMRegister(vvvv), NameOfXMMRegister(rm));
1349 current++;
1350 AppendToBuffer(",%u", *current++);
1351 break;
1352 case 0x7E:
1353 AppendToBuffer("vmovd ");
1354 current += PrintRightOperand(current);
1355 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1356 break;
1357 case 0xC2: {
1358 AppendToBuffer("vcmppd %s,%s,", NameOfXMMRegister(regop),
1359 NameOfXMMRegister(vvvv));
1360 current += PrintRightXMMOperand(current);
1361 AppendToBuffer(", (%s)", cmp_pseudo_op[*current]);
1362 current++;
1363 break;
1364 }
1365 case 0xC4:
1366 AppendToBuffer("vpinsrw %s,%s,", NameOfXMMRegister(regop),
1367 NameOfXMMRegister(vvvv));
1368 current += PrintRightOperand(current);
1369 AppendToBuffer(",%d", Imm8(current));
1370 current++;
1371 break;
1372 case 0xC6:
1373 AppendToBuffer("vshufpd %s,%s,", NameOfXMMRegister(regop),
1374 NameOfXMMRegister(vvvv));
1375 current += PrintRightXMMOperand(current);
1376 AppendToBuffer(",%d", Imm8(current));
1377 current++;
1378 break;
1379 case 0xD7:
1380 AppendToBuffer("vpmovmskb %s,%s", NameOfCPURegister(regop),
1381 NameOfXMMRegister(rm));
1382 current++;
1383 break;
1384 case 0xE6:
1385 AppendToBuffer("vcvttpd2dq %s,", NameOfXMMRegister(regop));
1386 current += PrintRightXMMOperand(current);
1387 break;
1388 #define DECLARE_SSE_AVX_DIS_CASE(instruction, notUsed1, notUsed2, opcode) \
1389 case 0x##opcode: { \
1390 AppendToBuffer("v" #instruction " %s,%s,", NameOfXMMRegister(regop), \
1391 NameOfXMMRegister(vvvv)); \
1392 current += PrintRightXMMOperand(current); \
1393 break; \
1394 }
1395
1396 SSE2_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE)
1397 #undef DECLARE_SSE_AVX_DIS_CASE
1398 default:
1399 UnimplementedInstruction();
1400 }
1401 } else {
1402 UnimplementedInstruction();
1403 }
1404
1405 return static_cast<int>(current - data);
1406 }
1407
1408 // Returns number of bytes used, including *data.
FPUInstruction(byte * data)1409 int DisassemblerIA32::FPUInstruction(byte* data) {
1410 byte escape_opcode = *data;
1411 DCHECK_EQ(0xD8, escape_opcode & 0xF8);
1412 byte modrm_byte = *(data + 1);
1413
1414 if (modrm_byte >= 0xC0) {
1415 return RegisterFPUInstruction(escape_opcode, modrm_byte);
1416 } else {
1417 return MemoryFPUInstruction(escape_opcode, modrm_byte, data + 1);
1418 }
1419 }
1420
MemoryFPUInstruction(int escape_opcode,int modrm_byte,byte * modrm_start)1421 int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode, int modrm_byte,
1422 byte* modrm_start) {
1423 const char* mnem = "?";
1424 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
1425 switch (escape_opcode) {
1426 case 0xD9:
1427 switch (regop) {
1428 case 0:
1429 mnem = "fld_s";
1430 break;
1431 case 2:
1432 mnem = "fst_s";
1433 break;
1434 case 3:
1435 mnem = "fstp_s";
1436 break;
1437 case 7:
1438 mnem = "fstcw";
1439 break;
1440 default:
1441 UnimplementedInstruction();
1442 }
1443 break;
1444
1445 case 0xDB:
1446 switch (regop) {
1447 case 0:
1448 mnem = "fild_s";
1449 break;
1450 case 1:
1451 mnem = "fisttp_s";
1452 break;
1453 case 2:
1454 mnem = "fist_s";
1455 break;
1456 case 3:
1457 mnem = "fistp_s";
1458 break;
1459 default:
1460 UnimplementedInstruction();
1461 }
1462 break;
1463
1464 case 0xDD:
1465 switch (regop) {
1466 case 0:
1467 mnem = "fld_d";
1468 break;
1469 case 1:
1470 mnem = "fisttp_d";
1471 break;
1472 case 2:
1473 mnem = "fst_d";
1474 break;
1475 case 3:
1476 mnem = "fstp_d";
1477 break;
1478 default:
1479 UnimplementedInstruction();
1480 }
1481 break;
1482
1483 case 0xDF:
1484 switch (regop) {
1485 case 5:
1486 mnem = "fild_d";
1487 break;
1488 case 7:
1489 mnem = "fistp_d";
1490 break;
1491 default:
1492 UnimplementedInstruction();
1493 }
1494 break;
1495
1496 default:
1497 UnimplementedInstruction();
1498 }
1499 AppendToBuffer("%s ", mnem);
1500 int count = PrintRightOperand(modrm_start);
1501 return count + 1;
1502 }
1503
RegisterFPUInstruction(int escape_opcode,byte modrm_byte)1504 int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
1505 byte modrm_byte) {
1506 bool has_register = false; // Is the FPU register encoded in modrm_byte?
1507 const char* mnem = "?";
1508
1509 switch (escape_opcode) {
1510 case 0xD8:
1511 has_register = true;
1512 switch (modrm_byte & 0xF8) {
1513 case 0xC0:
1514 mnem = "fadd_i";
1515 break;
1516 case 0xE0:
1517 mnem = "fsub_i";
1518 break;
1519 case 0xC8:
1520 mnem = "fmul_i";
1521 break;
1522 case 0xF0:
1523 mnem = "fdiv_i";
1524 break;
1525 default:
1526 UnimplementedInstruction();
1527 }
1528 break;
1529
1530 case 0xD9:
1531 switch (modrm_byte & 0xF8) {
1532 case 0xC0:
1533 mnem = "fld";
1534 has_register = true;
1535 break;
1536 case 0xC8:
1537 mnem = "fxch";
1538 has_register = true;
1539 break;
1540 default:
1541 switch (modrm_byte) {
1542 case 0xE0:
1543 mnem = "fchs";
1544 break;
1545 case 0xE1:
1546 mnem = "fabs";
1547 break;
1548 case 0xE4:
1549 mnem = "ftst";
1550 break;
1551 case 0xE8:
1552 mnem = "fld1";
1553 break;
1554 case 0xEB:
1555 mnem = "fldpi";
1556 break;
1557 case 0xED:
1558 mnem = "fldln2";
1559 break;
1560 case 0xEE:
1561 mnem = "fldz";
1562 break;
1563 case 0xF0:
1564 mnem = "f2xm1";
1565 break;
1566 case 0xF1:
1567 mnem = "fyl2x";
1568 break;
1569 case 0xF4:
1570 mnem = "fxtract";
1571 break;
1572 case 0xF5:
1573 mnem = "fprem1";
1574 break;
1575 case 0xF7:
1576 mnem = "fincstp";
1577 break;
1578 case 0xF8:
1579 mnem = "fprem";
1580 break;
1581 case 0xFC:
1582 mnem = "frndint";
1583 break;
1584 case 0xFD:
1585 mnem = "fscale";
1586 break;
1587 case 0xFE:
1588 mnem = "fsin";
1589 break;
1590 case 0xFF:
1591 mnem = "fcos";
1592 break;
1593 default:
1594 UnimplementedInstruction();
1595 }
1596 }
1597 break;
1598
1599 case 0xDA:
1600 if (modrm_byte == 0xE9) {
1601 mnem = "fucompp";
1602 } else {
1603 UnimplementedInstruction();
1604 }
1605 break;
1606
1607 case 0xDB:
1608 if ((modrm_byte & 0xF8) == 0xE8) {
1609 mnem = "fucomi";
1610 has_register = true;
1611 } else if (modrm_byte == 0xE2) {
1612 mnem = "fclex";
1613 } else if (modrm_byte == 0xE3) {
1614 mnem = "fninit";
1615 } else {
1616 UnimplementedInstruction();
1617 }
1618 break;
1619
1620 case 0xDC:
1621 has_register = true;
1622 switch (modrm_byte & 0xF8) {
1623 case 0xC0:
1624 mnem = "fadd";
1625 break;
1626 case 0xE8:
1627 mnem = "fsub";
1628 break;
1629 case 0xC8:
1630 mnem = "fmul";
1631 break;
1632 case 0xF8:
1633 mnem = "fdiv";
1634 break;
1635 default:
1636 UnimplementedInstruction();
1637 }
1638 break;
1639
1640 case 0xDD:
1641 has_register = true;
1642 switch (modrm_byte & 0xF8) {
1643 case 0xC0:
1644 mnem = "ffree";
1645 break;
1646 case 0xD0:
1647 mnem = "fst";
1648 break;
1649 case 0xD8:
1650 mnem = "fstp";
1651 break;
1652 default:
1653 UnimplementedInstruction();
1654 }
1655 break;
1656
1657 case 0xDE:
1658 if (modrm_byte == 0xD9) {
1659 mnem = "fcompp";
1660 } else {
1661 has_register = true;
1662 switch (modrm_byte & 0xF8) {
1663 case 0xC0:
1664 mnem = "faddp";
1665 break;
1666 case 0xE8:
1667 mnem = "fsubp";
1668 break;
1669 case 0xC8:
1670 mnem = "fmulp";
1671 break;
1672 case 0xF8:
1673 mnem = "fdivp";
1674 break;
1675 default:
1676 UnimplementedInstruction();
1677 }
1678 }
1679 break;
1680
1681 case 0xDF:
1682 if (modrm_byte == 0xE0) {
1683 mnem = "fnstsw_ax";
1684 } else if ((modrm_byte & 0xF8) == 0xE8) {
1685 mnem = "fucomip";
1686 has_register = true;
1687 }
1688 break;
1689
1690 default:
1691 UnimplementedInstruction();
1692 }
1693
1694 if (has_register) {
1695 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1696 } else {
1697 AppendToBuffer("%s", mnem);
1698 }
1699 return 2;
1700 }
1701
1702 // Mnemonics for instructions 0xF0 byte.
1703 // Returns nullptr if the instruction is not handled here.
F0Mnem(byte f0byte)1704 static const char* F0Mnem(byte f0byte) {
1705 switch (f0byte) {
1706 case 0x0B:
1707 return "ud2";
1708 case 0x18:
1709 return "prefetch";
1710 case 0xA2:
1711 return "cpuid";
1712 case 0xBE:
1713 return "movsx_b";
1714 case 0xBF:
1715 return "movsx_w";
1716 case 0xB6:
1717 return "movzx_b";
1718 case 0xB7:
1719 return "movzx_w";
1720 case 0xAF:
1721 return "imul";
1722 case 0xA4:
1723 return "shld";
1724 case 0xA5:
1725 return "shld";
1726 case 0xAD:
1727 return "shrd";
1728 case 0xAC:
1729 return "shrd"; // 3-operand version.
1730 case 0xAB:
1731 return "bts";
1732 case 0xB0:
1733 return "cmpxchg_b";
1734 case 0xB1:
1735 return "cmpxchg";
1736 case 0xBC:
1737 return "bsf";
1738 case 0xBD:
1739 return "bsr";
1740 case 0xC7:
1741 return "cmpxchg8b";
1742 default:
1743 return nullptr;
1744 }
1745 }
1746
1747 // Disassembled instruction '*instr' and writes it into 'out_buffer'.
InstructionDecode(v8::base::Vector<char> out_buffer,byte * instr)1748 int DisassemblerIA32::InstructionDecode(v8::base::Vector<char> out_buffer,
1749 byte* instr) {
1750 tmp_buffer_pos_ = 0; // starting to write as position 0
1751 byte* data = instr;
1752 // Check for hints.
1753 const char* branch_hint = nullptr;
1754 // We use these two prefixes only with branch prediction
1755 if (*data == 0x3E /*ds*/) {
1756 branch_hint = "predicted taken";
1757 data++;
1758 } else if (*data == 0x2E /*cs*/) {
1759 branch_hint = "predicted not taken";
1760 data++;
1761 } else if (*data == 0xC4 && *(data + 1) >= 0xC0) {
1762 vex_byte0_ = *data;
1763 vex_byte1_ = *(data + 1);
1764 vex_byte2_ = *(data + 2);
1765 data += 3;
1766 } else if (*data == 0xC5 && *(data + 1) >= 0xC0) {
1767 vex_byte0_ = *data;
1768 vex_byte1_ = *(data + 1);
1769 data += 2;
1770 } else if (*data == 0xF0 /*lock*/) {
1771 AppendToBuffer("lock ");
1772 data++;
1773 }
1774
1775 bool processed = true; // Will be set to false if the current instruction
1776 // is not in 'instructions' table.
1777 // Decode AVX instructions.
1778 if (vex_byte0_ != 0) {
1779 data += AVXInstruction(data);
1780 } else {
1781 const InstructionDesc& idesc = instruction_table_->Get(*data);
1782 switch (idesc.type) {
1783 case ZERO_OPERANDS_INSTR:
1784 AppendToBuffer("%s", idesc.mnem);
1785 data++;
1786 break;
1787
1788 case TWO_OPERANDS_INSTR:
1789 data++;
1790 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1791 break;
1792
1793 case JUMP_CONDITIONAL_SHORT_INSTR:
1794 data += JumpConditionalShort(data, branch_hint);
1795 break;
1796
1797 case REGISTER_INSTR:
1798 AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
1799 data++;
1800 break;
1801
1802 case MOVE_REG_INSTR: {
1803 byte* addr = reinterpret_cast<byte*>(Imm32(data + 1));
1804 AppendToBuffer("mov %s,%s", NameOfCPURegister(*data & 0x07),
1805 NameOfAddress(addr));
1806 data += 5;
1807 break;
1808 }
1809
1810 case CALL_JUMP_INSTR: {
1811 byte* addr = data + Imm32(data + 1) + 5;
1812 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1813 data += 5;
1814 break;
1815 }
1816
1817 case SHORT_IMMEDIATE_INSTR: {
1818 byte* addr = reinterpret_cast<byte*>(Imm32(data + 1));
1819 AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
1820 data += 5;
1821 break;
1822 }
1823
1824 case BYTE_IMMEDIATE_INSTR: {
1825 AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
1826 data += 2;
1827 break;
1828 }
1829
1830 case NO_INSTR:
1831 processed = false;
1832 break;
1833
1834 default:
1835 UNIMPLEMENTED(); // This type is not implemented.
1836 }
1837 }
1838 //----------------------------
1839 if (!processed) {
1840 switch (*data) {
1841 case 0xC2:
1842 AppendToBuffer("ret 0x%x", Imm16_U(data + 1));
1843 data += 3;
1844 break;
1845
1846 case 0x6B: {
1847 data++;
1848 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1849 AppendToBuffer(",%d", *data);
1850 data++;
1851 } break;
1852
1853 case 0x69: {
1854 data++;
1855 data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1856 AppendToBuffer(",%d", Imm32(data));
1857 data += 4;
1858 } break;
1859
1860 case 0xF6: {
1861 data++;
1862 int mod, regop, rm;
1863 get_modrm(*data, &mod, ®op, &rm);
1864 if (regop == eax) {
1865 AppendToBuffer("test_b ");
1866 data += PrintRightByteOperand(data);
1867 int32_t imm = *data;
1868 AppendToBuffer(",0x%x", imm);
1869 data++;
1870 } else {
1871 UnimplementedInstruction();
1872 }
1873 } break;
1874
1875 case 0x81: // fall through
1876 case 0x83: // 0x81 with sign extension bit set
1877 data += PrintImmediateOp(data);
1878 break;
1879
1880 case 0x0F: {
1881 byte f0byte = data[1];
1882 const char* f0mnem = F0Mnem(f0byte);
1883 int mod, regop, rm;
1884 // Not every instruction use this, and it is safe to index data+2 as all
1885 // instructions are at least 3 bytes with operands.
1886 get_modrm(*(data + 2), &mod, ®op, &rm);
1887 if (f0byte == 0x12) {
1888 data += 2;
1889 if (mod == 0b11) {
1890 AppendToBuffer("movhlps %s,", NameOfXMMRegister(regop));
1891 } else {
1892 AppendToBuffer("movlps %s,", NameOfXMMRegister(regop));
1893 }
1894 data += PrintRightXMMOperand(data);
1895 } else if (f0byte == 0x13) {
1896 data += 2;
1897 AppendToBuffer("movlps ");
1898 data += PrintRightXMMOperand(data);
1899 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1900 } else if (f0byte == 0x14) {
1901 data += 2;
1902 AppendToBuffer("unpcklps %s,", NameOfXMMRegister(regop));
1903 data += PrintRightXMMOperand(data);
1904 } else if (f0byte == 0x16) {
1905 data += 2;
1906 AppendToBuffer("movhps %s,", NameOfXMMRegister(regop));
1907 data += PrintRightXMMOperand(data);
1908 } else if (f0byte == 0x17) {
1909 data += 2;
1910 AppendToBuffer("movhps ");
1911 data += PrintRightXMMOperand(data);
1912 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1913 } else if (f0byte == 0x18) {
1914 data += 2;
1915 const char* suffix[] = {"nta", "1", "2", "3"};
1916 AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1917 data += PrintRightOperand(data);
1918 } else if (f0byte == 0x1F && data[2] == 0) {
1919 AppendToBuffer("nop"); // 3 byte nop.
1920 data += 3;
1921 } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1922 AppendToBuffer("nop"); // 4 byte nop.
1923 data += 4;
1924 } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1925 data[4] == 0) {
1926 AppendToBuffer("nop"); // 5 byte nop.
1927 data += 5;
1928 } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1929 data[4] == 0 && data[5] == 0 && data[6] == 0) {
1930 AppendToBuffer("nop"); // 7 byte nop.
1931 data += 7;
1932 } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1933 data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1934 data[7] == 0) {
1935 AppendToBuffer("nop"); // 8 byte nop.
1936 data += 8;
1937 } else if (f0byte == 0x0B || f0byte == 0xA2 || f0byte == 0x31) {
1938 AppendToBuffer("%s", f0mnem);
1939 data += 2;
1940 } else if (f0byte == 0x28) {
1941 data += 2;
1942 AppendToBuffer("movaps %s,%s", NameOfXMMRegister(regop),
1943 NameOfXMMRegister(rm));
1944 data++;
1945 } else if (f0byte == 0x10 || f0byte == 0x11) {
1946 data += 2;
1947 // movups xmm, xmm/m128
1948 // movups xmm/m128, xmm
1949 AppendToBuffer("movups ");
1950 if (f0byte == 0x11) {
1951 data += PrintRightXMMOperand(data);
1952 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1953 } else {
1954 AppendToBuffer("%s,", NameOfXMMRegister(regop));
1955 data += PrintRightXMMOperand(data);
1956 }
1957 } else if (f0byte == 0x2E) {
1958 data += 2;
1959 AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
1960 data += PrintRightXMMOperand(data);
1961 } else if (f0byte >= 0x51 && f0byte <= 0x5F) {
1962 const char* const pseudo_op[] = {
1963 "sqrtps", "rsqrtps", "rcpps", "andps", "andnps",
1964 "orps", "xorps", "addps", "mulps", "cvtps2pd",
1965 "cvtdq2ps", "subps", "minps", "divps", "maxps",
1966 };
1967
1968 data += 2;
1969 AppendToBuffer("%s %s,", pseudo_op[f0byte - 0x51],
1970 NameOfXMMRegister(regop));
1971 data += PrintRightXMMOperand(data);
1972 } else if (f0byte == 0x50) {
1973 data += 2;
1974 AppendToBuffer("movmskps %s,%s", NameOfCPURegister(regop),
1975 NameOfXMMRegister(rm));
1976 data++;
1977 } else if (f0byte == 0xC0) {
1978 data += 2;
1979 data += PrintOperands("xadd_b", OPER_REG_OP_ORDER, data);
1980 } else if (f0byte == 0xC1) {
1981 data += 2;
1982 data += PrintOperands("xadd", OPER_REG_OP_ORDER, data);
1983 } else if (f0byte == 0xC2) {
1984 data += 2;
1985 AppendToBuffer("cmpps %s, ", NameOfXMMRegister(regop));
1986 data += PrintRightXMMOperand(data);
1987 AppendToBuffer(", (%s)", cmp_pseudo_op[*data]);
1988 data++;
1989 } else if (f0byte == 0xC6) {
1990 // shufps xmm, xmm/m128, imm8
1991 data += 2;
1992 int8_t imm8 = static_cast<int8_t>(data[1]);
1993 AppendToBuffer("shufps %s,%s,%d", NameOfXMMRegister(rm),
1994 NameOfXMMRegister(regop), static_cast<int>(imm8));
1995 data += 2;
1996 } else if (f0byte >= 0xC8 && f0byte <= 0xCF) {
1997 // bswap
1998 data += 2;
1999 int reg = f0byte - 0xC8;
2000 AppendToBuffer("bswap %s", NameOfCPURegister(reg));
2001 } else if ((f0byte & 0xF0) == 0x80) {
2002 data += JumpConditional(data, branch_hint);
2003 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
2004 f0byte == 0xB7 || f0byte == 0xAF) {
2005 data += 2;
2006 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
2007 } else if ((f0byte & 0xF0) == 0x90) {
2008 data += SetCC(data);
2009 } else if ((f0byte & 0xF0) == 0x40) {
2010 data += CMov(data);
2011 } else if (f0byte == 0xA4 || f0byte == 0xAC) {
2012 // shld, shrd
2013 data += 2;
2014 AppendToBuffer("%s ", f0mnem);
2015 int8_t imm8 = static_cast<int8_t>(data[1]);
2016 data += 2;
2017 AppendToBuffer("%s,%s,%d", NameOfCPURegister(rm),
2018 NameOfCPURegister(regop), static_cast<int>(imm8));
2019 } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
2020 // shrd_cl, shld_cl, bts
2021 data += 2;
2022 AppendToBuffer("%s ", f0mnem);
2023 data += PrintRightOperand(data);
2024 if (f0byte == 0xAB) {
2025 AppendToBuffer(",%s", NameOfCPURegister(regop));
2026 } else {
2027 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
2028 }
2029 } else if (f0byte == 0xB0) {
2030 // cmpxchg_b
2031 data += 2;
2032 AppendToBuffer("%s ", f0mnem);
2033 data += PrintRightOperand(data);
2034 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
2035 } else if (f0byte == 0xB1) {
2036 // cmpxchg
2037 data += 2;
2038 data += PrintOperands(f0mnem, OPER_REG_OP_ORDER, data);
2039 } else if (f0byte == 0xBC) {
2040 data += 2;
2041 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
2042 data += PrintRightOperand(data);
2043 } else if (f0byte == 0xBD) {
2044 data += 2;
2045 AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
2046 data += PrintRightOperand(data);
2047 } else if (f0byte == 0xC7) {
2048 // cmpxchg8b
2049 data += 2;
2050 AppendToBuffer("%s ", f0mnem);
2051 data += PrintRightOperand(data);
2052 } else if (f0byte == 0xAE && (data[2] & 0xF8) == 0xF0) {
2053 AppendToBuffer("mfence");
2054 data += 3;
2055 } else if (f0byte == 0xAE && (data[2] & 0xF8) == 0xE8) {
2056 AppendToBuffer("lfence");
2057 data += 3;
2058 } else {
2059 UnimplementedInstruction();
2060 data += 1;
2061 }
2062 } break;
2063
2064 case 0x8F: {
2065 data++;
2066 int mod, regop, rm;
2067 get_modrm(*data, &mod, ®op, &rm);
2068 if (regop == eax) {
2069 AppendToBuffer("pop ");
2070 data += PrintRightOperand(data);
2071 }
2072 } break;
2073
2074 case 0xFF: {
2075 data++;
2076 int mod, regop, rm;
2077 get_modrm(*data, &mod, ®op, &rm);
2078 const char* mnem = nullptr;
2079 switch (regop) {
2080 case esi:
2081 mnem = "push";
2082 break;
2083 case eax:
2084 mnem = "inc";
2085 break;
2086 case ecx:
2087 mnem = "dec";
2088 break;
2089 case edx:
2090 mnem = "call";
2091 break;
2092 case esp:
2093 mnem = "jmp";
2094 break;
2095 default:
2096 mnem = "???";
2097 }
2098 AppendToBuffer("%s ", mnem);
2099 data += PrintRightOperand(data);
2100 } break;
2101
2102 case 0xC7: // imm32, fall through
2103 case 0xC6: // imm8
2104 {
2105 bool is_byte = *data == 0xC6;
2106 data++;
2107 if (is_byte) {
2108 AppendToBuffer("%s ", "mov_b");
2109 data += PrintRightByteOperand(data);
2110 int32_t imm = *data;
2111 AppendToBuffer(",0x%x", imm);
2112 data++;
2113 } else {
2114 AppendToBuffer("%s ", "mov");
2115 data += PrintRightOperand(data);
2116 AppendToBuffer(",0x%x", Imm32(data));
2117 data += 4;
2118 }
2119 } break;
2120
2121 case 0x80: {
2122 data++;
2123 int mod, regop, rm;
2124 get_modrm(*data, &mod, ®op, &rm);
2125 const char* mnem = nullptr;
2126 switch (regop) {
2127 case 5:
2128 mnem = "subb";
2129 break;
2130 case 7:
2131 mnem = "cmpb";
2132 break;
2133 default:
2134 UnimplementedInstruction();
2135 }
2136 AppendToBuffer("%s ", mnem);
2137 data += PrintRightByteOperand(data);
2138 int32_t imm = *data;
2139 AppendToBuffer(",0x%x", imm);
2140 data++;
2141 } break;
2142
2143 case 0x88: // 8bit, fall through
2144 case 0x89: // 32bit
2145 {
2146 bool is_byte = *data == 0x88;
2147 int mod, regop, rm;
2148 data++;
2149 get_modrm(*data, &mod, ®op, &rm);
2150 if (is_byte) {
2151 AppendToBuffer("%s ", "mov_b");
2152 data += PrintRightByteOperand(data);
2153 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
2154 } else {
2155 AppendToBuffer("%s ", "mov");
2156 data += PrintRightOperand(data);
2157 AppendToBuffer(",%s", NameOfCPURegister(regop));
2158 }
2159 } break;
2160
2161 case 0x66: // prefix
2162 while (*data == 0x66) data++;
2163 if (*data == 0xF && data[1] == 0x1F) {
2164 AppendToBuffer("nop"); // 0x66 prefix
2165 } else if (*data == 0x39) {
2166 data++;
2167 data += PrintOperands("cmpw", OPER_REG_OP_ORDER, data);
2168 } else if (*data == 0x3B) {
2169 data++;
2170 data += PrintOperands("cmpw", REG_OPER_OP_ORDER, data);
2171 } else if (*data == 0x81) {
2172 data++;
2173 AppendToBuffer("cmpw ");
2174 data += PrintRightOperand(data);
2175 AppendToBuffer(",0x%x", Imm16(data));
2176 data += 2;
2177 } else if (*data == 0x87) {
2178 data++;
2179 int mod, regop, rm;
2180 get_modrm(*data, &mod, ®op, &rm);
2181 AppendToBuffer("xchg_w %s,", NameOfCPURegister(regop));
2182 data += PrintRightOperand(data);
2183 } else if (*data == 0x89) {
2184 data++;
2185 int mod, regop, rm;
2186 get_modrm(*data, &mod, ®op, &rm);
2187 AppendToBuffer("mov_w ");
2188 data += PrintRightOperand(data);
2189 AppendToBuffer(",%s", NameOfCPURegister(regop));
2190 } else if (*data == 0x8B) {
2191 data++;
2192 data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
2193 } else if (*data == 0x90) {
2194 AppendToBuffer("nop"); // 0x66 prefix
2195 } else if (*data == 0xC7) {
2196 data++;
2197 AppendToBuffer("%s ", "mov_w");
2198 data += PrintRightOperand(data);
2199 AppendToBuffer(",0x%x", Imm16(data));
2200 data += 2;
2201 } else if (*data == 0xF7) {
2202 data++;
2203 AppendToBuffer("%s ", "test_w");
2204 data += PrintRightOperand(data);
2205 AppendToBuffer(",0x%x", Imm16(data));
2206 data += 2;
2207 } else if (*data == 0x0F) {
2208 data++;
2209 if (*data == 0x10) {
2210 data++;
2211 int mod, regop, rm;
2212 get_modrm(*data, &mod, ®op, &rm);
2213 AppendToBuffer("movupd %s,", NameOfXMMRegister(regop));
2214 data += PrintRightXMMOperand(data);
2215 } else if (*data == 0x28) {
2216 data++;
2217 int mod, regop, rm;
2218 get_modrm(*data, &mod, ®op, &rm);
2219 AppendToBuffer("movapd %s,", NameOfXMMRegister(regop));
2220 data += PrintRightXMMOperand(data);
2221 } else if (*data == 0x38) {
2222 data++;
2223 byte op = *data;
2224 data++;
2225 int mod, regop, rm;
2226 get_modrm(*data, &mod, ®op, &rm);
2227 switch (op) {
2228 #define SSE34_DIS_CASE(instruction, notUsed1, notUsed2, notUsed3, opcode) \
2229 case 0x##opcode: { \
2230 AppendToBuffer(#instruction " %s,", NameOfXMMRegister(regop)); \
2231 data += PrintRightXMMOperand(data); \
2232 break; \
2233 }
2234
2235 SSSE3_INSTRUCTION_LIST(SSE34_DIS_CASE)
2236 SSSE3_UNOP_INSTRUCTION_LIST(SSE34_DIS_CASE)
2237 SSE4_INSTRUCTION_LIST(SSE34_DIS_CASE)
2238 SSE4_RM_INSTRUCTION_LIST(SSE34_DIS_CASE)
2239 #undef SSE34_DIS_CASE
2240 case 0x10:
2241 AppendToBuffer("pblendvb %s,", NameOfXMMRegister(regop));
2242 data += PrintRightXMMOperand(data);
2243 AppendToBuffer(",xmm0");
2244 break;
2245 case 0x14:
2246 AppendToBuffer("blendvps %s,", NameOfXMMRegister(regop));
2247 data += PrintRightXMMOperand(data);
2248 AppendToBuffer(",xmm0");
2249 break;
2250 case 0x15:
2251 AppendToBuffer("blendvps %s,", NameOfXMMRegister(regop));
2252 data += PrintRightXMMOperand(data);
2253 AppendToBuffer(",xmm0");
2254 break;
2255 case 0x37:
2256 AppendToBuffer("pcmpgtq %s,", NameOfXMMRegister(regop));
2257 data += PrintRightXMMOperand(data);
2258 break;
2259 default:
2260 UnimplementedInstruction();
2261 }
2262 } else if (*data == 0x3A) {
2263 data++;
2264 if (*data >= 0x08 && *data <= 0x0B) {
2265 const char* const pseudo_op[] = {
2266 "roundps",
2267 "roundpd",
2268 "roundss",
2269 "roundsd",
2270 };
2271 byte op = *data;
2272 data++;
2273 int mod, regop, rm;
2274 get_modrm(*data, &mod, ®op, &rm);
2275 int8_t imm8 = static_cast<int8_t>(data[1]);
2276 AppendToBuffer("%s %s,%s,%d", pseudo_op[op - 0x08],
2277 NameOfXMMRegister(regop), NameOfXMMRegister(rm),
2278 static_cast<int>(imm8));
2279 data += 2;
2280 } else if (*data == 0x0E) {
2281 data++;
2282 int mod, regop, rm;
2283 get_modrm(*data, &mod, ®op, &rm);
2284 AppendToBuffer("pblendw %s,", NameOfXMMRegister(regop));
2285 data += PrintRightXMMOperand(data);
2286 AppendToBuffer(",%d", Imm8_U(data));
2287 data++;
2288 } else if (*data == 0x0F) {
2289 data++;
2290 int mod, regop, rm;
2291 get_modrm(*data, &mod, ®op, &rm);
2292 AppendToBuffer("palignr %s,", NameOfXMMRegister(regop));
2293 data += PrintRightXMMOperand(data);
2294 AppendToBuffer(",%d", Imm8_U(data));
2295 data++;
2296 } else if (*data == 0x14) {
2297 data++;
2298 int mod, regop, rm;
2299 get_modrm(*data, &mod, ®op, &rm);
2300 AppendToBuffer("pextrb ");
2301 data += PrintRightOperand(data);
2302 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(data));
2303 data++;
2304 } else if (*data == 0x15) {
2305 data++;
2306 int mod, regop, rm;
2307 get_modrm(*data, &mod, ®op, &rm);
2308 AppendToBuffer("pextrw ");
2309 data += PrintRightOperand(data);
2310 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(data));
2311 data++;
2312 } else if (*data == 0x16) {
2313 data++;
2314 int mod, regop, rm;
2315 get_modrm(*data, &mod, ®op, &rm);
2316 AppendToBuffer("pextrd ");
2317 data += PrintRightOperand(data);
2318 AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(data));
2319 data++;
2320 } else if (*data == 0x17) {
2321 data++;
2322 int mod, regop, rm;
2323 get_modrm(*data, &mod, ®op, &rm);
2324 int8_t imm8 = static_cast<int8_t>(data[1]);
2325 AppendToBuffer("extractps %s,%s,%d", NameOfCPURegister(rm),
2326 NameOfXMMRegister(regop), static_cast<int>(imm8));
2327 data += 2;
2328 } else if (*data == 0x20) {
2329 data++;
2330 int mod, regop, rm;
2331 get_modrm(*data, &mod, ®op, &rm);
2332 AppendToBuffer("pinsrb %s,", NameOfXMMRegister(regop));
2333 data += PrintRightOperand(data);
2334 AppendToBuffer(",%d", Imm8(data));
2335 data++;
2336 } else if (*data == 0x21) {
2337 data++;
2338 int mod, regop, rm;
2339 get_modrm(*data, &mod, ®op, &rm);
2340 AppendToBuffer("insertps %s,", NameOfXMMRegister(regop));
2341 data += PrintRightXMMOperand(data);
2342 AppendToBuffer(",%d", Imm8(data));
2343 data++;
2344 } else if (*data == 0x22) {
2345 data++;
2346 int mod, regop, rm;
2347 get_modrm(*data, &mod, ®op, &rm);
2348 AppendToBuffer("pinsrd %s,", NameOfXMMRegister(regop));
2349 data += PrintRightOperand(data);
2350 AppendToBuffer(",%d", Imm8(data));
2351 data++;
2352 } else {
2353 UnimplementedInstruction();
2354 }
2355 } else if (*data == 0x2E || *data == 0x2F) {
2356 const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
2357 data++;
2358 int mod, regop, rm;
2359 get_modrm(*data, &mod, ®op, &rm);
2360 if (mod == 0x3) {
2361 AppendToBuffer("%s %s,%s", mnem, NameOfXMMRegister(regop),
2362 NameOfXMMRegister(rm));
2363 data++;
2364 } else {
2365 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2366 data += PrintRightOperand(data);
2367 }
2368 } else if (*data == 0x50) {
2369 data++;
2370 int mod, regop, rm;
2371 get_modrm(*data, &mod, ®op, &rm);
2372 AppendToBuffer("movmskpd %s,%s", NameOfCPURegister(regop),
2373 NameOfXMMRegister(rm));
2374 data++;
2375 } else if (*data >= 0x54 && *data <= 0x5A) {
2376 const char* const pseudo_op[] = {"andpd", "andnpd", "orpd",
2377 "xorpd", "addpd", "mulpd",
2378 "cvtpd2ps"};
2379 byte op = *data;
2380 data++;
2381 int mod, regop, rm;
2382 get_modrm(*data, &mod, ®op, &rm);
2383 AppendToBuffer("%s %s,", pseudo_op[op - 0x54],
2384 NameOfXMMRegister(regop));
2385 data += PrintRightXMMOperand(data);
2386 } else if (*data >= 0x5c && *data <= 0x5f) {
2387 const char* const pseudo_op[] = {
2388 "subpd",
2389 "minpd",
2390 "divpd",
2391 "maxpd",
2392 };
2393 byte op = *data;
2394 data++;
2395 int mod, regop, rm;
2396 get_modrm(*data, &mod, ®op, &rm);
2397 AppendToBuffer("%s %s,", pseudo_op[op - 0x5c],
2398 NameOfXMMRegister(regop));
2399 data += PrintRightXMMOperand(data);
2400 } else if (*data == 0x6E) {
2401 data++;
2402 int mod, regop, rm;
2403 get_modrm(*data, &mod, ®op, &rm);
2404 AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
2405 data += PrintRightOperand(data);
2406 } else if (*data == 0x6F) {
2407 data++;
2408 int mod, regop, rm;
2409 get_modrm(*data, &mod, ®op, &rm);
2410 AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
2411 data += PrintRightXMMOperand(data);
2412 } else if (*data == 0x70) {
2413 data++;
2414 int mod, regop, rm;
2415 get_modrm(*data, &mod, ®op, &rm);
2416 AppendToBuffer("pshufd %s,", NameOfXMMRegister(regop));
2417 data += PrintRightXMMOperand(data);
2418 AppendToBuffer(",%d", Imm8(data));
2419 data++;
2420 } else if (*data == 0x90) {
2421 data++;
2422 AppendToBuffer("nop"); // 2 byte nop.
2423 } else if (*data == 0x71) {
2424 data++;
2425 int mod, regop, rm;
2426 get_modrm(*data, &mod, ®op, &rm);
2427 int8_t imm8 = static_cast<int8_t>(data[1]);
2428 AppendToBuffer("ps%sw %s,%d", sf_str[regop / 2],
2429 NameOfXMMRegister(rm), static_cast<int>(imm8));
2430 data += 2;
2431 } else if (*data == 0x72) {
2432 data++;
2433 int mod, regop, rm;
2434 get_modrm(*data, &mod, ®op, &rm);
2435 int8_t imm8 = static_cast<int8_t>(data[1]);
2436 AppendToBuffer("ps%sd %s,%d", sf_str[regop / 2],
2437 NameOfXMMRegister(rm), static_cast<int>(imm8));
2438 data += 2;
2439 } else if (*data == 0x73) {
2440 data++;
2441 int mod, regop, rm;
2442 get_modrm(*data, &mod, ®op, &rm);
2443 int8_t imm8 = static_cast<int8_t>(data[1]);
2444 DCHECK(regop == esi || regop == edx);
2445 AppendToBuffer("ps%sq %s,%d", sf_str[regop / 2],
2446 NameOfXMMRegister(rm), static_cast<int>(imm8));
2447 data += 2;
2448 } else if (*data == 0x7F) {
2449 AppendToBuffer("movdqa ");
2450 data++;
2451 int mod, regop, rm;
2452 get_modrm(*data, &mod, ®op, &rm);
2453 data += PrintRightXMMOperand(data);
2454 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2455 } else if (*data == 0x7E) {
2456 data++;
2457 int mod, regop, rm;
2458 get_modrm(*data, &mod, ®op, &rm);
2459 AppendToBuffer("movd ");
2460 data += PrintRightOperand(data);
2461 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2462 } else if (*data == 0xC1) {
2463 data += 2;
2464 data += PrintOperands("xadd_w", OPER_REG_OP_ORDER, data);
2465 } else if (*data == 0xC2) {
2466 data++;
2467 int mod, regop, rm;
2468 get_modrm(*data, &mod, ®op, &rm);
2469 AppendToBuffer("cmppd %s, ", NameOfXMMRegister(regop));
2470 data += PrintRightXMMOperand(data);
2471 AppendToBuffer(", (%s)", cmp_pseudo_op[*data]);
2472 data++;
2473 } else if (*data == 0xC4) {
2474 data++;
2475 int mod, regop, rm;
2476 get_modrm(*data, &mod, ®op, &rm);
2477 AppendToBuffer("pinsrw %s,", NameOfXMMRegister(regop));
2478 data += PrintRightOperand(data);
2479 AppendToBuffer(",%d", Imm8(data));
2480 data++;
2481 } else if (*data == 0xC6) {
2482 // shufpd xmm, xmm/m128, imm8
2483 data++;
2484 int mod, regop, rm;
2485 get_modrm(*data, &mod, ®op, &rm);
2486 AppendToBuffer("shufpd %s,", NameOfXMMRegister(regop));
2487 data += PrintRightXMMOperand(data);
2488 AppendToBuffer(",%d", Imm8(data));
2489 data++;
2490 } else if (*data == 0xE6) {
2491 data++;
2492 int mod, regop, rm;
2493 get_modrm(*data, &mod, ®op, &rm);
2494 AppendToBuffer("cvttpd2dq %s,", NameOfXMMRegister(regop));
2495 data += PrintRightXMMOperand(data);
2496 } else if (*data == 0xE7) {
2497 data++;
2498 int mod, regop, rm;
2499 get_modrm(*data, &mod, ®op, &rm);
2500 if (mod == 3) {
2501 // movntdq
2502 UnimplementedInstruction();
2503 } else {
2504 UnimplementedInstruction();
2505 }
2506 } else if (*data == 0xB1) {
2507 data++;
2508 data += PrintOperands("cmpxchg_w", OPER_REG_OP_ORDER, data);
2509 } else if (*data == 0xD7) {
2510 data++;
2511 int mod, regop, rm;
2512 get_modrm(*data, &mod, ®op, &rm);
2513 AppendToBuffer("pmovmskb %s,%s", NameOfCPURegister(regop),
2514 NameOfXMMRegister(rm));
2515 data++;
2516 } else {
2517 byte op = *data;
2518 data++;
2519 int mod, regop, rm;
2520 get_modrm(*data, &mod, ®op, &rm);
2521 switch (op) {
2522 #define SSE2_DIS_CASE(instruction, notUsed1, notUsed2, opcode) \
2523 case 0x##opcode: { \
2524 AppendToBuffer(#instruction " %s,", NameOfXMMRegister(regop)); \
2525 data += PrintRightXMMOperand(data); \
2526 break; \
2527 }
2528
2529 SSE2_INSTRUCTION_LIST(SSE2_DIS_CASE)
2530 #undef SSE2_DIS_CASE
2531 default:
2532 UnimplementedInstruction();
2533 }
2534 }
2535 } else {
2536 UnimplementedInstruction();
2537 }
2538 break;
2539
2540 case 0xFE: {
2541 data++;
2542 int mod, regop, rm;
2543 get_modrm(*data, &mod, ®op, &rm);
2544 if (regop == ecx) {
2545 AppendToBuffer("dec_b ");
2546 data += PrintRightOperand(data);
2547 } else {
2548 UnimplementedInstruction();
2549 }
2550 } break;
2551
2552 case 0x68:
2553 AppendToBuffer("push 0x%x", Imm32(data + 1));
2554 data += 5;
2555 break;
2556
2557 case 0x6A:
2558 AppendToBuffer("push 0x%x", Imm8(data + 1));
2559 data += 2;
2560 break;
2561
2562 case 0xA8:
2563 AppendToBuffer("test al,0x%x", Imm8_U(data + 1));
2564 data += 2;
2565 break;
2566
2567 case 0xA9:
2568 AppendToBuffer("test eax,0x%x", Imm32(data + 1));
2569 data += 5;
2570 break;
2571
2572 case 0xD1: // fall through
2573 case 0xD3: // fall through
2574 case 0xC1:
2575 data += D1D3C1Instruction(data);
2576 break;
2577
2578 case 0xD8: // fall through
2579 case 0xD9: // fall through
2580 case 0xDA: // fall through
2581 case 0xDB: // fall through
2582 case 0xDC: // fall through
2583 case 0xDD: // fall through
2584 case 0xDE: // fall through
2585 case 0xDF:
2586 data += FPUInstruction(data);
2587 break;
2588
2589 case 0xEB:
2590 data += JumpShort(data);
2591 break;
2592
2593 case 0xF2:
2594 if (*(data + 1) == 0x0F) {
2595 byte b2 = *(data + 2);
2596 if (b2 == 0x11) {
2597 AppendToBuffer("movsd ");
2598 data += 3;
2599 int mod, regop, rm;
2600 get_modrm(*data, &mod, ®op, &rm);
2601 data += PrintRightXMMOperand(data);
2602 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2603 } else if (b2 == 0x10) {
2604 data += 3;
2605 int mod, regop, rm;
2606 get_modrm(*data, &mod, ®op, &rm);
2607 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
2608 data += PrintRightXMMOperand(data);
2609 } else if (b2 == 0x12) {
2610 data += 3;
2611 int mod, regop, rm;
2612 get_modrm(*data, &mod, ®op, &rm);
2613 AppendToBuffer("movddup %s,", NameOfXMMRegister(regop));
2614 data += PrintRightXMMOperand(data);
2615 } else if (b2 == 0x5A) {
2616 data += 3;
2617 int mod, regop, rm;
2618 get_modrm(*data, &mod, ®op, &rm);
2619 AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
2620 data += PrintRightXMMOperand(data);
2621 } else if (b2 == 0x70) {
2622 data += 3;
2623 int mod, regop, rm;
2624 get_modrm(*data, &mod, ®op, &rm);
2625 AppendToBuffer("pshuflw %s,", NameOfXMMRegister(regop));
2626 data += PrintRightXMMOperand(data);
2627 AppendToBuffer(",%d", Imm8(data));
2628 data++;
2629 } else {
2630 const char* mnem = "?";
2631 switch (b2) {
2632 case 0x2A:
2633 mnem = "cvtsi2sd";
2634 break;
2635 case 0x2C:
2636 mnem = "cvttsd2si";
2637 break;
2638 case 0x2D:
2639 mnem = "cvtsd2si";
2640 break;
2641 case 0x7C:
2642 mnem = "haddps";
2643 break;
2644 #define MNEM_FOR_SSE2_INSTRUCTION_LSIT_SD(instruction, _1, _2, opcode) \
2645 case 0x##opcode: \
2646 mnem = "" #instruction; \
2647 break;
2648 SSE2_INSTRUCTION_LIST_SD(MNEM_FOR_SSE2_INSTRUCTION_LSIT_SD)
2649 #undef MNEM_FOR_SSE2_INSTRUCTION_LSIT_SD
2650 }
2651 data += 3;
2652 int mod, regop, rm;
2653 get_modrm(*data, &mod, ®op, &rm);
2654 if (b2 == 0x2A) {
2655 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2656 data += PrintRightOperand(data);
2657 } else if (b2 == 0x2C || b2 == 0x2D) {
2658 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
2659 data += PrintRightXMMOperand(data);
2660 } else if (b2 == 0xC2) {
2661 // Intel manual 2A, Table 3-18.
2662 AppendToBuffer("cmp%ssd %s,%s", cmp_pseudo_op[data[1]],
2663 NameOfXMMRegister(regop), NameOfXMMRegister(rm));
2664 data += 2;
2665 } else {
2666 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2667 data += PrintRightXMMOperand(data);
2668 }
2669 }
2670 } else {
2671 UnimplementedInstruction();
2672 data++;
2673 }
2674 break;
2675
2676 case 0xF3:
2677 if (*(data + 1) == 0x0F) {
2678 byte b2 = *(data + 2);
2679 if (b2 == 0x11) {
2680 AppendToBuffer("movss ");
2681 data += 3;
2682 int mod, regop, rm;
2683 get_modrm(*data, &mod, ®op, &rm);
2684 data += PrintRightXMMOperand(data);
2685 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2686 } else if (b2 == 0x10) {
2687 data += 3;
2688 int mod, regop, rm;
2689 get_modrm(*data, &mod, ®op, &rm);
2690 AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
2691 data += PrintRightXMMOperand(data);
2692 } else if (b2 == 0x16) {
2693 data += 3;
2694 int mod, regop, rm;
2695 get_modrm(*data, &mod, ®op, &rm);
2696 AppendToBuffer("movshdup %s,", NameOfXMMRegister(regop));
2697 data += PrintRightXMMOperand(data);
2698 } else if (b2 == 0x5A) {
2699 data += 3;
2700 int mod, regop, rm;
2701 get_modrm(*data, &mod, ®op, &rm);
2702 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
2703 data += PrintRightXMMOperand(data);
2704 } else if (b2 == 0x6F) {
2705 data += 3;
2706 int mod, regop, rm;
2707 get_modrm(*data, &mod, ®op, &rm);
2708 AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
2709 data += PrintRightXMMOperand(data);
2710 } else if (b2 == 0x70) {
2711 data += 3;
2712 int mod, regop, rm;
2713 get_modrm(*data, &mod, ®op, &rm);
2714 AppendToBuffer("pshufhw %s,", NameOfXMMRegister(regop));
2715 data += PrintRightXMMOperand(data);
2716 AppendToBuffer(",%d", Imm8(data));
2717 data++;
2718 } else if (b2 == 0x7F) {
2719 AppendToBuffer("movdqu ");
2720 data += 3;
2721 int mod, regop, rm;
2722 get_modrm(*data, &mod, ®op, &rm);
2723 data += PrintRightXMMOperand(data);
2724 AppendToBuffer(",%s", NameOfXMMRegister(regop));
2725 } else if (b2 == 0xB8) {
2726 data += 3;
2727 int mod, regop, rm;
2728 get_modrm(*data, &mod, ®op, &rm);
2729 AppendToBuffer("popcnt %s,", NameOfCPURegister(regop));
2730 data += PrintRightOperand(data);
2731 } else if (b2 == 0xBC) {
2732 data += 3;
2733 int mod, regop, rm;
2734 get_modrm(*data, &mod, ®op, &rm);
2735 AppendToBuffer("tzcnt %s,", NameOfCPURegister(regop));
2736 data += PrintRightOperand(data);
2737 } else if (b2 == 0xBD) {
2738 data += 3;
2739 int mod, regop, rm;
2740 get_modrm(*data, &mod, ®op, &rm);
2741 AppendToBuffer("lzcnt %s,", NameOfCPURegister(regop));
2742 data += PrintRightOperand(data);
2743 } else if (b2 == 0xE6) {
2744 data += 3;
2745 int mod, regop, rm;
2746 get_modrm(*data, &mod, ®op, &rm);
2747 AppendToBuffer("cvtdq2pd %s", NameOfXMMRegister(regop));
2748 data += PrintRightXMMOperand(data);
2749 } else {
2750 const char* mnem = "?";
2751 switch (b2) {
2752 case 0x2A:
2753 mnem = "cvtsi2ss";
2754 break;
2755 case 0x2C:
2756 mnem = "cvttss2si";
2757 break;
2758 case 0x2D:
2759 mnem = "cvtss2si";
2760 break;
2761 case 0x51:
2762 mnem = "sqrtss";
2763 break;
2764 case 0x58:
2765 mnem = "addss";
2766 break;
2767 case 0x59:
2768 mnem = "mulss";
2769 break;
2770 case 0x5B:
2771 mnem = "cvttps2dq";
2772 break;
2773 case 0x5C:
2774 mnem = "subss";
2775 break;
2776 case 0x5D:
2777 mnem = "minss";
2778 break;
2779 case 0x5E:
2780 mnem = "divss";
2781 break;
2782 case 0x5F:
2783 mnem = "maxss";
2784 break;
2785 case 0x7E:
2786 mnem = "movq";
2787 break;
2788 }
2789 data += 3;
2790 int mod, regop, rm;
2791 get_modrm(*data, &mod, ®op, &rm);
2792 if (b2 == 0x2A) {
2793 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2794 data += PrintRightOperand(data);
2795 } else if (b2 == 0x2C || b2 == 0x2D) {
2796 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
2797 data += PrintRightXMMOperand(data);
2798 } else if (b2 == 0xC2) {
2799 // Intel manual 2A, Table 3-18.
2800 AppendToBuffer("cmp%sss %s,%s", cmp_pseudo_op[data[1]],
2801 NameOfXMMRegister(regop), NameOfXMMRegister(rm));
2802 data += 2;
2803 } else {
2804 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2805 data += PrintRightXMMOperand(data);
2806 }
2807 }
2808 } else if (*(data + 1) == 0xA5) {
2809 data += 2;
2810 AppendToBuffer("rep_movs");
2811 } else if (*(data + 1) == 0xAB) {
2812 data += 2;
2813 AppendToBuffer("rep_stos");
2814 } else if (*(data + 1) == 0x90) {
2815 data += 2;
2816 AppendToBuffer("pause");
2817 } else {
2818 UnimplementedInstruction();
2819 }
2820 break;
2821
2822 case 0xF7:
2823 data += F7Instruction(data);
2824 break;
2825
2826 default:
2827 UnimplementedInstruction();
2828 data++;
2829 }
2830 }
2831
2832 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
2833 tmp_buffer_[tmp_buffer_pos_] = '\0';
2834 }
2835
2836 int instr_len = data - instr;
2837 if (instr_len == 0) {
2838 printf("%02x", *data);
2839 }
2840 DCHECK_GT(instr_len, 0); // Ensure progress.
2841
2842 int outp = 0;
2843 // Instruction bytes.
2844 for (byte* bp = instr; bp < data; bp++) {
2845 outp += v8::base::SNPrintF(out_buffer + outp, "%02x", *bp);
2846 }
2847 // Indent instruction, leaving space for 6 bytes, i.e. 12 characters in hex.
2848 while (outp < 12) {
2849 outp += v8::base::SNPrintF(out_buffer + outp, " ");
2850 }
2851
2852 outp += v8::base::SNPrintF(out_buffer + outp, " %s", tmp_buffer_.begin());
2853 return instr_len;
2854 }
2855
2856 //------------------------------------------------------------------------------
2857
2858 static const char* const cpu_regs[8] = {"eax", "ecx", "edx", "ebx",
2859 "esp", "ebp", "esi", "edi"};
2860
2861 static const char* const byte_cpu_regs[8] = {"al", "cl", "dl", "bl",
2862 "ah", "ch", "dh", "bh"};
2863
2864 static const char* const xmm_regs[8] = {"xmm0", "xmm1", "xmm2", "xmm3",
2865 "xmm4", "xmm5", "xmm6", "xmm7"};
2866
NameOfAddress(byte * addr) const2867 const char* NameConverter::NameOfAddress(byte* addr) const {
2868 v8::base::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr));
2869 return tmp_buffer_.begin();
2870 }
2871
NameOfConstant(byte * addr) const2872 const char* NameConverter::NameOfConstant(byte* addr) const {
2873 return NameOfAddress(addr);
2874 }
2875
NameOfCPURegister(int reg) const2876 const char* NameConverter::NameOfCPURegister(int reg) const {
2877 if (0 <= reg && reg < 8) return cpu_regs[reg];
2878 return "noreg";
2879 }
2880
NameOfByteCPURegister(int reg) const2881 const char* NameConverter::NameOfByteCPURegister(int reg) const {
2882 if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
2883 return "noreg";
2884 }
2885
NameOfXMMRegister(int reg) const2886 const char* NameConverter::NameOfXMMRegister(int reg) const {
2887 if (0 <= reg && reg < 8) return xmm_regs[reg];
2888 return "noxmmreg";
2889 }
2890
NameInCode(byte * addr) const2891 const char* NameConverter::NameInCode(byte* addr) const {
2892 // IA32 does not embed debug strings at the moment.
2893 UNREACHABLE();
2894 }
2895
2896 //------------------------------------------------------------------------------
2897
InstructionDecode(v8::base::Vector<char> buffer,byte * instruction)2898 int Disassembler::InstructionDecode(v8::base::Vector<char> buffer,
2899 byte* instruction) {
2900 DisassemblerIA32 d(converter_, unimplemented_opcode_action());
2901 return d.InstructionDecode(buffer, instruction);
2902 }
2903
2904 // The IA-32 assembler does not currently use constant pools.
ConstantPoolSizeAt(byte * instruction)2905 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
2906
2907 // static
Disassemble(FILE * f,byte * begin,byte * end,UnimplementedOpcodeAction unimplemented_action)2908 void Disassembler::Disassemble(FILE* f, byte* begin, byte* end,
2909 UnimplementedOpcodeAction unimplemented_action) {
2910 NameConverter converter;
2911 Disassembler d(converter, unimplemented_action);
2912 for (byte* pc = begin; pc < end;) {
2913 v8::base::EmbeddedVector<char, 128> buffer;
2914 buffer[0] = '\0';
2915 byte* prev_pc = pc;
2916 pc += d.InstructionDecode(buffer, pc);
2917 fprintf(f, "%p", static_cast<void*>(prev_pc));
2918 fprintf(f, " ");
2919
2920 for (byte* bp = prev_pc; bp < pc; bp++) {
2921 fprintf(f, "%02x", *bp);
2922 }
2923 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
2924 fprintf(f, " ");
2925 }
2926 fprintf(f, " %s\n", buffer.begin());
2927 }
2928 }
2929
2930 } // namespace disasm
2931
2932 #endif // V8_TARGET_ARCH_IA32
2933