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