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