disasm-x64.cc 63.2 KB
Newer Older
1
// Copyright 2011 the V8 project authors. All rights reserved.
2 3
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
4

5 6
#include <assert.h>
#include <stdarg.h>
7
#include <stdio.h>
8

9
#include "src/v8.h"
10

11
#if V8_TARGET_ARCH_X64
12

13
#include "src/base/lazy-instance.h"
14
#include "src/disasm.h"
15 16 17

namespace disasm {

18 19 20 21 22 23 24 25 26
enum OperandType {
  UNSET_OP_ORDER = 0,
  // Operand size decides between 16, 32 and 64 bit operands.
  REG_OPER_OP_ORDER = 1,  // Register destination, operand source.
  OPER_REG_OP_ORDER = 2,  // Operand destination, register source.
  // Fixed 8-bit operands.
  BYTE_SIZE_OPERAND_FLAG = 4,
  BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG,
  BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
27 28
};

29

30 31 32 33 34
//------------------------------------------------------------------
// Tables
//------------------------------------------------------------------
struct ByteMnemonic {
  int b;  // -1 terminates, otherwise must be in range (0..255)
35
  OperandType op_order_;
36 37 38 39
  const char* mnem;
};


40
static const ByteMnemonic two_operands_instr[] = {
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72
  { 0x00, BYTE_OPER_REG_OP_ORDER, "add" },
  { 0x01, OPER_REG_OP_ORDER,      "add" },
  { 0x02, BYTE_REG_OPER_OP_ORDER, "add" },
  { 0x03, REG_OPER_OP_ORDER,      "add" },
  { 0x08, BYTE_OPER_REG_OP_ORDER, "or" },
  { 0x09, OPER_REG_OP_ORDER,      "or" },
  { 0x0A, BYTE_REG_OPER_OP_ORDER, "or" },
  { 0x0B, REG_OPER_OP_ORDER,      "or" },
  { 0x10, BYTE_OPER_REG_OP_ORDER, "adc" },
  { 0x11, OPER_REG_OP_ORDER,      "adc" },
  { 0x12, BYTE_REG_OPER_OP_ORDER, "adc" },
  { 0x13, REG_OPER_OP_ORDER,      "adc" },
  { 0x18, BYTE_OPER_REG_OP_ORDER, "sbb" },
  { 0x19, OPER_REG_OP_ORDER,      "sbb" },
  { 0x1A, BYTE_REG_OPER_OP_ORDER, "sbb" },
  { 0x1B, REG_OPER_OP_ORDER,      "sbb" },
  { 0x20, BYTE_OPER_REG_OP_ORDER, "and" },
  { 0x21, OPER_REG_OP_ORDER,      "and" },
  { 0x22, BYTE_REG_OPER_OP_ORDER, "and" },
  { 0x23, REG_OPER_OP_ORDER,      "and" },
  { 0x28, BYTE_OPER_REG_OP_ORDER, "sub" },
  { 0x29, OPER_REG_OP_ORDER,      "sub" },
  { 0x2A, BYTE_REG_OPER_OP_ORDER, "sub" },
  { 0x2B, REG_OPER_OP_ORDER,      "sub" },
  { 0x30, BYTE_OPER_REG_OP_ORDER, "xor" },
  { 0x31, OPER_REG_OP_ORDER,      "xor" },
  { 0x32, BYTE_REG_OPER_OP_ORDER, "xor" },
  { 0x33, REG_OPER_OP_ORDER,      "xor" },
  { 0x38, BYTE_OPER_REG_OP_ORDER, "cmp" },
  { 0x39, OPER_REG_OP_ORDER,      "cmp" },
  { 0x3A, BYTE_REG_OPER_OP_ORDER, "cmp" },
  { 0x3B, REG_OPER_OP_ORDER,      "cmp" },
73
  { 0x63, REG_OPER_OP_ORDER,      "movsxl" },
74 75 76 77 78 79 80 81
  { 0x84, BYTE_REG_OPER_OP_ORDER, "test" },
  { 0x85, REG_OPER_OP_ORDER,      "test" },
  { 0x86, BYTE_REG_OPER_OP_ORDER, "xchg" },
  { 0x87, REG_OPER_OP_ORDER,      "xchg" },
  { 0x88, BYTE_OPER_REG_OP_ORDER, "mov" },
  { 0x89, OPER_REG_OP_ORDER,      "mov" },
  { 0x8A, BYTE_REG_OPER_OP_ORDER, "mov" },
  { 0x8B, REG_OPER_OP_ORDER,      "mov" },
82
  { 0x8D, REG_OPER_OP_ORDER,      "lea" },
83 84 85 86
  { -1, UNSET_OP_ORDER, "" }
};


87
static const ByteMnemonic zero_operands_instr[] = {
88 89 90
  { 0xC3, UNSET_OP_ORDER, "ret" },
  { 0xC9, UNSET_OP_ORDER, "leave" },
  { 0xF4, UNSET_OP_ORDER, "hlt" },
91
  { 0xFC, UNSET_OP_ORDER, "cld" },
92 93 94 95 96 97 98 99
  { 0xCC, UNSET_OP_ORDER, "int3" },
  { 0x60, UNSET_OP_ORDER, "pushad" },
  { 0x61, UNSET_OP_ORDER, "popad" },
  { 0x9C, UNSET_OP_ORDER, "pushfd" },
  { 0x9D, UNSET_OP_ORDER, "popfd" },
  { 0x9E, UNSET_OP_ORDER, "sahf" },
  { 0x99, UNSET_OP_ORDER, "cdq" },
  { 0x9B, UNSET_OP_ORDER, "fwait" },
100 101 102 103
  { 0xA4, UNSET_OP_ORDER, "movs" },
  { 0xA5, UNSET_OP_ORDER, "movs" },
  { 0xA6, UNSET_OP_ORDER, "cmps" },
  { 0xA7, UNSET_OP_ORDER, "cmps" },
104 105 106 107
  { -1, UNSET_OP_ORDER, "" }
};


108
static const ByteMnemonic call_jump_instr[] = {
109 110 111 112 113 114
  { 0xE8, UNSET_OP_ORDER, "call" },
  { 0xE9, UNSET_OP_ORDER, "jmp" },
  { -1, UNSET_OP_ORDER, "" }
};


115
static const ByteMnemonic short_immediate_instr[] = {
116 117 118
  { 0x05, UNSET_OP_ORDER, "add" },
  { 0x0D, UNSET_OP_ORDER, "or" },
  { 0x15, UNSET_OP_ORDER, "adc" },
119
  { 0x1D, UNSET_OP_ORDER, "sbb" },
120 121 122 123 124 125 126 127
  { 0x25, UNSET_OP_ORDER, "and" },
  { 0x2D, UNSET_OP_ORDER, "sub" },
  { 0x35, UNSET_OP_ORDER, "xor" },
  { 0x3D, UNSET_OP_ORDER, "cmp" },
  { -1, UNSET_OP_ORDER, "" }
};


128
static const char* const conditional_code_suffix[] = {
129
  "o", "no", "c", "nc", "z", "nz", "na", "a",
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146
  "s", "ns", "pe", "po", "l", "ge", "le", "g"
};


enum InstructionType {
  NO_INSTR,
  ZERO_OPERANDS_INSTR,
  TWO_OPERANDS_INSTR,
  JUMP_CONDITIONAL_SHORT_INSTR,
  REGISTER_INSTR,
  PUSHPOP_INSTR,  // Has implicit 64-bit operand size.
  MOVE_REG_INSTR,
  CALL_JUMP_INSTR,
  SHORT_IMMEDIATE_INSTR
};


147 148 149 150
enum Prefixes {
  ESCAPE_PREFIX = 0x0F,
  OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
  ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
151 152
  VEX3_PREFIX = 0xC4,
  VEX2_PREFIX = 0xC5,
153 154 155 156 157 158
  REPNE_PREFIX = 0xF2,
  REP_PREFIX = 0xF3,
  REPEQ_PREFIX = REP_PREFIX
};


159 160 161
struct InstructionDesc {
  const char* mnem;
  InstructionType type;
162 163
  OperandType op_order_;
  bool byte_size_operation;  // Fixed 8-bit operation.
164 165 166 167 168 169 170 171 172 173 174 175 176 177
};


class InstructionTable {
 public:
  InstructionTable();
  const InstructionDesc& Get(byte x) const {
    return instructions_[x];
  }

