The data contained in this repository can be downloaded to your computer using one of several clients.
Please see the documentation of your version control software client for more information.

Please select the desired protocol below to get the URL.

This URL has Read-Only access.

Statistics
| Branch: | Revision:

main_repo / deps / v8 / src / ia32 / disasm-ia32.cc @ f230a1cf

History | View | Annotate | Download (53.5 KB)

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 V8_TARGET_ARCH_IA32
35

    
36
#include "disasm.h"
37

    
38
namespace disasm {
39

    
40
enum OperandOrder {
41
  UNSET_OP_ORDER = 0,
42
  REG_OPER_OP_ORDER,
43
  OPER_REG_OP_ORDER
44
};
45

    
46

    
47
//------------------------------------------------------------------
48
// Tables
49
//------------------------------------------------------------------
50
struct ByteMnemonic {
51
  int b;  // -1 terminates, otherwise must be in range (0..255)
52
  const char* mnem;
53
  OperandOrder op_order_;
54
};
55

    
56

    
57
static const ByteMnemonic two_operands_instr[] = {
58
  {0x01, "add", OPER_REG_OP_ORDER},
59
  {0x03, "add", REG_OPER_OP_ORDER},
60
  {0x09, "or", OPER_REG_OP_ORDER},
61
  {0x0B, "or", REG_OPER_OP_ORDER},
62
  {0x1B, "sbb", REG_OPER_OP_ORDER},
63
  {0x21, "and", OPER_REG_OP_ORDER},
64
  {0x23, "and", REG_OPER_OP_ORDER},
65
  {0x29, "sub", OPER_REG_OP_ORDER},
66
  {0x2A, "subb", REG_OPER_OP_ORDER},
67
  {0x2B, "sub", REG_OPER_OP_ORDER},
68
  {0x31, "xor", OPER_REG_OP_ORDER},
69
  {0x33, "xor", REG_OPER_OP_ORDER},
70
  {0x38, "cmpb", OPER_REG_OP_ORDER},
71
  {0x3A, "cmpb", REG_OPER_OP_ORDER},
72
  {0x3B, "cmp", REG_OPER_OP_ORDER},
73
  {0x84, "test_b", REG_OPER_OP_ORDER},
74
  {0x85, "test", REG_OPER_OP_ORDER},
75
  {0x87, "xchg", REG_OPER_OP_ORDER},
76
  {0x8A, "mov_b", REG_OPER_OP_ORDER},
77
  {0x8B, "mov", REG_OPER_OP_ORDER},
78
  {0x8D, "lea", REG_OPER_OP_ORDER},
79
  {-1, "", UNSET_OP_ORDER}
80
};
81

    
82

    
83
static const ByteMnemonic zero_operands_instr[] = {
84
  {0xC3, "ret", UNSET_OP_ORDER},
85
  {0xC9, "leave", UNSET_OP_ORDER},
86
  {0x90, "nop", UNSET_OP_ORDER},
87
  {0xF4, "hlt", UNSET_OP_ORDER},
88
  {0xCC, "int3", UNSET_OP_ORDER},
89
  {0x60, "pushad", UNSET_OP_ORDER},
90
  {0x61, "popad", UNSET_OP_ORDER},
91
  {0x9C, "pushfd", UNSET_OP_ORDER},
92
  {0x9D, "popfd", UNSET_OP_ORDER},
93
  {0x9E, "sahf", UNSET_OP_ORDER},
94
  {0x99, "cdq", UNSET_OP_ORDER},
95
  {0x9B, "fwait", UNSET_OP_ORDER},
96
  {0xFC, "cld", UNSET_OP_ORDER},
97
  {0xAB, "stos", UNSET_OP_ORDER},
98
  {-1, "", UNSET_OP_ORDER}
99
};
100

    
101

    
102
static const ByteMnemonic call_jump_instr[] = {
103
  {0xE8, "call", UNSET_OP_ORDER},
104
  {0xE9, "jmp", UNSET_OP_ORDER},
105
  {-1, "", UNSET_OP_ORDER}
106
};
107

    
108

    
109
static const ByteMnemonic short_immediate_instr[] = {
110
  {0x05, "add", UNSET_OP_ORDER},
111
  {0x0D, "or", UNSET_OP_ORDER},
112
  {0x15, "adc", UNSET_OP_ORDER},
113
  {0x25, "and", UNSET_OP_ORDER},
114
  {0x2D, "sub", UNSET_OP_ORDER},
115
  {0x35, "xor", UNSET_OP_ORDER},
116
  {0x3D, "cmp", UNSET_OP_ORDER},
117
  {-1, "", UNSET_OP_ORDER}
118
};
119

    
120

    
121
// Generally we don't want to generate these because they are subject to partial
122
// register stalls.  They are included for completeness and because the cmp
123
// variant is used by the RecordWrite stub.  Because it does not update the
124
// register it is not subject to partial register stalls.
125
static ByteMnemonic byte_immediate_instr[] = {
126
  {0x0c, "or", UNSET_OP_ORDER},
127
  {0x24, "and", UNSET_OP_ORDER},
128
  {0x34, "xor", UNSET_OP_ORDER},
129
  {0x3c, "cmp", UNSET_OP_ORDER},
130
  {-1, "", UNSET_OP_ORDER}
131
};
132

    
133

    
134
static const char* const jump_conditional_mnem[] = {
135
  /*0*/ "jo", "jno", "jc", "jnc",
136
  /*4*/ "jz", "jnz", "jna", "ja",
137
  /*8*/ "js", "jns", "jpe", "jpo",
138
  /*12*/ "jl", "jnl", "jng", "jg"
139
};
140

    
141

    
142
static const char* const set_conditional_mnem[] = {
143
  /*0*/ "seto", "setno", "setc", "setnc",
144
  /*4*/ "setz", "setnz", "setna", "seta",
145
  /*8*/ "sets", "setns", "setpe", "setpo",
146
  /*12*/ "setl", "setnl", "setng", "setg"
147
};
148

    
149

    
150
static const char* const conditional_move_mnem[] = {
151
  /*0*/ "cmovo", "cmovno", "cmovc", "cmovnc",
152
  /*4*/ "cmovz", "cmovnz", "cmovna", "cmova",
153
  /*8*/ "cmovs", "cmovns", "cmovpe", "cmovpo",
154
  /*12*/ "cmovl", "cmovnl", "cmovng", "cmovg"
155
};
156

    
157

    
158
enum InstructionType {
159
  NO_INSTR,
160
  ZERO_OPERANDS_INSTR,
161
  TWO_OPERANDS_INSTR,
162
  JUMP_CONDITIONAL_SHORT_INSTR,
163
  REGISTER_INSTR,
164
  MOVE_REG_INSTR,
165
  CALL_JUMP_INSTR,
166
  SHORT_IMMEDIATE_INSTR,
167
  BYTE_IMMEDIATE_INSTR
168
};
169

    
170

    
171
struct InstructionDesc {
172
  const char* mnem;
173
  InstructionType type;
174
  OperandOrder op_order_;
175
};
176

    
177

    
178
class InstructionTable {
179
 public:
180
  InstructionTable();
181
  const InstructionDesc& Get(byte x) const { return instructions_[x]; }
182
  static InstructionTable* get_instance() {
183
    static InstructionTable table;
184
    return &table;
185
  }
186

    
187
 private:
188
  InstructionDesc instructions_[256];
189
  void Clear();
190
  void Init();
191
  void CopyTable(const ByteMnemonic bm[], InstructionType type);
192
  void SetTableRange(InstructionType type,
193
                     byte start,
194
                     byte end,
195
                     const char* mnem);
196
  void AddJumpConditionalShort();
197
};
198

    
199

    
200
InstructionTable::InstructionTable() {
201
  Clear();
202
  Init();
203
}
204

    
205

    
206
void InstructionTable::Clear() {
207
  for (int i = 0; i < 256; i++) {
208
    instructions_[i].mnem = "";
209
    instructions_[i].type = NO_INSTR;
210
    instructions_[i].op_order_ = UNSET_OP_ORDER;
211
  }
212
}
213

    
214

    
215
void InstructionTable::Init() {
216
  CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
217
  CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
218
  CopyTable(call_jump_instr, CALL_JUMP_INSTR);
219
  CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
220
  CopyTable(byte_immediate_instr, BYTE_IMMEDIATE_INSTR);
221
  AddJumpConditionalShort();
222
  SetTableRange(REGISTER_INSTR, 0x40, 0x47, "inc");
223
  SetTableRange(REGISTER_INSTR, 0x48, 0x4F, "dec");
224
  SetTableRange(REGISTER_INSTR, 0x50, 0x57, "push");
225
  SetTableRange(REGISTER_INSTR, 0x58, 0x5F, "pop");
226
  SetTableRange(REGISTER_INSTR, 0x91, 0x97, "xchg eax,");  // 0x90 is nop.
227
  SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
228
}
229

    
230

    
231
void InstructionTable::CopyTable(const ByteMnemonic bm[],
232
                                 InstructionType type) {
233
  for (int i = 0; bm[i].b >= 0; i++) {
234
    InstructionDesc* id = &instructions_[bm[i].b];
235
    id->mnem = bm[i].mnem;
236
    id->op_order_ = bm[i].op_order_;
237
    ASSERT_EQ(NO_INSTR, id->type);  // Information not already entered.
238
    id->type = type;
239
  }
240
}
241

    
242

    
243
void InstructionTable::SetTableRange(InstructionType type,
244
                                     byte start,
245
                                     byte end,
246
                                     const char* mnem) {
247
  for (byte b = start; b <= end; b++) {
248
    InstructionDesc* id = &instructions_[b];
249
    ASSERT_EQ(NO_INSTR, id->type);  // Information not already entered.
250
    id->mnem = mnem;
251
    id->type = type;
252
  }
253
}
254

    
255

    
256
void InstructionTable::AddJumpConditionalShort() {
257
  for (byte b = 0x70; b <= 0x7F; b++) {
258
    InstructionDesc* id = &instructions_[b];
259
    ASSERT_EQ(NO_INSTR, id->type);  // Information not already entered.
260
    id->mnem = jump_conditional_mnem[b & 0x0F];
261
    id->type = JUMP_CONDITIONAL_SHORT_INSTR;
262
  }
263
}
264

    
265

    
266
// The IA32 disassembler implementation.
267
class DisassemblerIA32 {
268
 public:
269
  DisassemblerIA32(const NameConverter& converter,
270
                   bool abort_on_unimplemented = true)
271
      : converter_(converter),
272
        instruction_table_(InstructionTable::get_instance()),
273
        tmp_buffer_pos_(0),
274
        abort_on_unimplemented_(abort_on_unimplemented) {
275
    tmp_buffer_[0] = '\0';
276
  }
277

    
278
  virtual ~DisassemblerIA32() {}
279

    
280
  // Writes one disassembled instruction into 'buffer' (0-terminated).
281
  // Returns the length of the disassembled machine instruction in bytes.
282
  int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
283

    
284
 private:
285
  const NameConverter& converter_;
286
  InstructionTable* instruction_table_;
287
  v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
288
  unsigned int tmp_buffer_pos_;
289
  bool abort_on_unimplemented_;
290

    
291
  enum {
292
    eax = 0,
293
    ecx = 1,
294
    edx = 2,
295
    ebx = 3,
296
    esp = 4,
297
    ebp = 5,
298
    esi = 6,
299
    edi = 7
300
  };
301

    
302

    
303
  enum ShiftOpcodeExtension {
304
    kROL = 0,
305
    kROR = 1,
306
    kRCL = 2,
307
    kRCR = 3,
308
    kSHL = 4,
309
    KSHR = 5,
310
    kSAR = 7
311
  };
312

    
313

    
314
  const char* NameOfCPURegister(int reg) const {
315
    return converter_.NameOfCPURegister(reg);
316
  }
317

    
318

    
319
  const char* NameOfByteCPURegister(int reg) const {
320
    return converter_.NameOfByteCPURegister(reg);
321
  }
322

    
323

    
324
  const char* NameOfXMMRegister(int reg) const {
325
    return converter_.NameOfXMMRegister(reg);
326
  }
327

    
328

    
329
  const char* NameOfAddress(byte* addr) const {
330
    return converter_.NameOfAddress(addr);
331
  }
332

    
333

    
334
  // Disassembler helper functions.
335
  static void get_modrm(byte data, int* mod, int* regop, int* rm) {
336
    *mod = (data >> 6) & 3;
337
    *regop = (data & 0x38) >> 3;
338
    *rm = data & 7;
339
  }
340

    
341

    
342
  static void get_sib(byte data, int* scale, int* index, int* base) {
343
    *scale = (data >> 6) & 3;
344
    *index = (data >> 3) & 7;
345
    *base = data & 7;
346
  }
347

    
348
  typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const;
349

    
350
  int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
351
  int PrintRightOperand(byte* modrmp);
352
  int PrintRightByteOperand(byte* modrmp);
353
  int PrintRightXMMOperand(byte* modrmp);
354
  int PrintOperands(const char* mnem, OperandOrder op_order, byte* data);
355
  int PrintImmediateOp(byte* data);
356
  int F7Instruction(byte* data);
357
  int D1D3C1Instruction(byte* data);
358
  int JumpShort(byte* data);
359
  int JumpConditional(byte* data, const char* comment);
360
  int JumpConditionalShort(byte* data, const char* comment);
361
  int SetCC(byte* data);
362
  int CMov(byte* data);
363
  int FPUInstruction(byte* data);
364
  int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
365
  int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
366
  void AppendToBuffer(const char* format, ...);
367

    
368

    
369
  void UnimplementedInstruction() {
370
    if (abort_on_unimplemented_) {
371
      UNIMPLEMENTED();
372
    } else {
373
      AppendToBuffer("'Unimplemented Instruction'");
374
    }
375
  }
376
};
377

    
378

    
379
void DisassemblerIA32::AppendToBuffer(const char* format, ...) {
380
  v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
381
  va_list args;
382
  va_start(args, format);
383
  int result = v8::internal::OS::VSNPrintF(buf, format, args);
384
  va_end(args);
385
  tmp_buffer_pos_ += result;
386
}
387

    
388
int DisassemblerIA32::PrintRightOperandHelper(
389
    byte* modrmp,
390
    RegisterNameMapping direct_register_name) {
391
  int mod, regop, rm;
392
  get_modrm(*modrmp, &mod, &regop, &rm);
393
  RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
394
      &DisassemblerIA32::NameOfCPURegister;
395
  switch (mod) {
396
    case 0:
397
      if (rm == ebp) {
398
        int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1);
399
        AppendToBuffer("[0x%x]", disp);
400
        return 5;
401
      } else if (rm == esp) {
402
        byte sib = *(modrmp + 1);
403
        int scale, index, base;
404
        get_sib(sib, &scale, &index, &base);
405
        if (index == esp && base == esp && scale == 0 /*times_1*/) {
406
          AppendToBuffer("[%s]", (this->*register_name)(rm));
407
          return 2;
408
        } else if (base == ebp) {
409
          int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
410
          AppendToBuffer("[%s*%d+0x%x]",
411
                         (this->*register_name)(index),
412
                         1 << scale,
413
                         disp);
414
          return 6;
415
        } else if (index != esp && base != ebp) {
416
          // [base+index*scale]
417
          AppendToBuffer("[%s+%s*%d]",
418
                         (this->*register_name)(base),
419
                         (this->*register_name)(index),
420
                         1 << scale);
421
          return 2;
422
        } else {
423
          UnimplementedInstruction();
424
          return 1;
425
        }
426
      } else {
427
        AppendToBuffer("[%s]", (this->*register_name)(rm));
428
        return 1;
429
      }
430
      break;
431
    case 1:  // fall through
432
    case 2:
433
      if (rm == esp) {
434
        byte sib = *(modrmp + 1);
435
        int scale, index, base;
436
        get_sib(sib, &scale, &index, &base);
437
        int disp =
438
            mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 2) : *(modrmp + 2);
439
        if (index == base && index == rm /*esp*/ && scale == 0 /*times_1*/) {
440
          AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp);
441
        } else {
442
          AppendToBuffer("[%s+%s*%d+0x%x]",
443
                         (this->*register_name)(base),
444
                         (this->*register_name)(index),
445
                         1 << scale,
446
                         disp);
447
        }
448
        return mod == 2 ? 6 : 3;
449
      } else {
450
        // No sib.
451
        int disp =
452
            mod == 2 ? *reinterpret_cast<int32_t*>(modrmp + 1) : *(modrmp + 1);
453
        AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp);
