Home | History | Annotate | Download | only in ia32
      1 // Copyright 2007-2008 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include <assert.h>
     29 #include <stdio.h>
     30 #include <stdarg.h>
     31 
     32 #include "v8.h"
     33 
     34 #if defined(V8_TARGET_ARCH_IA32)
     35 
     36 #include "disasm.h"
     37 
     38 namespace disasm {
     39 
     40 enum OperandOrder {
     41   UNSET_OP_ORDER = 0,
     42   REG_OPER_OP_ORDER,
     43   OPER_REG_OP_ORDER
     44 };
     45 
     46 
     47 //------------------------------------------------------------------
     48 // Tables
     49 //------------------------------------------------------------------
     50 struct ByteMnemonic {
     51   int b;  // -1 terminates, otherwise must be in range (0..255)
     52   const char* mnem;
     53   OperandOrder op_order_;
     54 };
     55 
     56 
     57 static ByteMnemonic two_operands_instr[] = {
     58   {0x03, "add", REG_OPER_OP_ORDER},
     59   {0x09, "or", OPER_REG_OP_ORDER},
     60   {0x0B, "or", REG_OPER_OP_ORDER},
     61   {0x1B, "sbb", REG_OPER_OP_ORDER},
     62   {0x21, "and", OPER_REG_OP_ORDER},
     63   {0x23, "and", REG_OPER_OP_ORDER},
     64   {0x29, "sub", OPER_REG_OP_ORDER},
     65   {0x2A, "subb", REG_OPER_OP_ORDER},
     66   {0x2B, "sub", REG_OPER_OP_ORDER},
     67   {0x31, "xor", OPER_REG_OP_ORDER},
     68   {0x33, "xor", REG_OPER_OP_ORDER},
     69   {0x38, "cmpb", OPER_REG_OP_ORDER},
     70   {0x3A, "cmpb", REG_OPER_OP_ORDER},
     71   {0x3B, "cmp", REG_OPER_OP_ORDER},
     72   {0x84, "test_b", REG_OPER_OP_ORDER},
     73   {0x85, "test", REG_OPER_OP_ORDER},
     74   {0x87, "xchg", REG_OPER_OP_ORDER},
     75   {0x8A, "mov_b", REG_OPER_OP_ORDER},
     76   {0x8B, "mov", REG_OPER_OP_ORDER},
     77   {0x8D, "lea", REG_OPER_OP_ORDER},
     78   {-1, "", UNSET_OP_ORDER}
     79 };
     80 
     81 
     82 static ByteMnemonic zero_operands_instr[] = {
     83   {0xC3, "ret", UNSET_OP_ORDER},
     84   {0xC9, "leave", UNSET_OP_ORDER},
     85   {0x90, "nop", UNSET_OP_ORDER},
     86   {0xF4, "hlt", UNSET_OP_ORDER},
     87   {0xCC, "int3", UNSET_OP_ORDER},
     88   {0x60, "pushad", UNSET_OP_ORDER},
     89   {0x61, "popad", UNSET_OP_ORDER},
     90   {0x9C, "pushfd", UNSET_OP_ORDER},
     91   {0x9D, "popfd", UNSET_OP_ORDER},
     92   {0x9E, "sahf", UNSET_OP_ORDER},
     93   {0x99, "cdq", UNSET_OP_ORDER},
     94   {0x9B, "fwait", UNSET_OP_ORDER},
     95   {0xFC, "cld", UNSET_OP_ORDER},
     96   {0xAB, "stos", UNSET_OP_ORDER},
     97   {-1, "", UNSET_OP_ORDER}
     98 };
     99 
    100 
    101 static ByteMnemonic call_jump_instr[] = {
    102   {0xE8, "call", UNSET_OP_ORDER},
    103   {0xE9, "jmp", UNSET_OP_ORDER},
    104   {-1, "", UNSET_OP_ORDER}
    105 };
    106 
    107 
    108 static ByteMnemonic short_immediate_instr[] = {
    109   {0x05, "add", UNSET_OP_ORDER},
    110   {0x0D, "or", UNSET_OP_ORDER},
    111   {0x15, "adc", UNSET_OP_ORDER},
    112   {0x25, "and", UNSET_OP_ORDER},
    113   {0x2D, "sub", UNSET_OP_ORDER},
    114   {0x35, "xor", UNSET_OP_ORDER},
    115   {0x3D, "cmp", UNSET_OP_ORDER},
    116   {-1, "", UNSET_OP_ORDER}
    117 };
    118 
    119 
    120 static const char* jump_conditional_mnem[] = {
    121   /*0*/ "jo", "jno", "jc", "jnc",
    122   /*4*/ "jz", "jnz", "jna", "ja",
    123   /*8*/ "js", "jns", "jpe", "jpo",
    124   /*12*/ "jl", "jnl", "jng", "jg"
    125 };
    126 
    127 
    128 static const char* set_conditional_mnem[] = {
    129   /*0*/ "seto", "setno", "setc", "setnc",
    130   /*4*/ "setz", "setnz", "setna", "seta",
    131   /*8*/ "sets", "setns", "setpe", "setpo",
    132   /*12*/ "setl", "setnl", "setng", "setg"
    133 };
    134 
    135 
    136 static const char* conditional_move_mnem[] = {
    137   /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc",
    138   /*4*/ "cmovz", "cmovnz", "cmovna", "cmova",
    139   /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo",
    140   /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg"
    141 };
    142 
    143 
    144 enum InstructionType {
    145   NO_INSTR,
    146   ZERO_OPERANDS_INSTR,
    147   TWO_OPERANDS_INSTR,
    148   JUMP_CONDITIONAL_SHORT_INSTR,
    149   REGISTER_INSTR,
    150   MOVE_REG_INSTR,
    151   CALL_JUMP_INSTR,
    152   SHORT_IMMEDIATE_INSTR
    153 };
    154 
    155 
    156 struct InstructionDesc {
    157   const char* mnem;
    158   InstructionType type;
    159   OperandOrder op_order_;
    160 };
    161 
    162 
    163 class InstructionTable {
    164  public:
    165   InstructionTable();
    166   const InstructionDesc& Get(byte x) const { return instructions_[x]; }
    167 
    168  private:
    169   InstructionDesc instructions_[256];
    170   void Clear();
    171   void Init();
    172   void CopyTable(ByteMnemonic bm[], InstructionType type);
    173   void SetTableRange(InstructionType type,
    174                      byte start,
    175                      byte end,
    176                      const char* mnem);
    177   void AddJumpConditionalShort();
    178 };
    179 
    180 
    181 InstructionTable::InstructionTable() {
    182   Clear();
    183   Init();
    184 }
    185 
    186 
    187 void InstructionTable::Clear() {
    188   for (int i = 0; i < 256; i++) {
    189     instructions_[i].mnem = "";
    190     instructions_[i].type = NO_INSTR;
    191     instructions_[i].op_order_ = UNSET_OP_ORDER;
    192   }
    193 }
    194 
    195 
    196 void InstructionTable::Init() {
    197   CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
    198   CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
    199   CopyTable(call_jump_instr, CALL_JUMP_INSTR);
    200   CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
    201   AddJumpConditionalShort();
    202   SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
    203   SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
    204   SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
    205   SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
    206   SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,");  // 0x90 is nop.
    207   SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
    208 }
    209 
    210 
    211 void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) {
    212   for (int i = 0; bm[i].b >= 0; i++) {
    213     InstructionDesc* id = &instructions_[bm[i].b];
    214     id->mnem = bm[i].mnem;
    215     id->op_order_ = bm[i].op_order_;
    216     ASSERT_EQ(NO_INSTR, id->type);  // Information not already entered.
    217     id->type = type;
    218   }
    219 }
    220 
    221 
    222 void InstructionTable::SetTableRange(InstructionType type,
    223                                      byte start,
    224                                      byte end,
    225                                      const char* mnem) {
    226   for (byte b = start; b <= end; b++) {
    227     InstructionDesc* id = &instructions_[b];
    228     ASSERT_EQ(NO_INSTR, id->type);  // Information not already entered.
    229     id->mnem = mnem;
    230     id->type = type;
    231   }
    232 }
    233 
    234 
    235 void InstructionTable::AddJumpConditionalShort() {
    236   for (byte b = 0x70; b <= 0x7F; b++) {
    237     InstructionDesc* id = &instructions_[b];
    238     ASSERT_EQ(NO_INSTR, id->type);  // Information not already entered.
    239     id->mnem = jump_conditional_mnem[b & 0x0F];
    240     id->type = JUMP_CONDITIONAL_SHORT_INSTR;
    241   }
    242 }
    243 
    244 
    245 static InstructionTable instruction_table;
    246 
    247 
    248 // The IA32 disassembler implementation.
    249 class DisassemblerIA32 {
    250  public:
    251   DisassemblerIA32(const NameConverter& converter,
    252                    bool abort_on_unimplemented = true)
    253       : converter_(converter),
    254         tmp_buffer_pos_(0),
    255         abort_on_unimplemented_(abort_on_unimplemented) {
    256     tmp_buffer_[0] = '\0';
    257   }
    258 
    259   virtual ~DisassemblerIA32() {}
    260 
    261   // Writes one disassembled instruction into 'buffer' (0-terminated).
    262   // Returns the length of the disassembled machine instruction in bytes.
    263   int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
    264 
    265  private:
    266   const NameConverter& converter_;
    267   v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
    268   unsigned int tmp_buffer_pos_;
    269   bool abort_on_unimplemented_;
    270 
    271 
    272   enum {
    273     eax = 0,
    274     ecx = 1,
    275     edx = 2,
    276     ebx = 3,
    277     esp = 4,
    278     ebp = 5,
    279     esi = 6,
    280     edi = 7
    281   };
    282 
    283 
    284   enum ShiftOpcodeExtension {
    285     kROL = 0,
    286     kROR = 1,
    287     kRCL = 2,
    288     kRCR = 3,
    289     kSHL = 4,
    290     KSHR = 5,
    291     kSAR = 7
    292   };
    293 
    294 
    295   const char* NameOfCPURegister(int reg) const {
    296     return converter_.NameOfCPURegister(reg);
    297   }
    298 
    299 
    300   const char* NameOfByteCPURegister(int reg) const {
    301     return converter_.NameOfByteCPURegister(reg);
    302   }
    303 
    304 
    305   const char* NameOfXMMRegister(int reg) const {
    306     return converter_.NameOfXMMRegister(reg);
    307   }
    308 
    309 
    310   const char* NameOfAddress(byte* addr) const {
    311     return converter_.NameOfAddress(addr);
    312   }
    313 
    314 
    315   // Disassembler helper functions.
    316   static void get_modrm(byte data, int* mod, int* regop, int* rm) {
    317     *mod = (data >> 6) & 3;
    318     *regop = (data & 0x38) >> 3;
    319     *rm = data & 7;
    320   }
    321 
    322 
    323   static void get_sib(byte data, int* scale, int* index, int* base) {
    324     *scale = (data >> 6) & 3;
    325     *index = (data >> 3) & 7;
    326     *base = data & 7;
    327   }
    328 
    329   typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const;
    330 
    331   int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
    332   int PrintRightOperand(byte* modrmp);
    333   int PrintRightByteOperand(byte* modrmp);
    334   int PrintRightXMMOperand(byte* modrmp);
    335   int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
    336   int PrintImmediateOp(byte* data);
    337   int F7Instruction(byte* data);
    338   int D1D3C1Instruction(byte* data);
    339   int JumpShort(byte* data);
    340   int JumpConditional(byte* data, const char* comment);
    341   int JumpConditionalShort(byte* data, const char* comment);
    342   int SetCC(byte* data);
    343   int CMov(byte* data);
    344   int FPUInstruction(byte* data);
    345   int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
    346   int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
    347   void AppendToBuffer(const char* format, ...);
    348 
    349 
    350   void UnimplementedInstruction() {
    351     if (abort_on_unimplemented_) {
    352       UNIMPLEMENTED();
    353     } else {
    354       AppendToBuffer("'Unimplemented Instruction'");
    355     }
    356   }
    357 };
    358 
    359 
    360 void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
    361   v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
    362   va_list args;
    363   va_start(args, format);
    364   int result = v8::internal::OS::VSNPrintF(buf, format, args);
    365   va_end(args);
    366   tmp_buffer_pos_ += result;
    367 }
    368 
    369 int DisassemblerIA32::PrintRightOperandHelper(
    370     byte* modrmp,
    371     RegisterNameMapping direct_register_name) {
    372   int mod, regop, rm;
    373   get_modrm(*modrmp, &mod, &regop, &rm);
    374   RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
    375       &DisassemblerIA32::NameOfCPURegister;
    376   switch (mod) {
    377     case 0:
    378       if (rm == ebp) {
    379         int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
    380         AppendToBuffer("[0x%x]", disp);
    381         return 5;
    382       } else if (rm == esp) {
    383         byte sib = *(modrmp + 1);
    384         int scale, index, base;
    385         get_sib(sib, &scale, &index, &base);
    386         if (index == esp && base == esp && scale == 0 /*times_1*/) {
    387           AppendToBuffer("[%s]", (this->*register_name)(rm));
    388           return 2;
    389         } else if (base == ebp) {
    390           int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
    391           AppendToBuffer("[%s*%d+0x%x]",
    392                          (this->*register_name)(index),
    393                          1 << scale,
    394                          disp);
    395           return 6;
    396         } else if (index != esp && base != ebp) {
    397           // [base+index*scale]
    398           AppendToBuffer("[%s+%s*%d]",
    399                          (this->*register_name)(base),
    400                          (this->*register_name)(index),
    401                          1 << scale);
    402           return 2;
    403         } else {
    404           UnimplementedInstruction();
    405           return 1;
    406         }
    407       } else {
    408         AppendToBuffer("[%s]", (this->*register_name)(rm));
    409         return 1;
    410       }
    411       break;
    412     case 1:  // fall through
    413     case 2:
    414       if (rm == esp) {
    415         byte sib = *(modrmp + 1);
    416         int scale, index, base;
    417         get_sib(sib, &scale, &index, &base);
    418         int disp =
    419             mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2) : *(modrmp + 2);
    420         if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
    421           AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp);
    422         } else {
    423           AppendToBuffer("[%s+%s*%d+0x%x]",
    424                          (this->*register_name)(base),
    425                          (this->*register_name)(index),
    426                          1 << scale,
    427                          disp);
    428         }
    429         return mod == 2 ? 6 : 3;
    430       } else {
    431         // No sib.
    432         int disp =
    433             mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1) : *(modrmp + 1);
    434         AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp);
    435         return mod == 2 ? 5 : 2;
    436       }
    437       break;
    438     case 3:
    439       AppendToBuffer("%s", (this->*register_name)(rm));
    440       return 1;
    441     default:
    442       UnimplementedInstruction();
    443       return 1;
    444   }
    445   UNREACHABLE();
    446 }
    447 
    448 
    449 int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
    450   return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
    451 }
    452 
    453 
    454 int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
    455   return PrintRightOperandHelper(modrmp,
    456                                  &DisassemblerIA32::NameOfByteCPURegister);
    457 }
    458 
    459 
    460 int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
    461   return PrintRightOperandHelper(modrmp,
    462                                  &DisassemblerIA32::NameOfXMMRegister);
    463 }
    464 
    465 
    466 // Returns number of bytes used including the current *data.
    467 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
    468 int DisassemblerIA32::PrintOperands(const char* mnem,
    469                                     OperandOrder op_order,
    470                                     byte* data) {
    471   byte modrm = *data;
    472   int mod, regop, rm;
    473   get_modrm(modrm, &mod, &regop, &rm);
    474   int advance = 0;
    475   switch (op_order) {
    476     case REG_OPER_OP_ORDER: {
    477       AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
    478       advance = PrintRightOperand(data);
    479       break;
    480     }
    481     case OPER_REG_OP_ORDER: {
    482       AppendToBuffer("%s ", mnem);
    483       advance = PrintRightOperand(data);
    484       AppendToBuffer(",%s", NameOfCPURegister(regop));
    485       break;
    486     }
    487     default:
    488       UNREACHABLE();
    489       break;
    490   }
    491   return advance;
    492 }
    493 
    494 
    495 // Returns number of bytes used by machine instruction, including *data byte.
    496 // Writes immediate instructions to 'tmp_buffer_'.
    497 int DisassemblerIA32::PrintImmediateOp(byte* data) {
    498   bool sign_extension_bit = (*data & 0x02) != 0;
    499   byte modrm = *(data+1);
    500   int mod, regop, rm;
    501   get_modrm(modrm, &mod, &regop, &rm);
    502   const char* mnem = "Imm???";
    503   switch (regop) {
    504     case 0: mnem = "add"; break;
    505     case 1: mnem = "or"; break;
    506     case 2: mnem = "adc"; break;
    507     case 4: mnem = "and"; break;
    508     case 5: mnem = "sub"; break;
    509     case 6: mnem = "xor"; break;
    510     case 7: mnem = "cmp"; break;
    511     default: UnimplementedInstruction();
    512   }
    513   AppendToBuffer("%s ", mnem);
    514   int count = PrintRightOperand(data+1);
    515   if (sign_extension_bit) {
    516     AppendToBuffer(",0x%x", *(data + 1 + count));
    517     return 1 + count + 1 /*int8*/;
    518   } else {
    519     AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
    520     return 1 + count + 4 /*int32_t*/;
    521   }
    522 }
    523 
    524 
    525 // Returns number of bytes used, including *data.
    526 int DisassemblerIA32::F7Instruction(byte* data) {
    527   ASSERT_EQ(0xF7, *data);
    528   byte modrm = *(data+1);
    529   int mod, regop, rm;
    530   get_modrm(modrm, &mod, &regop, &rm);
    531   if (mod == 3 && regop != 0) {
    532     const char* mnem = NULL;
    533     switch (regop) {
    534       case 2: mnem = "not"; break;
    535       case 3: mnem = "neg"; break;
    536       case 4: mnem = "mul"; break;
    537       case 7: mnem = "idiv"; break;
    538       default: UnimplementedInstruction();
    539     }
    540     AppendToBuffer("%s %s", mnem, NameOfCPURegister(rm));
    541     return 2;
    542   } else if (mod == 3 && regop == eax) {
    543     int32_t imm = *reinterpret_cast<int32_t*>(data+2);
    544     AppendToBuffer("test %s,0x%x", NameOfCPURegister(rm), imm);
    545     return 6;
    546   } else if (regop == eax) {
    547     AppendToBuffer("test ");
    548     int count = PrintRightOperand(data+1);
    549     int32_t imm = *reinterpret_cast<int32_t*>(data+1+count);
    550     AppendToBuffer(",0x%x", imm);
    551     return 1+count+4 /*int32_t*/;
    552   } else {
    553     UnimplementedInstruction();
    554     return 2;
    555   }
    556 }
    557 
    558 int DisassemblerIA32::D1D3C1Instruction(byte* data) {
    559   byte op = *data;
    560   ASSERT(op == 0xD1 || op == 0xD3 || op == 0xC1);
    561   byte modrm = *(data+1);
    562   int mod, regop, rm;
    563   get_modrm(modrm, &mod, &regop, &rm);
    564   int imm8 = -1;
    565   int num_bytes = 2;
    566   if (mod == 3) {
    567     const char* mnem = NULL;
    568     switch (regop) {
    569       case kROL: mnem = "rol"; break;
    570       case kROR: mnem = "ror"; break;
    571       case kRCL: mnem = "rcl"; break;
    572       case kRCR: mnem = "rcr"; break;
    573       case kSHL: mnem = "shl"; break;
    574       case KSHR: mnem = "shr"; break;
    575       case kSAR: mnem = "sar"; break;
    576       default: UnimplementedInstruction();
    577     }
    578     if (op == 0xD1) {
    579       imm8 = 1;
    580     } else if (op == 0xC1) {
    581       imm8 = *(data+2);
    582       num_bytes = 3;
    583     } else if (op == 0xD3) {
    584       // Shift/rotate by cl.
    585     }
    586     ASSERT_NE(NULL, mnem);
    587     AppendToBuffer("%s %s,", mnem, NameOfCPURegister(rm));
    588     if (imm8 > 0) {
    589       AppendToBuffer("%d", imm8);
    590     } else {
    591       AppendToBuffer("cl");
    592     }
    593   } else {
    594     UnimplementedInstruction();
    595   }
    596   return num_bytes;
    597 }
    598 
    599 
    600 // Returns number of bytes used, including *data.
    601 int DisassemblerIA32::JumpShort(byte* data) {
    602   ASSERT_EQ(0xEB, *data);
    603   byte b = *(data+1);
    604   byte* dest = data + static_cast<int8_t>(b) + 2;
    605   AppendToBuffer("jmp %s", NameOfAddress(dest));
    606   return 2;
    607 }
    608 
    609 
    610 // Returns number of bytes used, including *data.
    611 int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
    612   ASSERT_EQ(0x0F, *data);
    613   byte cond = *(data+1) & 0x0F;
    614   byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
    615   const char* mnem = jump_conditional_mnem[cond];
    616   AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
    617   if (comment != NULL) {
    618     AppendToBuffer(", %s", comment);
    619   }
    620   return 6;  // includes 0x0F
    621 }
    622 
    623 
    624 // Returns number of bytes used, including *data.
    625 int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
    626   byte cond = *data & 0x0F;
    627   byte b = *(data+1);
    628   byte* dest = data + static_cast<int8_t>(b) + 2;
    629   const char* mnem = jump_conditional_mnem[cond];
    630   AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
    631   if (comment != NULL) {
    632     AppendToBuffer(", %s", comment);
    633   }
    634   return 2;
    635 }
    636 
    637 
    638 // Returns number of bytes used, including *data.
    639 int DisassemblerIA32::SetCC(byte* data) {
    640   ASSERT_EQ(0x0F, *data);
    641   byte cond = *(data+1) & 0x0F;
    642   const char* mnem = set_conditional_mnem[cond];
    643   AppendToBuffer("%s ", mnem);
    644   PrintRightByteOperand(data+2);
    645   return 3;  // Includes 0x0F.
    646 }
    647 
    648 
    649 // Returns number of bytes used, including *data.
    650 int DisassemblerIA32::CMov(byte* data) {
    651   ASSERT_EQ(0x0F, *data);
    652   byte cond = *(data + 1) & 0x0F;
    653   const char* mnem = conditional_move_mnem[cond];
    654   int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
    655   return 2 + op_size;  // includes 0x0F
    656 }
    657 
    658 
    659 // Returns number of bytes used, including *data.
    660 int DisassemblerIA32::FPUInstruction(byte* data) {
    661   byte escape_opcode = *data;
    662   ASSERT_EQ(0xD8, escape_opcode & 0xF8);
    663   byte modrm_byte = *(data+1);
    664 
    665   if (modrm_byte >= 0xC0) {
    666     return RegisterFPUInstruction(escape_opcode, modrm_byte);
    667   } else {
    668     return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
    669   }
    670 }
    671 
    672 int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
    673                                            int modrm_byte,
    674                                            byte* modrm_start) {
    675   const char* mnem = "?";
    676   int regop = (modrm_byte >> 3) & 0x7;  // reg/op field of modrm byte.
    677   switch (escape_opcode) {
    678     case 0xD9: switch (regop) {
    679         case 0: mnem = "fld_s"; break;
    680         case 3: mnem = "fstp_s"; break;
    681         case 7: mnem = "fstcw"; break;
    682         default: UnimplementedInstruction();
    683       }
    684       break;
    685 
    686     case 0xDB: switch (regop) {
    687         case 0: mnem = "fild_s"; break;
    688         case 1: mnem = "fisttp_s"; break;
    689         case 2: mnem = "fist_s"; break;
    690         case 3: mnem = "fistp_s"; break;
    691         default: UnimplementedInstruction();
    692       }
    693       break;
    694 
    695     case 0xDD: switch (regop) {
    696         case 0: mnem = "fld_d"; break;
    697         case 1: mnem = "fisttp_d"; break;
    698         case 2: mnem = "fst_d"; break;
    699         case 3: mnem = "fstp_d"; break;
    700         default: UnimplementedInstruction();
    701       }
    702       break;
    703 
    704     case 0xDF: switch (regop) {
    705         case 5: mnem = "fild_d"; break;
    706         case 7: mnem = "fistp_d"; break;
    707         default: UnimplementedInstruction();
    708       }
    709       break;
    710 
    711     default: UnimplementedInstruction();
    712   }
    713   AppendToBuffer("%s ", mnem);
    714   int count = PrintRightOperand(modrm_start);
    715   return count + 1;
    716 }
    717 
    718 int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
    719                                              byte modrm_byte) {
    720   bool has_register = false;  // Is the FPU register encoded in modrm_byte?
    721   const char* mnem = "?";
    722 
    723   switch (escape_opcode) {
    724     case 0xD8:
    725       UnimplementedInstruction();
    726       break;
    727 
    728     case 0xD9:
    729       switch (modrm_byte & 0xF8) {
    730         case 0xC0:
    731           mnem = "fld";
    732           has_register = true;
    733           break;
    734         case 0xC8:
    735           mnem = "fxch";
    736           has_register = true;
    737           break;
    738         default:
    739           switch (modrm_byte) {
    740             case 0xE0: mnem = "fchs"; break;
    741             case 0xE1: mnem = "fabs"; break;
    742             case 0xE4: mnem = "ftst"; break;
    743             case 0xE8: mnem = "fld1"; break;
    744             case 0xEB: mnem = "fldpi"; break;
    745             case 0xED: mnem = "fldln2"; break;
    746             case 0xEE: mnem = "fldz"; break;
    747             case 0xF1: mnem = "fyl2x"; break;
    748             case 0xF5: mnem = "fprem1"; break;
    749             case 0xF7: mnem = "fincstp"; break;
    750             case 0xF8: mnem = "fprem"; break;
    751             case 0xFE: mnem = "fsin"; break;
    752             case 0xFF: mnem = "fcos"; break;
    753             default: UnimplementedInstruction();
    754           }
    755       }
    756       break;
    757 
    758     case 0xDA:
    759       if (modrm_byte == 0xE9) {
    760         mnem = "fucompp";
    761       } else {
    762         UnimplementedInstruction();
    763       }
    764       break;
    765 
    766     case 0xDB:
    767       if ((modrm_byte & 0xF8) == 0xE8) {
    768         mnem = "fucomi";
    769         has_register = true;
    770       } else if (modrm_byte  == 0xE2) {
    771         mnem = "fclex";
    772       } else {
    773         UnimplementedInstruction();
    774       }
    775       break;
    776 
    777     case 0xDC:
    778       has_register = true;
    779       switch (modrm_byte & 0xF8) {
    780         case 0xC0: mnem = "fadd"; break;
    781         case 0xE8: mnem = "fsub"; break;
    782         case 0xC8: mnem = "fmul"; break;
    783         case 0xF8: mnem = "fdiv"; break;
    784         default: UnimplementedInstruction();
    785       }
    786       break;
    787 
    788     case 0xDD:
    789       has_register = true;
    790       switch (modrm_byte & 0xF8) {
    791         case 0xC0: mnem = "ffree"; break;
    792         case 0xD8: mnem = "fstp"; break;
    793         default: UnimplementedInstruction();
    794       }
    795       break;
    796 
    797     case 0xDE:
    798       if (modrm_byte  == 0xD9) {
    799         mnem = "fcompp";
    800       } else {
    801         has_register = true;
    802         switch (modrm_byte & 0xF8) {
    803           case 0xC0: mnem = "faddp"; break;
    804           case 0xE8: mnem = "fsubp"; break;
    805           case 0xC8: mnem = "fmulp"; break;
    806           case 0xF8: mnem = "fdivp"; break;
    807           default: UnimplementedInstruction();
    808         }
    809       }
    810       break;
    811 
    812     case 0xDF:
    813       if (modrm_byte == 0xE0) {
    814         mnem = "fnstsw_ax";
    815       } else if ((modrm_byte & 0xF8) == 0xE8) {
    816         mnem = "fucomip";
    817         has_register = true;
    818       }
    819       break;
    820 
    821     default: UnimplementedInstruction();
    822   }
    823 
    824   if (has_register) {
    825     AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
    826   } else {
    827     AppendToBuffer("%s", mnem);
    828   }
    829   return 2;
    830 }
    831 
    832 
    833 // Mnemonics for instructions 0xF0 byte.
    834 // Returns NULL if the instruction is not handled here.
    835 static const char* F0Mnem(byte f0byte) {
    836   switch (f0byte) {
    837     case 0x18: return "prefetch";
    838     case 0xA2: return "cpuid";
    839     case 0x31: return "rdtsc";
    840     case 0xBE: return "movsx_b";
    841     case 0xBF: return "movsx_w";
    842     case 0xB6: return "movzx_b";
    843     case 0xB7: return "movzx_w";
    844     case 0xAF: return "imul";
    845     case 0xA5: return "shld";
    846     case 0xAD: return "shrd";
    847     case 0xAB: return "bts";
    848     default: return NULL;
    849   }
    850 }
    851 
    852 
    853 // Disassembled instruction '*instr' and writes it into 'out_buffer'.
    854 int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
    855                                         byte* instr) {
    856   tmp_buffer_pos_ = 0;  // starting to write as position 0
    857   byte* data = instr;
    858   // Check for hints.
    859   const char* branch_hint = NULL;
    860   // We use these two prefixes only with branch prediction
    861   if (*data == 0x3E /*ds*/) {
    862     branch_hint = "predicted taken";
    863     data++;
    864   } else if (*data == 0x2E /*cs*/) {
    865     branch_hint = "predicted not taken";
    866     data++;
    867   }
    868   bool processed = true;  // Will be set to false if the current instruction
    869                           // is not in 'instructions' table.
    870   const InstructionDesc& idesc = instruction_table.Get(*data);
    871   switch (idesc.type) {
    872     case ZERO_OPERANDS_INSTR:
    873       AppendToBuffer(idesc.mnem);
    874       data++;
    875       break;
    876 
    877     case TWO_OPERANDS_INSTR:
    878       data++;
    879       data += PrintOperands(idesc.mnem, idesc.op_order_, data);
    880       break;
    881 
    882     case JUMP_CONDITIONAL_SHORT_INSTR:
    883       data += JumpConditionalShort(data, branch_hint);
    884       break;
    885 
    886     case REGISTER_INSTR:
    887       AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
    888       data++;
    889       break;
    890 
    891     case MOVE_REG_INSTR: {
    892       byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
    893       AppendToBuffer("mov %s,%s",
    894                      NameOfCPURegister(*data & 0x07),
    895                      NameOfAddress(addr));
    896       data += 5;
    897       break;
    898     }
    899 
    900     case CALL_JUMP_INSTR: {
    901       byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5;
    902       AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
    903       data += 5;
    904       break;
    905     }
    906 
    907     case SHORT_IMMEDIATE_INSTR: {
    908       byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
    909       AppendToBuffer("%s eax, %s", idesc.mnem, NameOfAddress(addr));
    910       data += 5;
    911       break;
    912     }
    913 
    914     case NO_INSTR:
    915       processed = false;
    916       break;
    917 
    918     default:
    919       UNIMPLEMENTED();  // This type is not implemented.
    920   }
    921   //----------------------------
    922   if (!processed) {
    923     switch (*data) {
    924       case 0xC2:
    925         AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
    926         data += 3;
    927         break;
    928 
    929       case 0x69:  // fall through
    930       case 0x6B:
    931         { int mod, regop, rm;
    932           get_modrm(*(data+1), &mod, &regop, &rm);
    933           int32_t imm =
    934               *data == 0x6B ? *(data+2) : *reinterpret_cast<int32_t*>(data+2);
    935           AppendToBuffer("imul %s,%s,0x%x",
    936                          NameOfCPURegister(regop),
    937                          NameOfCPURegister(rm),
    938                          imm);
    939           data += 2 + (*data == 0x6B ? 1 : 4);
    940         }
    941         break;
    942 
    943       case 0xF6:
    944         { data++;
    945           int mod, regop, rm;
    946           get_modrm(*data, &mod, &regop, &rm);
    947           if (regop == eax) {
    948             AppendToBuffer("test_b ");
    949             data += PrintRightByteOperand(data);
    950             int32_t imm = *data;
    951             AppendToBuffer(",0x%x", imm);
    952             data++;
    953           } else {
    954             UnimplementedInstruction();
    955           }
    956         }
    957         break;
    958 
    959       case 0x81:  // fall through
    960       case 0x83:  // 0x81 with sign extension bit set
    961         data += PrintImmediateOp(data);
    962         break;
    963 
    964       case 0x0F:
    965         { byte f0byte = *(data+1);
    966           const char* f0mnem = F0Mnem(f0byte);
    967           if (f0byte == 0x18) {
    968             int mod, regop, rm;
    969             get_modrm(*data, &mod, &regop, &rm);
    970             const char* suffix[] = {"nta", "1", "2", "3"};
    971             AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
    972             data += PrintRightOperand(data);
    973           } else if (f0byte == 0xA2 || f0byte == 0x31) {
    974             AppendToBuffer("%s", f0mnem);
    975             data += 2;
    976           } else if (f0byte == 0x28) {
    977             data += 2;
    978             int mod, regop, rm;
    979             get_modrm(*data, &mod, &regop, &rm);
    980             AppendToBuffer("movaps %s,%s",
    981                            NameOfXMMRegister(regop),
    982                            NameOfXMMRegister(rm));
    983             data++;
    984           } else if ((f0byte & 0xF0) == 0x80) {
    985             data += JumpConditional(data, branch_hint);
    986           } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
    987                      f0byte == 0xB7 || f0byte == 0xAF) {
    988             data += 2;
    989             data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
    990           } else if ((f0byte & 0xF0) == 0x90) {
    991             data += SetCC(data);
    992           } else if ((f0byte & 0xF0) == 0x40) {
    993             data += CMov(data);
    994           } else {
    995             data += 2;
    996             if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
    997               // shrd, shld, bts
    998               AppendToBuffer("%s ", f0mnem);
    999               int mod, regop, rm;
   1000               get_modrm(*data, &mod, &regop, &rm);
   1001               data += PrintRightOperand(data);
   1002               if (f0byte == 0xAB) {
   1003                 AppendToBuffer(",%s", NameOfCPURegister(regop));
   1004               } else {
   1005                 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
   1006               }
   1007             } else {
   1008               UnimplementedInstruction();
   1009             }
   1010           }
   1011         }
   1012         break;
   1013 
   1014       case 0x8F:
   1015         { data++;
   1016           int mod, regop, rm;
   1017           get_modrm(*data, &mod, &regop, &rm);
   1018           if (regop == eax) {
   1019             AppendToBuffer("pop ");
   1020             data += PrintRightOperand(data);
   1021           }
   1022         }
   1023         break;
   1024 
   1025       case 0xFF:
   1026         { data++;
   1027           int mod, regop, rm;
   1028           get_modrm(*data, &mod, &regop, &rm);
   1029           const char* mnem = NULL;
   1030           switch (regop) {
   1031             case esi: mnem = "push"; break;
   1032             case eax: mnem = "inc"; break;
   1033             case ecx: mnem = "dec"; break;
   1034             case edx: mnem = "call"; break;
   1035             case esp: mnem = "jmp"; break;
   1036             default: mnem = "???";
   1037           }
   1038           AppendToBuffer("%s ", mnem);
   1039           data += PrintRightOperand(data);
   1040         }
   1041         break;
   1042 
   1043       case 0xC7:  // imm32, fall through
   1044       case 0xC6:  // imm8
   1045         { bool is_byte = *data == 0xC6;
   1046           data++;
   1047           if (is_byte) {
   1048             AppendToBuffer("%s ", "mov_b");
   1049             data += PrintRightByteOperand(data);
   1050             int32_t imm = *data;
   1051             AppendToBuffer(",0x%x", imm);
   1052             data++;
   1053           } else {
   1054             AppendToBuffer("%s ", "mov");
   1055             data += PrintRightOperand(data);
   1056             int32_t imm = *reinterpret_cast<int32_t*>(data);
   1057             AppendToBuffer(",0x%x", imm);
   1058             data += 4;
   1059           }
   1060         }
   1061         break;
   1062 
   1063       case 0x80:
   1064         { data++;
   1065           int mod, regop, rm;
   1066           get_modrm(*data, &mod, &regop, &rm);
   1067           const char* mnem = NULL;
   1068           switch (regop) {
   1069             case 5:  mnem = "subb"; break;
   1070             case 7:  mnem = "cmpb"; break;
   1071             default: UnimplementedInstruction();
   1072           }
   1073           AppendToBuffer("%s ", mnem);
   1074           data += PrintRightByteOperand(data);
   1075           int32_t imm = *data;
   1076           AppendToBuffer(",0x%x", imm);
   1077           data++;
   1078         }
   1079         break;
   1080 
   1081       case 0x88:  // 8bit, fall through
   1082       case 0x89:  // 32bit
   1083         { bool is_byte = *data == 0x88;
   1084           int mod, regop, rm;
   1085           data++;
   1086           get_modrm(*data, &mod, &regop, &rm);
   1087           if (is_byte) {
   1088             AppendToBuffer("%s ", "mov_b");
   1089             data += PrintRightByteOperand(data);
   1090             AppendToBuffer(",%s", NameOfByteCPURegister(regop));
   1091           } else {
   1092             AppendToBuffer("%s ", "mov");
   1093             data += PrintRightOperand(data);
   1094             AppendToBuffer(",%s", NameOfCPURegister(regop));
   1095           }
   1096         }
   1097         break;
   1098 
   1099       case 0x66:  // prefix
   1100         data++;
   1101         if (*data == 0x8B) {
   1102           data++;
   1103           data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
   1104         } else if (*data == 0x89) {
   1105           data++;
   1106           int mod, regop, rm;
   1107           get_modrm(*data, &mod, &regop, &rm);
   1108           AppendToBuffer("mov_w ");
   1109           data += PrintRightOperand(data);
   1110           AppendToBuffer(",%s", NameOfCPURegister(regop));
   1111         } else if (*data == 0x0F) {
   1112           data++;
   1113           if (*data == 0x38) {
   1114             data++;
   1115             if (*data == 0x17) {
   1116               data++;
   1117               int mod, regop, rm;
   1118               get_modrm(*data, &mod, &regop, &rm);
   1119               AppendToBuffer("ptest %s,%s",
   1120                              NameOfXMMRegister(regop),
   1121                              NameOfXMMRegister(rm));
   1122               data++;
   1123             } else if (*data == 0x2A) {
   1124               // movntdqa
   1125               data++;
   1126               int mod, regop, rm;
   1127               get_modrm(*data, &mod, &regop, &rm);
   1128               AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop));
   1129               data += PrintRightOperand(data);
   1130             } else {
   1131               UnimplementedInstruction();
   1132             }
   1133           } else if (*data == 0x3A) {
   1134             data++;
   1135             if (*data == 0x16) {
   1136               data++;
   1137               int mod, regop, rm;
   1138               get_modrm(*data, &mod, &regop, &rm);
   1139               int8_t imm8 = static_cast<int8_t>(data[1]);
   1140               AppendToBuffer("pextrd %s,%s,%d",
   1141                              NameOfCPURegister(regop),
   1142                              NameOfXMMRegister(rm),
   1143                              static_cast<int>(imm8));
   1144               data += 2;
   1145             } else if (*data == 0x22) {
   1146               data++;
   1147               int mod, regop, rm;
   1148               get_modrm(*data, &mod, &regop, &rm);
   1149               int8_t imm8 = static_cast<int8_t>(data[1]);
   1150               AppendToBuffer("pinsrd %s,%s,%d",
   1151                              NameOfXMMRegister(regop),
   1152                              NameOfCPURegister(rm),
   1153                              static_cast<int>(imm8));
   1154               data += 2;
   1155             } else {
   1156               UnimplementedInstruction();
   1157             }
   1158           } else if (*data == 0x2E || *data == 0x2F) {
   1159             const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
   1160             data++;
   1161             int mod, regop, rm;
   1162             get_modrm(*data, &mod, &regop, &rm);
   1163             if (mod == 0x3) {
   1164               AppendToBuffer("%s %s,%s", mnem,
   1165                              NameOfXMMRegister(regop),
   1166                              NameOfXMMRegister(rm));
   1167               data++;
   1168             } else {
   1169               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
   1170               data += PrintRightOperand(data);
   1171             }
   1172           } else if (*data == 0x50) {
   1173             data++;
   1174             int mod, regop, rm;
   1175             get_modrm(*data, &mod, &regop, &rm);
   1176             AppendToBuffer("movmskpd %s,%s",
   1177                            NameOfCPURegister(regop),
   1178                            NameOfXMMRegister(rm));
   1179             data++;
   1180           } else if (*data == 0x54) {
   1181             data++;
   1182             int mod, regop, rm;
   1183             get_modrm(*data, &mod, &regop, &rm);
   1184             AppendToBuffer("andpd %s,%s",
   1185                            NameOfXMMRegister(regop),
   1186                            NameOfXMMRegister(rm));
   1187             data++;
   1188           } else if (*data == 0x57) {
   1189             data++;
   1190             int mod, regop, rm;
   1191             get_modrm(*data, &mod, &regop, &rm);
   1192             AppendToBuffer("xorpd %s,%s",
   1193                            NameOfXMMRegister(regop),
   1194                            NameOfXMMRegister(rm));
   1195             data++;
   1196           } else if (*data == 0x6E) {
   1197             data++;
   1198             int mod, regop, rm;
   1199             get_modrm(*data, &mod, &regop, &rm);
   1200             AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
   1201             data += PrintRightOperand(data);
   1202           } else if (*data == 0x6F) {
   1203             data++;
   1204             int mod, regop, rm;
   1205             get_modrm(*data, &mod, &regop, &rm);
   1206             AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
   1207             data += PrintRightXMMOperand(data);
   1208           } else if (*data == 0x70) {
   1209             data++;
   1210             int mod, regop, rm;
   1211             get_modrm(*data, &mod, &regop, &rm);
   1212             int8_t imm8 = static_cast<int8_t>(data[1]);
   1213             AppendToBuffer("pshufd %s,%s,%d",
   1214                            NameOfXMMRegister(regop),
   1215                            NameOfXMMRegister(rm),
   1216                            static_cast<int>(imm8));
   1217             data += 2;
   1218           } else if (*data == 0xF3) {
   1219             data++;
   1220             int mod, regop, rm;
   1221             get_modrm(*data, &mod, &regop, &rm);
   1222             AppendToBuffer("psllq %s,%s",
   1223                            NameOfXMMRegister(regop),
   1224                            NameOfXMMRegister(rm));
   1225             data++;
   1226           } else if (*data == 0x73) {
   1227             data++;
   1228             int mod, regop, rm;
   1229             get_modrm(*data, &mod, &regop, &rm);
   1230             int8_t imm8 = static_cast<int8_t>(data[1]);
   1231             ASSERT(regop == esi || regop == edx);
   1232             AppendToBuffer("%s %s,%d",
   1233                            (regop == esi) ? "psllq" : "psrlq",
   1234                            NameOfXMMRegister(rm),
   1235                            static_cast<int>(imm8));
   1236             data += 2;
   1237           } else if (*data == 0xD3) {
   1238             data++;
   1239             int mod, regop, rm;
   1240             get_modrm(*data, &mod, &regop, &rm);
   1241             AppendToBuffer("psrlq %s,%s",
   1242                            NameOfXMMRegister(regop),
   1243                            NameOfXMMRegister(rm));
   1244             data++;
   1245           } else if (*data == 0x7F) {
   1246             AppendToBuffer("movdqa ");
   1247             data++;
   1248             int mod, regop, rm;
   1249             get_modrm(*data, &mod, &regop, &rm);
   1250             data += PrintRightXMMOperand(data);
   1251             AppendToBuffer(",%s", NameOfXMMRegister(regop));
   1252           } else if (*data == 0x7E) {
   1253             data++;
   1254             int mod, regop, rm;
   1255             get_modrm(*data, &mod, &regop, &rm);
   1256             AppendToBuffer("movd ");
   1257             data += PrintRightOperand(data);
   1258             AppendToBuffer(",%s", NameOfXMMRegister(regop));
   1259           } else if (*data == 0xDB) {
   1260             data++;
   1261             int mod, regop, rm;
   1262             get_modrm(*data, &mod, &regop, &rm);
   1263             AppendToBuffer("pand %s,%s",
   1264                            NameOfXMMRegister(regop),
   1265                            NameOfXMMRegister(rm));
   1266             data++;
   1267           } else if (*data == 0xE7) {
   1268             data++;
   1269             int mod, regop, rm;
   1270             get_modrm(*data, &mod, &regop, &rm);
   1271             if (mod == 3) {
   1272               AppendToBuffer("movntdq ");
   1273               data += PrintRightOperand(data);
   1274               AppendToBuffer(",%s", NameOfXMMRegister(regop));
   1275             } else {
   1276               UnimplementedInstruction();
   1277             }
   1278           } else if (*data == 0xEF) {
   1279             data++;
   1280             int mod, regop, rm;
   1281             get_modrm(*data, &mod, &regop, &rm);
   1282             AppendToBuffer("pxor %s,%s",
   1283                            NameOfXMMRegister(regop),
   1284                            NameOfXMMRegister(rm));
   1285             data++;
   1286           } else if (*data == 0xEB) {
   1287             data++;
   1288             int mod, regop, rm;
   1289             get_modrm(*data, &mod, &regop, &rm);
   1290             AppendToBuffer("por %s,%s",
   1291                            NameOfXMMRegister(regop),
   1292                            NameOfXMMRegister(rm));
   1293             data++;
   1294           } else {
   1295             UnimplementedInstruction();
   1296           }
   1297         } else {
   1298           UnimplementedInstruction();
   1299         }
   1300         break;
   1301 
   1302       case 0xFE:
   1303         { data++;
   1304           int mod, regop, rm;
   1305           get_modrm(*data, &mod, &regop, &rm);
   1306           if (regop == ecx) {
   1307             AppendToBuffer("dec_b ");
   1308             data += PrintRightOperand(data);
   1309           } else {
   1310             UnimplementedInstruction();
   1311           }
   1312         }
   1313         break;
   1314 
   1315       case 0x68:
   1316         AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
   1317         data += 5;
   1318         break;
   1319 
   1320       case 0x6A:
   1321         AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
   1322         data += 2;
   1323         break;
   1324 
   1325       case 0xA8:
   1326         AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
   1327         data += 2;
   1328         break;
   1329 
   1330       case 0x2C:
   1331         AppendToBuffer("subb eax,0x%x", *reinterpret_cast<uint8_t*>(data+1));
   1332         data += 2;
   1333         break;
   1334 
   1335       case 0xA9:
   1336         AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
   1337         data += 5;
   1338         break;
   1339 
   1340       case 0xD1:  // fall through
   1341       case 0xD3:  // fall through
   1342       case 0xC1:
   1343         data += D1D3C1Instruction(data);
   1344         break;
   1345 
   1346       case 0xD9:  // fall through
   1347       case 0xDA:  // fall through
   1348       case 0xDB:  // fall through
   1349       case 0xDC:  // fall through
   1350       case 0xDD:  // fall through
   1351       case 0xDE:  // fall through
   1352       case 0xDF:
   1353         data += FPUInstruction(data);
   1354         break;
   1355 
   1356       case 0xEB:
   1357         data += JumpShort(data);
   1358         break;
   1359 
   1360       case 0xF2:
   1361         if (*(data+1) == 0x0F) {
   1362           byte b2 = *(data+2);
   1363           if (b2 == 0x11) {
   1364             AppendToBuffer("movsd ");
   1365             data += 3;
   1366             int mod, regop, rm;
   1367             get_modrm(*data, &mod, &regop, &rm);
   1368             data += PrintRightXMMOperand(data);
   1369             AppendToBuffer(",%s", NameOfXMMRegister(regop));
   1370           } else if (b2 == 0x10) {
   1371             data += 3;
   1372             int mod, regop, rm;
   1373             get_modrm(*data, &mod, &regop, &rm);
   1374             AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
   1375             data += PrintRightXMMOperand(data);
   1376           } else  if (b2 == 0x5A) {
   1377             data += 3;
   1378             int mod, regop, rm;
   1379             get_modrm(*data, &mod, &regop, &rm);
   1380             AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
   1381             data += PrintRightXMMOperand(data);
   1382           } else {
   1383             const char* mnem = "?";
   1384             switch (b2) {
   1385               case 0x2A: mnem = "cvtsi2sd"; break;
   1386               case 0x2C: mnem = "cvttsd2si"; break;
   1387               case 0x51: mnem = "sqrtsd"; break;
   1388               case 0x58: mnem = "addsd"; break;
   1389               case 0x59: mnem = "mulsd"; break;
   1390               case 0x5C: mnem = "subsd"; break;
   1391               case 0x5E: mnem = "divsd"; break;
   1392             }
   1393             data += 3;
   1394             int mod, regop, rm;
   1395             get_modrm(*data, &mod, &regop, &rm);
   1396             if (b2 == 0x2A) {
   1397               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
   1398               data += PrintRightOperand(data);
   1399             } else if (b2 == 0x2C) {
   1400               AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
   1401               data += PrintRightXMMOperand(data);
   1402             } else if (b2 == 0xC2) {
   1403               // Intel manual 2A, Table 3-18.
   1404               const char* const pseudo_op[] = {
   1405                 "cmpeqsd",
   1406                 "cmpltsd",
   1407                 "cmplesd",
   1408                 "cmpunordsd",
   1409                 "cmpneqsd",
   1410                 "cmpnltsd",
   1411                 "cmpnlesd",
   1412                 "cmpordsd"
   1413               };
   1414               AppendToBuffer("%s %s,%s",
   1415                              pseudo_op[data[1]],
   1416                              NameOfXMMRegister(regop),
   1417                              NameOfXMMRegister(rm));
   1418               data += 2;
   1419             } else {
   1420               AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
   1421               data += PrintRightXMMOperand(data);
   1422             }
   1423           }
   1424         } else {
   1425           UnimplementedInstruction();
   1426         }
   1427         break;
   1428 
   1429       case 0xF3:
   1430         if (*(data+1) == 0x0F) {
   1431           byte b2 = *(data+2);
   1432           if (b2 == 0x11) {
   1433             AppendToBuffer("movss ");
   1434             data += 3;
   1435             int mod, regop, rm;
   1436             get_modrm(*data, &mod, &regop, &rm);
   1437             data += PrintRightXMMOperand(data);
   1438             AppendToBuffer(",%s", NameOfXMMRegister(regop));
   1439           } else if (b2 == 0x10) {
   1440             data += 3;
   1441             int mod, regop, rm;
   1442             get_modrm(*data, &mod, &regop, &rm);
   1443             AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
   1444             data += PrintRightXMMOperand(data);
   1445           } else if (b2 == 0x2C) {
   1446             data += 3;
   1447             int mod, regop, rm;
   1448             get_modrm(*data, &mod, &regop, &rm);
   1449             AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
   1450             data += PrintRightXMMOperand(data);
   1451           } else if (b2 == 0x5A) {
   1452             data += 3;
   1453             int mod, regop, rm;
   1454             get_modrm(*data, &mod, &regop, &rm);
   1455             AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
   1456             data += PrintRightXMMOperand(data);
   1457           } else  if (b2 == 0x6F) {
   1458             data += 3;
   1459             int mod, regop, rm;
   1460             get_modrm(*data, &mod, &regop, &rm);
   1461             AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
   1462             data += PrintRightXMMOperand(data);
   1463           } else  if (b2 == 0x7F) {
   1464             AppendToBuffer("movdqu ");
   1465             data += 3;
   1466             int mod, regop, rm;
   1467             get_modrm(*data, &mod, &regop, &rm);
   1468             data += PrintRightXMMOperand(data);
   1469             AppendToBuffer(",%s", NameOfXMMRegister(regop));
   1470           } else {
   1471             UnimplementedInstruction();
   1472           }
   1473         } else if (*(data+1) == 0xA5) {
   1474           data += 2;
   1475           AppendToBuffer("rep_movs");
   1476         } else if (*(data+1) == 0xAB) {
   1477           data += 2;
   1478           AppendToBuffer("rep_stos");
   1479         } else {
   1480           UnimplementedInstruction();
   1481         }
   1482         break;
   1483 
   1484       case 0xF7:
   1485         data += F7Instruction(data);
   1486         break;
   1487 
   1488       default:
   1489         UnimplementedInstruction();
   1490     }
   1491   }
   1492 
   1493   if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
   1494     tmp_buffer_[tmp_buffer_pos_] = '\0';
   1495   }
   1496 
   1497   int instr_len = data - instr;
   1498   if (instr_len == 0) {
   1499     printf("%02x", *data);
   1500   }
   1501   ASSERT(instr_len > 0);  // Ensure progress.
   1502 
   1503   int outp = 0;
   1504   // Instruction bytes.
   1505   for (byte* bp = instr; bp < data; bp++) {
   1506     outp += v8::internal::OS::SNPrintF(out_buffer + outp,
   1507                                        "%02x",
   1508                                        *bp);
   1509   }
   1510   for (int i = 6 - instr_len; i >= 0; i--) {
   1511     outp += v8::internal::OS::SNPrintF(out_buffer + outp,
   1512                                        "  ");
   1513   }
   1514 
   1515   outp += v8::internal::OS::SNPrintF(out_buffer + outp,
   1516                                      " %s",
   1517                                      tmp_buffer_.start());
   1518   return instr_len;
   1519 }  // NOLINT (function is too long)
   1520 
   1521 
   1522 //------------------------------------------------------------------------------
   1523 
   1524 
   1525 static const char* cpu_regs[8] = {
   1526   "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
   1527 };
   1528 
   1529 
   1530 static const char* byte_cpu_regs[8] = {
   1531   "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
   1532 };
   1533 
   1534 
   1535 static const char* xmm_regs[8] = {
   1536   "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
   1537 };
   1538 
   1539 
   1540 const char* NameConverter::NameOfAddress(byte* addr) const {
   1541   v8::internal::OS::SNPrintF(tmp_buffer_, "%p", addr);
   1542   return tmp_buffer_.start();
   1543 }
   1544 
   1545 
   1546 const char* NameConverter::NameOfConstant(byte* addr) const {
   1547   return NameOfAddress(addr);
   1548 }
   1549 
   1550 
   1551 const char* NameConverter::NameOfCPURegister(int reg) const {
   1552   if (0 <= reg && reg < 8) return cpu_regs[reg];
   1553   return "noreg";
   1554 }
   1555 
   1556 
   1557 const char* NameConverter::NameOfByteCPURegister(int reg) const {
   1558   if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
   1559   return "noreg";
   1560 }
   1561 
   1562 
   1563 const char* NameConverter::NameOfXMMRegister(int reg) const {
   1564   if (0 <= reg && reg < 8) return xmm_regs[reg];
   1565   return "noxmmreg";
   1566 }
   1567 
   1568 
   1569 const char* NameConverter::NameInCode(byte* addr) const {
   1570   // IA32 does not embed debug strings at the moment.
   1571   UNREACHABLE();
   1572   return "";
   1573 }
   1574 
   1575 
   1576 //------------------------------------------------------------------------------
   1577 
   1578 Disassembler::Disassembler(const NameConverter& converter)
   1579     : converter_(converter) {}
   1580 
   1581 
   1582 Disassembler::~Disassembler() {}
   1583 
   1584 
   1585 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
   1586                                     byte* instruction) {
   1587   DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
   1588   return d.InstructionDecode(buffer, instruction);
   1589 }
   1590 
   1591 
   1592 // The IA-32 assembler does not currently use constant pools.
   1593 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
   1594 
   1595 
   1596 /*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
   1597   NameConverter converter;
   1598   Disassembler d(converter);
   1599   for (byte* pc = begin; pc < end;) {
   1600     v8::internal::EmbeddedVector<char, 128> buffer;
   1601     buffer[0] = '\0';
   1602     byte* prev_pc = pc;
   1603     pc += d.InstructionDecode(buffer, pc);
   1604     fprintf(f, "%p", prev_pc);
   1605     fprintf(f, "    ");
   1606 
   1607     for (byte* bp = prev_pc; bp < pc; bp++) {
   1608       fprintf(f, "%02x",  *bp);
   1609     }
   1610     for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
   1611       fprintf(f, "  ");
   1612     }
   1613     fprintf(f, "  %s\n", buffer.start());
   1614   }
   1615 }
   1616 
   1617 
   1618 }  // namespace disasm
   1619 
   1620 #endif  // V8_TARGET_ARCH_IA32
   1621