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