 private:
  InstructionDesc instructions_[256];
  void Clear();
  void Init();
178
  void CopyTable(const ByteMnemonic bm[], InstructionType type);
179
  void SetTableRange(InstructionType type, byte start, byte end, bool byte_size,
180 181 182 183 184 185 186 187 188 189 190 191 192
                     const char* mnem);
  void AddJumpConditionalShort();
};


InstructionTable::InstructionTable() {
  Clear();
  Init();
}


void InstructionTable::Clear() {
  for (int i = 0; i < 256; i++) {
193
    instructions_[i].mnem = "(bad)";
194 195
    instructions_[i].type = NO_INSTR;
    instructions_[i].op_order_ = UNSET_OP_ORDER;
196
    instructions_[i].byte_size_operation = false;
197 198 199 200 201 202 203 204 205 206
  }
}


void InstructionTable::Init() {
  CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
  CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
  CopyTable(call_jump_instr, CALL_JUMP_INSTR);
  CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
  AddJumpConditionalShort();
207 208 209
  SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push");
  SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop");
  SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov");
210 211 212
}


213 214
void InstructionTable::CopyTable(const ByteMnemonic bm[],
                                 InstructionType type) {
215 216 217
  for (int i = 0; bm[i].b >= 0; i++) {
    InstructionDesc* id = &instructions_[bm[i].b];
    id->mnem = bm[i].mnem;
218 219 220
    OperandType op_order = bm[i].op_order_;
    id->op_order_ =
        static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
221
    DCHECK_EQ(NO_INSTR, id->type);  // Information not already entered
222
    id->type = type;
223
    id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
224 225 226 227
  }
}


228 229 230 231 232
void InstructionTable::SetTableRange(InstructionType type,
                                     byte start,
                                     byte end,
                                     bool byte_size,
                                     const char* mnem) {
233 234
  for (byte b = start; b <= end; b++) {
    InstructionDesc* id = &instructions_[b];
235
    DCHECK_EQ(NO_INSTR, id->type);  // Information not already entered
236 237
    id->mnem = mnem;
    id->type = type;
238
    id->byte_size_operation = byte_size;
239 240 241 242 243 244 245
  }
}


void InstructionTable::AddJumpConditionalShort() {
  for (byte b = 0x70; b <= 0x7F; b++) {
    InstructionDesc* id = &instructions_[b];
246
    DCHECK_EQ(NO_INSTR, id->type);  // Information not already entered
247 248 249 250 251 252
    id->mnem = NULL;  // Computed depending on condition code.
    id->type = JUMP_CONDITIONAL_SHORT_INSTR;
  }
}


253
static v8::base::LazyInstance<InstructionTable>::type instruction_table =
254
    LAZY_INSTANCE_INITIALIZER;
255

256

257
static const InstructionDesc cmov_instructions[16] = {
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
  {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
  {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
  {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
  {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
  {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
  {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
  {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
  {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
  {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
  {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
  {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
  {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
  {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
  {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
  {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
  {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}
};
275

276

277 278 279
//------------------------------------------------------------------------------
// DisassemblerX64 implementation.

280 281 282 283 284
enum UnimplementedOpcodeAction {
  CONTINUE_ON_UNIMPLEMENTED_OPCODE,
  ABORT_ON_UNIMPLEMENTED_OPCODE
};

285

286 287
// A new DisassemblerX64 object is created to disassemble each instruction.
// The object can only disassemble a single instruction.
288 289 290 291 292 293 294
class DisassemblerX64 {
 public:
  DisassemblerX64(const NameConverter& converter,
                  UnimplementedOpcodeAction unimplemented_action =
                      ABORT_ON_UNIMPLEMENTED_OPCODE)
      : converter_(converter),
        tmp_buffer_pos_(0),
295 296
        abort_on_unimplemented_(unimplemented_action ==
                                ABORT_ON_UNIMPLEMENTED_OPCODE),
297
        rex_(0),
298
        operand_size_(0),
299
        group_1_prefix_(0),
300 301 302
        vex_byte0_(0),
        vex_byte1_(0),
        vex_byte2_(0),
303 304
        byte_size_operand_(false),
        instruction_table_(instruction_table.Pointer()) {
305 306 307 308 309 310 311 312 313 314 315
    tmp_buffer_[0] = '\0';
  }

  virtual ~DisassemblerX64() {
  }

  // Writes one disassembled instruction into 'buffer' (0-terminated).
  // Returns the length of the disassembled machine instruction in bytes.
  int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);

 private:
316
  enum OperandSize {
317 318 319 320
    OPERAND_BYTE_SIZE = 0,
    OPERAND_WORD_SIZE = 1,
    OPERAND_DOUBLEWORD_SIZE = 2,
    OPERAND_QUADWORD_SIZE = 3
321
  };
322 323 324 325 326 327 328

  const NameConverter& converter_;
  v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
  unsigned int tmp_buffer_pos_;
  bool abort_on_unimplemented_;
  // Prefixes parsed
  byte rex_;
329 330
  byte operand_size_;  // 0x66 or (if no group 3 prefix is present) 0x0.
  byte group_1_prefix_;  // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
331 332 333
  byte vex_byte0_;       // 0xc4 or 0xc5
  byte vex_byte1_;
  byte vex_byte2_;  // only for 3 bytes vex prefix
334 335
  // Byte size operand override.
  bool byte_size_operand_;
336
  const InstructionTable* const instruction_table_;
337 338

  void setRex(byte rex) {
339
    DCHECK_EQ(0x40, rex & 0xF0);
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
    rex_ = rex;
  }

  bool rex() { return rex_ != 0; }

  bool rex_b() { return (rex_ & 0x01) != 0; }

  // Actual number of base register given the low bits and the rex.b state.
  int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); }

  bool rex_x() { return (rex_ & 0x02) != 0; }

  bool rex_r() { return (rex_ & 0x04) != 0; }

  bool rex_w() { return (rex_ & 0x08) != 0; }

356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
  bool vex_128() {
    DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
    byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
    return (checked & 4) != 1;
  }

  bool vex_66() {
    DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
    byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
    return (checked & 3) == 1;
  }

  bool vex_f3() {
    DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
    byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
    return (checked & 3) == 2;
  }

  bool vex_f2() {
    DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
    byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
    return (checked & 3) == 3;
  }

  bool vex_0f() {
    if (vex_byte0_ == VEX2_PREFIX) return true;
    return (vex_byte1_ & 3) == 1;
  }

  bool vex_0f38() {
386
    if (vex_byte0_ == VEX2_PREFIX) return false;
387 388 389 390
    return (vex_byte1_ & 3) == 2;
  }

  bool vex_0f3a() {
391
    if (vex_byte0_ == VEX2_PREFIX) return false;
392 393 394 395 396 397 398 399 400
    return (vex_byte1_ & 3) == 3;
  }

  int vex_vreg() {
    DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
    byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
    return ~(checked >> 3) & 0xf;
  }

401
  OperandSize operand_size() {
402 403 404 405
    if (byte_size_operand_) return OPERAND_BYTE_SIZE;
    if (rex_w()) return OPERAND_QUADWORD_SIZE;
    if (operand_size_ != 0) return OPERAND_WORD_SIZE;
    return OPERAND_DOUBLEWORD_SIZE;
406 407 408
  }

  char operand_size_code() {
409
    return "bwlq"[operand_size()];
410 411
  }

412 413
  char float_size_code() { return "sd"[rex_w()]; }

414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445
  const char* NameOfCPURegister(int reg) const {
    return converter_.NameOfCPURegister(reg);
  }

  const char* NameOfByteCPURegister(int reg) const {
    return converter_.NameOfByteCPURegister(reg);
  }

  const char* NameOfXMMRegister(int reg) const {
    return converter_.NameOfXMMRegister(reg);
  }

  const char* NameOfAddress(byte* addr) const {
    return converter_.NameOfAddress(addr);
  }

  // Disassembler helper functions.
  void get_modrm(byte data,
                 int* mod,
                 int* regop,
                 int* rm) {
    *mod = (data >> 6) & 3;
    *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0);
    *rm = (data & 7) | (rex_b() ? 8 : 0);
  }

  void get_sib(byte data,
               int* scale,
               int* index,
               int* base) {
    *scale = (data >> 6) & 3;
    *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
446
    *base = (data & 7) | (rex_b() ? 8 : 0);
447 448 449 450 451 452 453 454
  }

  typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const;

  int PrintRightOperandHelper(byte* modrmp,
                              RegisterNameMapping register_name);
  int PrintRightOperand(byte* modrmp);
  int PrintRightByteOperand(byte* modrmp);
455
  int PrintRightXMMOperand(byte* modrmp);
456
  int PrintOperands(const char* mnem,
457
                    OperandType op_order,
458
                    byte* data);
459
  int PrintImmediate(byte* data, OperandSize size);
460
  int PrintImmediateOp(byte* data);
461 462
  const char* TwoByteMnemonic(byte opcode);
  int TwoByteOpcodeInstruction(byte* data);
463
  int F6F7Instruction(byte* data);
464
  int ShiftInstruction(byte* data);
465 466 467 468 469
  int JumpShort(byte* data);
  int JumpConditional(byte* data);
  int JumpConditionalShort(byte* data);
  int SetCC(byte* data);
  int FPUInstruction(byte* data);
470 471
  int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
  int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
472
  int AVXInstruction(byte* data);
473 474 475 476
  void AppendToBuffer(const char* format, ...);

  void UnimplementedInstruction() {
    if (abort_on_unimplemented_) {
477
      CHECK(false);
478 479 480 481 482 483 484 485 486 487 488
    } else {
      AppendToBuffer("'Unimplemented Instruction'");
    }
  }
};


void DisassemblerX64::AppendToBuffer(const char* format, ...) {
  v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
  va_list args;
  va_start(args, format);
489
  int result = v8::internal::VSNPrintF(buf, format, args);
490 491 492 493 494 495 496
  va_end(args);
  tmp_buffer_pos_ += result;
}


int DisassemblerX64::PrintRightOperandHelper(
    byte* modrmp,
497
    RegisterNameMapping direct_register_name) {
498 499
  int mod, regop, rm;
  get_modrm(*modrmp, &mod, &regop, &rm);
500 501
  RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
      &DisassemblerX64::NameOfCPURegister;
502 503 504 505 506 507 508 509 510 511 512 513 514 515
  switch (mod) {
    case 0:
      if ((rm & 7) == 5) {
        int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1);
        AppendToBuffer("[0x%x]", disp);
        return 5;
      } else if ((rm & 7) == 4) {
        // Codes for SIB byte.
        byte sib = *(modrmp + 1);
        int scale, index, base;
        get_sib(sib, &scale, &index, &base);
        if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
          // index == rsp means no index. Only use sib byte with no index for
          // rsp and r12 base.
516
          AppendToBuffer("[%s]", NameOfCPURegister(base));
517 518 519 520
          return 2;
        } else if (base == 5) {
          // base == rbp means no base register (when mod == 0).
          int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
521
          AppendToBuffer("[%s*%d%s0x%x]",
522
                         NameOfCPURegister(index),
523 524 525
                         1 << scale,
                         disp < 0 ? "-" : "+",
                         disp < 0 ? -disp : disp);
526 527 528 529
          return 6;
        } else if (index != 4 && base != 5) {
          // [base+index*scale]
          AppendToBuffer("[%s+%s*%d]",
530 531
                         NameOfCPURegister(base),
                         NameOfCPURegister(index),
532 533 534 535 536 537 538
                         1 << scale);
          return 2;
        } else {
          UnimplementedInstruction();
          return 1;
        }
      } else {
539
        AppendToBuffer("[%s]", NameOfCPURegister(rm));
540 541 542 543 544 545 546 547 548 549
        return 1;
      }
      break;
    case 1:  // fall through
    case 2:
      if ((rm & 7) == 4) {
        byte sib = *(modrmp + 1);
        int scale, index, base;
        get_sib(sib, &scale, &index, &base);
        int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2)
550
                              : *reinterpret_cast<int8_t*>(modrmp + 2);
551
        if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
552 553 554 555
          AppendToBuffer("[%s%s0x%x]",
                         NameOfCPURegister(base),
                         disp < 0 ? "-" : "+",
                         disp < 0 ? -disp : disp);
556
        } else {
557 558 559 560 561 562
          AppendToBuffer("[%s+%s*%d%s0x%x]",
                         NameOfCPURegister(base),
                         NameOfCPURegister(index),
                         1 << scale,
                         disp < 0 ? "-" : "+",
                         disp < 0 ? -disp : disp);
563 564 565 566 567
        }
        return mod == 2 ? 6 : 3;
      } else {
        // No sib.
        int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1)
568 569 570 571 572
                              : *reinterpret_cast<int8_t*>(modrmp + 1);
        AppendToBuffer("[%s%s0x%x]",
                       NameOfCPURegister(rm),
                       disp < 0 ? "-" : "+",
                       disp < 0 ? -disp : disp);
573 574 575 576 577 578 579 580 581 582 583 584 585 586
        return (mod == 2) ? 5 : 2;
      }
      break;
    case 3:
      AppendToBuffer("%s", (this->*register_name)(rm));
      return 1;
    default:
      UnimplementedInstruction();
      return 1;
  }
  UNREACHABLE();
}


587 588 589 590
int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) {
  int64_t value;
  int count;
  switch (size) {
591
    case OPERAND_BYTE_SIZE:
592 593 594
      value = *data;
      count = 1;
      break;
595
    case OPERAND_WORD_SIZE:
596 597 598
      value = *reinterpret_cast<int16_t*>(data);
      count = 2;
      break;
599
    case OPERAND_DOUBLEWORD_SIZE:
600 601 602
      value = *reinterpret_cast<uint32_t*>(data);
      count = 4;
      break;
603
    case OPERAND_QUADWORD_SIZE:
604 605 606 607 608 609 610 611
      value = *reinterpret_cast<int32_t*>(data);
      count = 4;
      break;
    default:
      UNREACHABLE();
      value = 0;  // Initialize variables on all paths to satisfy the compiler.
      count = 0;
  }
612
  AppendToBuffer("%" V8_PTR_PREFIX "x", value);
613 614 615 616
  return count;
}


617 618 619 620 621 622 623 624 625
int DisassemblerX64::PrintRightOperand(byte* modrmp) {
  return PrintRightOperandHelper(modrmp,
                                 &DisassemblerX64::NameOfCPURegister);
}


int DisassemblerX64::PrintRightByteOperand(byte* modrmp) {
  return PrintRightOperandHelper(modrmp,
                                 &DisassemblerX64::NameOfByteCPURegister);
626
}
627 628


629 630 631 632 633 634
int DisassemblerX64::PrintRightXMMOperand(byte* modrmp) {
  return PrintRightOperandHelper(modrmp,
                                 &DisassemblerX64::NameOfXMMRegister);
}


635 636 637
// Returns number of bytes used including the current *data.
// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
int DisassemblerX64::PrintOperands(const char* mnem,
638
                                   OperandType op_order,
639 640 641 642 643
                                   byte* data) {
  byte modrm = *data;
  int mod, regop, rm;
  get_modrm(modrm, &mod, &regop, &rm);
  int advance = 0;
644 645 646
  const char* register_name =
      byte_size_operand_ ? NameOfByteCPURegister(regop)
                         : NameOfCPURegister(regop);
647 648 649 650 651
  switch (op_order) {
    case REG_OPER_OP_ORDER: {
      AppendToBuffer("%s%c %s,",
                     mnem,
                     operand_size_code(),
652 653 654
                     register_name);
      advance = byte_size_operand_ ? PrintRightByteOperand(data)
                                   : PrintRightOperand(data);
655 656 657 658
      break;
    }
    case OPER_REG_OP_ORDER: {
      AppendToBuffer("%s%c ", mnem, operand_size_code());
659 660 661
      advance = byte_size_operand_ ? PrintRightByteOperand(data)
                                   : PrintRightOperand(data);
      AppendToBuffer(",%s", register_name);
662 663 664 665 666 667 668
      break;
    }
    default:
      UNREACHABLE();
      break;
  }
  return advance;
669
}
670 671


672 673 674
// Returns number of bytes used by machine instruction, including *data byte.
// Writes immediate instructions to 'tmp_buffer_'.
int DisassemblerX64::PrintImmediateOp(byte* data) {
675
  bool byte_size_immediate = (*data & 0x02) != 0;
676 677 678 679 680 681 682 683 684 685 686 687 688 689
  byte modrm = *(data + 1);
  int mod, regop, rm;
  get_modrm(modrm, &mod, &regop, &rm);
  const char* mnem = "Imm???";
  switch (regop) {
    case 0:
      mnem = "add";
      break;
    case 1:
      mnem = "or";
      break;
    case 2:
      mnem = "adc";
      break;
690 691 692
    case 3:
      mnem = "sbb";
      break;
693 694 695 696 697 698 699 700 701 702 703 704 705 706 707
    case 4:
      mnem = "and";
      break;
    case 5:
      mnem = "sub";
      break;
    case 6:
      mnem = "xor";
      break;
    case 7:
      mnem = "cmp";
      break;
    default:
      UnimplementedInstruction();
  }
708
  AppendToBuffer("%s%c ", mnem, operand_size_code());
709
  int count = PrintRightOperand(data + 1);
710
  AppendToBuffer(",0x");
711 712
  OperandSize immediate_size =
      byte_size_immediate ? OPERAND_BYTE_SIZE : operand_size();
713 714
  count += PrintImmediate(data + 1 + count, immediate_size);
  return 1 + count;
715 716 717 718
}


// Returns number of bytes used, including *data.
719
int DisassemblerX64::F6F7Instruction(byte* data) {
720
  DCHECK(*data == 0xF7 || *data == 0xF6);
721 722 723 724 725 726 727 728 729 730 731 732 733 734 735
  byte modrm = *(data + 1);
  int mod, regop, rm;
  get_modrm(modrm, &mod, &regop, &rm);
  if (mod == 3 && regop != 0) {
    const char* mnem = NULL;
    switch (regop) {
      case 2:
        mnem = "not";
        break;
      case 3:
        mnem = "neg";
        break;
      case 4:
        mnem = "mul";
        break;
736 737 738
      case 5:
        mnem = "imul";
        break;
739 740 741
      case 6:
        mnem = "div";
        break;
742 743 744 745 746 747 748 749 750 751 752 753 754
      case 7:
        mnem = "idiv";
        break;
      default:
        UnimplementedInstruction();
    }
    AppendToBuffer("%s%c %s",
                   mnem,
                   operand_size_code(),
                   NameOfCPURegister(rm));
    return 2;
  } else if (regop == 0) {
    AppendToBuffer("test%c ", operand_size_code());
755 756 757 758
    int count = PrintRightOperand(data + 1);  // Use name of 64-bit register.
    AppendToBuffer(",0x");
    count += PrintImmediate(data + 1 + count, operand_size());
    return 1 + count;
759 760 761 762 763 764 765
  } else {
    UnimplementedInstruction();
    return 2;
  }
}


766 767
int DisassemblerX64::ShiftInstruction(byte* data) {
  byte op = *data & (~1);
768
  int count = 1;
769 770
  if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
    UnimplementedInstruction();
771
    return count;
772
  }
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
  // Print mneumonic.
  {
    byte modrm = *(data + count);
    int mod, regop, rm;
    get_modrm(modrm, &mod, &regop, &rm);
    regop &= 0x7;  // The REX.R bit does not affect the operation.
    const char* mnem = NULL;
    switch (regop) {
      case 0:
        mnem = "rol";
        break;
      case 1:
        mnem = "ror";
        break;
      case 2:
        mnem = "rcl";
        break;
      case 3:
        mnem = "rcr";
        break;
      case 4:
        mnem = "shl";
        break;
      case 5:
        mnem = "shr";
        break;
      case 7:
        mnem = "sar";
        break;
      default:
        UnimplementedInstruction();
        return count + 1;
    }
    DCHECK_NE(NULL, mnem);
    AppendToBuffer("%s%c ", mnem, operand_size_code());
808
  }
809
  count += PrintRightOperand(data + count);
810
  if (op == 0xD2) {
811
    AppendToBuffer(", cl");
812
  } else {
813 814 815 816 817 818 819 820 821
    int imm8 = -1;
    if (op == 0xD0) {
      imm8 = 1;
    } else {
      DCHECK_EQ(0xC0, op);
      imm8 = *(data + count);
      count++;
    }
    AppendToBuffer(", %d", imm8);
822
  }
823
  return count;
824 825 826 827 828
}


// Returns number of bytes used, including *data.
int DisassemblerX64::JumpShort(byte* data) {
829
  DCHECK_EQ(0xEB, *data);
830 831 832 833 834 835 836 837 838
  byte b = *(data + 1);
  byte* dest = data + static_cast<int8_t>(b) + 2;
  AppendToBuffer("jmp %s", NameOfAddress(dest));
  return 2;
}


// Returns number of bytes used, including *data.
int DisassemblerX64::JumpConditional(byte* data) {
839
  DCHECK_EQ(0x0F, *data);
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860
  byte cond = *(data + 1) & 0x0F;
  byte* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6;
  const char* mnem = conditional_code_suffix[cond];
  AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
  return 6;  // includes 0x0F
}


// Returns number of bytes used, including *data.
int DisassemblerX64::JumpConditionalShort(byte* data) {
  byte cond = *data & 0x0F;
  byte b = *(data + 1);
  byte* dest = data + static_cast<int8_t>(b) + 2;
  const char* mnem = conditional_code_suffix[cond];
  AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
  return 2;
}


// Returns number of bytes used, including *data.
int DisassemblerX64::SetCC(byte* data) {
861
  DCHECK_EQ(0x0F, *data);
862 863 864 865 866 867 868 869
  byte cond = *(data + 1) & 0x0F;
  const char* mnem = conditional_code_suffix[cond];
  AppendToBuffer("set%s%c ", mnem, operand_size_code());
  PrintRightByteOperand(data + 2);
  return 3;  // includes 0x0F
}


870 871 872
int DisassemblerX64::AVXInstruction(byte* data) {
  byte opcode = *data;
  byte* current = data + 1;
873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965
  if (vex_66() && vex_0f38()) {
    int mod, regop, rm, vvvv = vex_vreg();
    get_modrm(*current, &mod, &regop, &rm);
    switch (opcode) {
      case 0x99:
        AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(),
                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
        current += PrintRightXMMOperand(current);
        break;
      case 0xa9:
        AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(),
                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
        current += PrintRightXMMOperand(current);
        break;
      case 0xb9:
        AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(),
                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
        current += PrintRightXMMOperand(current);
        break;
      case 0x9b:
        AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(),
                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
        current += PrintRightXMMOperand(current);
        break;
      case 0xab:
        AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(),
                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
        current += PrintRightXMMOperand(current);
        break;
      case 0xbb:
        AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(),
                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
        current += PrintRightXMMOperand(current);
        break;
      case 0x9d:
        AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(),
                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
        current += PrintRightXMMOperand(current);
        break;
      case 0xad:
        AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(),
                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
        current += PrintRightXMMOperand(current);
        break;
      case 0xbd:
        AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(),
                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
        current += PrintRightXMMOperand(current);
        break;
      case 0x9f:
        AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(),
                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
        current += PrintRightXMMOperand(current);
        break;
      case 0xaf:
        AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(),
                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
        current += PrintRightXMMOperand(current);
        break;
      case 0xbf:
        AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(),
                       NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
        current += PrintRightXMMOperand(current);
        break;
      default:
        UnimplementedInstruction();
    }
  } else if (vex_f2() && vex_0f()) {
    int mod, regop, rm, vvvv = vex_vreg();
    get_modrm(*current, &mod, &regop, &rm);
    switch (opcode) {
      case 0x58:
        AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
                       NameOfXMMRegister(vvvv));
        current += PrintRightXMMOperand(current);
        break;
      case 0x59:
        AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
                       NameOfXMMRegister(vvvv));
        current += PrintRightXMMOperand(current);
        break;
      case 0x5c:
        AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
                       NameOfXMMRegister(vvvv));
        current += PrintRightXMMOperand(current);
        break;
      case 0x5e:
        AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
                       NameOfXMMRegister(vvvv));
        current += PrintRightXMMOperand(current);
        break;
      default:
        UnimplementedInstruction();
966 967
    }
  } else {
968
    UnimplementedInstruction();
969 970 971 972 973 974
  }

  return static_cast<int>(current - data);
}


975 976
// Returns number of bytes used, including *data.
int DisassemblerX64::FPUInstruction(byte* data) {
977
  byte escape_opcode = *data;
978
  DCHECK_EQ(0xD8, escape_opcode & 0xF8);
979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998
  byte modrm_byte = *(data+1);

  if (modrm_byte >= 0xC0) {
    return RegisterFPUInstruction(escape_opcode, modrm_byte);
  } else {
    return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
  }
}

int DisassemblerX64::MemoryFPUInstruction(int escape_opcode,
                                           int modrm_byte,
                                           byte* modrm_start) {
  const char* mnem = "?";
  int regop = (modrm_byte >> 3) & 0x7;  // reg/op field of modrm byte.
  switch (escape_opcode) {
    case 0xD9: switch (regop) {
        case 0: mnem = "fld_s"; break;
        case 3: mnem = "fstp_s"; break;
        case 7: mnem = "fstcw"; break;
        default: UnimplementedInstruction();
999
      }
1000 1001 1002 1003 1004 1005 1006 1007
      break;

    case 0xDB: switch (regop) {
        case 0: mnem = "fild_s"; break;
        case 1: mnem = "fisttp_s"; break;
        case 2: mnem = "fist_s"; break;
        case 3: mnem = "fistp_s"; break;
        default: UnimplementedInstruction();
1008
      }
1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043
      break;

    case 0xDD: switch (regop) {
        case 0: mnem = "fld_d"; break;
        case 3: mnem = "fstp_d"; break;
        default: UnimplementedInstruction();
      }
      break;

    case 0xDF: switch (regop) {
        case 5: mnem = "fild_d"; break;
        case 7: mnem = "fistp_d"; break;
        default: UnimplementedInstruction();
      }
      break;

    default: UnimplementedInstruction();
  }
  AppendToBuffer("%s ", mnem);
  int count = PrintRightOperand(modrm_start);
  return count + 1;
}

int DisassemblerX64::RegisterFPUInstruction(int escape_opcode,
                                             byte modrm_byte) {
  bool has_register = false;  // Is the FPU register encoded in modrm_byte?
  const char* mnem = "?";

  switch (escape_opcode) {
    case 0xD8:
      UnimplementedInstruction();
      break;

    case 0xD9:
      switch (modrm_byte & 0xF8) {
1044 1045 1046 1047
        case 0xC0:
          mnem = "fld";
          has_register = true;
          break;
1048 1049 1050
        case 0xC8:
          mnem = "fxch";
          has_register = true;
1051 1052
          break;
        default:
1053 1054 1055
          switch (modrm_byte) {
            case 0xE0: mnem = "fchs"; break;
            case 0xE1: mnem = "fabs"; break;
1056
            case 0xE3: mnem = "fninit"; break;
1057 1058
            case 0xE4: mnem = "ftst"; break;
            case 0xE8: mnem = "fld1"; break;
1059
            case 0xEB: mnem = "fldpi"; break;
1060
            case 0xED: mnem = "fldln2"; break;
1061
            case 0xEE: mnem = "fldz"; break;
1062
            case 0xF0: mnem = "f2xm1"; break;
1063
            case 0xF1: mnem = "fyl2x"; break;
1064
            case 0xF2: mnem = "fptan"; break;
1065 1066 1067
            case 0xF5: mnem = "fprem1"; break;
            case 0xF7: mnem = "fincstp"; break;
            case 0xF8: mnem = "fprem"; break;
1068
            case 0xFC: mnem = "frndint"; break;
1069
            case 0xFD: mnem = "fscale"; break;
1070 1071 1072 1073
            case 0xFE: mnem = "fsin"; break;
            case 0xFF: mnem = "fcos"; break;
            default: UnimplementedInstruction();
          }
1074
      }
1075 1076 1077 1078 1079 1080
      break;

    case 0xDA:
      if (modrm_byte == 0xE9) {
        mnem = "fucompp";
      } else {
1081
        UnimplementedInstruction();
1082 1083 1084 1085 1086 1087 1088 1089 1090
      }
      break;

    case 0xDB:
      if ((modrm_byte & 0xF8) == 0xE8) {
        mnem = "fucomi";
        has_register = true;
      } else if (modrm_byte  == 0xE2) {
        mnem = "fclex";
1091 1092
      } else if (modrm_byte == 0xE3) {
        mnem = "fninit";
1093
      } else {
1094
        UnimplementedInstruction();
1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147
      }
      break;

    case 0xDC:
      has_register = true;
      switch (modrm_byte & 0xF8) {
        case 0xC0: mnem = "fadd"; break;
        case 0xE8: mnem = "fsub"; break;
        case 0xC8: mnem = "fmul"; break;
        case 0xF8: mnem = "fdiv"; break;
        default: UnimplementedInstruction();
      }
      break;

    case 0xDD:
      has_register = true;
      switch (modrm_byte & 0xF8) {
        case 0xC0: mnem = "ffree"; break;
        case 0xD8: mnem = "fstp"; break;
        default: UnimplementedInstruction();
      }
      break;

    case 0xDE:
      if (modrm_byte  == 0xD9) {
        mnem = "fcompp";
      } else {
        has_register = true;
        switch (modrm_byte & 0xF8) {
          case 0xC0: mnem = "faddp"; break;
          case 0xE8: mnem = "fsubp"; break;
          case 0xC8: mnem = "fmulp"; break;
          case 0xF8: mnem = "fdivp"; break;
          default: UnimplementedInstruction();
        }
      }
      break;

    case 0xDF:
      if (modrm_byte == 0xE0) {
        mnem = "fnstsw_ax";
      } else if ((modrm_byte & 0xF8) == 0xE8) {
        mnem = "fucomip";
        has_register = true;
      }
      break;

    default: UnimplementedInstruction();
  }

  if (has_register) {
    AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
  } else {
1148 1149 1150 1151 1152
    AppendToBuffer("%s", mnem);
  }
  return 2;
}

1153

1154

1155 1156 1157 1158 1159 1160 1161 1162
// Handle all two-byte opcodes, which start with 0x0F.
// These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
// We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
  byte opcode = *(data + 1);
  byte* current = data + 2;
  // At return, "current" points to the start of the next instruction.
  const char* mnemonic = TwoByteMnemonic(opcode);
1163 1164 1165
  if (operand_size_ == 0x66) {
    // 0x66 0x0F prefix.
    int mod, regop, rm;
1166 1167 1168 1169 1170 1171 1172
    if (opcode == 0x3A) {
      byte third_byte = *current;
      current = data + 3;
      if (third_byte == 0x17) {
        get_modrm(*current, &mod, &regop, &rm);
        AppendToBuffer("extractps ");  // reg/m32, xmm, imm8
        current += PrintRightOperand(current);
1173
        AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
1174
        current += 1;
1175 1176 1177
      } else if (third_byte == 0x0b) {
        get_modrm(*current, &mod, &regop, &rm);
         // roundsd xmm, xmm/m64, imm8
1178 1179 1180
        AppendToBuffer("roundsd %s,", NameOfXMMRegister(regop));
        current += PrintRightXMMOperand(current);
        AppendToBuffer(",%d", (*current) & 3);
1181
        current += 1;
1182 1183 1184
      } else {
        UnimplementedInstruction();
      }
1185 1186
    } else {
      get_modrm(*current, &mod, &regop, &rm);
1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198
      if (opcode == 0x1f) {
        current++;
        if (rm == 4) {  // SIB byte present.
          current++;
        }
        if (mod == 1) {  // Byte displacement.
          current += 1;
        } else if (mod == 2) {  // 32-bit displacement.
          current += 4;
        }  // else no immediate displacement.
        AppendToBuffer("nop");
      } else if (opcode == 0x28) {
1199
        AppendToBuffer("movapd %s,", NameOfXMMRegister(regop));
lrn@chromium.org's avatar
lrn@chromium.org committed
1200 1201 1202 1203
        current += PrintRightXMMOperand(current);
      } else if (opcode == 0x29) {
        AppendToBuffer("movapd ");
        current += PrintRightXMMOperand(current);
1204
        AppendToBuffer(",%s", NameOfXMMRegister(regop));
lrn@chromium.org's avatar
lrn@chromium.org committed
1205
      } else if (opcode == 0x6E) {
1206 1207 1208 1209
        AppendToBuffer("mov%c %s,",
                       rex_w() ? 'q' : 'd',
                       NameOfXMMRegister(regop));
        current += PrintRightOperand(current);
1210 1211 1212
      } else if (opcode == 0x6F) {
        AppendToBuffer("movdqa %s,",
                       NameOfXMMRegister(regop));
1213
        current += PrintRightXMMOperand(current);
1214
      } else if (opcode == 0x7E) {
1215 1216 1217
        AppendToBuffer("mov%c ",
                       rex_w() ? 'q' : 'd');
        current += PrintRightOperand(current);
1218
        AppendToBuffer(",%s", NameOfXMMRegister(regop));
1219 1220
      } else if (opcode == 0x7F) {
        AppendToBuffer("movdqa ");
1221
        current += PrintRightXMMOperand(current);
1222
        AppendToBuffer(",%s", NameOfXMMRegister(regop));
lrn@chromium.org's avatar
lrn@chromium.org committed
1223 1224 1225
      } else if (opcode == 0xD6) {
        AppendToBuffer("movq ");
        current += PrintRightXMMOperand(current);
1226
        AppendToBuffer(",%s", NameOfXMMRegister(regop));
1227 1228 1229
      } else if (opcode == 0x50) {
        AppendToBuffer("movmskpd %s,", NameOfCPURegister(regop));
        current += PrintRightXMMOperand(current);
1230 1231 1232 1233 1234
      } else if (opcode == 0x72) {
        current += 1;
        AppendToBuffer("%s,%s,%d", (regop == 6) ? "pslld" : "psrld",
                       NameOfXMMRegister(rm), *current & 0x7f);
        current += 1;
1235 1236
      } else if (opcode == 0x73) {
        current += 1;
1237 1238
        AppendToBuffer("%s,%s,%d", (regop == 6) ? "psllq" : "psrlq",
                       NameOfXMMRegister(rm), *current & 0x7f);
1239
        current += 1;
1240 1241
      } else {
        const char* mnemonic = "?";
1242
        if (opcode == 0x54) {
1243 1244 1245 1246
          mnemonic = "andpd";
        } else  if (opcode == 0x56) {
          mnemonic = "orpd";
        } else  if (opcode == 0x57) {
1247 1248 1249
          mnemonic = "xorpd";
        } else if (opcode == 0x2E) {
          mnemonic = "ucomisd";
1250 1251
        } else if (opcode == 0x2F) {
          mnemonic = "comisd";
1252 1253
        } else if (opcode == 0x76) {
          mnemonic = "pcmpeqd";
1254 1255 1256 1257 1258 1259
        } else {
          UnimplementedInstruction();
        }
        AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
        current += PrintRightXMMOperand(current);
      }
1260 1261 1262 1263 1264 1265 1266 1267 1268 1269
    }
  } else if (group_1_prefix_ == 0xF2) {
    // Beginning of instructions with prefix 0xF2.

    if (opcode == 0x11 || opcode == 0x10) {
      // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
      AppendToBuffer("movsd ");
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      if (opcode == 0x11) {
1270
        current += PrintRightXMMOperand(current);
1271 1272 1273
        AppendToBuffer(",%s", NameOfXMMRegister(regop));
      } else {
        AppendToBuffer("%s,", NameOfXMMRegister(regop));
1274
        current += PrintRightXMMOperand(current);
1275 1276 1277 1278 1279
      }
    } else if (opcode == 0x2A) {
      // CVTSI2SD: integer to XMM double conversion.
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
1280
      AppendToBuffer("%sd %s,", mnemonic, NameOfXMMRegister(regop));
1281
      current += PrintRightOperand(current);
1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296
    } else if (opcode == 0x2C) {
      // CVTTSD2SI:
      // Convert with truncation scalar double-precision FP to integer.
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      AppendToBuffer("cvttsd2si%c %s,",
          operand_size_code(), NameOfCPURegister(regop));
      current += PrintRightXMMOperand(current);
    } else if (opcode == 0x2D) {
      // CVTSD2SI: Convert scalar double-precision FP to integer.
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      AppendToBuffer("cvtsd2si%c %s,",
          operand_size_code(), NameOfCPURegister(regop));
      current += PrintRightXMMOperand(current);
1297
    } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
1298 1299 1300 1301 1302
      // XMM arithmetic. Mnemonic was retrieved at the start of this function.
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
      current += PrintRightXMMOperand(current);
1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321
    } else if (opcode == 0xC2) {
      // Intel manual 2A, Table 3-18.
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      const char* const pseudo_op[] = {
        "cmpeqsd",
        "cmpltsd",
        "cmplesd",
        "cmpunordsd",
        "cmpneqsd",
        "cmpnltsd",
        "cmpnlesd",
        "cmpordsd"
      };
      AppendToBuffer("%s %s,%s",
                     pseudo_op[current[1]],
                     NameOfXMMRegister(regop),
                     NameOfXMMRegister(rm));
      current += 2;
1322 1323 1324
    } else {
      UnimplementedInstruction();
    }
1325 1326
  } else if (group_1_prefix_ == 0xF3) {
    // Instructions with prefix 0xF3.
1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345
    if (opcode == 0x11 || opcode == 0x10) {
      // MOVSS: Move scalar double-precision fp to/from/between XMM registers.
      AppendToBuffer("movss ");
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      if (opcode == 0x11) {
        current += PrintRightOperand(current);
        AppendToBuffer(",%s", NameOfXMMRegister(regop));
      } else {
        AppendToBuffer("%s,", NameOfXMMRegister(regop));
        current += PrintRightOperand(current);
      }
    } else if (opcode == 0x2A) {
      // CVTSI2SS: integer to XMM single conversion.
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      AppendToBuffer("%ss %s,", mnemonic, NameOfXMMRegister(regop));
      current += PrintRightOperand(current);
    } else if (opcode == 0x2C) {
1346 1347
      // CVTTSS2SI:
      // Convert with truncation scalar single-precision FP to dword integer.
1348 1349 1350 1351 1352
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      AppendToBuffer("cvttss2si%c %s,",
          operand_size_code(), NameOfCPURegister(regop));
      current += PrintRightXMMOperand(current);
1353 1354 1355 1356 1357 1358 1359 1360 1361 1362
    } else if (opcode == 0x58) {
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      AppendToBuffer("addss %s,", NameOfXMMRegister(regop));
      current += PrintRightXMMOperand(current);
    } else if (opcode == 0x59) {
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      AppendToBuffer("mulss %s,", NameOfXMMRegister(regop));
      current += PrintRightXMMOperand(current);
1363
    } else if (opcode == 0x5A) {
1364 1365
      // CVTSS2SD:
      // Convert scalar single-precision FP to scalar double-precision FP.
1366 1367 1368 1369
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
      current += PrintRightXMMOperand(current);
1370 1371 1372 1373 1374 1375 1376 1377 1378 1379
    } else if (opcode == 0x5c) {
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      AppendToBuffer("subss %s,", NameOfXMMRegister(regop));
      current += PrintRightXMMOperand(current);
    } else if (opcode == 0x5e) {
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
      AppendToBuffer("divss %s,", NameOfXMMRegister(regop));
      current += PrintRightXMMOperand(current);
lrn@chromium.org's avatar
lrn@chromium.org committed
1380 1381 1382
    } else if (opcode == 0x7E) {
      int mod, regop, rm;
      get_modrm(*current, &mod, &regop, &rm);
1383
      AppendToBuffer("movq %s,", NameOfXMMRegister(regop));
lrn@chromium.org's avatar
lrn@chromium.org committed
1384
      current += PrintRightXMMOperand(current);
1385 1386 1387
    } else {
      UnimplementedInstruction();
    }
1388
  } else if (opcode == 0x1F) {
1389 1390 1391 1392
    // NOP
    int mod, regop, rm;
    get_modrm(*current, &mod, &regop, &rm);
    current++;
1393
    if (rm == 4) {  // SIB byte present.
1394 1395 1396 1397 1398 1399 1400 1401
      current++;
    }
    if (mod == 1) {  // Byte displacement.
      current += 1;
    } else if (mod == 2) {  // 32-bit displacement.
      current += 4;
    }  // else no immediate displacement.
    AppendToBuffer("nop");
lrn@chromium.org's avatar
lrn@chromium.org committed
1402

1403
  } else if (opcode == 0x28) {
lrn@chromium.org's avatar
lrn@chromium.org committed
1404 1405 1406
    // movaps xmm, xmm/m128
    int mod, regop, rm;
    get_modrm(*current, &mod, &regop, &rm);
1407
    AppendToBuffer("movaps %s,", NameOfXMMRegister(regop));
lrn@chromium.org's avatar
lrn@chromium.org committed
1408 1409
    current += PrintRightXMMOperand(current);

1410
  } else if (opcode == 0x29) {
lrn@chromium.org's avatar
lrn@chromium.org committed
1411 1412 1413
    // movaps xmm/m128, xmm
    int mod, regop, rm;
    get_modrm(*current, &mod, &regop, &rm);
1414
    AppendToBuffer("movaps ");
lrn@chromium.org's avatar
lrn@chromium.org committed
1415
    current += PrintRightXMMOperand(current);
1416
    AppendToBuffer(",%s", NameOfXMMRegister(regop));
lrn@chromium.org's avatar
lrn@chromium.org committed
1417

1418 1419 1420 1421 1422
  } else if (opcode == 0x2e) {
    int mod, regop, rm;
    get_modrm(*current, &mod, &regop, &rm);
    AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
    current += PrintRightXMMOperand(current);
1423 1424
  } else if (opcode == 0xA2) {
    // CPUID
1425 1426
    AppendToBuffer("%s", mnemonic);

1427 1428 1429 1430 1431 1432 1433
  } else if ((opcode & 0xF0) == 0x40) {
    // CMOVcc: conditional move.
    int condition = opcode & 0x0F;
    const InstructionDesc& idesc = cmov_instructions[condition];
    byte_size_operand_ = idesc.byte_size_operation;
    current += PrintOperands(idesc.mnem, idesc.op_order_, current);

1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449
  } else if (opcode >= 0x53 && opcode <= 0x5F) {
    const char* const pseudo_op[] = {
      "rcpps",
      "andps",
      "andnps",
      "orps",
      "xorps",
      "addps",
      "mulps",
      "cvtps2pd",
      "cvtdq2ps",
      "subps",
      "minps",
      "divps",
      "maxps",
    };
1450 1451
    int mod, regop, rm;
    get_modrm(*current, &mod, &regop, &rm);
1452 1453 1454
    AppendToBuffer("%s %s,",
                   pseudo_op[opcode - 0x53],
                   NameOfXMMRegister(regop));
1455 1456
    current += PrintRightXMMOperand(current);

1457 1458
  } else if (opcode == 0xC6) {
    // shufps xmm, xmm/m128, imm8
1459 1460
    int mod, regop, rm;
    get_modrm(*current, &mod, &regop, &rm);
1461
    AppendToBuffer("shufps %s, ", NameOfXMMRegister(regop));
lrn@chromium.org's avatar
lrn@chromium.org committed
1462
    current += PrintRightXMMOperand(current);
1463 1464
    AppendToBuffer(", %d", (*current) & 3);
    current += 1;
lrn@chromium.org's avatar
lrn@chromium.org committed
1465

1466 1467 1468 1469
  } else if (opcode == 0x50) {
    // movmskps reg, xmm
    int mod, regop, rm;
    get_modrm(*current, &mod, &regop, &rm);
1470
    AppendToBuffer("movmskps %s,", NameOfCPURegister(regop));
1471 1472
    current += PrintRightXMMOperand(current);

1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496
  } else if ((opcode & 0xF0) == 0x80) {
    // Jcc: Conditional jump (branch).
    current = data + JumpConditional(data);

  } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
             opcode == 0xB7 || opcode == 0xAF) {
    // Size-extending moves, IMUL.
    current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);

  } else if ((opcode & 0xF0) == 0x90) {
    // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
    current = data + SetCC(data);

  } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
    // SHLD, SHRD (double-precision shift), BTS (bit set).
    AppendToBuffer("%s ", mnemonic);
    int mod, regop, rm;
    get_modrm(*current, &mod, &regop, &rm);
    current += PrintRightOperand(current);
    if (opcode == 0xAB) {
      AppendToBuffer(",%s", NameOfCPURegister(regop));
    } else {
      AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
    }
