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