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