1497 1498 1499 1500 1501 1502
  } else if (opcode == 0xBD) {
    AppendToBuffer("%s%c ", mnemonic, operand_size_code());
    int mod, regop, rm;
    get_modrm(*current, &mod, &regop, &rm);
    AppendToBuffer("%s,", NameOfCPURegister(regop));
    current += PrintRightOperand(current);
1503 1504 1505
  } else {
    UnimplementedInstruction();
  }
1506
  return static_cast<int>(current - data);
1507 1508 1509 1510 1511
}


// Mnemonics for two-byte opcode instructions starting with 0x0F.
// The argument is the second byte of the two-byte opcode.
1512
// Returns NULL if the instruction is not handled here.
1513 1514
const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
  switch (opcode) {
1515 1516
    case 0x1F:
      return "nop";
1517 1518
    case 0x2A:  // F2/F3 prefix.
      return "cvtsi2s";
1519 1520
    case 0x51:  // F2 prefix.
      return "sqrtsd";
1521 1522 1523 1524
    case 0x58:  // F2 prefix.
      return "addsd";
    case 0x59:  // F2 prefix.
      return "mulsd";
1525 1526
    case 0x5A:  // F2 prefix.
      return "cvtsd2ss";
1527 1528 1529 1530
    case 0x5C:  // F2 prefix.
      return "subsd";
    case 0x5E:  // F2 prefix.
      return "divsd";
1531 1532 1533 1534 1535 1536
    case 0xA2:
      return "cpuid";
    case 0xA5:
      return "shld";
    case 0xAB:
      return "bts";
1537 1538 1539 1540 1541 1542 1543 1544
    case 0xAD:
      return "shrd";
    case 0xAF:
      return "imul";
    case 0xB6:
      return "movzxb";
    case 0xB7:
      return "movzxw";
1545 1546
    case 0xBD:
      return "bsr";
1547 1548 1549 1550
    case 0xBE:
      return "movsxb";
    case 0xBF:
      return "movsxw";
1551 1552 1553 1554 1555
    default:
      return NULL;
  }
}

