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