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