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