v8  3.11.10(node0.8.26)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
disasm-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 7: mnem = "idiv"; break;
557  default: UnimplementedInstruction();
558  }
559  AppendToBuffer("%s %s", mnem, NameOfCPURegister(rm));
560  return 2;
561  } else if (mod == 3 && regop == eax) {
562  int32_t imm = *reinterpret_cast<int32_t*>(data+2);
563  AppendToBuffer("test %s,0x%x", NameOfCPURegister(rm), imm);
564  return 6;
565  } else if (regop == eax) {
566  AppendToBuffer("test ");
567  int count = PrintRightOperand(data+1);
568  int32_t imm = *reinterpret_cast<int32_t*>(data+1+count);
569  AppendToBuffer(",0x%x", imm);
570  return 1+count+4 /*int32_t*/;
571  } else {
572  UnimplementedInstruction();
573  return 2;
574  }
575 }
576 
577 int DisassemblerIA32::D1D3C1Instruction(byte* data) {
578  byte op = *data;
579  ASSERT(op == 0xD1 || op == 0xD3 || op == 0xC1);
580  byte modrm = *(data+1);
581  int mod, regop, rm;
582  get_modrm(modrm, &mod, &regop, &rm);
583  int imm8 = -1;
584  int num_bytes = 2;
585  if (mod == 3) {
586  const char* mnem = NULL;
587  switch (regop) {
588  case kROL: mnem = "rol"; break;
589  case kROR: mnem = "ror"; break;
590  case kRCL: mnem = "rcl"; break;
591  case kRCR: mnem = "rcr"; break;
592  case kSHL: mnem = "shl"; break;
593  case KSHR: mnem = "shr"; break;
594  case kSAR: mnem = "sar"; break;
595  default: UnimplementedInstruction();
596  }
597  if (op == 0xD1) {
598  imm8 = 1;
599  } else if (op == 0xC1) {
600  imm8 = *(data+2);
601  num_bytes = 3;
602  } else if (op == 0xD3) {
603  // Shift/rotate by cl.
604  }
605  ASSERT_NE(NULL, mnem);
606  AppendToBuffer("%s %s,", mnem, NameOfCPURegister(rm));
607  if (imm8 > 0) {
608  AppendToBuffer("%d", imm8);
609  } else {
610  AppendToBuffer("cl");
611  }
612  } else {
613  UnimplementedInstruction();
614  }
615  return num_bytes;
616 }
617 
618 
619 // Returns number of bytes used, including *data.
620 int DisassemblerIA32::JumpShort(byte* data) {
621  ASSERT_EQ(0xEB, *data);
622  byte b = *(data+1);
623  byte* dest = data + static_cast<int8_t>(b) + 2;
624  AppendToBuffer("jmp %s", NameOfAddress(dest));
625  return 2;
626 }
627 
628 
629 // Returns number of bytes used, including *data.
630 int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
631  ASSERT_EQ(0x0F, *data);
632  byte cond = *(data+1) & 0x0F;
633  byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
634  const char* mnem = jump_conditional_mnem[cond];
635  AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
636  if (comment != NULL) {
637  AppendToBuffer(", %s", comment);
638  }
639  return 6; // includes 0x0F
640 }
641 
642 
643 // Returns number of bytes used, including *data.
644 int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
645  byte cond = *data & 0x0F;
646  byte b = *(data+1);
647  byte* dest = data + static_cast<int8_t>(b) + 2;
648  const char* mnem = jump_conditional_mnem[cond];
649  AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
650  if (comment != NULL) {
651  AppendToBuffer(", %s", comment);
652  }
653  return 2;
654 }
655 
656 
657 // Returns number of bytes used, including *data.
658 int DisassemblerIA32::SetCC(byte* data) {
659  ASSERT_EQ(0x0F, *data);
660  byte cond = *(data+1) & 0x0F;
661  const char* mnem = set_conditional_mnem[cond];
662  AppendToBuffer("%s ", mnem);
663  PrintRightByteOperand(data+2);
664  return 3; // Includes 0x0F.
665 }
666 
667 
668 // Returns number of bytes used, including *data.
669 int DisassemblerIA32::CMov(byte* data) {
670  ASSERT_EQ(0x0F, *data);
671  byte cond = *(data + 1) & 0x0F;
672  const char* mnem = conditional_move_mnem[cond];
673  int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
674  return 2 + op_size; // includes 0x0F
675 }
676 
677 
678 // Returns number of bytes used, including *data.
679 int DisassemblerIA32::FPUInstruction(byte* data) {
680  byte escape_opcode = *data;
681  ASSERT_EQ(0xD8, escape_opcode & 0xF8);
682  byte modrm_byte = *(data+1);
683 
684  if (modrm_byte >= 0xC0) {
685  return RegisterFPUInstruction(escape_opcode, modrm_byte);
686  } else {
687  return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
688  }
689 }
690 
691 int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
692  int modrm_byte,
693  byte* modrm_start) {
694  const char* mnem = "?";
695  int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
696  switch (escape_opcode) {
697  case 0xD9: switch (regop) {
698  case 0: mnem = "fld_s"; break;
699  case 3: mnem = "fstp_s"; break;
700  case 7: mnem = "fstcw"; break;
701  default: UnimplementedInstruction();
702  }
703  break;
704 
705  case 0xDB: switch (regop) {
706  case 0: mnem = "fild_s"; break;
707  case 1: mnem = "fisttp_s"; break;
708  case 2: mnem = "fist_s"; break;
709  case 3: mnem = "fistp_s"; break;
710  default: UnimplementedInstruction();
711  }
712  break;
713 
714  case 0xDD: switch (regop) {
715  case 0: mnem = "fld_d"; break;
716  case 1: mnem = "fisttp_d"; break;
717  case 2: mnem = "fst_d"; break;
718  case 3: mnem = "fstp_d"; break;
719  default: UnimplementedInstruction();
720  }
721  break;
722 
723  case 0xDF: switch (regop) {
724  case 5: mnem = "fild_d"; break;
725  case 7: mnem = "fistp_d"; break;
726  default: UnimplementedInstruction();
727  }
728  break;
729 
730  default: UnimplementedInstruction();
731  }
732  AppendToBuffer("%s ", mnem);
733  int count = PrintRightOperand(modrm_start);
734  return count + 1;
735 }
736 
737 int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
738  byte modrm_byte) {
739  bool has_register = false; // Is the FPU register encoded in modrm_byte?
740  const char* mnem = "?";
741 
742  switch (escape_opcode) {
743  case 0xD8:
744  UnimplementedInstruction();
745  break;
746 
747  case 0xD9:
748  switch (modrm_byte & 0xF8) {
749  case 0xC0:
750  mnem = "fld";
751  has_register = true;
752  break;
753  case 0xC8:
754  mnem = "fxch";
755  has_register = true;
756  break;
757  default:
758  switch (modrm_byte) {
759  case 0xE0: mnem = "fchs"; break;
760  case 0xE1: mnem = "fabs"; break;
761  case 0xE4: mnem = "ftst"; break;
762  case 0xE8: mnem = "fld1"; break;
763  case 0xEB: mnem = "fldpi"; break;
764  case 0xED: mnem = "fldln2"; break;
765  case 0xEE: mnem = "fldz"; break;
766  case 0xF0: mnem = "f2xm1"; break;
767  case 0xF1: mnem = "fyl2x"; break;
768  case 0xF5: mnem = "fprem1"; break;
769  case 0xF7: mnem = "fincstp"; break;
770  case 0xF8: mnem = "fprem"; break;
771  case 0xFC: mnem = "frndint"; break;
772  case 0xFD: mnem = "fscale"; break;
773  case 0xFE: mnem = "fsin"; break;
774  case 0xFF: mnem = "fcos"; break;
775  default: UnimplementedInstruction();
776  }
777  }
778  break;
779 
780  case 0xDA:
781  if (modrm_byte == 0xE9) {
782  mnem = "fucompp";
783  } else {
784  UnimplementedInstruction();
785  }
786  break;
787 
788  case 0xDB:
789  if ((modrm_byte & 0xF8) == 0xE8) {
790  mnem = "fucomi";
791  has_register = true;
792  } else if (modrm_byte == 0xE2) {
793  mnem = "fclex";
794  } else if (modrm_byte == 0xE3) {
795  mnem = "fninit";
796  } else {
797  UnimplementedInstruction();
798  }
799  break;
800 
801  case 0xDC:
802  has_register = true;
803  switch (modrm_byte & 0xF8) {
804  case 0xC0: mnem = "fadd"; break;
805  case 0xE8: mnem = "fsub"; break;
806  case 0xC8: mnem = "fmul"; break;
807  case 0xF8: mnem = "fdiv"; break;
808  default: UnimplementedInstruction();
809  }
810  break;
811 
812  case 0xDD:
813  has_register = true;
814  switch (modrm_byte & 0xF8) {
815  case 0xC0: mnem = "ffree"; break;
816  case 0xD8: mnem = "fstp"; break;
817  default: UnimplementedInstruction();
818  }
819  break;
820 
821  case 0xDE:
822  if (modrm_byte == 0xD9) {
823  mnem = "fcompp";
824  } else {
825  has_register = true;
826  switch (modrm_byte & 0xF8) {
827  case 0xC0: mnem = "faddp"; break;
828  case 0xE8: mnem = "fsubp"; break;
829  case 0xC8: mnem = "fmulp"; break;
830  case 0xF8: mnem = "fdivp"; break;
831  default: UnimplementedInstruction();
832  }
833  }
834  break;
835 
836  case 0xDF:
837  if (modrm_byte == 0xE0) {
838  mnem = "fnstsw_ax";
839  } else if ((modrm_byte & 0xF8) == 0xE8) {
840  mnem = "fucomip";
841  has_register = true;
842  }
843  break;
844 
845  default: UnimplementedInstruction();
846  }
847 
848  if (has_register) {
849  AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
850  } else {
851  AppendToBuffer("%s", mnem);
852  }
853  return 2;
854 }
855 
856 
857 // Mnemonics for instructions 0xF0 byte.
858 // Returns NULL if the instruction is not handled here.
859 static const char* F0Mnem(byte f0byte) {
860  switch (f0byte) {
861  case 0x18: return "prefetch";
862  case 0xA2: return "cpuid";
863  case 0x31: return "rdtsc";
864  case 0xBE: return "movsx_b";
865  case 0xBF: return "movsx_w";
866  case 0xB6: return "movzx_b";
867  case 0xB7: return "movzx_w";
868  case 0xAF: return "imul";
869  case 0xA5: return "shld";
870  case 0xAD: return "shrd";
871  case 0xAB: return "bts";
872  default: return NULL;
873  }
874 }
875 
876 
877 // Disassembled instruction '*instr' and writes it into 'out_buffer'.
878 int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
879  byte* instr) {
880  tmp_buffer_pos_ = 0; // starting to write as position 0
881  byte* data = instr;
882  // Check for hints.
883  const char* branch_hint = NULL;
884  // We use these two prefixes only with branch prediction
885  if (*data == 0x3E /*ds*/) {
886  branch_hint = "predicted taken";
887  data++;
888  } else if (*data == 0x2E /*cs*/) {
889  branch_hint = "predicted not taken";
890  data++;
891  }
892  bool processed = true; // Will be set to false if the current instruction
893  // is not in 'instructions' table.
894  const InstructionDesc& idesc = instruction_table_->Get(*data);
895  switch (idesc.type) {
896  case ZERO_OPERANDS_INSTR:
897  AppendToBuffer(idesc.mnem);
898  data++;
899  break;
900 
901  case TWO_OPERANDS_INSTR:
902  data++;
903  data += PrintOperands(idesc.mnem, idesc.op_order_, data);
904  break;
905 
906  case JUMP_CONDITIONAL_SHORT_INSTR:
907  data += JumpConditionalShort(data, branch_hint);
908  break;
909 
910  case REGISTER_INSTR:
911  AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
912  data++;
913  break;
914 
915  case MOVE_REG_INSTR: {
916  byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
917  AppendToBuffer("mov %s,%s",
918  NameOfCPURegister(*data & 0x07),
919  NameOfAddress(addr));
920  data += 5;
921  break;
922  }
923 
924  case CALL_JUMP_INSTR: {
925  byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5;
926  AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
927  data += 5;
928  break;
929  }
930 
931  case SHORT_IMMEDIATE_INSTR: {
932  byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
933  AppendToBuffer("%s eax, %s", idesc.mnem, NameOfAddress(addr));
934  data += 5;
935  break;
936  }
937 
938  case BYTE_IMMEDIATE_INSTR: {
939  AppendToBuffer("%s al, 0x%x", idesc.mnem, data[1]);
940  data += 2;
941  break;
942  }
943 
944  case NO_INSTR:
945  processed = false;
946  break;
947 
948  default:
949  UNIMPLEMENTED(); // This type is not implemented.
950  }
951  //----------------------------
952  if (!processed) {
953  switch (*data) {
954  case 0xC2:
955  AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
956  data += 3;
957  break;
958 
959  case 0x69: // fall through
960  case 0x6B:
961  { int mod, regop, rm;
962  get_modrm(*(data+1), &mod, &regop, &rm);
963  int32_t imm =
964  *data == 0x6B ? *(data+2) : *reinterpret_cast<int32_t*>(data+2);
965  AppendToBuffer("imul %s,%s,0x%x",
966  NameOfCPURegister(regop),
967  NameOfCPURegister(rm),
968  imm);
969  data += 2 + (*data == 0x6B ? 1 : 4);
970  }
971  break;
972 
973  case 0xF6:
974  { data++;
975  int mod, regop, rm;
976  get_modrm(*data, &mod, &regop, &rm);
977  if (regop == eax) {
978  AppendToBuffer("test_b ");
979  data += PrintRightByteOperand(data);
980  int32_t imm = *data;
981  AppendToBuffer(",0x%x", imm);
982  data++;
983  } else {
984  UnimplementedInstruction();
985  }
986  }
987  break;
988 
989  case 0x81: // fall through
990  case 0x83: // 0x81 with sign extension bit set
991  data += PrintImmediateOp(data);
992  break;
993 
994  case 0x0F:
995  { byte f0byte = data[1];
996  const char* f0mnem = F0Mnem(f0byte);
997  if (f0byte == 0x18) {
998  int mod, regop, rm;
999  get_modrm(*data, &mod, &regop, &rm);
1000  const char* suffix[] = {"nta", "1", "2", "3"};
1001  AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1002  data += PrintRightOperand(data);
1003  } else if (f0byte == 0x1F && data[2] == 0) {
1004  AppendToBuffer("nop"); // 3 byte nop.
1005  data += 3;
1006  } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1007  AppendToBuffer("nop"); // 4 byte nop.
1008  data += 4;
1009  } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1010  data[4] == 0) {
1011  AppendToBuffer("nop"); // 5 byte nop.
1012  data += 5;
1013  } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1014  data[4] == 0 && data[5] == 0 && data[6] == 0) {
1015  AppendToBuffer("nop"); // 7 byte nop.
1016  data += 7;
1017  } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1018  data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1019  data[7] == 0) {
1020  AppendToBuffer("nop"); // 8 byte nop.
1021  data += 8;
1022  } else if (f0byte == 0xA2 || f0byte == 0x31) {
1023  AppendToBuffer("%s", f0mnem);
1024  data += 2;
1025  } else if (f0byte == 0x28) {
1026  data += 2;
1027  int mod, regop, rm;
1028  get_modrm(*data, &mod, &regop, &rm);
1029  AppendToBuffer("movaps %s,%s",
1030  NameOfXMMRegister(regop),
1031  NameOfXMMRegister(rm));
1032  data++;
1033  } else if (f0byte == 0x57) {
1034  data += 2;
1035  int mod, regop, rm;
1036  get_modrm(*data, &mod, &regop, &rm);
1037  AppendToBuffer("xorps %s,%s",
1038  NameOfXMMRegister(regop),
1039  NameOfXMMRegister(rm));
1040  data++;
1041  } else if ((f0byte & 0xF0) == 0x80) {
1042  data += JumpConditional(data, branch_hint);
1043  } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1044  f0byte == 0xB7 || f0byte == 0xAF) {
1045  data += 2;
1046  data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1047  } else if ((f0byte & 0xF0) == 0x90) {
1048  data += SetCC(data);
1049  } else if ((f0byte & 0xF0) == 0x40) {
1050  data += CMov(data);
1051  } else {
1052  data += 2;
1053  if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1054  // shrd, shld, bts
1055  AppendToBuffer("%s ", f0mnem);
1056  int mod, regop, rm;
1057  get_modrm(*data, &mod, &regop, &rm);
1058  data += PrintRightOperand(data);
1059  if (f0byte == 0xAB) {
1060  AppendToBuffer(",%s", NameOfCPURegister(regop));
1061  } else {
1062  AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1063  }
1064  } else {
1065  UnimplementedInstruction();
1066  }
1067  }
1068  }
1069  break;
1070 
1071  case 0x8F:
1072  { data++;
1073  int mod, regop, rm;
1074  get_modrm(*data, &mod, &regop, &rm);
1075  if (regop == eax) {
1076  AppendToBuffer("pop ");
1077  data += PrintRightOperand(data);
1078  }
1079  }
1080  break;
1081 
1082  case 0xFF:
1083  { data++;
1084  int mod, regop, rm;
1085  get_modrm(*data, &mod, &regop, &rm);
1086  const char* mnem = NULL;
1087  switch (regop) {
1088  case esi: mnem = "push"; break;
1089  case eax: mnem = "inc"; break;
1090  case ecx: mnem = "dec"; break;
1091  case edx: mnem = "call"; break;
1092  case esp: mnem = "jmp"; break;
1093  default: mnem = "???";
1094  }
1095  AppendToBuffer("%s ", mnem);
1096  data += PrintRightOperand(data);
1097  }
1098  break;
1099 
1100  case 0xC7: // imm32, fall through
1101  case 0xC6: // imm8
1102  { bool is_byte = *data == 0xC6;
1103  data++;
1104  if (is_byte) {
1105  AppendToBuffer("%s ", "mov_b");
1106  data += PrintRightByteOperand(data);
1107  int32_t imm = *data;
1108  AppendToBuffer(",0x%x", imm);
1109  data++;
1110  } else {
1111  AppendToBuffer("%s ", "mov");
1112  data += PrintRightOperand(data);
1113  int32_t imm = *reinterpret_cast<int32_t*>(data);
1114  AppendToBuffer(",0x%x", imm);
1115  data += 4;
1116  }
1117  }
1118  break;
1119 
1120  case 0x80:
1121  { data++;
1122  int mod, regop, rm;
1123  get_modrm(*data, &mod, &regop, &rm);
1124  const char* mnem = NULL;
1125  switch (regop) {
1126  case 5: mnem = "subb"; break;
1127  case 7: mnem = "cmpb"; break;
1128  default: UnimplementedInstruction();
1129  }
1130  AppendToBuffer("%s ", mnem);
1131  data += PrintRightByteOperand(data);
1132  int32_t imm = *data;
1133  AppendToBuffer(",0x%x", imm);
1134  data++;
1135  }
1136  break;
1137 
1138  case 0x88: // 8bit, fall through
1139  case 0x89: // 32bit
1140  { bool is_byte = *data == 0x88;
1141  int mod, regop, rm;
1142  data++;
1143  get_modrm(*data, &mod, &regop, &rm);
1144  if (is_byte) {
1145  AppendToBuffer("%s ", "mov_b");
1146  data += PrintRightByteOperand(data);
1147  AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1148  } else {
1149  AppendToBuffer("%s ", "mov");
1150  data += PrintRightOperand(data);
1151  AppendToBuffer(",%s", NameOfCPURegister(regop));
1152  }
1153  }
1154  break;
1155 
1156  case 0x66: // prefix
1157  while (*data == 0x66) data++;
1158  if (*data == 0xf && data[1] == 0x1f) {
1159  AppendToBuffer("nop"); // 0x66 prefix
1160  } else if (*data == 0x90) {
1161  AppendToBuffer("nop"); // 0x66 prefix
1162  } else if (*data == 0x8B) {
1163  data++;
1164  data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1165  } else if (*data == 0x89) {
1166  data++;
1167  int mod, regop, rm;
1168  get_modrm(*data, &mod, &regop, &rm);
1169  AppendToBuffer("mov_w ");
1170  data += PrintRightOperand(data);
1171  AppendToBuffer(",%s", NameOfCPURegister(regop));
1172  } else if (*data == 0x0F) {
1173  data++;
1174  if (*data == 0x38) {
1175  data++;
1176  if (*data == 0x17) {
1177  data++;
1178  int mod, regop, rm;
1179  get_modrm(*data, &mod, &regop, &rm);
1180  AppendToBuffer("ptest %s,%s",
1181  NameOfXMMRegister(regop),
1182  NameOfXMMRegister(rm));
1183  data++;
1184  } else if (*data == 0x2A) {
1185  // movntdqa
1186  data++;
1187  int mod, regop, rm;
1188  get_modrm(*data, &mod, &regop, &rm);
1189  AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop));
1190  data += PrintRightOperand(data);
1191  } else {
1192  UnimplementedInstruction();
1193  }
1194  } else if (*data == 0x3A) {
1195  data++;
1196  if (*data == 0x0B) {
1197  data++;
1198  int mod, regop, rm;
1199  get_modrm(*data, &mod, &regop, &rm);
1200  int8_t imm8 = static_cast<int8_t>(data[1]);
1201  AppendToBuffer("roundsd %s,%s,%d",
1202  NameOfXMMRegister(regop),
1203  NameOfXMMRegister(rm),
1204  static_cast<int>(imm8));
1205  data += 2;
1206  } else if (*data == 0x16) {
1207  data++;
1208  int mod, regop, rm;
1209  get_modrm(*data, &mod, &regop, &rm);
1210  int8_t imm8 = static_cast<int8_t>(data[1]);
1211  AppendToBuffer("pextrd %s,%s,%d",
1212  NameOfCPURegister(regop),
1213  NameOfXMMRegister(rm),
1214  static_cast<int>(imm8));
1215  data += 2;
1216  } else if (*data == 0x17) {
1217  data++;
1218  int mod, regop, rm;
1219  get_modrm(*data, &mod, &regop, &rm);
1220  int8_t imm8 = static_cast<int8_t>(data[1]);
1221  AppendToBuffer("extractps %s,%s,%d",
1222  NameOfCPURegister(regop),
1223  NameOfXMMRegister(rm),
1224  static_cast<int>(imm8));
1225  data += 2;
1226  } else if (*data == 0x22) {
1227  data++;
1228  int mod, regop, rm;
1229  get_modrm(*data, &mod, &regop, &rm);
1230  int8_t imm8 = static_cast<int8_t>(data[1]);
1231  AppendToBuffer("pinsrd %s,%s,%d",
1232  NameOfXMMRegister(regop),
1233  NameOfCPURegister(rm),
1234  static_cast<int>(imm8));
1235  data += 2;
1236  } else {
1237  UnimplementedInstruction();
1238  }
1239  } else if (*data == 0x2E || *data == 0x2F) {
1240  const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
1241  data++;
1242  int mod, regop, rm;
1243  get_modrm(*data, &mod, &regop, &rm);
1244  if (mod == 0x3) {
1245  AppendToBuffer("%s %s,%s", mnem,
1246  NameOfXMMRegister(regop),
1247  NameOfXMMRegister(rm));
1248  data++;
1249  } else {
1250  AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1251  data += PrintRightOperand(data);
1252  }
1253  } else if (*data == 0x50) {
1254  data++;
1255  int mod, regop, rm;
1256  get_modrm(*data, &mod, &regop, &rm);
1257  AppendToBuffer("movmskpd %s,%s",
1258  NameOfCPURegister(regop),
1259  NameOfXMMRegister(rm));
1260  data++;
1261  } else if (*data == 0x54) {
1262  data++;
1263  int mod, regop, rm;
1264  get_modrm(*data, &mod, &regop, &rm);
1265  AppendToBuffer("andpd %s,%s",
1266  NameOfXMMRegister(regop),
1267  NameOfXMMRegister(rm));
1268  data++;
1269  } else if (*data == 0x57) {
1270  data++;
1271  int mod, regop, rm;
1272  get_modrm(*data, &mod, &regop, &rm);
1273  AppendToBuffer("xorpd %s,%s",
1274  NameOfXMMRegister(regop),
1275  NameOfXMMRegister(rm));
1276  data++;
1277  } else if (*data == 0x6E) {
1278  data++;
1279  int mod, regop, rm;
1280  get_modrm(*data, &mod, &regop, &rm);
1281  AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1282  data += PrintRightOperand(data);
1283  } else if (*data == 0x6F) {
1284  data++;
1285  int mod, regop, rm;
1286  get_modrm(*data, &mod, &regop, &rm);
1287  AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
1288  data += PrintRightXMMOperand(data);
1289  } else if (*data == 0x70) {
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("pshufd %s,%s,%d",
1295  NameOfXMMRegister(regop),
1296  NameOfXMMRegister(rm),
1297  static_cast<int>(imm8));
1298  data += 2;
1299  } else if (*data == 0x90) {
1300  data++;
1301  AppendToBuffer("nop"); // 2 byte nop.
1302  } else if (*data == 0xF3) {
1303  data++;
1304  int mod, regop, rm;
1305  get_modrm(*data, &mod, &regop, &rm);
1306  AppendToBuffer("psllq %s,%s",
1307  NameOfXMMRegister(regop),
1308  NameOfXMMRegister(rm));
1309  data++;
1310  } else if (*data == 0x73) {
1311  data++;
1312  int mod, regop, rm;
1313  get_modrm(*data, &mod, &regop, &rm);
1314  int8_t imm8 = static_cast<int8_t>(data[1]);
1315  ASSERT(regop == esi || regop == edx);
1316  AppendToBuffer("%s %s,%d",
1317  (regop == esi) ? "psllq" : "psrlq",
1318  NameOfXMMRegister(rm),
1319  static_cast<int>(imm8));
1320  data += 2;
1321  } else if (*data == 0xD3) {
1322  data++;
1323  int mod, regop, rm;
1324  get_modrm(*data, &mod, &regop, &rm);
1325  AppendToBuffer("psrlq %s,%s",
1326  NameOfXMMRegister(regop),
1327  NameOfXMMRegister(rm));
1328  data++;
1329  } else if (*data == 0x7F) {
1330  AppendToBuffer("movdqa ");
1331  data++;
1332  int mod, regop, rm;
1333  get_modrm(*data, &mod, &regop, &rm);
1334  data += PrintRightXMMOperand(data);
1335  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1336  } else if (*data == 0x7E) {
1337  data++;
1338  int mod, regop, rm;
1339  get_modrm(*data, &mod, &regop, &rm);
1340  AppendToBuffer("movd ");
1341  data += PrintRightOperand(data);
1342  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1343  } else if (*data == 0xDB) {
1344  data++;
1345  int mod, regop, rm;
1346  get_modrm(*data, &mod, &regop, &rm);
1347  AppendToBuffer("pand %s,%s",
1348  NameOfXMMRegister(regop),
1349  NameOfXMMRegister(rm));
1350  data++;
1351  } else if (*data == 0xE7) {
1352  data++;
1353  int mod, regop, rm;
1354  get_modrm(*data, &mod, &regop, &rm);
1355  if (mod == 3) {
1356  AppendToBuffer("movntdq ");
1357  data += PrintRightOperand(data);
1358  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1359  } else {
1360  UnimplementedInstruction();
1361  }
1362  } else if (*data == 0xEF) {
1363  data++;
1364  int mod, regop, rm;
1365  get_modrm(*data, &mod, &regop, &rm);
1366  AppendToBuffer("pxor %s,%s",
1367  NameOfXMMRegister(regop),
1368  NameOfXMMRegister(rm));
1369  data++;
1370  } else if (*data == 0xEB) {
1371  data++;
1372  int mod, regop, rm;
1373  get_modrm(*data, &mod, &regop, &rm);
1374  AppendToBuffer("por %s,%s",
1375  NameOfXMMRegister(regop),
1376  NameOfXMMRegister(rm));
1377  data++;
1378  } else {
1379  UnimplementedInstruction();
1380  }
1381  } else {
1382  UnimplementedInstruction();
1383  }
1384  break;
1385 
1386  case 0xFE:
1387  { data++;
1388  int mod, regop, rm;
1389  get_modrm(*data, &mod, &regop, &rm);
1390  if (regop == ecx) {
1391  AppendToBuffer("dec_b ");
1392  data += PrintRightOperand(data);
1393  } else {
1394  UnimplementedInstruction();
1395  }
1396  }
1397  break;
1398 
1399  case 0x68:
1400  AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1401  data += 5;
1402  break;
1403 
1404  case 0x6A:
1405  AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1406  data += 2;
1407  break;
1408 
1409  case 0xA8:
1410  AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1411  data += 2;
1412  break;
1413 
1414  case 0xA9:
1415  AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1416  data += 5;
1417  break;
1418 
1419  case 0xD1: // fall through
1420  case 0xD3: // fall through
1421  case 0xC1:
1422  data += D1D3C1Instruction(data);
1423  break;
1424 
1425  case 0xD9: // fall through
1426  case 0xDA: // fall through
1427  case 0xDB: // fall through
1428  case 0xDC: // fall through
1429  case 0xDD: // fall through
1430  case 0xDE: // fall through
1431  case 0xDF:
1432  data += FPUInstruction(data);
1433  break;
1434 
1435  case 0xEB:
1436  data += JumpShort(data);
1437  break;
1438 
1439  case 0xF2:
1440  if (*(data+1) == 0x0F) {
1441  byte b2 = *(data+2);
1442  if (b2 == 0x11) {
1443  AppendToBuffer("movsd ");
1444  data += 3;
1445  int mod, regop, rm;
1446  get_modrm(*data, &mod, &regop, &rm);
1447  data += PrintRightXMMOperand(data);
1448  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1449  } else if (b2 == 0x10) {
1450  data += 3;
1451  int mod, regop, rm;
1452  get_modrm(*data, &mod, &regop, &rm);
1453  AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
1454  data += PrintRightXMMOperand(data);
1455  } else if (b2 == 0x5A) {
1456  data += 3;
1457  int mod, regop, rm;
1458  get_modrm(*data, &mod, &regop, &rm);
1459  AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
1460  data += PrintRightXMMOperand(data);
1461  } else {
1462  const char* mnem = "?";
1463  switch (b2) {
1464  case 0x2A: mnem = "cvtsi2sd"; break;
1465  case 0x2C: mnem = "cvttsd2si"; break;
1466  case 0x51: mnem = "sqrtsd"; break;
1467  case 0x58: mnem = "addsd"; break;
1468  case 0x59: mnem = "mulsd"; break;
1469  case 0x5C: mnem = "subsd"; break;
1470  case 0x5E: mnem = "divsd"; break;
1471  }
1472  data += 3;
1473  int mod, regop, rm;
1474  get_modrm(*data, &mod, &regop, &rm);
1475  if (b2 == 0x2A) {
1476  AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1477  data += PrintRightOperand(data);
1478  } else if (b2 == 0x2C) {
1479  AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
1480  data += PrintRightXMMOperand(data);
1481  } else if (b2 == 0xC2) {
1482  // Intel manual 2A, Table 3-18.
1483  const char* const pseudo_op[] = {
1484  "cmpeqsd",
1485  "cmpltsd",
1486  "cmplesd",
1487  "cmpunordsd",
1488  "cmpneqsd",
1489  "cmpnltsd",
1490  "cmpnlesd",
1491  "cmpordsd"
1492  };
1493  AppendToBuffer("%s %s,%s",
1494  pseudo_op[data[1]],
1495  NameOfXMMRegister(regop),
1496  NameOfXMMRegister(rm));
1497  data += 2;
1498  } else {
1499  AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1500  data += PrintRightXMMOperand(data);
1501  }
1502  }
1503  } else {
1504  UnimplementedInstruction();
1505  }
1506  break;
1507 
1508  case 0xF3:
1509  if (*(data+1) == 0x0F) {
1510  byte b2 = *(data+2);
1511  if (b2 == 0x11) {
1512  AppendToBuffer("movss ");
1513  data += 3;
1514  int mod, regop, rm;
1515  get_modrm(*data, &mod, &regop, &rm);
1516  data += PrintRightXMMOperand(data);
1517  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1518  } else if (b2 == 0x10) {
1519  data += 3;
1520  int mod, regop, rm;
1521  get_modrm(*data, &mod, &regop, &rm);
1522  AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
1523  data += PrintRightXMMOperand(data);
1524  } else if (b2 == 0x2C) {
1525  data += 3;
1526  int mod, regop, rm;
1527  get_modrm(*data, &mod, &regop, &rm);
1528  AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
1529  data += PrintRightXMMOperand(data);
1530  } else if (b2 == 0x5A) {
1531  data += 3;
1532  int mod, regop, rm;
1533  get_modrm(*data, &mod, &regop, &rm);
1534  AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1535  data += PrintRightXMMOperand(data);
1536  } else if (b2 == 0x6F) {
1537  data += 3;
1538  int mod, regop, rm;
1539  get_modrm(*data, &mod, &regop, &rm);
1540  AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
1541  data += PrintRightXMMOperand(data);
1542  } else if (b2 == 0x7F) {
1543  AppendToBuffer("movdqu ");
1544  data += 3;
1545  int mod, regop, rm;
1546  get_modrm(*data, &mod, &regop, &rm);
1547  data += PrintRightXMMOperand(data);
1548  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1549  } else {
1550  UnimplementedInstruction();
1551  }
1552  } else if (*(data+1) == 0xA5) {
1553  data += 2;
1554  AppendToBuffer("rep_movs");
1555  } else if (*(data+1) == 0xAB) {
1556  data += 2;
1557  AppendToBuffer("rep_stos");
1558  } else {
1559  UnimplementedInstruction();
1560  }
1561  break;
1562 
1563  case 0xF7:
1564  data += F7Instruction(data);
1565  break;
1566 
1567  default:
1568  UnimplementedInstruction();
1569  }
1570  }
1571 
1572  if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1573  tmp_buffer_[tmp_buffer_pos_] = '\0';
1574  }
1575 
1576  int instr_len = data - instr;
1577  if (instr_len == 0) {
1578  printf("%02x", *data);
1579  }
1580  ASSERT(instr_len > 0); // Ensure progress.
1581 
1582  int outp = 0;
1583  // Instruction bytes.
1584  for (byte* bp = instr; bp < data; bp++) {
1585  outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1586  "%02x",
1587  *bp);
1588  }
1589  for (int i = 6 - instr_len; i >= 0; i--) {
1590  outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1591  " ");
1592  }
1593 
1594  outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1595  " %s",
1596  tmp_buffer_.start());
1597  return instr_len;
1598 } // NOLINT (function is too long)
1599 
1600 
1601 //------------------------------------------------------------------------------
1602 
1603 
1604 static const char* cpu_regs[8] = {
1605  "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
1606 };
1607 
1608 
1609 static const char* byte_cpu_regs[8] = {
1610  "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
1611 };
1612 
1613 
1614 static const char* xmm_regs[8] = {
1615  "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
1616 };
1617 
1618 
1619 const char* NameConverter::NameOfAddress(byte* addr) const {
1621  return tmp_buffer_.start();
1622 }
1623 
1624 
1625 const char* NameConverter::NameOfConstant(byte* addr) const {
1626  return NameOfAddress(addr);
1627 }
1628 
1629 
1630 const char* NameConverter::NameOfCPURegister(int reg) const {
1631  if (0 <= reg && reg < 8) return cpu_regs[reg];
1632  return "noreg";
1633 }
1634 
1635 
1636 const char* NameConverter::NameOfByteCPURegister(int reg) const {
1637  if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
1638  return "noreg";
1639 }
1640 
1641 
1642 const char* NameConverter::NameOfXMMRegister(int reg) const {
1643  if (0 <= reg && reg < 8) return xmm_regs[reg];
1644  return "noxmmreg";
1645 }
1646 
1647 
1648 const char* NameConverter::NameInCode(byte* addr) const {
1649  // IA32 does not embed debug strings at the moment.
1650  UNREACHABLE();
1651  return "";
1652 }
1653 
1654 
1655 //------------------------------------------------------------------------------
1656 
1657 Disassembler::Disassembler(const NameConverter& converter)
1658  : converter_(converter) {}
1659 
1660 
1661 Disassembler::~Disassembler() {}
1662 
1663 
1664 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1665  byte* instruction) {
1666  DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
1667  return d.InstructionDecode(buffer, instruction);
1668 }
1669 
1670 
1671 // The IA-32 assembler does not currently use constant pools.
1672 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
1673 
1674 
1675 /*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1676  NameConverter converter;
1677  Disassembler d(converter);
1678  for (byte* pc = begin; pc < end;) {
1680  buffer[0] = '\0';
1681  byte* prev_pc = pc;
1682  pc += d.InstructionDecode(buffer, pc);
1683  fprintf(f, "%p", prev_pc);
1684  fprintf(f, " ");
1685 
1686  for (byte* bp = prev_pc; bp < pc; bp++) {
1687  fprintf(f, "%02x", *bp);
1688  }
1689  for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
1690  fprintf(f, " ");
1691  }
1692  fprintf(f, " %s\n", buffer.start());
1693  }
1694 }
1695 
1696 
1697 } // namespace disasm
1698 
1699 #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
const char * comment() const
Definition: flags.cc:1362
virtual const char * NameInCode(byte *addr) const
virtual const char * NameOfByteCPURegister(int reg) const
const Register edi
uint8_t byte
Definition: globals.h:171
const Register ebp
#define UNREACHABLE()
Definition: checks.h:50
T * start() const
Definition: utils.h:389
virtual const char * NameOfCPURegister(int reg) const
const Register eax
activate correct semantics for inheriting readonliness enable harmony semantics for typeof enable harmony enable harmony proxies enable all harmony harmony_scoping harmony_proxies harmony_scoping tracks arrays with only smi values automatically unbox arrays of doubles use crankshaft use hydrogen range analysis use hydrogen global value numbering use function inlining maximum number of AST nodes considered for a single inlining loop invariant code motion print statistics for hydrogen trace generated IR for specified phases trace register allocator trace range analysis trace representation types environment for every instruction put a break point before deoptimizing polymorphic inlining perform array bounds checks elimination trace on stack replacement optimize closures functions with arguments object optimize functions containing for in loops profiler considers IC stability primitive functions trigger their own optimization re try self optimization if it failed insert an interrupt check at function exit execution budget before interrupt is triggered call count before self optimization self_optimization count_based_interrupts weighted_back_edges trace_opt emit comments in code disassembly enable use of SSE3 instructions if available enable use of CMOV instruction if available enable use of SAHF instruction if enable use of VFP3 instructions if available this implies enabling ARMv7 enable use of ARMv7 instructions if enable use of MIPS FPU instructions if NULL
const Register 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
#define ASSERT_NE(v1, v2)
Definition: checks.h:272
const Register edx
FlagType type() const
Definition: flags.cc:1358