454
        return mod == 2 ? 5 : 2;
455
      }
456
      break;
457
    case 3:
458
      AppendToBuffer("%s", (this->*register_name)(rm));
459
      return 1;
460
    default:
461
      UnimplementedInstruction();
462
      return 1;
463
  }
464
  UNREACHABLE();
465
}
466

    
467

    
468
int DisassemblerIA32::PrintRightOperand(byte* modrmp) {
469
  return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister);
470
}
471

    
472

    
473
int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) {
474
  return PrintRightOperandHelper(modrmp,
475
                                 &DisassemblerIA32::NameOfByteCPURegister);
476
}
477

    
478

    
479
int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) {
480
  return PrintRightOperandHelper(modrmp,
481
                                 &DisassemblerIA32::NameOfXMMRegister);
482
}
483

    
484

    
485
// Returns number of bytes used including the current *data.
486
// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
487
int DisassemblerIA32::PrintOperands(const char* mnem,
488
                                    OperandOrder op_order,
489
                                    byte* data) {
490
  byte modrm = *data;
491
  int mod, regop, rm;
492
  get_modrm(modrm, &mod, &regop, &rm);
493
  int advance = 0;
494
  switch (op_order) {
495
    case REG_OPER_OP_ORDER: {
496
      AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
497
      advance = PrintRightOperand(data);
498
      break;
499
    }
500
    case OPER_REG_OP_ORDER: {
501
      AppendToBuffer("%s ", mnem);
502
      advance = PrintRightOperand(data);
503
      AppendToBuffer(",%s", NameOfCPURegister(regop));
504
      break;
505
    }
506
    default:
507
      UNREACHABLE();
508
      break;
509
  }
510
  return advance;
511
}
512

    
513

    
514
// Returns number of bytes used by machine instruction, including *data byte.
515
// Writes immediate instructions to 'tmp_buffer_'.
516
int DisassemblerIA32::PrintImmediateOp(byte* data) {
517
  bool sign_extension_bit = (*data & 0x02) != 0;
518
  byte modrm = *(data+1);
519
  int mod, regop, rm;
520
  get_modrm(modrm, &mod, &regop, &rm);
521
  const char* mnem = "Imm???";
522
  switch (regop) {
523
    case 0: mnem = "add"; break;
524
    case 1: mnem = "or"; break;
525
    case 2: mnem = "adc"; break;
526
    case 4: mnem = "and"; break;
527
    case 5: mnem = "sub"; break;
528
    case 6: mnem = "xor"; break;
529
    case 7: mnem = "cmp"; break;
530
    default: UnimplementedInstruction();
531
  }
532
  AppendToBuffer("%s ", mnem);
533
  int count = PrintRightOperand(data+1);
534
  if (sign_extension_bit) {
535
    AppendToBuffer(",0x%x", *(data + 1 + count));
536
    return 1 + count + 1 /*int8*/;
537
  } else {
538
    AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
539
    return 1 + count + 4 /*int32_t*/;
540
  }
541
}
542

    
543

    
544
// Returns number of bytes used, including *data.
545
int DisassemblerIA32::F7Instruction(byte* data) {
546
  ASSERT_EQ(0xF7, *data);
547
  byte modrm = *(data+1);
548
  int mod, regop, rm;
549
  get_modrm(modrm, &mod, &regop, &rm);
550
  if (mod == 3 && regop != 0) {
551
    const char* mnem = NULL;
552
    switch (regop) {
553
      case 2: mnem = "not"; break;
554
      case 3: mnem = "neg"; break;
555
      case 4: mnem = "mul"; break;
556
      case 5: mnem = "imul"; break;
557
      case 7: mnem = "idiv"; break;
558
      default: UnimplementedInstruction();
559
    }
560
    AppendToBuffer("%s %s", mnem, NameOfCPURegister(rm));
561
    return 2;
562
  } else if (mod == 3 && regop == eax) {
563
    int32_t imm = *reinterpret_cast<int32_t*>(data+2);
564
    AppendToBuffer("test %s,0x%x", NameOfCPURegister(rm), imm);
565
    return 6;
566
  } else if (regop == eax) {
567
    AppendToBuffer("test ");
568
    int count = PrintRightOperand(data+1);
569
    int32_t imm = *reinterpret_cast<int32_t*>(data+1+count);
570
    AppendToBuffer(",0x%x", imm);
571
    return 1+count+4 /*int32_t*/;
572
  } else {
573
    UnimplementedInstruction();
574
    return 2;
575
  }
576
}
577

    
578

    
579
int DisassemblerIA32::D1D3C1Instruction(byte* data) {
580
  byte op = *data;
581
  ASSERT(op == 0xD1 || op == 0xD3 || op == 0xC1);
582
  byte modrm = *(data+1);
583
  int mod, regop, rm;
584
  get_modrm(modrm, &mod, &regop, &rm);
585
  int imm8 = -1;
586
  int num_bytes = 2;
587
  if (mod == 3) {
588
    const char* mnem = NULL;
589
    switch (regop) {
590
      case kROL: mnem = "rol"; break;
591
      case kROR: mnem = "ror"; break;
592
      case kRCL: mnem = "rcl"; break;
593
      case kRCR: mnem = "rcr"; break;
594
      case kSHL: mnem = "shl"; break;
595
      case KSHR: mnem = "shr"; break;
596
      case kSAR: mnem = "sar"; break;
597
      default: UnimplementedInstruction();
598
    }
599
    if (op == 0xD1) {
600
      imm8 = 1;
601
    } else if (op == 0xC1) {
602
      imm8 = *(data+2);
603
      num_bytes = 3;
604
    } else if (op == 0xD3) {
605
      // Shift/rotate by cl.
606
    }
607
    ASSERT_NE(NULL, mnem);
608
    AppendToBuffer("%s %s,", mnem, NameOfCPURegister(rm));
609
    if (imm8 >= 0) {
610
      AppendToBuffer("%d", imm8);
611
    } else {
612
      AppendToBuffer("cl");
613
    }
614
  } else {
615
    UnimplementedInstruction();
616
  }
617
  return num_bytes;
618
}
619

    
620

    
621
// Returns number of bytes used, including *data.
622
int DisassemblerIA32::JumpShort(byte* data) {
623
  ASSERT_EQ(0xEB, *data);
624
  byte b = *(data+1);
625
  byte* dest = data + static_cast<int8_t>(b) + 2;
626
  AppendToBuffer("jmp %s", NameOfAddress(dest));
627
  return 2;
628
}
629

    
630

    
631
// Returns number of bytes used, including *data.
632
int DisassemblerIA32::JumpConditional(byte* data, const char* comment) {
633
  ASSERT_EQ(0x0F, *data);
634
  byte cond = *(data+1) & 0x0F;
635
  byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6;
636
  const char* mnem = jump_conditional_mnem[cond];
637
  AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
638
  if (comment != NULL) {
639
    AppendToBuffer(", %s", comment);
640
  }
641
  return 6;  // includes 0x0F
642
}
643

    
644

    
645
// Returns number of bytes used, including *data.
646
int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) {
647
  byte cond = *data & 0x0F;
648
  byte b = *(data+1);
649
  byte* dest = data + static_cast<int8_t>(b) + 2;
650
  const char* mnem = jump_conditional_mnem[cond];
651
  AppendToBuffer("%s %s", mnem, NameOfAddress(dest));
652
  if (comment != NULL) {
653
    AppendToBuffer(", %s", comment);
654
  }
655
  return 2;
656
}
657

    
658

    
659
// Returns number of bytes used, including *data.
660
int DisassemblerIA32::SetCC(byte* data) {
661
  ASSERT_EQ(0x0F, *data);
662
  byte cond = *(data+1) & 0x0F;
663
  const char* mnem = set_conditional_mnem[cond];
664
  AppendToBuffer("%s ", mnem);
665
  PrintRightByteOperand(data+2);
666
  return 3;  // Includes 0x0F.
667
}
668

    
669

    
670
// Returns number of bytes used, including *data.
671
int DisassemblerIA32::CMov(byte* data) {
672
  ASSERT_EQ(0x0F, *data);
673
  byte cond = *(data + 1) & 0x0F;
674
  const char* mnem = conditional_move_mnem[cond];
675
  int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2);
