Home | History | Annotate | Download | only in x64
      1 // Copyright 2009 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 OperandType {
     38   UNSET_OP_ORDER = 0,
     39   // Operand size decides between 16, 32 and 64 bit operands.
     40   REG_OPER_OP_ORDER = 1,  // Register destination, operand source.
     41   OPER_REG_OP_ORDER = 2,  // Operand destination, register source.
     42   // Fixed 8-bit operands.
     43   BYTE_SIZE_OPERAND_FLAG = 4,
     44   BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG,
     45   BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
     46 };
     47 
     48 //------------------------------------------------------------------
     49 // Tables
     50 //------------------------------------------------------------------
     51 struct ByteMnemonic {
     52   int b;  // -1 terminates, otherwise must be in range (0..255)
     53   OperandType op_order_;
     54   const char* mnem;
     55 };
     56 
     57 
     58 static ByteMnemonic two_operands_instr[] = {
     59   { 0x00, BYTE_OPER_REG_OP_ORDER, "add" },
     60   { 0x01, OPER_REG_OP_ORDER,      "add" },
     61   { 0x02, BYTE_REG_OPER_OP_ORDER, "add" },
     62   { 0x03, REG_OPER_OP_ORDER,      "add" },
     63   { 0x08, BYTE_OPER_REG_OP_ORDER, "or" },
     64   { 0x09, OPER_REG_OP_ORDER,      "or" },
     65   { 0x0A, BYTE_REG_OPER_OP_ORDER, "or" },
     66   { 0x0B, REG_OPER_OP_ORDER,      "or" },
     67   { 0x10, BYTE_OPER_REG_OP_ORDER, "adc" },
     68   { 0x11, OPER_REG_OP_ORDER,      "adc" },
     69   { 0x12, BYTE_REG_OPER_OP_ORDER, "adc" },
     70   { 0x13, REG_OPER_OP_ORDER,      "adc" },
     71   { 0x18, BYTE_OPER_REG_OP_ORDER, "sbb" },
     72   { 0x19, OPER_REG_OP_ORDER,      "sbb" },
     73   { 0x1A, BYTE_REG_OPER_OP_ORDER, "sbb" },
     74   { 0x1B, REG_OPER_OP_ORDER,      "sbb" },
     75   { 0x20, BYTE_OPER_REG_OP_ORDER, "and" },
     76   { 0x21, OPER_REG_OP_ORDER,      "and" },
     77   { 0x22, BYTE_REG_OPER_OP_ORDER, "and" },
     78   { 0x23, REG_OPER_OP_ORDER,      "and" },
     79   { 0x28, BYTE_OPER_REG_OP_ORDER, "sub" },
     80   { 0x29, OPER_REG_OP_ORDER,      "sub" },
     81   { 0x2A, BYTE_REG_OPER_OP_ORDER, "sub" },
     82   { 0x2B, REG_OPER_OP_ORDER,      "sub" },
     83   { 0x30, BYTE_OPER_REG_OP_ORDER, "xor" },
     84   { 0x31, OPER_REG_OP_ORDER,      "xor" },
     85   { 0x32, BYTE_REG_OPER_OP_ORDER, "xor" },
     86   { 0x33, REG_OPER_OP_ORDER,      "xor" },
     87   { 0x38, BYTE_OPER_REG_OP_ORDER, "cmp" },
     88   { 0x39, OPER_REG_OP_ORDER,      "cmp" },
     89   { 0x3A, BYTE_REG_OPER_OP_ORDER, "cmp" },
     90   { 0x3B, REG_OPER_OP_ORDER,      "cmp" },
     91   { 0x63, REG_OPER_OP_ORDER,      "movsxlq" },
     92   { 0x84, BYTE_REG_OPER_OP_ORDER, "test" },
     93   { 0x85, REG_OPER_OP_ORDER,      "test" },
     94   { 0x86, BYTE_REG_OPER_OP_ORDER, "xchg" },
     95   { 0x87, REG_OPER_OP_ORDER,      "xchg" },
     96   { 0x88, BYTE_OPER_REG_OP_ORDER, "mov" },
     97   { 0x89, OPER_REG_OP_ORDER,      "mov" },
     98   { 0x8A, BYTE_REG_OPER_OP_ORDER, "mov" },
     99   { 0x8B, REG_OPER_OP_ORDER,      "mov" },
    100   { 0x8D, REG_OPER_OP_ORDER,      "lea" },
    101   { -1, UNSET_OP_ORDER, "" }
    102 };
    103 
    104 
    105 static ByteMnemonic zero_operands_instr[] = {
    106   { 0xC3, UNSET_OP_ORDER, "ret" },
    107   { 0xC9, UNSET_OP_ORDER, "leave" },
    108   { 0xF4, UNSET_OP_ORDER, "hlt" },
    109   { 0xCC, UNSET_OP_ORDER, "int3" },
    110   { 0x60, UNSET_OP_ORDER, "pushad" },
    111   { 0x61, UNSET_OP_ORDER, "popad" },
    112   { 0x9C, UNSET_OP_ORDER, "pushfd" },
    113   { 0x9D, UNSET_OP_ORDER, "popfd" },
    114   { 0x9E, UNSET_OP_ORDER, "sahf" },
    115   { 0x99, UNSET_OP_ORDER, "cdq" },
    116   { 0x9B, UNSET_OP_ORDER, "fwait" },
    117   { 0xA4, UNSET_OP_ORDER, "movs" },
    118   { 0xA5, UNSET_OP_ORDER, "movs" },
    119   { 0xA6, UNSET_OP_ORDER, "cmps" },
    120   { 0xA7, UNSET_OP_ORDER, "cmps" },
    121   { -1, UNSET_OP_ORDER, "" }
    122 };
    123 
    124 
    125 static ByteMnemonic call_jump_instr[] = {
    126   { 0xE8, UNSET_OP_ORDER, "call" },
    127   { 0xE9, UNSET_OP_ORDER, "jmp" },
    128   { -1, UNSET_OP_ORDER, "" }
    129 };
    130 
    131 
    132 static ByteMnemonic short_immediate_instr[] = {
    133   { 0x05, UNSET_OP_ORDER, "add" },
    134   { 0x0D, UNSET_OP_ORDER, "or" },
    135   { 0x15, UNSET_OP_ORDER, "adc" },
    136   { 0x1D, UNSET_OP_ORDER, "sbb" },
    137   { 0x25, UNSET_OP_ORDER, "and" },
    138   { 0x2D, UNSET_OP_ORDER, "sub" },
    139   { 0x35, UNSET_OP_ORDER, "xor" },
    140   { 0x3D, UNSET_OP_ORDER, "cmp" },
    141   { -1, UNSET_OP_ORDER, "" }
    142 };
    143 
    144 
    145 static const char* conditional_code_suffix[] = {
    146   "o", "no", "c", "nc", "z", "nz", "na", "a",
    147   "s", "ns", "pe", "po", "l", "ge", "le", "g"
    148 };
    149 
    150 
    151 enum InstructionType {
    152   NO_INSTR,
    153   ZERO_OPERANDS_INSTR,
    154   TWO_OPERANDS_INSTR,
    155   JUMP_CONDITIONAL_SHORT_INSTR,
    156   REGISTER_INSTR,
    157   PUSHPOP_INSTR,  // Has implicit 64-bit operand size.
    158   MOVE_REG_INSTR,
    159   CALL_JUMP_INSTR,
    160   SHORT_IMMEDIATE_INSTR
    161 };
    162 
    163 
    164 enum Prefixes {
    165   ESCAPE_PREFIX = 0x0F,
    166   OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
    167   ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
    168   REPNE_PREFIX = 0xF2,
    169   REP_PREFIX = 0xF3,
    170   REPEQ_PREFIX = REP_PREFIX
    171 };
    172 
    173 
    174 struct InstructionDesc {
    175   const char* mnem;
    176   InstructionType type;
    177   OperandType op_order_;
    178   bool byte_size_operation;  // Fixed 8-bit operation.
    179 };
    180 
    181 
    182 class InstructionTable {
    183  public:
    184   InstructionTable();
    185   const InstructionDesc& Get(byte x) const {
    186     return instructions_[x];
    187   }
    188 
    189  private:
    190   InstructionDesc instructions_[256];
    191   void Clear();
    192   void Init();
    193   void CopyTable(ByteMnemonic bm[], InstructionType type);
    194   void SetTableRange(InstructionType type, byte start, byte end, bool byte_size,
    195                      const char* mnem);
    196   void AddJumpConditionalShort();
    197 };
    198 
    199 
    200 InstructionTable::InstructionTable() {
    201   Clear();
    202   Init();
    203 }
    204 
    205 
    206 void InstructionTable::Clear() {
    207   for (int i = 0; i < 256; i++) {
    208     instructions_[i].mnem = "(bad)";
    209     instructions_[i].type = NO_INSTR;
    210     instructions_[i].op_order_ = UNSET_OP_ORDER;
    211     instructions_[i].byte_size_operation = false;
    212   }
    213 }
    214 
    215 
    216 void InstructionTable::Init() {
    217   CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
    218   CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
    219   CopyTable(call_jump_instr, CALL_JUMP_INSTR);
    220   CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
    221   AddJumpConditionalShort();
    222   SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push");
    223   SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop");
    224   SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov");
    225 }
    226 
    227 
    228 void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) {
    229   for (int i = 0; bm[i].b >= 0; i++) {
    230     InstructionDesc* id = &instructions_[bm[i].b];
    231     id->mnem = bm[i].mnem;
    232     OperandType op_order = bm[i].op_order_;
    233     id->op_order_ =
    234         static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
    235     ASSERT_EQ(NO_INSTR, id->type);  // Information not already entered
    236     id->type = type;
    237     id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
    238   }
    239 }
    240 
    241 
    242 void InstructionTable::SetTableRange(InstructionType type,
    243                                      byte start,
    244                                      byte end,
    245                                      bool byte_size,
    246                                      const char* mnem) {
    247   for (byte b = start; b <= end; b++) {
    248     InstructionDesc* id = &instructions_[b];
    249     ASSERT_EQ(NO_INSTR, id->type);  // Information not already entered
    250     id->mnem = mnem;
    251     id->type = type;
    252     id->byte_size_operation = byte_size;
    253   }
    254 }
    255 
    256 
    257 void InstructionTable::AddJumpConditionalShort() {
    258   for (byte b = 0x70; b <= 0x7F; b++) {
    259     InstructionDesc* id = &instructions_[b];
    260     ASSERT_EQ(NO_INSTR, id->type);  // Information not already entered
    261     id->mnem = NULL;  // Computed depending on condition code.
    262     id->type = JUMP_CONDITIONAL_SHORT_INSTR;
    263   }
    264 }
    265 
    266 
    267 static InstructionTable instruction_table;
    268 
    269 static InstructionDesc cmov_instructions[16] = {
    270   {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
    271   {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
    272   {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
    273   {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
    274   {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
    275   {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
    276   {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
    277   {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
    278   {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
    279   {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
    280   {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
    281   {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
    282   {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
    283   {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
    284   {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
    285   {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}
    286 };
    287 
    288 //------------------------------------------------------------------------------
    289 // DisassemblerX64 implementation.
    290 
    291 enum UnimplementedOpcodeAction {
    292   CONTINUE_ON_UNIMPLEMENTED_OPCODE,
    293   ABORT_ON_UNIMPLEMENTED_OPCODE
    294 };
    295 
    296 // A new DisassemblerX64 object is created to disassemble each instruction.
    297 // The object can only disassemble a single instruction.
    298 class DisassemblerX64 {
    299  public:
    300   DisassemblerX64(const NameConverter& converter,
    301                   UnimplementedOpcodeAction unimplemented_action =
    302                       ABORT_ON_UNIMPLEMENTED_OPCODE)
    303       : converter_(converter),
    304         tmp_buffer_pos_(0),
    305         abort_on_unimplemented_(
    306             unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE),
    307         rex_(0),
    308         operand_size_(0),
    309         group_1_prefix_(0),
    310         byte_size_operand_(false) {
    311     tmp_buffer_[0] = '\0';
    312   }
    313 
    314   virtual ~DisassemblerX64() {
    315   }
    316 
    317   // Writes one disassembled instruction into 'buffer' (0-terminated).
    318   // Returns the length of the disassembled machine instruction in bytes.
    319   int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
    320 
    321  private:
    322   enum OperandSize {
    323     BYTE_SIZE = 0,
    324     WORD_SIZE = 1,
    325     DOUBLEWORD_SIZE = 2,
    326     QUADWORD_SIZE = 3
    327   };
    328 
    329   const NameConverter& converter_;
    330   v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
    331   unsigned int tmp_buffer_pos_;
    332   bool abort_on_unimplemented_;
    333   // Prefixes parsed
    334   byte rex_;
    335   byte operand_size_;  // 0x66 or (if no group 3 prefix is present) 0x0.
    336   byte group_1_prefix_;  // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
    337   // Byte size operand override.
    338   bool byte_size_operand_;
    339 
    340   void setRex(byte rex) {
    341     ASSERT_EQ(0x40, rex & 0xF0);
    342     rex_ = rex;
    343   }
    344 
    345   bool rex() { return rex_ != 0; }
    346 
    347   bool rex_b() { return (rex_ & 0x01) != 0; }
    348 
    349   // Actual number of base register given the low bits and the rex.b state.
    350   int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); }
    351 
    352   bool rex_x() { return (rex_ & 0x02) != 0; }
    353 
    354   bool rex_r() { return (rex_ & 0x04) != 0; }
    355 
    356   bool rex_w() { return (rex_ & 0x08) != 0; }
    357 
    358   OperandSize operand_size() {
    359     if (byte_size_operand_) return BYTE_SIZE;
    360     if (rex_w()) return QUADWORD_SIZE;
    361     if (operand_size_ != 0) return WORD_SIZE;
    362     return DOUBLEWORD_SIZE;
    363   }
    364 
    365   char operand_size_code() {
    366     return "bwlq"[operand_size()];
    367   }
    368 
    369   const char* NameOfCPURegister(int reg) const {
    370     return converter_.NameOfCPURegister(reg);
    371   }
    372 
    373   const char* NameOfByteCPURegister(int reg) const {
    374     return converter_.NameOfByteCPURegister(reg);
    375   }
    376 
    377   const char* NameOfXMMRegister(int reg) const {
    378     return converter_.NameOfXMMRegister(reg);
    379   }
    380 
    381   const char* NameOfAddress(byte* addr) const {
    382     return converter_.NameOfAddress(addr);
    383   }
    384 
    385   // Disassembler helper functions.
    386   void get_modrm(byte data,
    387                  int* mod,
    388                  int* regop,
    389                  int* rm) {
    390     *mod = (data >> 6) & 3;
    391     *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0);
    392     *rm = (data & 7) | (rex_b() ? 8 : 0);
    393   }
    394 
    395   void get_sib(byte data,
    396                int* scale,
    397                int* index,
    398                int* base) {
    399     *scale = (data >> 6) & 3;
    400     *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
    401     *base = (data & 7) | (rex_b() ? 8 : 0);
    402   }
    403 
    404   typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const;
    405 
    406   int PrintRightOperandHelper(byte* modrmp,
    407                               RegisterNameMapping register_name);
    408   int PrintRightOperand(byte* modrmp);
    409   int PrintRightByteOperand(byte* modrmp);
    410   int PrintRightXMMOperand(byte* modrmp);
    411   int PrintOperands(const char* mnem,
    412                     OperandType op_order,
    413                     byte* data);
    414   int PrintImmediate(byte* data, OperandSize size);
    415   int PrintImmediateOp(byte* data);
    416   const char* TwoByteMnemonic(byte opcode);
    417   int TwoByteOpcodeInstruction(byte* data);
    418   int F6F7Instruction(byte* data);
    419   int ShiftInstruction(byte* data);
    420   int JumpShort(byte* data);
    421   int JumpConditional(byte* data);
    422   int JumpConditionalShort(byte* data);
    423   int SetCC(byte* data);
    424   int FPUInstruction(byte* data);
    425   int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
    426   int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
    427   void AppendToBuffer(const char* format, ...);
    428 
    429   void UnimplementedInstruction() {
    430     if (abort_on_unimplemented_) {
    431       CHECK(false);
    432     } else {
    433       AppendToBuffer("'Unimplemented Instruction'");
    434     }
    435   }
    436 };
    437 
    438 
    439 void DisassemblerX64::AppendToBuffer(const char* format, ...) {
    440   v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
    441   va_list args;
    442   va_start(args, format);
    443   int result = v8::internal::OS::VSNPrintF(buf, format, args);
    444   va_end(args);
    445   tmp_buffer_pos_ += result;
    446 }
    447 
    448 
    449 int DisassemblerX64::PrintRightOperandHelper(
    450     byte* modrmp,
    451     RegisterNameMapping register_name) {
    452   int mod, regop, rm;
    453   get_modrm(*modrmp, &mod, &regop, &rm);
    454   switch (mod) {
    455     case 0:
    456       if ((rm & 7) == 5) {
    457         int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1);
    458         AppendToBuffer("[0x%x]", disp);
    459         return 5;
    460       } else if ((rm & 7) == 4) {
    461         // Codes for SIB byte.
    462         byte sib = *(modrmp + 1);
    463         int scale, index, base;
    464         get_sib(sib, &scale, &index, &base);
    465         if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
    466           // index == rsp means no index. Only use sib byte with no index for
    467           // rsp and r12 base.
    468           AppendToBuffer("[%s]", (this->*register_name)(base));
    469           return 2;
    470         } else if (base == 5) {
    471           // base == rbp means no base register (when mod == 0).
    472           int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
    473           AppendToBuffer("[%s*%d+0x%x]",
    474                          (this->*register_name)(index),
    475                          1 << scale, disp);
    476           return 6;
    477         } else if (index != 4 && base != 5) {
    478           // [base+index*scale]
    479           AppendToBuffer("[%s+%s*%d]",
    480                          (this->*register_name)(base),
    481                          (this->*register_name)(index),
    482                          1 << scale);
    483           return 2;
    484         } else {
    485           UnimplementedInstruction();
    486           return 1;
    487         }
    488       } else {
    489         AppendToBuffer("[%s]", (this->*register_name)(rm));
    490         return 1;
    491       }
    492       break;
    493     case 1:  // fall through
    494     case 2:
    495       if ((rm & 7) == 4) {
    496         byte sib = *(modrmp + 1);
    497         int scale, index, base;
    498         get_sib(sib, &scale, &index, &base);
    499         int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2)
    500                               : *reinterpret_cast<char*>(modrmp + 2);
    501         if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
    502           if (-disp > 0) {
    503             AppendToBuffer("[%s-0x%x]", (this->*register_name)(base), -disp);
    504           } else {
    505             AppendToBuffer("[%s+0x%x]", (this->*register_name)(base), disp);
    506           }
    507         } else {
    508           if (-disp > 0) {
    509             AppendToBuffer("[%s+%s*%d-0x%x]",
    510                            (this->*register_name)(base),
    511                            (this->*register_name)(index),
    512                            1 << scale,
    513                            -disp);
    514           } else {
    515             AppendToBuffer("[%s+%s*%d+0x%x]",
    516                            (this->*register_name)(base),
    517                            (this->*register_name)(index),
    518                            1 << scale,
    519                            disp);
    520           }
    521         }
    522         return mod == 2 ? 6 : 3;
    523       } else {
    524         // No sib.
    525         int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1)
    526                               : *reinterpret_cast<char*>(modrmp + 1);
    527         if (-disp > 0) {
    528         AppendToBuffer("[%s-0x%x]", (this->*register_name)(rm), -disp);
    529         } else {
    530         AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp);
    531         }
    532         return (mod == 2) ? 5 : 2;
    533       }
    534       break;
    535     case 3:
    536       AppendToBuffer("%s", (this->*register_name)(rm));
    537       return 1;
    538     default:
    539       UnimplementedInstruction();
    540       return 1;
    541   }
    542   UNREACHABLE();
    543 }
    544 
    545 
    546 int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) {
    547   int64_t value;
    548   int count;
    549   switch (size) {
    550     case BYTE_SIZE:
    551       value = *data;
    552       count = 1;
    553       break;
    554     case WORD_SIZE:
    555       value = *reinterpret_cast<int16_t*>(data);
    556       count = 2;
    557       break;
    558     case DOUBLEWORD_SIZE:
    559       value = *reinterpret_cast<uint32_t*>(data);
    560       count = 4;
    561       break;
    562     case QUADWORD_SIZE:
    563       value = *reinterpret_cast<int32_t*>(data);
    564       count = 4;
    565       break;
    566     default:
    567       UNREACHABLE();
    568       value = 0;  // Initialize variables on all paths to satisfy the compiler.
    569       count = 0;
    570   }
    571   AppendToBuffer("%" V8_PTR_PREFIX "x", value);
    572   return count;
    573 }
    574 
    575 
    576 int DisassemblerX64::PrintRightOperand(byte* modrmp) {
    577   return PrintRightOperandHelper(modrmp,
    578                                  &DisassemblerX64::NameOfCPURegister);
    579 }
    580 
    581 
    582 int DisassemblerX64::PrintRightByteOperand(byte* modrmp) {
    583   return PrintRightOperandHelper(modrmp,
    584                                  &DisassemblerX64::NameOfByteCPURegister);
    585 }
    586 
    587 
    588 int DisassemblerX64::PrintRightXMMOperand(byte* modrmp) {
    589   return PrintRightOperandHelper(modrmp,
    590                                  &DisassemblerX64::NameOfXMMRegister);
    591 }
    592 
    593 
    594 // Returns number of bytes used including the current *data.
    595 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
    596 int DisassemblerX64::PrintOperands(const char* mnem,
    597                                    OperandType op_order,
    598                                    byte* data) {
    599   byte modrm = *data;
    600   int mod, regop, rm;
    601   get_modrm(modrm, &mod, &regop, &rm);
    602   int advance = 0;
    603   const char* register_name =
    604       byte_size_operand_ ? NameOfByteCPURegister(regop)
    605                          : NameOfCPURegister(regop);
    606   switch (op_order) {
    607     case REG_OPER_OP_ORDER: {
    608       AppendToBuffer("%s%c %s,",
    609                      mnem,
    610                      operand_size_code(),
    611                      register_name);
    612       advance = byte_size_operand_ ? PrintRightByteOperand(data)
    613                                    : PrintRightOperand(data);
    614       break;
    615     }
    616     case OPER_REG_OP_ORDER: {
    617       AppendToBuffer("%s%c ", mnem, operand_size_code());
    618       advance = byte_size_operand_ ? PrintRightByteOperand(data)
    619                                    : PrintRightOperand(data);
    620       AppendToBuffer(",%s", register_name);
    621       break;
    622     }
    623     default:
    624       UNREACHABLE();
    625       break;
    626   }
    627   return advance;
    628 }
    629 
    630 
    631 // Returns number of bytes used by machine instruction, including *data byte.
    632 // Writes immediate instructions to 'tmp_buffer_'.
    633 int DisassemblerX64::PrintImmediateOp(byte* data) {
    634   bool byte_size_immediate = (*data & 0x02) != 0;
    635   byte modrm = *(data + 1);
    636   int mod, regop, rm;
    637   get_modrm(modrm, &mod, &regop, &rm);
    638   const char* mnem = "Imm???";
    639   switch (regop) {
    640     case 0:
    641       mnem = "add";
    642       break;
    643     case 1:
    644       mnem = "or";
    645       break;
    646     case 2:
    647       mnem = "adc";
    648       break;
    649     case 4:
    650       mnem = "and";
    651       break;
    652     case 5:
    653       mnem = "sub";
    654       break;
    655     case 6:
    656       mnem = "xor";
    657       break;
    658     case 7:
    659       mnem = "cmp";
    660       break;
    661     default:
    662       UnimplementedInstruction();
    663   }
    664   AppendToBuffer("%s%c ", mnem, operand_size_code());
    665   int count = PrintRightOperand(data + 1);
    666   AppendToBuffer(",0x");
    667   OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size();
    668   count += PrintImmediate(data + 1 + count, immediate_size);
    669   return 1 + count;
    670 }
    671 
    672 
    673 // Returns number of bytes used, including *data.
    674 int DisassemblerX64::F6F7Instruction(byte* data) {
    675   ASSERT(*data == 0xF7 || *data == 0xF6);
    676   byte modrm = *(data + 1);
    677   int mod, regop, rm;
    678   get_modrm(modrm, &mod, &regop, &rm);
    679   if (mod == 3 && regop != 0) {
    680     const char* mnem = NULL;
    681     switch (regop) {
    682       case 2:
    683         mnem = "not";
    684         break;
    685       case 3:
    686         mnem = "neg";
    687         break;
    688       case 4:
    689         mnem = "mul";
    690         break;
    691       case 7:
    692         mnem = "idiv";
    693         break;
    694       default:
    695         UnimplementedInstruction();
    696     }
    697     AppendToBuffer("%s%c %s",
    698                    mnem,
    699                    operand_size_code(),
    700                    NameOfCPURegister(rm));
    701     return 2;
    702   } else if (regop == 0) {
    703     AppendToBuffer("test%c ", operand_size_code());
    704     int count = PrintRightOperand(data + 1);  // Use name of 64-bit register.
    705     AppendToBuffer(",0x");
    706     count += PrintImmediate(data + 1 + count, operand_size());
    707     return 1 + count;
    708   } else {
    709     UnimplementedInstruction();
    710     return 2;
    711   }
    712 }
    713 
    714 
    715 int DisassemblerX64::ShiftInstruction(byte* data) {
    716   byte op = *data & (~1);
    717   if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
    718     UnimplementedInstruction();
    719     return 1;
    720   }
    721   byte modrm = *(data + 1);
    722   int mod, regop, rm;
    723   get_modrm(modrm, &mod, &regop, &rm);
    724   regop &= 0x7;  // The REX.R bit does not affect the operation.
    725   int imm8 = -1;
    726   int num_bytes = 2;
    727   if (mod != 3) {
    728     UnimplementedInstruction();
    729     return num_bytes;
    730   }
    731   const char* mnem = NULL;
    732   switch (regop) {
    733     case 0:
    734       mnem = "rol";
    735       break;
    736     case 1:
    737       mnem = "ror";
    738       break;
    739     case 2:
    740       mnem = "rcl";
    741       break;
    742     case 3:
    743       mnem = "rcr";
    744       break;
    745     case 4:
    746       mnem = "shl";
    747       break;
    748     case 5:
    749       mnem = "shr";
    750       break;
    751     case 7:
    752       mnem = "sar";
    753       break;
    754     default:
    755       UnimplementedInstruction();
    756       return num_bytes;
    757   }
    758   ASSERT_NE(NULL, mnem);
    759   if (op == 0xD0) {
    760     imm8 = 1;
    761   } else if (op == 0xC0) {
    762     imm8 = *(data + 2);
    763     num_bytes = 3;
    764   }
    765   AppendToBuffer("%s%c %s,",
    766                  mnem,
    767                  operand_size_code(),
    768                  byte_size_operand_ ? NameOfByteCPURegister(rm)
    769                                     : NameOfCPURegister(rm));
    770   if (op == 0xD2) {
    771     AppendToBuffer("cl");
    772   } else {
    773     AppendToBuffer("%d", imm8);
    774   }
    775   return num_bytes;
    776 }
    777 
    778 
    779 // Returns number of bytes used, including *data.
    780 int DisassemblerX64::JumpShort(byte* data) {
    781   ASSERT_EQ(0xEB, *data);
    782   byte b = *(data + 1);
    783   byte* dest = data + static_cast<int8_t>(b) + 2;
    784   AppendToBuffer("jmp %s", NameOfAddress(dest));
    785   return 2;
    786 }
    787 
    788 
    789 // Returns number of bytes used, including *data.
    790 int DisassemblerX64::JumpConditional(byte* data) {
    791   ASSERT_EQ(0x0F, *data);
    792   byte cond = *(data + 1) & 0x0F;
    793   byte* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6;
    794   const char* mnem = conditional_code_suffix[cond];
    795   AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
    796   return 6;  // includes 0x0F
    797 }
    798 
    799 
    800 // Returns number of bytes used, including *data.
    801 int DisassemblerX64::JumpConditionalShort(byte* data) {
    802   byte cond = *data & 0x0F;
    803   byte b = *(data + 1);
    804   byte* dest = data + static_cast<int8_t>(b) + 2;
    805   const char* mnem = conditional_code_suffix[cond];
    806   AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
    807   return 2;
    808 }
    809 
    810 
    811 // Returns number of bytes used, including *data.
    812 int DisassemblerX64::SetCC(byte* data) {
    813   ASSERT_EQ(0x0F, *data);
    814   byte cond = *(data + 1) & 0x0F;
    815   const char* mnem = conditional_code_suffix[cond];
    816   AppendToBuffer("set%s%c ", mnem, operand_size_code());
    817   PrintRightByteOperand(data + 2);
    818   return 3;  // includes 0x0F
    819 }
    820 
    821 
    822 // Returns number of bytes used, including *data.
    823 int DisassemblerX64::FPUInstruction(byte* data) {
    824   byte escape_opcode = *data;
    825   ASSERT_EQ(0xD8, escape_opcode & 0xF8);
    826   byte modrm_byte = *(data+1);
    827 
    828   if (modrm_byte >= 0xC0) {
    829     return RegisterFPUInstruction(escape_opcode, modrm_byte);
    830   } else {
    831     return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
    832   }
    833 }
    834 
    835 int DisassemblerX64::MemoryFPUInstruction(int escape_opcode,
    836                                            int modrm_byte,
    837                                            byte* modrm_start) {
    838   const char* mnem = "?";
    839   int regop = (modrm_byte >> 3) & 0x7;  // reg/op field of modrm byte.
    840   switch (escape_opcode) {
    841     case 0xD9: switch (regop) {
    842         case 0: mnem = "fld_s"; break;
    843         case 3: mnem = "fstp_s"; break;
    844         case 7: mnem = "fstcw"; break;
    845         default: UnimplementedInstruction();
    846       }
    847       break;
    848 
    849     case 0xDB: switch (regop) {
    850         case 0: mnem = "fild_s"; break;
    851         case 1: mnem = "fisttp_s"; break;
    852         case 2: mnem = "fist_s"; break;
    853         case 3: mnem = "fistp_s"; break;
    854         default: UnimplementedInstruction();
    855       }
    856       break;
    857 
    858     case 0xDD: switch (regop) {
    859         case 0: mnem = "fld_d"; break;
    860         case 3: mnem = "fstp_d"; break;
    861         default: UnimplementedInstruction();
    862       }
    863       break;
    864 
    865     case 0xDF: switch (regop) {
    866         case 5: mnem = "fild_d"; break;
    867         case 7: mnem = "fistp_d"; break;
    868         default: UnimplementedInstruction();
    869       }
    870       break;
    871 
    872     default: UnimplementedInstruction();
    873   }
    874   AppendToBuffer("%s ", mnem);
    875   int count = PrintRightOperand(modrm_start);
    876   return count + 1;
    877 }
    878 
    879 int DisassemblerX64::RegisterFPUInstruction(int escape_opcode,
    880                                              byte modrm_byte) {
    881   bool has_register = false;  // Is the FPU register encoded in modrm_byte?
    882   const char* mnem = "?";
    883 
    884   switch (escape_opcode) {
    885     case 0xD8:
    886       UnimplementedInstruction();
    887       break;
    888 
    889     case 0xD9:
    890       switch (modrm_byte & 0xF8) {
    891         case 0xC8:
    892           mnem = "fxch";
    893           has_register = true;
    894           break;
    895         default:
    896           switch (modrm_byte) {
    897             case 0xE0: mnem = "fchs"; break;
    898             case 0xE1: mnem = "fabs"; break;
    899             case 0xE4: mnem = "ftst"; break;
    900             case 0xE8: mnem = "fld1"; break;
    901             case 0xEE: mnem = "fldz"; break;
    902             case 0xF5: mnem = "fprem1"; break;
    903             case 0xF7: mnem = "fincstp"; break;
    904             case 0xF8: mnem = "fprem"; break;
    905             case 0xFE: mnem = "fsin"; break;
    906             case 0xFF: mnem = "fcos"; break;
    907             default: UnimplementedInstruction();
    908           }
    909       }
    910       break;
    911 
    912     case 0xDA:
    913       if (modrm_byte == 0xE9) {
    914         mnem = "fucompp";
    915       } else {
    916         UnimplementedInstruction();
    917       }
    918       break;
    919 
    920     case 0xDB:
    921       if ((modrm_byte & 0xF8) == 0xE8) {
    922         mnem = "fucomi";
    923         has_register = true;
    924       } else if (modrm_byte  == 0xE2) {
    925         mnem = "fclex";
    926       } else {
    927         UnimplementedInstruction();
    928       }
    929       break;
    930 
    931     case 0xDC:
    932       has_register = true;
    933       switch (modrm_byte & 0xF8) {
    934         case 0xC0: mnem = "fadd"; break;
    935         case 0xE8: mnem = "fsub"; break;
    936         case 0xC8: mnem = "fmul"; break;
    937         case 0xF8: mnem = "fdiv"; break;
    938         default: UnimplementedInstruction();
    939       }
    940       break;
    941 
    942     case 0xDD:
    943       has_register = true;
    944       switch (modrm_byte & 0xF8) {
    945         case 0xC0: mnem = "ffree"; break;
    946         case 0xD8: mnem = "fstp"; break;
    947         default: UnimplementedInstruction();
    948       }
    949       break;
    950 
    951     case 0xDE:
    952       if (modrm_byte  == 0xD9) {
    953         mnem = "fcompp";
    954       } else {
    955         has_register = true;
    956         switch (modrm_byte & 0xF8) {
    957           case 0xC0: mnem = "faddp"; break;
    958           case 0xE8: mnem = "fsubp"; break;
    959           case 0xC8: mnem = "fmulp"; break;
    960           case 0xF8: mnem = "fdivp"; break;
    961           default: UnimplementedInstruction();
    962         }
    963       }
    964       break;
    965 
    966     case 0xDF:
    967       if (modrm_byte == 0xE0) {
    968         mnem = "fnstsw_ax";
    969       } else if ((modrm_byte & 0xF8) == 0xE8) {
    970         mnem = "fucomip";
    971         has_register = true;
    972       }
    973       break;
    974 
    975     default: UnimplementedInstruction();
    976   }
    977 
    978   if (has_register) {
    979     AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
    980   } else {
    981     AppendToBuffer("%s", mnem);
    982   }
    983   return 2;
    984 }
    985 
    986 
    987 
    988 // Handle all two-byte opcodes, which start with 0x0F.
    989 // These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
    990 // We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
    991 int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
    992   byte opcode = *(data + 1);
    993   byte* current = data + 2;
    994   // At return, "current" points to the start of the next instruction.
    995   const char* mnemonic = TwoByteMnemonic(opcode);
    996   if (operand_size_ == 0x66) {
    997     // 0x66 0x0F prefix.
    998     int mod, regop, rm;
    999     get_modrm(*current, &mod, &regop, &rm);
   1000     const char* mnemonic = "?";
   1001     if (opcode == 0x57) {
   1002       mnemonic = "xorpd";
   1003     } else if (opcode == 0x2E) {
   1004       mnemonic = "comisd";
   1005     } else if (opcode == 0x2F) {
   1006       mnemonic = "ucomisd";
   1007     } else {
   1008       UnimplementedInstruction();
   1009     }
   1010     AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
   1011     current += PrintRightXMMOperand(current);
   1012   } else if (group_1_prefix_ == 0xF2) {
   1013     // Beginning of instructions with prefix 0xF2.
   1014 
   1015     if (opcode == 0x11 || opcode == 0x10) {
   1016       // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
   1017       AppendToBuffer("movsd ");
   1018       int mod, regop, rm;
   1019       get_modrm(*current, &mod, &regop, &rm);
   1020       if (opcode == 0x11) {
   1021         current += PrintRightOperand(current);
   1022         AppendToBuffer(",%s", NameOfXMMRegister(regop));
   1023       } else {
   1024         AppendToBuffer("%s,", NameOfXMMRegister(regop));
   1025         current += PrintRightOperand(current);
   1026       }
   1027     } else if (opcode == 0x2A) {
   1028       // CVTSI2SD: integer to XMM double conversion.
   1029       int mod, regop, rm;
   1030       get_modrm(*current, &mod, &regop, &rm);
   1031       AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
   1032       current += PrintRightOperand(current);
   1033     } else if ((opcode & 0xF8) == 0x58) {
   1034       // XMM arithmetic. Mnemonic was retrieved at the start of this function.
   1035       int mod, regop, rm;
   1036       get_modrm(*current, &mod, &regop, &rm);
   1037       AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
   1038       current += PrintRightXMMOperand(current);
   1039     } else {
   1040       UnimplementedInstruction();
   1041     }
   1042   } else if (opcode == 0x2C && group_1_prefix_ == 0xF3) {
   1043     // Instruction with prefix 0xF3.
   1044 
   1045     // CVTTSS2SI: Convert scalar single-precision FP to dword integer.
   1046     // Assert that mod is not 3, so source is memory, not an XMM register.
   1047     ASSERT_NE(0xC0, *current & 0xC0);
   1048     current += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, current);
   1049   } else if (opcode == 0x1F) {
   1050     // NOP
   1051     int mod, regop, rm;
   1052     get_modrm(*current, &mod, &regop, &rm);
   1053     current++;
   1054     if (regop == 4) {  // SIB byte present.
   1055       current++;
   1056     }
   1057     if (mod == 1) {  // Byte displacement.
   1058       current += 1;
   1059     } else if (mod == 2) {  // 32-bit displacement.
   1060       current += 4;
   1061     }  // else no immediate displacement.
   1062     AppendToBuffer("nop");
   1063   } else if (opcode == 0xA2 || opcode == 0x31) {
   1064     // RDTSC or CPUID
   1065     AppendToBuffer("%s", mnemonic);
   1066 
   1067   } else if ((opcode & 0xF0) == 0x40) {
   1068     // CMOVcc: conditional move.
   1069     int condition = opcode & 0x0F;
   1070     const InstructionDesc& idesc = cmov_instructions[condition];
   1071     byte_size_operand_ = idesc.byte_size_operation;
   1072     current += PrintOperands(idesc.mnem, idesc.op_order_, current);
   1073 
   1074   } else if ((opcode & 0xF0) == 0x80) {
   1075     // Jcc: Conditional jump (branch).
   1076     current = data + JumpConditional(data);
   1077 
   1078   } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
   1079              opcode == 0xB7 || opcode == 0xAF) {
   1080     // Size-extending moves, IMUL.
   1081     current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
   1082 
   1083   } else if ((opcode & 0xF0) == 0x90) {
   1084     // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
   1085     current = data + SetCC(data);
   1086 
   1087   } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
   1088     // SHLD, SHRD (double-precision shift), BTS (bit set).
   1089     AppendToBuffer("%s ", mnemonic);
   1090     int mod, regop, rm;
   1091     get_modrm(*current, &mod, &regop, &rm);
   1092     current += PrintRightOperand(current);
   1093     if (opcode == 0xAB) {
   1094       AppendToBuffer(",%s", NameOfCPURegister(regop));
   1095     } else {
   1096       AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
   1097     }
   1098   } else {
   1099     UnimplementedInstruction();
   1100   }
   1101   return static_cast<int>(current - data);
   1102 }
   1103 
   1104 
   1105 // Mnemonics for two-byte opcode instructions starting with 0x0F.
   1106 // The argument is the second byte of the two-byte opcode.
   1107 // Returns NULL if the instruction is not handled here.
   1108 const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
   1109   switch (opcode) {
   1110     case 0x1F:
   1111       return "nop";
   1112     case 0x2A:  // F2 prefix.
   1113       return "cvtsi2sd";
   1114     case 0x31:
   1115       return "rdtsc";
   1116     case 0x58:  // F2 prefix.
   1117       return "addsd";
   1118     case 0x59:  // F2 prefix.
   1119       return "mulsd";
   1120     case 0x5C:  // F2 prefix.
   1121       return "subsd";
   1122     case 0x5E:  // F2 prefix.
   1123       return "divsd";
   1124     case 0xA2:
   1125       return "cpuid";
   1126     case 0xA5:
   1127       return "shld";
   1128     case 0xAB:
   1129       return "bts";
   1130     case 0xAD:
   1131       return "shrd";
   1132     case 0xAF:
   1133       return "imul";
   1134     case 0xB6:
   1135       return "movzxb";
   1136     case 0xB7:
   1137       return "movzxw";
   1138     case 0xBE:
   1139       return "movsxb";
   1140     case 0xBF:
   1141       return "movsxw";
   1142     default:
   1143       return NULL;
   1144   }
   1145 }
   1146 
   1147 
   1148 // Disassembles the instruction at instr, and writes it into out_buffer.
   1149 int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
   1150                                        byte* instr) {
   1151   tmp_buffer_pos_ = 0;  // starting to write as position 0
   1152   byte* data = instr;
   1153   bool processed = true;  // Will be set to false if the current instruction
   1154                           // is not in 'instructions' table.
   1155   byte current;
   1156 
   1157   // Scan for prefixes.
   1158   while (true) {
   1159     current = *data;
   1160     if (current == OPERAND_SIZE_OVERRIDE_PREFIX) {  // Group 3 prefix.
   1161       operand_size_ = current;
   1162     } else if ((current & 0xF0) == 0x40) {  // REX prefix.
   1163       setRex(current);
   1164       if (rex_w()) AppendToBuffer("REX.W ");
   1165     } else if ((current & 0xFE) == 0xF2) {  // Group 1 prefix (0xF2 or 0xF3).
   1166       group_1_prefix_ = current;
   1167     } else {  // Not a prefix - an opcode.
   1168       break;
   1169     }
   1170     data++;
   1171   }
   1172 
   1173   const InstructionDesc& idesc = instruction_table.Get(current);
   1174   byte_size_operand_ = idesc.byte_size_operation;
   1175   switch (idesc.type) {
   1176     case ZERO_OPERANDS_INSTR:
   1177       if (current >= 0xA4 && current <= 0xA7) {
   1178         // String move or compare operations.
   1179         if (group_1_prefix_ == REP_PREFIX) {
   1180           // REP.
   1181           AppendToBuffer("rep ");
   1182         }
   1183         if (rex_w()) AppendToBuffer("REX.W ");
   1184         AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
   1185       } else {
   1186         AppendToBuffer("%s", idesc.mnem, operand_size_code());
   1187       }
   1188       data++;
   1189       break;
   1190 
   1191     case TWO_OPERANDS_INSTR:
   1192       data++;
   1193       data += PrintOperands(idesc.mnem, idesc.op_order_, data);
   1194       break;
   1195 
   1196     case JUMP_CONDITIONAL_SHORT_INSTR:
   1197       data += JumpConditionalShort(data);
   1198       break;
   1199 
   1200     case REGISTER_INSTR:
   1201       AppendToBuffer("%s%c %s",
   1202                      idesc.mnem,
   1203                      operand_size_code(),
   1204                      NameOfCPURegister(base_reg(current & 0x07)));
   1205       data++;
   1206       break;
   1207     case PUSHPOP_INSTR:
   1208       AppendToBuffer("%s %s",
   1209                      idesc.mnem,
   1210                      NameOfCPURegister(base_reg(current & 0x07)));
   1211       data++;
   1212       break;
   1213     case MOVE_REG_INSTR: {
   1214       byte* addr = NULL;
   1215       switch (operand_size()) {
   1216         case WORD_SIZE:
   1217           addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
   1218           data += 3;
   1219           break;
   1220         case DOUBLEWORD_SIZE:
   1221           addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
   1222           data += 5;
   1223           break;
   1224         case QUADWORD_SIZE:
   1225           addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
   1226           data += 9;
   1227           break;
   1228         default:
   1229           UNREACHABLE();
   1230       }
   1231       AppendToBuffer("mov%c %s,%s",
   1232                      operand_size_code(),
   1233                      NameOfCPURegister(base_reg(current & 0x07)),
   1234                      NameOfAddress(addr));
   1235       break;
   1236     }
   1237 
   1238     case CALL_JUMP_INSTR: {
   1239       byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
   1240       AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
   1241       data += 5;
   1242       break;
   1243     }
   1244 
   1245     case SHORT_IMMEDIATE_INSTR: {
   1246       byte* addr =
   1247           reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
   1248       AppendToBuffer("%s rax, %s", idesc.mnem, NameOfAddress(addr));
   1249       data += 5;
   1250       break;
   1251     }
   1252 
   1253     case NO_INSTR:
   1254       processed = false;
   1255       break;
   1256 
   1257     default:
   1258       UNIMPLEMENTED();  // This type is not implemented.
   1259   }
   1260 
   1261   // The first byte didn't match any of the simple opcodes, so we
   1262   // need to do special processing on it.
   1263   if (!processed) {
   1264     switch (*data) {
   1265       case 0xC2:
   1266         AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
   1267         data += 3;
   1268         break;
   1269 
   1270       case 0x69:  // fall through
   1271       case 0x6B: {
   1272         int mod, regop, rm;
   1273         get_modrm(*(data + 1), &mod, &regop, &rm);
   1274         int32_t imm = *data == 0x6B ? *(data + 2)
   1275             : *reinterpret_cast<int32_t*>(data + 2);
   1276         AppendToBuffer("imul %s,%s,0x%x", NameOfCPURegister(regop),
   1277                        NameOfCPURegister(rm), imm);
   1278         data += 2 + (*data == 0x6B ? 1 : 4);
   1279         break;
   1280       }
   1281 
   1282       case 0x81:  // fall through
   1283       case 0x83:  // 0x81 with sign extension bit set
   1284         data += PrintImmediateOp(data);
   1285         break;
   1286 
   1287       case 0x0F:
   1288         data += TwoByteOpcodeInstruction(data);
   1289         break;
   1290 
   1291       case 0x8F: {
   1292         data++;
   1293         int mod, regop, rm;
   1294         get_modrm(*data, &mod, &regop, &rm);
   1295         if (regop == 0) {
   1296           AppendToBuffer("pop ");
   1297           data += PrintRightOperand(data);
   1298         }
   1299       }
   1300         break;
   1301 
   1302       case 0xFF: {
   1303         data++;
   1304         int mod, regop, rm;
   1305         get_modrm(*data, &mod, &regop, &rm);
   1306         const char* mnem = NULL;
   1307         switch (regop) {
   1308           case 0:
   1309             mnem = "inc";
   1310             break;
   1311           case 1:
   1312             mnem = "dec";
   1313             break;
   1314           case 2:
   1315             mnem = "call";
   1316             break;
   1317           case 4:
   1318             mnem = "jmp";
   1319             break;
   1320           case 6:
   1321             mnem = "push";
   1322             break;
   1323           default:
   1324             mnem = "???";
   1325         }
   1326         AppendToBuffer(((regop <= 1) ? "%s%c " : "%s "),
   1327                        mnem,
   1328                        operand_size_code());
   1329         data += PrintRightOperand(data);
   1330       }
   1331         break;
   1332 
   1333       case 0xC7:  // imm32, fall through
   1334       case 0xC6:  // imm8
   1335       {
   1336         bool is_byte = *data == 0xC6;
   1337         data++;
   1338 
   1339         AppendToBuffer("mov%c ", is_byte ? 'b' : operand_size_code());
   1340         data += PrintRightOperand(data);
   1341         int32_t imm = is_byte ? *data : *reinterpret_cast<int32_t*>(data);
   1342         AppendToBuffer(",0x%x", imm);
   1343         data += is_byte ? 1 : 4;
   1344       }
   1345         break;
   1346 
   1347       case 0x80: {
   1348         data++;
   1349         AppendToBuffer("cmpb ");
   1350         data += PrintRightOperand(data);
   1351         int32_t imm = *data;
   1352         AppendToBuffer(",0x%x", imm);
   1353         data++;
   1354       }
   1355         break;
   1356 
   1357       case 0x88:  // 8bit, fall through
   1358       case 0x89:  // 32bit
   1359       {
   1360         bool is_byte = *data == 0x88;
   1361         int mod, regop, rm;
   1362         data++;
   1363         get_modrm(*data, &mod, &regop, &rm);
   1364         AppendToBuffer("mov%c ", is_byte ? 'b' : operand_size_code());
   1365         data += PrintRightOperand(data);
   1366         AppendToBuffer(",%s", NameOfCPURegister(regop));
   1367       }
   1368         break;
   1369 
   1370       case 0x90:
   1371       case 0x91:
   1372       case 0x92:
   1373       case 0x93:
   1374       case 0x94:
   1375       case 0x95:
   1376       case 0x96:
   1377       case 0x97: {
   1378         int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
   1379         if (reg == 0) {
   1380           AppendToBuffer("nop");  // Common name for xchg rax,rax.
   1381         } else {
   1382           AppendToBuffer("xchg%c rax, %s",
   1383                          operand_size_code(),
   1384                          NameOfCPURegister(reg));
   1385         }
   1386         data++;
   1387       }
   1388         break;
   1389 
   1390       case 0xFE: {
   1391         data++;
   1392         int mod, regop, rm;
   1393         get_modrm(*data, &mod, &regop, &rm);
   1394         if (mod == 3 && regop == 1) {
   1395           AppendToBuffer("decb %s", NameOfCPURegister(rm));
   1396         } else {
   1397           UnimplementedInstruction();
   1398         }
   1399         data++;
   1400       }
   1401         break;
   1402 
   1403       case 0x68:
   1404         AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
   1405         data += 5;
   1406         break;
   1407 
   1408       case 0x6A:
   1409         AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
   1410         data += 2;
   1411         break;
   1412 
   1413       case 0xA1:  // Fall through.
   1414       case 0xA3:
   1415         switch (operand_size()) {
   1416           case DOUBLEWORD_SIZE: {
   1417             const char* memory_location = NameOfAddress(
   1418                 reinterpret_cast<byte*>(
   1419                     *reinterpret_cast<int32_t*>(data + 1)));
   1420             if (*data == 0xA1) {  // Opcode 0xA1
   1421               AppendToBuffer("movzxlq rax,(%s)", memory_location);
   1422             } else {  // Opcode 0xA3
   1423               AppendToBuffer("movzxlq (%s),rax", memory_location);
   1424             }
   1425             data += 5;
   1426             break;
   1427           }
   1428           case QUADWORD_SIZE: {
   1429             // New x64 instruction mov rax,(imm_64).
   1430             const char* memory_location = NameOfAddress(
   1431                 *reinterpret_cast<byte**>(data + 1));
   1432             if (*data == 0xA1) {  // Opcode 0xA1
   1433               AppendToBuffer("movq rax,(%s)", memory_location);
   1434             } else {  // Opcode 0xA3
   1435               AppendToBuffer("movq (%s),rax", memory_location);
   1436             }
   1437             data += 9;
   1438             break;
   1439           }
   1440           default:
   1441             UnimplementedInstruction();
   1442             data += 2;
   1443         }
   1444         break;
   1445 
   1446       case 0xA8:
   1447         AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
   1448         data += 2;
   1449         break;
   1450 
   1451       case 0xA9: {
   1452         int64_t value = 0;
   1453         switch (operand_size()) {
   1454           case WORD_SIZE:
   1455             value = *reinterpret_cast<uint16_t*>(data + 1);
   1456             data += 3;
   1457             break;
   1458           case DOUBLEWORD_SIZE:
   1459             value = *reinterpret_cast<uint32_t*>(data + 1);
   1460             data += 5;
   1461             break;
   1462           case QUADWORD_SIZE:
   1463             value = *reinterpret_cast<int32_t*>(data + 1);
   1464             data += 5;
   1465             break;
   1466           default:
   1467             UNREACHABLE();
   1468         }
   1469         AppendToBuffer("test%c rax,0x%"V8_PTR_PREFIX"x",
   1470                        operand_size_code(),
   1471                        value);
   1472         break;
   1473       }
   1474       case 0xD1:  // fall through
   1475       case 0xD3:  // fall through
   1476       case 0xC1:
   1477         data += ShiftInstruction(data);
   1478         break;
   1479       case 0xD0:  // fall through
   1480       case 0xD2:  // fall through
   1481       case 0xC0:
   1482         byte_size_operand_ = true;
   1483         data += ShiftInstruction(data);
   1484         break;
   1485 
   1486       case 0xD9:  // fall through
   1487       case 0xDA:  // fall through
   1488       case 0xDB:  // fall through
   1489       case 0xDC:  // fall through
   1490       case 0xDD:  // fall through
   1491       case 0xDE:  // fall through
   1492       case 0xDF:
   1493         data += FPUInstruction(data);
   1494         break;
   1495 
   1496       case 0xEB:
   1497         data += JumpShort(data);
   1498         break;
   1499 
   1500       case 0xF6:
   1501         byte_size_operand_ = true;  // fall through
   1502       case 0xF7:
   1503         data += F6F7Instruction(data);
   1504         break;
   1505 
   1506       default:
   1507         UnimplementedInstruction();
   1508         data += 1;
   1509     }
   1510   }  // !processed
   1511 
   1512   if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
   1513     tmp_buffer_[tmp_buffer_pos_] = '\0';
   1514   }
   1515 
   1516   int instr_len = static_cast<int>(data - instr);
   1517   ASSERT(instr_len > 0);  // Ensure progress.
   1518 
   1519   int outp = 0;
   1520   // Instruction bytes.
   1521   for (byte* bp = instr; bp < data; bp++) {
   1522     outp += v8::internal::OS::SNPrintF(out_buffer + outp, "%02x", *bp);
   1523   }
   1524   for (int i = 6 - instr_len; i >= 0; i--) {
   1525     outp += v8::internal::OS::SNPrintF(out_buffer + outp, "  ");
   1526   }
   1527 
   1528   outp += v8::internal::OS::SNPrintF(out_buffer + outp, " %s",
   1529                                      tmp_buffer_.start());
   1530   return instr_len;
   1531 }
   1532 
   1533 //------------------------------------------------------------------------------
   1534 
   1535 
   1536 static const char* cpu_regs[16] = {
   1537   "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
   1538   "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
   1539 };
   1540 
   1541 
   1542 static const char* byte_cpu_regs[16] = {
   1543   "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
   1544   "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
   1545 };
   1546 
   1547 
   1548 static const char* xmm_regs[16] = {
   1549   "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
   1550   "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
   1551 };
   1552 
   1553 
   1554 const char* NameConverter::NameOfAddress(byte* addr) const {
   1555   static v8::internal::EmbeddedVector<char, 32> tmp_buffer;
   1556   v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr);
   1557   return tmp_buffer.start();
   1558 }
   1559 
   1560 
   1561 const char* NameConverter::NameOfConstant(byte* addr) const {
   1562   return NameOfAddress(addr);
   1563 }
   1564 
   1565 
   1566 const char* NameConverter::NameOfCPURegister(int reg) const {
   1567   if (0 <= reg && reg < 16)
   1568     return cpu_regs[reg];
   1569   return "noreg";
   1570 }
   1571 
   1572 
   1573 const char* NameConverter::NameOfByteCPURegister(int reg) const {
   1574   if (0 <= reg && reg < 16)
   1575     return byte_cpu_regs[reg];
   1576   return "noreg";
   1577 }
   1578 
   1579 
   1580 const char* NameConverter::NameOfXMMRegister(int reg) const {
   1581   if (0 <= reg && reg < 16)
   1582     return xmm_regs[reg];
   1583   return "noxmmreg";
   1584 }
   1585 
   1586 
   1587 const char* NameConverter::NameInCode(byte* addr) const {
   1588   // X64 does not embed debug strings at the moment.
   1589   UNREACHABLE();
   1590   return "";
   1591 }
   1592 
   1593 //------------------------------------------------------------------------------
   1594 
   1595 Disassembler::Disassembler(const NameConverter& converter)
   1596     : converter_(converter) { }
   1597 
   1598 Disassembler::~Disassembler() { }
   1599 
   1600 
   1601 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
   1602                                     byte* instruction) {
   1603   DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE);
   1604   return d.InstructionDecode(buffer, instruction);
   1605 }
   1606 
   1607 
   1608 // The X64 assembler does not use constant pools.
   1609 int Disassembler::ConstantPoolSizeAt(byte* instruction) {
   1610   return -1;
   1611 }
   1612 
   1613 
   1614 void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
   1615   NameConverter converter;
   1616   Disassembler d(converter);
   1617   for (byte* pc = begin; pc < end;) {
   1618     v8::internal::EmbeddedVector<char, 128> buffer;
   1619     buffer[0] = '\0';
   1620     byte* prev_pc = pc;
   1621     pc += d.InstructionDecode(buffer, pc);
   1622     fprintf(f, "%p", prev_pc);
   1623     fprintf(f, "    ");
   1624 
   1625     for (byte* bp = prev_pc; bp < pc; bp++) {
   1626       fprintf(f, "%02x", *bp);
   1627     }
   1628     for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) {
   1629       fprintf(f, "  ");
   1630     }
   1631     fprintf(f, "  %s\n", buffer.start());
   1632   }
   1633 }
   1634 
   1635 }  // namespace disasm
   1636