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