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