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