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