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