676
  return 2 + op_size;  // includes 0x0F
677
}
678

    
679

    
680
// Returns number of bytes used, including *data.
681
int DisassemblerIA32::FPUInstruction(byte* data) {
682
  byte escape_opcode = *data;
683
  ASSERT_EQ(0xD8, escape_opcode & 0xF8);
684
  byte modrm_byte = *(data+1);
685

    
686
  if (modrm_byte >= 0xC0) {
687
    return RegisterFPUInstruction(escape_opcode, modrm_byte);
688
  } else {
689
    return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
690
  }
691
}
692

    
693
int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode,
694
                                           int modrm_byte,
695
                                           byte* modrm_start) {
696
  const char* mnem = "?";
697
  int regop = (modrm_byte >> 3) & 0x7;  // reg/op field of modrm byte.
698
  switch (escape_opcode) {
699
    case 0xD9: switch (regop) {
700
        case 0: mnem = "fld_s"; break;
701
        case 2: mnem = "fst_s"; break;
702
        case 3: mnem = "fstp_s"; break;
703
        case 7: mnem = "fstcw"; break;
704
        default: UnimplementedInstruction();
705
      }
706
      break;
707

    
708
    case 0xDB: switch (regop) {
709
        case 0: mnem = "fild_s"; break;
710
        case 1: mnem = "fisttp_s"; break;
711
        case 2: mnem = "fist_s"; break;
712
        case 3: mnem = "fistp_s"; break;
713
        default: UnimplementedInstruction();
714
      }
715
      break;
716

    
717
    case 0xDD: switch (regop) {
718
        case 0: mnem = "fld_d"; break;
719
        case 1: mnem = "fisttp_d"; break;
720
        case 2: mnem = "fst_d"; break;
721
        case 3: mnem = "fstp_d"; break;
722
        default: UnimplementedInstruction();
723
      }
724
      break;
725

    
726
    case 0xDF: switch (regop) {
727
        case 5: mnem = "fild_d"; break;
728
        case 7: mnem = "fistp_d"; break;
729
        default: UnimplementedInstruction();
730
      }
731
      break;
732

    
733
    default: UnimplementedInstruction();
734
  }
735
  AppendToBuffer("%s ", mnem);
736
  int count = PrintRightOperand(modrm_start);
737
  return count + 1;
738
}
739

    
740
int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode,
741
                                             byte modrm_byte) {
742
  bool has_register = false;  // Is the FPU register encoded in modrm_byte?
743
  const char* mnem = "?";
744

    
745
  switch (escape_opcode) {
746
    case 0xD8:
747
      has_register = true;
748
      switch (modrm_byte & 0xF8) {
749
        case 0xC0: mnem = "fadd_i"; break;
750
        case 0xE0: mnem = "fsub_i"; break;
751
        case 0xC8: mnem = "fmul_i"; break;
752
        case 0xF0: mnem = "fdiv_i"; break;
753
        default: UnimplementedInstruction();
754
      }
755
      break;
756

    
757
    case 0xD9:
758
      switch (modrm_byte & 0xF8) {
759
        case 0xC0:
760
          mnem = "fld";
761
          has_register = true;
762
          break;
763
        case 0xC8:
764
          mnem = "fxch";
765
          has_register = true;
766
          break;
767
        default:
768
          switch (modrm_byte) {
769
            case 0xE0: mnem = "fchs"; break;
770
            case 0xE1: mnem = "fabs"; break;
771
            case 0xE4: mnem = "ftst"; break;
772
            case 0xE8: mnem = "fld1"; break;
773
            case 0xEB: mnem = "fldpi"; break;
774
            case 0xED: mnem = "fldln2"; break;
775
            case 0xEE: mnem = "fldz"; break;
776
            case 0xF0: mnem = "f2xm1"; break;
777
            case 0xF1: mnem = "fyl2x"; break;
778
            case 0xF4: mnem = "fxtract"; break;
779
            case 0xF5: mnem = "fprem1"; break;
780
            case 0xF7: mnem = "fincstp"; break;
781
            case 0xF8: mnem = "fprem"; break;
782
            case 0xFC: mnem = "frndint"; break;
783
            case 0xFD: mnem = "fscale"; break;
784
            case 0xFE: mnem = "fsin"; break;
785
            case 0xFF: mnem = "fcos"; break;
786
            default: UnimplementedInstruction();
787
          }
788
      }
789
      break;
790

    
791
    case 0xDA:
792
      if (modrm_byte == 0xE9) {
793
        mnem = "fucompp";
794
      } else {
795
        UnimplementedInstruction();
796
      }
797
      break;
798

    
799
    case 0xDB:
800
      if ((modrm_byte & 0xF8) == 0xE8) {
801
        mnem = "fucomi";
802
        has_register = true;
803
      } else if (modrm_byte  == 0xE2) {
804
        mnem = "fclex";
805
      } else if (modrm_byte == 0xE3) {
806
        mnem = "fninit";
807
      } else {
808
        UnimplementedInstruction();
809
      }
810
      break;
811

    
812
    case 0xDC:
813
      has_register = true;
814
      switch (modrm_byte & 0xF8) {
815
        case 0xC0: mnem = "fadd"; break;
816
        case 0xE8: mnem = "fsub"; break;
817
        case 0xC8: mnem = "fmul"; break;
818
        case 0xF8: mnem = "fdiv"; break;
819
        default: UnimplementedInstruction();
820
      }
821
      break;
822

    
823
    case 0xDD:
824
      has_register = true;
825
      switch (modrm_byte & 0xF8) {
826
        case 0xC0: mnem = "ffree"; break;
827
        case 0xD0: mnem = "fst"; break;
828
        case 0xD8: mnem = "fstp"; break;
829
        default: UnimplementedInstruction();
830
      }
831
      break;
832

    
833
    case 0xDE:
834
      if (modrm_byte  == 0xD9) {
835
        mnem = "fcompp";
836
      } else {
837
        has_register = true;
838
        switch (modrm_byte & 0xF8) {
839
          case 0xC0: mnem = "faddp"; break;
840
          case 0xE8: mnem = "fsubp"; break;
841
          case 0xC8: mnem = "fmulp"; break;
842
          case 0xF8: mnem = "fdivp"; break;
843
          default: UnimplementedInstruction();
844
        }
845
      }
846
      break;
847

    
848
    case 0xDF:
849
      if (modrm_byte == 0xE0) {
850
        mnem = "fnstsw_ax";
851
      } else if ((modrm_byte & 0xF8) == 0xE8) {
852
        mnem = "fucomip";
853
        has_register = true;
854
      }
855
      break;
856

    
857
    default: UnimplementedInstruction();
858
  }
859

    
860
  if (has_register) {
861
    AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
862
  } else {
863
    AppendToBuffer("%s", mnem);
864
  }
865
  return 2;
866
}
867

    
868

    
869
// Mnemonics for instructions 0xF0 byte.
870
// Returns NULL if the instruction is not handled here.
871
static const char* F0Mnem(byte f0byte) {
872
  switch (f0byte) {
873
    case 0x18: return "prefetch";
874
    case 0xA2: return "cpuid";
875
    case 0xBE: return "movsx_b";
876
    case 0xBF: return "movsx_w";
877
    case 0xB6: return "movzx_b";
878
    case 0xB7: return "movzx_w";
879
    case 0xAF: return "imul";
880
    case 0xA5: return "shld";
881
    case 0xAD: return "shrd";
882
    case 0xAC: return "shrd";  // 3-operand version.
883
    case 0xAB: return "bts";
884
    default: return NULL;
885
  }
886
}
887

    
888

    
889
// Disassembled instruction '*instr' and writes it into 'out_buffer'.
890
int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer,
891
                                        byte* instr) {
892
  tmp_buffer_pos_ = 0;  // starting to write as position 0
893
  byte* data = instr;
894
  // Check for hints.
895
  const char* branch_hint = NULL;
896
  // We use these two prefixes only with branch prediction
897
  if (*data == 0x3E /*ds*/) {
898
    branch_hint = "predicted taken";
899
    data++;
900
  } else if (*data == 0x2E /*cs*/) {
901
    branch_hint = "predicted not taken";
902
    data++;
903
  }
904
  bool processed = true;  // Will be set to false if the current instruction
905
                          // is not in 'instructions' table.
906
  const InstructionDesc& idesc = instruction_table_->Get(*data);
907
  switch (idesc.type) {
908
    case ZERO_OPERANDS_INSTR:
909
      AppendToBuffer(idesc.mnem);
910
      data++;
911
      break;
912

    
913
    case TWO_OPERANDS_INSTR:
914
      data++;
915
      data += PrintOperands(idesc.mnem, idesc.op_order_, data);
916
      break;
917

    
918
    case JUMP_CONDITIONAL_SHORT_INSTR:
919
      data += JumpConditionalShort(data, branch_hint);
920
      break;
921

    
922
    case REGISTER_INSTR:
923
      AppendToBuffer("%s %s", idesc.mnem, NameOfCPURegister(*data & 0x07));
924
      data++;
925
      break;
926

    
927
    case MOVE_REG_INSTR: {
928
      byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
929
      AppendToBuffer("mov %s,%s",
930
                     NameOfCPURegister(*data & 0x07),
931
                     NameOfAddress(addr));
932
      data += 5;
933
      break;
934
    }
935

    
936
    case CALL_JUMP_INSTR: {
937
      byte* addr = data + *reinterpret_cast<int32_t*>(data+1) + 5;
938
      AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
939
      data += 5;
940
      break;
941
    }
942

    
943
    case SHORT_IMMEDIATE_INSTR: {
944
      byte* addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data+1));
945
      AppendToBuffer("%s eax,%s", idesc.mnem, NameOfAddress(addr));
946
      data += 5;
947
      break;
948
    }
