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