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