949

    
950
    case BYTE_IMMEDIATE_INSTR: {
951
      AppendToBuffer("%s al,0x%x", idesc.mnem, data[1]);
952
      data += 2;
953
      break;
954
    }
955

    
956
    case NO_INSTR:
957
      processed = false;
958
      break;
959

    
960
    default:
961
      UNIMPLEMENTED();  // This type is not implemented.
962
  }
963
  //----------------------------
964
  if (!processed) {
965
    switch (*data) {
966
      case 0xC2:
967
        AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data+1));
968
        data += 3;
969
        break;
970

    
971
      case 0x69:  // fall through
972
      case 0x6B:
973
        { int mod, regop, rm;
974
          get_modrm(*(data+1), &mod, &regop, &rm);
975
          int32_t imm =
976
              *data == 0x6B ? *(data+2) : *reinterpret_cast<int32_t*>(data+2);
977
          AppendToBuffer("imul %s,%s,0x%x",
978
                         NameOfCPURegister(regop),
979
                         NameOfCPURegister(rm),
980
                         imm);
981
          data += 2 + (*data == 0x6B ? 1 : 4);
982
        }
983
        break;
984

    
985
      case 0xF6:
986
        { data++;
987
          int mod, regop, rm;
988
          get_modrm(*data, &mod, &regop, &rm);
989
          if (regop == eax) {
990
            AppendToBuffer("test_b ");
991
            data += PrintRightByteOperand(data);
992
            int32_t imm = *data;
993
            AppendToBuffer(",0x%x", imm);
994
            data++;
995
          } else {
996
            UnimplementedInstruction();
997
          }
998
        }
