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