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 / x64 / disasm-x64.cc @ f230a1cf

History | View | Annotate | Download (56.2 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_X64
35

    
36
#include "disasm.h"
37
#include "lazy-instance.h"
38

    
39
namespace disasm {
40

    
41
enum OperandType {
42
  UNSET_OP_ORDER = 0,
43
  // Operand size decides between 16, 32 and 64 bit operands.
44
  REG_OPER_OP_ORDER = 1,  // Register destination, operand source.
45
  OPER_REG_OP_ORDER = 2,  // Operand destination, register source.
46
  // Fixed 8-bit operands.
47
  BYTE_SIZE_OPERAND_FLAG = 4,
48
  BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG,
49
  BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
50
};
51

    
52

    
53
//------------------------------------------------------------------
54
// Tables
55
//------------------------------------------------------------------
56
struct ByteMnemonic {
57
  int b;  // -1 terminates, otherwise must be in range (0..255)
58
  OperandType op_order_;
59
  const char* mnem;
60
};
61

    
62

    
63
static const ByteMnemonic two_operands_instr[] = {
64
  { 0x00, BYTE_OPER_REG_OP_ORDER, "add" },
65
  { 0x01, OPER_REG_OP_ORDER,      "add" },
66
  { 0x02, BYTE_REG_OPER_OP_ORDER, "add" },
67
  { 0x03, REG_OPER_OP_ORDER,      "add" },
68
  { 0x08, BYTE_OPER_REG_OP_ORDER, "or" },
69
  { 0x09, OPER_REG_OP_ORDER,      "or" },
70
  { 0x0A, BYTE_REG_OPER_OP_ORDER, "or" },
71
  { 0x0B, REG_OPER_OP_ORDER,      "or" },
72
  { 0x10, BYTE_OPER_REG_OP_ORDER, "adc" },
73
  { 0x11, OPER_REG_OP_ORDER,      "adc" },
74
  { 0x12, BYTE_REG_OPER_OP_ORDER, "adc" },
75
  { 0x13, REG_OPER_OP_ORDER,      "adc" },
76
  { 0x18, BYTE_OPER_REG_OP_ORDER, "sbb" },
77
  { 0x19, OPER_REG_OP_ORDER,      "sbb" },
78
  { 0x1A, BYTE_REG_OPER_OP_ORDER, "sbb" },
79
  { 0x1B, REG_OPER_OP_ORDER,      "sbb" },
80
  { 0x20, BYTE_OPER_REG_OP_ORDER, "and" },
81
  { 0x21, OPER_REG_OP_ORDER,      "and" },
82
  { 0x22, BYTE_REG_OPER_OP_ORDER, "and" },
83
  { 0x23, REG_OPER_OP_ORDER,      "and" },
84
  { 0x28, BYTE_OPER_REG_OP_ORDER, "sub" },
85
  { 0x29, OPER_REG_OP_ORDER,      "sub" },
86
  { 0x2A, BYTE_REG_OPER_OP_ORDER, "sub" },
87
  { 0x2B, REG_OPER_OP_ORDER,      "sub" },
88
  { 0x30, BYTE_OPER_REG_OP_ORDER, "xor" },
89
  { 0x31, OPER_REG_OP_ORDER,      "xor" },
90
  { 0x32, BYTE_REG_OPER_OP_ORDER, "xor" },
91
  { 0x33, REG_OPER_OP_ORDER,      "xor" },
92
  { 0x38, BYTE_OPER_REG_OP_ORDER, "cmp" },
93
  { 0x39, OPER_REG_OP_ORDER,      "cmp" },
94
  { 0x3A, BYTE_REG_OPER_OP_ORDER, "cmp" },
95
  { 0x3B, REG_OPER_OP_ORDER,      "cmp" },
96
  { 0x63, REG_OPER_OP_ORDER,      "movsxl" },
97
  { 0x84, BYTE_REG_OPER_OP_ORDER, "test" },
98
  { 0x85, REG_OPER_OP_ORDER,      "test" },
99
  { 0x86, BYTE_REG_OPER_OP_ORDER, "xchg" },
100
  { 0x87, REG_OPER_OP_ORDER,      "xchg" },
101
  { 0x88, BYTE_OPER_REG_OP_ORDER, "mov" },
102
  { 0x89, OPER_REG_OP_ORDER,      "mov" },
103
  { 0x8A, BYTE_REG_OPER_OP_ORDER, "mov" },
104
  { 0x8B, REG_OPER_OP_ORDER,      "mov" },
105
  { 0x8D, REG_OPER_OP_ORDER,      "lea" },
106
  { -1, UNSET_OP_ORDER, "" }
107
};
108

    
109

    
110
static const ByteMnemonic zero_operands_instr[] = {
111
  { 0xC3, UNSET_OP_ORDER, "ret" },
112
  { 0xC9, UNSET_OP_ORDER, "leave" },
113
  { 0xF4, UNSET_OP_ORDER, "hlt" },
114
  { 0xFC, UNSET_OP_ORDER, "cld" },
115
  { 0xCC, UNSET_OP_ORDER, "int3" },
116
  { 0x60, UNSET_OP_ORDER, "pushad" },
117
  { 0x61, UNSET_OP_ORDER, "popad" },
118
  { 0x9C, UNSET_OP_ORDER, "pushfd" },
119
  { 0x9D, UNSET_OP_ORDER, "popfd" },
120
  { 0x9E, UNSET_OP_ORDER, "sahf" },
121
  { 0x99, UNSET_OP_ORDER, "cdq" },
122
  { 0x9B, UNSET_OP_ORDER, "fwait" },
123
  { 0xA4, UNSET_OP_ORDER, "movs" },
124
  { 0xA5, UNSET_OP_ORDER, "movs" },
125
  { 0xA6, UNSET_OP_ORDER, "cmps" },
126
  { 0xA7, UNSET_OP_ORDER, "cmps" },
127
  { -1, UNSET_OP_ORDER, "" }
128
};
129

    
130

    
131
static const ByteMnemonic call_jump_instr[] = {
132
  { 0xE8, UNSET_OP_ORDER, "call" },
133
  { 0xE9, UNSET_OP_ORDER, "jmp" },
134
  { -1, UNSET_OP_ORDER, "" }
135
};
136

    
137

    
138
static const ByteMnemonic short_immediate_instr[] = {
139
  { 0x05, UNSET_OP_ORDER, "add" },
140
  { 0x0D, UNSET_OP_ORDER, "or" },
141
  { 0x15, UNSET_OP_ORDER, "adc" },
142
  { 0x1D, UNSET_OP_ORDER, "sbb" },
143
  { 0x25, UNSET_OP_ORDER, "and" },
144
  { 0x2D, UNSET_OP_ORDER, "sub" },
145
  { 0x35, UNSET_OP_ORDER, "xor" },
146
  { 0x3D, UNSET_OP_ORDER, "cmp" },
147
  { -1, UNSET_OP_ORDER, "" }
148
};
149

    
150

    
151
static const char* const conditional_code_suffix[] = {
152
  "o", "no", "c", "nc", "z", "nz", "na", "a",
153
  "s", "ns", "pe", "po", "l", "ge", "le", "g"
154
};
155

    
156

    
157
enum InstructionType {
158
  NO_INSTR,
159
  ZERO_OPERANDS_INSTR,
160
  TWO_OPERANDS_INSTR,
161
  JUMP_CONDITIONAL_SHORT_INSTR,
162
  REGISTER_INSTR,
163
  PUSHPOP_INSTR,  // Has implicit 64-bit operand size.
164
  MOVE_REG_INSTR,
165
  CALL_JUMP_INSTR,
166
  SHORT_IMMEDIATE_INSTR
167
};
168

    
169

    
170
enum Prefixes {
171
  ESCAPE_PREFIX = 0x0F,
172
  OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
173
  ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
174
  REPNE_PREFIX = 0xF2,
175
  REP_PREFIX = 0xF3,
176
  REPEQ_PREFIX = REP_PREFIX
177
};
178

    
179

    
180
struct InstructionDesc {
181
  const char* mnem;
182
  InstructionType type;
183
  OperandType op_order_;
184
  bool byte_size_operation;  // Fixed 8-bit operation.
185
};
186

    
187

    
188
class InstructionTable {
189
 public:
190
  InstructionTable();
191
  const InstructionDesc& Get(byte x) const {
192
    return instructions_[x];
193
  }
194

    
195
 private:
196
  InstructionDesc instructions_[256];
197
  void Clear();
198
  void Init();
199
  void CopyTable(const ByteMnemonic bm[], InstructionType type);
200
  void SetTableRange(InstructionType type, byte start, byte end, bool byte_size,
201
                     const char* mnem);
202
  void AddJumpConditionalShort();
203
};
204

    
205

    
206
InstructionTable::InstructionTable() {
207
  Clear();
208
  Init();
209
}
210

    
211

    
212
void InstructionTable::Clear() {
213
  for (int i = 0; i < 256; i++) {
214
    instructions_[i].mnem = "(bad)";
215
    instructions_[i].type = NO_INSTR;
216
    instructions_[i].op_order_ = UNSET_OP_ORDER;
217
    instructions_[i].byte_size_operation = false;
218
  }
219
}
220

    
221

    
222
void InstructionTable::Init() {
223
  CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
224
  CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
225
  CopyTable(call_jump_instr, CALL_JUMP_INSTR);
226
  CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
227
  AddJumpConditionalShort();
228
  SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push");
229
  SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop");
230
  SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov");
231
}
232

    
233

    
234
void InstructionTable::CopyTable(const ByteMnemonic bm[],
235
                                 InstructionType type) {
236
  for (int i = 0; bm[i].b >= 0; i++) {
237
    InstructionDesc* id = &instructions_[bm[i].b];
238
    id->mnem = bm[i].mnem;
239
    OperandType op_order = bm[i].op_order_;
240
    id->op_order_ =
241
        static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
242
    ASSERT_EQ(NO_INSTR, id->type);  // Information not already entered
243
    id->type = type;
244
    id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
245
  }
246
}
247

    
248

    
249
void InstructionTable::SetTableRange(InstructionType type,
250
                                     byte start,
251
                                     byte end,
252
                                     bool byte_size,
253
                                     const char* mnem) {
254
  for (byte b = start; b <= end; b++) {
255
    InstructionDesc* id = &instructions_[b];
256
    ASSERT_EQ(NO_INSTR, id->type);  // Information not already entered
257
    id->mnem = mnem;
258
    id->type = type;
259
    id->byte_size_operation = byte_size;
260
  }
261
}
262

    
263

    
264
void InstructionTable::AddJumpConditionalShort() {
265
  for (byte b = 0x70; b <= 0x7F; b++) {
266
    InstructionDesc* id = &instructions_[b];
267
    ASSERT_EQ(NO_INSTR, id->type);  // Information not already entered
268
    id->mnem = NULL;  // Computed depending on condition code.
269
    id->type = JUMP_CONDITIONAL_SHORT_INSTR;
270
  }
271
}
272

    
273

    
274
static v8::internal::LazyInstance<InstructionTable>::type instruction_table =
275
    LAZY_INSTANCE_INITIALIZER;
276

    
277

    
278
static InstructionDesc cmov_instructions[16] = {
279
  {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
280
  {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
281
  {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
282
  {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
283
  {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
284
  {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
285
  {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
286
  {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
287
  {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
288
  {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
289
  {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
290
  {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
291
  {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
292
  {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
293
  {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
294
  {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}
295
};
296

    
297

    
298
//------------------------------------------------------------------------------
299
// DisassemblerX64 implementation.
300

    
301
enum UnimplementedOpcodeAction {
302
  CONTINUE_ON_UNIMPLEMENTED_OPCODE,
303
  ABORT_ON_UNIMPLEMENTED_OPCODE
304
};
305

    
306

    
307
// A new DisassemblerX64 object is created to disassemble each instruction.
308
// The object can only disassemble a single instruction.
309
class DisassemblerX64 {
310
 public:
311
  DisassemblerX64(const NameConverter& converter,
312
                  UnimplementedOpcodeAction unimplemented_action =
313
                      ABORT_ON_UNIMPLEMENTED_OPCODE)
314
      : converter_(converter),
315
        tmp_buffer_pos_(0),
316
        abort_on_unimplemented_(
317
            unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE),
318
        rex_(0),
319
        operand_size_(0),
320
        group_1_prefix_(0),
321
        byte_size_operand_(false),
322
        instruction_table_(instruction_table.Pointer()) {
323
    tmp_buffer_[0] = '\0';
324
  }
325

    
326
  virtual ~DisassemblerX64() {
327
  }
328

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

    
333
 private:
334
  enum OperandSize {
335
    OPERAND_BYTE_SIZE = 0,
336
    OPERAND_WORD_SIZE = 1,
337
    OPERAND_DOUBLEWORD_SIZE = 2,
338
    OPERAND_QUADWORD_SIZE = 3
339
  };
340

    
341
  const NameConverter& converter_;
342
  v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
343
  unsigned int tmp_buffer_pos_;
344
  bool abort_on_unimplemented_;
345
  // Prefixes parsed
346
  byte rex_;
347
  byte operand_size_;  // 0x66 or (if no group 3 prefix is present) 0x0.
348
  byte group_1_prefix_;  // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
349
  // Byte size operand override.
350
  bool byte_size_operand_;
351
  const InstructionTable* const instruction_table_;
352

    
353
  void setRex(byte rex) {
354
    ASSERT_EQ(0x40, rex & 0xF0);
355
    rex_ = rex;
356
  }
357

    
358
  bool rex() { return rex_ != 0; }
359

    
360
  bool rex_b() { return (rex_ & 0x01) != 0; }
361

    
362
  // Actual number of base register given the low bits and the rex.b state.
363
  int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); }
364

    
365
  bool rex_x() { return (rex_ & 0x02) != 0; }
366

    
367
  bool rex_r() { return (rex_ & 0x04) != 0; }
368

    
369
  bool rex_w() { return (rex_ & 0x08) != 0; }
370

    
371
  OperandSize operand_size() {
372
    if (byte_size_operand_) return OPERAND_BYTE_SIZE;
373
    if (rex_w()) return OPERAND_QUADWORD_SIZE;
374
    if (operand_size_ != 0) return OPERAND_WORD_SIZE;
375
    return OPERAND_DOUBLEWORD_SIZE;
376
  }
377

    
378
  char operand_size_code() {
379
    return "bwlq"[operand_size()];
380
  }
381

    
382
  const char* NameOfCPURegister(int reg) const {
383
    return converter_.NameOfCPURegister(reg);
384
  }
385

    
386
  const char* NameOfByteCPURegister(int reg) const {
387
    return converter_.NameOfByteCPURegister(reg);
388
  }
389

    
390
  const char* NameOfXMMRegister(int reg) const {
391
    return converter_.NameOfXMMRegister(reg);
392
  }
393

    
394
  const char* NameOfAddress(byte* addr) const {
395
    return converter_.NameOfAddress(addr);
396
  }
397

    
398
  // Disassembler helper functions.
399
  void get_modrm(byte data,
400
                 int* mod,
401
                 int* regop,
402
                 int* rm) {
403
    *mod = (data >> 6) & 3;
404
    *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0);
405
    *rm = (data & 7) | (rex_b() ? 8 : 0);
406
  }
407

    
408
  void get_sib(byte data,
409
               int* scale,
410
               int* index,
411
               int* base) {
412
    *scale = (data >> 6) & 3;
413
    *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
414
    *base = (data & 7) | (rex_b() ? 8 : 0);
415
  }
416

    
417
  typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const;
418

    
419
  int PrintRightOperandHelper(byte* modrmp,
420
                              RegisterNameMapping register_name);
421
  int PrintRightOperand(byte* modrmp);
422
  int PrintRightByteOperand(byte* modrmp);
423
  int PrintRightXMMOperand(byte* modrmp);
424
  int PrintOperands(const char* mnem,
425
                    OperandType op_order,
426
                    byte* data);
427
  int PrintImmediate(byte* data, OperandSize size);
428
  int PrintImmediateOp(byte* data);
429
  const char* TwoByteMnemonic(byte opcode);
430
  int TwoByteOpcodeInstruction(byte* data);
431
  int F6F7Instruction(byte* data);
432
  int ShiftInstruction(byte* data);
433
  int JumpShort(byte* data);
434
  int JumpConditional(byte* data);
435
  int JumpConditionalShort(byte* data);
436
  int SetCC(byte* data);
437
  int FPUInstruction(byte* data);
438
  int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
439
  int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
440
  void AppendToBuffer(const char* format, ...);
441

    
442
  void UnimplementedInstruction() {
443
    if (abort_on_unimplemented_) {
444
      CHECK(false);
445
    } else {
446
      AppendToBuffer("'Unimplemented Instruction'");
447
    }
448
  }
449
};
450

    
451

    
452
void DisassemblerX64::AppendToBuffer(const char* format, ...) {
453
  v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
454
  va_list args;
455
  va_start(args, format);
456
  int result = v8::internal::OS::VSNPrintF(buf, format, args);
457
  va_end(args);
458
  tmp_buffer_pos_ += result;
459
}
460

    
461

    
462
int DisassemblerX64::PrintRightOperandHelper(
463
    byte* modrmp,
464
    RegisterNameMapping direct_register_name) {
465
  int mod, regop, rm;
466
  get_modrm(*modrmp, &mod, &regop, &rm);
467
  RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
468
      &DisassemblerX64::NameOfCPURegister;
469
  switch (mod) {
470
    case 0:
471
      if ((rm & 7) == 5) {
472
        int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1);
473
        AppendToBuffer("[0x%x]", disp);
474
        return 5;
475
      } else if ((rm & 7) == 4) {
476
        // Codes for SIB byte.
477
        byte sib = *(modrmp + 1);
478
        int scale, index, base;
479
        get_sib(sib, &scale, &index, &base);
480
        if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
481
          // index == rsp means no index. Only use sib byte with no index for
482
          // rsp and r12 base.
483
          AppendToBuffer("[%s]", NameOfCPURegister(base));
484
          return 2;
485
        } else if (base == 5) {
486
          // base == rbp means no base register (when mod == 0).
487
          int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
488
          AppendToBuffer("[%s*%d+0x%x]",
489
                         NameOfCPURegister(index),
490
                         1 << scale, disp);
491
          return 6;
492
        } else if (index != 4 && base != 5) {
493
          // [base+index*scale]
494
          AppendToBuffer("[%s+%s*%d]",
495
                         NameOfCPURegister(base),
496
                         NameOfCPURegister(index),
497
                         1 << scale);
498
          return 2;
499
        } else {
500
          UnimplementedInstruction();
501
          return 1;
502
        }
503
      } else {
504
        AppendToBuffer("[%s]", NameOfCPURegister(rm));
505
        return 1;
506
      }
507
      break;
508
    case 1:  // fall through
509
    case 2:
510
      if ((rm & 7) == 4) {
511
        byte sib = *(modrmp + 1);
512
        int scale, index, base;
513
        get_sib(sib, &scale, &index, &base);
514
        int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2)
515
                              : *reinterpret_cast<char*>(modrmp + 2);
516
        if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
517
          if (-disp > 0) {
518
            AppendToBuffer("[%s-0x%x]", NameOfCPURegister(base), -disp);
519
          } else {
520
            AppendToBuffer("[%s+0x%x]", NameOfCPURegister(base), disp);
521
          }
522
        } else {
523
          if (-disp > 0) {
524
            AppendToBuffer("[%s+%s*%d-0x%x]",
525
                           NameOfCPURegister(base),
526
                           NameOfCPURegister(index),
527
                           1 << scale,
528
                           -disp);
529
          } else {
530
            AppendToBuffer("[%s+%s*%d+0x%x]",
531
                           NameOfCPURegister(base),
532
                           NameOfCPURegister(index),
533
                           1 << scale,
534
                           disp);
535
          }
536
        }
537
        return mod == 2 ? 6 : 3;
538
      } else {
539
        // No sib.
540
        int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1)
541
                              : *reinterpret_cast<char*>(modrmp + 1);
542
        if (-disp > 0) {
543
        AppendToBuffer("[%s-0x%x]", NameOfCPURegister(rm), -disp);
544
        } else {
545
        AppendToBuffer("[%s+0x%x]", NameOfCPURegister(rm), disp);
546
        }
547
        return (mod == 2) ? 5 : 2;
548
      }
549
      break;
550
    case 3:
551
      AppendToBuffer("%s", (this->*register_name)(rm));
552
      return 1;
553
    default:
554
      UnimplementedInstruction();
555
      return 1;
556
  }
557
  UNREACHABLE();
558
}
559

    
560

    
561
int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) {
562
  int64_t value;
563
  int count;
564
  switch (size) {
565
    case OPERAND_BYTE_SIZE:
566
      value = *data;
567
      count = 1;
568
      break;
569
    case OPERAND_WORD_SIZE:
570
      value = *reinterpret_cast<int16_t*>(data);
571
      count = 2;
572
      break;
573
    case OPERAND_DOUBLEWORD_SIZE:
574
      value = *reinterpret_cast<uint32_t*>(data);
575
      count = 4;
576
      break;
577
    case OPERAND_QUADWORD_SIZE:
578
      value = *reinterpret_cast<int32_t*>(data);
579
      count = 4;
580
      break;
581
    default:
582
      UNREACHABLE();
583
      value = 0;  // Initialize variables on all paths to satisfy the compiler.
584
      count = 0;
585
  }
586
  AppendToBuffer("%" V8_PTR_PREFIX "x", value);
587
  return count;
588
}
589

    
590

    
591
int DisassemblerX64::PrintRightOperand(byte* modrmp) {
592
  return PrintRightOperandHelper(modrmp,
593
                                 &DisassemblerX64::NameOfCPURegister);
594
}
595

    
596

    
597
int DisassemblerX64::PrintRightByteOperand(byte* modrmp) {
598
  return PrintRightOperandHelper(modrmp,
599
                                 &DisassemblerX64::NameOfByteCPURegister);
600
}
601

    
602

    
603
int DisassemblerX64::PrintRightXMMOperand(byte* modrmp) {
604
  return PrintRightOperandHelper(modrmp,
605
                                 &DisassemblerX64::NameOfXMMRegister);
606
}
607

    
608

    
609
// Returns number of bytes used including the current *data.
610
// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
611
int DisassemblerX64::PrintOperands(const char* mnem,
612
                                   OperandType op_order,
613
                                   byte* data) {
614
  byte modrm = *data;
615
  int mod, regop, rm;
616
  get_modrm(modrm, &mod, &regop, &rm);
617
  int advance = 0;
618
  const char* register_name =
619
      byte_size_operand_ ? NameOfByteCPURegister(regop)
620
                         : NameOfCPURegister(regop);
621
  switch (op_order) {
622
    case REG_OPER_OP_ORDER: {
623
      AppendToBuffer("%s%c %s,",
624
                     mnem,
625
                     operand_size_code(),
626
                     register_name);
627
      advance = byte_size_operand_ ? PrintRightByteOperand(data)
628
                                   : PrintRightOperand(data);
629
      break;
630
    }
631
    case OPER_REG_OP_ORDER: {
632
      AppendToBuffer("%s%c ", mnem, operand_size_code());
633
      advance = byte_size_operand_ ? PrintRightByteOperand(data)
634
                                   : PrintRightOperand(data);
635
      AppendToBuffer(",%s", register_name);
636
      break;
637
    }
638
    default:
639
      UNREACHABLE();
640
      break;
641
  }
642
  return advance;
643
}
644

    
645

    
646
// Returns number of bytes used by machine instruction, including *data byte.
647
// Writes immediate instructions to 'tmp_buffer_'.
648
int DisassemblerX64::PrintImmediateOp(byte* data) {
649
  bool byte_size_immediate = (*data & 0x02) != 0;
650
  byte modrm = *(data + 1);
651
  int mod, regop, rm;
652
  get_modrm(modrm, &mod, &regop, &rm);
653
  const char* mnem = "Imm???";
654
  switch (regop) {
655
    case 0:
656
      mnem = "add";
657
      break;
658
    case 1:
659
      mnem = "or";
660
      break;
661
    case 2:
662
      mnem = "adc";
663
      break;
664
    case 3:
665
      mnem = "sbb";
666
      break;
667
    case 4:
668
      mnem = "and";
669
      break;
670
    case 5:
671
      mnem = "sub";
672
      break;
673
    case 6:
674
      mnem = "xor";
675
      break;
676
    case 7:
677
      mnem = "cmp";
678
      break;
679
    default:
680
      UnimplementedInstruction();
681
  }
682
  AppendToBuffer("%s%c ", mnem, operand_size_code());
683
  int count = PrintRightOperand(data + 1);
684
  AppendToBuffer(",0x");
685
  OperandSize immediate_size =
686
      byte_size_immediate ? OPERAND_BYTE_SIZE : operand_size();
687
  count += PrintImmediate(data + 1 + count, immediate_size);
688
  return 1 + count;
689
}
690

    
691

    
692
// Returns number of bytes used, including *data.
693
int DisassemblerX64::F6F7Instruction(byte* data) {
694
  ASSERT(*data == 0xF7 || *data == 0xF6);
695
  byte modrm = *(data + 1);
696
  int mod, regop, rm;
697
  get_modrm(modrm, &mod, &regop, &rm);
698
  if (mod == 3 && regop != 0) {
699
    const char* mnem = NULL;
700
    switch (regop) {
701
      case 2:
702
        mnem = "not";
703
        break;
704
      case 3:
705
        mnem = "neg";
706
        break;
707
      case 4:
708
        mnem = "mul";
709
        break;
710
      case 5:
711
        mnem = "imul";
712
        break;
713
      case 7:
714
        mnem = "idiv";
715
        break;
716
      default:
717
        UnimplementedInstruction();
718
    }
719
    AppendToBuffer("%s%c %s",
720
                   mnem,
721
                   operand_size_code(),
722
                   NameOfCPURegister(rm));
723
    return 2;
724
  } else if (regop == 0) {
725
    AppendToBuffer("test%c ", operand_size_code());
726
    int count = PrintRightOperand(data + 1);  // Use name of 64-bit register.
727
    AppendToBuffer(",0x");
728
    count += PrintImmediate(data + 1 + count, operand_size());
729
    return 1 + count;
730
  } else {
731
    UnimplementedInstruction();
732
    return 2;
733
  }
734
}
735

    
736

    
737
int DisassemblerX64::ShiftInstruction(byte* data) {
738
  byte op = *data & (~1);
739
  if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
740
    UnimplementedInstruction();
741
    return 1;
742
  }
743
  byte modrm = *(data + 1);
744
  int mod, regop, rm;
745
  get_modrm(modrm, &mod, &regop, &rm);
746
  regop &= 0x7;  // The REX.R bit does not affect the operation.
747
  int imm8 = -1;
748
  int num_bytes = 2;
749
  if (mod != 3) {
750
    UnimplementedInstruction();
751
    return num_bytes;
752
  }
753
  const char* mnem = NULL;
754
  switch (regop) {
755
    case 0:
756
      mnem = "rol";
757
      break;
758
    case 1:
759
      mnem = "ror";
760
      break;
761
    case 2:
762
      mnem = "rcl";
763
      break;
764
    case 3:
765
      mnem = "rcr";
766
      break;
767
    case 4:
768
      mnem = "shl";
769
      break;
770
    case 5:
771
      mnem = "shr";
772
      break;
773
    case 7:
774
      mnem = "sar";
775
      break;
776
    default:
777
      UnimplementedInstruction();
778
      return num_bytes;
779
  }
780
  ASSERT_NE(NULL, mnem);
781
  if (op == 0xD0) {
782
    imm8 = 1;
783
  } else if (op == 0xC0) {
784
    imm8 = *(data + 2);
785
    num_bytes = 3;
786
  }
787
  AppendToBuffer("%s%c %s,",
788
                 mnem,
789
                 operand_size_code(),
790
                 byte_size_operand_ ? NameOfByteCPURegister(rm)
791
                                    : NameOfCPURegister(rm));
792
  if (op == 0xD2) {
793
    AppendToBuffer("cl");
794
  } else {
795
    AppendToBuffer("%d", imm8);
796
  }
797
  return num_bytes;
798
}
799

    
800

    
801
// Returns number of bytes used, including *data.
802
int DisassemblerX64::JumpShort(byte* data) {
803
  ASSERT_EQ(0xEB, *data);
804
  byte b = *(data + 1);
805
  byte* dest = data + static_cast<int8_t>(b) + 2;
806
  AppendToBuffer("jmp %s", NameOfAddress(dest));
807
  return 2;
808
}
809

    
810

    
811
// Returns number of bytes used, including *data.
812
int DisassemblerX64::JumpConditional(byte* data) {
813
  ASSERT_EQ(0x0F, *data);
814
  byte cond = *(data + 1) & 0x0F;
815
  byte* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6;
816
  const char* mnem = conditional_code_suffix[cond];
817
  AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
818
  return 6;  // includes 0x0F
819
}
820

    
821

    
822
// Returns number of bytes used, including *data.
823
int DisassemblerX64::JumpConditionalShort(byte* data) {
824
  byte cond = *data & 0x0F;
825
  byte b = *(data + 1);
826
  byte* dest = data + static_cast<int8_t>(b) + 2;
827
  const char* mnem = conditional_code_suffix[cond];
828
  AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
829
  return 2;
830
}
831

    
832

    
833
// Returns number of bytes used, including *data.
834
int DisassemblerX64::SetCC(byte* data) {
835
  ASSERT_EQ(0x0F, *data);
836
  byte cond = *(data + 1) & 0x0F;
837
  const char* mnem = conditional_code_suffix[cond];
838
  AppendToBuffer("set%s%c ", mnem, operand_size_code());
839
  PrintRightByteOperand(data + 2);
840
  return 3;  // includes 0x0F
841
}
842

    
843

    
844
// Returns number of bytes used, including *data.
845
int DisassemblerX64::FPUInstruction(byte* data) {
846
  byte escape_opcode = *data;
847
  ASSERT_EQ(0xD8, escape_opcode & 0xF8);
848
  byte modrm_byte = *(data+1);
849

    
850
  if (modrm_byte >= 0xC0) {
851
    return RegisterFPUInstruction(escape_opcode, modrm_byte);
852
  } else {
853
    return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
854
  }
855
}
856

    
857
int DisassemblerX64::MemoryFPUInstruction(int escape_opcode,
858
                                           int modrm_byte,
859
                                           byte* modrm_start) {
860
  const char* mnem = "?";
861
  int regop = (modrm_byte >> 3) & 0x7;  // reg/op field of modrm byte.
862
  switch (escape_opcode) {
863
    case 0xD9: switch (regop) {
864
        case 0: mnem = "fld_s"; break;
865
        case 3: mnem = "fstp_s"; break;
866
        case 7: mnem = "fstcw"; break;
867
        default: UnimplementedInstruction();
868
      }
869
      break;
870

    
871
    case 0xDB: switch (regop) {
872
        case 0: mnem = "fild_s"; break;
873
        case 1: mnem = "fisttp_s"; break;
874
        case 2: mnem = "fist_s"; break;
875
        case 3: mnem = "fistp_s"; break;
876
        default: UnimplementedInstruction();
877
      }
878
      break;
879

    
880
    case 0xDD: switch (regop) {
881
        case 0: mnem = "fld_d"; break;
882
        case 3: mnem = "fstp_d"; break;
883
        default: UnimplementedInstruction();
884
      }
885
      break;
886

    
887
    case 0xDF: switch (regop) {
888
        case 5: mnem = "fild_d"; break;
889
        case 7: mnem = "fistp_d"; break;
890
        default: UnimplementedInstruction();
891
      }
892
      break;
893

    
894
    default: UnimplementedInstruction();
895
  }
896
  AppendToBuffer("%s ", mnem);
897
  int count = PrintRightOperand(modrm_start);
898
  return count + 1;
899
}
900

    
901
int DisassemblerX64::RegisterFPUInstruction(int escape_opcode,
902
                                             byte modrm_byte) {
903
  bool has_register = false;  // Is the FPU register encoded in modrm_byte?
904
  const char* mnem = "?";
905

    
906
  switch (escape_opcode) {
907
    case 0xD8:
908
      UnimplementedInstruction();
909
      break;
910

    
911
    case 0xD9:
912
      switch (modrm_byte & 0xF8) {
913
        case 0xC0:
914
          mnem = "fld";
915
          has_register = true;
916
          break;
917
        case 0xC8:
918
          mnem = "fxch";
919
          has_register = true;
920
          break;
921
        default:
922
          switch (modrm_byte) {
923
            case 0xE0: mnem = "fchs"; break;
924
            case 0xE1: mnem = "fabs"; break;
925
            case 0xE3: mnem = "fninit"; break;
926
            case 0xE4: mnem = "ftst"; break;
927
            case 0xE8: mnem = "fld1"; break;
928
            case 0xEB: mnem = "fldpi"; break;
929
            case 0xED: mnem = "fldln2"; break;
930
            case 0xEE: mnem = "fldz"; break;
931
            case 0xF0: mnem = "f2xm1"; break;
932
            case 0xF1: mnem = "fyl2x"; break;
933
            case 0xF2: mnem = "fptan"; break;
934
            case 0xF5: mnem = "fprem1"; break;
935
            case 0xF7: mnem = "fincstp"; break;
936
            case 0xF8: mnem = "fprem"; break;
937
            case 0xFD: mnem = "fscale"; break;
938
            case 0xFE: mnem = "fsin"; break;
939
            case 0xFF: mnem = "fcos"; break;
940
            default: UnimplementedInstruction();
941
          }
942
      }
943
      break;
944

    
945
    case 0xDA:
946
      if (modrm_byte == 0xE9) {
947
        mnem = "fucompp";
948
      } else {
949
        UnimplementedInstruction();
950
      }
951
      break;
952

    
953
    case 0xDB:
954
      if ((modrm_byte & 0xF8) == 0xE8) {
955
        mnem = "fucomi";
956
        has_register = true;
957
      } else if (modrm_byte  == 0xE2) {
958
        mnem = "fclex";
959
      } else {
960
        UnimplementedInstruction();
961
      }
962
      break;
963

    
964
    case 0xDC:
965
      has_register = true;
966
      switch (modrm_byte & 0xF8) {
967
        case 0xC0: mnem = "fadd"; break;
968
        case 0xE8: mnem = "fsub"; break;
969
        case 0xC8: mnem = "fmul"; break;
970
        case 0xF8: mnem = "fdiv"; break;
971
        default: UnimplementedInstruction();
972
      }
973
      break;
974

    
975
    case 0xDD:
976
      has_register = true;
977
      switch (modrm_byte & 0xF8) {
978
        case 0xC0: mnem = "ffree"; break;
979
        case 0xD8: mnem = "fstp"; break;
980
        default: UnimplementedInstruction();
981
      }
982
      break;
983

    
984
    case 0xDE:
985
      if (modrm_byte  == 0xD9) {
986
        mnem = "fcompp";
987
      } else {
988
        has_register = true;
989
        switch (modrm_byte & 0xF8) {
990
          case 0xC0: mnem = "faddp"; break;
991
          case 0xE8: mnem = "fsubp"; break;
992
          case 0xC8: mnem = "fmulp"; break;
993
          case 0xF8: mnem = "fdivp"; break;
994
          default: UnimplementedInstruction();
995
        }
996
      }
997
      break;
998

    
999
    case 0xDF:
1000
      if (modrm_byte == 0xE0) {
1001
        mnem = "fnstsw_ax";
1002
      } else if ((modrm_byte & 0xF8) == 0xE8) {
1003
        mnem = "fucomip";
1004
        has_register = true;
1005
      }
1006
      break;
1007

    
1008
    default: UnimplementedInstruction();
1009
  }
1010

    
1011
  if (has_register) {
1012
    AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1013
  } else {
1014
    AppendToBuffer("%s", mnem);
1015
  }
1016
  return 2;
1017
}
1018

    
1019

    
1020

    
1021
// Handle all two-byte opcodes, which start with 0x0F.
1022
// These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
1023
// We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
1024
int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
1025
  byte opcode = *(data + 1);
1026
  byte* current = data + 2;
1027
  // At return, "current" points to the start of the next instruction.
1028
  const char* mnemonic = TwoByteMnemonic(opcode);
1029
  if (operand_size_ == 0x66) {
1030
    // 0x66 0x0F prefix.
1031
    int mod, regop, rm;
1032
    if (opcode == 0x3A) {
1033
      byte third_byte = *current;
1034
      current = data + 3;
1035
      if (third_byte == 0x17) {
1036
        get_modrm(*current, &mod, &regop, &rm);
1037
        AppendToBuffer("extractps ");  // reg/m32, xmm, imm8
1038
        current += PrintRightOperand(current);
1039
        AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
1040
        current += 1;
1041
      } else if (third_byte == 0x0b) {
1042
        get_modrm(*current, &mod, &regop, &rm);
1043
         // roundsd xmm, xmm/m64, imm8
1044
        AppendToBuffer("roundsd %s,", NameOfXMMRegister(regop));
1045
        current += PrintRightXMMOperand(current);
1046
        AppendToBuffer(",%d", (*current) & 3);
1047
        current += 1;
1048
      } else {
1049
        UnimplementedInstruction();
1050
      }
1051
    } else {
1052
      get_modrm(*current, &mod, &regop, &rm);
1053
      if (opcode == 0x1f) {
1054
        current++;
1055
        if (rm == 4) {  // SIB byte present.
1056
          current++;
1057
        }
1058
        if (mod == 1) {  // Byte displacement.
1059
          current += 1;
1060
        } else if (mod == 2) {  // 32-bit displacement.
1061
          current += 4;
1062
        }  // else no immediate displacement.
1063
        AppendToBuffer("nop");
1064
      } else if (opcode == 0x28) {
1065
        AppendToBuffer("movapd %s,", NameOfXMMRegister(regop));
1066
        current += PrintRightXMMOperand(current);
1067
      } else if (opcode == 0x29) {
1068
        AppendToBuffer("movapd ");
1069
        current += PrintRightXMMOperand(current);
1070
        AppendToBuffer(",%s", NameOfXMMRegister(regop));
1071
      } else if (opcode == 0x6E) {
1072
        AppendToBuffer("mov%c %s,",
1073
                       rex_w() ? 'q' : 'd',
1074
                       NameOfXMMRegister(regop));
1075
        current += PrintRightOperand(current);
1076
      } else if (opcode == 0x6F) {
1077
        AppendToBuffer("movdqa %s,",
1078
                       NameOfXMMRegister(regop));
1079
        current += PrintRightXMMOperand(current);
1080
      } else if (opcode == 0x7E) {
1081
        AppendToBuffer("mov%c ",
1082
                       rex_w() ? 'q' : 'd');
1083
        current += PrintRightOperand(current);
1084
        AppendToBuffer(",%s", NameOfXMMRegister(regop));
1085
      } else if (opcode == 0x7F) {
1086
        AppendToBuffer("movdqa ");
1087
        current += PrintRightXMMOperand(current);
1088
        AppendToBuffer(",%s", NameOfXMMRegister(regop));
1089
      } else if (opcode == 0xD6) {
1090
        AppendToBuffer("movq ");
1091
        current += PrintRightXMMOperand(current);
1092
        AppendToBuffer(",%s", NameOfXMMRegister(regop));
1093
      } else if (opcode == 0x50) {
1094
        AppendToBuffer("movmskpd %s,", NameOfCPURegister(regop));
1095
        current += PrintRightXMMOperand(current);
1096
      } else {
1097
        const char* mnemonic = "?";
1098
        if (opcode == 0x54) {
1099
          mnemonic = "andpd";
1100
        } else  if (opcode == 0x56) {
1101
          mnemonic = "orpd";
1102
        } else  if (opcode == 0x57) {
1103
          mnemonic = "xorpd";
1104
        } else if (opcode == 0x2E) {
1105
          mnemonic = "ucomisd";
1106
        } else if (opcode == 0x2F) {
1107
          mnemonic = "comisd";
1108
        } else {
1109
          UnimplementedInstruction();
1110
        }
1111
        AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1112
        current += PrintRightXMMOperand(current);
1113
      }
1114
    }
1115
  } else if (group_1_prefix_ == 0xF2) {
1116
    // Beginning of instructions with prefix 0xF2.
1117

    
1118
    if (opcode == 0x11 || opcode == 0x10) {
1119
      // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
1120
      AppendToBuffer("movsd ");
1121
      int mod, regop, rm;
1122
      get_modrm(*current, &mod, &regop, &rm);
1123
      if (opcode == 0x11) {
1124
        current += PrintRightXMMOperand(current);
1125
        AppendToBuffer(",%s", NameOfXMMRegister(regop));
1126
      } else {
1127
        AppendToBuffer("%s,", NameOfXMMRegister(regop));
1128
        current += PrintRightXMMOperand(current);
1129
      }
1130
    } else if (opcode == 0x2A) {
1131
      // CVTSI2SD: integer to XMM double conversion.
1132
      int mod, regop, rm;
1133
      get_modrm(*current, &mod, &regop, &rm);
1134
      AppendToBuffer("%sd %s,", mnemonic, NameOfXMMRegister(regop));
1135
      current += PrintRightOperand(current);
1136
    } else if (opcode == 0x2C) {
1137
      // CVTTSD2SI:
1138
      // Convert with truncation scalar double-precision FP to integer.
1139
      int mod, regop, rm;
1140
      get_modrm(*current, &mod, &regop, &rm);
1141
      AppendToBuffer("cvttsd2si%c %s,",
1142
          operand_size_code(), NameOfCPURegister(regop));
1143
      current += PrintRightXMMOperand(current);
1144
    } else if (opcode == 0x2D) {
1145
      // CVTSD2SI: Convert scalar double-precision FP to integer.
1146
      int mod, regop, rm;
1147
      get_modrm(*current, &mod, &regop, &rm);
1148
      AppendToBuffer("cvtsd2si%c %s,",
1149
          operand_size_code(), NameOfCPURegister(regop));
1150
      current += PrintRightXMMOperand(current);
1151
    } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
1152
      // XMM arithmetic. Mnemonic was retrieved at the start of this function.
1153
      int mod, regop, rm;
1154
      get_modrm(*current, &mod, &regop, &rm);
1155
      AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1156
      current += PrintRightXMMOperand(current);
1157
    } else if (opcode == 0xC2) {
1158
      // Intel manual 2A, Table 3-18.
1159
      int mod, regop, rm;
1160
      get_modrm(*current, &mod, &regop, &rm);
1161
      const char* const pseudo_op[] = {
1162
        "cmpeqsd",
1163
        "cmpltsd",
1164
        "cmplesd",
1165
        "cmpunordsd",
1166
        "cmpneqsd",
1167
        "cmpnltsd",
1168
        "cmpnlesd",
1169
        "cmpordsd"
1170
      };
1171
      AppendToBuffer("%s %s,%s",
1172
                     pseudo_op[current[1]],
1173
                     NameOfXMMRegister(regop),
1174
                     NameOfXMMRegister(rm));
1175
      current += 2;
1176
    } else {
1177
      UnimplementedInstruction();
1178
    }
1179
  } else if (group_1_prefix_ == 0xF3) {
1180
    // Instructions with prefix 0xF3.
1181
    if (opcode == 0x11 || opcode == 0x10) {
1182
      // MOVSS: Move scalar double-precision fp to/from/between XMM registers.
1183
      AppendToBuffer("movss ");
1184
      int mod, regop, rm;
1185
      get_modrm(*current, &mod, &regop, &rm);
1186
      if (opcode == 0x11) {
1187
        current += PrintRightOperand(current);
1188
        AppendToBuffer(",%s", NameOfXMMRegister(regop));
1189
      } else {
1190
        AppendToBuffer("%s,", NameOfXMMRegister(regop));
1191
        current += PrintRightOperand(current);
1192
      }
1193
    } else if (opcode == 0x2A) {
1194
      // CVTSI2SS: integer to XMM single conversion.
1195
      int mod, regop, rm;
1196
      get_modrm(*current, &mod, &regop, &rm);
1197
      AppendToBuffer("%ss %s,", mnemonic, NameOfXMMRegister(regop));
1198
      current += PrintRightOperand(current);
1199
    } else if (opcode == 0x2C) {
1200
      // CVTTSS2SI:
1201
      // Convert with truncation scalar single-precision FP to dword integer.
1202
      int mod, regop, rm;
1203
      get_modrm(*current, &mod, &regop, &rm);
1204
      AppendToBuffer("cvttss2si%c %s,",
1205
          operand_size_code(), NameOfCPURegister(regop));
1206
      current += PrintRightXMMOperand(current);
1207
    } else if (opcode == 0x5A) {
1208
      // CVTSS2SD:
1209
      // Convert scalar single-precision FP to scalar double-precision FP.
1210
      int mod, regop, rm;
1211
      get_modrm(*current, &mod, &regop, &rm);
1212
      AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1213
      current += PrintRightXMMOperand(current);
1214
    } else if (opcode == 0x7E) {
1215
      int mod, regop, rm;
1216
      get_modrm(*current, &mod, &regop, &rm);
1217
      AppendToBuffer("movq %s,", NameOfXMMRegister(regop));
1218
      current += PrintRightXMMOperand(current);
1219
    } else {
1220
      UnimplementedInstruction();
1221
    }
1222
  } else if (opcode == 0x1F) {
1223
    // NOP
1224
    int mod, regop, rm;
1225
    get_modrm(*current, &mod, &regop, &rm);
1226
    current++;
1227
    if (rm == 4) {  // SIB byte present.
1228
      current++;
1229
    }
1230
    if (mod == 1) {  // Byte displacement.
1231
      current += 1;
1232
    } else if (mod == 2) {  // 32-bit displacement.
1233
      current += 4;
1234
    }  // else no immediate displacement.
1235
    AppendToBuffer("nop");
1236

    
1237
  } else if (opcode == 0x28) {
1238
    // movaps xmm, xmm/m128
1239
    int mod, regop, rm;
1240
    get_modrm(*current, &mod, &regop, &rm);
1241
    AppendToBuffer("movaps %s,", NameOfXMMRegister(regop));
1242
    current += PrintRightXMMOperand(current);
1243

    
1244
  } else if (opcode == 0x29) {
1245
    // movaps xmm/m128, xmm
1246
    int mod, regop, rm;
1247
    get_modrm(*current, &mod, &regop, &rm);
1248
    AppendToBuffer("movaps ");
1249
    current += PrintRightXMMOperand(current);
1250
    AppendToBuffer(",%s", NameOfXMMRegister(regop));
1251

    
1252
  } else if (opcode == 0xA2) {
1253
    // CPUID
1254
    AppendToBuffer("%s", mnemonic);
1255

    
1256
  } else if ((opcode & 0xF0) == 0x40) {
1257
    // CMOVcc: conditional move.
1258
    int condition = opcode & 0x0F;
1259
    const InstructionDesc& idesc = cmov_instructions[condition];
1260
    byte_size_operand_ = idesc.byte_size_operation;
1261
    current += PrintOperands(idesc.mnem, idesc.op_order_, current);
1262

    
1263
  } else if (opcode == 0x54) {
1264
    // xorps xmm, xmm/m128
1265
    int mod, regop, rm;
1266
    get_modrm(*current, &mod, &regop, &rm);
1267
    AppendToBuffer("andps %s,", NameOfXMMRegister(regop));
1268
    current += PrintRightXMMOperand(current);
1269

    
1270
  } else if (opcode == 0x57) {
1271
    // xorps xmm, xmm/m128
1272
    int mod, regop, rm;
1273
    get_modrm(*current, &mod, &regop, &rm);
1274
    AppendToBuffer("xorps %s,", NameOfXMMRegister(regop));
1275
    current += PrintRightXMMOperand(current);
1276

    
1277
  } else if (opcode == 0x50) {
1278
    // movmskps reg, xmm
1279
    int mod, regop, rm;
1280
    get_modrm(*current, &mod, &regop, &rm);
1281
    AppendToBuffer("movmskps %s,", NameOfCPURegister(regop));
1282
    current += PrintRightXMMOperand(current);
1283

    
1284
  } else if ((opcode & 0xF0) == 0x80) {
1285
    // Jcc: Conditional jump (branch).
1286
    current = data + JumpConditional(data);
1287

    
1288
  } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
1289
             opcode == 0xB7 || opcode == 0xAF) {
1290
    // Size-extending moves, IMUL.
1291
    current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1292

    
1293
  } else if ((opcode & 0xF0) == 0x90) {
1294
    // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
1295
    current = data + SetCC(data);
1296

    
1297
  } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
1298
    // SHLD, SHRD (double-precision shift), BTS (bit set).
1299
    AppendToBuffer("%s ", mnemonic);
1300
    int mod, regop, rm;
1301
    get_modrm(*current, &mod, &regop, &rm);
1302
    current += PrintRightOperand(current);
1303
    if (opcode == 0xAB) {
1304
      AppendToBuffer(",%s", NameOfCPURegister(regop));
1305
    } else {
1306
      AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1307
    }
1308
  } else {
1309
    UnimplementedInstruction();
1310
  }
1311
  return static_cast<int>(current - data);
1312
}
1313

    
1314

    
1315
// Mnemonics for two-byte opcode instructions starting with 0x0F.
1316
// The argument is the second byte of the two-byte opcode.
1317
// Returns NULL if the instruction is not handled here.
1318
const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
1319
  switch (opcode) {
1320
    case 0x1F:
1321
      return "nop";
1322
    case 0x2A:  // F2/F3 prefix.
1323
      return "cvtsi2s";
1324
    case 0x51:  // F2 prefix.
1325
      return "sqrtsd";
1326
    case 0x58:  // F2 prefix.
1327
      return "addsd";
1328
    case 0x59:  // F2 prefix.
1329
      return "mulsd";
1330
    case 0x5A:  // F2 prefix.
1331
      return "cvtsd2ss";
1332
    case 0x5C:  // F2 prefix.
1333
      return "subsd";
1334
    case 0x5E:  // F2 prefix.
1335
      return "divsd";
1336
    case 0xA2:
1337
      return "cpuid";
1338
    case 0xA5:
1339
      return "shld";
1340
    case 0xAB:
1341
      return "bts";
1342
    case 0xAD:
1343
      return "shrd";
1344
    case 0xAF:
1345
      return "imul";
1346
    case 0xB6:
1347
      return "movzxb";
1348
    case 0xB7:
1349
      return "movzxw";
1350
    case 0xBE:
1351
      return "movsxb";
1352
    case 0xBF:
1353
      return "movsxw";
1354
    default:
1355
      return NULL;
1356
  }
1357
}
1358

    
1359

    
1360
// Disassembles the instruction at instr, and writes it into out_buffer.
1361
int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
1362
                                       byte* instr) {
1363
  tmp_buffer_pos_ = 0;  // starting to write as position 0
1364
  byte* data = instr;
1365
  bool processed = true;  // Will be set to false if the current instruction
1366
                          // is not in 'instructions' table.
1367
  byte current;
1368

    
1369
  // Scan for prefixes.
1370
  while (true) {
1371
    current = *data;
1372
    if (current == OPERAND_SIZE_OVERRIDE_PREFIX) {  // Group 3 prefix.
1373
      operand_size_ = current;
1374
    } else if ((current & 0xF0) == 0x40) {  // REX prefix.
1375
      setRex(current);
1376
      if (rex_w()) AppendToBuffer("REX.W ");
1377
    } else if ((current & 0xFE) == 0xF2) {  // Group 1 prefix (0xF2 or 0xF3).
1378
      group_1_prefix_ = current;
1379
    } else {  // Not a prefix - an opcode.
1380
      break;
1381
    }
1382
    data++;
1383
  }
1384

    
1385
  const InstructionDesc& idesc = instruction_table_->Get(current);
1386
  byte_size_operand_ = idesc.byte_size_operation;
1387
  switch (idesc.type) {
1388
    case ZERO_OPERANDS_INSTR:
1389
      if (current >= 0xA4 && current <= 0xA7) {
1390
        // String move or compare operations.
1391
        if (group_1_prefix_ == REP_PREFIX) {
1392
          // REP.
1393
          AppendToBuffer("rep ");
1394
        }
1395
        if (rex_w()) AppendToBuffer("REX.W ");
1396
        AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
1397
      } else {
1398
        AppendToBuffer("%s", idesc.mnem, operand_size_code());
1399
      }
1400
      data++;
1401
      break;
1402

    
1403
    case TWO_OPERANDS_INSTR:
1404
      data++;
1405
      data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1406
      break;
1407

    
1408
    case JUMP_CONDITIONAL_SHORT_INSTR:
1409
      data += JumpConditionalShort(data);
1410
      break;
1411

    
1412
    case REGISTER_INSTR:
1413
      AppendToBuffer("%s%c %s",
1414
                     idesc.mnem,
1415
                     operand_size_code(),
1416
                     NameOfCPURegister(base_reg(current & 0x07)));
1417
      data++;
1418
      break;
1419
    case PUSHPOP_INSTR:
1420
      AppendToBuffer("%s %s",
1421
                     idesc.mnem,
1422
                     NameOfCPURegister(base_reg(current & 0x07)));
1423
      data++;
1424
      break;
1425
    case MOVE_REG_INSTR: {
1426
      byte* addr = NULL;
1427
      switch (operand_size()) {
1428
        case OPERAND_WORD_SIZE:
1429
          addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
1430
          data += 3;
1431
          break;
1432
        case OPERAND_DOUBLEWORD_SIZE:
1433
          addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1434
          data += 5;
1435
          break;
1436
        case OPERAND_QUADWORD_SIZE:
1437
          addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
1438
          data += 9;
1439
          break;
1440
        default:
1441
          UNREACHABLE();
1442
      }
1443
      AppendToBuffer("mov%c %s,%s",
1444
                     operand_size_code(),
1445
                     NameOfCPURegister(base_reg(current & 0x07)),
1446
                     NameOfAddress(addr));
1447
      break;
1448
    }
1449

    
1450
    case CALL_JUMP_INSTR: {
1451
      byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
1452
      AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1453
      data += 5;
1454
      break;
1455
    }
1456

    
1457
    case SHORT_IMMEDIATE_INSTR: {
1458
      byte* addr =
1459
          reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1460
      AppendToBuffer("%s rax,%s", idesc.mnem, NameOfAddress(addr));
1461
      data += 5;
1462
      break;
1463
    }
1464

    
1465
    case NO_INSTR:
1466
      processed = false;
1467
      break;
1468

    
1469
    default:
1470
      UNIMPLEMENTED();  // This type is not implemented.
1471
  }
1472

    
1473
  // The first byte didn't match any of the simple opcodes, so we
1474
  // need to do special processing on it.
1475
  if (!processed) {
1476
    switch (*data) {
1477
      case 0xC2:
1478
        AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
1479
        data += 3;
1480
        break;
1481

    
1482
      case 0x69:  // fall through
1483
      case 0x6B: {
1484
        int mod, regop, rm;
1485
        get_modrm(*(data + 1), &mod, &regop, &rm);
1486
        int32_t imm = *data == 0x6B ? *(data + 2)
1487
            : *reinterpret_cast<int32_t*>(data + 2);
1488
        AppendToBuffer("imul%c %s,%s,0x%x",
1489
                       operand_size_code(),
1490
                       NameOfCPURegister(regop),
1491
                       NameOfCPURegister(rm), imm);
1492
        data += 2 + (*data == 0x6B ? 1 : 4);
1493
        break;
1494
      }
1495

    
1496
      case 0x81:  // fall through
1497
      case 0x83:  // 0x81 with sign extension bit set
1498
        data += PrintImmediateOp(data);
1499
        break;
1500

    
1501
      case 0x0F:
1502
        data += TwoByteOpcodeInstruction(data);
1503
        break;
1504

    
1505
      case 0x8F: {
1506
        data++;
1507
        int mod, regop, rm;
1508
        get_modrm(*data, &mod, &regop, &rm);
1509
        if (regop == 0) {
1510
          AppendToBuffer("pop ");
1511
          data += PrintRightOperand(data);
1512
        }
1513
      }
1514
        break;
1515

    
1516
      case 0xFF: {
1517
        data++;
1518
        int mod, regop, rm;
1519
        get_modrm(*data, &mod, &regop, &rm);
1520
        const char* mnem = NULL;
1521
        switch (regop) {
1522
          case 0:
1523
            mnem = "inc";
1524
            break;
1525
          case 1:
1526
            mnem = "dec";
1527
            break;
1528
          case 2:
1529
            mnem = "call";
1530
            break;
1531
          case 4:
1532
            mnem = "jmp";
1533
            break;
1534
          case 6:
1535
            mnem = "push";
1536
            break;
1537
          default:
1538
            mnem = "???";
1539
        }
1540
        AppendToBuffer(((regop <= 1) ? "%s%c " : "%s "),
1541
                       mnem,
1542
                       operand_size_code());
1543
        data += PrintRightOperand(data);
1544
      }
1545
        break;
1546

    
1547
      case 0xC7:  // imm32, fall through
1548
      case 0xC6:  // imm8
1549
      {
1550
        bool is_byte = *data == 0xC6;
1551
        data++;
1552
        if (is_byte) {
1553
          AppendToBuffer("movb ");
1554
          data += PrintRightByteOperand(data);
1555
          int32_t imm = *data;
1556
          AppendToBuffer(",0x%x", imm);
1557
          data++;
1558
        } else {
1559
          AppendToBuffer("mov%c ", operand_size_code());
1560
          data += PrintRightOperand(data);
1561
          int32_t imm = *reinterpret_cast<int32_t*>(data);
1562
          AppendToBuffer(",0x%x", imm);
1563
          data += 4;
1564
        }
1565
      }
1566
        break;
1567

    
1568
      case 0x80: {
1569
        data++;
1570
        AppendToBuffer("cmpb ");
1571
        data += PrintRightByteOperand(data);
1572
        int32_t imm = *data;
1573
        AppendToBuffer(",0x%x", imm);
1574
        data++;
1575
      }
1576
        break;
1577

    
1578
      case 0x88:  // 8bit, fall through
1579
      case 0x89:  // 32bit
1580
      {
1581
        bool is_byte = *data == 0x88;
1582
        int mod, regop, rm;
1583
        data++;
1584
        get_modrm(*data, &mod, &regop, &rm);
1585
        if (is_byte) {
1586
          AppendToBuffer("movb ");
1587
          data += PrintRightByteOperand(data);
1588
          AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1589
        } else {
1590
          AppendToBuffer("mov%c ", operand_size_code());
1591
          data += PrintRightOperand(data);
1592
          AppendToBuffer(",%s", NameOfCPURegister(regop));
1593
        }
1594
      }
1595
        break;
1596

    
1597
      case 0x90:
1598
      case 0x91:
1599
      case 0x92:
1600
      case 0x93:
1601
      case 0x94:
1602
      case 0x95:
1603
      case 0x96:
1604
      case 0x97: {
1605
        int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
1606
        if (reg == 0) {
1607
          AppendToBuffer("nop");  // Common name for xchg rax,rax.
1608
        } else {
1609
          AppendToBuffer("xchg%c rax,%s",
1610
                         operand_size_code(),
1611
                         NameOfCPURegister(reg));
1612
        }
1613
        data++;
1614
      }
1615
        break;
1616
      case 0xB0:
1617
      case 0xB1:
1618
      case 0xB2:
1619
      case 0xB3:
1620
      case 0xB4:
1621
      case 0xB5:
1622
      case 0xB6:
1623
      case 0xB7:
1624
      case 0xB8:
1625
      case 0xB9:
1626
      case 0xBA:
1627
      case 0xBB:
1628
      case 0xBC:
1629
      case 0xBD:
1630
      case 0xBE:
1631
      case 0xBF: {
1632
        // mov reg8,imm8 or mov reg32,imm32
1633
        byte opcode = *data;
1634
        data++;
1635
        bool is_32bit = (opcode >= 0xB8);
1636
        int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
1637
        if (is_32bit) {
1638
          AppendToBuffer("mov%c %s,",
1639
                         operand_size_code(),
1640
                         NameOfCPURegister(reg));
1641
          data += PrintImmediate(data, OPERAND_DOUBLEWORD_SIZE);
1642
        } else {
1643
          AppendToBuffer("movb %s,",
1644
                         NameOfByteCPURegister(reg));
1645
          data += PrintImmediate(data, OPERAND_BYTE_SIZE);
1646
        }
1647
        break;
1648
      }
1649
      case 0xFE: {
1650
        data++;
1651
        int mod, regop, rm;
1652
        get_modrm(*data, &mod, &regop, &rm);
1653
        if (regop == 1) {
1654
          AppendToBuffer("decb ");
1655
          data += PrintRightByteOperand(data);
1656
        } else {
1657
          UnimplementedInstruction();
1658
        }
1659
        break;
1660
      }
1661
      case 0x68:
1662
        AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
1663
        data += 5;
1664
        break;
1665

    
1666
      case 0x6A:
1667
        AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1668
        data += 2;
1669
        break;
1670

    
1671
      case 0xA1:  // Fall through.
1672
      case 0xA3:
1673
        switch (operand_size()) {
1674
          case OPERAND_DOUBLEWORD_SIZE: {
1675
            const char* memory_location = NameOfAddress(
1676
                reinterpret_cast<byte*>(
1677
                    *reinterpret_cast<int32_t*>(data + 1)));
1678
            if (*data == 0xA1) {  // Opcode 0xA1
1679
              AppendToBuffer("movzxlq rax,(%s)", memory_location);
1680
            } else {  // Opcode 0xA3
1681
              AppendToBuffer("movzxlq (%s),rax", memory_location);
1682
            }
1683
            data += 5;
1684
            break;
1685
          }
1686
          case OPERAND_QUADWORD_SIZE: {
1687
            // New x64 instruction mov rax,(imm_64).
1688
            const char* memory_location = NameOfAddress(
1689
                *reinterpret_cast<byte**>(data + 1));
1690
            if (*data == 0xA1) {  // Opcode 0xA1
1691
              AppendToBuffer("movq rax,(%s)", memory_location);
1692
            } else {  // Opcode 0xA3
1693
              AppendToBuffer("movq (%s),rax", memory_location);
1694
            }
1695
            data += 9;
1696
            break;
1697
          }
1698
          default:
1699
            UnimplementedInstruction();
1700
            data += 2;
1701
        }
1702
        break;
1703

    
1704
      case 0xA8:
1705
        AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
1706
        data += 2;
1707
        break;
1708

    
1709
      case 0xA9: {
1710
        int64_t value = 0;
1711
        switch (operand_size()) {
1712
          case OPERAND_WORD_SIZE:
1713
            value = *reinterpret_cast<uint16_t*>(data + 1);
1714
            data += 3;
1715
            break;
1716
          case OPERAND_DOUBLEWORD_SIZE:
1717
            value = *reinterpret_cast<uint32_t*>(data + 1);
1718
            data += 5;
1719
            break;
1720
          case OPERAND_QUADWORD_SIZE:
1721
            value = *reinterpret_cast<int32_t*>(data + 1);
1722
            data += 5;
1723
            break;
1724
          default:
1725
            UNREACHABLE();
1726
        }
1727
        AppendToBuffer("test%c rax,0x%" V8_PTR_PREFIX "x",
1728
                       operand_size_code(),
1729
                       value);
1730
        break;
1731
      }
1732
      case 0xD1:  // fall through
1733
      case 0xD3:  // fall through
1734
      case 0xC1:
1735
        data += ShiftInstruction(data);
1736
        break;
1737
      case 0xD0:  // fall through
1738
      case 0xD2:  // fall through
1739
      case 0xC0:
1740
        byte_size_operand_ = true;
1741
        data += ShiftInstruction(data);
1742
        break;
1743

    
1744
      case 0xD9:  // fall through
1745
      case 0xDA:  // fall through
1746
      case 0xDB:  // fall through
1747
      case 0xDC:  // fall through
1748
      case 0xDD:  // fall through
1749
      case 0xDE:  // fall through
1750
      case 0xDF:
1751
        data += FPUInstruction(data);
1752
        break;
1753

    
1754
      case 0xEB:
1755
        data += JumpShort(data);
1756
        break;
1757

    
1758
      case 0xF6:
1759
        byte_size_operand_ = true;  // fall through
1760
      case 0xF7:
1761
        data += F6F7Instruction(data);
1762
        break;
1763

    
1764
      case 0x3C:
1765
        AppendToBuffer("cmp al,0x%x", *reinterpret_cast<int8_t*>(data + 1));
1766
        data +=2;
1767
        break;
1768

    
1769
      default:
1770
        UnimplementedInstruction();
1771
        data += 1;
1772
    }
1773
  }  // !processed
1774

    
1775
  if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1776
    tmp_buffer_[tmp_buffer_pos_] = '\0';
1777
  }
1778

    
1779
  int instr_len = static_cast<int>(data - instr);
1780
  ASSERT(instr_len > 0);  // Ensure progress.
1781

    
1782
  int outp = 0;
1783
  // Instruction bytes.
1784
  for (byte* bp = instr; bp < data; bp++) {
1785
    outp += v8::internal::OS::SNPrintF(out_buffer + outp, "%02x", *bp);
1786
  }
1787
  for (int i = 6 - instr_len; i >= 0; i--) {
1788
    outp += v8::internal::OS::SNPrintF(out_buffer + outp, "  ");
1789
  }
1790

    
1791
  outp += v8::internal::OS::SNPrintF(out_buffer + outp, " %s",
1792
                                     tmp_buffer_.start());
1793
  return instr_len;
1794
}
1795

    
1796

    
1797
//------------------------------------------------------------------------------
1798

    
1799

    
1800
static const char* cpu_regs[16] = {
1801
  "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
1802
  "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
1803
};
1804

    
1805

    
1806
static const char* byte_cpu_regs[16] = {
1807
  "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
1808
  "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
1809
};
1810

    
1811

    
1812
static const char* xmm_regs[16] = {
1813
  "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
1814
  "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
1815
};
1816

    
1817

    
1818
const char* NameConverter::NameOfAddress(byte* addr) const {
1819
  v8::internal::OS::SNPrintF(tmp_buffer_, "%p", addr);
1820
  return tmp_buffer_.start();
1821
}
1822

    
1823

    
1824
const char* NameConverter::NameOfConstant(byte* addr) const {
1825
  return NameOfAddress(addr);
1826
}
1827

    
1828

    
1829
const char* NameConverter::NameOfCPURegister(int reg) const {
1830
  if (0 <= reg && reg < 16)
1831
    return cpu_regs[reg];
1832
  return "noreg";
1833
}
1834

    
1835

    
1836
const char* NameConverter::NameOfByteCPURegister(int reg) const {
1837
  if (0 <= reg && reg < 16)
1838
    return byte_cpu_regs[reg];
1839
  return "noreg";
1840
}
1841

    
1842

    
1843
const char* NameConverter::NameOfXMMRegister(int reg) const {
1844
  if (0 <= reg && reg < 16)
1845
    return xmm_regs[reg];
1846
  return "noxmmreg";
1847
}
1848

    
1849

    
1850
const char* NameConverter::NameInCode(byte* addr) const {
1851
  // X64 does not embed debug strings at the moment.
1852
  UNREACHABLE();
1853
  return "";
1854
}
1855

    
1856

    
1857
//------------------------------------------------------------------------------
1858

    
1859
Disassembler::Disassembler(const NameConverter& converter)
1860
    : converter_(converter) { }