999
        break;
1000

    
1001
      case 0x81:  // fall through
1002
      case 0x83:  // 0x81 with sign extension bit set
1003
        data += PrintImmediateOp(data);
1004
        break;
1005

    
1006
      case 0x0F:
1007
        { byte f0byte = data[1];
1008
          const char* f0mnem = F0Mnem(f0byte);
1009
          if (f0byte == 0x18) {
1010
            int mod, regop, rm;
1011
            get_modrm(*data, &mod, &regop, &rm);
1012
            const char* suffix[] = {"nta", "1", "2", "3"};
1013
            AppendToBuffer("%s%s ", f0mnem, suffix[regop & 0x03]);
1014
            data += PrintRightOperand(data);
1015
          } else if (f0byte == 0x1F && data[2] == 0) {
1016
            AppendToBuffer("nop");  // 3 byte nop.
1017
            data += 3;
1018
          } else if (f0byte == 0x1F && data[2] == 0x40 && data[3] == 0) {
1019
            AppendToBuffer("nop");  // 4 byte nop.
1020
            data += 4;
1021
          } else if (f0byte == 0x1F && data[2] == 0x44 && data[3] == 0 &&
1022
                     data[4] == 0) {
1023
            AppendToBuffer("nop");  // 5 byte nop.
1024
            data += 5;
1025
          } else if (f0byte == 0x1F && data[2] == 0x80 && data[3] == 0 &&
1026
                     data[4] == 0 && data[5] == 0 && data[6] == 0) {
1027
            AppendToBuffer("nop");  // 7 byte nop.
1028
            data += 7;
1029
          } else if (f0byte == 0x1F && data[2] == 0x84 && data[3] == 0 &&
1030
                     data[4] == 0 && data[5] == 0 && data[6] == 0 &&
1031
                     data[7] == 0) {
1032
            AppendToBuffer("nop");  // 8 byte nop.
1033
            data += 8;
1034
          } else if (f0byte == 0xA2 || f0byte == 0x31) {
1035
            AppendToBuffer("%s", f0mnem);
1036
            data += 2;
1037
          } else if (f0byte == 0x28) {
1038
            data += 2;
1039
            int mod, regop, rm;
1040
            get_modrm(*data, &mod, &regop, &rm);
1041
            AppendToBuffer("movaps %s,%s",
1042
                           NameOfXMMRegister(regop),
1043
                           NameOfXMMRegister(rm));
1044
            data++;
1045
          } else if (f0byte == 0x54) {
1046
            data += 2;
1047
            int mod, regop, rm;
1048
            get_modrm(*data, &mod, &regop, &rm);
1049
            AppendToBuffer("andps %s,%s",
1050
                           NameOfXMMRegister(regop),
1051
                           NameOfXMMRegister(rm));
1052
            data++;
1053
          } else if (f0byte == 0x57) {
1054
            data += 2;
1055
            int mod, regop, rm;
1056
            get_modrm(*data, &mod, &regop, &rm);
1057
            AppendToBuffer("xorps %s,%s",
1058
                           NameOfXMMRegister(regop),
1059
                           NameOfXMMRegister(rm));
1060
            data++;
1061
          } else if (f0byte == 0x50) {
1062
            data += 2;
1063
            int mod, regop, rm;
1064
            get_modrm(*data, &mod, &regop, &rm);
1065
            AppendToBuffer("movmskps %s,%s",
1066
                           NameOfCPURegister(regop),
1067
                           NameOfXMMRegister(rm));
1068
            data++;
1069
          } else if ((f0byte & 0xF0) == 0x80) {
1070
            data += JumpConditional(data, branch_hint);
1071
          } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 ||
1072
                     f0byte == 0xB7 || f0byte == 0xAF) {
1073
            data += 2;
1074
            data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1075
          } else if ((f0byte & 0xF0) == 0x90) {
1076
            data += SetCC(data);
1077
          } else if ((f0byte & 0xF0) == 0x40) {
1078
            data += CMov(data);
1079
          } else {
1080
            data += 2;
1081
            if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1082
              // shrd, shld, bts
1083
              AppendToBuffer("%s ", f0mnem);
1084
              int mod, regop, rm;
1085
              get_modrm(*data, &mod, &regop, &rm);
1086
              data += PrintRightOperand(data);
1087
              if (f0byte == 0xAB) {
1088
                AppendToBuffer(",%s", NameOfCPURegister(regop));
1089
              } else {
1090
                AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1091
              }
1092
            } else {
1093
              UnimplementedInstruction();
1094
            }
1095
          }
1096
        }
1097
        break;
1098

    
1099
      case 0x8F:
1100
        { data++;
1101
          int mod, regop, rm;
1102
          get_modrm(*data, &mod, &regop, &rm);
1103
          if (regop == eax) {
1104
            AppendToBuffer("pop ");
1105
            data += PrintRightOperand(data);
1106
          }
1107
        }
1108
        break;
