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