1556 1557

// Disassembles the instruction at instr, and writes it into out_buffer.
1558 1559 1560 1561 1562 1563 1564 1565 1566 1567 1568
int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
                                       byte* instr) {
  tmp_buffer_pos_ = 0;  // starting to write as position 0
  byte* data = instr;
  bool processed = true;  // Will be set to false if the current instruction
                          // is not in 'instructions' table.
  byte current;

  // Scan for prefixes.
  while (true) {
    current = *data;
1569
    if (current == OPERAND_SIZE_OVERRIDE_PREFIX) {  // Group 3 prefix.
1570 1571
      operand_size_ = current;
    } else if ((current & 0xF0) == 0x40) {  // REX prefix.
1572 1573
      setRex(current);
      if (rex_w()) AppendToBuffer("REX.W ");
1574
    } else if ((current & 0xFE) == 0xF2) {  // Group 1 prefix (0xF2 or 0xF3).
1575
      group_1_prefix_ = current;
1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586
    } else if (current == VEX3_PREFIX) {
      vex_byte0_ = current;
      vex_byte1_ = *(data + 1);
      vex_byte2_ = *(data + 2);
      setRex(0x40 | (~(vex_byte1_ >> 5) & 7) | ((vex_byte2_ >> 4) & 8));
      data += 2;
    } else if (current == VEX2_PREFIX) {
      vex_byte0_ = current;
      vex_byte1_ = *(data + 1);
      setRex(0x40 | (~(vex_byte1_ >> 5) & 4));
      data++;
1587
    } else {  // Not a prefix - an opcode.
1588 1589
      break;
    }
1590
    data++;
1591 1592
  }

1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611
  // Decode AVX instructions.
  if (vex_byte0_ != 0) {
    processed = true;
    data += AVXInstruction(data);
  } else {
    const InstructionDesc& idesc = instruction_table_->Get(current);
    byte_size_operand_ = idesc.byte_size_operation;
    switch (idesc.type) {
      case ZERO_OPERANDS_INSTR:
        if (current >= 0xA4 && current <= 0xA7) {
          // String move or compare operations.
          if (group_1_prefix_ == REP_PREFIX) {
            // REP.
            AppendToBuffer("rep ");
          }
          if (rex_w()) AppendToBuffer("REX.W ");
          AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
        } else {
          AppendToBuffer("%s", idesc.mnem, operand_size_code());
1612
        }
1613 1614
        data++;
        break;
1615

1616 1617 1618 1619
      case TWO_OPERANDS_INSTR:
        data++;
        data += PrintOperands(idesc.mnem, idesc.op_order_, data);
        break;
1620

1621 1622 1623
      case JUMP_CONDITIONAL_SHORT_INSTR:
        data += JumpConditionalShort(data);
        break;
1624

1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659
      case REGISTER_INSTR:
        AppendToBuffer("%s%c %s", idesc.mnem, operand_size_code(),
                       NameOfCPURegister(base_reg(current & 0x07)));
        data++;
        break;
      case PUSHPOP_INSTR:
        AppendToBuffer("%s %s", idesc.mnem,
                       NameOfCPURegister(base_reg(current & 0x07)));
        data++;
        break;
      case MOVE_REG_INSTR: {
        byte* addr = NULL;
        switch (operand_size()) {
          case OPERAND_WORD_SIZE:
            addr =
                reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
            data += 3;
            break;
          case OPERAND_DOUBLEWORD_SIZE:
            addr =
                reinterpret_cast<byte*>(*reinterpret_cast<uint32_t*>(data + 1));
            data += 5;
            break;
          case OPERAND_QUADWORD_SIZE:
            addr =
                reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
            data += 9;
            break;
          default:
            UNREACHABLE();
        }
        AppendToBuffer("mov%c %s,%s", operand_size_code(),
                       NameOfCPURegister(base_reg(current & 0x07)),
                       NameOfAddress(addr));
        break;
1660 1661
      }

1662 1663 1664 1665 1666 1667
      case CALL_JUMP_INSTR: {
        byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
        AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
        data += 5;
        break;
      }
1668

1669 1670 1671 1672 1673 1674 1675
      case SHORT_IMMEDIATE_INSTR: {
        byte* addr =
            reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
        AppendToBuffer("%s rax,%s", idesc.mnem, NameOfAddress(addr));
        data += 5;
        break;
      }
1676

1677 1678 1679
      case NO_INSTR:
        processed = false;
        break;
1680

1681 1682 1683
      default:
        UNIMPLEMENTED();  // This type is not implemented.
    }
1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696
  }

  // The first byte didn't match any of the simple opcodes, so we
  // need to do special processing on it.
  if (!processed) {
    switch (*data) {
      case 0xC2:
        AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
        data += 3;
        break;

      case 0x69:  // fall through
      case 0x6B: {
1697 1698 1699 1700 1701 1702 1703 1704 1705
        int count = 1;
        count += PrintOperands("imul", REG_OPER_OP_ORDER, data + count);
        AppendToBuffer(",0x");
        if (*data == 0x69) {
          count += PrintImmediate(data + count, operand_size());
        } else {
          count += PrintImmediate(data + count, OPERAND_BYTE_SIZE);
        }
        data += count;
1706
        break;
1707
      }
1708 1709 1710 1711 1712 1713

      case 0x81:  // fall through
      case 0x83:  // 0x81 with sign extension bit set
        data += PrintImmediateOp(data);
        break;

1714 1715
      case 0x0F:
        data += TwoByteOpcodeInstruction(data);
1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764
        break;

      case 0x8F: {
        data++;
        int mod, regop, rm;
        get_modrm(*data, &mod, &regop, &rm);
        if (regop == 0) {
          AppendToBuffer("pop ");
          data += PrintRightOperand(data);
        }
      }
        break;

      case 0xFF: {
        data++;
        int mod, regop, rm;
        get_modrm(*data, &mod, &regop, &rm);
        const char* mnem = NULL;
        switch (regop) {
          case 0:
            mnem = "inc";
            break;
          case 1:
            mnem = "dec";
            break;
          case 2:
            mnem = "call";
            break;
          case 4:
            mnem = "jmp";
            break;
          case 6:
            mnem = "push";
            break;
          default:
            mnem = "???";
        }
        AppendToBuffer(((regop <= 1) ? "%s%c " : "%s "),
                       mnem,
                       operand_size_code());
        data += PrintRightOperand(data);
      }
        break;

      case 0xC7:  // imm32, fall through
      case 0xC6:  // imm8
      {
        bool is_byte = *data == 0xC6;
        data++;
1765 1766 1767 1768 1769 1770 1771 1772 1773
        if (is_byte) {
          AppendToBuffer("movb ");
          data += PrintRightByteOperand(data);
          int32_t imm = *data;
          AppendToBuffer(",0x%x", imm);
          data++;
        } else {
          AppendToBuffer("mov%c ", operand_size_code());
          data += PrintRightOperand(data);
1774 1775 1776 1777 1778 1779 1780 1781 1782
          if (operand_size() == OPERAND_WORD_SIZE) {
            int16_t imm = *reinterpret_cast<int16_t*>(data);
            AppendToBuffer(",0x%x", imm);
            data += 2;
          } else {
            int32_t imm = *reinterpret_cast<int32_t*>(data);
            AppendToBuffer(",0x%x", imm);
            data += 4;
          }
1783
        }
1784 1785 1786 1787 1788 1789
      }
        break;

      case 0x80: {
        data++;
        AppendToBuffer("cmpb ");
1790
        data += PrintRightByteOperand(data);
1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803
        int32_t imm = *data;
        AppendToBuffer(",0x%x", imm);
        data++;
      }
        break;

      case 0x88:  // 8bit, fall through
      case 0x89:  // 32bit
      {
        bool is_byte = *data == 0x88;
        int mod, regop, rm;
        data++;
        get_modrm(*data, &mod, &regop, &rm);
1804 1805 1806 1807 1808 1809 1810 1811 1812
        if (is_byte) {
          AppendToBuffer("movb ");
          data += PrintRightByteOperand(data);
          AppendToBuffer(",%s", NameOfByteCPURegister(regop));
        } else {
          AppendToBuffer("mov%c ", operand_size_code());
          data += PrintRightOperand(data);
          AppendToBuffer(",%s", NameOfCPURegister(regop));
        }
1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823
      }
        break;

      case 0x90:
      case 0x91:
      case 0x92:
      case 0x93:
      case 0x94:
      case 0x95:
      case 0x96:
      case 0x97: {
1824
        int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
1825 1826 1827
        if (reg == 0) {
          AppendToBuffer("nop");  // Common name for xchg rax,rax.
        } else {
1828
          AppendToBuffer("xchg%c rax,%s",
1829
                         operand_size_code(),
1830
                         NameOfCPURegister(reg));
1831
        }
1832
        data++;
1833
      }
1834
        break;
1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856
      case 0xB0:
      case 0xB1:
      case 0xB2:
      case 0xB3:
      case 0xB4:
      case 0xB5:
      case 0xB6:
      case 0xB7:
      case 0xB8:
      case 0xB9:
      case 0xBA:
      case 0xBB:
      case 0xBC:
      case 0xBD:
      case 0xBE:
      case 0xBF: {
        // mov reg8,imm8 or mov reg32,imm32
        byte opcode = *data;
        data++;
        bool is_32bit = (opcode >= 0xB8);
        int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
        if (is_32bit) {
1857
          AppendToBuffer("mov%c %s,",
1858 1859
                         operand_size_code(),
                         NameOfCPURegister(reg));
1860
          data += PrintImmediate(data, OPERAND_DOUBLEWORD_SIZE);
1861
        } else {
1862
          AppendToBuffer("movb %s,",
1863
                         NameOfByteCPURegister(reg));
1864
          data += PrintImmediate(data, OPERAND_BYTE_SIZE);
1865 1866 1867
        }
        break;
      }
1868 1869 1870 1871
      case 0xFE: {
        data++;
        int mod, regop, rm;
        get_modrm(*data, &mod, &regop, &rm);
1872 1873
        if (regop == 1) {
          AppendToBuffer("decb ");
1874
          data += PrintRightByteOperand(data);
1875 1876 1877 1878
        } else {
          UnimplementedInstruction();
        }
        break;
1879
      }
1880 1881 1882 1883 1884 1885 1886 1887 1888 1889
      case 0x68:
        AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
        data += 5;
        break;

      case 0x6A:
        AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
        data += 2;
        break;

1890 1891 1892
      case 0xA1:  // Fall through.
      case 0xA3:
        switch (operand_size()) {
1893
          case OPERAND_DOUBLEWORD_SIZE: {
1894 1895 1896
            const char* memory_location = NameOfAddress(
                reinterpret_cast<byte*>(
                    *reinterpret_cast<int32_t*>(data + 1)));
1897
            if (*data == 0xA1) {  // Opcode 0xA1
1898
              AppendToBuffer("movzxlq rax,(%s)", memory_location);
1899
            } else {  // Opcode 0xA3
1900 1901 1902 1903 1904
              AppendToBuffer("movzxlq (%s),rax", memory_location);
            }
            data += 5;
            break;
          }
1905
          case OPERAND_QUADWORD_SIZE: {
1906 1907 1908
            // New x64 instruction mov rax,(imm_64).
            const char* memory_location = NameOfAddress(
                *reinterpret_cast<byte**>(data + 1));
1909
            if (*data == 0xA1) {  // Opcode 0xA1
1910
              AppendToBuffer("movq rax,(%s)", memory_location);
1911
            } else {  // Opcode 0xA3
1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922
              AppendToBuffer("movq (%s),rax", memory_location);
            }
            data += 9;
            break;
          }
          default:
            UnimplementedInstruction();
            data += 2;
        }
        break;

1923 1924 1925 1926 1927
      case 0xA8:
        AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
        data += 2;
        break;

1928
      case 0xA9: {
1929
        int64_t value = 0;
1930
        switch (operand_size()) {
1931
          case OPERAND_WORD_SIZE:
1932 1933 1934
            value = *reinterpret_cast<uint16_t*>(data + 1);
            data += 3;
            break;
1935
          case OPERAND_DOUBLEWORD_SIZE:
1936 1937 1938
            value = *reinterpret_cast<uint32_t*>(data + 1);
            data += 5;
            break;
1939
          case OPERAND_QUADWORD_SIZE:
1940 1941 1942 1943 1944 1945
            value = *reinterpret_cast<int32_t*>(data + 1);
            data += 5;
            break;
          default:
            UNREACHABLE();
        }
1946
        AppendToBuffer("test%c rax,0x%" V8_PTR_PREFIX "x",
1947 1948
                       operand_size_code(),
                       value);
1949
        break;
1950
      }
1951 1952 1953
      case 0xD1:  // fall through
      case 0xD3:  // fall through
      case 0xC1:
1954 1955 1956 1957 1958 1959 1960
        data += ShiftInstruction(data);
        break;
      case 0xD0:  // fall through
      case 0xD2:  // fall through
      case 0xC0:
        byte_size_operand_ = true;
        data += ShiftInstruction(data);
1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976
        break;

      case 0xD9:  // fall through
      case 0xDA:  // fall through
      case 0xDB:  // fall through
      case 0xDC:  // fall through
      case 0xDD:  // fall through
      case 0xDE:  // fall through
      case 0xDF:
        data += FPUInstruction(data);
        break;

      case 0xEB:
        data += JumpShort(data);
        break;

1977 1978
      case 0xF6:
        byte_size_operand_ = true;  // fall through
1979
      case 0xF7:
1980
        data += F6F7Instruction(data);
1981 1982
        break;

1983
      case 0x3C:
1984
        AppendToBuffer("cmp al,0x%x", *reinterpret_cast<int8_t*>(data + 1));
1985 1986 1987
        data +=2;
        break;

1988 1989
      default:
        UnimplementedInstruction();
1990
        data += 1;
1991 1992 1993 1994 1995 1996 1997
    }
  }  // !processed

  if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
    tmp_buffer_[tmp_buffer_pos_] = '\0';
  }