1109

    
1110
      case 0xFF:
1111
        { data++;
1112
          int mod, regop, rm;
1113
          get_modrm(*data, &mod, &regop, &rm);
1114
          const char* mnem = NULL;
1115
          switch (regop) {
1116
            case esi: mnem = "push"; break;
1117
            case eax: mnem = "inc"; break;
1118
            case ecx: mnem = "dec"; break;
1119
            case edx: mnem = "call"; break;
1120
            case esp: mnem = "jmp"; break;
1121
            default: mnem = "???";
1122
          }
1123
          AppendToBuffer("%s ", mnem);
1124
          data += PrintRightOperand(data);
1125
        }
1126
        break;
1127

    
1128
      case 0xC7:  // imm32, fall through
1129
      case 0xC6:  // imm8
1130
        { bool is_byte = *data == 0xC6;
1131
          data++;
1132
          if (is_byte) {
1133
            AppendToBuffer("%s ", "mov_b");
1134
            data += PrintRightByteOperand(data);
1135
            int32_t imm = *data;
1136
            AppendToBuffer(",0x%x", imm);
1137
            data++;
1138
          } else {
1139
            AppendToBuffer("%s ", "mov");
1140
            data += PrintRightOperand(data);
1141
            int32_t imm = *reinterpret_cast<int32_t*>(data);
1142
            AppendToBuffer(",0x%x", imm);
1143
            data += 4;
1144
          }
1145
        }
1146
        break;
1147

    
1148
      case 0x80:
1149
        { data++;
1150
          int mod, regop, rm;
1151
          get_modrm(*data, &mod, &regop, &rm);
1152
          const char* mnem = NULL;
1153
          switch (regop) {
1154
            case 5:  mnem = "subb"; break;
1155
            case 7:  mnem = "cmpb"; break;
1156
            default: UnimplementedInstruction();
1157
          }
1158
          AppendToBuffer("%s ", mnem);
1159
          data += PrintRightByteOperand(data);
1160
          int32_t imm = *data;
1161
          AppendToBuffer(",0x%x", imm);
1162
          data++;
1163
        }
1164
        break;
1165

    
1166
      case 0x88:  // 8bit, fall through
1167
      case 0x89:  // 32bit
1168
        { bool is_byte = *data == 0x88;
1169
          int mod, regop, rm;
1170
          data++;
1171
          get_modrm(*data, &mod, &regop, &rm);
1172
          if (is_byte) {
1173
            AppendToBuffer("%s ", "mov_b");
1174
            data += PrintRightByteOperand(data);
1175
            AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1176
          } else {
1177
            AppendToBuffer("%s ", "mov");
1178
            data += PrintRightOperand(data);
1179
            AppendToBuffer(",%s", NameOfCPURegister(regop));
1180
          }
1181
        }
1182
        break;
1183

    
1184
      case 0x66:  // prefix
1185
        while (*data == 0x66) data++;
1186
        if (*data == 0xf && data[1] == 0x1f) {
1187
          AppendToBuffer("nop");  // 0x66 prefix
1188
        } else if (*data == 0x90) {
1189
          AppendToBuffer("nop");  // 0x66 prefix
1190
        } else if (*data == 0x8B) {
1191
          data++;
1192
          data += PrintOperands("mov_w", REG_OPER_OP_ORDER, data);
1193
        } else if (*data == 0x89) {
1194
          data++;
1195
          int mod, regop, rm;
1196
          get_modrm(*data, &mod, &regop, &rm);
1197
          AppendToBuffer("mov_w ");
1198
          data += PrintRightOperand(data);
1199
          AppendToBuffer(",%s", NameOfCPURegister(regop));
1200
        } else if (*data == 0x0F) {
1201
          data++;
1202
          if (*data == 0x38) {
1203
            data++;
1204
            if (*data == 0x17) {
1205
              data++;
1206
              int mod, regop, rm;
1207
              get_modrm(*data, &mod, &regop, &rm);
1208
              AppendToBuffer("ptest %s,%s",
1209
                             NameOfXMMRegister(regop),
1210
                             NameOfXMMRegister(rm));
1211
              data++;
1212
            } else if (*data == 0x2A) {
1213
              // movntdqa
1214
              data++;
1215
              int mod, regop, rm;
1216
              get_modrm(*data, &mod, &regop, &rm);
1217
              AppendToBuffer("movntdqa %s,", NameOfXMMRegister(regop));
1218
              data += PrintRightOperand(data);
1219
            } else {
1220
              UnimplementedInstruction();
1221
            }
1222
          } else if (*data == 0x3A) {
1223
            data++;
1224
            if (*data == 0x0B) {
1225
              data++;
1226
              int mod, regop, rm;
1227
              get_modrm(*data, &mod, &regop, &rm);
1228
              int8_t imm8 = static_cast<int8_t>(data[1]);
1229
              AppendToBuffer("roundsd %s,%s,%d",
1230
                             NameOfXMMRegister(regop),
1231
                             NameOfXMMRegister(rm),
1232
                             static_cast<int>(imm8));
1233
              data += 2;
1234
            } else if (*data == 0x16) {
1235
              data++;
1236
              int mod, regop, rm;
1237
              get_modrm(*data, &mod, &regop, &rm);
1238
              int8_t imm8 = static_cast<int8_t>(data[1]);
1239
              AppendToBuffer("pextrd %s,%s,%d",
1240
                             NameOfCPURegister(regop),
1241
                             NameOfXMMRegister(rm),
1242
                             static_cast<int>(imm8));
1243
              data += 2;
1244
            } else if (*data == 0x17) {
1245
              data++;
1246
              int mod, regop, rm;
1247
              get_modrm(*data, &mod, &regop, &rm);
1248
              int8_t imm8 = static_cast<int8_t>(data[1]);
1249
              AppendToBuffer("extractps %s,%s,%d",
1250
                             NameOfCPURegister(rm),
1251
                             NameOfXMMRegister(regop),
1252
                             static_cast<int>(imm8));
1253
              data += 2;
1254
            } else if (*data == 0x22) {
1255
              data++;
1256
              int mod, regop, rm;
1257
              get_modrm(*data, &mod, &regop, &rm);
1258
              int8_t imm8 = static_cast<int8_t>(data[1]);
1259
              AppendToBuffer("pinsrd %s,%s,%d",
1260
                             NameOfXMMRegister(regop),
1261
                             NameOfCPURegister(rm),
1262
                             static_cast<int>(imm8));
1263
              data += 2;
1264
            } else {
1265
              UnimplementedInstruction();
1266
            }
1267
          } else if (*data == 0x2E || *data == 0x2F) {
1268
            const char* mnem = (*data == 0x2E) ? "ucomisd" : "comisd";
1269
            data++;
1270
            int mod, regop, rm;
1271
            get_modrm(*data, &mod, &regop, &rm);
1272
            if (mod == 0x3) {
1273
              AppendToBuffer("%s %s,%s", mnem,
1274
                             NameOfXMMRegister(regop),
1275
                             NameOfXMMRegister(rm));
1276
              data++;
1277
            } else {
1278
              AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1279
              data += PrintRightOperand(data);
1280
            }
1281
          } else if (*data == 0x50) {
1282
            data++;
1283
            int mod, regop, rm;
1284
            get_modrm(*data, &mod, &regop, &rm);
1285
            AppendToBuffer("movmskpd %s,%s",
1286
                           NameOfCPURegister(regop),
1287
                           NameOfXMMRegister(rm));
1288
            data++;
1289
          } else if (*data == 0x54) {
1290
            data++;
1291
            int mod, regop, rm;
1292
            get_modrm(*data, &mod, &regop, &rm);
1293
            AppendToBuffer("andpd %s,%s",
1294
                           NameOfXMMRegister(regop),
1295
                           NameOfXMMRegister(rm));
1296
            data++;
1297
          } else if (*data == 0x56) {
1298
            data++;
1299
            int mod, regop, rm;
1300
            get_modrm(*data, &mod, &regop, &rm);
1301
            AppendToBuffer("orpd %s,%s",
1302
                           NameOfXMMRegister(regop),
1303
                           NameOfXMMRegister(rm));
1304
            data++;
1305
          } else if (*data == 0x57) {
1306
            data++;
1307
            int mod, regop, rm;
1308
            get_modrm(*data, &mod, &regop, &rm);
1309
            AppendToBuffer("xorpd %s,%s",
1310
                           NameOfXMMRegister(regop),
1311
                           NameOfXMMRegister(rm));
1312
            data++;
1313
          } else if (*data == 0x6E) {
1314
            data++;
1315
            int mod, regop, rm;
1316
            get_modrm(*data, &mod, &regop, &rm);
1317
            AppendToBuffer("movd %s,", NameOfXMMRegister(regop));
1318
            data += PrintRightOperand(data);
1319
          } else if (*data == 0x6F) {
1320
            data++;
1321
            int mod, regop, rm;
1322
            get_modrm(*data, &mod, &regop, &rm);
1323
            AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
1324
            data += PrintRightXMMOperand(data);
1325
          } else if (*data == 0x70) {
1326
            data++;
1327
            int mod, regop, rm;
1328
            get_modrm(*data, &mod, &regop, &rm);
1329
            int8_t imm8 = static_cast<int8_t>(data[1]);
1330
            AppendToBuffer("pshufd %s,%s,%d",
1331
                           NameOfXMMRegister(regop),
1332
                           NameOfXMMRegister(rm),
1333
                           static_cast<int>(imm8));
1334
            data += 2;
1335
          } else if (*data == 0x76) {
1336
            data++;
1337
            int mod, regop, rm;
1338
            get_modrm(*data, &mod, &regop, &rm);
1339
            AppendToBuffer("pcmpeqd %s,%s",
1340
                           NameOfXMMRegister(regop),
1341
                           NameOfXMMRegister(rm));
1342
            data++;
1343
          } else if (*data == 0x90) {
1344
            data++;
1345
            AppendToBuffer("nop");  // 2 byte nop.
1346
          } else if (*data == 0xF3) {
1347
            data++;
1348
            int mod, regop, rm;
1349
            get_modrm(*data, &mod, &regop, &rm);
1350
            AppendToBuffer("psllq %s,%s",
1351
                           NameOfXMMRegister(regop),
1352
                           NameOfXMMRegister(rm));
1353
            data++;
1354
          } else if (*data == 0x73) {
1355
            data++;
1356
            int mod, regop, rm;
1357
            get_modrm(*data, &mod, &regop, &rm);
1358
            int8_t imm8 = static_cast<int8_t>(data[1]);
1359
            ASSERT(regop == esi || regop == edx);
1360
            AppendToBuffer("%s %s,%d",
1361
                           (regop == esi) ? "psllq" : "psrlq",
1362
                           NameOfXMMRegister(rm),
1363
                           static_cast<int>(imm8));
1364
            data += 2;
1365
          } else if (*data == 0xD3) {
1366
            data++;
1367
            int mod, regop, rm;
1368
            get_modrm(*data, &mod, &regop, &rm);
1369
            AppendToBuffer("psrlq %s,%s",
1370
                           NameOfXMMRegister(regop),
1371
                           NameOfXMMRegister(rm));
1372
            data++;
1373
          } else if (*data == 0x7F) {
1374
            AppendToBuffer("movdqa ");
1375
            data++;
1376
            int mod, regop, rm;
1377
            get_modrm(*data, &mod, &regop, &rm);
1378
            data += PrintRightXMMOperand(data);
1379
            AppendToBuffer(",%s", NameOfXMMRegister(regop));
1380
          } else if (*data == 0x7E) {
1381
            data++;
1382
            int mod, regop, rm;
1383
            get_modrm(*data, &mod, &regop, &rm);
1384
            AppendToBuffer("movd ");
1385
            data += PrintRightOperand(data);
1386
            AppendToBuffer(",%s", NameOfXMMRegister(regop));
1387
          } else if (*data == 0xDB) {
1388
            data++;
1389
            int mod, regop, rm;
1390
            get_modrm(*data, &mod, &regop, &rm);
1391
            AppendToBuffer("pand %s,%s",
1392
                           NameOfXMMRegister(regop),
1393
                           NameOfXMMRegister(rm));
1394
            data++;
1395
          } else if (*data == 0xE7) {
1396
            data++;
1397
            int mod, regop, rm;
1398
            get_modrm(*data, &mod, &regop, &rm);
1399
            if (mod == 3) {
1400
              AppendToBuffer("movntdq ");
1401
              data += PrintRightOperand(data);
1402
              AppendToBuffer(",%s", NameOfXMMRegister(regop));
1403
            } else {
1404
              UnimplementedInstruction();
1405
            }
1406
          } else if (*data == 0xEF) {
1407
            data++;
1408
            int mod, regop, rm;
1409
            get_modrm(*data, &mod, &regop, &rm);
1410
            AppendToBuffer("pxor %s,%s",
1411
                           NameOfXMMRegister(regop),
1412
                           NameOfXMMRegister(rm));
1413
            data++;
1414
          } else if (*data == 0xEB) {
1415
            data++;
1416
            int mod, regop, rm;
1417
            get_modrm(*data, &mod, &regop, &rm);
1418
            AppendToBuffer("por %s,%s",
1419
                           NameOfXMMRegister(regop),
1420
                           NameOfXMMRegister(rm));
1421
            data++;
1422
          } else {
1423
            UnimplementedInstruction();
1424
          }
1425
        } else {
1426
          UnimplementedInstruction();
1427
        }