1861

    
1862
Disassembler::~Disassembler() { }
1863

    
1864

    
1865
int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1866
                                    byte* instruction) {
1867
  DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE);
1868
  return d.InstructionDecode(buffer, instruction);
1869
}
1870

    
1871

    
1872
// The X64 assembler does not use constant pools.
1873
int Disassembler::ConstantPoolSizeAt(byte* instruction) {
1874
  return -1;
1875
}
1876

    
1877

    
1878
void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1879
  NameConverter converter;
1880
  Disassembler d(converter);
1881
  for (byte* pc = begin; pc < end;) {
1882
    v8::internal::EmbeddedVector<char, 128> buffer;
1883
    buffer[0] = '\0';
1884
    byte* prev_pc = pc;
1885
    pc += d.InstructionDecode(buffer, pc);
1886
    fprintf(f, "%p", prev_pc);
1887
    fprintf(f, "    ");
1888

    
1889
    for (byte* bp = prev_pc; bp < pc; bp++) {
1890
      fprintf(f, "%02x", *bp);
1891
    }
1892
    for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) {
1893
      fprintf(f, "  ");
1894
    }
1895
    fprintf(f, "  %s\n", buffer.start());
1896
  }
1897
}
1898

    
1899
}  // namespace disasm
1900

    
1901
#endif  // V8_TARGET_ARCH_X64