V8 Project
disasm-ia32.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_IA32
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 IA32 disassembler implementation.
244 class DisassemblerIA32 {
245  public:
246  DisassemblerIA32(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 ~DisassemblerIA32() {}
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* (DisassemblerIA32::*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 DisassemblerIA32::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 DisassemblerIA32::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  &DisassemblerIA32::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 DisassemblerIA32::PrintRightOperand(byte* modrmp) {
454  return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
455 }
456 
457 
458 int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
459  return PrintRightOperandHelper(modrmp,
460  &DisassemblerIA32::NameOfByteCPURegister);
461 }
462 
463 
464 int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
465  return PrintRightOperandHelper(modrmp,
466  &DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 DisassemblerIA32::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 7: mnem = "fstcw"; break;
706  default: UnimplementedInstruction();
707  }
708  break;
709 
710  case 0xDB: switch (regop) {
711  case 0: mnem = "fild_s"; break;
712  case 1: mnem = "fisttp_s"; break;
713  case 2: mnem = "fist_s"; break;
714  case 3: mnem = "fistp_s"; break;
715  default: UnimplementedInstruction();
716  }
717  break;
718 
719  case 0xDD: switch (regop) {
720  case 0: mnem = "fld_d"; break;
721  case 1: mnem = "fisttp_d"; break;
722  case 2: mnem = "fst_d"; break;
723  case 3: mnem = "fstp_d"; break;
724  default: UnimplementedInstruction();
725  }
726  break;
727 
728  case 0xDF: switch (regop) {
729  case 5: mnem = "fild_d"; break;
730  case 7: mnem = "fistp_d"; break;
731  default: UnimplementedInstruction();
732  }
733  break;
734 
735  default: UnimplementedInstruction();
736  }
737  AppendToBuffer("%s ", mnem);
738  int count = PrintRightOperand(modrm_start);
739  return count + 1;
740 }
741 
742 int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
743  byte modrm_byte) {
744  bool has_register = false; // Is the FPU register encoded in modrm_byte?
745  const char* mnem = "?";
746 
747  switch (escape_opcode) {
748  case 0xD8:
749  has_register = true;
750  switch (modrm_byte & 0xF8) {
751  case 0xC0: mnem = "fadd_i"; break;
752  case 0xE0: mnem = "fsub_i"; break;
753  case 0xC8: mnem = "fmul_i"; break;
754  case 0xF0: mnem = "fdiv_i"; break;
755  default: UnimplementedInstruction();
756  }
757  break;
758 
759  case 0xD9:
760  switch (modrm_byte & 0xF8) {
761  case 0xC0:
762  mnem = "fld";
763  has_register = true;
764  break;
765  case 0xC8:
766  mnem = "fxch";
767  has_register = true;
768  break;
769  default:
770  switch (modrm_byte) {
771  case 0xE0: mnem = "fchs"; break;
772  case 0xE1: mnem = "fabs"; break;
773  case 0xE4: mnem = "ftst"; break;
774  case 0xE8: mnem = "fld1"; break;
775  case 0xEB: mnem = "fldpi"; break;
776  case 0xED: mnem = "fldln2"; break;
777  case 0xEE: mnem = "fldz"; break;
778  case 0xF0: mnem = "f2xm1"; break;
779  case 0xF1: mnem = "fyl2x"; break;
780  case 0xF4: mnem = "fxtract"; break;
781  case 0xF5: mnem = "fprem1"; break;
782  case 0xF7: mnem = "fincstp"; break;
783  case 0xF8: mnem = "fprem"; break;
784  case 0xFC: mnem = "frndint"; break;
785  case 0xFD: mnem = "fscale"; break;
786  case 0xFE: mnem = "fsin"; break;
787  case 0xFF: mnem = "fcos"; break;
788  default: UnimplementedInstruction();
789  }
790  }
791  break;
792 
793  case 0xDA:
794  if (modrm_byte == 0xE9) {
795  mnem = "fucompp";
796  } else {
797  UnimplementedInstruction();
798  }
799  break;
800 
801  case 0xDB:
802  if ((modrm_byte & 0xF8) == 0xE8) {
803  mnem = "fucomi";
804  has_register = true;
805  } else if (modrm_byte == 0xE2) {
806  mnem = "fclex";
807  } else if (modrm_byte == 0xE3) {
808  mnem = "fninit";
809  } else {
810  UnimplementedInstruction();
811  }
812  break;
813 
814  case 0xDC:
815  has_register = true;
816  switch (modrm_byte & 0xF8) {
817  case 0xC0: mnem = "fadd"; break;
818  case 0xE8: mnem = "fsub"; break;
819  case 0xC8: mnem = "fmul"; break;
820  case 0xF8: mnem = "fdiv"; break;
821  default: UnimplementedInstruction();
822  }
823  break;
824 
825  case 0xDD:
826  has_register = true;
827  switch (modrm_byte & 0xF8) {
828  case 0xC0: mnem = "ffree"; break;
829  case 0xD0: mnem = "fst"; break;
830  case 0xD8: mnem = "fstp"; break;
831  default: UnimplementedInstruction();
832  }
833  break;
834 
835  case 0xDE:
836  if (modrm_byte == 0xD9) {
837  mnem = "fcompp";
838  } else {
839  has_register = true;
840  switch (modrm_byte & 0xF8) {
841  case 0xC0: mnem = "faddp"; break;
842  case 0xE8: mnem = "fsubp"; break;
843  case 0xC8: mnem = "fmulp"; break;
844  case 0xF8: mnem = "fdivp"; break;
845  default: UnimplementedInstruction();
846  }
847  }
848  break;
849 
850  case 0xDF:
851  if (modrm_byte == 0xE0) {
852  mnem = "fnstsw_ax";
853  } else if ((modrm_byte & 0xF8) == 0xE8) {
854  mnem = "fucomip";
855  has_register = true;
856  }
857  break;
858 
859  default: UnimplementedInstruction();
860  }
861 
862  if (has_register) {
863  AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
864  } else {
865  AppendToBuffer("%s", mnem);
866  }
867  return 2;
868 }
869 
870 
871 // Mnemonics for instructions 0xF0 byte.
872 // Returns NULL if the instruction is not handled here.
873 static const char* F0Mnem(byte f0byte) {
874  switch (f0byte) {
875  case 0x18: return "prefetch";
876  case 0xA2: return "cpuid";
877  case 0xBE: return "movsx_b";
878  case 0xBF: return "movsx_w";
879  case 0xB6: return "movzx_b";
880  case 0xB7: return "movzx_w";
881  case 0xAF: return "imul";
882  case 0xA5: return "shld";
883  case 0xAD: return "shrd";
884  case 0xAC: return "shrd"; // 3-operand version.
885  case 0xAB: return "bts";
886  case 0xBD: return "bsr";
887  default: return NULL;
888  }
889 }
890 
891 
892 // Disassembled instruction '*instr' and writes it into 'out_buffer'.
893 int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
894  byte* instr) {
895  tmp_buffer_pos_ = 0; // starting to write as position 0
896  byte* data = instr;
897  // Check for hints.
898  const char* branch_hint = NULL;
899  // We use these two prefixes only with branch prediction
900  if (*data == 0x3E /*ds*/) {
901  branch_hint = "predicted taken";
902  data++;
903  } else if (*data == 0x2E /*cs*/) {
904  branch_hint = "predicted not taken";
905  data++;
906  }
907  bool processed = true; // Will be set to false if the current instruction
908  // is not in 'instructions' table.
909  const InstructionDesc& idesc = instruction_table_->Get(*data);
910  switch (idesc.type) {
911  case ZERO_OPERANDS_INSTR:
912  AppendToBuffer(idesc.mnem);
913  data++;
914  break;
915 
916  case TWO_OPERANDS_INSTR:
917  data++;
918  data += PrintOperands(idesc.mnem, idesc.op_order_, data);
919  break;
920 
921  case JUMP_CONDITIONAL_SHORT_INSTR:
922  data += JumpConditionalShort(data, branch_hint);
923  break;
924 
925  case REGISTER_INSTR:
926  AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
927  data++;
928  break;
929 
930  case MOVE_REG_INSTR: {
931  byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
932  AppendToBuffer("mov %s,%s",
933  NameOfCPURegister(*data & 0x07),
934  NameOfAddress(addr));
935  data += 5;
936  break;
937  }
938 
939  case CALL_JUMP_INSTR: {
940  byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5;
941  AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
942  data += 5;
943  break;
944  }
945 
946  case SHORT_IMMEDIATE_INSTR: {
947  byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
948  AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
949  data += 5;
950  break;
951  }
952 
953  case BYTE_IMMEDIATE_INSTR: {
954  AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
955  data += 2;
956  break;
957  }
958 
959  case NO_INSTR:
960  processed = false;
961  break;
962 
963  default:
964  UNIMPLEMENTED(); // This type is not implemented.
965  }
966  //----------------------------
967  if (!processed) {
968  switch (*data) {
969  case 0xC2:
970  AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
971  data += 3;
972  break;
973 
974  case 0x6B: {
975  data++;
976  data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
977  AppendToBuffer(",%d", *data);
978  data++;
979  } break;
980 
981  case 0x69: {
982  data++;
983  data += PrintOperands("imul", REG_OPER_OP_ORDER, data);
984  AppendToBuffer(",%d", *reinterpret_cast<int32_t*>(data));
985  data += 4;
986  }
987  break;
988 
989  case 0xF6:
990  { data++;
991  int mod, regop, rm;
992  get_modrm(*data, &mod, &regop, &rm);
993  if (regop == eax) {
994  AppendToBuffer("test_b ");
995  data += PrintRightByteOperand(data);
996  int32_t imm = *data;
997  AppendToBuffer(",0x%x", imm);
998  data++;
999  } else {
1000  UnimplementedInstruction();
1001  }
1002  }
1003  break;
1004 
1005  case 0x81: // fall through
1006  case 0x83: // 0x81 with sign extension bit set
1007  data += PrintImmediateOp(data);
1008  break;
1009 
1010  case 0x0F:
1011  { byte f0byte = data[1];
1012  const char* f0mnem = F0Mnem(f0byte);
1013  if (f0byte == 0x18) {
1014  data += 2;
1015  int mod, regop, rm;
1016  get_modrm(*data, &mod, &regop, &rm);
1017  const char* suffix[] = {"nta", "1", "2", "3"};
1018  AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1019  data += PrintRightOperand(data);
1020  } else if (f0byte == 0x1F && data[2] == 0) {
1021  AppendToBuffer("nop"); // 3 byte nop.
1022  data += 3;
1023  } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1024  AppendToBuffer("nop"); // 4 byte nop.
1025  data += 4;
1026  } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1027  data[4] == 0) {
1028  AppendToBuffer("nop"); // 5 byte nop.
1029  data += 5;
1030  } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1031  data[4] == 0 && data[5] == 0 && data[6] == 0) {
1032  AppendToBuffer("nop"); // 7 byte nop.
1033  data += 7;
1034  } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1035  data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1036  data[7] == 0) {
1037  AppendToBuffer("nop"); // 8 byte nop.
1038  data += 8;
1039  } else if (f0byte == 0xA2 || f0byte == 0x31) {
1040  AppendToBuffer("%s", f0mnem);
1041  data += 2;
1042  } else if (f0byte == 0x28) {
1043  data += 2;
1044  int mod, regop, rm;
1045  get_modrm(*data, &mod, &regop, &rm);
1046  AppendToBuffer("movaps %s,%s",
1047  NameOfXMMRegister(regop),
1048  NameOfXMMRegister(rm));
1049  data++;
1050  } else if (f0byte >= 0x53 && f0byte <= 0x5F) {
1051  const char* const pseudo_op[] = {
1052  "rcpps",
1053  "andps",
1054  "andnps",
1055  "orps",
1056  "xorps",
1057  "addps",
1058  "mulps",
1059  "cvtps2pd",
1060  "cvtdq2ps",
1061  "subps",
1062  "minps",
1063  "divps",
1064  "maxps",
1065  };
1066 
1067  data += 2;
1068  int mod, regop, rm;
1069  get_modrm(*data, &mod, &regop, &rm);
1070  AppendToBuffer("%s %s,",
1071  pseudo_op[f0byte - 0x53],
1072  NameOfXMMRegister(regop));
1073  data += PrintRightXMMOperand(data);
1074  } else if (f0byte == 0x50) {
1075  data += 2;
1076  int mod, regop, rm;
1077  get_modrm(*data, &mod, &regop, &rm);
1078  AppendToBuffer("movmskps %s,%s",
1079  NameOfCPURegister(regop),
1080  NameOfXMMRegister(rm));
1081  data++;
1082  } else if (f0byte== 0xC6) {
1083  // shufps xmm, xmm/m128, imm8
1084  data += 2;
1085  int mod, regop, rm;
1086  get_modrm(*data, &mod, &regop, &rm);
1087  int8_t imm8 = static_cast<int8_t>(data[1]);
1088  AppendToBuffer("shufps %s,%s,%d",
1089  NameOfXMMRegister(rm),
1090  NameOfXMMRegister(regop),
1091  static_cast<int>(imm8));
1092  data += 2;
1093  } else if ((f0byte & 0xF0) == 0x80) {
1094  data += JumpConditional(data, branch_hint);
1095  } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1096  f0byte == 0xB7 || f0byte == 0xAF) {
1097  data += 2;
1098  data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1099  } else if ((f0byte & 0xF0) == 0x90) {
1100  data += SetCC(data);
1101  } else if ((f0byte & 0xF0) == 0x40) {
1102  data += CMov(data);
1103  } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1104  // shrd, shld, bts
1105  data += 2;
1106  AppendToBuffer("%s ", f0mnem);
1107  int mod, regop, rm;
1108  get_modrm(*data, &mod, &regop, &rm);
1109  data += PrintRightOperand(data);
1110  if (f0byte == 0xAB) {
1111  AppendToBuffer(",%s", NameOfCPURegister(regop));
1112  } else {
1113  AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1114  }
1115  } else if (f0byte == 0xBD) {
1116  data += 2;
1117  int mod, regop, rm;
1118  get_modrm(*data, &mod, &regop, &rm);
1119  AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1120  data += PrintRightOperand(data);
1121  } else {
1122  UnimplementedInstruction();
1123  }
1124  }
1125  break;
1126 
1127  case 0x8F:
1128  { data++;
1129  int mod, regop, rm;
1130  get_modrm(*data, &mod, &regop, &rm);
1131  if (regop == eax) {
1132  AppendToBuffer("pop ");
1133  data += PrintRightOperand(data);
1134  }
1135  }
1136  break;
1137 
1138  case 0xFF:
1139  { data++;
1140  int mod, regop, rm;
1141  get_modrm(*data, &mod, &regop, &rm);
1142  const char* mnem = NULL;
1143  switch (regop) {
1144  case esi: mnem = "push"; break;
1145  case eax: mnem = "inc"; break;
1146  case ecx: mnem = "dec"; break;
1147  case edx: mnem = "call"; break;
1148  case esp: mnem = "jmp"; break;
1149  default: mnem = "???";
1150  }
1151  AppendToBuffer("%s ", mnem);
1152  data += PrintRightOperand(data);
1153  }
1154  break;
1155 
1156  case 0xC7: // imm32, fall through
1157  case 0xC6: // imm8
1158  { bool is_byte = *data == 0xC6;
1159  data++;
1160  if (is_byte) {
1161  AppendToBuffer("%s ", "mov_b");
1162  data += PrintRightByteOperand(data);
1163  int32_t imm = *data;
1164  AppendToBuffer(",0x%x", imm);
1165  data++;
1166  } else {
1167  AppendToBuffer("%s ", "mov");
1168  data += PrintRightOperand(data);
1169  int32_t imm = *reinterpret_cast<int32_t*>(data);
1170  AppendToBuffer(",0x%x", imm);
1171  data += 4;
1172  }
1173  }
1174  break;
1175 
1176  case 0x80:
1177  { data++;
1178  int mod, regop, rm;
1179  get_modrm(*data, &mod, &regop, &rm);
1180  const char* mnem = NULL;
1181  switch (regop) {
1182  case 5: mnem = "subb"; break;
1183  case 7: mnem = "cmpb"; break;
1184  default: UnimplementedInstruction();
1185  }
1186  AppendToBuffer("%s ", mnem);
1187  data += PrintRightByteOperand(data);
1188  int32_t imm = *data;
1189  AppendToBuffer(",0x%x", imm);
1190  data++;
1191  }
1192  break;
1193 
1194  case 0x88: // 8bit, fall through
1195  case 0x89: // 32bit
1196  { bool is_byte = *data == 0x88;
1197  int mod, regop, rm;
1198  data++;
1199  get_modrm(*data, &mod, &regop, &rm);
1200  if (is_byte) {
1201  AppendToBuffer("%s ", "mov_b");
1202  data += PrintRightByteOperand(data);
1203  AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1204  } else {
1205  AppendToBuffer("%s ", "mov");
1206  data += PrintRightOperand(data);
1207  AppendToBuffer(",%s", NameOfCPURegister(regop));
1208  }
1209  }
1210  break;
1211 
1212  case 0x66: // prefix
1213  while (*data == 0x66) data++;
1214  if (*data == 0xf && data[1] == 0x1f) {
1215  AppendToBuffer("nop"); // 0x66 prefix
1216  } else if (*data == 0x90) {
1217  AppendToBuffer("nop"); // 0x66 prefix
1218  } else if (*data == 0x8B) {
1219  data++;
1220  data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1221  } else if (*data == 0x89) {
1222  data++;
1223  int mod, regop, rm;
1224  get_modrm(*data, &mod, &regop, &rm);
1225  AppendToBuffer("mov_w ");
1226  data += PrintRightOperand(data);
1227  AppendToBuffer(",%s", NameOfCPURegister(regop));
1228  } else if (*data == 0xC7) {
1229  data++;
1230  AppendToBuffer("%s ", "mov_w");
1231  data += PrintRightOperand(data);
1232  int imm = *reinterpret_cast<int16_t*>(data);
1233  AppendToBuffer(",0x%x", imm);
1234  data += 2;
1235  } else if (*data == 0x0F) {
1236  data++;
1237  if (*data == 0x38) {
1238  data++;
1239  if (*data == 0x17) {
1240  data++;
1241  int mod, regop, rm;
1242  get_modrm(*data, &mod, &regop, &rm);
1243  AppendToBuffer("ptest %s,%s",
1244  NameOfXMMRegister(regop),
1245  NameOfXMMRegister(rm));
1246  data++;
1247  } else if (*data == 0x2A) {
1248  // movntdqa
1249  data++;
1250  int mod, regop, rm;
1251  get_modrm(*data, &mod, &regop, &rm);
1252  AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop));
1253  data += PrintRightOperand(data);
1254  } else {
1255  UnimplementedInstruction();
1256  }
1257  } else if (*data == 0x3A) {
1258  data++;
1259  if (*data == 0x0B) {
1260  data++;
1261  int mod, regop, rm;
1262  get_modrm(*data, &mod, &regop, &rm);
1263  int8_t imm8 = static_cast<int8_t>(data[1]);
1264  AppendToBuffer("roundsd %s,%s,%d",
1265  NameOfXMMRegister(regop),
1266  NameOfXMMRegister(rm),
1267  static_cast<int>(imm8));
1268  data += 2;
1269  } else if (*data == 0x16) {
1270  data++;
1271  int mod, regop, rm;
1272  get_modrm(*data, &mod, &regop, &rm);
1273  int8_t imm8 = static_cast<int8_t>(data[1]);
1274  AppendToBuffer("pextrd %s,%s,%d",
1275  NameOfCPURegister(regop),
1276  NameOfXMMRegister(rm),
1277  static_cast<int>(imm8));
1278  data += 2;
1279  } else if (*data == 0x17) {
1280  data++;
1281  int mod, regop, rm;
1282  get_modrm(*data, &mod, &regop, &rm);
1283  int8_t imm8 = static_cast<int8_t>(data[1]);
1284  AppendToBuffer("extractps %s,%s,%d",
1285  NameOfCPURegister(rm),
1286  NameOfXMMRegister(regop),
1287  static_cast<int>(imm8));
1288  data += 2;
1289  } else if (*data == 0x22) {
1290  data++;
1291  int mod, regop, rm;
1292  get_modrm(*data, &mod, &regop, &rm);
1293  int8_t imm8 = static_cast<int8_t>(data[1]);
1294  AppendToBuffer("pinsrd %s,%s,%d",
1295  NameOfXMMRegister(regop),
1296  NameOfCPURegister(rm),
1297  static_cast<int>(imm8));
1298  data += 2;
1299  } else {
1300  UnimplementedInstruction();
1301  }
1302  } else if (*data == 0x2E || *data == 0x2F) {
1303  const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
1304  data++;
1305  int mod, regop, rm;
1306  get_modrm(*data, &mod, &regop, &rm);
1307  if (mod == 0x3) {
1308  AppendToBuffer("%s %s,%s", mnem,
1309  NameOfXMMRegister(regop),
1310  NameOfXMMRegister(rm));
1311  data++;
1312  } else {
1313  AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1314  data += PrintRightOperand(data);
1315  }
1316  } else if (*data == 0x50) {
1317  data++;
1318  int mod, regop, rm;
1319  get_modrm(*data, &mod, &regop, &rm);
1320  AppendToBuffer("movmskpd %s,%s",
1321  NameOfCPURegister(regop),
1322  NameOfXMMRegister(rm));
1323  data++;
1324  } else if (*data == 0x54) {
1325  data++;
1326  int mod, regop, rm;
1327  get_modrm(*data, &mod, &regop, &rm);
1328  AppendToBuffer("andpd %s,%s",
1329  NameOfXMMRegister(regop),
1330  NameOfXMMRegister(rm));
1331  data++;
1332  } else if (*data == 0x56) {
1333  data++;
1334  int mod, regop, rm;
1335  get_modrm(*data, &mod, &regop, &rm);
1336  AppendToBuffer("orpd %s,%s",
1337  NameOfXMMRegister(regop),
1338  NameOfXMMRegister(rm));
1339  data++;
1340  } else if (*data == 0x57) {
1341  data++;
1342  int mod, regop, rm;
1343  get_modrm(*data, &mod, &regop, &rm);
1344  AppendToBuffer("xorpd %s,%s",
1345  NameOfXMMRegister(regop),
1346  NameOfXMMRegister(rm));
1347  data++;
1348  } else if (*data == 0x6E) {
1349  data++;
1350  int mod, regop, rm;
1351  get_modrm(*data, &mod, &regop, &rm);
1352  AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1353  data += PrintRightOperand(data);
1354  } else if (*data == 0x6F) {
1355  data++;
1356  int mod, regop, rm;
1357  get_modrm(*data, &mod, &regop, &rm);
1358  AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
1359  data += PrintRightXMMOperand(data);
1360  } else if (*data == 0x70) {
1361  data++;
1362  int mod, regop, rm;
1363  get_modrm(*data, &mod, &regop, &rm);
1364  int8_t imm8 = static_cast<int8_t>(data[1]);
1365  AppendToBuffer("pshufd %s,%s,%d",
1366  NameOfXMMRegister(regop),
1367  NameOfXMMRegister(rm),
1368  static_cast<int>(imm8));
1369  data += 2;
1370  } else if (*data == 0x76) {
1371  data++;
1372  int mod, regop, rm;
1373  get_modrm(*data, &mod, &regop, &rm);
1374  AppendToBuffer("pcmpeqd %s,%s",
1375  NameOfXMMRegister(regop),
1376  NameOfXMMRegister(rm));
1377  data++;
1378  } else if (*data == 0x90) {
1379  data++;
1380  AppendToBuffer("nop"); // 2 byte nop.
1381  } else if (*data == 0xF3) {
1382  data++;
1383  int mod, regop, rm;
1384  get_modrm(*data, &mod, &regop, &rm);
1385  AppendToBuffer("psllq %s,%s",
1386  NameOfXMMRegister(regop),
1387  NameOfXMMRegister(rm));
1388  data++;
1389  } else if (*data == 0x73) {
1390  data++;
1391  int mod, regop, rm;
1392  get_modrm(*data, &mod, &regop, &rm);
1393  int8_t imm8 = static_cast<int8_t>(data[1]);
1394  DCHECK(regop == esi || regop == edx);
1395  AppendToBuffer("%s %s,%d",
1396  (regop == esi) ? "psllq" : "psrlq",
1397  NameOfXMMRegister(rm),
1398  static_cast<int>(imm8));
1399  data += 2;
1400  } else if (*data == 0xD3) {
1401  data++;
1402  int mod, regop, rm;
1403  get_modrm(*data, &mod, &regop, &rm);
1404  AppendToBuffer("psrlq %s,%s",
1405  NameOfXMMRegister(regop),
1406  NameOfXMMRegister(rm));
1407  data++;
1408  } else if (*data == 0x7F) {
1409  AppendToBuffer("movdqa ");
1410  data++;
1411  int mod, regop, rm;
1412  get_modrm(*data, &mod, &regop, &rm);
1413  data += PrintRightXMMOperand(data);
1414  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1415  } else if (*data == 0x7E) {
1416  data++;
1417  int mod, regop, rm;
1418  get_modrm(*data, &mod, &regop, &rm);
1419  AppendToBuffer("movd ");
1420  data += PrintRightOperand(data);
1421  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1422  } else if (*data == 0xDB) {
1423  data++;
1424  int mod, regop, rm;
1425  get_modrm(*data, &mod, &regop, &rm);
1426  AppendToBuffer("pand %s,%s",
1427  NameOfXMMRegister(regop),
1428  NameOfXMMRegister(rm));
1429  data++;
1430  } else if (*data == 0xE7) {
1431  data++;
1432  int mod, regop, rm;
1433  get_modrm(*data, &mod, &regop, &rm);
1434  if (mod == 3) {
1435  AppendToBuffer("movntdq ");
1436  data += PrintRightOperand(data);
1437  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1438  } else {
1439  UnimplementedInstruction();
1440  }
1441  } else if (*data == 0xEF) {
1442  data++;
1443  int mod, regop, rm;
1444  get_modrm(*data, &mod, &regop, &rm);
1445  AppendToBuffer("pxor %s,%s",
1446  NameOfXMMRegister(regop),
1447  NameOfXMMRegister(rm));
1448  data++;
1449  } else if (*data == 0xEB) {
1450  data++;
1451  int mod, regop, rm;
1452  get_modrm(*data, &mod, &regop, &rm);
1453  AppendToBuffer("por %s,%s",
1454  NameOfXMMRegister(regop),
1455  NameOfXMMRegister(rm));
1456  data++;
1457  } else {
1458  UnimplementedInstruction();
1459  }
1460  } else {
1461  UnimplementedInstruction();
1462  }
1463  break;
1464 
1465  case 0xFE:
1466  { data++;
1467  int mod, regop, rm;
1468  get_modrm(*data, &mod, &regop, &rm);
1469  if (regop == ecx) {
1470  AppendToBuffer("dec_b ");
1471  data += PrintRightOperand(data);
1472  } else {
1473  UnimplementedInstruction();
1474  }
1475  }
1476  break;
1477 
1478  case 0x68:
1479  AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1480  data += 5;
1481  break;
1482 
1483  case 0x6A:
1484  AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1485  data += 2;
1486  break;
1487 
1488  case 0xA8:
1489  AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1490  data += 2;
1491  break;
1492 
1493  case 0xA9:
1494  AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1495  data += 5;
1496  break;
1497 
1498  case 0xD1: // fall through
1499  case 0xD3: // fall through
1500  case 0xC1:
1501  data += D1D3C1Instruction(data);
1502  break;
1503 
1504  case 0xD8: // fall through
1505  case 0xD9: // fall through
1506  case 0xDA: // fall through
1507  case 0xDB: // fall through
1508  case 0xDC: // fall through
1509  case 0xDD: // fall through
1510  case 0xDE: // fall through
1511  case 0xDF:
1512  data += FPUInstruction(data);
1513  break;
1514 
1515  case 0xEB:
1516  data += JumpShort(data);
1517  break;
1518 
1519  case 0xF2:
1520  if (*(data+1) == 0x0F) {
1521  byte b2 = *(data+2);
1522  if (b2 == 0x11) {
1523  AppendToBuffer("movsd ");
1524  data += 3;
1525  int mod, regop, rm;
1526  get_modrm(*data, &mod, &regop, &rm);
1527  data += PrintRightXMMOperand(data);
1528  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1529  } else if (b2 == 0x10) {
1530  data += 3;
1531  int mod, regop, rm;
1532  get_modrm(*data, &mod, &regop, &rm);
1533  AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
1534  data += PrintRightXMMOperand(data);
1535  } else if (b2 == 0x5A) {
1536  data += 3;
1537  int mod, regop, rm;
1538  get_modrm(*data, &mod, &regop, &rm);
1539  AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
1540  data += PrintRightXMMOperand(data);
1541  } else {
1542  const char* mnem = "?";
1543  switch (b2) {
1544  case 0x2A: mnem = "cvtsi2sd"; break;
1545  case 0x2C: mnem = "cvttsd2si"; break;
1546  case 0x2D: mnem = "cvtsd2si"; break;
1547  case 0x51: mnem = "sqrtsd"; break;
1548  case 0x58: mnem = "addsd"; break;
1549  case 0x59: mnem = "mulsd"; break;
1550  case 0x5C: mnem = "subsd"; break;
1551  case 0x5E: mnem = "divsd"; break;
1552  }
1553  data += 3;
1554  int mod, regop, rm;
1555  get_modrm(*data, &mod, &regop, &rm);
1556  if (b2 == 0x2A) {
1557  AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1558  data += PrintRightOperand(data);
1559  } else if (b2 == 0x2C || b2 == 0x2D) {
1560  AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
1561  data += PrintRightXMMOperand(data);
1562  } else if (b2 == 0xC2) {
1563  // Intel manual 2A, Table 3-18.
1564  const char* const pseudo_op[] = {
1565  "cmpeqsd",
1566  "cmpltsd",
1567  "cmplesd",
1568  "cmpunordsd",
1569  "cmpneqsd",
1570  "cmpnltsd",
1571  "cmpnlesd",
1572  "cmpordsd"
1573  };
1574  AppendToBuffer("%s %s,%s",
1575  pseudo_op[data[1]],
1576  NameOfXMMRegister(regop),
1577  NameOfXMMRegister(rm));
1578  data += 2;
1579  } else {
1580  AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1581  data += PrintRightXMMOperand(data);
1582  }
1583  }
1584  } else {
1585  UnimplementedInstruction();
1586  }
1587  break;
1588 
1589  case 0xF3:
1590  if (*(data+1) == 0x0F) {
1591  byte b2 = *(data+2);
1592  if (b2 == 0x11) {
1593  AppendToBuffer("movss ");
1594  data += 3;
1595  int mod, regop, rm;
1596  get_modrm(*data, &mod, &regop, &rm);
1597  data += PrintRightXMMOperand(data);
1598  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1599  } else if (b2 == 0x10) {
1600  data += 3;
1601  int mod, regop, rm;
1602  get_modrm(*data, &mod, &regop, &rm);
1603  AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
1604  data += PrintRightXMMOperand(data);
1605  } else if (b2 == 0x2C) {
1606  data += 3;
1607  int mod, regop, rm;
1608  get_modrm(*data, &mod, &regop, &rm);
1609  AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
1610  data += PrintRightXMMOperand(data);
1611  } else if (b2 == 0x5A) {
1612  data += 3;
1613  int mod, regop, rm;
1614  get_modrm(*data, &mod, &regop, &rm);
1615  AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1616  data += PrintRightXMMOperand(data);
1617  } else if (b2 == 0x6F) {
1618  data += 3;
1619  int mod, regop, rm;
1620  get_modrm(*data, &mod, &regop, &rm);
1621  AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
1622  data += PrintRightXMMOperand(data);
1623  } else if (b2 == 0x7F) {
1624  AppendToBuffer("movdqu ");
1625  data += 3;
1626  int mod, regop, rm;
1627  get_modrm(*data, &mod, &regop, &rm);
1628  data += PrintRightXMMOperand(data);
1629  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1630  } else {
1631  UnimplementedInstruction();
1632  }
1633  } else if (*(data+1) == 0xA5) {
1634  data += 2;
1635  AppendToBuffer("rep_movs");
1636  } else if (*(data+1) == 0xAB) {
1637  data += 2;
1638  AppendToBuffer("rep_stos");
1639  } else {
1640  UnimplementedInstruction();
1641  }
1642  break;
1643 
1644  case 0xF7:
1645  data += F7Instruction(data);
1646  break;
1647 
1648  default:
1649  UnimplementedInstruction();
1650  }
1651  }
1652 
1653  if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1654  tmp_buffer_[tmp_buffer_pos_] = '\0';
1655  }
1656 
1657  int instr_len = data - instr;
1658  if (instr_len == 0) {
1659  printf("%02x", *data);
1660  }
1661  DCHECK(instr_len > 0); // Ensure progress.
1662 
1663  int outp = 0;
1664  // Instruction bytes.
1665  for (byte* bp = instr; bp < data; bp++) {
1666  outp += v8::internal::SNPrintF(out_buffer + outp,
1667  "%02x",
1668  *bp);
1669  }
1670  for (int i = 6 - instr_len; i >= 0; i--) {
1671  outp += v8::internal::SNPrintF(out_buffer + outp, " ");
1672  }
1673 
1674  outp += v8::internal::SNPrintF(out_buffer + outp,
1675  " %s",
1676  tmp_buffer_.start());
1677  return instr_len;
1678 } // NOLINT (function is too long)
1679 
1680 
1681 //------------------------------------------------------------------------------
1682 
1683 
1684 static const char* cpu_regs[8] = {
1685  "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
1686 };
1687 
1688 
1689 static const char* byte_cpu_regs[8] = {
1690  "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
1691 };
1692 
1693 
1694 static const char* xmm_regs[8] = {
1695  "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
1696 };
1697 
1698 
1699 const char* NameConverter::NameOfAddress(byte* addr) const {
1700  v8::internal::SNPrintF(tmp_buffer_, "%p", addr);
1701  return tmp_buffer_.start();
1702 }
1703 
1704 
1705 const char* NameConverter::NameOfConstant(byte* addr) const {
1706  return NameOfAddress(addr);
1707 }
1708 
1709 
1710 const char* NameConverter::NameOfCPURegister(int reg) const {
1711  if (0 <= reg && reg < 8) return cpu_regs[reg];
1712  return "noreg";
1713 }
1714 
1715 
1716 const char* NameConverter::NameOfByteCPURegister(int reg) const {
1717  if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
1718  return "noreg";
1719 }
1720 
1721 
1722 const char* NameConverter::NameOfXMMRegister(int reg) const {
1723  if (0 <= reg && reg < 8) return xmm_regs[reg];
1724  return "noxmmreg";
1725 }
1726 
1727 
1728 const char* NameConverter::NameInCode(byte* addr) const {
1729  // IA32 does not embed debug strings at the moment.
1730  UNREACHABLE();
1731  return "";
1732 }
1733 
1734 
1735 //------------------------------------------------------------------------------
1736 
1737 Disassembler::Disassembler(const NameConverter& converter)
1738  : converter_(converter) {}
1739 
1740 
1741 Disassembler::~Disassembler() {}
1742 
1743 
1744 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1745  byte* instruction) {
1746  DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
1747  return d.InstructionDecode(buffer, instruction);
1748 }
1749 
1750 
1751 // The IA-32 assembler does not currently use constant pools.
1752 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
1753 
1754 
1755 /*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1756  NameConverter converter;
1757  Disassembler d(converter);
1758  for (byte* pc = begin; pc < end;) {
1760  buffer[0] = '\0';
1761  byte* prev_pc = pc;
1762  pc += d.InstructionDecode(buffer, pc);
1763  fprintf(f, "%p", prev_pc);
1764  fprintf(f, " ");
1765 
1766  for (byte* bp = prev_pc; bp < pc; bp++) {
1767  fprintf(f, "%02x", *bp);
1768  }
1769  for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
1770  fprintf(f, " ");
1771  }
1772  fprintf(f, " %s\n", buffer.start());
1773  }
1774 }
1775 
1776 
1777 } // namespace disasm
1778 
1779 #endif // V8_TARGET_ARCH_IA32
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