1428
        break;
1429

    
1430
      case 0xFE:
1431
        { data++;
1432
          int mod, regop, rm;
1433
          get_modrm(*data, &mod, &regop, &rm);
1434
          if (regop == ecx) {
1435
            AppendToBuffer("dec_b ");
1436
            data += PrintRightOperand(data);
1437
          } else {
1438
            UnimplementedInstruction();
1439
          }
1440
        }
1441
        break;
1442

    
1443
      case 0x68:
1444
        AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data+1));
1445
        data += 5;
1446
        break;
1447

    
1448
      case 0x6A:
1449
        AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1450
        data += 2;
1451
        break;
1452

    
1453
      case 0xA8:
1454
        AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data+1));
1455
        data += 2;
1456
        break;
1457

    
1458
      case 0xA9:
1459
        AppendToBuffer("test eax,0x%x", *reinterpret_cast<int32_t*>(data+1));
1460
        data += 5;
1461
        break;
1462

    
1463
      case 0xD1:  // fall through
1464
      case 0xD3:  // fall through
1465
      case 0xC1:
1466
        data += D1D3C1Instruction(data);
1467
        break;
1468

    
1469
      case 0xD8:  // fall through
1470
      case 0xD9:  // fall through
1471
      case 0xDA:  // fall through
1472
      case 0xDB:  // fall through
1473
      case 0xDC:  // fall through
1474
      case 0xDD:  // fall through
1475
      case 0xDE:  // fall through
1476
      case 0xDF:
1477
        data += FPUInstruction(data);
1478
        break;
1479

    
1480
      case 0xEB:
1481
        data += JumpShort(data);
1482
        break;
1483

    
1484
      case 0xF2:
