• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 0x08:
795         AppendToBuffer("vroundps %s,", NameOfXMMRegister(regop));
796         current += PrintRightXMMOperand(current);
797         AppendToBuffer(",%d", Imm8_U(current));
798         current++;
799         break;
800       case 0x09:
801         AppendToBuffer("vroundpd %s,", NameOfXMMRegister(regop));
802         current += PrintRightXMMOperand(current);
803         AppendToBuffer(",%d", Imm8_U(current));
804         current++;
805         break;
806       case 0x0E:
807         AppendToBuffer("vpblendw %s,%s,", NameOfXMMRegister(regop),
808                        NameOfXMMRegister(vvvv));
809         current += PrintRightXMMOperand(current);
810         AppendToBuffer(",%d", Imm8_U(current));
811         current++;
812         break;
813       case 0x0F:
814         AppendToBuffer("vpalignr %s,%s,", NameOfXMMRegister(regop),
815                        NameOfXMMRegister(vvvv));
816         current += PrintRightXMMOperand(current);
817         AppendToBuffer(",%d", Imm8_U(current));
818         current++;
819         break;
820       case 0x14:
821         AppendToBuffer("vpextrb ");
822         current += PrintRightOperand(current);
823         AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(current));
824         current++;
825         break;
826       case 0x15:
827         AppendToBuffer("vpextrw ");
828         current += PrintRightOperand(current);
829         AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(current));
830         current++;
831         break;
832       case 0x16:
833         AppendToBuffer("vpextrd ");
834         current += PrintRightOperand(current);
835         AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(current));
836         current++;
837         break;
838       case 0x20:
839         AppendToBuffer("vpinsrb %s,%s,", NameOfXMMRegister(regop),
840                        NameOfXMMRegister(vvvv));
841         current += PrintRightOperand(current);
842         AppendToBuffer(",%d", Imm8(current));
843         current++;
844         break;
845       case 0x21:
846         AppendToBuffer("vinsertps %s,%s,", NameOfXMMRegister(regop),
847                        NameOfXMMRegister(vvvv));
848         current += PrintRightXMMOperand(current);
849         AppendToBuffer(",%d", Imm8(current));
850         current++;
851         break;
852       case 0x22:
853         AppendToBuffer("vpinsrd %s,%s,", NameOfXMMRegister(regop),
854                        NameOfXMMRegister(vvvv));
855         current += PrintRightOperand(current);
856         AppendToBuffer(",%d", Imm8(current));
857         current++;
858         break;
859       default:
860         UnimplementedInstruction();
861     }
862   } else if (vex_f2() && vex_0f()) {
863     int mod, regop, rm, vvvv = vex_vreg();
864     get_modrm(*current, &mod, &regop, &rm);
865     switch (opcode) {
866       case 0x12:
867         AppendToBuffer("vmovddup %s,", NameOfXMMRegister(regop));
868         current += PrintRightXMMOperand(current);
869         break;
870       case 0x51:
871         AppendToBuffer("vsqrtsd %s,%s,", NameOfXMMRegister(regop),
872                        NameOfXMMRegister(vvvv));
873         current += PrintRightXMMOperand(current);
874         break;
875       case 0x58:
876         AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
877                        NameOfXMMRegister(vvvv));
878         current += PrintRightXMMOperand(current);
879         break;
880       case 0x59:
881         AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
882                        NameOfXMMRegister(vvvv));
883         current += PrintRightXMMOperand(current);
884         break;
885       case 0x5C:
886         AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
887                        NameOfXMMRegister(vvvv));
888         current += PrintRightXMMOperand(current);
889         break;
890       case 0x5D:
891         AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop),
892                        NameOfXMMRegister(vvvv));
893         current += PrintRightXMMOperand(current);
894         break;
895       case 0x5E:
896         AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
897                        NameOfXMMRegister(vvvv));
898         current += PrintRightXMMOperand(current);
899         break;
900       case 0x5F:
901         AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop),
902                        NameOfXMMRegister(vvvv));
903         current += PrintRightXMMOperand(current);
904         break;
905       case 0x70:
906         AppendToBuffer("vpshuflw %s,", NameOfXMMRegister(regop));
907         current += PrintRightXMMOperand(current);
908         AppendToBuffer(",%d", Imm8(current));
909         current++;
910         break;
911       case 0x7C:
912         AppendToBuffer("vhaddps %s,%s,", NameOfXMMRegister(regop),
913                        NameOfXMMRegister(vvvv));
914         current += PrintRightXMMOperand(current);
915         break;
916       default:
917         UnimplementedInstruction();
918     }
919   } else if (vex_f3() && vex_0f()) {
920     int mod, regop, rm, vvvv = vex_vreg();
921     get_modrm(*current, &mod, &regop, &rm);
922     switch (opcode) {
923       case 0x51:
924         AppendToBuffer("vsqrtss %s,%s,", NameOfXMMRegister(regop),
925                        NameOfXMMRegister(vvvv));
926         current += PrintRightXMMOperand(current);
927         break;
928       case 0x58:
929         AppendToBuffer("vaddss %s,%s,", NameOfXMMRegister(regop),
930                        NameOfXMMRegister(vvvv));
931         current += PrintRightXMMOperand(current);
932         break;
933       case 0x59:
934         AppendToBuffer("vmulss %s,%s,", NameOfXMMRegister(regop),
935                        NameOfXMMRegister(vvvv));
936         current += PrintRightXMMOperand(current);
937         break;
938       case 0x5B:
939         AppendToBuffer("vcvttps2dq %s,", NameOfXMMRegister(regop));
940         current += PrintRightXMMOperand(current);
941         break;
942       case 0x5C:
943         AppendToBuffer("vsubss %s,%s,", NameOfXMMRegister(regop),
944                        NameOfXMMRegister(vvvv));
945         current += PrintRightXMMOperand(current);
946         break;
947       case 0x5D:
948         AppendToBuffer("vminss %s,%s,", NameOfXMMRegister(regop),
949                        NameOfXMMRegister(vvvv));
950         current += PrintRightXMMOperand(current);
951         break;
952       case 0x5E:
953         AppendToBuffer("vdivss %s,%s,", NameOfXMMRegister(regop),
954                        NameOfXMMRegister(vvvv));
955         current += PrintRightXMMOperand(current);
956         break;
957       case 0x5F:
958         AppendToBuffer("vmaxss %s,%s,", NameOfXMMRegister(regop),
959                        NameOfXMMRegister(vvvv));
960         current += PrintRightXMMOperand(current);
961         break;
962       case 0x6f:
963         AppendToBuffer("vmovdqu %s,", NameOfXMMRegister(regop));
964         current += PrintRightOperand(current);
965         break;
966       case 0x70:
967         AppendToBuffer("vpshufhw %s,", NameOfXMMRegister(regop));
968         current += PrintRightXMMOperand(current);
969         AppendToBuffer(",%d", Imm8(current));
970         current++;
971         break;
972       case 0x7f:
973         AppendToBuffer("vmovdqu ");
974         current += PrintRightOperand(current);
975         AppendToBuffer(",%s", NameOfXMMRegister(regop));
976         break;
977       default:
978         UnimplementedInstruction();
979     }
980   } else if (vex_none() && vex_0f38()) {
981     int mod, regop, rm, vvvv = vex_vreg();
982     get_modrm(*current, &mod, &regop, &rm);
983     const char* mnem = "?";
984     switch (opcode) {
985       case 0xF2:
986         AppendToBuffer("andn %s,%s,", NameOfCPURegister(regop),
987                        NameOfCPURegister(vvvv));
988         current += PrintRightOperand(current);
989         break;
990       case 0xF5:
991         AppendToBuffer("bzhi %s,", NameOfCPURegister(regop));
992         current += PrintRightOperand(current);
993         AppendToBuffer(",%s", NameOfCPURegister(vvvv));
994         break;
995       case 0xF7:
996         AppendToBuffer("bextr %s,", NameOfCPURegister(regop));
997         current += PrintRightOperand(current);
998         AppendToBuffer(",%s", NameOfCPURegister(vvvv));
999         break;
1000       case 0xF3:
1001         switch (regop) {
1002           case 1:
1003             mnem = "blsr";
1004             break;
1005           case 2:
1006             mnem = "blsmsk";
1007             break;
1008           case 3:
1009             mnem = "blsi";
1010             break;
1011           default:
1012             UnimplementedInstruction();
1013         }
1014         AppendToBuffer("%s %s,", mnem, NameOfCPURegister(vvvv));
1015         current += PrintRightOperand(current);
1016         mnem = "?";
1017         break;
1018       default:
1019         UnimplementedInstruction();
1020     }
1021   } else if (vex_f2() && vex_0f38()) {
1022     int mod, regop, rm, vvvv = vex_vreg();
1023     get_modrm(*current, &mod, &regop, &rm);
1024     switch (opcode) {
1025       case 0xF5:
1026         AppendToBuffer("pdep %s,%s,", NameOfCPURegister(regop),
1027                        NameOfCPURegister(vvvv));
1028         current += PrintRightOperand(current);
1029         break;
1030       case 0xF6:
1031         AppendToBuffer("mulx %s,%s,", NameOfCPURegister(regop),
1032                        NameOfCPURegister(vvvv));
1033         current += PrintRightOperand(current);
1034         break;
1035       case 0xF7:
1036         AppendToBuffer("shrx %s,", NameOfCPURegister(regop));
1037         current += PrintRightOperand(current);
1038         AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1039         break;
1040       default:
1041         UnimplementedInstruction();
1042     }
1043   } else if (vex_f3() && vex_0f38()) {
1044     int mod, regop, rm, vvvv = vex_vreg();
1045     get_modrm(*current, &mod, &regop, &rm);
1046     switch (opcode) {
1047       case 0xF5:
1048         AppendToBuffer("pext %s,%s,", NameOfCPURegister(regop),
1049                        NameOfCPURegister(vvvv));
1050         current += PrintRightOperand(current);
1051         break;
1052       case 0xF7:
1053         AppendToBuffer("sarx %s,", NameOfCPURegister(regop));
1054         current += PrintRightOperand(current);
1055         AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1056         break;
1057       default:
1058         UnimplementedInstruction();
1059     }
1060   } else if (vex_f2() && vex_0f3a()) {
1061     int mod, regop, rm;
1062     get_modrm(*current, &mod, &regop, &rm);
1063     switch (opcode) {
1064       case 0xF0:
1065         AppendToBuffer("rorx %s,", NameOfCPURegister(regop));
1066         current += PrintRightOperand(current);
1067         AppendToBuffer(",%d", *current & 0x1F);
1068         current += 1;
1069         break;
1070       default:
1071         UnimplementedInstruction();
1072     }
1073   } else if (vex_none() && vex_0f()) {
1074     int mod, regop, rm, vvvv = vex_vreg();
1075     get_modrm(*current, &mod, &regop, &rm);
1076     switch (opcode) {
1077       case 0x10:
1078         AppendToBuffer("vmovups %s,", NameOfXMMRegister(regop));
1079         current += PrintRightXMMOperand(current);
1080         break;
1081       case 0x28:
1082         AppendToBuffer("vmovaps %s,", NameOfXMMRegister(regop));
1083         current += PrintRightXMMOperand(current);
1084         break;
1085       case 0x50:
1086         AppendToBuffer("vmovmskps %s,%s", NameOfCPURegister(regop),
1087                        NameOfXMMRegister(rm));
1088         current++;
1089         break;
1090       case 0x51:
1091         AppendToBuffer("vsqrtps %s,", NameOfXMMRegister(regop));
1092         current += PrintRightXMMOperand(current);
1093         break;
1094       case 0x52:
1095         AppendToBuffer("vrsqrtps %s,", NameOfXMMRegister(regop));
1096         current += PrintRightXMMOperand(current);
1097         break;
1098       case 0x53:
1099         AppendToBuffer("vrcpps %s,", NameOfXMMRegister(regop));
1100         current += PrintRightXMMOperand(current);
1101         break;
1102       case 0x54:
1103         AppendToBuffer("vandps %s,%s,", NameOfXMMRegister(regop),
1104                        NameOfXMMRegister(vvvv));
1105         current += PrintRightXMMOperand(current);
1106         break;
1107       case 0x55:
1108         AppendToBuffer("vandnps %s,%s,", NameOfXMMRegister(regop),
1109                        NameOfXMMRegister(vvvv));
1110         current += PrintRightXMMOperand(current);
1111         break;
1112       case 0x56:
1113         AppendToBuffer("vorps %s,%s,", NameOfXMMRegister(regop),
1114                        NameOfXMMRegister(vvvv));
1115         current += PrintRightXMMOperand(current);
1116         break;
1117       case 0x57:
1118         AppendToBuffer("vxorps %s,%s,", NameOfXMMRegister(regop),
1119                        NameOfXMMRegister(vvvv));
1120         current += PrintRightXMMOperand(current);
1121         break;
1122       case 0x58:
1123         AppendToBuffer("vaddps %s,%s,", NameOfXMMRegister(regop),
1124                        NameOfXMMRegister(vvvv));
1125         current += PrintRightXMMOperand(current);
1126         break;
1127       case 0x59:
1128         AppendToBuffer("vmulps %s,%s,", NameOfXMMRegister(regop),
1129                        NameOfXMMRegister(vvvv));
1130         current += PrintRightXMMOperand(current);
1131         break;
1132       case 0x5B:
1133         AppendToBuffer("vcvtdq2ps %s,", NameOfXMMRegister(regop));
1134         current += PrintRightXMMOperand(current);
1135         break;
1136       case 0x5C:
1137         AppendToBuffer("vsubps %s,%s,", NameOfXMMRegister(regop),
1138                        NameOfXMMRegister(vvvv));
1139         current += PrintRightXMMOperand(current);
1140         break;
1141       case 0x5D:
1142         AppendToBuffer("vminps %s,%s,", NameOfXMMRegister(regop),
1143                        NameOfXMMRegister(vvvv));
1144         current += PrintRightXMMOperand(current);
1145         break;
1146       case 0x5E:
1147         AppendToBuffer("vdivps %s,%s,", NameOfXMMRegister(regop),
1148                        NameOfXMMRegister(vvvv));
1149         current += PrintRightXMMOperand(current);
1150         break;
1151       case 0x5F:
1152         AppendToBuffer("vmaxps %s,%s,", NameOfXMMRegister(regop),
1153                        NameOfXMMRegister(vvvv));
1154         current += PrintRightXMMOperand(current);
1155         break;
1156       case 0xC2: {
1157         const char* const pseudo_op[] = {"eq",  "lt",  "le",  "unord",
1158                                          "neq", "nlt", "nle", "ord"};
1159         AppendToBuffer("vcmpps %s,%s,", NameOfXMMRegister(regop),
1160                        NameOfXMMRegister(vvvv));
1161         current += PrintRightXMMOperand(current);
1162         AppendToBuffer(", (%s)", pseudo_op[*current]);
1163         current++;
1164         break;
1165       }
1166       case 0xC6:
1167         AppendToBuffer("vshufps %s,%s,", NameOfXMMRegister(regop),
1168                        NameOfXMMRegister(vvvv));
1169         current += PrintRightXMMOperand(current);
1170         AppendToBuffer(", %d", (*current) & 3);
1171         current += 1;
1172         break;
1173       default:
1174         UnimplementedInstruction();
1175     }
1176   } else if (vex_66() && vex_0f()) {
1177     int mod, regop, rm, vvvv = vex_vreg();
1178     get_modrm(*current, &mod, &regop, &rm);
1179     switch (opcode) {
1180       case 0x10:
1181         AppendToBuffer("vmovupd %s,", NameOfXMMRegister(regop));
1182         current += PrintRightXMMOperand(current);
1183         break;
1184       case 0x28:
1185         AppendToBuffer("vmovapd %s,", NameOfXMMRegister(regop));
1186         current += PrintRightXMMOperand(current);
1187         break;
1188       case 0x54:
1189         AppendToBuffer("vandpd %s,%s,", NameOfXMMRegister(regop),
1190                        NameOfXMMRegister(vvvv));
1191         current += PrintRightXMMOperand(current);
1192         break;
1193       case 0x55:
1194         AppendToBuffer("vandnpd %s,%s,", NameOfXMMRegister(regop),
1195                        NameOfXMMRegister(vvvv));
1196         current += PrintRightXMMOperand(current);
1197         break;
1198       case 0x56:
1199         AppendToBuffer("vorpd %s,%s,", NameOfXMMRegister(regop),
1200                        NameOfXMMRegister(vvvv));
1201         current += PrintRightXMMOperand(current);
1202         break;
1203       case 0x57:
1204         AppendToBuffer("vxorpd %s,%s,", NameOfXMMRegister(regop),
1205                        NameOfXMMRegister(vvvv));
1206         current += PrintRightXMMOperand(current);
1207         break;
1208       case 0x58:
1209         AppendToBuffer("vaddpd %s,%s,", NameOfXMMRegister(regop),
1210                        NameOfXMMRegister(vvvv));
1211         current += PrintRightXMMOperand(current);
1212         break;
1213       case 0x59:
1214         AppendToBuffer("vmulpd %s,%s,", NameOfXMMRegister(regop),
1215                        NameOfXMMRegister(vvvv));
1216         current += PrintRightXMMOperand(current);
1217         break;
1218       case 0x5C:
1219         AppendToBuffer("vsubpd %s,%s,", NameOfXMMRegister(regop),
1220                        NameOfXMMRegister(vvvv));
1221         current += PrintRightXMMOperand(current);
1222         break;
1223       case 0x5D:
1224         AppendToBuffer("vminpd %s,%s,", NameOfXMMRegister(regop),
1225                        NameOfXMMRegister(vvvv));
1226         current += PrintRightXMMOperand(current);
1227         break;
1228       case 0x5E:
1229         AppendToBuffer("vdivpd %s,%s,", NameOfXMMRegister(regop),
1230                        NameOfXMMRegister(vvvv));
1231         current += PrintRightXMMOperand(current);
1232         break;
1233       case 0x5F:
1234         AppendToBuffer("vmaxpd %s,%s,", NameOfXMMRegister(regop),
1235                        NameOfXMMRegister(vvvv));
1236         current += PrintRightXMMOperand(current);
1237         break;
1238       case 0x6E:
1239         AppendToBuffer("vmovd %s,", NameOfXMMRegister(regop));
1240         current += PrintRightOperand(current);
1241         break;
1242       case 0x70:
1243         AppendToBuffer("vpshufd %s,", NameOfXMMRegister(regop));
1244         current += PrintRightXMMOperand(current);
1245         AppendToBuffer(",%d", Imm8(current));
1246         current++;
1247         break;
1248       case 0x71:
1249         AppendToBuffer("vps%sw %s,%s", sf_str[regop / 2],
1250                        NameOfXMMRegister(vvvv), NameOfXMMRegister(rm));
1251         current++;
1252         AppendToBuffer(",%u", *current++);
1253         break;
1254       case 0x72:
1255         AppendToBuffer("vps%sd %s,%s", sf_str[regop / 2],
1256                        NameOfXMMRegister(vvvv), NameOfXMMRegister(rm));
1257         current++;
1258         AppendToBuffer(",%u", *current++);
1259         break;
1260       case 0x73:
1261         AppendToBuffer("vps%sq %s,%s", sf_str[regop / 2],
1262                        NameOfXMMRegister(vvvv), NameOfXMMRegister(rm));
1263         current++;
1264         AppendToBuffer(",%u", *current++);
1265         break;
1266       case 0x7E:
1267         AppendToBuffer("vmovd ");
1268         current += PrintRightOperand(current);
1269         AppendToBuffer(",%s", NameOfXMMRegister(regop));
1270         break;
1271       case 0xC2: {
1272         const char* const pseudo_op[] = {"eq", "lt", "le", "unord", "neq"};
1273         AppendToBuffer("vcmppd %s,%s,", NameOfXMMRegister(regop),
1274                        NameOfXMMRegister(vvvv));
1275         current += PrintRightXMMOperand(current);
1276         AppendToBuffer(", (%s)", pseudo_op[*current]);
1277         current++;
1278         break;
1279       }
1280       case 0xC4:
1281         AppendToBuffer("vpinsrw %s,%s,", NameOfXMMRegister(regop),
1282                        NameOfXMMRegister(vvvv));
1283         current += PrintRightOperand(current);
1284         AppendToBuffer(",%d", Imm8(current));
1285         current++;
1286         break;
1287       case 0xC6:
1288         AppendToBuffer("vshufpd %s,%s,", NameOfXMMRegister(regop),
1289                        NameOfXMMRegister(vvvv));
1290         current += PrintRightXMMOperand(current);
1291         AppendToBuffer(",%d", Imm8(current));
1292         current++;
1293         break;
1294       case 0xD7:
1295         AppendToBuffer("vpmovmskb %s,%s", NameOfCPURegister(regop),
1296                        NameOfXMMRegister(rm));
1297         current++;
1298         break;
1299 #define DECLARE_SSE_AVX_DIS_CASE(instruction, notUsed1, notUsed2, opcode) \
1300   case 0x##opcode: {                                                      \
1301     AppendToBuffer("v" #instruction " %s,%s,", NameOfXMMRegister(regop),  \
1302                    NameOfXMMRegister(vvvv));                              \
1303     current += PrintRightXMMOperand(current);                             \
1304     break;                                                                \
1305   }
1306 
1307         SSE2_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE)
1308 #undef DECLARE_SSE_AVX_DIS_CASE
1309       default:
1310         UnimplementedInstruction();
1311     }
1312   } else {
1313     UnimplementedInstruction();
1314   }
1315 
1316   return static_cast<int>(current - data);
1317 }
1318 
1319 // Returns number of bytes used, including *data.
FPUInstruction(byte * data)1320 int DisassemblerIA32::FPUInstruction(byte* data) {
1321   byte escape_opcode = *data;
1322   DCHECK_EQ(0xD8, escape_opcode & 0xF8);
1323   byte modrm_byte = *(data + 1);
1324 
1325   if (modrm_byte >= 0xC0) {
1326     return RegisterFPUInstruction(escape_opcode, modrm_byte);
1327   } else {
1328     return MemoryFPUInstruction(escape_opcode, modrm_byte, data + 1);
1329   }
1330 }
1331 
MemoryFPUInstruction(int escape_opcode,int modrm_byte,byte * modrm_start)1332 int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode, int modrm_byte,
1333                                            byte* modrm_start) {
1334   const char* mnem = "?";
1335   int regop = (modrm_byte >> 3) & 0x7;  // reg/op field of modrm byte.
1336   switch (escape_opcode) {
1337     case 0xD9:
1338       switch (regop) {
1339         case 0:
1340           mnem = "fld_s";
1341           break;
1342         case 2:
1343           mnem = "fst_s";
1344           break;
1345         case 3:
1346           mnem = "fstp_s";
1347           break;
1348         case 7:
1349           mnem = "fstcw";
1350           break;
1351         default:
1352           UnimplementedInstruction();
1353       }
1354       break;
1355 
1356     case 0xDB:
1357       switch (regop) {
1358         case 0:
1359           mnem = "fild_s";
1360           break;
1361         case 1:
1362           mnem = "fisttp_s";
1363           break;
1364         case 2:
1365           mnem = "fist_s";
1366           break;
1367         case 3:
1368           mnem = "fistp_s";
1369           break;
1370         default:
1371           UnimplementedInstruction();
1372       }
1373       break;
1374 
1375     case 0xDD:
1376       switch (regop) {
1377         case 0:
1378           mnem = "fld_d";
1379           break;
1380         case 1:
1381           mnem = "fisttp_d";
1382           break;
1383         case 2:
1384           mnem = "fst_d";
1385           break;
1386         case 3:
1387           mnem = "fstp_d";
1388           break;
1389         default:
1390           UnimplementedInstruction();
1391       }
1392       break;
1393 
1394     case 0xDF:
1395       switch (regop) {
1396         case 5:
1397           mnem = "fild_d";
1398           break;
1399         case 7:
1400           mnem = "fistp_d";
1401           break;
1402         default:
1403           UnimplementedInstruction();
1404       }
1405       break;
1406 
1407     default:
1408       UnimplementedInstruction();
1409   }
1410   AppendToBuffer("%s ", mnem);
1411   int count = PrintRightOperand(modrm_start);
1412   return count + 1;
1413 }
1414 
RegisterFPUInstruction(int escape_opcode,byte modrm_byte)1415 int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
1416                                              byte modrm_byte) {
1417   bool has_register = false;  // Is the FPU register encoded in modrm_byte?
1418   const char* mnem = "?";
1419 
1420   switch (escape_opcode) {
1421     case 0xD8:
1422       has_register = true;
1423       switch (modrm_byte & 0xF8) {
1424         case 0xC0:
1425           mnem = "fadd_i";
1426           break;
1427         case 0xE0:
1428           mnem = "fsub_i";
1429           break;
1430         case 0xC8:
1431           mnem = "fmul_i";
1432           break;
1433         case 0xF0:
1434           mnem = "fdiv_i";
1435           break;
1436         default:
1437           UnimplementedInstruction();
1438       }
1439       break;
1440 
1441     case 0xD9:
1442       switch (modrm_byte & 0xF8) {
1443         case 0xC0:
1444           mnem = "fld";
1445           has_register = true;
1446           break;
1447         case 0xC8:
1448           mnem = "fxch";
1449           has_register = true;
1450           break;
1451         default:
1452           switch (modrm_byte) {
1453             case 0xE0:
1454               mnem = "fchs";
1455               break;
1456             case 0xE1:
1457               mnem = "fabs";
1458               break;
1459             case 0xE4:
1460               mnem = "ftst";
1461               break;
1462             case 0xE8:
1463               mnem = "fld1";
1464               break;
1465             case 0xEB:
1466               mnem = "fldpi";
1467               break;
1468             case 0xED:
1469               mnem = "fldln2";
1470               break;
1471             case 0xEE:
1472               mnem = "fldz";
1473               break;
1474             case 0xF0:
1475               mnem = "f2xm1";
1476               break;
1477             case 0xF1:
1478               mnem = "fyl2x";
1479               break;
1480             case 0xF4:
1481               mnem = "fxtract";
1482               break;
1483             case 0xF5:
1484               mnem = "fprem1";
1485               break;
1486             case 0xF7:
1487               mnem = "fincstp";
1488               break;
1489             case 0xF8:
1490               mnem = "fprem";
1491               break;
1492             case 0xFC:
1493               mnem = "frndint";
1494               break;
1495             case 0xFD:
1496               mnem = "fscale";
1497               break;
1498             case 0xFE:
1499               mnem = "fsin";
1500               break;
1501             case 0xFF:
1502               mnem = "fcos";
1503               break;
1504             default:
1505               UnimplementedInstruction();
1506           }
1507       }
1508       break;
1509 
1510     case 0xDA:
1511       if (modrm_byte == 0xE9) {
1512         mnem = "fucompp";
1513       } else {
1514         UnimplementedInstruction();
1515       }
1516       break;
1517 
1518     case 0xDB:
1519       if ((modrm_byte & 0xF8) == 0xE8) {
1520         mnem = "fucomi";
1521         has_register = true;
1522       } else if (modrm_byte == 0xE2) {
1523         mnem = "fclex";
1524       } else if (modrm_byte == 0xE3) {
1525         mnem = "fninit";
1526       } else {
1527         UnimplementedInstruction();
1528       }
1529       break;
1530 
1531     case 0xDC:
1532       has_register = true;
1533       switch (modrm_byte & 0xF8) {
1534         case 0xC0:
1535           mnem = "fadd";
1536           break;
1537         case 0xE8:
1538           mnem = "fsub";
1539           break;
1540         case 0xC8:
1541           mnem = "fmul";
1542           break;
1543         case 0xF8:
1544           mnem = "fdiv";
1545           break;
1546         default:
1547           UnimplementedInstruction();
1548       }
1549       break;
1550 
1551     case 0xDD:
1552       has_register = true;
1553       switch (modrm_byte & 0xF8) {
1554         case 0xC0:
1555           mnem = "ffree";
1556           break;
1557         case 0xD0:
1558           mnem = "fst";
1559           break;
1560         case 0xD8:
1561           mnem = "fstp";
1562           break;
1563         default:
1564           UnimplementedInstruction();
1565       }
1566       break;
1567 
1568     case 0xDE:
1569       if (modrm_byte == 0xD9) {
1570         mnem = "fcompp";
1571       } else {
1572         has_register = true;
1573         switch (modrm_byte & 0xF8) {
1574           case 0xC0:
1575             mnem = "faddp";
1576             break;
1577           case 0xE8:
1578             mnem = "fsubp";
1579             break;
1580           case 0xC8:
1581             mnem = "fmulp";
1582             break;
1583           case 0xF8:
1584             mnem = "fdivp";
1585             break;
1586           default:
1587             UnimplementedInstruction();
1588         }
1589       }
1590       break;
1591 
1592     case 0xDF:
1593       if (modrm_byte == 0xE0) {
1594         mnem = "fnstsw_ax";
1595       } else if ((modrm_byte & 0xF8) == 0xE8) {
1596         mnem = "fucomip";
1597         has_register = true;
1598       }
1599       break;
1600 
1601     default:
1602       UnimplementedInstruction();
1603   }
1604 
1605   if (has_register) {
1606     AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1607   } else {
1608     AppendToBuffer("%s", mnem);
1609   }
1610   return 2;
1611 }
1612 
1613 // Mnemonics for instructions 0xF0 byte.
1614 // Returns nullptr if the instruction is not handled here.
F0Mnem(byte f0byte)1615 static const char* F0Mnem(byte f0byte) {
1616   switch (f0byte) {
1617     case 0x0B:
1618       return "ud2";
1619     case 0x18:
1620       return "prefetch";
1621     case 0xA2:
1622       return "cpuid";
1623     case 0xBE:
1624       return "movsx_b";
1625     case 0xBF:
1626       return "movsx_w";
1627     case 0xB6:
1628       return "movzx_b";
1629     case 0xB7:
1630       return "movzx_w";
1631     case 0xAF:
1632       return "imul";
1633     case 0xA4:
1634       return "shld";
1635     case 0xA5:
1636       return "shld";
1637     case 0xAD:
1638       return "shrd";
1639     case 0xAC:
1640       return "shrd";  // 3-operand version.
1641     case 0xAB:
1642       return "bts";
1643     case 0xB0:
1644       return "cmpxchg_b";
1645     case 0xB1:
1646       return "cmpxchg";
1647     case 0xBC:
1648       return "bsf";
1649     case 0xBD:
1650       return "bsr";
1651     case 0xC7:
1652       return "cmpxchg8b";
1653     default:
1654       return nullptr;
1655   }
1656 }
1657 
1658 // Disassembled instruction '*instr' and writes it into 'out_buffer'.
InstructionDecode(v8::internal::Vector<char> out_buffer,byte * instr)1659 int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
1660                                         byte* instr) {
1661   tmp_buffer_pos_ = 0;  // starting to write as position 0
1662   byte* data = instr;
1663   // Check for hints.
1664   const char* branch_hint = nullptr;
1665   // We use these two prefixes only with branch prediction
1666   if (*data == 0x3E /*ds*/) {
1667     branch_hint = "predicted taken";
1668     data++;
1669   } else if (*data == 0x2E /*cs*/) {
1670     branch_hint = "predicted not taken";
1671     data++;
1672   } else if (*data == 0xC4 && *(data + 1) >= 0xC0) {
1673     vex_byte0_ = *data;
1674     vex_byte1_ = *(data + 1);
1675     vex_byte2_ = *(data + 2);
1676     data += 3;
1677   } else if (*data == 0xC5 && *(data + 1) >= 0xC0) {
1678     vex_byte0_ = *data;
1679     vex_byte1_ = *(data + 1);
1680     data += 2;
1681   } else if (*data == 0xF0 /*lock*/) {
1682     AppendToBuffer("lock ");
1683     data++;
1684   }
1685 
1686   bool processed = true;  // Will be set to false if the current instruction
1687                           // is not in 'instructions' table.
1688   // Decode AVX instructions.
1689   if (vex_byte0_ != 0) {
1690     data += AVXInstruction(data);
1691   } else {
1692     const InstructionDesc& idesc = instruction_table_->Get(*data);
1693     switch (idesc.type) {
1694       case ZERO_OPERANDS_INSTR:
1695         AppendToBuffer("%s", idesc.mnem);
1696         data++;
1697         break;
1698 
1699       case TWO_OPERANDS_INSTR:
1700         data++;
1701         data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1702         break;
1703 
1704       case JUMP_CONDITIONAL_SHORT_INSTR:
1705         data += JumpConditionalShort(data, branch_hint);
1706         break;
1707 
1708       case REGISTER_INSTR:
1709         AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
1710         data++;
1711         break;
1712 
1713       case MOVE_REG_INSTR: {
1714         byte* addr = reinterpret_cast<byte*>(Imm32(data + 1));
1715         AppendToBuffer("mov %s,%s", NameOfCPURegister(*data & 0x07),
1716                        NameOfAddress(addr));
1717         data += 5;
1718         break;
1719       }
1720 
1721       case CALL_JUMP_INSTR: {
1722         byte* addr = data + Imm32(data + 1) + 5;
1723         AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1724         data += 5;
1725         break;
1726       }
1727 
1728       case SHORT_IMMEDIATE_INSTR: {
1729         byte* addr = reinterpret_cast<byte*>(Imm32(data + 1));
1730         AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
1731         data += 5;
1732         break;
1733       }
1734 
1735       case BYTE_IMMEDIATE_INSTR: {
1736         AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
1737         data += 2;
1738         break;
1739       }
1740 
1741       case NO_INSTR:
1742         processed = false;
1743         break;
1744 
1745       default:
1746         UNIMPLEMENTED();  // This type is not implemented.
1747     }
1748   }
1749   //----------------------------
1750   if (!processed) {
1751     switch (*data) {
1752       case 0xC2:
1753         AppendToBuffer("ret 0x%x", Imm16_U(data + 1));
1754         data += 3;
1755         break;
1756 
1757       case 0x6B: {
1758         data++;
1759         data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1760         AppendToBuffer(",%d", *data);
1761         data++;
1762       } break;
1763 
1764       case 0x69: {
1765         data++;
1766         data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1767         AppendToBuffer(",%d", Imm32(data));
1768         data += 4;
1769       } break;
1770 
1771       case 0xF6: {
1772         data++;
1773         int mod, regop, rm;
1774         get_modrm(*data, &mod, &regop, &rm);
1775         if (regop == eax) {
1776           AppendToBuffer("test_b ");
1777           data += PrintRightByteOperand(data);
1778           int32_t imm = *data;
1779           AppendToBuffer(",0x%x", imm);
1780           data++;
1781         } else {
1782           UnimplementedInstruction();
1783         }
1784       } break;
1785 
1786       case 0x81:  // fall through
1787       case 0x83:  // 0x81 with sign extension bit set
1788         data += PrintImmediateOp(data);
1789         break;
1790 
1791       case 0x0F: {
1792         byte f0byte = data[1];
1793         const char* f0mnem = F0Mnem(f0byte);
1794         if (f0byte == 0x18) {
1795           data += 2;
1796           int mod, regop, rm;
1797           get_modrm(*data, &mod, &regop, &rm);
1798           const char* suffix[] = {"nta", "1", "2", "3"};
1799           AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1800           data += PrintRightOperand(data);
1801         } else if (f0byte == 0x1F && data[2] == 0) {
1802           AppendToBuffer("nop");  // 3 byte nop.
1803           data += 3;
1804         } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1805           AppendToBuffer("nop");  // 4 byte nop.
1806           data += 4;
1807         } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1808                    data[4] == 0) {
1809           AppendToBuffer("nop");  // 5 byte nop.
1810           data += 5;
1811         } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1812                    data[4] == 0 && data[5] == 0 && data[6] == 0) {
1813           AppendToBuffer("nop");  // 7 byte nop.
1814           data += 7;
1815         } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1816                    data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1817                    data[7] == 0) {
1818           AppendToBuffer("nop");  // 8 byte nop.
1819           data += 8;
1820         } else if (f0byte == 0x0B || f0byte == 0xA2 || f0byte == 0x31) {
1821           AppendToBuffer("%s", f0mnem);
1822           data += 2;
1823         } else if (f0byte == 0x28) {
1824           data += 2;
1825           int mod, regop, rm;
1826           get_modrm(*data, &mod, &regop, &rm);
1827           AppendToBuffer("movaps %s,%s", NameOfXMMRegister(regop),
1828                          NameOfXMMRegister(rm));
1829           data++;
1830         } else if (f0byte == 0x10 || f0byte == 0x11) {
1831           data += 2;
1832           // movups xmm, xmm/m128
1833           // movups xmm/m128, xmm
1834           int mod, regop, rm;
1835           get_modrm(*data, &mod, &regop, &rm);
1836           AppendToBuffer("movups ");
1837           if (f0byte == 0x11) {
1838             data += PrintRightXMMOperand(data);
1839             AppendToBuffer(",%s", NameOfXMMRegister(regop));
1840           } else {
1841             AppendToBuffer("%s,", NameOfXMMRegister(regop));
1842             data += PrintRightXMMOperand(data);
1843           }
1844         } else if (f0byte == 0x2E) {
1845           data += 2;
1846           int mod, regop, rm;
1847           get_modrm(*data, &mod, &regop, &rm);
1848           AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
1849           data += PrintRightXMMOperand(data);
1850         } else if (f0byte >= 0x51 && f0byte <= 0x5F) {
1851           const char* const pseudo_op[] = {
1852               "sqrtps",   "rsqrtps", "rcpps", "andps", "andnps",
1853               "orps",     "xorps",   "addps", "mulps", "cvtps2pd",
1854               "cvtdq2ps", "subps",   "minps", "divps", "maxps",
1855           };
1856 
1857           data += 2;
1858           int mod, regop, rm;
1859           get_modrm(*data, &mod, &regop, &rm);
1860           AppendToBuffer("%s %s,", pseudo_op[f0byte - 0x51],
1861                          NameOfXMMRegister(regop));
1862           data += PrintRightXMMOperand(data);
1863         } else if (f0byte == 0x50) {
1864           data += 2;
1865           int mod, regop, rm;
1866           get_modrm(*data, &mod, &regop, &rm);
1867           AppendToBuffer("movmskps %s,%s", NameOfCPURegister(regop),
1868                          NameOfXMMRegister(rm));
1869           data++;
1870         } else if (f0byte == 0xC0) {
1871           data += 2;
1872           data += PrintOperands("xadd_b", OPER_REG_OP_ORDER, data);
1873         } else if (f0byte == 0xC1) {
1874           data += 2;
1875           data += PrintOperands("xadd", OPER_REG_OP_ORDER, data);
1876         } else if (f0byte == 0xC2) {
1877           data += 2;
1878           int mod, regop, rm;
1879           get_modrm(*data, &mod, &regop, &rm);
1880           const char* const pseudo_op[] = {"eq",  "lt",  "le",  "unord",
1881                                            "neq", "nlt", "nle", "ord"};
1882           AppendToBuffer("cmpps %s, ", NameOfXMMRegister(regop));
1883           data += PrintRightXMMOperand(data);
1884           AppendToBuffer(", (%s)", pseudo_op[*data]);
1885           data++;
1886         } else if (f0byte == 0xC6) {
1887           // shufps xmm, xmm/m128, imm8
1888           data += 2;
1889           int mod, regop, rm;
1890           get_modrm(*data, &mod, &regop, &rm);
1891           int8_t imm8 = static_cast<int8_t>(data[1]);
1892           AppendToBuffer("shufps %s,%s,%d", NameOfXMMRegister(rm),
1893                          NameOfXMMRegister(regop), static_cast<int>(imm8));
1894           data += 2;
1895         } else if (f0byte >= 0xC8 && f0byte <= 0xCF) {
1896           // bswap
1897           data += 2;
1898           int reg = f0byte - 0xC8;
1899           AppendToBuffer("bswap %s", NameOfCPURegister(reg));
1900         } else if ((f0byte & 0xF0) == 0x80) {
1901           data += JumpConditional(data, branch_hint);
1902         } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1903                    f0byte == 0xB7 || f0byte == 0xAF) {
1904           data += 2;
1905           data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1906         } else if ((f0byte & 0xF0) == 0x90) {
1907           data += SetCC(data);
1908         } else if ((f0byte & 0xF0) == 0x40) {
1909           data += CMov(data);
1910         } else if (f0byte == 0xA4 || f0byte == 0xAC) {
1911           // shld, shrd
1912           data += 2;
1913           AppendToBuffer("%s ", f0mnem);
1914           int mod, regop, rm;
1915           get_modrm(*data, &mod, &regop, &rm);
1916           int8_t imm8 = static_cast<int8_t>(data[1]);
1917           data += 2;
1918           AppendToBuffer("%s,%s,%d", NameOfCPURegister(rm),
1919                          NameOfCPURegister(regop), static_cast<int>(imm8));
1920         } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1921           // shrd_cl, shld_cl, bts
1922           data += 2;
1923           AppendToBuffer("%s ", f0mnem);
1924           int mod, regop, rm;
1925           get_modrm(*data, &mod, &regop, &rm);
1926           data += PrintRightOperand(data);
1927           if (f0byte == 0xAB) {
1928             AppendToBuffer(",%s", NameOfCPURegister(regop));
1929           } else {
1930             AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1931           }
1932         } else if (f0byte == 0xB0) {
1933           // cmpxchg_b
1934           data += 2;
1935           AppendToBuffer("%s ", f0mnem);
1936           int mod, regop, rm;
1937           get_modrm(*data, &mod, &regop, &rm);
1938           data += PrintRightOperand(data);
1939           AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1940         } else if (f0byte == 0xB1) {
1941           // cmpxchg
1942           data += 2;
1943           data += PrintOperands(f0mnem, OPER_REG_OP_ORDER, data);
1944         } else if (f0byte == 0xBC) {
1945           data += 2;
1946           int mod, regop, rm;
1947           get_modrm(*data, &mod, &regop, &rm);
1948           AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1949           data += PrintRightOperand(data);
1950         } else if (f0byte == 0xBD) {
1951           data += 2;
1952           int mod, regop, rm;
1953           get_modrm(*data, &mod, &regop, &rm);
1954           AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1955           data += PrintRightOperand(data);
1956         } else if (f0byte == 0xC7) {
1957           // cmpxchg8b
1958           data += 2;
1959           AppendToBuffer("%s ", f0mnem);
1960           int mod, regop, rm;
1961           get_modrm(*data, &mod, &regop, &rm);
1962           data += PrintRightOperand(data);
1963         } else if (f0byte == 0xAE && (data[2] & 0xF8) == 0xF0) {
1964           AppendToBuffer("mfence");
1965           data += 3;
1966         } else if (f0byte == 0xAE && (data[2] & 0xF8) == 0xE8) {
1967           AppendToBuffer("lfence");
1968           data += 3;
1969         } else {
1970           UnimplementedInstruction();
1971         }
1972       } break;
1973 
1974       case 0x8F: {
1975         data++;
1976         int mod, regop, rm;
1977         get_modrm(*data, &mod, &regop, &rm);
1978         if (regop == eax) {
1979           AppendToBuffer("pop ");
1980           data += PrintRightOperand(data);
1981         }
1982       } break;
1983 
1984       case 0xFF: {
1985         data++;
1986         int mod, regop, rm;
1987         get_modrm(*data, &mod, &regop, &rm);
1988         const char* mnem = nullptr;
1989         switch (regop) {
1990           case esi:
1991             mnem = "push";
1992             break;
1993           case eax:
1994             mnem = "inc";
1995             break;
1996           case ecx:
1997             mnem = "dec";
1998             break;
1999           case edx:
2000             mnem = "call";
2001             break;
2002           case esp:
2003             mnem = "jmp";
2004             break;
2005           default:
2006             mnem = "???";
2007         }
2008         AppendToBuffer("%s ", mnem);
2009         data += PrintRightOperand(data);
2010       } break;
2011 
2012       case 0xC7:  // imm32, fall through
2013       case 0xC6:  // imm8
2014       {
2015         bool is_byte = *data == 0xC6;
2016         data++;
2017         if (is_byte) {
2018           AppendToBuffer("%s ", "mov_b");
2019           data += PrintRightByteOperand(data);
2020           int32_t imm = *data;
2021           AppendToBuffer(",0x%x", imm);
2022           data++;
2023         } else {
2024           AppendToBuffer("%s ", "mov");
2025           data += PrintRightOperand(data);
2026           AppendToBuffer(",0x%x", Imm32(data));
2027           data += 4;
2028         }
2029       } break;
2030 
2031       case 0x80: {
2032         data++;
2033         int mod, regop, rm;
2034         get_modrm(*data, &mod, &regop, &rm);
2035         const char* mnem = nullptr;
2036         switch (regop) {
2037           case 5:
2038             mnem = "subb";
2039             break;
2040           case 7:
2041             mnem = "cmpb";
2042             break;
2043           default:
2044             UnimplementedInstruction();
2045         }
2046         AppendToBuffer("%s ", mnem);
2047         data += PrintRightByteOperand(data);
2048         int32_t imm = *data;
2049         AppendToBuffer(",0x%x", imm);
2050         data++;
2051       } break;
2052 
2053       case 0x88:  // 8bit, fall through
2054       case 0x89:  // 32bit
2055       {
2056         bool is_byte = *data == 0x88;
2057         int mod, regop, rm;
2058         data++;
2059         get_modrm(*data, &mod, &regop, &rm);
2060         if (is_byte) {
2061           AppendToBuffer("%s ", "mov_b");
2062           data += PrintRightByteOperand(data);
2063           AppendToBuffer(",%s", NameOfByteCPURegister(regop));
2064         } else {
2065           AppendToBuffer("%s ", "mov");
2066           data += PrintRightOperand(data);
2067           AppendToBuffer(",%s", NameOfCPURegister(regop));
2068         }
2069       } break;
2070 
2071       case 0x66:  // prefix
2072         while (*data == 0x66) data++;
2073         if (*data == 0xF && data[1] == 0x1F) {
2074           AppendToBuffer("nop");  // 0x66 prefix
2075         } else if (*data == 0x39) {
2076           data++;
2077           data += PrintOperands("cmpw", OPER_REG_OP_ORDER, data);
2078         } else if (*data == 0x3B) {
2079           data++;
2080           data += PrintOperands("cmpw", REG_OPER_OP_ORDER, data);
2081         } else if (*data == 0x81) {
2082           data++;
2083           AppendToBuffer("cmpw ");
2084           data += PrintRightOperand(data);
2085           AppendToBuffer(",0x%x", Imm16(data));
2086           data += 2;
2087         } else if (*data == 0x87) {
2088           data++;
2089           int mod, regop, rm;
2090           get_modrm(*data, &mod, &regop, &rm);
2091           AppendToBuffer("xchg_w %s,", NameOfCPURegister(regop));
2092           data += PrintRightOperand(data);
2093         } else if (*data == 0x89) {
2094           data++;
2095           int mod, regop, rm;
2096           get_modrm(*data, &mod, &regop, &rm);
2097           AppendToBuffer("mov_w ");
2098           data += PrintRightOperand(data);
2099           AppendToBuffer(",%s", NameOfCPURegister(regop));
2100         } else if (*data == 0x8B) {
2101           data++;
2102           data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
2103         } else if (*data == 0x90) {
2104           AppendToBuffer("nop");  // 0x66 prefix
2105         } else if (*data == 0xC7) {
2106           data++;
2107           AppendToBuffer("%s ", "mov_w");
2108           data += PrintRightOperand(data);
2109           AppendToBuffer(",0x%x", Imm16(data));
2110           data += 2;
2111         } else if (*data == 0xF7) {
2112           data++;
2113           AppendToBuffer("%s ", "test_w");
2114           data += PrintRightOperand(data);
2115           AppendToBuffer(",0x%x", Imm16(data));
2116           data += 2;
2117         } else if (*data == 0x0F) {
2118           data++;
2119           if (*data == 0x10) {
2120             data++;
2121             int mod, regop, rm;
2122             get_modrm(*data, &mod, &regop, &rm);
2123             AppendToBuffer("movupd %s,", NameOfXMMRegister(regop));
2124             data += PrintRightXMMOperand(data);
2125           } else if (*data == 0x28) {
2126             data++;
2127             int mod, regop, rm;
2128             get_modrm(*data, &mod, &regop, &rm);
2129             AppendToBuffer("movapd %s,", NameOfXMMRegister(regop));
2130             data += PrintRightXMMOperand(data);
2131           } else if (*data == 0x38) {
2132             data++;
2133             byte op = *data;
2134             data++;
2135             int mod, regop, rm;
2136             get_modrm(*data, &mod, &regop, &rm);
2137             switch (op) {
2138 #define SSE34_DIS_CASE(instruction, notUsed1, notUsed2, notUsed3, opcode) \
2139   case 0x##opcode: {                                                      \
2140     AppendToBuffer(#instruction " %s,", NameOfXMMRegister(regop));        \
2141     data += PrintRightXMMOperand(data);                                   \
2142     break;                                                                \
2143   }
2144 
2145               SSSE3_INSTRUCTION_LIST(SSE34_DIS_CASE)
2146               SSSE3_UNOP_INSTRUCTION_LIST(SSE34_DIS_CASE)
2147               SSE4_INSTRUCTION_LIST(SSE34_DIS_CASE)
2148               SSE4_RM_INSTRUCTION_LIST(SSE34_DIS_CASE)
2149 #undef SSE34_DIS_CASE
2150               default:
2151                 UnimplementedInstruction();
2152             }
2153           } else if (*data == 0x3A) {
2154             data++;
2155             if (*data >= 0x08 && *data <= 0x0B) {
2156               const char* const pseudo_op[] = {
2157                   "roundps",
2158                   "roundpd",
2159                   "roundss",
2160                   "roundsd",
2161               };
2162               byte op = *data;
2163               data++;
2164               int mod, regop, rm;
2165               get_modrm(*data, &mod, &regop, &rm);
2166               int8_t imm8 = static_cast<int8_t>(data[1]);
2167               AppendToBuffer("%s %s,%s,%d", pseudo_op[op - 0x08],
2168                              NameOfXMMRegister(regop), NameOfXMMRegister(rm),
2169                              static_cast<int>(imm8));
2170               data += 2;
2171             } else if (*data == 0x0E) {
2172               data++;
2173               int mod, regop, rm;
2174               get_modrm(*data, &mod, &regop, &rm);
2175               AppendToBuffer("pblendw %s,", NameOfXMMRegister(regop));
2176               data += PrintRightXMMOperand(data);
2177               AppendToBuffer(",%d", Imm8_U(data));
2178               data++;
2179             } else if (*data == 0x0F) {
2180               data++;
2181               int mod, regop, rm;
2182               get_modrm(*data, &mod, &regop, &rm);
2183               AppendToBuffer("palignr %s,", NameOfXMMRegister(regop));
2184               data += PrintRightXMMOperand(data);
2185               AppendToBuffer(",%d", Imm8_U(data));
2186               data++;
2187             } else if (*data == 0x14) {
2188               data++;
2189               int mod, regop, rm;
2190               get_modrm(*data, &mod, &regop, &rm);
2191               AppendToBuffer("pextrb ");
2192               data += PrintRightOperand(data);
2193               AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(data));
2194               data++;
2195             } else if (*data == 0x15) {
2196               data++;
2197               int mod, regop, rm;
2198               get_modrm(*data, &mod, &regop, &rm);
2199               AppendToBuffer("pextrw ");
2200               data += PrintRightOperand(data);
2201               AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(data));
2202               data++;
2203             } else if (*data == 0x16) {
2204               data++;
2205               int mod, regop, rm;
2206               get_modrm(*data, &mod, &regop, &rm);
2207               AppendToBuffer("pextrd ");
2208               data += PrintRightOperand(data);
2209               AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), Imm8(data));
2210               data++;
2211             } else if (*data == 0x17) {
2212               data++;
2213               int mod, regop, rm;
2214               get_modrm(*data, &mod, &regop, &rm);
2215               int8_t imm8 = static_cast<int8_t>(data[1]);
2216               AppendToBuffer("extractps %s,%s,%d", NameOfCPURegister(rm),
2217                              NameOfXMMRegister(regop), static_cast<int>(imm8));
2218               data += 2;
2219             } else if (*data == 0x20) {
2220               data++;
2221               int mod, regop, rm;
2222               get_modrm(*data, &mod, &regop, &rm);
2223               AppendToBuffer("pinsrb %s,", NameOfXMMRegister(regop));
2224               data += PrintRightOperand(data);
2225               AppendToBuffer(",%d", Imm8(data));
2226               data++;
2227             } else if (*data == 0x21) {
2228               data++;
2229               int mod, regop, rm;
2230               get_modrm(*data, &mod, &regop, &rm);
2231               AppendToBuffer("insertps %s,", NameOfXMMRegister(regop));
2232               data += PrintRightXMMOperand(data);
2233               AppendToBuffer(",%d", Imm8(data));
2234               data++;
2235             } else if (*data == 0x22) {
2236               data++;
2237               int mod, regop, rm;
2238               get_modrm(*data, &mod, &regop, &rm);
2239               AppendToBuffer("pinsrd %s,", NameOfXMMRegister(regop));
2240               data += PrintRightOperand(data);
2241               AppendToBuffer(",%d", Imm8(data));
2242               data++;
2243             } else {
2244               UnimplementedInstruction();
2245             }
2246           } else if (*data == 0x2E || *data == 0x2F) {
2247             const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
2248             data++;
2249             int mod, regop, rm;
2250             get_modrm(*data, &mod, &regop, &rm);
2251             if (mod == 0x3) {
2252               AppendToBuffer("%s %s,%s", mnem, NameOfXMMRegister(regop),
2253                              NameOfXMMRegister(rm));
2254               data++;
2255             } else {
2256               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2257               data += PrintRightOperand(data);
2258             }
2259           } else if (*data == 0x50) {
2260             data++;
2261             int mod, regop, rm;
2262             get_modrm(*data, &mod, &regop, &rm);
2263             AppendToBuffer("movmskpd %s,%s", NameOfCPURegister(regop),
2264                            NameOfXMMRegister(rm));
2265             data++;
2266           } else if (*data >= 0x54 && *data <= 0x59) {
2267             const char* const pseudo_op[] = {
2268                 "andpd", "andnpd", "orpd", "xorpd", "addpd", "mulpd",
2269             };
2270             byte op = *data;
2271             data++;
2272             int mod, regop, rm;
2273             get_modrm(*data, &mod, &regop, &rm);
2274             AppendToBuffer("%s %s,", pseudo_op[op - 0x54],
2275                            NameOfXMMRegister(regop));
2276             data += PrintRightXMMOperand(data);
2277           } else if (*data >= 0x5c && *data <= 0x5f) {
2278             const char* const pseudo_op[] = {
2279                 "subpd",
2280                 "minpd",
2281                 "divpd",
2282                 "maxpd",
2283             };
2284             byte op = *data;
2285             data++;
2286             int mod, regop, rm;
2287             get_modrm(*data, &mod, &regop, &rm);
2288             AppendToBuffer("%s %s,", pseudo_op[op - 0x5c],
2289                            NameOfXMMRegister(regop));
2290             data += PrintRightXMMOperand(data);
2291           } else if (*data == 0x6E) {
2292             data++;
2293             int mod, regop, rm;
2294             get_modrm(*data, &mod, &regop, &rm);
2295             AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
2296             data += PrintRightOperand(data);
2297           } else if (*data == 0x6F) {
2298             data++;
2299             int mod, regop, rm;
2300             get_modrm(*data, &mod, &regop, &rm);
2301             AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
2302             data += PrintRightXMMOperand(data);
2303           } else if (*data == 0x70) {
2304             data++;
2305             int mod, regop, rm;
2306             get_modrm(*data, &mod, &regop, &rm);
2307             AppendToBuffer("pshufd %s,", NameOfXMMRegister(regop));
2308             data += PrintRightXMMOperand(data);
2309             AppendToBuffer(",%d", Imm8(data));
2310             data++;
2311           } else if (*data == 0x90) {
2312             data++;
2313             AppendToBuffer("nop");  // 2 byte nop.
2314           } else if (*data == 0x71) {
2315             data++;
2316             int mod, regop, rm;
2317             get_modrm(*data, &mod, &regop, &rm);
2318             int8_t imm8 = static_cast<int8_t>(data[1]);
2319             AppendToBuffer("ps%sw %s,%d", sf_str[regop / 2],
2320                            NameOfXMMRegister(rm), static_cast<int>(imm8));
2321             data += 2;
2322           } else if (*data == 0x72) {
2323             data++;
2324             int mod, regop, rm;
2325             get_modrm(*data, &mod, &regop, &rm);
2326             int8_t imm8 = static_cast<int8_t>(data[1]);
2327             AppendToBuffer("ps%sd %s,%d", sf_str[regop / 2],
2328                            NameOfXMMRegister(rm), static_cast<int>(imm8));
2329             data += 2;
2330           } else if (*data == 0x73) {
2331             data++;
2332             int mod, regop, rm;
2333             get_modrm(*data, &mod, &regop, &rm);
2334             int8_t imm8 = static_cast<int8_t>(data[1]);
2335             DCHECK(regop == esi || regop == edx);
2336             AppendToBuffer("ps%sq %s,%d", sf_str[regop / 2],
2337                            NameOfXMMRegister(rm), static_cast<int>(imm8));
2338             data += 2;
2339           } else if (*data == 0x7F) {
2340             AppendToBuffer("movdqa ");
2341             data++;
2342             int mod, regop, rm;
2343             get_modrm(*data, &mod, &regop, &rm);
2344             data += PrintRightXMMOperand(data);
2345             AppendToBuffer(",%s", NameOfXMMRegister(regop));
2346           } else if (*data == 0x7E) {
2347             data++;
2348             int mod, regop, rm;
2349             get_modrm(*data, &mod, &regop, &rm);
2350             AppendToBuffer("movd ");
2351             data += PrintRightOperand(data);
2352             AppendToBuffer(",%s", NameOfXMMRegister(regop));
2353           } else if (*data == 0xC1) {
2354             data += 2;
2355             data += PrintOperands("xadd_w", OPER_REG_OP_ORDER, data);
2356           } else if (*data == 0xC2) {
2357             data++;
2358             int mod, regop, rm;
2359             get_modrm(*data, &mod, &regop, &rm);
2360             const char* const pseudo_op[] = {"eq", "lt", "le", "unord", "neq"};
2361             AppendToBuffer("cmppd %s, ", NameOfXMMRegister(regop));
2362             data += PrintRightXMMOperand(data);
2363             AppendToBuffer(", (%s)", pseudo_op[*data]);
2364             data++;
2365           } else if (*data == 0xC4) {
2366             data++;
2367             int mod, regop, rm;
2368             get_modrm(*data, &mod, &regop, &rm);
2369             AppendToBuffer("pinsrw %s,", NameOfXMMRegister(regop));
2370             data += PrintRightOperand(data);
2371             AppendToBuffer(",%d", Imm8(data));
2372             data++;
2373           } else if (*data == 0xC6) {
2374             // shufpd xmm, xmm/m128, imm8
2375             data++;
2376             int mod, regop, rm;
2377             get_modrm(*data, &mod, &regop, &rm);
2378             AppendToBuffer("shufpd %s,", NameOfXMMRegister(regop));
2379             data += PrintRightXMMOperand(data);
2380             AppendToBuffer(",%d", Imm8(data));
2381             data++;
2382           } else if (*data == 0xE7) {
2383             data++;
2384             int mod, regop, rm;
2385             get_modrm(*data, &mod, &regop, &rm);
2386             if (mod == 3) {
2387               // movntdq
2388               UnimplementedInstruction();
2389             } else {
2390               UnimplementedInstruction();
2391             }
2392           } else if (*data == 0xB1) {
2393             data++;
2394             data += PrintOperands("cmpxchg_w", OPER_REG_OP_ORDER, data);
2395           } else if (*data == 0xD7) {
2396             data++;
2397             int mod, regop, rm;
2398             get_modrm(*data, &mod, &regop, &rm);
2399             AppendToBuffer("pmovmskb %s,%s", NameOfCPURegister(regop),
2400                            NameOfXMMRegister(rm));
2401             data++;
2402           } else {
2403             byte op = *data;
2404             data++;
2405             int mod, regop, rm;
2406             get_modrm(*data, &mod, &regop, &rm);
2407             switch (op) {
2408 #define SSE2_DIS_CASE(instruction, notUsed1, notUsed2, opcode)     \
2409   case 0x##opcode: {                                               \
2410     AppendToBuffer(#instruction " %s,", NameOfXMMRegister(regop)); \
2411     data += PrintRightXMMOperand(data);                            \
2412     break;                                                         \
2413   }
2414 
2415               SSE2_INSTRUCTION_LIST(SSE2_DIS_CASE)
2416 #undef SSE2_DIS_CASE
2417               default:
2418                 UnimplementedInstruction();
2419             }
2420           }
2421         } else {
2422           UnimplementedInstruction();
2423         }
2424         break;
2425 
2426       case 0xFE: {
2427         data++;
2428         int mod, regop, rm;
2429         get_modrm(*data, &mod, &regop, &rm);
2430         if (regop == ecx) {
2431           AppendToBuffer("dec_b ");
2432           data += PrintRightOperand(data);
2433         } else {
2434           UnimplementedInstruction();
2435         }
2436       } break;
2437 
2438       case 0x68:
2439         AppendToBuffer("push 0x%x", Imm32(data + 1));
2440         data += 5;
2441         break;
2442 
2443       case 0x6A:
2444         AppendToBuffer("push 0x%x", Imm8(data + 1));
2445         data += 2;
2446         break;
2447 
2448       case 0xA8:
2449         AppendToBuffer("test al,0x%x", Imm8_U(data + 1));
2450         data += 2;
2451         break;
2452 
2453       case 0xA9:
2454         AppendToBuffer("test eax,0x%x", Imm32(data + 1));
2455         data += 5;
2456         break;
2457 
2458       case 0xD1:  // fall through
2459       case 0xD3:  // fall through
2460       case 0xC1:
2461         data += D1D3C1Instruction(data);
2462         break;
2463 
2464       case 0xD8:  // fall through
2465       case 0xD9:  // fall through
2466       case 0xDA:  // fall through
2467       case 0xDB:  // fall through
2468       case 0xDC:  // fall through
2469       case 0xDD:  // fall through
2470       case 0xDE:  // fall through
2471       case 0xDF:
2472         data += FPUInstruction(data);
2473         break;
2474 
2475       case 0xEB:
2476         data += JumpShort(data);
2477         break;
2478 
2479       case 0xF2:
2480         if (*(data + 1) == 0x0F) {
2481           byte b2 = *(data + 2);
2482           if (b2 == 0x11) {
2483             AppendToBuffer("movsd ");
2484             data += 3;
2485             int mod, regop, rm;
2486             get_modrm(*data, &mod, &regop, &rm);
2487             data += PrintRightXMMOperand(data);
2488             AppendToBuffer(",%s", NameOfXMMRegister(regop));
2489           } else if (b2 == 0x10) {
2490             data += 3;
2491             int mod, regop, rm;
2492             get_modrm(*data, &mod, &regop, &rm);
2493             AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
2494             data += PrintRightXMMOperand(data);
2495           } else if (b2 == 0x12) {
2496             data += 3;
2497             int mod, regop, rm;
2498             get_modrm(*data, &mod, &regop, &rm);
2499             AppendToBuffer("movddup %s,", NameOfXMMRegister(regop));
2500             data += PrintRightXMMOperand(data);
2501           } else if (b2 == 0x5A) {
2502             data += 3;
2503             int mod, regop, rm;
2504             get_modrm(*data, &mod, &regop, &rm);
2505             AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
2506             data += PrintRightXMMOperand(data);
2507           } else if (b2 == 0x70) {
2508             data += 3;
2509             int mod, regop, rm;
2510             get_modrm(*data, &mod, &regop, &rm);
2511             AppendToBuffer("pshuflw %s,", NameOfXMMRegister(regop));
2512             data += PrintRightXMMOperand(data);
2513             AppendToBuffer(",%d", Imm8(data));
2514             data++;
2515           } else {
2516             const char* mnem = "?";
2517             switch (b2) {
2518               case 0x2A:
2519                 mnem = "cvtsi2sd";
2520                 break;
2521               case 0x2C:
2522                 mnem = "cvttsd2si";
2523                 break;
2524               case 0x2D:
2525                 mnem = "cvtsd2si";
2526                 break;
2527               case 0x51:
2528                 mnem = "sqrtsd";
2529                 break;
2530               case 0x58:
2531                 mnem = "addsd";
2532                 break;
2533               case 0x59:
2534                 mnem = "mulsd";
2535                 break;
2536               case 0x5C:
2537                 mnem = "subsd";
2538                 break;
2539               case 0x5D:
2540                 mnem = "minsd";
2541                 break;
2542               case 0x5E:
2543                 mnem = "divsd";
2544                 break;
2545               case 0x5F:
2546                 mnem = "maxsd";
2547                 break;
2548               case 0x7C:
2549                 mnem = "haddps";
2550                 break;
2551             }
2552             data += 3;
2553             int mod, regop, rm;
2554             get_modrm(*data, &mod, &regop, &rm);
2555             if (b2 == 0x2A) {
2556               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2557               data += PrintRightOperand(data);
2558             } else if (b2 == 0x2C || b2 == 0x2D) {
2559               AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
2560               data += PrintRightXMMOperand(data);
2561             } else if (b2 == 0xC2) {
2562               // Intel manual 2A, Table 3-18.
2563               const char* const pseudo_op[] = {
2564                   "cmpeqsd",  "cmpltsd",  "cmplesd",  "cmpunordsd",
2565                   "cmpneqsd", "cmpnltsd", "cmpnlesd", "cmpordsd"};
2566               AppendToBuffer("%s %s,%s", pseudo_op[data[1]],
2567                              NameOfXMMRegister(regop), NameOfXMMRegister(rm));
2568               data += 2;
2569             } else {
2570               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2571               data += PrintRightXMMOperand(data);
2572             }
2573           }
2574         } else {
2575           UnimplementedInstruction();
2576         }
2577         break;
2578 
2579       case 0xF3:
2580         if (*(data + 1) == 0x0F) {
2581           byte b2 = *(data + 2);
2582           if (b2 == 0x11) {
2583             AppendToBuffer("movss ");
2584             data += 3;
2585             int mod, regop, rm;
2586             get_modrm(*data, &mod, &regop, &rm);
2587             data += PrintRightXMMOperand(data);
2588             AppendToBuffer(",%s", NameOfXMMRegister(regop));
2589           } else if (b2 == 0x10) {
2590             data += 3;
2591             int mod, regop, rm;
2592             get_modrm(*data, &mod, &regop, &rm);
2593             AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
2594             data += PrintRightXMMOperand(data);
2595           } else if (b2 == 0x5A) {
2596             data += 3;
2597             int mod, regop, rm;
2598             get_modrm(*data, &mod, &regop, &rm);
2599             AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
2600             data += PrintRightXMMOperand(data);
2601           } else if (b2 == 0x6F) {
2602             data += 3;
2603             int mod, regop, rm;
2604             get_modrm(*data, &mod, &regop, &rm);
2605             AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
2606             data += PrintRightXMMOperand(data);
2607           } else if (b2 == 0x70) {
2608             data += 3;
2609             int mod, regop, rm;
2610             get_modrm(*data, &mod, &regop, &rm);
2611             AppendToBuffer("pshufhw %s,", NameOfXMMRegister(regop));
2612             data += PrintRightXMMOperand(data);
2613             AppendToBuffer(",%d", Imm8(data));
2614             data++;
2615           } else if (b2 == 0x7F) {
2616             AppendToBuffer("movdqu ");
2617             data += 3;
2618             int mod, regop, rm;
2619             get_modrm(*data, &mod, &regop, &rm);
2620             data += PrintRightXMMOperand(data);
2621             AppendToBuffer(",%s", NameOfXMMRegister(regop));
2622           } else if (b2 == 0xB8) {
2623             data += 3;
2624             int mod, regop, rm;
2625             get_modrm(*data, &mod, &regop, &rm);
2626             AppendToBuffer("popcnt %s,", NameOfCPURegister(regop));
2627             data += PrintRightOperand(data);
2628           } else if (b2 == 0xBC) {
2629             data += 3;
2630             int mod, regop, rm;
2631             get_modrm(*data, &mod, &regop, &rm);
2632             AppendToBuffer("tzcnt %s,", NameOfCPURegister(regop));
2633             data += PrintRightOperand(data);
2634           } else if (b2 == 0xBD) {
2635             data += 3;
2636             int mod, regop, rm;
2637             get_modrm(*data, &mod, &regop, &rm);
2638             AppendToBuffer("lzcnt %s,", NameOfCPURegister(regop));
2639             data += PrintRightOperand(data);
2640           } else {
2641             const char* mnem = "?";
2642             switch (b2) {
2643               case 0x2A:
2644                 mnem = "cvtsi2ss";
2645                 break;
2646               case 0x2C:
2647                 mnem = "cvttss2si";
2648                 break;
2649               case 0x2D:
2650                 mnem = "cvtss2si";
2651                 break;
2652               case 0x51:
2653                 mnem = "sqrtss";
2654                 break;
2655               case 0x58:
2656                 mnem = "addss";
2657                 break;
2658               case 0x59:
2659                 mnem = "mulss";
2660                 break;
2661               case 0x5B:
2662                 mnem = "cvttps2dq";
2663                 break;
2664               case 0x5C:
2665                 mnem = "subss";
2666                 break;
2667               case 0x5D:
2668                 mnem = "minss";
2669                 break;
2670               case 0x5E:
2671                 mnem = "divss";
2672                 break;
2673               case 0x5F:
2674                 mnem = "maxss";
2675                 break;
2676               case 0x7E:
2677                 mnem = "movq";
2678                 break;
2679             }
2680             data += 3;
2681             int mod, regop, rm;
2682             get_modrm(*data, &mod, &regop, &rm);
2683             if (b2 == 0x2A) {
2684               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2685               data += PrintRightOperand(data);
2686             } else if (b2 == 0x2C || b2 == 0x2D) {
2687               AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
2688               data += PrintRightXMMOperand(data);
2689             } else if (b2 == 0xC2) {
2690               // Intel manual 2A, Table 3-18.
2691               const char* const pseudo_op[] = {
2692                   "cmpeqss",  "cmpltss",  "cmpless",  "cmpunordss",
2693                   "cmpneqss", "cmpnltss", "cmpnless", "cmpordss"};
2694               AppendToBuffer("%s %s,%s", pseudo_op[data[1]],
2695                              NameOfXMMRegister(regop), NameOfXMMRegister(rm));
2696               data += 2;
2697             } else {
2698               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
2699               data += PrintRightXMMOperand(data);
2700             }
2701           }
2702         } else if (*(data + 1) == 0xA5) {
2703           data += 2;
2704           AppendToBuffer("rep_movs");
2705         } else if (*(data + 1) == 0xAB) {
2706           data += 2;
2707           AppendToBuffer("rep_stos");
2708         } else if (*(data + 1) == 0x90) {
2709           data += 2;
2710           AppendToBuffer("pause");
2711         } else {
2712           UnimplementedInstruction();
2713         }
2714         break;
2715 
2716       case 0xF7:
2717         data += F7Instruction(data);
2718         break;
2719 
2720       default:
2721         UnimplementedInstruction();
2722     }
2723   }
2724 
2725   if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
2726     tmp_buffer_[tmp_buffer_pos_] = '\0';
2727   }
2728 
2729   int instr_len = data - instr;
2730   if (instr_len == 0) {
2731     printf("%02x", *data);
2732   }
2733   DCHECK_GT(instr_len, 0);  // Ensure progress.
2734 
2735   int outp = 0;
2736   // Instruction bytes.
2737   for (byte* bp = instr; bp < data; bp++) {
2738     outp += v8::internal::SNPrintF(out_buffer + outp, "%02x", *bp);
2739   }
2740   for (int i = 6 - instr_len; i >= 0; i--) {
2741     outp += v8::internal::SNPrintF(out_buffer + outp, "  ");
2742   }
2743 
2744   outp += v8::internal::SNPrintF(out_buffer + outp, " %s", tmp_buffer_.begin());
2745   return instr_len;
2746 }  // NOLINT (function is too long)
2747 
2748 //------------------------------------------------------------------------------
2749 
2750 static const char* const cpu_regs[8] = {"eax", "ecx", "edx", "ebx",
2751                                         "esp", "ebp", "esi", "edi"};
2752 
2753 static const char* const byte_cpu_regs[8] = {"al", "cl", "dl", "bl",
2754                                              "ah", "ch", "dh", "bh"};
2755 
2756 static const char* const xmm_regs[8] = {"xmm0", "xmm1", "xmm2", "xmm3",
2757                                         "xmm4", "xmm5", "xmm6", "xmm7"};
2758 
NameOfAddress(byte * addr) const2759 const char* NameConverter::NameOfAddress(byte* addr) const {
2760   v8::internal::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr));
2761   return tmp_buffer_.begin();
2762 }
2763 
NameOfConstant(byte * addr) const2764 const char* NameConverter::NameOfConstant(byte* addr) const {
2765   return NameOfAddress(addr);
2766 }
2767 
NameOfCPURegister(int reg) const2768 const char* NameConverter::NameOfCPURegister(int reg) const {
2769   if (0 <= reg && reg < 8) return cpu_regs[reg];
2770   return "noreg";
2771 }
2772 
NameOfByteCPURegister(int reg) const2773 const char* NameConverter::NameOfByteCPURegister(int reg) const {
2774   if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
2775   return "noreg";
2776 }
2777 
NameOfXMMRegister(int reg) const2778 const char* NameConverter::NameOfXMMRegister(int reg) const {
2779   if (0 <= reg && reg < 8) return xmm_regs[reg];
2780   return "noxmmreg";
2781 }
2782 
NameInCode(byte * addr) const2783 const char* NameConverter::NameInCode(byte* addr) const {
2784   // IA32 does not embed debug strings at the moment.
2785   UNREACHABLE();
2786 }
2787 
2788 //------------------------------------------------------------------------------
2789 
InstructionDecode(v8::internal::Vector<char> buffer,byte * instruction)2790 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
2791                                     byte* instruction) {
2792   DisassemblerIA32 d(converter_, unimplemented_opcode_action());
2793   return d.InstructionDecode(buffer, instruction);
2794 }
2795 
2796 // The IA-32 assembler does not currently use constant pools.
ConstantPoolSizeAt(byte * instruction)2797 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
2798 
2799 // static
Disassemble(FILE * f,byte * begin,byte * end,UnimplementedOpcodeAction unimplemented_action)2800 void Disassembler::Disassemble(FILE* f, byte* begin, byte* end,
2801                                UnimplementedOpcodeAction unimplemented_action) {
2802   NameConverter converter;
2803   Disassembler d(converter, unimplemented_action);
2804   for (byte* pc = begin; pc < end;) {
2805     v8::internal::EmbeddedVector<char, 128> buffer;
2806     buffer[0] = '\0';
2807     byte* prev_pc = pc;
2808     pc += d.InstructionDecode(buffer, pc);
2809     fprintf(f, "%p", static_cast<void*>(prev_pc));
2810     fprintf(f, "    ");
2811 
2812     for (byte* bp = prev_pc; bp < pc; bp++) {
2813       fprintf(f, "%02x", *bp);
2814     }
2815     for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
2816       fprintf(f, "  ");
2817     }
2818     fprintf(f, "  %s\n", buffer.begin());
2819   }
2820 }
2821 
2822 }  // namespace disasm
2823 
2824 #endif  // V8_TARGET_ARCH_IA32
2825