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