Home | History | Annotate | Download | only in ia32
      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();
    145   const InstructionDesc& Get(byte x) const { return instructions_[x]; }
    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 
    164 InstructionTable::InstructionTable() {
    165   Clear();
    166   Init();
    167 }
    168 
    169 
    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 
    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 
    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 
    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 
    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:
    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 
    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 
    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 
    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 
    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 
    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 
    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 
    313   bool vex_w() {
    314     if (vex_byte0_ == 0xc5) return false;
    315     return (vex_byte2_ & 0x80) != 0;
    316   }
    317 
    318   bool vex_0f() {
    319     if (vex_byte0_ == 0xc5) return true;
    320     return (vex_byte1_ & 3) == 1;
    321   }
    322 
    323   bool vex_0f38() {
    324     if (vex_byte0_ == 0xc5) return false;
    325     return (vex_byte1_ & 3) == 2;
    326   }
    327 
    328   bool vex_0f3a() {
    329     if (vex_byte0_ == 0xc5) return false;
    330     return (vex_byte1_ & 3) == 3;
    331   }
    332 
    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 
    339   char float_size_code() { return "sd"[vex_w()]; }
    340 
    341   const char* NameOfCPURegister(int reg) const {
    342     return converter_.NameOfCPURegister(reg);
    343   }
    344 
    345 
    346   const char* NameOfByteCPURegister(int reg) const {
    347     return converter_.NameOfByteCPURegister(reg);
    348   }
    349 
    350 
    351   const char* NameOfXMMRegister(int reg) const {
    352     return converter_.NameOfXMMRegister(reg);
    353   }
    354 
    355 
    356   const char* NameOfAddress(byte* addr) const {
    357     return converter_.NameOfAddress(addr);
    358   }
    359 
    360 
    361   // Disassembler helper functions.
    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 
    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 
    396   void UnimplementedInstruction() {
    397     if (abort_on_unimplemented_) {
    398       UNIMPLEMENTED();
    399     } else {
    400       AppendToBuffer("'Unimplemented Instruction'");
    401     }
    402   }
    403 };
    404 
    405 
    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 
    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 
    503 int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
    504   return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
    505 }
    506 
    507 
    508 int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
    509   return PrintRightOperandHelper(modrmp,
    510                                  &DisassemblerIA32::NameOfByteCPURegister);
    511 }
    512 
    513 
    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_'.
    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_'.
    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.
    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 
    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.
    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.
    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.
    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.
    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.
    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 
    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.
   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 
   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 
   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.
   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'.
   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 
   2264 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 
   2270 const char* NameConverter::NameOfConstant(byte* addr) const {
   2271   return NameOfAddress(addr);
   2272 }
   2273 
   2274 
   2275 const char* NameConverter::NameOfCPURegister(int reg) const {
   2276   if (0 <= reg && reg < 8) return cpu_regs[reg];
   2277   return "noreg";
   2278 }
   2279 
   2280 
   2281 const char* NameConverter::NameOfByteCPURegister(int reg) const {
   2282   if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
   2283   return "noreg";
   2284 }
   2285 
   2286 
   2287 const char* NameConverter::NameOfXMMRegister(int reg) const {
   2288   if (0 <= reg && reg < 8) return xmm_regs[reg];
   2289   return "noxmmreg";
   2290 }
   2291 
   2292 
   2293 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 
   2302 Disassembler::Disassembler(const NameConverter& converter)
   2303     : converter_(converter) {}
   2304 
   2305 
   2306 Disassembler::~Disassembler() {}
   2307 
   2308 
   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.
   2317 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
   2318 
   2319 
   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