V8 Project
disasm-x87.cc
Go to the documentation of this file.
1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <assert.h>
6 #include <stdarg.h>
7 #include <stdio.h>
8 
9 #include "src/v8.h"
10 
11 #if V8_TARGET_ARCH_X87
12 
13 #include "src/disasm.h"
14 
15 namespace disasm {
16 
17 enum OperandOrder {
18  UNSET_OP_ORDER = 0,
19  REG_OPER_OP_ORDER,
20  OPER_REG_OP_ORDER
21 };
22 
23 
24 //------------------------------------------------------------------
25 // Tables
26 //------------------------------------------------------------------
27 struct ByteMnemonic {
28  int b; // -1 terminates, otherwise must be in range (0..255)
29  const char* mnem;
30  OperandOrder op_order_;
31 };
32 
33 
34 static const ByteMnemonic two_operands_instr[] = {
35  {0x01, "add", OPER_REG_OP_ORDER},
36  {0x03, "add", REG_OPER_OP_ORDER},
37  {0x09, "or", OPER_REG_OP_ORDER},
38  {0x0B, "or", REG_OPER_OP_ORDER},
39  {0x1B, "sbb", REG_OPER_OP_ORDER},
40  {0x21, "and", OPER_REG_OP_ORDER},
41  {0x23, "and", REG_OPER_OP_ORDER},
42  {0x29, "sub", OPER_REG_OP_ORDER},
43  {0x2A, "subb", REG_OPER_OP_ORDER},
44  {0x2B, "sub", REG_OPER_OP_ORDER},
45  {0x31, "xor", OPER_REG_OP_ORDER},
46  {0x33, "xor", REG_OPER_OP_ORDER},
47  {0x38, "cmpb", OPER_REG_OP_ORDER},
48  {0x3A, "cmpb", REG_OPER_OP_ORDER},
49  {0x3B, "cmp", REG_OPER_OP_ORDER},
50  {0x84, "test_b", REG_OPER_OP_ORDER},
51  {0x85, "test", REG_OPER_OP_ORDER},
52  {0x87, "xchg", REG_OPER_OP_ORDER},
53  {0x8A, "mov_b", REG_OPER_OP_ORDER},
54  {0x8B, "mov", REG_OPER_OP_ORDER},
55  {0x8D, "lea", REG_OPER_OP_ORDER},
56  {-1, "", UNSET_OP_ORDER}
57 };
58 
59 
60 static const ByteMnemonic zero_operands_instr[] = {
61  {0xC3, "ret", UNSET_OP_ORDER},
62  {0xC9, "leave", UNSET_OP_ORDER},
63  {0x90, "nop", UNSET_OP_ORDER},
64  {0xF4, "hlt", UNSET_OP_ORDER},
65  {0xCC, "int3", UNSET_OP_ORDER},
66  {0x60, "pushad", UNSET_OP_ORDER},
67  {0x61, "popad", UNSET_OP_ORDER},
68  {0x9C, "pushfd", UNSET_OP_ORDER},
69  {0x9D, "popfd", UNSET_OP_ORDER},
70  {0x9E, "sahf", UNSET_OP_ORDER},
71  {0x99, "cdq", UNSET_OP_ORDER},
72  {0x9B, "fwait", UNSET_OP_ORDER},
73  {0xFC, "cld", UNSET_OP_ORDER},
74  {0xAB, "stos", UNSET_OP_ORDER},
75  {-1, "", UNSET_OP_ORDER}
76 };
77 
78 
79 static const ByteMnemonic call_jump_instr[] = {
80  {0xE8, "call", UNSET_OP_ORDER},
81  {0xE9, "jmp", UNSET_OP_ORDER},
82  {-1, "", UNSET_OP_ORDER}
83 };
84 
85 
86 static const ByteMnemonic short_immediate_instr[] = {
87  {0x05, "add", UNSET_OP_ORDER},
88  {0x0D, "or", UNSET_OP_ORDER},
89  {0x15, "adc", UNSET_OP_ORDER},
90  {0x25, "and", UNSET_OP_ORDER},
91  {0x2D, "sub", UNSET_OP_ORDER},
92  {0x35, "xor", UNSET_OP_ORDER},
93  {0x3D, "cmp", UNSET_OP_ORDER},
94  {-1, "", UNSET_OP_ORDER}
95 };
96 
97 
98 // Generally we don't want to generate these because they are subject to partial
99 // register stalls. They are included for completeness and because the cmp
100 // variant is used by the RecordWrite stub. Because it does not update the
101 // register it is not subject to partial register stalls.
102 static ByteMnemonic byte_immediate_instr[] = {
103  {0x0c, "or", UNSET_OP_ORDER},
104  {0x24, "and", UNSET_OP_ORDER},
105  {0x34, "xor", UNSET_OP_ORDER},
106  {0x3c, "cmp", UNSET_OP_ORDER},
107  {-1, "", UNSET_OP_ORDER}
108 };
109 
110 
111 static const char* const jump_conditional_mnem[] = {
112  /*0*/ "jo", "jno", "jc", "jnc",
113  /*4*/ "jz", "jnz", "jna", "ja",
114  /*8*/ "js", "jns", "jpe", "jpo",
115  /*12*/ "jl", "jnl", "jng", "jg"
116 };
117 
118 
119 static const char* const set_conditional_mnem[] = {
120  /*0*/ "seto", "setno", "setc", "setnc",
121  /*4*/ "setz", "setnz", "setna", "seta",
122  /*8*/ "sets", "setns", "setpe", "setpo",
123  /*12*/ "setl", "setnl", "setng", "setg"
124 };
125 
126 
127 static const char* const conditional_move_mnem[] = {
128  /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc",
129  /*4*/ "cmovz", "cmovnz", "cmovna", "cmova",
130  /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo",
131  /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg"
132 };
133 
134 
135 enum InstructionType {
136  NO_INSTR,
137  ZERO_OPERANDS_INSTR,
138  TWO_OPERANDS_INSTR,
139  JUMP_CONDITIONAL_SHORT_INSTR,
140  REGISTER_INSTR,
141  MOVE_REG_INSTR,
142  CALL_JUMP_INSTR,
143  SHORT_IMMEDIATE_INSTR,
144  BYTE_IMMEDIATE_INSTR
145 };
146 
147 
148 struct InstructionDesc {
149  const char* mnem;
150  InstructionType type;
151  OperandOrder op_order_;
152 };
153 
154 
155 class InstructionTable {
156  public:
157  InstructionTable();
158  const InstructionDesc& Get(byte x) const { return instructions_[x]; }
159  static InstructionTable* get_instance() {
160  static InstructionTable table;
161  return &table;
162  }
163 
164  private:
165  InstructionDesc instructions_[256];
166  void Clear();
167  void Init();
168  void CopyTable(const ByteMnemonic bm[], InstructionType type);
169  void SetTableRange(InstructionType type,
170  byte start,
171  byte end,
172  const char* mnem);
173  void AddJumpConditionalShort();
174 };
175 
176 
177 InstructionTable::InstructionTable() {
178  Clear();
179  Init();
180 }
181 
182 
183 void InstructionTable::Clear() {
184  for (int i = 0; i < 256; i++) {
185  instructions_[i].mnem = "";
186  instructions_[i].type = NO_INSTR;
187  instructions_[i].op_order_ = UNSET_OP_ORDER;
188  }
189 }
190 
191 
192 void InstructionTable::Init() {
193  CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
194  CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
195  CopyTable(call_jump_instr, CALL_JUMP_INSTR);
196  CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
197  CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR);
198  AddJumpConditionalShort();
199  SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
200  SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
201  SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
202  SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
203  SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,"); // 0x90 is nop.
204  SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
205 }
206 
207 
208 void InstructionTable::CopyTable(const ByteMnemonic bm[],
209  InstructionType type) {
210  for (int i = 0; bm[i].b >= 0; i++) {
211  InstructionDesc* id = &instructions_[bm[i].b];
212  id->mnem = bm[i].mnem;
213  id->op_order_ = bm[i].op_order_;
214  DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
215  id->type = type;
216  }
217 }
218 
219 
220 void InstructionTable::SetTableRange(InstructionType type,
221  byte start,
222  byte end,
223  const char* mnem) {
224  for (byte b = start; b <= end; b++) {
225  InstructionDesc* id = &instructions_[b];
226  DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
227  id->mnem = mnem;
228  id->type = type;
229  }
230 }
231 
232 
233 void InstructionTable::AddJumpConditionalShort() {
234  for (byte b = 0x70; b <= 0x7F; b++) {
235  InstructionDesc* id = &instructions_[b];
236  DCHECK_EQ(NO_INSTR, id->type); // Information not already entered.
237  id->mnem = jump_conditional_mnem[b & 0x0F];
238  id->type = JUMP_CONDITIONAL_SHORT_INSTR;
239  }
240 }
241 
242 
243 // The X87 disassembler implementation.
244 class DisassemblerX87 {
245  public:
246  DisassemblerX87(const NameConverter& converter,
247  bool abort_on_unimplemented = true)
248  : converter_(converter),
249  instruction_table_(InstructionTable::get_instance()),
250  tmp_buffer_pos_(0),
251  abort_on_unimplemented_(abort_on_unimplemented) {
252  tmp_buffer_[0] = '\0';
253  }
254 
255  virtual ~DisassemblerX87() {}
256 
257  // Writes one disassembled instruction into 'buffer' (0-terminated).
258  // Returns the length of the disassembled machine instruction in bytes.
259  int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
260 
261  private:
262  const NameConverter& converter_;
263  InstructionTable* instruction_table_;
265  unsigned int tmp_buffer_pos_;
266  bool abort_on_unimplemented_;
267 
268  enum {
269  eax = 0,
270  ecx = 1,
271  edx = 2,
272  ebx = 3,
273  esp = 4,
274  ebp = 5,
275  esi = 6,
276  edi = 7
277  };
278 
279 
280  enum ShiftOpcodeExtension {
281  kROL = 0,
282  kROR = 1,
283  kRCL = 2,
284  kRCR = 3,
285  kSHL = 4,
286  KSHR = 5,
287  kSAR = 7
288  };
289 
290 
291  const char* NameOfCPURegister(int reg) const {
292  return converter_.NameOfCPURegister(reg);
293  }
294 
295 
296  const char* NameOfByteCPURegister(int reg) const {
297  return converter_.NameOfByteCPURegister(reg);
298  }
299 
300 
301  const char* NameOfXMMRegister(int reg) const {
302  return converter_.NameOfXMMRegister(reg);
303  }
304 
305 
306  const char* NameOfAddress(byte* addr) const {
307  return converter_.NameOfAddress(addr);
308  }
309 
310 
311  // Disassembler helper functions.
312  static void get_modrm(byte data, int* mod, int* regop, int* rm) {
313  *mod = (data >> 6) & 3;
314  *regop = (data & 0x38) >> 3;
315  *rm = data & 7;
316  }
317 
318 
319  static void get_sib(byte data, int* scale, int* index, int* base) {
320  *scale = (data >> 6) & 3;
321  *index = (data >> 3) & 7;
322  *base = data & 7;
323  }
324 
325  typedef const char* (DisassemblerX87::*RegisterNameMapping)(int reg) const;
326 
327  int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
328  int PrintRightOperand(byte* modrmp);
329  int PrintRightByteOperand(byte* modrmp);
330  int PrintRightXMMOperand(byte* modrmp);
331  int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
332  int PrintImmediateOp(byte* data);
333  int F7Instruction(byte* data);
334  int D1D3C1Instruction(byte* data);
335  int JumpShort(byte* data);
336  int JumpConditional(byte* data, const char* comment);
337  int JumpConditionalShort(byte* data, const char* comment);
338  int SetCC(byte* data);
339  int CMov(byte* data);
340  int FPUInstruction(byte* data);
341  int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
342  int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
343  void AppendToBuffer(const char* format, ...);
344 
345 
346  void UnimplementedInstruction() {
347  if (abort_on_unimplemented_) {
348  UNIMPLEMENTED();
349  } else {
350  AppendToBuffer("'Unimplemented Instruction'");
351  }
352  }
353 };
354 
355 
356 void DisassemblerX87::AppendToBuffer(const char* format, ...) {
357  v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
358  va_list args;
359  va_start(args, format);
360  int result = v8::internal::VSNPrintF(buf, format, args);
361  va_end(args);
362  tmp_buffer_pos_ += result;
363 }
364 
365 int DisassemblerX87::PrintRightOperandHelper(
366  byte* modrmp,
367  RegisterNameMapping direct_register_name) {
368  int mod, regop, rm;
369  get_modrm(*modrmp, &mod, &regop, &rm);
370  RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
371  &DisassemblerX87::NameOfCPURegister;
372  switch (mod) {
373  case 0:
374  if (rm == ebp) {
375  int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
376  AppendToBuffer("[0x%x]", disp);
377  return 5;
378  } else if (rm == esp) {
379  byte sib = *(modrmp + 1);
380  int scale, index, base;
381  get_sib(sib, &scale, &index, &base);
382  if (index == esp && base == esp && scale == 0 /*times_1*/) {
383  AppendToBuffer("[%s]", (this->*register_name)(rm));
384  return 2;
385  } else if (base == ebp) {
386  int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
387  AppendToBuffer("[%s*%d%s0x%x]",
388  (this->*register_name)(index),
389  1 << scale,
390  disp < 0 ? "-" : "+",
391  disp < 0 ? -disp : disp);
392  return 6;
393  } else if (index != esp && base != ebp) {
394  // [base+index*scale]
395  AppendToBuffer("[%s+%s*%d]",
396  (this->*register_name)(base),
397  (this->*register_name)(index),
398  1 << scale);
399  return 2;
400  } else {
401  UnimplementedInstruction();
402  return 1;
403  }
404  } else {
405  AppendToBuffer("[%s]", (this->*register_name)(rm));
406  return 1;
407  }
408  break;
409  case 1: // fall through
410  case 2:
411  if (rm == esp) {
412  byte sib = *(modrmp + 1);
413  int scale, index, base;
414  get_sib(sib, &scale, &index, &base);
415  int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2)
416  : *reinterpret_cast<int8_t*>(modrmp + 2);
417  if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
418  AppendToBuffer("[%s%s0x%x]",
419  (this->*register_name)(rm),
420  disp < 0 ? "-" : "+",
421  disp < 0 ? -disp : disp);
422  } else {
423  AppendToBuffer("[%s+%s*%d%s0x%x]",
424  (this->*register_name)(base),
425  (this->*register_name)(index),
426  1 << scale,
427  disp < 0 ? "-" : "+",
428  disp < 0 ? -disp : disp);
429  }
430  return mod == 2 ? 6 : 3;
431  } else {
432  // No sib.
433  int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1)
434  : *reinterpret_cast<int8_t*>(modrmp + 1);
435  AppendToBuffer("[%s%s0x%x]",
436  (this->*register_name)(rm),
437  disp < 0 ? "-" : "+",
438  disp < 0 ? -disp : disp);
439  return mod == 2 ? 5 : 2;
440  }
441  break;
442  case 3:
443  AppendToBuffer("%s", (this->*register_name)(rm));
444  return 1;
445  default:
446  UnimplementedInstruction();
447  return 1;
448  }
449  UNREACHABLE();
450 }
451 
452 
453 int DisassemblerX87::PrintRightOperand(byte* modrmp) {
454  return PrintRightOperandHelper(modrmp, &DisassemblerX87::NameOfCPURegister);
455 }
456 
457 
458 int DisassemblerX87::PrintRightByteOperand(byte* modrmp) {
459  return PrintRightOperandHelper(modrmp,
460  &DisassemblerX87::NameOfByteCPURegister);
461 }
462 
463 
464 int DisassemblerX87::PrintRightXMMOperand(byte* modrmp) {
465  return PrintRightOperandHelper(modrmp,
466  &DisassemblerX87::NameOfXMMRegister);
467 }
468 
469 
470 // Returns number of bytes used including the current *data.
471 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
472 int DisassemblerX87::PrintOperands(const char* mnem,
473  OperandOrder op_order,
474  byte* data) {
475  byte modrm = *data;
476  int mod, regop, rm;
477  get_modrm(modrm, &mod, &regop, &rm);
478  int advance = 0;
479  switch (op_order) {
480  case REG_OPER_OP_ORDER: {
481  AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
482  advance = PrintRightOperand(data);
483  break;
484  }
485  case OPER_REG_OP_ORDER: {
486  AppendToBuffer("%s ", mnem);
487  advance = PrintRightOperand(data);
488  AppendToBuffer(",%s", NameOfCPURegister(regop));
489  break;
490  }
491  default:
492  UNREACHABLE();
493  break;
494  }
495  return advance;
496 }
497 
498 
499 // Returns number of bytes used by machine instruction, including *data byte.
500 // Writes immediate instructions to 'tmp_buffer_'.
501 int DisassemblerX87::PrintImmediateOp(byte* data) {
502  bool sign_extension_bit = (*data & 0x02) != 0;
503  byte modrm = *(data+1);
504  int mod, regop, rm;
505  get_modrm(modrm, &mod, &regop, &rm);
506  const char* mnem = "Imm???";
507  switch (regop) {
508  case 0: mnem = "add"; break;
509  case 1: mnem = "or"; break;
510  case 2: mnem = "adc"; break;
511  case 4: mnem = "and"; break;
512  case 5: mnem = "sub"; break;
513  case 6: mnem = "xor"; break;
514  case 7: mnem = "cmp"; break;
515  default: UnimplementedInstruction();
516  }
517  AppendToBuffer("%s ", mnem);
518  int count = PrintRightOperand(data+1);
519  if (sign_extension_bit) {
520  AppendToBuffer(",0x%x", *(data + 1 + count));
521  return 1 + count + 1 /*int8*/;
522  } else {
523  AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
524  return 1 + count + 4 /*int32_t*/;
525  }
526 }
527 
528 
529 // Returns number of bytes used, including *data.
530 int DisassemblerX87::F7Instruction(byte* data) {
531  DCHECK_EQ(0xF7, *data);
532  byte modrm = *++data;
533  int mod, regop, rm;
534  get_modrm(modrm, &mod, &regop, &rm);
535  const char* mnem = NULL;
536  switch (regop) {
537  case 0:
538  mnem = "test";
539  break;
540  case 2:
541  mnem = "not";
542  break;
543  case 3:
544  mnem = "neg";
545  break;
546  case 4:
547  mnem = "mul";
548  break;
549  case 5:
550  mnem = "imul";
551  break;
552  case 6:
553  mnem = "div";
554  break;
555  case 7:
556  mnem = "idiv";
557  break;
558  default:
559  UnimplementedInstruction();
560  }
561  AppendToBuffer("%s ", mnem);
562  int count = PrintRightOperand(data);
563  if (regop == 0) {
564  AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + count));
565  count += 4;
566  }
567  return 1 + count;
568 }
569 
570 
571 int DisassemblerX87::D1D3C1Instruction(byte* data) {
572  byte op = *data;
573  DCHECK(op == 0xD1 || op == 0xD3 || op == 0xC1);
574  byte modrm = *++data;
575  int mod, regop, rm;
576  get_modrm(modrm, &mod, &regop, &rm);
577  int imm8 = -1;
578  const char* mnem = NULL;
579  switch (regop) {
580  case kROL:
581  mnem = "rol";
582  break;
583  case kROR:
584  mnem = "ror";
585  break;
586  case kRCL:
587  mnem = "rcl";
588  break;
589  case kRCR:
590  mnem = "rcr";
591  break;
592  case kSHL:
593  mnem = "shl";
594  break;
595  case KSHR:
596  mnem = "shr";
597  break;
598  case kSAR:
599  mnem = "sar";
600  break;
601  default:
602  UnimplementedInstruction();
603  }
604  AppendToBuffer("%s ", mnem);
605  int count = PrintRightOperand(data);
606  if (op == 0xD1) {
607  imm8 = 1;
608  } else if (op == 0xC1) {
609  imm8 = *(data + 1);
610  count++;
611  } else if (op == 0xD3) {
612  // Shift/rotate by cl.
613  }
614  if (imm8 >= 0) {
615  AppendToBuffer(",%d", imm8);
616  } else {
617  AppendToBuffer(",cl");
618  }
619  return 1 + count;
620 }
621 
622 
623 // Returns number of bytes used, including *data.
624 int DisassemblerX87::JumpShort(byte* data) {
625  DCHECK_EQ(0xEB, *data);
626  byte b = *(data+1);
627  byte* dest = data + static_cast<int8_t>(b) + 2;
628  AppendToBuffer("jmp %s", NameOfAddress(dest));
629  return 2;
630 }
631 
632 
633 // Returns number of bytes used, including *data.
634 int DisassemblerX87::JumpConditional(byte* data, const char* comment) {
635  DCHECK_EQ(0x0F, *data);
636  byte cond = *(data+1) & 0x0F;
637  byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
638  const char* mnem = jump_conditional_mnem[cond];
639  AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
640  if (comment != NULL) {
641  AppendToBuffer(", %s", comment);
642  }
643  return 6; // includes 0x0F
644 }
645 
646 
647 // Returns number of bytes used, including *data.
648 int DisassemblerX87::JumpConditionalShort(byte* data, const char* comment) {
649  byte cond = *data & 0x0F;
650  byte b = *(data+1);
651  byte* dest = data + static_cast<int8_t>(b) + 2;
652  const char* mnem = jump_conditional_mnem[cond];
653  AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
654  if (comment != NULL) {
655  AppendToBuffer(", %s", comment);
656  }
657  return 2;
658 }
659 
660 
661 // Returns number of bytes used, including *data.
662 int DisassemblerX87::SetCC(byte* data) {
663  DCHECK_EQ(0x0F, *data);
664  byte cond = *(data+1) & 0x0F;
665  const char* mnem = set_conditional_mnem[cond];
666  AppendToBuffer("%s ", mnem);
667  PrintRightByteOperand(data+2);
668  return 3; // Includes 0x0F.
669 }
670 
671 
672 // Returns number of bytes used, including *data.
673 int DisassemblerX87::CMov(byte* data) {
674  DCHECK_EQ(0x0F, *data);
675  byte cond = *(data + 1) & 0x0F;
676  const char* mnem = conditional_move_mnem[cond];
677  int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
678  return 2 + op_size; // includes 0x0F
679 }
680 
681 
682 // Returns number of bytes used, including *data.
683 int DisassemblerX87::FPUInstruction(byte* data) {
684  byte escape_opcode = *data;
685  DCHECK_EQ(0xD8, escape_opcode & 0xF8);
686  byte modrm_byte = *(data+1);
687 
688  if (modrm_byte >= 0xC0) {
689  return RegisterFPUInstruction(escape_opcode, modrm_byte);
690  } else {
691  return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
692  }
693 }
694 
695 int DisassemblerX87::MemoryFPUInstruction(int escape_opcode,
696  int modrm_byte,
697  byte* modrm_start) {
698  const char* mnem = "?";
699  int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
700  switch (escape_opcode) {
701  case 0xD9: switch (regop) {
702  case 0: mnem = "fld_s"; break;
703  case 2: mnem = "fst_s"; break;
704  case 3: mnem = "fstp_s"; break;
705  case 5:
706  mnem = "fldcw";
707  break;
708  case 7:
709  mnem = "fnstcw";
710  break;
711  default: UnimplementedInstruction();
712  }
713  break;
714 
715  case 0xDB: switch (regop) {
716  case 0: mnem = "fild_s"; break;
717  case 1: mnem = "fisttp_s"; break;
718  case 2: mnem = "fist_s"; break;
719  case 3: mnem = "fistp_s"; break;
720  default: UnimplementedInstruction();
721  }
722  break;
723 
724  case 0xDC:
725  switch (regop) {
726  case 0:
727  mnem = "fadd_d";
728  break;
729  default:
730  UnimplementedInstruction();
731  }
732  break;
733 
734  case 0xDD: switch (regop) {
735  case 0: mnem = "fld_d"; break;
736  case 1: mnem = "fisttp_d"; break;
737  case 2: mnem = "fst_d"; break;
738  case 3: mnem = "fstp_d"; break;
739  case 4:
740  mnem = "frstor";
741  break;
742  case 6:
743  mnem = "fnsave";
744  break;
745  default: UnimplementedInstruction();
746  }
747  break;
748 
749  case 0xDF: switch (regop) {
750  case 5: mnem = "fild_d"; break;
751  case 7: mnem = "fistp_d"; break;
752  default: UnimplementedInstruction();
753  }
754  break;
755 
756  default: UnimplementedInstruction();
757  }
758  AppendToBuffer("%s ", mnem);
759  int count = PrintRightOperand(modrm_start);
760  return count + 1;
761 }
762 
763 int DisassemblerX87::RegisterFPUInstruction(int escape_opcode,
764  byte modrm_byte) {
765  bool has_register = false; // Is the FPU register encoded in modrm_byte?
766  const char* mnem = "?";
767 
768  switch (escape_opcode) {
769  case 0xD8:
770  has_register = true;
771  switch (modrm_byte & 0xF8) {
772  case 0xC0: mnem = "fadd_i"; break;
773  case 0xE0: mnem = "fsub_i"; break;
774  case 0xC8: mnem = "fmul_i"; break;
775  case 0xF0: mnem = "fdiv_i"; break;
776  default: UnimplementedInstruction();
777  }
778  break;
779 
780  case 0xD9:
781  switch (modrm_byte & 0xF8) {
782  case 0xC0:
783  mnem = "fld";
784  has_register = true;
785  break;
786  case 0xC8:
787  mnem = "fxch";
788  has_register = true;
789  break;
790  default:
791  switch (modrm_byte) {
792  case 0xE0: mnem = "fchs"; break;
793  case 0xE1: mnem = "fabs"; break;
794  case 0xE4: mnem = "ftst"; break;
795  case 0xE8: mnem = "fld1"; break;
796  case 0xEB: mnem = "fldpi"; break;
797  case 0xED: mnem = "fldln2"; break;
798  case 0xEE: mnem = "fldz"; break;
799  case 0xF0: mnem = "f2xm1"; break;
800  case 0xF1: mnem = "fyl2x"; break;
801  case 0xF4: mnem = "fxtract"; break;
802  case 0xF5: mnem = "fprem1"; break;
803  case 0xF7: mnem = "fincstp"; break;
804  case 0xF8: mnem = "fprem"; break;
805  case 0xFC: mnem = "frndint"; break;
806  case 0xFD: mnem = "fscale"; break;
807  case 0xFE: mnem = "fsin"; break;
808  case 0xFF: mnem = "fcos"; break;
809  default: UnimplementedInstruction();
810  }
811  }
812  break;
813 
814  case 0xDA:
815  if (modrm_byte == 0xE9) {
816  mnem = "fucompp";
817  } else {
818  UnimplementedInstruction();
819  }
820  break;
821 
822  case 0xDB:
823  if ((modrm_byte & 0xF8) == 0xE8) {
824  mnem = "fucomi";
825  has_register = true;
826  } else if (modrm_byte == 0xE2) {
827  mnem = "fclex";
828  } else if (modrm_byte == 0xE3) {
829  mnem = "fninit";
830  } else {
831  UnimplementedInstruction();
832  }
833  break;
834 
835  case 0xDC:
836  has_register = true;
837  switch (modrm_byte & 0xF8) {
838  case 0xC0: mnem = "fadd"; break;
839  case 0xE8: mnem = "fsub"; break;
840  case 0xC8: mnem = "fmul"; break;
841  case 0xF8: mnem = "fdiv"; break;
842  default: UnimplementedInstruction();
843  }
844  break;
845 
846  case 0xDD:
847  has_register = true;
848  switch (modrm_byte & 0xF8) {
849  case 0xC0: mnem = "ffree"; break;
850  case 0xD0: mnem = "fst"; break;
851  case 0xD8: mnem = "fstp"; break;
852  default: UnimplementedInstruction();
853  }
854  break;
855 
856  case 0xDE:
857  if (modrm_byte == 0xD9) {
858  mnem = "fcompp";
859  } else {
860  has_register = true;
861  switch (modrm_byte & 0xF8) {
862  case 0xC0: mnem = "faddp"; break;
863  case 0xE8: mnem = "fsubp"; break;
864  case 0xC8: mnem = "fmulp"; break;
865  case 0xF8: mnem = "fdivp"; break;
866  default: UnimplementedInstruction();
867  }
868  }
869  break;
870 
871  case 0xDF:
872  if (modrm_byte == 0xE0) {
873  mnem = "fnstsw_ax";
874  } else if ((modrm_byte & 0xF8) == 0xE8) {
875  mnem = "fucomip";
876  has_register = true;
877  }
878  break;
879 
880  default: UnimplementedInstruction();
881  }
882 
883  if (has_register) {
884  AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
885  } else {
886  AppendToBuffer("%s", mnem);
887  }
888  return 2;
889 }
890 
891 
892 // Mnemonics for instructions 0xF0 byte.
893 // Returns NULL if the instruction is not handled here.
894 static const char* F0Mnem(byte f0byte) {
895  switch (f0byte) {
896  case 0x18: return "prefetch";
897  case 0xA2: return "cpuid";
898  case 0xBE: return "movsx_b";
899  case 0xBF: return "movsx_w";
900  case 0xB6: return "movzx_b";
901  case 0xB7: return "movzx_w";
902  case 0xAF: return "imul";
903  case 0xA5: return "shld";
904  case 0xAD: return "shrd";
905  case 0xAC: return "shrd"; // 3-operand version.
906  case 0xAB: return "bts";
907  case 0xBD: return "bsr";
908  default: return NULL;
909  }
910 }
911 
912 
913 // Disassembled instruction '*instr' and writes it into 'out_buffer'.
914 int DisassemblerX87::InstructionDecode(v8::internal::Vector<char> out_buffer,
915  byte* instr) {
916  tmp_buffer_pos_ = 0; // starting to write as position 0
917  byte* data = instr;
918  // Check for hints.
919  const char* branch_hint = NULL;
920  // We use these two prefixes only with branch prediction
921  if (*data == 0x3E /*ds*/) {
922  branch_hint = "predicted taken";
923  data++;
924  } else if (*data == 0x2E /*cs*/) {
925  branch_hint = "predicted not taken";
926  data++;
927  }
928  bool processed = true; // Will be set to false if the current instruction
929  // is not in 'instructions' table.
930  const InstructionDesc& idesc = instruction_table_->Get(*data);
931  switch (idesc.type) {
932  case ZERO_OPERANDS_INSTR:
933  AppendToBuffer(idesc.mnem);
934  data++;
935  break;
936 
937  case TWO_OPERANDS_INSTR:
938  data++;
939  data += PrintOperands(idesc.mnem, idesc.op_order_, data);
940  break;
941 
942  case JUMP_CONDITIONAL_SHORT_INSTR:
943  data += JumpConditionalShort(data, branch_hint);
944  break;
945 
946  case REGISTER_INSTR:
947  AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
948  data++;
949  break;
950 
951  case MOVE_REG_INSTR: {
952  byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
953  AppendToBuffer("mov %s,%s",
954  NameOfCPURegister(*data & 0x07),
955  NameOfAddress(addr));
956  data += 5;
957  break;
958  }
959 
960  case CALL_JUMP_INSTR: {
961  byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5;
962  AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
963  data += 5;
964  break;
965  }
966 
967  case SHORT_IMMEDIATE_INSTR: {
968  byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
969  AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
970  data += 5;
971  break;
972  }
973 
974  case BYTE_IMMEDIATE_INSTR: {
975  AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
976  data += 2;
977  break;
978  }
979 
980  case NO_INSTR:
981  processed = false;
982  break;
983 
984  default:
985  UNIMPLEMENTED(); // This type is not implemented.
986  }
987  //----------------------------
988  if (!processed) {
989  switch (*data) {
990  case 0xC2:
991  AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
992  data += 3;
993  break;
994 
995  case 0x6B: {
996  data++;
997  data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
998  AppendToBuffer(",%d", *data);
999  data++;
1000  } break;
1001 
1002  case 0x69: {
1003  data++;
1004  data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
1005  AppendToBuffer(",%d", *reinterpret_cast<int32_t*>(data));
1006  data += 4;
1007  }
1008  break;
1009 
1010  case 0xF6:
1011  { data++;
1012  int mod, regop, rm;
1013  get_modrm(*data, &mod, &regop, &rm);
1014  if (regop == eax) {
1015  AppendToBuffer("test_b ");
1016  data += PrintRightByteOperand(data);
1017  int32_t imm = *data;
1018  AppendToBuffer(",0x%x", imm);
1019  data++;
1020  } else {
1021  UnimplementedInstruction();
1022  }
1023  }
1024  break;
1025 
1026  case 0x81: // fall through
1027  case 0x83: // 0x81 with sign extension bit set
1028  data += PrintImmediateOp(data);
1029  break;
1030 
1031  case 0x0F:
1032  { byte f0byte = data[1];
1033  const char* f0mnem = F0Mnem(f0byte);
1034  if (f0byte == 0x18) {
1035  data += 2;
1036  int mod, regop, rm;
1037  get_modrm(*data, &mod, &regop, &rm);
1038  const char* suffix[] = {"nta", "1", "2", "3"};
1039  AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1040  data += PrintRightOperand(data);
1041  } else if (f0byte == 0x1F && data[2] == 0) {
1042  AppendToBuffer("nop"); // 3 byte nop.
1043  data += 3;
1044  } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1045  AppendToBuffer("nop"); // 4 byte nop.
1046  data += 4;
1047  } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1048  data[4] == 0) {
1049  AppendToBuffer("nop"); // 5 byte nop.
1050  data += 5;
1051  } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1052  data[4] == 0 && data[5] == 0 && data[6] == 0) {
1053  AppendToBuffer("nop"); // 7 byte nop.
1054  data += 7;
1055  } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1056  data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1057  data[7] == 0) {
1058  AppendToBuffer("nop"); // 8 byte nop.
1059  data += 8;
1060  } else if (f0byte == 0xA2 || f0byte == 0x31) {
1061  AppendToBuffer("%s", f0mnem);
1062  data += 2;
1063  } else if (f0byte == 0x28) {
1064  data += 2;
1065  int mod, regop, rm;
1066  get_modrm(*data, &mod, &regop, &rm);
1067  AppendToBuffer("movaps %s,%s",
1068  NameOfXMMRegister(regop),
1069  NameOfXMMRegister(rm));
1070  data++;
1071  } else if (f0byte >= 0x53 && f0byte <= 0x5F) {
1072  const char* const pseudo_op[] = {
1073  "rcpps",
1074  "andps",
1075  "andnps",
1076  "orps",
1077  "xorps",
1078  "addps",
1079  "mulps",
1080  "cvtps2pd",
1081  "cvtdq2ps",
1082  "subps",
1083  "minps",
1084  "divps",
1085  "maxps",
1086  };
1087 
1088  data += 2;
1089  int mod, regop, rm;
1090  get_modrm(*data, &mod, &regop, &rm);
1091  AppendToBuffer("%s %s,",
1092  pseudo_op[f0byte - 0x53],
1093  NameOfXMMRegister(regop));
1094  data += PrintRightXMMOperand(data);
1095  } else if (f0byte == 0x50) {
1096  data += 2;
1097  int mod, regop, rm;
1098  get_modrm(*data, &mod, &regop, &rm);
1099  AppendToBuffer("movmskps %s,%s",
1100  NameOfCPURegister(regop),
1101  NameOfXMMRegister(rm));
1102  data++;
1103  } else if (f0byte== 0xC6) {
1104  // shufps xmm, xmm/m128, imm8
1105  data += 2;
1106  int mod, regop, rm;
1107  get_modrm(*data, &mod, &regop, &rm);
1108  int8_t imm8 = static_cast<int8_t>(data[1]);
1109  AppendToBuffer("shufps %s,%s,%d",
1110  NameOfXMMRegister(rm),
1111  NameOfXMMRegister(regop),
1112  static_cast<int>(imm8));
1113  data += 2;
1114  } else if ((f0byte & 0xF0) == 0x80) {
1115  data += JumpConditional(data, branch_hint);
1116  } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1117  f0byte == 0xB7 || f0byte == 0xAF) {
1118  data += 2;
1119  data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1120  } else if ((f0byte & 0xF0) == 0x90) {
1121  data += SetCC(data);
1122  } else if ((f0byte & 0xF0) == 0x40) {
1123  data += CMov(data);
1124  } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1125  // shrd, shld, bts
1126  data += 2;
1127  AppendToBuffer("%s ", f0mnem);
1128  int mod, regop, rm;
1129  get_modrm(*data, &mod, &regop, &rm);
1130  data += PrintRightOperand(data);
1131  if (f0byte == 0xAB) {
1132  AppendToBuffer(",%s", NameOfCPURegister(regop));
1133  } else {
1134  AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1135  }
1136  } else if (f0byte == 0xBD) {
1137  data += 2;
1138  int mod, regop, rm;
1139  get_modrm(*data, &mod, &regop, &rm);
1140  AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1141  data += PrintRightOperand(data);
1142  } else {
1143  UnimplementedInstruction();
1144  }
1145  }
1146  break;
1147 
1148  case 0x8F:
1149  { data++;
1150  int mod, regop, rm;
1151  get_modrm(*data, &mod, &regop, &rm);
1152  if (regop == eax) {
1153  AppendToBuffer("pop ");
1154  data += PrintRightOperand(data);
1155  }
1156  }
1157  break;
1158 
1159  case 0xFF:
1160  { data++;
1161  int mod, regop, rm;
1162  get_modrm(*data, &mod, &regop, &rm);
1163  const char* mnem = NULL;
1164  switch (regop) {
1165  case esi: mnem = "push"; break;
1166  case eax: mnem = "inc"; break;
1167  case ecx: mnem = "dec"; break;
1168  case edx: mnem = "call"; break;
1169  case esp: mnem = "jmp"; break;
1170  default: mnem = "???";
1171  }
1172  AppendToBuffer("%s ", mnem);
1173  data += PrintRightOperand(data);
1174  }
1175  break;
1176 
1177  case 0xC7: // imm32, fall through
1178  case 0xC6: // imm8
1179  { bool is_byte = *data == 0xC6;
1180  data++;
1181  if (is_byte) {
1182  AppendToBuffer("%s ", "mov_b");
1183  data += PrintRightByteOperand(data);
1184  int32_t imm = *data;
1185  AppendToBuffer(",0x%x", imm);
1186  data++;
1187  } else {
1188  AppendToBuffer("%s ", "mov");
1189  data += PrintRightOperand(data);
1190  int32_t imm = *reinterpret_cast<int32_t*>(data);
1191  AppendToBuffer(",0x%x", imm);
1192  data += 4;
1193  }
1194  }
1195  break;
1196 
1197  case 0x80:
1198  { data++;
1199  int mod, regop, rm;
1200  get_modrm(*data, &mod, &regop, &rm);
1201  const char* mnem = NULL;
1202  switch (regop) {
1203  case 5: mnem = "subb"; break;
1204  case 7: mnem = "cmpb"; break;
1205  default: UnimplementedInstruction();
1206  }
1207  AppendToBuffer("%s ", mnem);
1208  data += PrintRightByteOperand(data);
1209  int32_t imm = *data;
1210  AppendToBuffer(",0x%x", imm);
1211  data++;
1212  }
1213  break;
1214 
1215  case 0x88: // 8bit, fall through
1216  case 0x89: // 32bit
1217  { bool is_byte = *data == 0x88;
1218  int mod, regop, rm;
1219  data++;
1220  get_modrm(*data, &mod, &regop, &rm);
1221  if (is_byte) {
1222  AppendToBuffer("%s ", "mov_b");
1223  data += PrintRightByteOperand(data);
1224  AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1225  } else {
1226  AppendToBuffer("%s ", "mov");
1227  data += PrintRightOperand(data);
1228  AppendToBuffer(",%s", NameOfCPURegister(regop));
1229  }
1230  }
1231  break;
1232 
1233  case 0x66: // prefix
1234  while (*data == 0x66) data++;
1235  if (*data == 0xf && data[1] == 0x1f) {
1236  AppendToBuffer("nop"); // 0x66 prefix
1237  } else if (*data == 0x90) {
1238  AppendToBuffer("nop"); // 0x66 prefix
1239  } else if (*data == 0x8B) {
1240  data++;
1241  data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1242  } else if (*data == 0x89) {
1243  data++;
1244  int mod, regop, rm;
1245  get_modrm(*data, &mod, &regop, &rm);
1246  AppendToBuffer("mov_w ");
1247  data += PrintRightOperand(data);
1248  AppendToBuffer(",%s", NameOfCPURegister(regop));
1249  } else if (*data == 0xC7) {
1250  data++;
1251  AppendToBuffer("%s ", "mov_w");
1252  data += PrintRightOperand(data);
1253  int imm = *reinterpret_cast<int16_t*>(data);
1254  AppendToBuffer(",0x%x", imm);
1255  data += 2;
1256  } else if (*data == 0x0F) {
1257  data++;
1258  if (*data == 0x38) {
1259  data++;
1260  if (*data == 0x17) {
1261  data++;
1262  int mod, regop, rm;
1263  get_modrm(*data, &mod, &regop, &rm);
1264  AppendToBuffer("ptest %s,%s",
1265  NameOfXMMRegister(regop),
1266  NameOfXMMRegister(rm));
1267  data++;
1268  } else if (*data == 0x2A) {
1269  // movntdqa
1270  data++;
1271  int mod, regop, rm;
1272  get_modrm(*data, &mod, &regop, &rm);
1273  AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop));
1274  data += PrintRightOperand(data);
1275  } else {
1276  UnimplementedInstruction();
1277  }
1278  } else if (*data == 0x3A) {
1279  data++;
1280  if (*data == 0x0B) {
1281  data++;
1282  int mod, regop, rm;
1283  get_modrm(*data, &mod, &regop, &rm);
1284  int8_t imm8 = static_cast<int8_t>(data[1]);
1285  AppendToBuffer("roundsd %s,%s,%d",
1286  NameOfXMMRegister(regop),
1287  NameOfXMMRegister(rm),
1288  static_cast<int>(imm8));
1289  data += 2;
1290  } else if (*data == 0x16) {
1291  data++;
1292  int mod, regop, rm;
1293  get_modrm(*data, &mod, &regop, &rm);
1294  int8_t imm8 = static_cast<int8_t>(data[1]);
1295  AppendToBuffer("pextrd %s,%s,%d",
1296  NameOfCPURegister(regop),
1297  NameOfXMMRegister(rm),
1298  static_cast<int>(imm8));
1299  data += 2;
1300  } else if (*data == 0x17) {
1301  data++;
1302  int mod, regop, rm;
1303  get_modrm(*data, &mod, &regop, &rm);
1304  int8_t imm8 = static_cast<int8_t>(data[1]);
1305  AppendToBuffer("extractps %s,%s,%d",
1306  NameOfCPURegister(rm),
1307  NameOfXMMRegister(regop),
1308  static_cast<int>(imm8));
1309  data += 2;
1310  } else if (*data == 0x22) {
1311  data++;
1312  int mod, regop, rm;
1313  get_modrm(*data, &mod, &regop, &rm);
1314  int8_t imm8 = static_cast<int8_t>(data[1]);
1315  AppendToBuffer("pinsrd %s,%s,%d",
1316  NameOfXMMRegister(regop),
1317  NameOfCPURegister(rm),
1318  static_cast<int>(imm8));
1319  data += 2;
1320  } else {
1321  UnimplementedInstruction();
1322  }
1323  } else if (*data == 0x2E || *data == 0x2F) {
1324  const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
1325  data++;
1326  int mod, regop, rm;
1327  get_modrm(*data, &mod, &regop, &rm);
1328  if (mod == 0x3) {
1329  AppendToBuffer("%s %s,%s", mnem,
1330  NameOfXMMRegister(regop),
1331  NameOfXMMRegister(rm));
1332  data++;
1333  } else {
1334  AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1335  data += PrintRightOperand(data);
1336  }
1337  } else if (*data == 0x50) {
1338  data++;
1339  int mod, regop, rm;
1340  get_modrm(*data, &mod, &regop, &rm);
1341  AppendToBuffer("movmskpd %s,%s",
1342  NameOfCPURegister(regop),
1343  NameOfXMMRegister(rm));
1344  data++;
1345  } else if (*data == 0x54) {
1346  data++;
1347  int mod, regop, rm;
1348  get_modrm(*data, &mod, &regop, &rm);
1349  AppendToBuffer("andpd %s,%s",
1350  NameOfXMMRegister(regop),
1351  NameOfXMMRegister(rm));
1352  data++;
1353  } else if (*data == 0x56) {
1354  data++;
1355  int mod, regop, rm;
1356  get_modrm(*data, &mod, &regop, &rm);
1357  AppendToBuffer("orpd %s,%s",
1358  NameOfXMMRegister(regop),
1359  NameOfXMMRegister(rm));
1360  data++;
1361  } else if (*data == 0x57) {
1362  data++;
1363  int mod, regop, rm;
1364  get_modrm(*data, &mod, &regop, &rm);
1365  AppendToBuffer("xorpd %s,%s",
1366  NameOfXMMRegister(regop),
1367  NameOfXMMRegister(rm));
1368  data++;
1369  } else if (*data == 0x6E) {
1370  data++;
1371  int mod, regop, rm;
1372  get_modrm(*data, &mod, &regop, &rm);
1373  AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1374  data += PrintRightOperand(data);
1375  } else if (*data == 0x6F) {
1376  data++;
1377  int mod, regop, rm;
1378  get_modrm(*data, &mod, &regop, &rm);
1379  AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
1380  data += PrintRightXMMOperand(data);
1381  } else if (*data == 0x70) {
1382  data++;
1383  int mod, regop, rm;
1384  get_modrm(*data, &mod, &regop, &rm);
1385  int8_t imm8 = static_cast<int8_t>(data[1]);
1386  AppendToBuffer("pshufd %s,%s,%d",
1387  NameOfXMMRegister(regop),
1388  NameOfXMMRegister(rm),
1389  static_cast<int>(imm8));
1390  data += 2;
1391  } else if (*data == 0x76) {
1392  data++;
1393  int mod, regop, rm;
1394  get_modrm(*data, &mod, &regop, &rm);
1395  AppendToBuffer("pcmpeqd %s,%s",
1396  NameOfXMMRegister(regop),
1397  NameOfXMMRegister(rm));
1398  data++;
1399  } else if (*data == 0x90) {
1400  data++;
1401  AppendToBuffer("nop"); // 2 byte nop.
1402  } else if (*data == 0xF3) {
1403  data++;
1404  int mod, regop, rm;
1405  get_modrm(*data, &mod, &regop, &rm);
1406  AppendToBuffer("psllq %s,%s",
1407  NameOfXMMRegister(regop),
1408  NameOfXMMRegister(rm));
1409  data++;
1410  } else if (*data == 0x73) {
1411  data++;
1412  int mod, regop, rm;
1413  get_modrm(*data, &mod, &regop, &rm);
1414  int8_t imm8 = static_cast<int8_t>(data[1]);
1415  DCHECK(regop == esi || regop == edx);
1416  AppendToBuffer("%s %s,%d",
1417  (regop == esi) ? "psllq" : "psrlq",
1418  NameOfXMMRegister(rm),
1419  static_cast<int>(imm8));
1420  data += 2;
1421  } else if (*data == 0xD3) {
1422  data++;
1423  int mod, regop, rm;
1424  get_modrm(*data, &mod, &regop, &rm);
1425  AppendToBuffer("psrlq %s,%s",
1426  NameOfXMMRegister(regop),
1427  NameOfXMMRegister(rm));
1428  data++;
1429  } else if (*data == 0x7F) {
1430  AppendToBuffer("movdqa ");
1431  data++;
1432  int mod, regop, rm;
1433  get_modrm(*data, &mod, &regop, &rm);
1434  data += PrintRightXMMOperand(data);
1435  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1436  } else if (*data == 0x7E) {
1437  data++;
1438  int mod, regop, rm;
1439  get_modrm(*data, &mod, &regop, &rm);
1440  AppendToBuffer("movd ");
1441  data += PrintRightOperand(data);
1442  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1443  } else if (*data == 0xDB) {
1444  data++;
1445  int mod, regop, rm;
1446  get_modrm(*data, &mod, &regop, &rm);
1447  AppendToBuffer("pand %s,%s",
1448  NameOfXMMRegister(regop),
1449  NameOfXMMRegister(rm));
1450  data++;
1451  } else if (*data == 0xE7) {
1452  data++;
1453  int mod, regop, rm;
1454  get_modrm(*data, &mod, &regop, &rm);
1455  if (mod == 3) {
1456  AppendToBuffer("movntdq ");
1457  data += PrintRightOperand(data);
1458  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1459  } else {
1460  UnimplementedInstruction();
1461  }
1462  } else if (*data == 0xEF) {
1463  data++;
1464  int mod, regop, rm;
1465  get_modrm(*data, &mod, &regop, &rm);
1466  AppendToBuffer("pxor %s,%s",
1467  NameOfXMMRegister(regop),
1468  NameOfXMMRegister(rm));
1469  data++;
1470  } else if (*data == 0xEB) {
1471  data++;
1472  int mod, regop, rm;
1473  get_modrm(*data, &mod, &regop, &rm);
1474  AppendToBuffer("por %s,%s",
1475  NameOfXMMRegister(regop),
1476  NameOfXMMRegister(rm));
1477  data++;
1478  } else {
1479  UnimplementedInstruction();
1480  }
1481  } else {
1482  UnimplementedInstruction();
1483  }
1484  break;
1485 
1486  case 0xFE:
1487  { data++;
1488  int mod, regop, rm;
1489  get_modrm(*data, &mod, &regop, &rm);
1490  if (regop == ecx) {
1491  AppendToBuffer("dec_b ");
1492  data += PrintRightOperand(data);
1493  } else {
1494  UnimplementedInstruction();
1495  }
1496  }
1497  break;
1498 
1499  case 0x68:
1500  AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1501  data += 5;
1502  break;
1503 
1504  case 0x6A:
1505  AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1506  data += 2;
1507  break;
1508 
1509  case 0xA8:
1510  AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1511  data += 2;
1512  break;
1513 
1514  case 0xA9:
1515  AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1516  data += 5;
1517  break;
1518 
1519  case 0xD1: // fall through
1520  case 0xD3: // fall through
1521  case 0xC1:
1522  data += D1D3C1Instruction(data);
1523  break;
1524 
1525  case 0xD8: // fall through
1526  case 0xD9: // fall through
1527  case 0xDA: // fall through
1528  case 0xDB: // fall through
1529  case 0xDC: // fall through
1530  case 0xDD: // fall through
1531  case 0xDE: // fall through
1532  case 0xDF:
1533  data += FPUInstruction(data);
1534  break;
1535 
1536  case 0xEB:
1537  data += JumpShort(data);
1538  break;
1539 
1540  case 0xF2:
1541  if (*(data+1) == 0x0F) {
1542  byte b2 = *(data+2);
1543  if (b2 == 0x11) {
1544  AppendToBuffer("movsd ");
1545  data += 3;
1546  int mod, regop, rm;
1547  get_modrm(*data, &mod, &regop, &rm);
1548  data += PrintRightXMMOperand(data);
1549  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1550  } else if (b2 == 0x10) {
1551  data += 3;
1552  int mod, regop, rm;
1553  get_modrm(*data, &mod, &regop, &rm);
1554  AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
1555  data += PrintRightXMMOperand(data);
1556  } else if (b2 == 0x5A) {
1557  data += 3;
1558  int mod, regop, rm;
1559  get_modrm(*data, &mod, &regop, &rm);
1560  AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
1561  data += PrintRightXMMOperand(data);
1562  } else {
1563  const char* mnem = "?";
1564  switch (b2) {
1565  case 0x2A: mnem = "cvtsi2sd"; break;
1566  case 0x2C: mnem = "cvttsd2si"; break;
1567  case 0x2D: mnem = "cvtsd2si"; break;
1568  case 0x51: mnem = "sqrtsd"; break;
1569  case 0x58: mnem = "addsd"; break;
1570  case 0x59: mnem = "mulsd"; break;
1571  case 0x5C: mnem = "subsd"; break;
1572  case 0x5E: mnem = "divsd"; break;
1573  }
1574  data += 3;
1575  int mod, regop, rm;
1576  get_modrm(*data, &mod, &regop, &rm);
1577  if (b2 == 0x2A) {
1578  AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1579  data += PrintRightOperand(data);
1580  } else if (b2 == 0x2C || b2 == 0x2D) {
1581  AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
1582  data += PrintRightXMMOperand(data);
1583  } else if (b2 == 0xC2) {
1584  // Intel manual 2A, Table 3-18.
1585  const char* const pseudo_op[] = {
1586  "cmpeqsd",
1587  "cmpltsd",
1588  "cmplesd",
1589  "cmpunordsd",
1590  "cmpneqsd",
1591  "cmpnltsd",
1592  "cmpnlesd",
1593  "cmpordsd"
1594  };
1595  AppendToBuffer("%s %s,%s",
1596  pseudo_op[data[1]],
1597  NameOfXMMRegister(regop),
1598  NameOfXMMRegister(rm));
1599  data += 2;
1600  } else {
1601  AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1602  data += PrintRightXMMOperand(data);
1603  }
1604  }
1605  } else {
1606  UnimplementedInstruction();
1607  }
1608  break;
1609 
1610  case 0xF3:
1611  if (*(data+1) == 0x0F) {
1612  byte b2 = *(data+2);
1613  if (b2 == 0x11) {
1614  AppendToBuffer("movss ");
1615  data += 3;
1616  int mod, regop, rm;
1617  get_modrm(*data, &mod, &regop, &rm);
1618  data += PrintRightXMMOperand(data);
1619  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1620  } else if (b2 == 0x10) {
1621  data += 3;
1622  int mod, regop, rm;
1623  get_modrm(*data, &mod, &regop, &rm);
1624  AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
1625  data += PrintRightXMMOperand(data);
1626  } else if (b2 == 0x2C) {
1627  data += 3;
1628  int mod, regop, rm;
1629  get_modrm(*data, &mod, &regop, &rm);
1630  AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
1631  data += PrintRightXMMOperand(data);
1632  } else if (b2 == 0x5A) {
1633  data += 3;
1634  int mod, regop, rm;
1635  get_modrm(*data, &mod, &regop, &rm);
1636  AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1637  data += PrintRightXMMOperand(data);
1638  } else if (b2 == 0x6F) {
1639  data += 3;
1640  int mod, regop, rm;
1641  get_modrm(*data, &mod, &regop, &rm);
1642  AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
1643  data += PrintRightXMMOperand(data);
1644  } else if (b2 == 0x7F) {
1645  AppendToBuffer("movdqu ");
1646  data += 3;
1647  int mod, regop, rm;
1648  get_modrm(*data, &mod, &regop, &rm);
1649  data += PrintRightXMMOperand(data);
1650  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1651  } else {
1652  UnimplementedInstruction();
1653  }
1654  } else if (*(data+1) == 0xA5) {
1655  data += 2;
1656  AppendToBuffer("rep_movs");
1657  } else if (*(data+1) == 0xAB) {
1658  data += 2;
1659  AppendToBuffer("rep_stos");
1660  } else {
1661  UnimplementedInstruction();
1662  }
1663  break;
1664 
1665  case 0xF7:
1666  data += F7Instruction(data);
1667  break;
1668 
1669  default:
1670  UnimplementedInstruction();
1671  }
1672  }
1673 
1674  if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1675  tmp_buffer_[tmp_buffer_pos_] = '\0';
1676  }
1677 
1678  int instr_len = data - instr;
1679  if (instr_len == 0) {
1680  printf("%02x", *data);
1681  }
1682  DCHECK(instr_len > 0); // Ensure progress.
1683 
1684  int outp = 0;
1685  // Instruction bytes.
1686  for (byte* bp = instr; bp < data; bp++) {
1687  outp += v8::internal::SNPrintF(out_buffer + outp, "%02x", *bp);
1688  }
1689  for (int i = 6 - instr_len; i >= 0; i--) {
1690  outp += v8::internal::SNPrintF(out_buffer + outp, " ");
1691  }
1692 
1693  outp += v8::internal::SNPrintF(out_buffer + outp, " %s", tmp_buffer_.start());
1694  return instr_len;
1695 } // NOLINT (function is too long)
1696 
1697 
1698 //------------------------------------------------------------------------------
1699 
1700 
1701 static const char* cpu_regs[8] = {
1702  "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
1703 };
1704 
1705 
1706 static const char* byte_cpu_regs[8] = {
1707  "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
1708 };
1709 
1710 
1711 static const char* xmm_regs[8] = {
1712  "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
1713 };
1714 
1715 
1716 const char* NameConverter::NameOfAddress(byte* addr) const {
1717  v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
1718  return tmp_buffer_.start();
1719 }
1720 
1721 
1722 const char* NameConverter::NameOfConstant(byte* addr) const {
1723  return NameOfAddress(addr);
1724 }
1725 
1726 
1727 const char* NameConverter::NameOfCPURegister(int reg) const {
1728  if (0 <= reg && reg < 8) return cpu_regs[reg];
1729  return "noreg";
1730 }
1731 
1732 
1733 const char* NameConverter::NameOfByteCPURegister(int reg) const {
1734  if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
1735  return "noreg";
1736 }
1737 
1738 
1739 const char* NameConverter::NameOfXMMRegister(int reg) const {
1740  if (0 <= reg && reg < 8) return xmm_regs[reg];
1741  return "noxmmreg";
1742 }
1743 
1744 
1745 const char* NameConverter::NameInCode(byte* addr) const {
1746  // X87 does not embed debug strings at the moment.
1747  UNREACHABLE();
1748  return "";
1749 }
1750 
1751 
1752 //------------------------------------------------------------------------------
1753 
1754 Disassembler::Disassembler(const NameConverter& converter)
1755  : converter_(converter) {}
1756 
1757 
1758 Disassembler::~Disassembler() {}
1759 
1760 
1761 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1762  byte* instruction) {
1763  DisassemblerX87 d(converter_, false /*do not crash if unimplemented*/);
1764  return d.InstructionDecode(buffer, instruction);
1765 }
1766 
1767 
1768 // The IA-32 assembler does not currently use constant pools.
1769 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
1770 
1771 
1772 /*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1773  NameConverter converter;
1774  Disassembler d(converter);
1775  for (byte* pc = begin; pc < end;) {
1777  buffer[0] = '\0';
1778  byte* prev_pc = pc;
1779  pc += d.InstructionDecode(buffer, pc);
1780  fprintf(f, "%p", prev_pc);
1781  fprintf(f, " ");
1782 
1783  for (byte* bp = prev_pc; bp < pc; bp++) {
1784  fprintf(f, "%02x", *bp);
1785  }
1786  for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
1787  fprintf(f, " ");
1788  }
1789  fprintf(f, " %s\n", buffer.start());
1790  }
1791 }
1792 
1793 
1794 } // namespace disasm
1795 
1796 #endif // V8_TARGET_ARCH_X87
Disassembler(const NameConverter &converter)
v8::internal::EmbeddedVector< char, 128 > tmp_buffer_
Definition: disasm.h:26
virtual const char * NameInCode(byte *addr) const
virtual const char * NameOfByteCPURegister(int reg) const
virtual const char * NameOfXMMRegister(int reg) const
virtual const char * NameOfAddress(byte *addr) const
virtual const char * NameOfCPURegister(int reg) const
virtual const char * NameOfConstant(byte *addr) const
T * start() const
Definition: vector.h:47
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define UNREACHABLE()
Definition: logging.h:30
#define UNIMPLEMENTED()
Definition: logging.h:28
#define DCHECK(condition)
Definition: logging.h:205
#define DCHECK_EQ(v1, v2)
Definition: logging.h:206
Definition: disasm.h:8
unsigned short uint16_t
Definition: unicode.cc:23
signed short int16_t
Definition: unicode.cc:22
int int32_t
Definition: unicode.cc:24
const Register edx
const Register edi
const Register esp
int SNPrintF(Vector< char > str, const char *format,...)
Definition: utils.cc:105
const Register esi
const Register eax
const Register pc
const Register ebx
int VSNPrintF(Vector< char > str, const char *format, va_list args)
Definition: utils.cc:114
const Register ebp
const Register ecx