1998
  int instr_len = static_cast<int>(data - instr);
1999
  DCHECK(instr_len > 0);  // Ensure progress.
2000 2001 2002 2003

  int outp = 0;
  // Instruction bytes.
  for (byte* bp = instr; bp < data; bp++) {
2004
    outp += v8::internal::SNPrintF(out_buffer + outp, "%02x", *bp);
2005 2006
  }
  for (int i = 6 - instr_len; i >= 0; i--) {
2007
    outp += v8::internal::SNPrintF(out_buffer + outp, "  ");
2008 2009
  }

2010 2011
  outp += v8::internal::SNPrintF(out_buffer + outp, " %s",
                                 tmp_buffer_.start());
2012 2013 2014
  return instr_len;
}

2015

2016 2017 2018
//------------------------------------------------------------------------------


2019
static const char* const cpu_regs[16] = {
2020 2021 2022 2023 2024
  "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
  "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
};


2025
static const char* const byte_cpu_regs[16] = {
2026 2027 2028 2029 2030
  "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
  "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
};


2031
static const char* const xmm_regs[16] = {
2032 2033 2034 2035 2036 2037
  "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
  "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
};


const char* NameConverter::NameOfAddress(byte* addr) const {
2038
  v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
2039
  return tmp_buffer_.start();
2040 2041 2042 2043 2044
}


