v8  3.25.30(node0.11.13)
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 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%s0x%x]",
411  (this->*register_name)(index),
412  1 << scale,
413  disp < 0 ? "-" : "+",
414  disp < 0 ? -disp : disp);
415  return 6;
416  } else if (index != esp && base != ebp) {
417  // [base+index*scale]
418  AppendToBuffer("[%s+%s*%d]",
419  (this->*register_name)(base),
420  (this->*register_name)(index),
421  1 << scale);
422  return 2;
423  } else {
424  UnimplementedInstruction();
425  return 1;
426  }
427  } else {
428  AppendToBuffer("[%s]", (this->*register_name)(rm));
429  return 1;
430  }
431  break;
432  case 1: // fall through
433  case 2:
434  if (rm == esp) {
435  byte sib = *(modrmp + 1);
436  int scale, index, base;
437  get_sib(sib, &scale, &index, &base);
438  int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2)
439  : *reinterpret_cast<int8_t*>(modrmp + 2);
440  if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
441  AppendToBuffer("[%s%s0x%x]",
442  (this->*register_name)(rm),
443  disp < 0 ? "-" : "+",
444  disp < 0 ? -disp : disp);
445  } else {
446  AppendToBuffer("[%s+%s*%d%s0x%x]",
447  (this->*register_name)(base),
448  (this->*register_name)(index),
449  1 << scale,
450  disp < 0 ? "-" : "+",
451  disp < 0 ? -disp : disp);
452  }
453  return mod == 2 ? 6 : 3;
454  } else {
455  // No sib.
456  int disp = mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1)
457  : *reinterpret_cast<int8_t*>(modrmp + 1);
458  AppendToBuffer("[%s%s0x%x]",
459  (this->*register_name)(rm),
460  disp < 0 ? "-" : "+",
461  disp < 0 ? -disp : disp);
462  return mod == 2 ? 5 : 2;
463  }
464  break;
465  case 3:
466  AppendToBuffer("%s", (this->*register_name)(rm));
467  return 1;
468  default:
469  UnimplementedInstruction();
470  return 1;
471  }
472  UNREACHABLE();
473 }
474 
475 
476 int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
477  return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
478 }
479 
480 
481 int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
482  return PrintRightOperandHelper(modrmp,
483  &DisassemblerIA32::NameOfByteCPURegister);
484 }
485 
486 
487 int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
488  return PrintRightOperandHelper(modrmp,
489  &DisassemblerIA32::NameOfXMMRegister);
490 }
491 
492 
493 // Returns number of bytes used including the current *data.
494 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
495 int DisassemblerIA32::PrintOperands(const char* mnem,
496  OperandOrder op_order,
497  byte* data) {
498  byte modrm = *data;
499  int mod, regop, rm;
500  get_modrm(modrm, &mod, &regop, &rm);
501  int advance = 0;
502  switch (op_order) {
503  case REG_OPER_OP_ORDER: {
504  AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
505  advance = PrintRightOperand(data);
506  break;
507  }
508  case OPER_REG_OP_ORDER: {
509  AppendToBuffer("%s ", mnem);
510  advance = PrintRightOperand(data);
511  AppendToBuffer(",%s", NameOfCPURegister(regop));
512  break;
513  }
514  default:
515  UNREACHABLE();
516  break;
517  }
518  return advance;
519 }
520 
521 
522 // Returns number of bytes used by machine instruction, including *data byte.
523 // Writes immediate instructions to 'tmp_buffer_'.
524 int DisassemblerIA32::PrintImmediateOp(byte* data) {
525  bool sign_extension_bit = (*data & 0x02) != 0;
526  byte modrm = *(data+1);
527  int mod, regop, rm;
528  get_modrm(modrm, &mod, &regop, &rm);
529  const char* mnem = "Imm???";
530  switch (regop) {
531  case 0: mnem = "add"; break;
532  case 1: mnem = "or"; break;
533  case 2: mnem = "adc"; break;
534  case 4: mnem = "and"; break;
535  case 5: mnem = "sub"; break;
536  case 6: mnem = "xor"; break;
537  case 7: mnem = "cmp"; break;
538  default: UnimplementedInstruction();
539  }
540  AppendToBuffer("%s ", mnem);
541  int count = PrintRightOperand(data+1);
542  if (sign_extension_bit) {
543  AppendToBuffer(",0x%x", *(data + 1 + count));
544  return 1 + count + 1 /*int8*/;
545  } else {
546  AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
547  return 1 + count + 4 /*int32_t*/;
548  }
549 }
550 
551 
552 // Returns number of bytes used, including *data.
553 int DisassemblerIA32::F7Instruction(byte* data) {
554  ASSERT_EQ(0xF7, *data);
555  byte modrm = *(data+1);
556  int mod, regop, rm;
557  get_modrm(modrm, &mod, &regop, &rm);
558  if (mod == 3 && regop != 0) {
559  const char* mnem = NULL;
560  switch (regop) {
561  case 2: mnem = "not"; break;
562  case 3: mnem = "neg"; break;
563  case 4: mnem = "mul"; break;
564  case 5: mnem = "imul"; break;
565  case 7: mnem = "idiv"; break;
566  default: UnimplementedInstruction();
567  }
568  AppendToBuffer("%s %s", mnem, NameOfCPURegister(rm));
569  return 2;
570  } else if (mod == 3 && regop == eax) {
571  int32_t imm = *reinterpret_cast<int32_t*>(data+2);
572  AppendToBuffer("test %s,0x%x", NameOfCPURegister(rm), imm);
573  return 6;
574  } else if (regop == eax) {
575  AppendToBuffer("test ");
576  int count = PrintRightOperand(data+1);
577  int32_t imm = *reinterpret_cast<int32_t*>(data+1+count);
578  AppendToBuffer(",0x%x", imm);
579  return 1+count+4 /*int32_t*/;
580  } else {
581  UnimplementedInstruction();
582  return 2;
583  }
584 }
585 
586 
587 int DisassemblerIA32::D1D3C1Instruction(byte* data) {
588  byte op = *data;
589  ASSERT(op == 0xD1 || op == 0xD3 || op == 0xC1);
590  byte modrm = *(data+1);
591  int mod, regop, rm;
592  get_modrm(modrm, &mod, &regop, &rm);
593  int imm8 = -1;
594  int num_bytes = 2;
595  if (mod == 3) {
596  const char* mnem = NULL;
597  switch (regop) {
598  case kROL: mnem = "rol"; break;
599  case kROR: mnem = "ror"; break;
600  case kRCL: mnem = "rcl"; break;
601  case kRCR: mnem = "rcr"; break;
602  case kSHL: mnem = "shl"; break;
603  case KSHR: mnem = "shr"; break;
604  case kSAR: mnem = "sar"; break;
605  default: UnimplementedInstruction();
606  }
607  if (op == 0xD1) {
608  imm8 = 1;
609  } else if (op == 0xC1) {
610  imm8 = *(data+2);
611  num_bytes = 3;
612  } else if (op == 0xD3) {
613  // Shift/rotate by cl.
614  }
615  ASSERT_NE(NULL, mnem);
616  AppendToBuffer("%s %s,", mnem, NameOfCPURegister(rm));
617  if (imm8 >= 0) {
618  AppendToBuffer("%d", imm8);
619  } else {
620  AppendToBuffer("cl");
621  }
622  } else {
623  UnimplementedInstruction();
624  }
625  return num_bytes;
626 }
627 
628 
629 // Returns number of bytes used, including *data.
630 int DisassemblerIA32::JumpShort(byte* data) {
631  ASSERT_EQ(0xEB, *data);
632  byte b = *(data+1);
633  byte* dest = data + static_cast<int8_t>(b) + 2;
634  AppendToBuffer("jmp %s", NameOfAddress(dest));
635  return 2;
636 }
637 
638 
639 // Returns number of bytes used, including *data.
640 int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
641  ASSERT_EQ(0x0F, *data);
642  byte cond = *(data+1) & 0x0F;
643  byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
644  const char* mnem = jump_conditional_mnem[cond];
645  AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
646  if (comment != NULL) {
647  AppendToBuffer(", %s", comment);
648  }
649  return 6; // includes 0x0F
650 }
651 
652 
653 // Returns number of bytes used, including *data.
654 int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
655  byte cond = *data & 0x0F;
656  byte b = *(data+1);
657  byte* dest = data + static_cast<int8_t>(b) + 2;
658  const char* mnem = jump_conditional_mnem[cond];
659  AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
660  if (comment != NULL) {
661  AppendToBuffer(", %s", comment);
662  }
663  return 2;
664 }
665 
666 
667 // Returns number of bytes used, including *data.
668 int DisassemblerIA32::SetCC(byte* data) {
669  ASSERT_EQ(0x0F, *data);
670  byte cond = *(data+1) & 0x0F;
671  const char* mnem = set_conditional_mnem[cond];
672  AppendToBuffer("%s ", mnem);
673  PrintRightByteOperand(data+2);
674  return 3; // Includes 0x0F.
675 }
676 
677 
678 // Returns number of bytes used, including *data.
679 int DisassemblerIA32::CMov(byte* data) {
680  ASSERT_EQ(0x0F, *data);
681  byte cond = *(data + 1) & 0x0F;
682  const char* mnem = conditional_move_mnem[cond];
683  int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
684  return 2 + op_size; // includes 0x0F
685 }
686 
687 
688 // Returns number of bytes used, including *data.
689 int DisassemblerIA32::FPUInstruction(byte* data) {
690  byte escape_opcode = *data;
691  ASSERT_EQ(0xD8, escape_opcode & 0xF8);
692  byte modrm_byte = *(data+1);
693 
694  if (modrm_byte >= 0xC0) {
695  return RegisterFPUInstruction(escape_opcode, modrm_byte);
696  } else {
697  return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
698  }
699 }
700 
701 int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
702  int modrm_byte,
703  byte* modrm_start) {
704  const char* mnem = "?";
705  int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
706  switch (escape_opcode) {
707  case 0xD9: switch (regop) {
708  case 0: mnem = "fld_s"; break;
709  case 2: mnem = "fst_s"; break;
710  case 3: mnem = "fstp_s"; break;
711  case 7: mnem = "fstcw"; break;
712  default: UnimplementedInstruction();
713  }
714  break;
715 
716  case 0xDB: switch (regop) {
717  case 0: mnem = "fild_s"; break;
718  case 1: mnem = "fisttp_s"; break;
719  case 2: mnem = "fist_s"; break;
720  case 3: mnem = "fistp_s"; break;
721  default: UnimplementedInstruction();
722  }
723  break;
724 
725  case 0xDD: switch (regop) {
726  case 0: mnem = "fld_d"; break;
727  case 1: mnem = "fisttp_d"; break;
728  case 2: mnem = "fst_d"; break;
729  case 3: mnem = "fstp_d"; break;
730  default: UnimplementedInstruction();
731  }
732  break;
733 
734  case 0xDF: switch (regop) {
735  case 5: mnem = "fild_d"; break;
736  case 7: mnem = "fistp_d"; break;
737  default: UnimplementedInstruction();
738  }
739  break;
740 
741  default: UnimplementedInstruction();
742  }
743  AppendToBuffer("%s ", mnem);
744  int count = PrintRightOperand(modrm_start);
745  return count + 1;
746 }
747 
748 int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
749  byte modrm_byte) {
750  bool has_register = false; // Is the FPU register encoded in modrm_byte?
751  const char* mnem = "?";
752 
753  switch (escape_opcode) {
754  case 0xD8:
755  has_register = true;
756  switch (modrm_byte & 0xF8) {
757  case 0xC0: mnem = "fadd_i"; break;
758  case 0xE0: mnem = "fsub_i"; break;
759  case 0xC8: mnem = "fmul_i"; break;
760  case 0xF0: mnem = "fdiv_i"; break;
761  default: UnimplementedInstruction();
762  }
763  break;
764 
765  case 0xD9:
766  switch (modrm_byte & 0xF8) {
767  case 0xC0:
768  mnem = "fld";
769  has_register = true;
770  break;
771  case 0xC8:
772  mnem = "fxch";
773  has_register = true;
774  break;
775  default:
776  switch (modrm_byte) {
777  case 0xE0: mnem = "fchs"; break;
778  case 0xE1: mnem = "fabs"; break;
779  case 0xE4: mnem = "ftst"; break;
780  case 0xE8: mnem = "fld1"; break;
781  case 0xEB: mnem = "fldpi"; break;
782  case 0xED: mnem = "fldln2"; break;
783  case 0xEE: mnem = "fldz"; break;
784  case 0xF0: mnem = "f2xm1"; break;
785  case 0xF1: mnem = "fyl2x"; break;
786  case 0xF4: mnem = "fxtract"; break;
787  case 0xF5: mnem = "fprem1"; break;
788  case 0xF7: mnem = "fincstp"; break;
789  case 0xF8: mnem = "fprem"; break;
790  case 0xFC: mnem = "frndint"; break;
791  case 0xFD: mnem = "fscale"; break;
792  case 0xFE: mnem = "fsin"; break;
793  case 0xFF: mnem = "fcos"; break;
794  default: UnimplementedInstruction();
795  }
796  }
797  break;
798 
799  case 0xDA:
800  if (modrm_byte == 0xE9) {
801  mnem = "fucompp";
802  } else {
803  UnimplementedInstruction();
804  }
805  break;
806 
807  case 0xDB:
808  if ((modrm_byte & 0xF8) == 0xE8) {
809  mnem = "fucomi";
810  has_register = true;
811  } else if (modrm_byte == 0xE2) {
812  mnem = "fclex";
813  } else if (modrm_byte == 0xE3) {
814  mnem = "fninit";
815  } else {
816  UnimplementedInstruction();
817  }
818  break;
819 
820  case 0xDC:
821  has_register = true;
822  switch (modrm_byte & 0xF8) {
823  case 0xC0: mnem = "fadd"; break;
824  case 0xE8: mnem = "fsub"; break;
825  case 0xC8: mnem = "fmul"; break;
826  case 0xF8: mnem = "fdiv"; break;
827  default: UnimplementedInstruction();
828  }
829  break;
830 
831  case 0xDD:
832  has_register = true;
833  switch (modrm_byte & 0xF8) {
834  case 0xC0: mnem = "ffree"; break;
835  case 0xD0: mnem = "fst"; break;
836  case 0xD8: mnem = "fstp"; break;
837  default: UnimplementedInstruction();
838  }
839  break;
840 
841  case 0xDE:
842  if (modrm_byte == 0xD9) {
843  mnem = "fcompp";
844  } else {
845  has_register = true;
846  switch (modrm_byte & 0xF8) {
847  case 0xC0: mnem = "faddp"; break;
848  case 0xE8: mnem = "fsubp"; break;
849  case 0xC8: mnem = "fmulp"; break;
850  case 0xF8: mnem = "fdivp"; break;
851  default: UnimplementedInstruction();
852  }
853  }
854  break;
855 
856  case 0xDF:
857  if (modrm_byte == 0xE0) {
858  mnem = "fnstsw_ax";
859  } else if ((modrm_byte & 0xF8) == 0xE8) {
860  mnem = "fucomip";
861  has_register = true;
862  }
863  break;
864 
865  default: UnimplementedInstruction();
866  }
867 
868  if (has_register) {
869  AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
870  } else {
871  AppendToBuffer("%s", mnem);
872  }
873  return 2;
874 }
875 
876 
877 // Mnemonics for instructions 0xF0 byte.
878 // Returns NULL if the instruction is not handled here.
879 static const char* F0Mnem(byte f0byte) {
880  switch (f0byte) {
881  case 0x18: return "prefetch";
882  case 0xA2: return "cpuid";
883  case 0xBE: return "movsx_b";
884  case 0xBF: return "movsx_w";
885  case 0xB6: return "movzx_b";
886  case 0xB7: return "movzx_w";
887  case 0xAF: return "imul";
888  case 0xA5: return "shld";
889  case 0xAD: return "shrd";
890  case 0xAC: return "shrd"; // 3-operand version.
891  case 0xAB: return "bts";
892  case 0xBD: return "bsr";
893  default: return NULL;
894  }
895 }
896 
897 
898 // Disassembled instruction '*instr' and writes it into 'out_buffer'.
899 int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
900  byte* instr) {
901  tmp_buffer_pos_ = 0; // starting to write as position 0
902  byte* data = instr;
903  // Check for hints.
904  const char* branch_hint = NULL;
905  // We use these two prefixes only with branch prediction
906  if (*data == 0x3E /*ds*/) {
907  branch_hint = "predicted taken";
908  data++;
909  } else if (*data == 0x2E /*cs*/) {
910  branch_hint = "predicted not taken";
911  data++;
912  }
913  bool processed = true; // Will be set to false if the current instruction
914  // is not in 'instructions' table.
915  const InstructionDesc& idesc = instruction_table_->Get(*data);
916  switch (idesc.type) {
917  case ZERO_OPERANDS_INSTR:
918  AppendToBuffer(idesc.mnem);
919  data++;
920  break;
921 
922  case TWO_OPERANDS_INSTR:
923  data++;
924  data += PrintOperands(idesc.mnem, idesc.op_order_, data);
925  break;
926 
927  case JUMP_CONDITIONAL_SHORT_INSTR:
928  data += JumpConditionalShort(data, branch_hint);
929  break;
930 
931  case REGISTER_INSTR:
932  AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
933  data++;
934  break;
935 
936  case MOVE_REG_INSTR: {
937  byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
938  AppendToBuffer("mov %s,%s",
939  NameOfCPURegister(*data & 0x07),
940  NameOfAddress(addr));
941  data += 5;
942  break;
943  }
944 
945  case CALL_JUMP_INSTR: {
946  byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5;
947  AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
948  data += 5;
949  break;
950  }
951 
952  case SHORT_IMMEDIATE_INSTR: {
953  byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
954  AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
955  data += 5;
956  break;
957  }
958 
959  case BYTE_IMMEDIATE_INSTR: {
960  AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
961  data += 2;
962  break;
963  }
964 
965  case NO_INSTR:
966  processed = false;
967  break;
968 
969  default:
970  UNIMPLEMENTED(); // This type is not implemented.
971  }
972  //----------------------------
973  if (!processed) {
974  switch (*data) {
975  case 0xC2:
976  AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
977  data += 3;
978  break;
979 
980  case 0x69: // fall through
981  case 0x6B:
982  { int mod, regop, rm;
983  get_modrm(*(data+1), &mod, &regop, &rm);
984  int32_t imm =
985  *data == 0x6B ? *(data+2) : *reinterpret_cast<int32_t*>(data+2);
986  AppendToBuffer("imul %s,%s,0x%x",
987  NameOfCPURegister(regop),
988  NameOfCPURegister(rm),
989  imm);
990  data += 2 + (*data == 0x6B ? 1 : 4);
991  }
992  break;
993 
994  case 0xF6:
995  { data++;
996  int mod, regop, rm;
997  get_modrm(*data, &mod, &regop, &rm);
998  if (regop == eax) {
999  AppendToBuffer("test_b ");
1000  data += PrintRightByteOperand(data);
1001  int32_t imm = *data;
1002  AppendToBuffer(",0x%x", imm);
1003  data++;
1004  } else {
1005  UnimplementedInstruction();
1006  }
1007  }
1008  break;
1009 
1010  case 0x81: // fall through
1011  case 0x83: // 0x81 with sign extension bit set
1012  data += PrintImmediateOp(data);
1013  break;
1014 
1015  case 0x0F:
1016  { byte f0byte = data[1];
1017  const char* f0mnem = F0Mnem(f0byte);
1018  if (f0byte == 0x18) {
1019  data += 2;
1020  int mod, regop, rm;
1021  get_modrm(*data, &mod, &regop, &rm);
1022  const char* suffix[] = {"nta", "1", "2", "3"};
1023  AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1024  data += PrintRightOperand(data);
1025  } else if (f0byte == 0x1F && data[2] == 0) {
1026  AppendToBuffer("nop"); // 3 byte nop.
1027  data += 3;
1028  } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1029  AppendToBuffer("nop"); // 4 byte nop.
1030  data += 4;
1031  } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1032  data[4] == 0) {
1033  AppendToBuffer("nop"); // 5 byte nop.
1034  data += 5;
1035  } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1036  data[4] == 0 && data[5] == 0 && data[6] == 0) {
1037  AppendToBuffer("nop"); // 7 byte nop.
1038  data += 7;
1039  } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1040  data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1041  data[7] == 0) {
1042  AppendToBuffer("nop"); // 8 byte nop.
1043  data += 8;
1044  } else if (f0byte == 0xA2 || f0byte == 0x31) {
1045  AppendToBuffer("%s", f0mnem);
1046  data += 2;
1047  } else if (f0byte == 0x28) {
1048  data += 2;
1049  int mod, regop, rm;
1050  get_modrm(*data, &mod, &regop, &rm);
1051  AppendToBuffer("movaps %s,%s",
1052  NameOfXMMRegister(regop),
1053  NameOfXMMRegister(rm));
1054  data++;
1055  } else if (f0byte >= 0x53 && f0byte <= 0x5F) {
1056  const char* const pseudo_op[] = {
1057  "rcpps",
1058  "andps",
1059  "andnps",
1060  "orps",
1061  "xorps",
1062  "addps",
1063  "mulps",
1064  "cvtps2pd",
1065  "cvtdq2ps",
1066  "subps",
1067  "minps",
1068  "divps",
1069  "maxps",
1070  };
1071 
1072  data += 2;
1073  int mod, regop, rm;
1074  get_modrm(*data, &mod, &regop, &rm);
1075  AppendToBuffer("%s %s,",
1076  pseudo_op[f0byte - 0x53],
1077  NameOfXMMRegister(regop));
1078  data += PrintRightXMMOperand(data);
1079  } else if (f0byte == 0x50) {
1080  data += 2;
1081  int mod, regop, rm;
1082  get_modrm(*data, &mod, &regop, &rm);
1083  AppendToBuffer("movmskps %s,%s",
1084  NameOfCPURegister(regop),
1085  NameOfXMMRegister(rm));
1086  data++;
1087  } else if (f0byte== 0xC6) {
1088  // shufps xmm, xmm/m128, imm8
1089  data += 2;
1090  int mod, regop, rm;
1091  get_modrm(*data, &mod, &regop, &rm);
1092  int8_t imm8 = static_cast<int8_t>(data[1]);
1093  AppendToBuffer("shufps %s,%s,%d",
1094  NameOfXMMRegister(rm),
1095  NameOfXMMRegister(regop),
1096  static_cast<int>(imm8));
1097  data += 2;
1098  } else if ((f0byte & 0xF0) == 0x80) {
1099  data += JumpConditional(data, branch_hint);
1100  } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1101  f0byte == 0xB7 || f0byte == 0xAF) {
1102  data += 2;
1103  data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1104  } else if ((f0byte & 0xF0) == 0x90) {
1105  data += SetCC(data);
1106  } else if ((f0byte & 0xF0) == 0x40) {
1107  data += CMov(data);
1108  } else if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1109  // shrd, shld, bts
1110  data += 2;
1111  AppendToBuffer("%s ", f0mnem);
1112  int mod, regop, rm;
1113  get_modrm(*data, &mod, &regop, &rm);
1114  data += PrintRightOperand(data);
1115  if (f0byte == 0xAB) {
1116  AppendToBuffer(",%s", NameOfCPURegister(regop));
1117  } else {
1118  AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1119  }
1120  } else if (f0byte == 0xBD) {
1121  data += 2;
1122  int mod, regop, rm;
1123  get_modrm(*data, &mod, &regop, &rm);
1124  AppendToBuffer("%s %s,", f0mnem, NameOfCPURegister(regop));
1125  data += PrintRightOperand(data);
1126  } else {
1127  UnimplementedInstruction();
1128  }
1129  }
1130  break;
1131 
1132  case 0x8F:
1133  { data++;
1134  int mod, regop, rm;
1135  get_modrm(*data, &mod, &regop, &rm);
1136  if (regop == eax) {
1137  AppendToBuffer("pop ");
1138  data += PrintRightOperand(data);
1139  }
1140  }
1141  break;
1142 
1143  case 0xFF:
1144  { data++;
1145  int mod, regop, rm;
1146  get_modrm(*data, &mod, &regop, &rm);
1147  const char* mnem = NULL;
1148  switch (regop) {
1149  case esi: mnem = "push"; break;
1150  case eax: mnem = "inc"; break;
1151  case ecx: mnem = "dec"; break;
1152  case edx: mnem = "call"; break;
1153  case esp: mnem = "jmp"; break;
1154  default: mnem = "???";
1155  }
1156  AppendToBuffer("%s ", mnem);
1157  data += PrintRightOperand(data);
1158  }
1159  break;
1160 
1161  case 0xC7: // imm32, fall through
1162  case 0xC6: // imm8
1163  { bool is_byte = *data == 0xC6;
1164  data++;
1165  if (is_byte) {
1166  AppendToBuffer("%s ", "mov_b");
1167  data += PrintRightByteOperand(data);
1168  int32_t imm = *data;
1169  AppendToBuffer(",0x%x", imm);
1170  data++;
1171  } else {
1172  AppendToBuffer("%s ", "mov");
1173  data += PrintRightOperand(data);
1174  int32_t imm = *reinterpret_cast<int32_t*>(data);
1175  AppendToBuffer(",0x%x", imm);
1176  data += 4;
1177  }
1178  }
1179  break;
1180 
1181  case 0x80:
1182  { data++;
1183  int mod, regop, rm;
1184  get_modrm(*data, &mod, &regop, &rm);
1185  const char* mnem = NULL;
1186  switch (regop) {
1187  case 5: mnem = "subb"; break;
1188  case 7: mnem = "cmpb"; break;
1189  default: UnimplementedInstruction();
1190  }
1191  AppendToBuffer("%s ", mnem);
1192  data += PrintRightByteOperand(data);
1193  int32_t imm = *data;
1194  AppendToBuffer(",0x%x", imm);
1195  data++;
1196  }
1197  break;
1198 
1199  case 0x88: // 8bit, fall through
1200  case 0x89: // 32bit
1201  { bool is_byte = *data == 0x88;
1202  int mod, regop, rm;
1203  data++;
1204  get_modrm(*data, &mod, &regop, &rm);
1205  if (is_byte) {
1206  AppendToBuffer("%s ", "mov_b");
1207  data += PrintRightByteOperand(data);
1208  AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1209  } else {
1210  AppendToBuffer("%s ", "mov");
1211  data += PrintRightOperand(data);
1212  AppendToBuffer(",%s", NameOfCPURegister(regop));
1213  }
1214  }
1215  break;
1216 
1217  case 0x66: // prefix
1218  while (*data == 0x66) data++;
1219  if (*data == 0xf && data[1] == 0x1f) {
1220  AppendToBuffer("nop"); // 0x66 prefix
1221  } else if (*data == 0x90) {
1222  AppendToBuffer("nop"); // 0x66 prefix
1223  } else if (*data == 0x8B) {
1224  data++;
1225  data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1226  } else if (*data == 0x89) {
1227  data++;
1228  int mod, regop, rm;
1229  get_modrm(*data, &mod, &regop, &rm);
1230  AppendToBuffer("mov_w ");
1231  data += PrintRightOperand(data);
1232  AppendToBuffer(",%s", NameOfCPURegister(regop));
1233  } else if (*data == 0xC7) {
1234  data++;
1235  AppendToBuffer("%s ", "mov_w");
1236  data += PrintRightOperand(data);
1237  int imm = *reinterpret_cast<int16_t*>(data);
1238  AppendToBuffer(",0x%x", imm);
1239  data += 2;
1240  } else if (*data == 0x0F) {
1241  data++;
1242  if (*data == 0x38) {
1243  data++;
1244  if (*data == 0x17) {
1245  data++;
1246  int mod, regop, rm;
1247  get_modrm(*data, &mod, &regop, &rm);
1248  AppendToBuffer("ptest %s,%s",
1249  NameOfXMMRegister(regop),
1250  NameOfXMMRegister(rm));
1251  data++;
1252  } else if (*data == 0x2A) {
1253  // movntdqa
1254  data++;
1255  int mod, regop, rm;
1256  get_modrm(*data, &mod, &regop, &rm);
1257  AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop));
1258  data += PrintRightOperand(data);
1259  } else {
1260  UnimplementedInstruction();
1261  }
1262  } else if (*data == 0x3A) {
1263  data++;
1264  if (*data == 0x0B) {
1265  data++;
1266  int mod, regop, rm;
1267  get_modrm(*data, &mod, &regop, &rm);
1268  int8_t imm8 = static_cast<int8_t>(data[1]);
1269  AppendToBuffer("roundsd %s,%s,%d",
1270  NameOfXMMRegister(regop),
1271  NameOfXMMRegister(rm),
1272  static_cast<int>(imm8));
1273  data += 2;
1274  } else if (*data == 0x16) {
1275  data++;
1276  int mod, regop, rm;
1277  get_modrm(*data, &mod, &regop, &rm);
1278  int8_t imm8 = static_cast<int8_t>(data[1]);
1279  AppendToBuffer("pextrd %s,%s,%d",
1280  NameOfCPURegister(regop),
1281  NameOfXMMRegister(rm),
1282  static_cast<int>(imm8));
1283  data += 2;
1284  } else if (*data == 0x17) {
1285  data++;
1286  int mod, regop, rm;
1287  get_modrm(*data, &mod, &regop, &rm);
1288  int8_t imm8 = static_cast<int8_t>(data[1]);
1289  AppendToBuffer("extractps %s,%s,%d",
1290  NameOfCPURegister(rm),
1291  NameOfXMMRegister(regop),
1292  static_cast<int>(imm8));
1293  data += 2;
1294  } else if (*data == 0x22) {
1295  data++;
1296  int mod, regop, rm;
1297  get_modrm(*data, &mod, &regop, &rm);
1298  int8_t imm8 = static_cast<int8_t>(data[1]);
1299  AppendToBuffer("pinsrd %s,%s,%d",
1300  NameOfXMMRegister(regop),
1301  NameOfCPURegister(rm),
1302  static_cast<int>(imm8));
1303  data += 2;
1304  } else {
1305  UnimplementedInstruction();
1306  }
1307  } else if (*data == 0x2E || *data == 0x2F) {
1308  const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
1309  data++;
1310  int mod, regop, rm;
1311  get_modrm(*data, &mod, &regop, &rm);
1312  if (mod == 0x3) {
1313  AppendToBuffer("%s %s,%s", mnem,
1314  NameOfXMMRegister(regop),
1315  NameOfXMMRegister(rm));
1316  data++;
1317  } else {
1318  AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1319  data += PrintRightOperand(data);
1320  }
1321  } else if (*data == 0x50) {
1322  data++;
1323  int mod, regop, rm;
1324  get_modrm(*data, &mod, &regop, &rm);
1325  AppendToBuffer("movmskpd %s,%s",
1326  NameOfCPURegister(regop),
1327  NameOfXMMRegister(rm));
1328  data++;
1329  } else if (*data == 0x54) {
1330  data++;
1331  int mod, regop, rm;
1332  get_modrm(*data, &mod, &regop, &rm);
1333  AppendToBuffer("andpd %s,%s",
1334  NameOfXMMRegister(regop),
1335  NameOfXMMRegister(rm));
1336  data++;
1337  } else if (*data == 0x56) {
1338  data++;
1339  int mod, regop, rm;
1340  get_modrm(*data, &mod, &regop, &rm);
1341  AppendToBuffer("orpd %s,%s",
1342  NameOfXMMRegister(regop),
1343  NameOfXMMRegister(rm));
1344  data++;
1345  } else if (*data == 0x57) {
1346  data++;
1347  int mod, regop, rm;
1348  get_modrm(*data, &mod, &regop, &rm);
1349  AppendToBuffer("xorpd %s,%s",
1350  NameOfXMMRegister(regop),
1351  NameOfXMMRegister(rm));
1352  data++;
1353  } else if (*data == 0x6E) {
1354  data++;
1355  int mod, regop, rm;
1356  get_modrm(*data, &mod, &regop, &rm);
1357  AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1358  data += PrintRightOperand(data);
1359  } else if (*data == 0x6F) {
1360  data++;
1361  int mod, regop, rm;
1362  get_modrm(*data, &mod, &regop, &rm);
1363  AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
1364  data += PrintRightXMMOperand(data);
1365  } else if (*data == 0x70) {
1366  data++;
1367  int mod, regop, rm;
1368  get_modrm(*data, &mod, &regop, &rm);
1369  int8_t imm8 = static_cast<int8_t>(data[1]);
1370  AppendToBuffer("pshufd %s,%s,%d",
1371  NameOfXMMRegister(regop),
1372  NameOfXMMRegister(rm),
1373  static_cast<int>(imm8));
1374  data += 2;
1375  } else if (*data == 0x76) {
1376  data++;
1377  int mod, regop, rm;
1378  get_modrm(*data, &mod, &regop, &rm);
1379  AppendToBuffer("pcmpeqd %s,%s",
1380  NameOfXMMRegister(regop),
1381  NameOfXMMRegister(rm));
1382  data++;
1383  } else if (*data == 0x90) {
1384  data++;
1385  AppendToBuffer("nop"); // 2 byte nop.
1386  } else if (*data == 0xF3) {
1387  data++;
1388  int mod, regop, rm;
1389  get_modrm(*data, &mod, &regop, &rm);
1390  AppendToBuffer("psllq %s,%s",
1391  NameOfXMMRegister(regop),
1392  NameOfXMMRegister(rm));
1393  data++;
1394  } else if (*data == 0x73) {
1395  data++;
1396  int mod, regop, rm;
1397  get_modrm(*data, &mod, &regop, &rm);
1398  int8_t imm8 = static_cast<int8_t>(data[1]);
1399  ASSERT(regop == esi || regop == edx);
1400  AppendToBuffer("%s %s,%d",
1401  (regop == esi) ? "psllq" : "psrlq",
1402  NameOfXMMRegister(rm),
1403  static_cast<int>(imm8));
1404  data += 2;
1405  } else if (*data == 0xD3) {
1406  data++;
1407  int mod, regop, rm;
1408  get_modrm(*data, &mod, &regop, &rm);
1409  AppendToBuffer("psrlq %s,%s",
1410  NameOfXMMRegister(regop),
1411  NameOfXMMRegister(rm));
1412  data++;
1413  } else if (*data == 0x7F) {
1414  AppendToBuffer("movdqa ");
1415  data++;
1416  int mod, regop, rm;
1417  get_modrm(*data, &mod, &regop, &rm);
1418  data += PrintRightXMMOperand(data);
1419  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1420  } else if (*data == 0x7E) {
1421  data++;
1422  int mod, regop, rm;
1423  get_modrm(*data, &mod, &regop, &rm);
1424  AppendToBuffer("movd ");
1425  data += PrintRightOperand(data);
1426  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1427  } else if (*data == 0xDB) {
1428  data++;
1429  int mod, regop, rm;
1430  get_modrm(*data, &mod, &regop, &rm);
1431  AppendToBuffer("pand %s,%s",
1432  NameOfXMMRegister(regop),
1433  NameOfXMMRegister(rm));
1434  data++;
1435  } else if (*data == 0xE7) {
1436  data++;
1437  int mod, regop, rm;
1438  get_modrm(*data, &mod, &regop, &rm);
1439  if (mod == 3) {
1440  AppendToBuffer("movntdq ");
1441  data += PrintRightOperand(data);
1442  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1443  } else {
1444  UnimplementedInstruction();
1445  }
1446  } else if (*data == 0xEF) {
1447  data++;
1448  int mod, regop, rm;
1449  get_modrm(*data, &mod, &regop, &rm);
1450  AppendToBuffer("pxor %s,%s",
1451  NameOfXMMRegister(regop),
1452  NameOfXMMRegister(rm));
1453  data++;
1454  } else if (*data == 0xEB) {
1455  data++;
1456  int mod, regop, rm;
1457  get_modrm(*data, &mod, &regop, &rm);
1458  AppendToBuffer("por %s,%s",
1459  NameOfXMMRegister(regop),
1460  NameOfXMMRegister(rm));
1461  data++;
1462  } else {
1463  UnimplementedInstruction();
1464  }
1465  } else {
1466  UnimplementedInstruction();
1467  }
1468  break;
1469 
1470  case 0xFE:
1471  { data++;
1472  int mod, regop, rm;
1473  get_modrm(*data, &mod, &regop, &rm);
1474  if (regop == ecx) {
1475  AppendToBuffer("dec_b ");
1476  data += PrintRightOperand(data);
1477  } else {
1478  UnimplementedInstruction();
1479  }
1480  }
1481  break;
1482 
1483  case 0x68:
1484  AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1485  data += 5;
1486  break;
1487 
1488  case 0x6A:
1489  AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1490  data += 2;
1491  break;
1492 
1493  case 0xA8:
1494  AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1495  data += 2;
1496  break;
1497 
1498  case 0xA9:
1499  AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1500  data += 5;
1501  break;
1502 
1503  case 0xD1: // fall through
1504  case 0xD3: // fall through
1505  case 0xC1:
1506  data += D1D3C1Instruction(data);
1507  break;
1508 
1509  case 0xD8: // fall through
1510  case 0xD9: // fall through
1511  case 0xDA: // fall through
1512  case 0xDB: // fall through
1513  case 0xDC: // fall through
1514  case 0xDD: // fall through
1515  case 0xDE: // fall through
1516  case 0xDF:
1517  data += FPUInstruction(data);
1518  break;
1519 
1520  case 0xEB:
1521  data += JumpShort(data);
1522  break;
1523 
1524  case 0xF2:
1525  if (*(data+1) == 0x0F) {
1526  byte b2 = *(data+2);
1527  if (b2 == 0x11) {
1528  AppendToBuffer("movsd ");
1529  data += 3;
1530  int mod, regop, rm;
1531  get_modrm(*data, &mod, &regop, &rm);
1532  data += PrintRightXMMOperand(data);
1533  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1534  } else if (b2 == 0x10) {
1535  data += 3;
1536  int mod, regop, rm;
1537  get_modrm(*data, &mod, &regop, &rm);
1538  AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
1539  data += PrintRightXMMOperand(data);
1540  } else if (b2 == 0x5A) {
1541  data += 3;
1542  int mod, regop, rm;
1543  get_modrm(*data, &mod, &regop, &rm);
1544  AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
1545  data += PrintRightXMMOperand(data);
1546  } else {
1547  const char* mnem = "?";
1548  switch (b2) {
1549  case 0x2A: mnem = "cvtsi2sd"; break;
1550  case 0x2C: mnem = "cvttsd2si"; break;
1551  case 0x2D: mnem = "cvtsd2si"; break;
1552  case 0x51: mnem = "sqrtsd"; break;
1553  case 0x58: mnem = "addsd"; break;
1554  case 0x59: mnem = "mulsd"; break;
1555  case 0x5C: mnem = "subsd"; break;
1556  case 0x5E: mnem = "divsd"; break;
1557  }
1558  data += 3;
1559  int mod, regop, rm;
1560  get_modrm(*data, &mod, &regop, &rm);
1561  if (b2 == 0x2A) {
1562  AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1563  data += PrintRightOperand(data);
1564  } else if (b2 == 0x2C || b2 == 0x2D) {
1565  AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
1566  data += PrintRightXMMOperand(data);
1567  } else if (b2 == 0xC2) {
1568  // Intel manual 2A, Table 3-18.
1569  const char* const pseudo_op[] = {
1570  "cmpeqsd",
1571  "cmpltsd",
1572  "cmplesd",
1573  "cmpunordsd",
1574  "cmpneqsd",
1575  "cmpnltsd",
1576  "cmpnlesd",
1577  "cmpordsd"
1578  };
1579  AppendToBuffer("%s %s,%s",
1580  pseudo_op[data[1]],
1581  NameOfXMMRegister(regop),
1582  NameOfXMMRegister(rm));
1583  data += 2;
1584  } else {
1585  AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1586  data += PrintRightXMMOperand(data);
1587  }
1588  }
1589  } else {
1590  UnimplementedInstruction();
1591  }
1592  break;
1593 
1594  case 0xF3:
1595  if (*(data+1) == 0x0F) {
1596  byte b2 = *(data+2);
1597  if (b2 == 0x11) {
1598  AppendToBuffer("movss ");
1599  data += 3;
1600  int mod, regop, rm;
1601  get_modrm(*data, &mod, &regop, &rm);
1602  data += PrintRightXMMOperand(data);
1603  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1604  } else if (b2 == 0x10) {
1605  data += 3;
1606  int mod, regop, rm;
1607  get_modrm(*data, &mod, &regop, &rm);
1608  AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
1609  data += PrintRightXMMOperand(data);
1610  } else if (b2 == 0x2C) {
1611  data += 3;
1612  int mod, regop, rm;
1613  get_modrm(*data, &mod, &regop, &rm);
1614  AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
1615  data += PrintRightXMMOperand(data);
1616  } else if (b2 == 0x5A) {
1617  data += 3;
1618  int mod, regop, rm;
1619  get_modrm(*data, &mod, &regop, &rm);
1620  AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1621  data += PrintRightXMMOperand(data);
1622  } else if (b2 == 0x6F) {
1623  data += 3;
1624  int mod, regop, rm;
1625  get_modrm(*data, &mod, &regop, &rm);
1626  AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
1627  data += PrintRightXMMOperand(data);
1628  } else if (b2 == 0x7F) {
1629  AppendToBuffer("movdqu ");
1630  data += 3;
1631  int mod, regop, rm;
1632  get_modrm(*data, &mod, &regop, &rm);
1633  data += PrintRightXMMOperand(data);
1634  AppendToBuffer(",%s", NameOfXMMRegister(regop));
1635  } else {
1636  UnimplementedInstruction();
1637  }
1638  } else if (*(data+1) == 0xA5) {
1639  data += 2;
1640  AppendToBuffer("rep_movs");
1641  } else if (*(data+1) == 0xAB) {
1642  data += 2;
1643  AppendToBuffer("rep_stos");
1644  } else {
1645  UnimplementedInstruction();
1646  }
1647  break;
1648 
1649  case 0xF7:
1650  data += F7Instruction(data);
1651  break;
1652 
1653  default:
1654  UnimplementedInstruction();
1655  }
1656  }
1657 
1658  if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1659  tmp_buffer_[tmp_buffer_pos_] = '\0';
1660  }
1661 
1662  int instr_len = data - instr;
1663  if (instr_len == 0) {
1664  printf("%02x", *data);
1665  }
1666  ASSERT(instr_len > 0); // Ensure progress.
1667 
1668  int outp = 0;
1669  // Instruction bytes.
1670  for (byte* bp = instr; bp < data; bp++) {
1671  outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1672  "%02x",
1673  *bp);
1674  }
1675  for (int i = 6 - instr_len; i >= 0; i--) {
1676  outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1677  " ");
1678  }
1679 
1680  outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1681  " %s",
1682  tmp_buffer_.start());
1683  return instr_len;
1684 } // NOLINT (function is too long)
1685 
1686 
1687 //------------------------------------------------------------------------------
1688 
1689 
1690 static const char* cpu_regs[8] = {
1691  "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
1692 };
1693 
1694 
1695 static const char* byte_cpu_regs[8] = {
1696  "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
1697 };
1698 
1699 
1700 static const char* xmm_regs[8] = {
1701  "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
1702 };
1703 
1704 
1705 const char* NameConverter::NameOfAddress(byte* addr) const {
1707  return tmp_buffer_.start();
1708 }
1709 
1710 
1711 const char* NameConverter::NameOfConstant(byte* addr) const {
1712  return NameOfAddress(addr);
1713 }
1714 
1715 
1716 const char* NameConverter::NameOfCPURegister(int reg) const {
1717  if (0 <= reg && reg < 8) return cpu_regs[reg];
1718  return "noreg";
1719 }
1720 
1721 
1722 const char* NameConverter::NameOfByteCPURegister(int reg) const {
1723  if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
1724  return "noreg";
1725 }
1726 
1727 
1728 const char* NameConverter::NameOfXMMRegister(int reg) const {
1729  if (0 <= reg && reg < 8) return xmm_regs[reg];
1730  return "noxmmreg";
1731 }
1732 
1733 
1734 const char* NameConverter::NameInCode(byte* addr) const {
1735  // IA32 does not embed debug strings at the moment.
1736  UNREACHABLE();
1737  return "";
1738 }
1739 
1740 
1741 //------------------------------------------------------------------------------
1742 
1743 Disassembler::Disassembler(const NameConverter& converter)
1744  : converter_(converter) {}
1745 
1746 
1748 
1749 
1750 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1751  byte* instruction) {
1752  DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
1753  return d.InstructionDecode(buffer, instruction);
1754 }
1755 
1756 
1757 // The IA-32 assembler does not currently use constant pools.
1758 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
1759 
1760 
1761 /*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1762  NameConverter converter;
1763  Disassembler d(converter);
1764  for (byte* pc = begin; pc < end;) {
1766  buffer[0] = '\0';
1767  byte* prev_pc = pc;
1768  pc += d.InstructionDecode(buffer, pc);
1769  fprintf(f, "%p", prev_pc);
1770  fprintf(f, " ");
1771 
1772  for (byte* bp = prev_pc; bp < pc; bp++) {
1773  fprintf(f, "%02x", *bp);
1774  }
1775  for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
1776  fprintf(f, " ");
1777  }
1778  fprintf(f, " %s\n", buffer.start());
1779  }
1780 }
1781 
1782 
1783 } // namespace disasm
1784 
1785 #endif // V8_TARGET_ARCH_IA32
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter NULL
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:329
virtual const char * NameInCode(byte *addr) const
virtual const char * NameOfByteCPURegister(int reg) const
const Register edi
uint8_t byte
Definition: globals.h:185
const Register ebp
#define UNREACHABLE()
Definition: checks.h:52
T * start() const
Definition: utils.h:426
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:50
#define ASSERT_EQ(v1, v2)
Definition: checks.h:330
const Register esi
#define ASSERT_NE(v1, v2)
Definition: checks.h:331
const Register edx
signed short int16_t
Definition: unicode.cc:45