1485
        if (*(data+1) == 0x0F) {
1486
          byte b2 = *(data+2);
1487
          if (b2 == 0x11) {
1488
            AppendToBuffer("movsd ");
1489
            data += 3;
1490
            int mod, regop, rm;
1491
            get_modrm(*data, &mod, &regop, &rm);
1492
            data += PrintRightXMMOperand(data);
1493
            AppendToBuffer(",%s", NameOfXMMRegister(regop));
1494
          } else if (b2 == 0x10) {
1495
            data += 3;
1496
            int mod, regop, rm;
1497
            get_modrm(*data, &mod, &regop, &rm);
1498
            AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
1499
            data += PrintRightXMMOperand(data);
1500
          } else  if (b2 == 0x5A) {
1501
            data += 3;
1502
            int mod, regop, rm;
1503
            get_modrm(*data, &mod, &regop, &rm);
1504
            AppendToBuffer("cvtsd2ss %s,", NameOfXMMRegister(regop));
1505
            data += PrintRightXMMOperand(data);
1506
          } else {
1507
            const char* mnem = "?";
1508
            switch (b2) {
1509
              case 0x2A: mnem = "cvtsi2sd"; break;
1510
              case 0x2C: mnem = "cvttsd2si"; break;
1511
              case 0x2D: mnem = "cvtsd2si"; break;
1512
              case 0x51: mnem = "sqrtsd"; break;
1513
              case 0x58: mnem = "addsd"; break;
1514
              case 0x59: mnem = "mulsd"; break;
1515
              case 0x5C: mnem = "subsd"; break;
1516
              case 0x5E: mnem = "divsd"; break;
1517
            }
1518
            data += 3;
1519
            int mod, regop, rm;
1520
            get_modrm(*data, &mod, &regop, &rm);
1521
            if (b2 == 0x2A) {
1522
              AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1523
              data += PrintRightOperand(data);
1524
            } else if (b2 == 0x2C || b2 == 0x2D) {
1525
              AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop));
1526
              data += PrintRightXMMOperand(data);
1527
            } else if (b2 == 0xC2) {
1528
              // Intel manual 2A, Table 3-18.
1529
              const char* const pseudo_op[] = {
1530
                "cmpeqsd",
1531
                "cmpltsd",
1532
                "cmplesd",
1533
                "cmpunordsd",
1534
                "cmpneqsd",
1535
                "cmpnltsd",
1536
                "cmpnlesd",
1537
                "cmpordsd"
1538
              };
1539
              AppendToBuffer("%s %s,%s",
1540
                             pseudo_op[data[1]],
1541
                             NameOfXMMRegister(regop),
1542
                             NameOfXMMRegister(rm));
1543
              data += 2;
1544
            } else {
1545
              AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1546
              data += PrintRightXMMOperand(data);
1547
            }
1548
          }
1549
        } else {
1550
          UnimplementedInstruction();
1551
        }
1552
        break;
1553

    
1554
      case 0xF3:
1555
        if (*(data+1) == 0x0F) {
1556
          byte b2 = *(data+2);
1557
          if (b2 == 0x11) {
1558
            AppendToBuffer("movss ");
1559
            data += 3;
1560
            int mod, regop, rm;
1561
            get_modrm(*data, &mod, &regop, &rm);
1562
            data += PrintRightXMMOperand(data);
1563
            AppendToBuffer(",%s", NameOfXMMRegister(regop));
1564
          } else if (b2 == 0x10) {
1565
            data += 3;
1566
            int mod, regop, rm;
1567
            get_modrm(*data, &mod, &regop, &rm);
1568
            AppendToBuffer("movss %s,", NameOfXMMRegister(regop));
1569
            data += PrintRightXMMOperand(data);
1570
          } else if (b2 == 0x2C) {
1571
            data += 3;
1572
            int mod, regop, rm;
1573
            get_modrm(*data, &mod, &regop, &rm);
1574
            AppendToBuffer("cvttss2si %s,", NameOfCPURegister(regop));
1575
            data += PrintRightXMMOperand(data);
1576
          } else if (b2 == 0x5A) {
1577
            data += 3;
1578
            int mod, regop, rm;
1579
            get_modrm(*data, &mod, &regop, &rm);
1580
            AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1581
            data += PrintRightXMMOperand(data);
1582
          } else  if (b2 == 0x6F) {
1583
            data += 3;
1584
            int mod, regop, rm;
1585
            get_modrm(*data, &mod, &regop, &rm);
1586
            AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
1587
            data += PrintRightXMMOperand(data);
1588
          } else  if (b2 == 0x7F) {
1589
            AppendToBuffer("movdqu ");
1590
            data += 3;
1591
            int mod, regop, rm;
1592
            get_modrm(*data, &mod, &regop, &rm);
1593
            data += PrintRightXMMOperand(data);
1594
            AppendToBuffer(",%s", NameOfXMMRegister(regop));
1595
          } else {
1596
            UnimplementedInstruction();
1597
          }
1598
        } else if (*(data+1) == 0xA5) {
1599
          data += 2;
1600
          AppendToBuffer("rep_movs");
1601
        } else if (*(data+1) == 0xAB) {
1602
          data += 2;
1603
          AppendToBuffer("rep_stos");
1604
        } else {
1605
          UnimplementedInstruction();
1606
        }
1607
        break;
1608

    
1609
      case 0xF7:
1610
        data += F7Instruction(data);
1611
        break;
1612

    
1613
      default:
1614
        UnimplementedInstruction();
1615
    }
1616
  }
1617

    
1618
  if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1619
    tmp_buffer_[tmp_buffer_pos_] = '\0';
1620
  }
1621

    
1622
  int instr_len = data - instr;
1623
  if (instr_len == 0) {
1624
    printf("%02x", *data);
1625
  }
1626
  ASSERT(instr_len > 0);  // Ensure progress.
1627

    
1628
  int outp = 0;
1629
  // Instruction bytes.
1630
  for (byte* bp = instr; bp < data; bp++) {
1631
    outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1632
                                       "%02x",
1633
                                       *bp);
1634
  }
1635
  for (int i = 6 - instr_len; i >= 0; i--) {
1636
    outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1637
                                       "  ");
1638
  }
1639

    
1640
  outp += v8::internal::OS::SNPrintF(out_buffer + outp,
1641
                                     " %s",
1642
                                     tmp_buffer_.start());
1643
  return instr_len;
1644
}  // NOLINT (function is too long)
1645

    
1646

    
1647
//------------------------------------------------------------------------------
1648

    
1649

    
1650
static const char* cpu_regs[8] = {
1651
  "eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"
1652
};
1653

    
1654

    
1655
static const char* byte_cpu_regs[8] = {
1656
  "al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"
1657
};
1658

    
1659

    
1660
static const char* xmm_regs[8] = {
1661
  "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7"
1662
};
1663

    
1664

    
1665
const char* NameConverter::NameOfAddress(byte* addr) const {
1666
  v8::internal::OS::SNPrintF(tmp_buffer_, "%p", addr);
1667
  return tmp_buffer_.start();
1668
}
1669

    
1670

    
1671
const char* NameConverter::NameOfConstant(byte* addr) const {
1672
  return NameOfAddress(addr);
1673
}
1674

    
1675

    
1676
const char* NameConverter::NameOfCPURegister(int reg) const {
1677
  if (0 <= reg && reg < 8) return cpu_regs[reg];
1678
  return "noreg";
1679
}
1680

    
1681

    
1682
const char* NameConverter::NameOfByteCPURegister(int reg) const {
1683
  if (0 <= reg && reg < 8) return byte_cpu_regs[reg];
1684
  return "noreg";
1685
}
1686

    
1687

    
1688
const char* NameConverter::NameOfXMMRegister(int reg) const {
1689
  if (0 <= reg && reg < 8) return xmm_regs[reg];
1690
  return "noxmmreg";
1691
}
1692

    
1693

    
1694
const char* NameConverter::NameInCode(byte* addr) const {
1695
  // IA32 does not embed debug strings at the moment.
1696
  UNREACHABLE();
1697
  return "";
1698
}
1699

    
1700

    
1701
//------------------------------------------------------------------------------
1702

    
1703
Disassembler::Disassembler(const NameConverter& converter)
1704
    : converter_(converter) {}
1705

    
1706

    
1707
Disassembler::~Disassembler() {}
1708

    
1709

    
1710
int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1711
                                    byte* instruction) {
1712
  DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/);
1713
  return d.InstructionDecode(buffer, instruction);
1714
}
1715

    
1716

    
1717
// The IA-32 assembler does not currently use constant pools.
1718
int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
1719

    
1720

    
1721
/*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1722
  NameConverter converter;
1723
  Disassembler d(converter);
1724
  for (byte* pc = begin; pc < end;) {
1725
    v8::internal::EmbeddedVector<char, 128> buffer;
1726
    buffer[0] = '\0';
1727
    byte* prev_pc = pc;
1728
    pc += d.InstructionDecode(buffer, pc);
1729
    fprintf(f, "%p", prev_pc);
1730
    fprintf(f, "    ");
1731

    
1732
    for (byte* bp = prev_pc; bp < pc; bp++) {
1733
      fprintf(f, "%02x",  *bp);
1734
    }
1735
    for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
1736
      fprintf(f, "  ");
1737
    }
1738
    fprintf(f, "  %s\n", buffer.start());
1739
  }
1740
}
1741

    
1742

    
1743
}  // namespace disasm
1744

    
1745
#endif  // V8_TARGET_ARCH_IA32