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