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