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