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