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