const char* NameConverter::NameOfConstant(byte* addr) const {
  return NameOfAddress(addr);
2045
}
2046 2047


2048
const char* NameConverter::NameOfCPURegister(int reg) const {
2049 2050 2051
  if (0 <= reg && reg < 16)
    return cpu_regs[reg];
  return "noreg";
2052
}
2053 2054


2055 2056 2057 2058
const char* NameConverter::NameOfByteCPURegister(int reg) const {
  if (0 <= reg && reg < 16)
    return byte_cpu_regs[reg];
  return "noreg";
2059
}
2060 2061


2062 2063 2064 2065
const char* NameConverter::NameOfXMMRegister(int reg) const {
  if (0 <= reg && reg < 16)
    return xmm_regs[reg];
  return "noxmmreg";
2066
}
2067

2068 2069 2070 2071 2072

const char* NameConverter::NameInCode(byte* addr) const {
  // X64 does not embed debug strings at the moment.
  UNREACHABLE();
  return "";
2073 2074
}

2075

2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087
//------------------------------------------------------------------------------

Disassembler::Disassembler(const NameConverter& converter)
    : converter_(converter) { }

Disassembler::~Disassembler() { }


int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
                                    byte* instruction) {
  DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE);
  return d.InstructionDecode(buffer, instruction);
2088 2089
}

2090 2091 2092 2093

// The X64 assembler does not use constant pools.
int Disassembler::ConstantPoolSizeAt(byte* instruction) {
  return -1;
2094 2095
}

2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110

void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
  NameConverter converter;
  Disassembler d(converter);
  for (byte* pc = begin; pc < end;) {
    v8::internal::EmbeddedVector<char, 128> buffer;
    buffer[0] = '\0';
    byte* prev_pc = pc;
    pc += d.InstructionDecode(buffer, pc);
    fprintf(f, "%p", prev_pc);
    fprintf(f, "    ");

    for (byte* bp = prev_pc; bp < pc; bp++) {
      fprintf(f, "%02x", *bp);
    }
2111
    for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) {
2112 2113 2114 2115
      fprintf(f, "  ");
    }
    fprintf(f, "  %s\n", buffer.start());
  }
2116
}
2117 2118

}  // namespace disasm
2119 2120

#endif  // V8_TARGET_ARCH_X64