1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include <cassert>
6 #include <cinttypes>
7 #include <cstdarg>
8 #include <cstdio>
9 
10 #if V8_TARGET_ARCH_X64
11 
12 #include "src/base/compiler-specific.h"
13 #include "src/base/lazy-instance.h"
14 #include "src/base/memory.h"
15 #include "src/base/v8-fallthrough.h"
16 #include "src/codegen/x64/register-x64.h"
17 #include "src/codegen/x64/sse-instr.h"
18 #include "src/diagnostics/disasm.h"
19 #include "src/utils/utils.h"
20 
21 namespace disasm {
22 
23 enum OperandType {
24   UNSET_OP_ORDER = 0,
25   // Operand size decides between 16, 32 and 64 bit operands.
26   REG_OPER_OP_ORDER = 1,  // Register destination, operand source.
27   OPER_REG_OP_ORDER = 2,  // Operand destination, register source.
28   // Fixed 8-bit operands.
29   BYTE_SIZE_OPERAND_FLAG = 4,
30   BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG,
31   BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
32 };
33 
34 //------------------------------------------------------------------
35 // Tables
36 //------------------------------------------------------------------
37 struct ByteMnemonic {
38   int b;  // -1 terminates, otherwise must be in range (0..255)
39   OperandType op_order_;
40   const char* mnem;
41 };
42 
43 static const ByteMnemonic two_operands_instr[] = {
44     {0x00, BYTE_OPER_REG_OP_ORDER, "add"},
45     {0x01, OPER_REG_OP_ORDER, "add"},
46     {0x02, BYTE_REG_OPER_OP_ORDER, "add"},
47     {0x03, REG_OPER_OP_ORDER, "add"},
48     {0x08, BYTE_OPER_REG_OP_ORDER, "or"},
49     {0x09, OPER_REG_OP_ORDER, "or"},
50     {0x0A, BYTE_REG_OPER_OP_ORDER, "or"},
51     {0x0B, REG_OPER_OP_ORDER, "or"},
52     {0x10, BYTE_OPER_REG_OP_ORDER, "adc"},
53     {0x11, OPER_REG_OP_ORDER, "adc"},
54     {0x12, BYTE_REG_OPER_OP_ORDER, "adc"},
55     {0x13, REG_OPER_OP_ORDER, "adc"},
56     {0x18, BYTE_OPER_REG_OP_ORDER, "sbb"},
57     {0x19, OPER_REG_OP_ORDER, "sbb"},
58     {0x1A, BYTE_REG_OPER_OP_ORDER, "sbb"},
59     {0x1B, REG_OPER_OP_ORDER, "sbb"},
60     {0x20, BYTE_OPER_REG_OP_ORDER, "and"},
61     {0x21, OPER_REG_OP_ORDER, "and"},
62     {0x22, BYTE_REG_OPER_OP_ORDER, "and"},
63     {0x23, REG_OPER_OP_ORDER, "and"},
64     {0x28, BYTE_OPER_REG_OP_ORDER, "sub"},
65     {0x29, OPER_REG_OP_ORDER, "sub"},
66     {0x2A, BYTE_REG_OPER_OP_ORDER, "sub"},
67     {0x2B, REG_OPER_OP_ORDER, "sub"},
68     {0x30, BYTE_OPER_REG_OP_ORDER, "xor"},
69     {0x31, OPER_REG_OP_ORDER, "xor"},
70     {0x32, BYTE_REG_OPER_OP_ORDER, "xor"},
71     {0x33, REG_OPER_OP_ORDER, "xor"},
72     {0x38, BYTE_OPER_REG_OP_ORDER, "cmp"},
73     {0x39, OPER_REG_OP_ORDER, "cmp"},
74     {0x3A, BYTE_REG_OPER_OP_ORDER, "cmp"},
75     {0x3B, REG_OPER_OP_ORDER, "cmp"},
76     {0x63, REG_OPER_OP_ORDER, "movsxl"},
77     {0x84, BYTE_REG_OPER_OP_ORDER, "test"},
78     {0x85, REG_OPER_OP_ORDER, "test"},
79     {0x86, BYTE_REG_OPER_OP_ORDER, "xchg"},
80     {0x87, REG_OPER_OP_ORDER, "xchg"},
81     {0x88, BYTE_OPER_REG_OP_ORDER, "mov"},
82     {0x89, OPER_REG_OP_ORDER, "mov"},
83     {0x8A, BYTE_REG_OPER_OP_ORDER, "mov"},
84     {0x8B, REG_OPER_OP_ORDER, "mov"},
85     {0x8D, REG_OPER_OP_ORDER, "lea"},
86     {-1, UNSET_OP_ORDER, ""}};
87 
88 static const ByteMnemonic zero_operands_instr[] = {
89     {0xC3, UNSET_OP_ORDER, "ret"},   {0xC9, UNSET_OP_ORDER, "leave"},
90     {0xF4, UNSET_OP_ORDER, "hlt"},   {0xFC, UNSET_OP_ORDER, "cld"},
91     {0xCC, UNSET_OP_ORDER, "int3"},  {0x60, UNSET_OP_ORDER, "pushad"},
92     {0x61, UNSET_OP_ORDER, "popad"}, {0x9C, UNSET_OP_ORDER, "pushfd"},
93     {0x9D, UNSET_OP_ORDER, "popfd"}, {0x9E, UNSET_OP_ORDER, "sahf"},
94     {0x99, UNSET_OP_ORDER, "cdq"},   {0x9B, UNSET_OP_ORDER, "fwait"},
95     {0xAB, UNSET_OP_ORDER, "stos"},  {0xA4, UNSET_OP_ORDER, "movs"},
96     {0xA5, UNSET_OP_ORDER, "movs"},  {0xA6, UNSET_OP_ORDER, "cmps"},
97     {0xA7, UNSET_OP_ORDER, "cmps"},  {-1, UNSET_OP_ORDER, ""}};
98 
99 static const ByteMnemonic call_jump_instr[] = {{0xE8, UNSET_OP_ORDER, "call"},
100                                                {0xE9, UNSET_OP_ORDER, "jmp"},
101                                                {-1, UNSET_OP_ORDER, ""}};
102 
103 static const ByteMnemonic short_immediate_instr[] = {
104     {0x05, UNSET_OP_ORDER, "add"}, {0x0D, UNSET_OP_ORDER, "or"},
105     {0x15, UNSET_OP_ORDER, "adc"}, {0x1D, UNSET_OP_ORDER, "sbb"},
106     {0x25, UNSET_OP_ORDER, "and"}, {0x2D, UNSET_OP_ORDER, "sub"},
107     {0x35, UNSET_OP_ORDER, "xor"}, {0x3D, UNSET_OP_ORDER, "cmp"},
108     {-1, UNSET_OP_ORDER, ""}};
109 
110 static const char* const conditional_code_suffix[] = {
111     "o", "no", "c",  "nc", "z", "nz", "na", "a",
112     "s", "ns", "pe", "po", "l", "ge", "le", "g"};
113 
114 enum InstructionType {
115   NO_INSTR,
116   ZERO_OPERANDS_INSTR,
117   TWO_OPERANDS_INSTR,
118   JUMP_CONDITIONAL_SHORT_INSTR,
119   REGISTER_INSTR,
120   PUSHPOP_INSTR,  // Has implicit 64-bit operand size.
121   MOVE_REG_INSTR,
122   CALL_JUMP_INSTR,
123   SHORT_IMMEDIATE_INSTR
124 };
125 
126 enum Prefixes {
127   ESCAPE_PREFIX = 0x0F,
128   OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
129   ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
130   VEX3_PREFIX = 0xC4,
131   VEX2_PREFIX = 0xC5,
132   LOCK_PREFIX = 0xF0,
133   REPNE_PREFIX = 0xF2,
134   REP_PREFIX = 0xF3,
135   REPEQ_PREFIX = REP_PREFIX
136 };
137 
138 struct InstructionDesc {
139   const char* mnem;
140   InstructionType type;
141   OperandType op_order_;
142   bool byte_size_operation;  // Fixed 8-bit operation.
143 };
144 
145 class InstructionTable {
146  public:
147   InstructionTable();
Get(byte x) const148   const InstructionDesc& Get(byte x) const { return instructions_[x]; }
149 
150  private:
151   InstructionDesc instructions_[256];
152   void Clear();
153   void Init();
154   void CopyTable(const ByteMnemonic bm[], InstructionType type);
155   void SetTableRange(InstructionType type, byte start, byte end, bool byte_size,
156                      const char* mnem);
157   void AddJumpConditionalShort();
158 };
159 
InstructionTable()160 InstructionTable::InstructionTable() {
161   Clear();
162   Init();
163 }
164 
Clear()165 void InstructionTable::Clear() {
166   for (int i = 0; i < 256; i++) {
167     instructions_[i].mnem = "(bad)";
168     instructions_[i].type = NO_INSTR;
169     instructions_[i].op_order_ = UNSET_OP_ORDER;
170     instructions_[i].byte_size_operation = false;
171   }
172 }
173 
Init()174 void InstructionTable::Init() {
175   CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
176   CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
177   CopyTable(call_jump_instr, CALL_JUMP_INSTR);
178   CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
179   AddJumpConditionalShort();
180   SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push");
181   SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop");
182   SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov");
183 }
184 
CopyTable(const ByteMnemonic bm[],InstructionType type)185 void InstructionTable::CopyTable(const ByteMnemonic bm[],
186                                  InstructionType type) {
187   for (int i = 0; bm[i].b >= 0; i++) {
188     InstructionDesc* id = &instructions_[bm[i].b];
189     id->mnem = bm[i].mnem;
190     OperandType op_order = bm[i].op_order_;
191     id->op_order_ =
192         static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
193     DCHECK_EQ(NO_INSTR, id->type);  // Information not already entered
194     id->type = type;
195     id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
196   }
197 }
198 
SetTableRange(InstructionType type,byte start,byte end,bool byte_size,const char * mnem)199 void InstructionTable::SetTableRange(InstructionType type, byte start, byte end,
200                                      bool byte_size, const char* mnem) {
201   for (byte b = start; b <= end; b++) {
202     InstructionDesc* id = &instructions_[b];
203     DCHECK_EQ(NO_INSTR, id->type);  // Information not already entered
204     id->mnem = mnem;
205     id->type = type;
206     id->byte_size_operation = byte_size;
207   }
208 }
209 
AddJumpConditionalShort()210 void InstructionTable::AddJumpConditionalShort() {
211   for (byte b = 0x70; b <= 0x7F; b++) {
212     InstructionDesc* id = &instructions_[b];
213     DCHECK_EQ(NO_INSTR, id->type);  // Information not already entered
214     id->mnem = nullptr;             // Computed depending on condition code.
215     id->type = JUMP_CONDITIONAL_SHORT_INSTR;
216   }
217 }
218 
219 namespace {
220 DEFINE_LAZY_LEAKY_OBJECT_GETTER(InstructionTable, GetInstructionTable)
221 }
222 
223 static const InstructionDesc cmov_instructions[16] = {
224     {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
225     {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
226     {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
227     {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
228     {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
229     {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
230     {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
231     {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
232     {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
233     {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
234     {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
235     {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
236     {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
237     {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
238     {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
239     {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}};
240 
241 namespace {
Imm8(const uint8_t * data)242 int8_t Imm8(const uint8_t* data) {
243   return *reinterpret_cast<const int8_t*>(data);
244 }
Imm8_U(const uint8_t * data)245 uint8_t Imm8_U(const uint8_t* data) {
246   return *reinterpret_cast<const uint8_t*>(data);
247 }
Imm16(const uint8_t * data)248 int16_t Imm16(const uint8_t* data) {
249   return v8::base::ReadUnalignedValue<int16_t>(
250       reinterpret_cast<v8::internal::Address>(data));
251 }
Imm16_U(const uint8_t * data)252 uint16_t Imm16_U(const uint8_t* data) {
253   return v8::base::ReadUnalignedValue<uint16_t>(
254       reinterpret_cast<v8::internal::Address>(data));
255 }
Imm32(const uint8_t * data)256 int32_t Imm32(const uint8_t* data) {
257   return v8::base::ReadUnalignedValue<int32_t>(
258       reinterpret_cast<v8::internal::Address>(data));
259 }
Imm32_U(const uint8_t * data)260 uint32_t Imm32_U(const uint8_t* data) {
261   return v8::base::ReadUnalignedValue<uint32_t>(
262       reinterpret_cast<v8::internal::Address>(data));
263 }
Imm64(const uint8_t * data)264 int64_t Imm64(const uint8_t* data) {
265   return v8::base::ReadUnalignedValue<int64_t>(
266       reinterpret_cast<v8::internal::Address>(data));
267 }
268 }  // namespace
269 
270 //------------------------------------------------------------------------------
271 // DisassemblerX64 implementation.
272 
273 // A new DisassemblerX64 object is created to disassemble each instruction.
274 // The object can only disassemble a single instruction.
275 class DisassemblerX64 {
276  public:
DisassemblerX64(const NameConverter & converter,Disassembler::UnimplementedOpcodeAction unimplemented_action)277   DisassemblerX64(const NameConverter& converter,
278                   Disassembler::UnimplementedOpcodeAction unimplemented_action)
279       : converter_(converter),
280         tmp_buffer_pos_(0),
281         abort_on_unimplemented_(unimplemented_action ==
282                                 Disassembler::kAbortOnUnimplementedOpcode),
283         rex_(0),
284         operand_size_(0),
285         group_1_prefix_(0),
286         vex_byte0_(0),
287         vex_byte1_(0),
288         vex_byte2_(0),
289         byte_size_operand_(false),
290         instruction_table_(GetInstructionTable()) {
291     tmp_buffer_[0] = '\0';
292   }
293 
294   // Writes one disassembled instruction into 'buffer' (0-terminated).
295   // Returns the length of the disassembled machine instruction in bytes.
296   int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
297 
298  private:
299   enum OperandSize {
300     OPERAND_BYTE_SIZE = 0,
301     OPERAND_WORD_SIZE = 1,
302     OPERAND_DOUBLEWORD_SIZE = 2,
303     OPERAND_QUADWORD_SIZE = 3
304   };
305 
306   const NameConverter& converter_;
307   v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
308   unsigned int tmp_buffer_pos_;
309   bool abort_on_unimplemented_;
310   // Prefixes parsed
311   byte rex_;
312   byte operand_size_;    // 0x66 or (if no group 3 prefix is present) 0x0.
313   byte group_1_prefix_;  // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
314   byte vex_byte0_;       // 0xC4 or 0xC5
315   byte vex_byte1_;
316   byte vex_byte2_;  // only for 3 bytes vex prefix
317   // Byte size operand override.
318   bool byte_size_operand_;
319   const InstructionTable* const instruction_table_;
320 
setRex(byte rex)321   void setRex(byte rex) {
322     DCHECK_EQ(0x40, rex & 0xF0);
323     rex_ = rex;
324   }
325 
rex()326   bool rex() { return rex_ != 0; }
327 
rex_b()328   bool rex_b() { return (rex_ & 0x01) != 0; }
329 
330   // Actual number of base register given the low bits and the rex.b state.
base_reg(int low_bits)331   int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); }
332 
rex_x()333   bool rex_x() { return (rex_ & 0x02) != 0; }
334 
rex_r()335   bool rex_r() { return (rex_ & 0x04) != 0; }
336 
rex_w()337   bool rex_w() { return (rex_ & 0x08) != 0; }
338 
vex_w()339   bool vex_w() {
340     DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
341     return vex_byte0_ == VEX3_PREFIX ? (vex_byte2_ & 0x80) != 0 : false;
342   }
343 
vex_128()344   bool vex_128() {
345     DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
346     byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
347     return (checked & 4) == 0;
348   }
349 
vex_none()350   bool vex_none() {
351     DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
352     byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
353     return (checked & 3) == 0;
354   }
355 
vex_66()356   bool vex_66() {
357     DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
358     byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
359     return (checked & 3) == 1;
360   }
361 
vex_f3()362   bool vex_f3() {
363     DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
364     byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
365     return (checked & 3) == 2;
366   }
367 
vex_f2()368   bool vex_f2() {
369     DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
370     byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
371     return (checked & 3) == 3;
372   }
373 
vex_0f()374   bool vex_0f() {
375     if (vex_byte0_ == VEX2_PREFIX) return true;
376     return (vex_byte1_ & 3) == 1;
377   }
378 
vex_0f38()379   bool vex_0f38() {
380     if (vex_byte0_ == VEX2_PREFIX) return false;
381     return (vex_byte1_ & 3) == 2;
382   }
383 
vex_0f3a()384   bool vex_0f3a() {
385     if (vex_byte0_ == VEX2_PREFIX) return false;
386     return (vex_byte1_ & 3) == 3;
387   }
388 
vex_vreg()389   int vex_vreg() {
390     DCHECK(vex_byte0_ == VEX3_PREFIX || vex_byte0_ == VEX2_PREFIX);
391     byte checked = vex_byte0_ == VEX3_PREFIX ? vex_byte2_ : vex_byte1_;
392     return ~(checked >> 3) & 0xF;
393   }
394 
operand_size()395   OperandSize operand_size() {
396     if (byte_size_operand_) return OPERAND_BYTE_SIZE;
397     if (rex_w()) return OPERAND_QUADWORD_SIZE;
398     if (operand_size_ != 0) return OPERAND_WORD_SIZE;
399     return OPERAND_DOUBLEWORD_SIZE;
400   }
401 
operand_size_code()402   char operand_size_code() { return "bwlq"[operand_size()]; }
403 
float_size_code()404   char float_size_code() { return "sd"[rex_w()]; }
405 
NameOfCPURegister(int reg) const406   const char* NameOfCPURegister(int reg) const {
407     return converter_.NameOfCPURegister(reg);
408   }
409 
NameOfByteCPURegister(int reg) const410   const char* NameOfByteCPURegister(int reg) const {
411     return converter_.NameOfByteCPURegister(reg);
412   }
413 
NameOfXMMRegister(int reg) const414   const char* NameOfXMMRegister(int reg) const {
415     return converter_.NameOfXMMRegister(reg);
416   }
417 
NameOfAddress(byte * addr) const418   const char* NameOfAddress(byte* addr) const {
419     return converter_.NameOfAddress(addr);
420   }
421 
422   // Disassembler helper functions.
get_modrm(byte data,int * mod,int * regop,int * rm)423   void get_modrm(byte data, int* mod, int* regop, int* rm) {
424     *mod = (data >> 6) & 3;
425     *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0);
426     *rm = (data & 7) | (rex_b() ? 8 : 0);
427   }
428 
get_sib(byte data,int * scale,int * index,int * base)429   void get_sib(byte data, int* scale, int* index, int* base) {
430     *scale = (data >> 6) & 3;
431     *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
432     *base = (data & 7) | (rex_b() ? 8 : 0);
433   }
434 
435   using RegisterNameMapping = const char* (DisassemblerX64::*)(int reg) const;
436 
437   void TryAppendRootRelativeName(int offset);
438   int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name);
439   int PrintRightOperand(byte* modrmp);
440   int PrintRightByteOperand(byte* modrmp);
441   int PrintRightXMMOperand(byte* modrmp);
442   int PrintOperands(const char* mnem, OperandType op_order, byte* data);
443   int PrintImmediate(byte* data, OperandSize size);
444   int PrintImmediateOp(byte* data);
445   const char* TwoByteMnemonic(byte opcode);
446   int TwoByteOpcodeInstruction(byte* data);
447   int F6F7Instruction(byte* data);
448   int ShiftInstruction(byte* data);
449   int JumpShort(byte* data);
450   int JumpConditional(byte* data);
451   int JumpConditionalShort(byte* data);
452   int SetCC(byte* data);
453   int FPUInstruction(byte* data);
454   int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
455   int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
456   int AVXInstruction(byte* data);
457   PRINTF_FORMAT(2, 3) void AppendToBuffer(const char* format, ...);
458 
UnimplementedInstruction()459   void UnimplementedInstruction() {
460     if (abort_on_unimplemented_) {
461       FATAL("'Unimplemented Instruction'");
462     } else {
463       AppendToBuffer("'Unimplemented Instruction'");
464     }
465   }
466 };
467 
AppendToBuffer(const char * format,...)468 void DisassemblerX64::AppendToBuffer(const char* format, ...) {
469   v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
470   va_list args;
471   va_start(args, format);
472   int result = v8::internal::VSNPrintF(buf, format, args);
473   va_end(args);
474   tmp_buffer_pos_ += result;
475 }
476 
TryAppendRootRelativeName(int offset)477 void DisassemblerX64::TryAppendRootRelativeName(int offset) {
478   const char* maybe_name = converter_.RootRelativeName(offset);
479   if (maybe_name != nullptr) AppendToBuffer(" (%s)", maybe_name);
480 }
481 
PrintRightOperandHelper(byte * modrmp,RegisterNameMapping direct_register_name)482 int DisassemblerX64::PrintRightOperandHelper(
483     byte* modrmp, RegisterNameMapping direct_register_name) {
484   int mod, regop, rm;
485   get_modrm(*modrmp, &mod, &regop, &rm);
486   RegisterNameMapping register_name =
487       (mod == 3) ? direct_register_name : &DisassemblerX64::NameOfCPURegister;
488   switch (mod) {
489     case 0:
490       if ((rm & 7) == 5) {
491         AppendToBuffer("[rip+0x%x]", Imm32(modrmp + 1));
492         return 5;
493       } else if ((rm & 7) == 4) {
494         // Codes for SIB byte.
495         byte sib = *(modrmp + 1);
496         int scale, index, base;
497         get_sib(sib, &scale, &index, &base);
498         if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
499           // index == rsp means no index. Only use sib byte with no index for
500           // rsp and r12 base.
501           AppendToBuffer("[%s]", NameOfCPURegister(base));
502           return 2;
503         } else if (base == 5) {
504           // base == rbp means no base register (when mod == 0).
505           int32_t disp = Imm32(modrmp + 2);
506           AppendToBuffer("[%s*%d%s0x%x]", NameOfCPURegister(index), 1 << scale,
507                          disp < 0 ? "-" : "+", disp < 0 ? -disp : disp);
508           return 6;
509         } else if (index != 4 && base != 5) {
510           // [base+index*scale]
511           AppendToBuffer("[%s+%s*%d]", NameOfCPURegister(base),
512                          NameOfCPURegister(index), 1 << scale);
513           return 2;
514         } else {
515           UnimplementedInstruction();
516           return 1;
517         }
518       } else {
519         AppendToBuffer("[%s]", NameOfCPURegister(rm));
520         return 1;
521       }
522       break;
523     case 1:  // fall through
524     case 2:
525       if ((rm & 7) == 4) {
526         byte sib = *(modrmp + 1);
527         int scale, index, base;
528         get_sib(sib, &scale, &index, &base);
529         int disp = (mod == 2) ? Imm32(modrmp + 2) : Imm8(modrmp + 2);
530         if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
531           AppendToBuffer("[%s%s0x%x]", NameOfCPURegister(base),
532                          disp < 0 ? "-" : "+", disp < 0 ? -disp : disp);
533         } else {
534           AppendToBuffer("[%s+%s*%d%s0x%x]", NameOfCPURegister(base),
535                          NameOfCPURegister(index), 1 << scale,
536                          disp < 0 ? "-" : "+", disp < 0 ? -disp : disp);
537         }
538         return mod == 2 ? 6 : 3;
539       } else {
540         // No sib.
541         int disp = (mod == 2) ? Imm32(modrmp + 1) : Imm8(modrmp + 1);
542         AppendToBuffer("[%s%s0x%x]", NameOfCPURegister(rm),
543                        disp < 0 ? "-" : "+", disp < 0 ? -disp : disp);
544         if (rm == i::kRootRegister.code()) {
545           // For root-relative accesses, try to append a description.
546           TryAppendRootRelativeName(disp);
547         }
548         return (mod == 2) ? 5 : 2;
549       }
550       break;
551     case 3:
552       AppendToBuffer("%s", (this->*register_name)(rm));
553       return 1;
554     default:
555       UnimplementedInstruction();
556       return 1;
557   }
558   UNREACHABLE();
559 }
560 
PrintImmediate(byte * data,OperandSize size)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 = Imm16(data);
571       count = 2;
572       break;
573     case OPERAND_DOUBLEWORD_SIZE:
574       value = Imm32_U(data);
575       count = 4;
576       break;
577     case OPERAND_QUADWORD_SIZE:
578       value = Imm32(data);
579       count = 4;
580       break;
581     default:
582       UNREACHABLE();
583   }
584   AppendToBuffer("%" PRIx64, value);
585   return count;
586 }
587 
PrintRightOperand(byte * modrmp)588 int DisassemblerX64::PrintRightOperand(byte* modrmp) {
589   return PrintRightOperandHelper(modrmp, &DisassemblerX64::NameOfCPURegister);
590 }
591 
PrintRightByteOperand(byte * modrmp)592 int DisassemblerX64::PrintRightByteOperand(byte* modrmp) {
593   return PrintRightOperandHelper(modrmp,
594                                  &DisassemblerX64::NameOfByteCPURegister);
595 }
596 
PrintRightXMMOperand(byte * modrmp)597 int DisassemblerX64::PrintRightXMMOperand(byte* modrmp) {
598   return PrintRightOperandHelper(modrmp, &DisassemblerX64::NameOfXMMRegister);
599 }
600 
601 // Returns number of bytes used including the current *data.
602 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
PrintOperands(const char * mnem,OperandType op_order,byte * data)603 int DisassemblerX64::PrintOperands(const char* mnem, OperandType op_order,
604                                    byte* data) {
605   byte modrm = *data;
606   int mod, regop, rm;
607   get_modrm(modrm, &mod, &regop, &rm);
608   int advance = 0;
609   const char* register_name = byte_size_operand_ ? NameOfByteCPURegister(regop)
610                                                  : NameOfCPURegister(regop);
611   switch (op_order) {
612     case REG_OPER_OP_ORDER: {
613       AppendToBuffer("%s%c %s,", mnem, operand_size_code(), register_name);
614       advance = byte_size_operand_ ? PrintRightByteOperand(data)
615                                    : PrintRightOperand(data);
616       break;
617     }
618     case OPER_REG_OP_ORDER: {
619       AppendToBuffer("%s%c ", mnem, operand_size_code());
620       advance = byte_size_operand_ ? PrintRightByteOperand(data)
621                                    : PrintRightOperand(data);
622       AppendToBuffer(",%s", register_name);
623       break;
624     }
625     default:
626       UNREACHABLE();
627   }
628   return advance;
629 }
630 
631 // Returns number of bytes used by machine instruction, including *data byte.
632 // Writes immediate instructions to 'tmp_buffer_'.
PrintImmediateOp(byte * data)633 int DisassemblerX64::PrintImmediateOp(byte* data) {
634   bool byte_size_immediate = (*data & 0x02) != 0;
635   byte modrm = *(data + 1);
636   int mod, regop, rm;
637   get_modrm(modrm, &mod, &regop, &rm);
638   const char* mnem = "Imm???";
639   switch (regop) {
640     case 0:
641       mnem = "add";
642       break;
643     case 1:
644       mnem = "or";
645       break;
646     case 2:
647       mnem = "adc";
648       break;
649     case 3:
650       mnem = "sbb";
651       break;
652     case 4:
653       mnem = "and";
654       break;
655     case 5:
656       mnem = "sub";
657       break;
658     case 6:
659       mnem = "xor";
660       break;
661     case 7:
662       mnem = "cmp";
663       break;
664     default:
665       UnimplementedInstruction();
666   }
667   AppendToBuffer("%s%c ", mnem, operand_size_code());
668   int count = PrintRightOperand(data + 1);
669   AppendToBuffer(",0x");
670   OperandSize immediate_size =
671       byte_size_immediate ? OPERAND_BYTE_SIZE : operand_size();
672   count += PrintImmediate(data + 1 + count, immediate_size);
673   return 1 + count;
674 }
675 
676 // Returns number of bytes used, including *data.
F6F7Instruction(byte * data)677 int DisassemblerX64::F6F7Instruction(byte* data) {
678   DCHECK(*data == 0xF7 || *data == 0xF6);
679   byte modrm = *(data + 1);
680   int mod, regop, rm;
681   get_modrm(modrm, &mod, &regop, &rm);
682   if (regop != 0) {
683     const char* mnem = nullptr;
684     switch (regop) {
685       case 2:
686         mnem = "not";
687         break;
688       case 3:
689         mnem = "neg";
690         break;
691       case 4:
692         mnem = "mul";
693         break;
694       case 5:
695         mnem = "imul";
696         break;
697       case 6:
698         mnem = "div";
699         break;
700       case 7:
701         mnem = "idiv";
702         break;
703       default:
704         UnimplementedInstruction();
705     }
706     if (mod == 3) {
707       AppendToBuffer("%s%c %s", mnem, operand_size_code(),
708                      NameOfCPURegister(rm));
709       return 2;
710     } else if (mod == 1) {
711       AppendToBuffer("%s%c ", mnem, operand_size_code());
712       int count = PrintRightOperand(data + 1);  // Use name of 64-bit register.
713       return 1 + count;
714     } else {
715       UnimplementedInstruction();
716       return 2;
717     }
718   } else if (regop == 0) {
719     AppendToBuffer("test%c ", operand_size_code());
720     int count = PrintRightOperand(data + 1);  // Use name of 64-bit register.
721     AppendToBuffer(",0x");
722     count += PrintImmediate(data + 1 + count, operand_size());
723     return 1 + count;
724   } else {
725     UnimplementedInstruction();
726     return 2;
727   }
728 }
729 
ShiftInstruction(byte * data)730 int DisassemblerX64::ShiftInstruction(byte* data) {
731   byte op = *data & (~1);
732   int count = 1;
733   if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
734     UnimplementedInstruction();
735     return count;
736   }
737   // Print mneumonic.
738   {
739     byte modrm = *(data + count);
740     int mod, regop, rm;
741     get_modrm(modrm, &mod, &regop, &rm);
742     regop &= 0x7;  // The REX.R bit does not affect the operation.
743     const char* mnem = nullptr;
744     switch (regop) {
745       case 0:
746         mnem = "rol";
747         break;
748       case 1:
749         mnem = "ror";
750         break;
751       case 2:
752         mnem = "rcl";
753         break;
754       case 3:
755         mnem = "rcr";
756         break;
757       case 4:
758         mnem = "shl";
759         break;
760       case 5:
761         mnem = "shr";
762         break;
763       case 7:
764         mnem = "sar";
765         break;
766       default:
767         UnimplementedInstruction();
768         return count + 1;
769     }
770     DCHECK_NOT_NULL(mnem);
771     AppendToBuffer("%s%c ", mnem, operand_size_code());
772   }
773   count += PrintRightOperand(data + count);
774   if (op == 0xD2) {
775     AppendToBuffer(", cl");
776   } else {
777     int imm8 = -1;
778     if (op == 0xD0) {
779       imm8 = 1;
780     } else {
781       DCHECK_EQ(0xC0, op);
782       imm8 = *(data + count);
783       count++;
784     }
785     AppendToBuffer(", %d", imm8);
786   }
787   return count;
788 }
789 
790 // Returns number of bytes used, including *data.
JumpShort(byte * data)791 int DisassemblerX64::JumpShort(byte* data) {
792   DCHECK_EQ(0xEB, *data);
793   byte b = *(data + 1);
794   byte* dest = data + static_cast<int8_t>(b) + 2;
795   AppendToBuffer("jmp %s", NameOfAddress(dest));
796   return 2;
797 }
798 
799 // Returns number of bytes used, including *data.
JumpConditional(byte * data)800 int DisassemblerX64::JumpConditional(byte* data) {
801   DCHECK_EQ(0x0F, *data);
802   byte cond = *(data + 1) & 0x0F;
803   byte* dest = data + Imm32(data + 2) + 6;
804   const char* mnem = conditional_code_suffix[cond];
805   AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
806   return 6;  // includes 0x0F
807 }
808 
809 // Returns number of bytes used, including *data.
JumpConditionalShort(byte * data)810 int DisassemblerX64::JumpConditionalShort(byte* data) {
811   byte cond = *data & 0x0F;
812   byte b = *(data + 1);
813   byte* dest = data + static_cast<int8_t>(b) + 2;
814   const char* mnem = conditional_code_suffix[cond];
815   AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
816   return 2;
817 }
818 
819 // Returns number of bytes used, including *data.
SetCC(byte * data)820 int DisassemblerX64::SetCC(byte* data) {
821   DCHECK_EQ(0x0F, *data);
822   byte cond = *(data + 1) & 0x0F;
823   const char* mnem = conditional_code_suffix[cond];
824   AppendToBuffer("set%s%c ", mnem, operand_size_code());
825   PrintRightByteOperand(data + 2);
826   return 3;  // includes 0x0F
827 }
828 
829 const char* sf_str[4] = {"", "rl", "ra", "ll"};
830 
AVXInstruction(byte * data)831 int DisassemblerX64::AVXInstruction(byte* data) {
832   byte opcode = *data;
833   byte* current = data + 1;
834   if (vex_66() && vex_0f38()) {
835     int mod, regop, rm, vvvv = vex_vreg();
836     get_modrm(*current, &mod, &regop, &rm);
837     switch (opcode) {
838       case 0x18:
839         AppendToBuffer("vbroadcastss %s,", NameOfXMMRegister(regop));
840         current += PrintRightXMMOperand(current);
841         break;
842       case 0x99:
843         AppendToBuffer("vfmadd132s%c %s,%s,", float_size_code(),
844                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
845         current += PrintRightXMMOperand(current);
846         break;
847       case 0xA9:
848         AppendToBuffer("vfmadd213s%c %s,%s,", float_size_code(),
849                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
850         current += PrintRightXMMOperand(current);
851         break;
852       case 0xB8:
853         AppendToBuffer("vfmadd231p%c %s,%s,", float_size_code(),
854                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
855         current += PrintRightXMMOperand(current);
856         break;
857       case 0xB9:
858         AppendToBuffer("vfmadd231s%c %s,%s,", float_size_code(),
859                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
860         current += PrintRightXMMOperand(current);
861         break;
862       case 0x9B:
863         AppendToBuffer("vfmsub132s%c %s,%s,", float_size_code(),
864                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
865         current += PrintRightXMMOperand(current);
866         break;
867       case 0xAB:
868         AppendToBuffer("vfmsub213s%c %s,%s,", float_size_code(),
869                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
870         current += PrintRightXMMOperand(current);
871         break;
872       case 0xBB:
873         AppendToBuffer("vfmsub231s%c %s,%s,", float_size_code(),
874                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
875         current += PrintRightXMMOperand(current);
876         break;
877       case 0xBC:
878         AppendToBuffer("vfnmadd231p%c %s,%s,", float_size_code(),
879                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
880         current += PrintRightXMMOperand(current);
881         break;
882       case 0x9D:
883         AppendToBuffer("vfnmadd132s%c %s,%s,", float_size_code(),
884                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
885         current += PrintRightXMMOperand(current);
886         break;
887       case 0xAD:
888         AppendToBuffer("vfnmadd213s%c %s,%s,", float_size_code(),
889                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
890         current += PrintRightXMMOperand(current);
891         break;
892       case 0xBD:
893         AppendToBuffer("vfnmadd231s%c %s,%s,", float_size_code(),
894                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
895         current += PrintRightXMMOperand(current);
896         break;
897       case 0x9F:
898         AppendToBuffer("vfnmsub132s%c %s,%s,", float_size_code(),
899                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
900         current += PrintRightXMMOperand(current);
901         break;
902       case 0xAF:
903         AppendToBuffer("vfnmsub213s%c %s,%s,", float_size_code(),
904                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
905         current += PrintRightXMMOperand(current);
906         break;
907       case 0xBF:
908         AppendToBuffer("vfnmsub231s%c %s,%s,", float_size_code(),
909                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
910         current += PrintRightXMMOperand(current);
911         break;
912       case 0xF7:
913         AppendToBuffer("shlx%c %s,", operand_size_code(),
914                        NameOfCPURegister(regop));
915         current += PrintRightOperand(current);
916         AppendToBuffer(",%s", NameOfCPURegister(vvvv));
917         break;
918 #define DECLARE_SSE_AVX_DIS_CASE(instruction, notUsed1, notUsed2, notUsed3, \
919                                  opcode)                                    \
920   case 0x##opcode: {                                                        \
921     AppendToBuffer("v" #instruction " %s,%s,", NameOfXMMRegister(regop),    \
922                    NameOfXMMRegister(vvvv));                                \
923     current += PrintRightXMMOperand(current);                               \
924     break;                                                                  \
925   }
926 
927         SSSE3_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE)
928         SSE4_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE)
929         SSE4_2_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE)
930 #undef DECLARE_SSE_AVX_DIS_CASE
931 
932 #define DECLARE_SSE_UNOP_AVX_DIS_CASE(instruction, notUsed1, notUsed2, \
933                                       notUsed3, opcode)                \
934   case 0x##opcode: {                                                   \
935     AppendToBuffer("v" #instruction " %s,", NameOfXMMRegister(regop)); \
936     current += PrintRightXMMOperand(current);                          \
937     break;                                                             \
938   }
939         SSSE3_UNOP_INSTRUCTION_LIST(DECLARE_SSE_UNOP_AVX_DIS_CASE)
940         SSE4_UNOP_INSTRUCTION_LIST(DECLARE_SSE_UNOP_AVX_DIS_CASE)
941 #undef DECLARE_SSE_UNOP_AVX_DIS_CASE
942 
943       default:
944         UnimplementedInstruction();
945     }
946   } else if (vex_66() && vex_0f3a()) {
947     int mod, regop, rm, vvvv = vex_vreg();
948     get_modrm(*current, &mod, &regop, &rm);
949     switch (opcode) {
950       case 0x0A:
951         AppendToBuffer("vroundss %s,%s,", NameOfXMMRegister(regop),
952                        NameOfXMMRegister(vvvv));
953         current += PrintRightXMMOperand(current);
954         AppendToBuffer(",0x%x", *current++);
955         break;
956       case 0x0B:
957         AppendToBuffer("vroundsd %s,%s,", NameOfXMMRegister(regop),
958                        NameOfXMMRegister(vvvv));
959         current += PrintRightXMMOperand(current);
960         AppendToBuffer(",0x%x", *current++);
961         break;
962       case 0x0E:
963         AppendToBuffer("vpblendw %s,%s,", NameOfXMMRegister(regop),
964                        NameOfXMMRegister(vvvv));
965         current += PrintRightXMMOperand(current);
966         AppendToBuffer(",0x%x", *current++);
967         break;
968       case 0x0F:
969         AppendToBuffer("vpalignr %s,%s,", NameOfXMMRegister(regop),
970                        NameOfXMMRegister(vvvv));
971         current += PrintRightXMMOperand(current);
972         AppendToBuffer(",0x%x", *current++);
973         break;
974       case 0x14:
975         AppendToBuffer("vpextrb ");
976         current += PrintRightByteOperand(current);
977         AppendToBuffer(",%s,0x%x,", NameOfXMMRegister(regop), *current++);
978         break;
979       case 0x15:
980         AppendToBuffer("vpextrw ");
981         current += PrintRightOperand(current);
982         AppendToBuffer(",%s,0x%x,", NameOfXMMRegister(regop), *current++);
983         break;
984       case 0x16:
985         AppendToBuffer("vpextr%c ", rex_w() ? 'q' : 'd');
986         current += PrintRightOperand(current);
987         AppendToBuffer(",%s,0x%x,", NameOfXMMRegister(regop), *current++);
988         break;
989       case 0x17:
990         AppendToBuffer("vextractps ");
991         current += PrintRightOperand(current);
992         AppendToBuffer(",%s,0x%x,", NameOfXMMRegister(regop), *current++);
993         break;
994       case 0x20:
995         AppendToBuffer("vpinsrb %s,%s,", NameOfXMMRegister(regop),
996                        NameOfXMMRegister(vvvv));
997         current += PrintRightByteOperand(current);
998         AppendToBuffer(",0x%x", *current++);
999         break;
1000       case 0x21:
1001         AppendToBuffer("vinsertps %s,%s,", NameOfXMMRegister(regop),
1002                        NameOfXMMRegister(vvvv));
1003         current += PrintRightXMMOperand(current);
1004         AppendToBuffer(",0x%x", *current++);
1005         break;
1006       case 0x22:
1007         AppendToBuffer("vpinsr%c %s,%s,", rex_w() ? 'q' : 'd',
1008                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
1009         current += PrintRightOperand(current);
1010         AppendToBuffer(",0x%x", *current++);
1011         break;
1012       case 0x4B: {
1013         AppendToBuffer("vblendvpd %s,%s,", NameOfXMMRegister(regop),
1014                        NameOfXMMRegister(vvvv));
1015         current += PrintRightXMMOperand(current);
1016         AppendToBuffer(",%s", NameOfXMMRegister((*current++) >> 4));
1017         break;
1018       }
1019       default:
1020         UnimplementedInstruction();
1021     }
1022   } else if (vex_f3() && vex_0f()) {
1023     int mod, regop, rm, vvvv = vex_vreg();
1024     get_modrm(*current, &mod, &regop, &rm);
1025     switch (opcode) {
1026       case 0x10:
1027         AppendToBuffer("vmovss %s,", NameOfXMMRegister(regop));
1028         if (mod == 3) {
1029           AppendToBuffer("%s,", NameOfXMMRegister(vvvv));
1030         }
1031         current += PrintRightXMMOperand(current);
1032         break;
1033       case 0x11:
1034         AppendToBuffer("vmovss ");
1035         current += PrintRightXMMOperand(current);
1036         if (mod == 3) {
1037           AppendToBuffer(",%s", NameOfXMMRegister(vvvv));
1038         }
1039         AppendToBuffer(",%s", NameOfXMMRegister(regop));
1040         break;
1041       case 0x2A:
1042         AppendToBuffer("%s %s,%s,", vex_w() ? "vcvtqsi2ss" : "vcvtlsi2ss",
1043                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
1044         current += PrintRightOperand(current);
1045         break;
1046       case 0x2C:
1047         AppendToBuffer("vcvttss2si%s %s,", vex_w() ? "q" : "",
1048                        NameOfCPURegister(regop));
1049         current += PrintRightXMMOperand(current);
1050         break;
1051       case 0x51:
1052         AppendToBuffer("vsqrtss %s,%s,", NameOfXMMRegister(regop),
1053                        NameOfXMMRegister(vvvv));
1054         current += PrintRightXMMOperand(current);
1055         break;
1056       case 0x58:
1057         AppendToBuffer("vaddss %s,%s,", NameOfXMMRegister(regop),
1058                        NameOfXMMRegister(vvvv));
1059         current += PrintRightXMMOperand(current);
1060         break;
1061       case 0x59:
1062         AppendToBuffer("vmulss %s,%s,", NameOfXMMRegister(regop),
1063                        NameOfXMMRegister(vvvv));
1064         current += PrintRightXMMOperand(current);
1065         break;
1066       case 0x5A:
1067         AppendToBuffer("vcvtss2sd %s,%s,", NameOfXMMRegister(regop),
1068                        NameOfXMMRegister(vvvv));
1069         current += PrintRightXMMOperand(current);
1070         break;
1071       case 0x5B:
1072         AppendToBuffer("vcvttps2dq %s,", NameOfXMMRegister(regop));
1073         current += PrintRightXMMOperand(current);
1074         break;
1075       case 0x5C:
1076         AppendToBuffer("vsubss %s,%s,", NameOfXMMRegister(regop),
1077                        NameOfXMMRegister(vvvv));
1078         current += PrintRightXMMOperand(current);
1079         break;
1080       case 0x5D:
1081         AppendToBuffer("vminss %s,%s,", NameOfXMMRegister(regop),
1082                        NameOfXMMRegister(vvvv));
1083         current += PrintRightXMMOperand(current);
1084         break;
1085       case 0x5E:
1086         AppendToBuffer("vdivss %s,%s,", NameOfXMMRegister(regop),
1087                        NameOfXMMRegister(vvvv));
1088         current += PrintRightXMMOperand(current);
1089         break;
1090       case 0x5F:
1091         AppendToBuffer("vmaxss %s,%s,", NameOfXMMRegister(regop),
1092                        NameOfXMMRegister(vvvv));
1093         current += PrintRightXMMOperand(current);
1094         break;
1095       case 0x6F:
1096         AppendToBuffer("vmovdqu %s,", NameOfXMMRegister(regop));
1097         current += PrintRightXMMOperand(current);
1098         break;
1099       case 0x70:
1100         AppendToBuffer("vpshufhw %s,", NameOfXMMRegister(regop));
1101         current += PrintRightXMMOperand(current);
1102         AppendToBuffer(",0x%x", *current++);
1103         break;
1104       case 0x7F:
1105         AppendToBuffer("vmovdqu ");
1106         current += PrintRightXMMOperand(current);
1107         AppendToBuffer(",%s", NameOfXMMRegister(regop));
1108         break;
1109       default:
1110         UnimplementedInstruction();
1111     }
1112   } else if (vex_f2() && vex_0f()) {
1113     int mod, regop, rm, vvvv = vex_vreg();
1114     get_modrm(*current, &mod, &regop, &rm);
1115     switch (opcode) {
1116       case 0x10:
1117         AppendToBuffer("vmovsd %s,", NameOfXMMRegister(regop));
1118         if (mod == 3) {
1119           AppendToBuffer("%s,", NameOfXMMRegister(vvvv));
1120         }
1121         current += PrintRightXMMOperand(current);
1122         break;
1123       case 0x11:
1124         AppendToBuffer("vmovsd ");
1125         current += PrintRightXMMOperand(current);
1126         if (mod == 3) {
1127           AppendToBuffer(",%s", NameOfXMMRegister(vvvv));
1128         }
1129         AppendToBuffer(",%s", NameOfXMMRegister(regop));
1130         break;
1131       case 0x12:
1132         AppendToBuffer("vmovddup %s,", NameOfXMMRegister(regop));
1133         current += PrintRightXMMOperand(current);
1134         break;
1135       case 0x2A:
1136         AppendToBuffer("%s %s,%s,", vex_w() ? "vcvtqsi2sd" : "vcvtlsi2sd",
1137                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
1138         current += PrintRightOperand(current);
1139         break;
1140       case 0x2C:
1141         AppendToBuffer("vcvttsd2si%s %s,", vex_w() ? "q" : "",
1142                        NameOfCPURegister(regop));
1143         current += PrintRightXMMOperand(current);
1144         break;
1145       case 0x2D:
1146         AppendToBuffer("vcvtsd2si%s %s,", vex_w() ? "q" : "",
1147                        NameOfCPURegister(regop));
1148         current += PrintRightXMMOperand(current);
1149         break;
1150       case 0x51:
1151         AppendToBuffer("vsqrtsd %s,%s,", NameOfXMMRegister(regop),
1152                        NameOfXMMRegister(vvvv));
1153         current += PrintRightXMMOperand(current);
1154         break;
1155       case 0x58:
1156         AppendToBuffer("vaddsd %s,%s,", NameOfXMMRegister(regop),
1157                        NameOfXMMRegister(vvvv));
1158         current += PrintRightXMMOperand(current);
1159         break;
1160       case 0x59:
1161         AppendToBuffer("vmulsd %s,%s,", NameOfXMMRegister(regop),
1162                        NameOfXMMRegister(vvvv));
1163         current += PrintRightXMMOperand(current);
1164         break;
1165       case 0x5A:
1166         AppendToBuffer("vcvtsd2ss %s,%s,", NameOfXMMRegister(regop),
1167                        NameOfXMMRegister(vvvv));
1168         current += PrintRightXMMOperand(current);
1169         break;
1170       case 0x5C:
1171         AppendToBuffer("vsubsd %s,%s,", NameOfXMMRegister(regop),
1172                        NameOfXMMRegister(vvvv));
1173         current += PrintRightXMMOperand(current);
1174         break;
1175       case 0x5D:
1176         AppendToBuffer("vminsd %s,%s,", NameOfXMMRegister(regop),
1177                        NameOfXMMRegister(vvvv));
1178         current += PrintRightXMMOperand(current);
1179         break;
1180       case 0x5E:
1181         AppendToBuffer("vdivsd %s,%s,", NameOfXMMRegister(regop),
1182                        NameOfXMMRegister(vvvv));
1183         current += PrintRightXMMOperand(current);
1184         break;
1185       case 0x5F:
1186         AppendToBuffer("vmaxsd %s,%s,", NameOfXMMRegister(regop),
1187                        NameOfXMMRegister(vvvv));
1188         current += PrintRightXMMOperand(current);
1189         break;
1190       case 0xF0:
1191         AppendToBuffer("vlddqu %s,", NameOfXMMRegister(regop));
1192         current += PrintRightXMMOperand(current);
1193         break;
1194       case 0x70:
1195         AppendToBuffer("vpshuflw %s,", NameOfXMMRegister(regop));
1196         current += PrintRightXMMOperand(current);
1197         AppendToBuffer(",0x%x", *current++);
1198         break;
1199       case 0x7C:
1200         AppendToBuffer("vhaddps %s,%s,", NameOfXMMRegister(regop),
1201                        NameOfXMMRegister(vvvv));
1202         current += PrintRightXMMOperand(current);
1203         break;
1204       default:
1205         UnimplementedInstruction();
1206     }
1207   } else if (vex_none() && vex_0f38()) {
1208     int mod, regop, rm, vvvv = vex_vreg();
1209     get_modrm(*current, &mod, &regop, &rm);
1210     const char* mnem = "?";
1211     switch (opcode) {
1212       case 0xF2:
1213         AppendToBuffer("andn%c %s,%s,", operand_size_code(),
1214                        NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1215         current += PrintRightOperand(current);
1216         break;
1217       case 0xF5:
1218         AppendToBuffer("bzhi%c %s,", operand_size_code(),
1219                        NameOfCPURegister(regop));
1220         current += PrintRightOperand(current);
1221         AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1222         break;
1223       case 0xF7:
1224         AppendToBuffer("bextr%c %s,", operand_size_code(),
1225                        NameOfCPURegister(regop));
1226         current += PrintRightOperand(current);
1227         AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1228         break;
1229       case 0xF3:
1230         switch (regop) {
1231           case 1:
1232             mnem = "blsr";
1233             break;
1234           case 2:
1235             mnem = "blsmsk";
1236             break;
1237           case 3:
1238             mnem = "blsi";
1239             break;
1240           default:
1241             UnimplementedInstruction();
1242         }
1243         AppendToBuffer("%s%c %s,", mnem, operand_size_code(),
1244                        NameOfCPURegister(vvvv));
1245         current += PrintRightOperand(current);
1246         mnem = "?";
1247         break;
1248       default:
1249         UnimplementedInstruction();
1250     }
1251   } else if (vex_f2() && vex_0f38()) {
1252     int mod, regop, rm, vvvv = vex_vreg();
1253     get_modrm(*current, &mod, &regop, &rm);
1254     switch (opcode) {
1255       case 0xF5:
1256         AppendToBuffer("pdep%c %s,%s,", operand_size_code(),
1257                        NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1258         current += PrintRightOperand(current);
1259         break;
1260       case 0xF6:
1261         AppendToBuffer("mulx%c %s,%s,", operand_size_code(),
1262                        NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1263         current += PrintRightOperand(current);
1264         break;
1265       case 0xF7:
1266         AppendToBuffer("shrx%c %s,", operand_size_code(),
1267                        NameOfCPURegister(regop));
1268         current += PrintRightOperand(current);
1269         AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1270         break;
1271       default:
1272         UnimplementedInstruction();
1273     }
1274   } else if (vex_f3() && vex_0f38()) {
1275     int mod, regop, rm, vvvv = vex_vreg();
1276     get_modrm(*current, &mod, &regop, &rm);
1277     switch (opcode) {
1278       case 0xF5:
1279         AppendToBuffer("pext%c %s,%s,", operand_size_code(),
1280                        NameOfCPURegister(regop), NameOfCPURegister(vvvv));
1281         current += PrintRightOperand(current);
1282         break;
1283       case 0xF7:
1284         AppendToBuffer("sarx%c %s,", operand_size_code(),
1285                        NameOfCPURegister(regop));
1286         current += PrintRightOperand(current);
1287         AppendToBuffer(",%s", NameOfCPURegister(vvvv));
1288         break;
1289       default:
1290         UnimplementedInstruction();
1291     }
1292   } else if (vex_f2() && vex_0f3a()) {
1293     int mod, regop, rm;
1294     get_modrm(*current, &mod, &regop, &rm);
1295     switch (opcode) {
1296       case 0xF0:
1297         AppendToBuffer("rorx%c %s,", operand_size_code(),
1298                        NameOfCPURegister(regop));
1299         current += PrintRightOperand(current);
1300         switch (operand_size()) {
1301           case OPERAND_DOUBLEWORD_SIZE:
1302             AppendToBuffer(",%d", *current & 0x1F);
1303             break;
1304           case OPERAND_QUADWORD_SIZE:
1305             AppendToBuffer(",%d", *current & 0x3F);
1306             break;
1307           default:
1308             UnimplementedInstruction();
1309         }
1310         current += 1;
1311         break;
1312       default:
1313         UnimplementedInstruction();
1314     }
1315   } else if (vex_none() && vex_0f()) {
1316     int mod, regop, rm, vvvv = vex_vreg();
1317     get_modrm(*current, &mod, &regop, &rm);
1318     switch (opcode) {
1319       case 0x10:
1320         AppendToBuffer("vmovups %s,", NameOfXMMRegister(regop));
1321         current += PrintRightXMMOperand(current);
1322         break;
1323       case 0x11:
1324         AppendToBuffer("vmovups ");
1325         current += PrintRightXMMOperand(current);
1326         AppendToBuffer(",%s", NameOfXMMRegister(regop));
1327         break;
1328       case 0x16:
1329         AppendToBuffer("vmovlhps %s,%s,", NameOfXMMRegister(regop),
1330                        NameOfXMMRegister(vvvv));
1331         current += PrintRightXMMOperand(current);
1332         break;
1333       case 0x28:
1334         AppendToBuffer("vmovaps %s,", NameOfXMMRegister(regop));
1335         current += PrintRightXMMOperand(current);
1336         break;
1337       case 0x29:
1338         AppendToBuffer("vmovaps ");
1339         current += PrintRightXMMOperand(current);
1340         AppendToBuffer(",%s", NameOfXMMRegister(regop));
1341         break;
1342       case 0x2E:
1343         AppendToBuffer("vucomiss %s,", NameOfXMMRegister(regop));
1344         current += PrintRightXMMOperand(current);
1345         break;
1346       case 0x50:
1347         AppendToBuffer("vmovmskps %s,", NameOfCPURegister(regop));
1348         current += PrintRightXMMOperand(current);
1349         break;
1350       case 0x51:
1351       case 0x52:
1352       case 0x53: {
1353         const char* const pseudo_op[] = {"vsqrtps", "vrsqrtps", "vrcpps"};
1354 
1355         AppendToBuffer("%s %s,", pseudo_op[opcode - 0x51],
1356                        NameOfXMMRegister(regop));
1357         current += PrintRightXMMOperand(current);
1358         break;
1359       }
1360       case 0x5A:
1361       case 0x5B: {
1362         const char* const pseudo_op[] = {"vcvtps2pd", "vcvtdq2ps"};
1363 
1364         AppendToBuffer("%s %s,", pseudo_op[opcode - 0x5A],
1365                        NameOfXMMRegister(regop));
1366         current += PrintRightXMMOperand(current);
1367         break;
1368       }
1369       case 0x54:
1370       case 0x55:
1371       case 0x56:
1372       case 0x57:
1373       case 0x58:
1374       case 0x59:
1375       case 0x5C:
1376       case 0x5D:
1377       case 0x5E:
1378       case 0x5F: {
1379         const char* const pseudo_op[] = {
1380             "vandps", "vandnps", "vorps",  "vxorps", "vaddps", "vmulps",
1381             "",       "",        "vsubps", "vminps", "vdivps", "vmaxps",
1382         };
1383 
1384         AppendToBuffer("%s %s,%s,", pseudo_op[opcode - 0x54],
1385                        NameOfXMMRegister(regop), NameOfXMMRegister(vvvv));
1386         current += PrintRightXMMOperand(current);
1387         break;
1388       }
1389       case 0xC2: {
1390         AppendToBuffer("vcmpps %s,%s,", NameOfXMMRegister(regop),
1391                        NameOfXMMRegister(vvvv));
1392         current += PrintRightXMMOperand(current);
1393         const char* const pseudo_op[] = {"eq",  "lt",  "le",  "unord",
1394                                          "neq", "nlt", "nle", "ord"};
1395         AppendToBuffer(", (%s)", pseudo_op[*current]);
1396         current += 1;
1397         break;
1398       }
1399       case 0xC6: {
1400         AppendToBuffer("vshufps %s,%s,", NameOfXMMRegister(regop),
1401                        NameOfXMMRegister(vvvv));
1402         current += PrintRightXMMOperand(current);
1403         AppendToBuffer(",0x%x", *current++);
1404         break;
1405       }
1406       default:
1407         UnimplementedInstruction();
1408     }
1409   } else if (vex_66() && vex_0f()) {
1410     int mod, regop, rm, vvvv = vex_vreg();
1411     get_modrm(*current, &mod, &regop, &rm);
1412     switch (opcode) {
1413       case 0x10:
1414         AppendToBuffer("vmovupd %s,", NameOfXMMRegister(regop));
1415         current += PrintRightXMMOperand(current);
1416         break;
1417       case 0x11:
1418         AppendToBuffer("vmovupd ");
1419         current += PrintRightXMMOperand(current);
1420         AppendToBuffer(",%s", NameOfXMMRegister(regop));
1421         break;
1422       case 0x28:
1423         AppendToBuffer("vmovapd %s,", NameOfXMMRegister(regop));
1424         current += PrintRightXMMOperand(current);
1425         break;
1426       case 0x29:
1427         AppendToBuffer("vmovapd ");
1428         current += PrintRightXMMOperand(current);
1429         AppendToBuffer(",%s", NameOfXMMRegister(regop));
1430         break;
1431       case 0x2E:
1432         AppendToBuffer("vucomisd %s,", NameOfXMMRegister(regop));
1433         current += PrintRightXMMOperand(current);
1434         break;
1435       case 0x50:
1436         AppendToBuffer("vmovmskpd %s,", NameOfCPURegister(regop));
1437         current += PrintRightXMMOperand(current);
1438         break;
1439       case 0x6E:
1440         AppendToBuffer("vmov%c %s,", vex_w() ? 'q' : 'd',
1441                        NameOfXMMRegister(regop));
1442         current += PrintRightOperand(current);
1443         break;
1444       case 0x70:
1445         AppendToBuffer("vpshufd %s,", NameOfXMMRegister(regop));
1446         current += PrintRightXMMOperand(current);
1447         AppendToBuffer(",0x%x", *current++);
1448         break;
1449       case 0x71:
1450         AppendToBuffer("vps%sw %s,", sf_str[regop / 2],
1451                        NameOfXMMRegister(vvvv));
1452         current += PrintRightXMMOperand(current);
1453         AppendToBuffer(",%u", *current++);
1454         break;
1455       case 0x72:
1456         AppendToBuffer("vps%sd %s,", sf_str[regop / 2],
1457                        NameOfXMMRegister(vvvv));
1458         current += PrintRightXMMOperand(current);
1459         AppendToBuffer(",%u", *current++);
1460         break;
1461       case 0x73:
1462         AppendToBuffer("vps%sq %s,", sf_str[regop / 2],
1463                        NameOfXMMRegister(vvvv));
1464         current += PrintRightXMMOperand(current);
1465         AppendToBuffer(",%u", *current++);
1466         break;
1467       case 0x7E:
1468         AppendToBuffer("vmov%c ", vex_w() ? 'q' : 'd');
1469         current += PrintRightOperand(current);
1470         AppendToBuffer(",%s", NameOfXMMRegister(regop));
1471         break;
1472       case 0xC2: {
1473         AppendToBuffer("vcmppd %s,%s,", NameOfXMMRegister(regop),
1474                        NameOfXMMRegister(vvvv));
1475         current += PrintRightXMMOperand(current);
1476         const char* const pseudo_op[] = {"eq",  "lt",  "le",  "unord",
1477                                          "neq", "nlt", "nle", "ord"};
1478         AppendToBuffer(", (%s)", pseudo_op[*current]);
1479         current += 1;
1480         break;
1481       }
1482       case 0xC4:
1483         AppendToBuffer("vpinsrw %s,%s,", NameOfXMMRegister(regop),
1484                        NameOfXMMRegister(vvvv));
1485         current += PrintRightOperand(current);
1486         AppendToBuffer(",0x%x", *current++);
1487         break;
1488       case 0xC5:
1489         AppendToBuffer("vpextrw %s,", NameOfCPURegister(regop));
1490         current += PrintRightXMMOperand(current);
1491         AppendToBuffer(",0x%x", *current++);
1492         break;
1493 #define DECLARE_SSE_AVX_DIS_CASE(instruction, notUsed1, notUsed2, opcode) \
1494   case 0x##opcode: {                                                      \
1495     AppendToBuffer("v" #instruction " %s,%s,", NameOfXMMRegister(regop),  \
1496                    NameOfXMMRegister(vvvv));                              \
1497     current += PrintRightXMMOperand(current);                             \
1498     break;                                                                \
1499   }
1500 
1501         SSE2_INSTRUCTION_LIST(DECLARE_SSE_AVX_DIS_CASE)
1502 #undef DECLARE_SSE_AVX_DIS_CASE
1503 #define DECLARE_SSE_UNOP_AVX_DIS_CASE(instruction, notUsed1, notUsed2, opcode) \
1504   case 0x##opcode: {                                                           \
1505     AppendToBuffer("v" #instruction " %s,", NameOfXMMRegister(regop));         \
1506     current += PrintRightXMMOperand(current);                                  \
1507     break;                                                                     \
1508   }
1509 
1510         SSE2_UNOP_INSTRUCTION_LIST(DECLARE_SSE_UNOP_AVX_DIS_CASE)
1511 #undef DECLARE_SSE_UNOP_AVX_DIS_CASE
1512       default:
1513         UnimplementedInstruction();
1514     }
1515 
1516   } else {
1517     UnimplementedInstruction();
1518   }
1519 
1520   return static_cast<int>(current - data);
1521 }
1522 
1523 // Returns number of bytes used, including *data.
FPUInstruction(byte * data)1524 int DisassemblerX64::FPUInstruction(byte* data) {
1525   byte escape_opcode = *data;
1526   DCHECK_EQ(0xD8, escape_opcode & 0xF8);
1527   byte modrm_byte = *(data + 1);
1528 
1529   if (modrm_byte >= 0xC0) {
1530     return RegisterFPUInstruction(escape_opcode, modrm_byte);
1531   } else {
1532     return MemoryFPUInstruction(escape_opcode, modrm_byte, data + 1);
1533   }
1534 }
1535 
MemoryFPUInstruction(int escape_opcode,int modrm_byte,byte * modrm_start)1536 int DisassemblerX64::MemoryFPUInstruction(int escape_opcode, int modrm_byte,
1537                                           byte* modrm_start) {
1538   const char* mnem = "?";
1539   int regop = (modrm_byte >> 3) & 0x7;  // reg/op field of modrm byte.
1540   switch (escape_opcode) {
1541     case 0xD9:
1542       switch (regop) {
1543         case 0:
1544           mnem = "fld_s";
1545           break;
1546         case 3:
1547           mnem = "fstp_s";
1548           break;
1549         case 7:
1550           mnem = "fstcw";
1551           break;
1552         default:
1553           UnimplementedInstruction();
1554       }
1555       break;
1556 
1557     case 0xDB:
1558       switch (regop) {
1559         case 0:
1560           mnem = "fild_s";
1561           break;
1562         case 1:
1563           mnem = "fisttp_s";
1564           break;
1565         case 2:
1566           mnem = "fist_s";
1567           break;
1568         case 3:
1569           mnem = "fistp_s";
1570           break;
1571         default:
1572           UnimplementedInstruction();
1573       }
1574       break;
1575 
1576     case 0xDD:
1577       switch (regop) {
1578         case 0:
1579           mnem = "fld_d";
1580           break;
1581         case 3:
1582           mnem = "fstp_d";
1583           break;
1584         default:
1585           UnimplementedInstruction();
1586       }
1587       break;
1588 
1589     case 0xDF:
1590       switch (regop) {
1591         case 5:
1592           mnem = "fild_d";
1593           break;
1594         case 7:
1595           mnem = "fistp_d";
1596           break;
1597         default:
1598           UnimplementedInstruction();
1599       }
1600       break;
1601 
1602     default:
1603       UnimplementedInstruction();
1604   }
1605   AppendToBuffer("%s ", mnem);
1606   int count = PrintRightOperand(modrm_start);
1607   return count + 1;
1608 }
1609 
RegisterFPUInstruction(int escape_opcode,byte modrm_byte)1610 int DisassemblerX64::RegisterFPUInstruction(int escape_opcode,
1611                                             byte modrm_byte) {
1612   bool has_register = false;  // Is the FPU register encoded in modrm_byte?
1613   const char* mnem = "?";
1614 
1615   switch (escape_opcode) {
1616     case 0xD8:
1617       UnimplementedInstruction();
1618       break;
1619 
1620     case 0xD9:
1621       switch (modrm_byte & 0xF8) {
1622         case 0xC0:
1623           mnem = "fld";
1624           has_register = true;
1625           break;
1626         case 0xC8:
1627           mnem = "fxch";
1628           has_register = true;
1629           break;
1630         default:
1631           switch (modrm_byte) {
1632             case 0xE0:
1633               mnem = "fchs";
1634               break;
1635             case 0xE1:
1636               mnem = "fabs";
1637               break;
1638             case 0xE3:
1639               mnem = "fninit";
1640               break;
1641             case 0xE4:
1642               mnem = "ftst";
1643               break;
1644             case 0xE8:
1645               mnem = "fld1";
1646               break;
1647             case 0xEB:
1648               mnem = "fldpi";
1649               break;
1650             case 0xED:
1651               mnem = "fldln2";
1652               break;
1653             case 0xEE:
1654               mnem = "fldz";
1655               break;
1656             case 0xF0:
1657               mnem = "f2xm1";
1658               break;
1659             case 0xF1:
1660               mnem = "fyl2x";
1661               break;
1662             case 0xF2:
1663               mnem = "fptan";
1664               break;
1665             case 0xF5:
1666               mnem = "fprem1";
1667               break;
1668             case 0xF7:
1669               mnem = "fincstp";
1670               break;
1671             case 0xF8:
1672               mnem = "fprem";
1673               break;
1674             case 0xFC:
1675               mnem = "frndint";
1676               break;
1677             case 0xFD:
1678               mnem = "fscale";
1679               break;
1680             case 0xFE:
1681               mnem = "fsin";
1682               break;
1683             case 0xFF:
1684               mnem = "fcos";
1685               break;
1686             default:
1687               UnimplementedInstruction();
1688           }
1689       }
1690       break;
1691 
1692     case 0xDA:
1693       if (modrm_byte == 0xE9) {
1694         mnem = "fucompp";
1695       } else {
1696         UnimplementedInstruction();
1697       }
1698       break;
1699 
1700     case 0xDB:
1701       if ((modrm_byte & 0xF8) == 0xE8) {
1702         mnem = "fucomi";
1703         has_register = true;
1704       } else if (modrm_byte == 0xE2) {
1705         mnem = "fclex";
1706       } else if (modrm_byte == 0xE3) {
1707         mnem = "fninit";
1708       } else {
1709         UnimplementedInstruction();
1710       }
1711       break;
1712 
1713     case 0xDC:
1714       has_register = true;
1715       switch (modrm_byte & 0xF8) {
1716         case 0xC0:
1717           mnem = "fadd";
1718           break;
1719         case 0xE8:
1720           mnem = "fsub";
1721           break;
1722         case 0xC8:
1723           mnem = "fmul";
1724           break;
1725         case 0xF8:
1726           mnem = "fdiv";
1727           break;
1728         default:
1729           UnimplementedInstruction();
1730       }
1731       break;
1732 
1733     case 0xDD:
1734       has_register = true;
1735       switch (modrm_byte & 0xF8) {
1736         case 0xC0:
1737           mnem = "ffree";
1738           break;
1739         case 0xD8:
1740           mnem = "fstp";
1741           break;
1742         default:
1743           UnimplementedInstruction();
1744       }
1745       break;
1746 
1747     case 0xDE:
1748       if (modrm_byte == 0xD9) {
1749         mnem = "fcompp";
1750       } else {
1751         has_register = true;
1752         switch (modrm_byte & 0xF8) {
1753           case 0xC0:
1754             mnem = "faddp";
1755             break;
1756           case 0xE8:
1757             mnem = "fsubp";
1758             break;
1759           case 0xC8:
1760             mnem = "fmulp";
1761             break;
1762           case 0xF8:
1763             mnem = "fdivp";
1764             break;
1765           default:
1766             UnimplementedInstruction();
1767         }
1768       }
1769       break;
1770 
1771     case 0xDF:
1772       if (modrm_byte == 0xE0) {
1773         mnem = "fnstsw_ax";
1774       } else if ((modrm_byte & 0xF8) == 0xE8) {
1775         mnem = "fucomip";
1776         has_register = true;
1777       }
1778       break;
1779 
1780     default:
1781       UnimplementedInstruction();
1782   }
1783 
1784   if (has_register) {
1785     AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1786   } else {
1787     AppendToBuffer("%s", mnem);
1788   }
1789   return 2;
1790 }
1791 
1792 // Handle all two-byte opcodes, which start with 0x0F.
1793 // These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
1794 // We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
TwoByteOpcodeInstruction(byte * data)1795 int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
1796   byte opcode = *(data + 1);
1797   byte* current = data + 2;
1798   // At return, "current" points to the start of the next instruction.
1799   const char* mnemonic = TwoByteMnemonic(opcode);
1800   if (operand_size_ == 0x66) {
1801     // 0x66 0x0F prefix.
1802     int mod, regop, rm;
1803     if (opcode == 0x38) {
1804       byte third_byte = *current;
1805       current = data + 3;
1806       get_modrm(*current, &mod, &regop, &rm);
1807       switch (third_byte) {
1808         case 0x15: {
1809           AppendToBuffer("blendvpd %s,", NameOfXMMRegister(regop));
1810           current += PrintRightXMMOperand(current);
1811           AppendToBuffer(",<xmm0>");
1812           break;
1813         }
1814 #define SSE34_DIS_CASE(instruction, notUsed1, notUsed2, notUsed3, opcode) \
1815   case 0x##opcode: {                                                      \
1816     AppendToBuffer(#instruction " %s,", NameOfXMMRegister(regop));        \
1817     current += PrintRightXMMOperand(current);                             \
1818     break;                                                                \
1819   }
1820 
1821         SSSE3_INSTRUCTION_LIST(SSE34_DIS_CASE)
1822         SSSE3_UNOP_INSTRUCTION_LIST(SSE34_DIS_CASE)
1823         SSE4_INSTRUCTION_LIST(SSE34_DIS_CASE)
1824         SSE4_UNOP_INSTRUCTION_LIST(SSE34_DIS_CASE)
1825         SSE4_2_INSTRUCTION_LIST(SSE34_DIS_CASE)
1826 #undef SSE34_DIS_CASE
1827         default:
1828           UnimplementedInstruction();
1829       }
1830     } else if (opcode == 0x3A) {
1831       byte third_byte = *current;
1832       current = data + 3;
1833       if (third_byte == 0x17) {
1834         get_modrm(*current, &mod, &regop, &rm);
1835         AppendToBuffer("extractps ");  // reg/m32, xmm, imm8
1836         current += PrintRightOperand(current);
1837         AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
1838         current += 1;
1839       } else if (third_byte == 0x0A) {
1840         get_modrm(*current, &mod, &regop, &rm);
1841         AppendToBuffer("roundss %s,", NameOfXMMRegister(regop));
1842         current += PrintRightXMMOperand(current);
1843         AppendToBuffer(",0x%x", (*current) & 3);
1844         current += 1;
1845       } else if (third_byte == 0x0B) {
1846         get_modrm(*current, &mod, &regop, &rm);
1847         // roundsd xmm, xmm/m64, imm8
1848         AppendToBuffer("roundsd %s,", NameOfXMMRegister(regop));
1849         current += PrintRightXMMOperand(current);
1850         AppendToBuffer(",0x%x", (*current) & 3);
1851         current += 1;
1852       } else if (third_byte == 0x0E) {
1853         get_modrm(*current, &mod, &regop, &rm);
1854         AppendToBuffer("pblendw %s,", NameOfXMMRegister(regop));
1855         current += PrintRightXMMOperand(current);
1856         AppendToBuffer(",0x%x", *current);
1857         current += 1;
1858       } else if (third_byte == 0x0F) {
1859         get_modrm(*current, &mod, &regop, &rm);
1860         AppendToBuffer("palignr %s,", NameOfXMMRegister(regop));
1861         current += PrintRightXMMOperand(current);
1862         AppendToBuffer(",0x%x", (*current));
1863         current += 1;
1864       } else if (third_byte == 0x14) {
1865         get_modrm(*current, &mod, &regop, &rm);
1866         AppendToBuffer("pextrb ");  // reg/m32, xmm, imm8
1867         current += PrintRightOperand(current);
1868         AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
1869         current += 1;
1870       } else if (third_byte == 0x15) {
1871         get_modrm(*current, &mod, &regop, &rm);
1872         AppendToBuffer("pextrw ");  // reg/m32, xmm, imm8
1873         current += PrintRightOperand(current);
1874         AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 7);
1875         current += 1;
1876       } else if (third_byte == 0x16) {
1877         get_modrm(*current, &mod, &regop, &rm);
1878         // reg/m32/reg/m64, xmm, imm8
1879         AppendToBuffer("pextr%c ", rex_w() ? 'q' : 'd');
1880         current += PrintRightOperand(current);
1881         AppendToBuffer(",%s,%d", NameOfXMMRegister(regop), (*current) & 3);
1882         current += 1;
1883       } else if (third_byte == 0x20) {
1884         get_modrm(*current, &mod, &regop, &rm);
1885         AppendToBuffer("pinsrb ");  // xmm, reg/m32, imm8
1886         AppendToBuffer(" %s,", NameOfXMMRegister(regop));
1887         current += PrintRightOperand(current);
1888         AppendToBuffer(",%d", (*current) & 3);
1889         current += 1;
1890       } else if (third_byte == 0x21) {
1891         get_modrm(*current, &mod, &regop, &rm);
1892         // insertps xmm, xmm/m32, imm8
1893         AppendToBuffer("insertps %s,", NameOfXMMRegister(regop));
1894         current += PrintRightXMMOperand(current);
1895         AppendToBuffer(",0x%x", (*current));
1896         current += 1;
1897       } else if (third_byte == 0x22) {
1898         get_modrm(*current, &mod, &regop, &rm);
1899         // xmm, reg/m32/reg/m64, imm8
1900         AppendToBuffer("pinsr%c ", rex_w() ? 'q' : 'd');
1901         AppendToBuffer(" %s,", NameOfXMMRegister(regop));
1902         current += PrintRightOperand(current);
1903         AppendToBuffer(",%d", (*current) & 3);
1904         current += 1;
1905       } else {
1906         UnimplementedInstruction();
1907       }
1908     } else if (opcode == 0xC1) {
1909       current += PrintOperands("xadd", OPER_REG_OP_ORDER, current);
1910     } else {
1911       get_modrm(*current, &mod, &regop, &rm);
1912       if (opcode == 0x1F) {
1913         current++;
1914         if (rm == 4) {  // SIB byte present.
1915           current++;
1916         }
1917         if (mod == 1) {  // Byte displacement.
1918           current += 1;
1919         } else if (mod == 2) {  // 32-bit displacement.
1920           current += 4;
1921         }  // else no immediate displacement.
1922         AppendToBuffer("nop");
1923       } else if (opcode == 0x10) {
1924         AppendToBuffer("movupd %s,", NameOfXMMRegister(regop));
1925         current += PrintRightXMMOperand(current);
1926       } else if (opcode == 0x11) {
1927         AppendToBuffer("movupd ");
1928         current += PrintRightXMMOperand(current);
1929         AppendToBuffer(",%s", NameOfXMMRegister(regop));
1930       } else if (opcode == 0x28) {
1931         AppendToBuffer("movapd %s,", NameOfXMMRegister(regop));
1932         current += PrintRightXMMOperand(current);
1933       } else if (opcode == 0x29) {
1934         AppendToBuffer("movapd ");
1935         current += PrintRightXMMOperand(current);
1936         AppendToBuffer(",%s", NameOfXMMRegister(regop));
1937       } else if (opcode == 0x6E) {
1938         AppendToBuffer("mov%c %s,", rex_w() ? 'q' : 'd',
1939                        NameOfXMMRegister(regop));
1940         current += PrintRightOperand(current);
1941       } else if (opcode == 0x6F) {
1942         AppendToBuffer("movdqa %s,", NameOfXMMRegister(regop));
1943         current += PrintRightXMMOperand(current);
1944       } else if (opcode == 0x7E) {
1945         AppendToBuffer("mov%c ", rex_w() ? 'q' : 'd');
1946         current += PrintRightOperand(current);
1947         AppendToBuffer(",%s", NameOfXMMRegister(regop));
1948       } else if (opcode == 0x7F) {
1949         AppendToBuffer("movdqa ");
1950         current += PrintRightXMMOperand(current);
1951         AppendToBuffer(",%s", NameOfXMMRegister(regop));
1952       } else if (opcode == 0xD6) {
1953         AppendToBuffer("movq ");
1954         current += PrintRightXMMOperand(current);
1955         AppendToBuffer(",%s", NameOfXMMRegister(regop));
1956       } else if (opcode == 0x50) {
1957         AppendToBuffer("movmskpd %s,", NameOfCPURegister(regop));
1958         current += PrintRightXMMOperand(current);
1959       } else if (opcode == 0x70) {
1960         AppendToBuffer("pshufd %s,", NameOfXMMRegister(regop));
1961         current += PrintRightXMMOperand(current);
1962         AppendToBuffer(",0x%x", *current);
1963         current += 1;
1964       } else if (opcode == 0x71) {
1965         current += 1;
1966         AppendToBuffer("ps%sw %s,%d", sf_str[regop / 2], NameOfXMMRegister(rm),
1967                        *current & 0x7F);
1968         current += 1;
1969       } else if (opcode == 0x72) {
1970         current += 1;
1971         AppendToBuffer("ps%sd %s,%d", sf_str[regop / 2], NameOfXMMRegister(rm),
1972                        *current & 0x7F);
1973         current += 1;
1974       } else if (opcode == 0x73) {
1975         current += 1;
1976         AppendToBuffer("ps%sq %s,%d", sf_str[regop / 2], NameOfXMMRegister(rm),
1977                        *current & 0x7F);
1978         current += 1;
1979       } else if (opcode == 0xB1) {
1980         current += PrintOperands("cmpxchg", OPER_REG_OP_ORDER, current);
1981       } else if (opcode == 0xC4) {
1982         AppendToBuffer("pinsrw %s,", NameOfXMMRegister(regop));
1983         current += PrintRightOperand(current);
1984         AppendToBuffer(",0x%x", (*current) & 7);
1985         current += 1;
1986       } else {
1987         const char* mnemonic;
1988         if (opcode == 0x51) {
1989           mnemonic = "sqrtpd";
1990         } else if (opcode == 0x54) {
1991           mnemonic = "andpd";
1992         } else if (opcode == 0x55) {
1993           mnemonic = "andnpd";
1994         } else if (opcode == 0x56) {
1995           mnemonic = "orpd";
1996         } else if (opcode == 0x57) {
1997           mnemonic = "xorpd";
1998         } else if (opcode == 0x58) {
1999           mnemonic = "addpd";
2000         } else if (opcode == 0x59) {
2001           mnemonic = "mulpd";
2002         } else if (opcode == 0x5B) {
2003           mnemonic = "cvtps2dq";
2004         } else if (opcode == 0x5C) {
2005           mnemonic = "subpd";
2006         } else if (opcode == 0x5D) {
2007           mnemonic = "minpd";
2008         } else if (opcode == 0x5E) {
2009           mnemonic = "divpd";
2010         } else if (opcode == 0x5F) {
2011           mnemonic = "maxpd";
2012         } else if (opcode == 0x60) {
2013           mnemonic = "punpcklbw";
2014         } else if (opcode == 0x61) {
2015           mnemonic = "punpcklwd";
2016         } else if (opcode == 0x62) {
2017           mnemonic = "punpckldq";
2018         } else if (opcode == 0x63) {
2019           mnemonic = "packsswb";
2020         } else if (opcode == 0x64) {
2021           mnemonic = "pcmpgtb";
2022         } else if (opcode == 0x65) {
2023           mnemonic = "pcmpgtw";
2024         } else if (opcode == 0x66) {
2025           mnemonic = "pcmpgtd";
2026         } else if (opcode == 0x67) {
2027           mnemonic = "packuswb";
2028         } else if (opcode == 0x68) {
2029           mnemonic = "punpckhbw";
2030         } else if (opcode == 0x69) {
2031           mnemonic = "punpckhwd";
2032         } else if (opcode == 0x6A) {
2033           mnemonic = "punpckhdq";
2034         } else if (opcode == 0x6B) {
2035           mnemonic = "packssdw";
2036         } else if (opcode == 0x6C) {
2037           mnemonic = "punpcklqdq";
2038         } else if (opcode == 0x6D) {
2039           mnemonic = "punpckhqdq";
2040         } else if (opcode == 0x2E) {
2041           mnemonic = "ucomisd";
2042         } else if (opcode == 0x2F) {
2043           mnemonic = "comisd";
2044         } else if (opcode == 0x74) {
2045           mnemonic = "pcmpeqb";
2046         } else if (opcode == 0x75) {
2047           mnemonic = "pcmpeqw";
2048         } else if (opcode == 0x76) {
2049           mnemonic = "pcmpeqd";
2050         } else if (opcode == 0xC2) {
2051           mnemonic = "cmppd";
2052         } else if (opcode == 0xD1) {
2053           mnemonic = "psrlw";
2054         } else if (opcode == 0xD2) {
2055           mnemonic = "psrld";
2056         } else if (opcode == 0xD3) {
2057           mnemonic = "psrlq";
2058         } else if (opcode == 0xD4) {
2059           mnemonic = "paddq";
2060         } else if (opcode == 0xD5) {
2061           mnemonic = "pmullw";
2062         } else if (opcode == 0xD7) {
2063           mnemonic = "pmovmskb";
2064         } else if (opcode == 0xD8) {
2065           mnemonic = "psubusb";
2066         } else if (opcode == 0xD9) {
2067           mnemonic = "psubusw";
2068         } else if (opcode == 0xDA) {
2069           mnemonic = "pminub";
2070         } else if (opcode == 0xDB) {
2071           mnemonic = "pand";
2072         } else if (opcode == 0xDC) {
2073           mnemonic = "paddusb";
2074         } else if (opcode == 0xDD) {
2075           mnemonic = "paddusw";
2076         } else if (opcode == 0xDE) {
2077           mnemonic = "pmaxub";
2078         } else if (opcode == 0xE0) {
2079           mnemonic = "pavgb";
2080         } else if (opcode == 0xE1) {
2081           mnemonic = "psraw";
2082         } else if (opcode == 0xE2) {
2083           mnemonic = "psrad";
2084         } else if (opcode == 0xE3) {
2085           mnemonic = "pavgw";
2086         } else if (opcode == 0xE8) {
2087           mnemonic = "psubsb";
2088         } else if (opcode == 0xE9) {
2089           mnemonic = "psubsw";
2090         } else if (opcode == 0xEA) {
2091           mnemonic = "pminsw";
2092         } else if (opcode == 0xEB) {
2093           mnemonic = "por";
2094         } else if (opcode == 0xEC) {
2095           mnemonic = "paddsb";
2096         } else if (opcode == 0xED) {
2097           mnemonic = "paddsw";
2098         } else if (opcode == 0xEE) {
2099           mnemonic = "pmaxsw";
2100         } else if (opcode == 0xEF) {
2101           mnemonic = "pxor";
2102         } else if (opcode == 0xF1) {
2103           mnemonic = "psllw";
2104         } else if (opcode == 0xF2) {
2105           mnemonic = "pslld";
2106         } else if (opcode == 0xF3) {
2107           mnemonic = "psllq";
2108         } else if (opcode == 0xF4) {
2109           mnemonic = "pmuludq";
2110         } else if (opcode == 0xF8) {
2111           mnemonic = "psubb";
2112         } else if (opcode == 0xF9) {
2113           mnemonic = "psubw";
2114         } else if (opcode == 0xFA) {
2115           mnemonic = "psubd";
2116         } else if (opcode == 0xFB) {
2117           mnemonic = "psubq";
2118         } else if (opcode == 0xFC) {
2119           mnemonic = "paddb";
2120         } else if (opcode == 0xFD) {
2121           mnemonic = "paddw";
2122         } else if (opcode == 0xFE) {
2123           mnemonic = "paddd";
2124         } else {
2125           UnimplementedInstruction();
2126         }
2127         AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
2128         current += PrintRightXMMOperand(current);
2129         if (opcode == 0xC2) {
2130           const char* const pseudo_op[] = {"eq",  "lt",  "le",  "unord",
2131                                            "neq", "nlt", "nle", "ord"};
2132           AppendToBuffer(", (%s)", pseudo_op[*current]);
2133           current += 1;
2134         }
2135       }
2136     }
2137   } else if (group_1_prefix_ == 0xF2) {
2138     // Beginning of instructions with prefix 0xF2.
2139 
2140     if (opcode == 0x11 || opcode == 0x10) {
2141       // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
2142       AppendToBuffer("movsd ");
2143       int mod, regop, rm;
2144       get_modrm(*current, &mod, &regop, &rm);
2145       if (opcode == 0x11) {
2146         current += PrintRightXMMOperand(current);
2147         AppendToBuffer(",%s", NameOfXMMRegister(regop));
2148       } else {
2149         AppendToBuffer("%s,", NameOfXMMRegister(regop));
2150         current += PrintRightXMMOperand(current);
2151       }
2152     } else if (opcode == 0x12) {
2153       int mod, regop, rm;
2154       get_modrm(*current, &mod, &regop, &rm);
2155       AppendToBuffer("movddup %s,", NameOfXMMRegister(regop));
2156       current += PrintRightXMMOperand(current);
2157     } else if (opcode == 0x2A) {
2158       // CVTSI2SD: integer to XMM double conversion.
2159       int mod, regop, rm;
2160       get_modrm(*current, &mod, &regop, &rm);
2161       AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
2162       current += PrintRightOperand(current);
2163     } else if (opcode == 0x2C) {
2164       // CVTTSD2SI:
2165       // Convert with truncation scalar double-precision FP to integer.
2166       int mod, regop, rm;
2167       get_modrm(*current, &mod, &regop, &rm);
2168       AppendToBuffer("cvttsd2si%c %s,", operand_size_code(),
2169                      NameOfCPURegister(regop));
2170       current += PrintRightXMMOperand(current);
2171     } else if (opcode == 0x2D) {
2172       // CVTSD2SI: Convert scalar double-precision FP to integer.
2173       int mod, regop, rm;
2174       get_modrm(*current, &mod, &regop, &rm);
2175       AppendToBuffer("cvtsd2si%c %s,", operand_size_code(),
2176                      NameOfCPURegister(regop));
2177       current += PrintRightXMMOperand(current);
2178     } else if (opcode == 0x5B) {
2179       // CVTTPS2DQ: Convert packed single-precision FP values to packed signed
2180       // doubleword integer values
2181       int mod, regop, rm;
2182       get_modrm(*current, &mod, &regop, &rm);
2183       AppendToBuffer("cvttps2dq%c %s,", operand_size_code(),
2184                      NameOfCPURegister(regop));
2185       current += PrintRightXMMOperand(current);
2186     } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
2187       // XMM arithmetic. Mnemonic was retrieved at the start of this function.
2188       int mod, regop, rm;
2189       get_modrm(*current, &mod, &regop, &rm);
2190       AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
2191       current += PrintRightXMMOperand(current);
2192     } else if (opcode == 0x70) {
2193       int mod, regop, rm;
2194       get_modrm(*current, &mod, &regop, &rm);
2195       AppendToBuffer("pshuflw %s, ", NameOfXMMRegister(regop));
2196       current += PrintRightXMMOperand(current);
2197       AppendToBuffer(", %d", (*current) & 7);
2198       current += 1;
2199     } else if (opcode == 0xC2) {
2200       // Intel manual 2A, Table 3-18.
2201       int mod, regop, rm;
2202       get_modrm(*current, &mod, &regop, &rm);
2203       const char* const pseudo_op[] = {"cmpeqsd",    "cmpltsd",  "cmplesd",
2204                                        "cmpunordsd", "cmpneqsd", "cmpnltsd",
2205                                        "cmpnlesd",   "cmpordsd"};
2206       AppendToBuffer("%s %s,%s", pseudo_op[current[1]],
2207                      NameOfXMMRegister(regop), NameOfXMMRegister(rm));
2208       current += 2;
2209     } else if (opcode == 0xF0) {
2210       int mod, regop, rm;
2211       get_modrm(*current, &mod, &regop, &rm);
2212       AppendToBuffer("lddqu %s,", NameOfXMMRegister(regop));
2213       current += PrintRightOperand(current);
2214     } else if (opcode == 0x7C) {
2215       int mod, regop, rm;
2216       get_modrm(*current, &mod, &regop, &rm);
2217       AppendToBuffer("haddps %s,", NameOfXMMRegister(regop));
2218       current += PrintRightXMMOperand(current);
2219     } else {
2220       UnimplementedInstruction();
2221     }
2222   } else if (group_1_prefix_ == 0xF3) {
2223     // Instructions with prefix 0xF3.
2224     if (opcode == 0x11 || opcode == 0x10) {
2225       // MOVSS: Move scalar double-precision fp to/from/between XMM registers.
2226       AppendToBuffer("movss ");
2227       int mod, regop, rm;
2228       get_modrm(*current, &mod, &regop, &rm);
2229       if (opcode == 0x11) {
2230         current += PrintRightOperand(current);
2231         AppendToBuffer(",%s", NameOfXMMRegister(regop));
2232       } else {
2233         AppendToBuffer("%s,", NameOfXMMRegister(regop));
2234         current += PrintRightOperand(current);
2235       }
2236     } else if (opcode == 0x2A) {
2237       // CVTSI2SS: integer to XMM single conversion.
2238       int mod, regop, rm;
2239       get_modrm(*current, &mod, &regop, &rm);
2240       AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
2241       current += PrintRightOperand(current);
2242     } else if (opcode == 0x2C) {
2243       // CVTTSS2SI:
2244       // Convert with truncation scalar single-precision FP to dword integer.
2245       int mod, regop, rm;
2246       get_modrm(*current, &mod, &regop, &rm);
2247       AppendToBuffer("cvttss2si%c %s,", operand_size_code(),
2248                      NameOfCPURegister(regop));
2249       current += PrintRightXMMOperand(current);
2250     } else if (opcode == 0x70) {
2251       int mod, regop, rm;
2252       get_modrm(*current, &mod, &regop, &rm);
2253       AppendToBuffer("pshufhw %s, ", NameOfXMMRegister(regop));
2254       current += PrintRightXMMOperand(current);
2255       AppendToBuffer(", %d", (*current) & 7);
2256       current += 1;
2257     } else if (opcode == 0x6F) {
2258       int mod, regop, rm;
2259       get_modrm(*current, &mod, &regop, &rm);
2260       AppendToBuffer("movdqu %s,", NameOfXMMRegister(regop));
2261       current += PrintRightXMMOperand(current);
2262     } else if (opcode == 0x7E) {
2263       int mod, regop, rm;
2264       get_modrm(*current, &mod, &regop, &rm);
2265       AppendToBuffer("movq %s,", NameOfXMMRegister(regop));
2266       current += PrintRightXMMOperand(current);
2267     } else if (opcode == 0x7F) {
2268       int mod, regop, rm;
2269       get_modrm(*current, &mod, &regop, &rm);
2270       AppendToBuffer("movdqu ");
2271       current += PrintRightXMMOperand(current);
2272       AppendToBuffer(",%s", NameOfXMMRegister(regop));
2273     } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
2274       // XMM arithmetic. Mnemonic was retrieved at the start of this function.
2275       int mod, regop, rm;
2276       get_modrm(*current, &mod, &regop, &rm);
2277       AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
2278       current += PrintRightXMMOperand(current);
2279     } else if (opcode == 0xB8) {
2280       int mod, regop, rm;
2281       get_modrm(*current, &mod, &regop, &rm);
2282       AppendToBuffer("popcnt%c %s,", operand_size_code(),
2283                      NameOfCPURegister(regop));
2284       current += PrintRightOperand(current);
2285     } else if (opcode == 0xBC) {
2286       int mod, regop, rm;
2287       get_modrm(*current, &mod, &regop, &rm);
2288       AppendToBuffer("tzcnt%c %s,", operand_size_code(),
2289                      NameOfCPURegister(regop));
2290       current += PrintRightOperand(current);
2291     } else if (opcode == 0xBD) {
2292       int mod, regop, rm;
2293       get_modrm(*current, &mod, &regop, &rm);
2294       AppendToBuffer("lzcnt%c %s,", operand_size_code(),
2295                      NameOfCPURegister(regop));
2296       current += PrintRightOperand(current);
2297     } else if (opcode == 0xC2) {
2298       // Intel manual 2A, Table 3-18.
2299       int mod, regop, rm;
2300       get_modrm(*current, &mod, &regop, &rm);
2301       const char* const pseudo_op[] = {"cmpeqss",    "cmpltss",  "cmpless",
2302                                        "cmpunordss", "cmpneqss", "cmpnltss",
2303                                        "cmpnless",   "cmpordss"};
2304       AppendToBuffer("%s %s,%s", pseudo_op[current[1]],
2305                      NameOfXMMRegister(regop), NameOfXMMRegister(rm));
2306       current += 2;
2307     } else {
2308       UnimplementedInstruction();
2309     }
2310   } else if (opcode == 0x10 || opcode == 0x11) {
2311     // movups xmm, xmm/m128
2312     // movups xmm/m128, xmm
2313     int mod, regop, rm;
2314     get_modrm(*current, &mod, &regop, &rm);
2315     AppendToBuffer("movups ");
2316     if (opcode == 0x11) {
2317       current += PrintRightXMMOperand(current);
2318       AppendToBuffer(",%s", NameOfXMMRegister(regop));
2319     } else {
2320       AppendToBuffer("%s,", NameOfXMMRegister(regop));
2321       current += PrintRightXMMOperand(current);
2322     }
2323   } else if (opcode == 0x16) {
2324     // movlhps xmm1, xmm2
2325     int mod, regop, rm;
2326     get_modrm(*current, &mod, &regop, &rm);
2327     AppendToBuffer("movlhps %s,", NameOfXMMRegister(regop));
2328     current += PrintRightXMMOperand(current);
2329   } else if (opcode == 0x1F) {
2330     // NOP
2331     int mod, regop, rm;
2332     get_modrm(*current, &mod, &regop, &rm);
2333     current++;
2334     if (rm == 4) {  // SIB byte present.
2335       current++;
2336     }
2337     if (mod == 1) {  // Byte displacement.
2338       current += 1;
2339     } else if (mod == 2) {  // 32-bit displacement.
2340       current += 4;
2341     }  // else no immediate displacement.
2342     AppendToBuffer("nop");
2343 
2344   } else if (opcode == 0x28) {
2345     // movaps xmm, xmm/m128
2346     int mod, regop, rm;
2347     get_modrm(*current, &mod, &regop, &rm);
2348     AppendToBuffer("movaps %s,", NameOfXMMRegister(regop));
2349     current += PrintRightXMMOperand(current);
2350 
2351   } else if (opcode == 0x29) {
2352     // movaps xmm/m128, xmm
2353     int mod, regop, rm;
2354     get_modrm(*current, &mod, &regop, &rm);
2355     AppendToBuffer("movaps ");
2356     current += PrintRightXMMOperand(current);
2357     AppendToBuffer(",%s", NameOfXMMRegister(regop));
2358 
2359   } else if (opcode == 0x2E) {
2360     int mod, regop, rm;
2361     get_modrm(*current, &mod, &regop, &rm);
2362     AppendToBuffer("ucomiss %s,", NameOfXMMRegister(regop));
2363     current += PrintRightXMMOperand(current);
2364   } else if (opcode == 0xA2) {
2365     // CPUID
2366     AppendToBuffer("%s", mnemonic);
2367   } else if ((opcode & 0xF0) == 0x40) {
2368     // CMOVcc: conditional move.
2369     int condition = opcode & 0x0F;
2370     const InstructionDesc& idesc = cmov_instructions[condition];
2371     byte_size_operand_ = idesc.byte_size_operation;
2372     current += PrintOperands(idesc.mnem, idesc.op_order_, current);
2373 
2374   } else if (opcode >= 0x51 && opcode <= 0x5F) {
2375     const char* const pseudo_op[] = {
2376         "sqrtps",   "rsqrtps", "rcpps", "andps", "andnps",
2377         "orps",     "xorps",   "addps", "mulps", "cvtps2pd",
2378         "cvtdq2ps", "subps",   "minps", "divps", "maxps",
2379     };
2380     int mod, regop, rm;
2381     get_modrm(*current, &mod, &regop, &rm);
2382     AppendToBuffer("%s %s,", pseudo_op[opcode - 0x51],
2383                    NameOfXMMRegister(regop));
2384     current += PrintRightXMMOperand(current);
2385 
2386   } else if (opcode == 0xC0) {
2387     byte_size_operand_ = true;
2388     current += PrintOperands("xadd", OPER_REG_OP_ORDER, current);
2389   } else if (opcode == 0xC1) {
2390     current += PrintOperands("xadd", OPER_REG_OP_ORDER, current);
2391   } else if (opcode == 0xC2) {
2392     // cmpps xmm, xmm/m128, imm8
2393     int mod, regop, rm;
2394     get_modrm(*current, &mod, &regop, &rm);
2395     const char* const pseudo_op[] = {"eq",  "lt",  "le",  "unord",
2396                                      "neq", "nlt", "nle", "ord"};
2397     AppendToBuffer("cmpps %s, ", NameOfXMMRegister(regop));
2398     current += PrintRightXMMOperand(current);
2399     AppendToBuffer(", %s", pseudo_op[*current]);
2400     current += 1;
2401   } else if (opcode == 0xC6) {
2402     // shufps xmm, xmm/m128, imm8
2403     int mod, regop, rm;
2404     get_modrm(*current, &mod, &regop, &rm);
2405     AppendToBuffer("shufps %s, ", NameOfXMMRegister(regop));
2406     current += PrintRightXMMOperand(current);
2407     AppendToBuffer(", %d", (*current) & 3);
2408     current += 1;
2409   } else if (opcode >= 0xC8 && opcode <= 0xCF) {
2410     // bswap
2411     int reg = (opcode - 0xC8) | (rex_r() ? 8 : 0);
2412     AppendToBuffer("bswap%c %s", operand_size_code(), NameOfCPURegister(reg));
2413   } else if (opcode == 0x50) {
2414     // movmskps reg, xmm
2415     int mod, regop, rm;
2416     get_modrm(*current, &mod, &regop, &rm);
2417     AppendToBuffer("movmskps %s,", NameOfCPURegister(regop));
2418     current += PrintRightXMMOperand(current);
2419   } else if ((opcode & 0xF0) == 0x80) {
2420     // Jcc: Conditional jump (branch).
2421     current = data + JumpConditional(data);
2422 
2423   } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
2424              opcode == 0xB7 || opcode == 0xAF) {
2425     // Size-extending moves, IMUL.
2426     current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
2427   } else if ((opcode & 0xF0) == 0x90) {
2428     // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
2429     current = data + SetCC(data);
2430   } else if (opcode == 0xA3 || opcode == 0xA5 || opcode == 0xAB ||
2431              opcode == 0xAD) {
2432     // BT (bit test), SHLD, BTS (bit test and set),
2433     // SHRD (double-precision shift)
2434     AppendToBuffer("%s ", mnemonic);
2435     int mod, regop, rm;
2436     get_modrm(*current, &mod, &regop, &rm);
2437     current += PrintRightOperand(current);
2438     if (opcode == 0xAB) {
2439       AppendToBuffer(",%s", NameOfCPURegister(regop));
2440     } else {
2441       AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
2442     }
2443   } else if (opcode == 0xBA) {
2444     // BTS / BTR (bit test and set/reset) with immediate
2445     int mod, regop, rm;
2446     get_modrm(*current, &mod, &regop, &rm);
2447     mnemonic = regop == 5 ? "bts" : regop == 6 ? "btr" : "?";
2448     AppendToBuffer("%s ", mnemonic);
2449     current += PrintRightOperand(current);
2450     AppendToBuffer(",%d", *current++);
2451   } else if (opcode == 0xB8 || opcode == 0xBC || opcode == 0xBD) {
2452     // POPCNT, CTZ, CLZ.
2453     AppendToBuffer("%s%c ", mnemonic, operand_size_code());
2454     int mod, regop, rm;
2455     get_modrm(*current, &mod, &regop, &rm);
2456     AppendToBuffer("%s,", NameOfCPURegister(regop));
2457     current += PrintRightOperand(current);
2458   } else if (opcode == 0x0B) {
2459     AppendToBuffer("ud2");
2460   } else if (opcode == 0xB0 || opcode == 0xB1) {
2461     // CMPXCHG.
2462     if (opcode == 0xB0) {
2463       byte_size_operand_ = true;
2464     }
2465     current += PrintOperands(mnemonic, OPER_REG_OP_ORDER, current);
2466   } else if (opcode == 0xAE && (data[2] & 0xF8) == 0xF0) {
2467     AppendToBuffer("mfence");
2468     current = data + 3;
2469   } else if (opcode == 0xAE && (data[2] & 0xF8) == 0xE8) {
2470     AppendToBuffer("lfence");
2471     current = data + 3;
2472   } else {
2473     UnimplementedInstruction();
2474   }
2475   return static_cast<int>(current - data);
2476 }
2477 
2478 // Mnemonics for two-byte opcode instructions starting with 0x0F.
2479 // The argument is the second byte of the two-byte opcode.
2480 // Returns nullptr if the instruction is not handled here.
TwoByteMnemonic(byte opcode)2481 const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
2482   if (opcode >= 0xC8 && opcode <= 0xCF) return "bswap";
2483   switch (opcode) {
2484     case 0x1F:
2485       return "nop";
2486     case 0x2A:  // F2/F3 prefix.
2487       return (group_1_prefix_ == 0xF2) ? "cvtsi2sd" : "cvtsi2ss";
2488     case 0x51:  // F2/F3 prefix.
2489       return (group_1_prefix_ == 0xF2) ? "sqrtsd" : "sqrtss";
2490     case 0x58:  // F2/F3 prefix.
2491       return (group_1_prefix_ == 0xF2) ? "addsd" : "addss";
2492     case 0x59:  // F2/F3 prefix.
2493       return (group_1_prefix_ == 0xF2) ? "mulsd" : "mulss";
2494     case 0x5A:  // F2/F3 prefix.
2495       return (group_1_prefix_ == 0xF2) ? "cvtsd2ss" : "cvtss2sd";
2496     case 0x5B:  // F2/F3 prefix.
2497       return "cvttps2dq";
2498     case 0x5D:  // F2/F3 prefix.
2499       return (group_1_prefix_ == 0xF2) ? "minsd" : "minss";
2500     case 0x5C:  // F2/F3 prefix.
2501       return (group_1_prefix_ == 0xF2) ? "subsd" : "subss";
2502     case 0x5E:  // F2/F3 prefix.
2503       return (group_1_prefix_ == 0xF2) ? "divsd" : "divss";
2504     case 0x5F:  // F2/F3 prefix.
2505       return (group_1_prefix_ == 0xF2) ? "maxsd" : "maxss";
2506     case 0xA2:
2507       return "cpuid";
2508     case 0xA3:
2509       return "bt";
2510     case 0xA5:
2511       return "shld";
2512     case 0xAB:
2513       return "bts";
2514     case 0xAD:
2515       return "shrd";
2516     case 0xAF:
2517       return "imul";
2518     case 0xB0:
2519     case 0xB1:
2520       return "cmpxchg";
2521     case 0xB6:
2522       return "movzxb";
2523     case 0xB7:
2524       return "movzxw";
2525     case 0xBC:
2526       return "bsf";
2527     case 0xBD:
2528       return "bsr";
2529     case 0xBE:
2530       return "movsxb";
2531     case 0xBF:
2532       return "movsxw";
2533     default:
2534       return nullptr;
2535   }
2536 }
2537 
2538 // Disassembles the instruction at instr, and writes it into out_buffer.
InstructionDecode(v8::internal::Vector<char> out_buffer,byte * instr)2539 int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
2540                                        byte* instr) {
2541   tmp_buffer_pos_ = 0;  // starting to write as position 0
2542   byte* data = instr;
2543   bool processed = true;  // Will be set to false if the current instruction
2544                           // is not in 'instructions' table.
2545   byte current;
2546 
2547   // Scan for prefixes.
2548   while (true) {
2549     current = *data;
2550     if (current == OPERAND_SIZE_OVERRIDE_PREFIX) {  // Group 3 prefix.
2551       operand_size_ = current;
2552     } else if ((current & 0xF0) == 0x40) {  // REX prefix.
2553       setRex(current);
2554       if (rex_w()) AppendToBuffer("REX.W ");
2555     } else if ((current & 0xFE) == 0xF2) {  // Group 1 prefix (0xF2 or 0xF3).
2556       group_1_prefix_ = current;
2557     } else if (current == LOCK_PREFIX) {
2558       AppendToBuffer("lock ");
2559     } else if (current == VEX3_PREFIX) {
2560       vex_byte0_ = current;
2561       vex_byte1_ = *(data + 1);
2562       vex_byte2_ = *(data + 2);
2563       setRex(0x40 | (~(vex_byte1_ >> 5) & 7) | ((vex_byte2_ >> 4) & 8));
2564       data += 3;
2565       break;  // Vex is the last prefix.
2566     } else if (current == VEX2_PREFIX) {
2567       vex_byte0_ = current;
2568       vex_byte1_ = *(data + 1);
2569       setRex(0x40 | (~(vex_byte1_ >> 5) & 4));
2570       data += 2;
2571       break;  // Vex is the last prefix.
2572     } else {  // Not a prefix - an opcode.
2573       break;
2574     }
2575     data++;
2576   }
2577 
2578   // Decode AVX instructions.
2579   if (vex_byte0_ != 0) {
2580     processed = true;
2581     data += AVXInstruction(data);
2582   } else {
2583     const InstructionDesc& idesc = instruction_table_->Get(current);
2584     byte_size_operand_ = idesc.byte_size_operation;
2585     switch (idesc.type) {
2586       case ZERO_OPERANDS_INSTR:
2587         if ((current >= 0xA4 && current <= 0xA7) ||
2588             (current >= 0xAA && current <= 0xAD)) {
2589           // String move or compare operations.
2590           if (group_1_prefix_ == REP_PREFIX) {
2591             // REP.
2592             AppendToBuffer("rep ");
2593           }
2594           AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
2595         } else {
2596           AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
2597         }
2598         data++;
2599         break;
2600 
2601       case TWO_OPERANDS_INSTR:
2602         data++;
2603         data += PrintOperands(idesc.mnem, idesc.op_order_, data);
2604         break;
2605 
2606       case JUMP_CONDITIONAL_SHORT_INSTR:
2607         data += JumpConditionalShort(data);
2608         break;
2609 
2610       case REGISTER_INSTR:
2611         AppendToBuffer("%s%c %s", idesc.mnem, operand_size_code(),
2612                        NameOfCPURegister(base_reg(current & 0x07)));
2613         data++;
2614         break;
2615       case PUSHPOP_INSTR:
2616         AppendToBuffer("%s %s", idesc.mnem,
2617                        NameOfCPURegister(base_reg(current & 0x07)));
2618         data++;
2619         break;
2620       case MOVE_REG_INSTR: {
2621         byte* addr = nullptr;
2622         switch (operand_size()) {
2623           case OPERAND_WORD_SIZE:
2624             addr = reinterpret_cast<byte*>(Imm16(data + 1));
2625             data += 3;
2626             break;
2627           case OPERAND_DOUBLEWORD_SIZE:
2628             addr = reinterpret_cast<byte*>(Imm32_U(data + 1));
2629             data += 5;
2630             break;
2631           case OPERAND_QUADWORD_SIZE:
2632             addr = reinterpret_cast<byte*>(Imm64(data + 1));
2633             data += 9;
2634             break;
2635           default:
2636             UNREACHABLE();
2637         }
2638         AppendToBuffer("mov%c %s,%s", operand_size_code(),
2639                        NameOfCPURegister(base_reg(current & 0x07)),
2640                        NameOfAddress(addr));
2641         break;
2642       }
2643 
2644       case CALL_JUMP_INSTR: {
2645         byte* addr = data + Imm32(data + 1) + 5;
2646         AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
2647         data += 5;
2648         break;
2649       }
2650 
2651       case SHORT_IMMEDIATE_INSTR: {
2652         int32_t imm;
2653         if (operand_size() == OPERAND_WORD_SIZE) {
2654           imm = Imm16(data + 1);
2655           data += 3;
2656         } else {
2657           imm = Imm32(data + 1);
2658           data += 5;
2659         }
2660         AppendToBuffer("%s rax,0x%x", idesc.mnem, imm);
2661         break;
2662       }
2663 
2664       case NO_INSTR:
2665         processed = false;
2666         break;
2667 
2668       default:
2669         UNIMPLEMENTED();  // This type is not implemented.
2670     }
2671   }
2672 
2673   // The first byte didn't match any of the simple opcodes, so we
2674   // need to do special processing on it.
2675   if (!processed) {
2676     switch (*data) {
2677       case 0xC2:
2678         AppendToBuffer("ret 0x%x", Imm16_U(data + 1));
2679         data += 3;
2680         break;
2681 
2682       case 0x69:  // fall through
2683       case 0x6B: {
2684         int count = 1;
2685         count += PrintOperands("imul", REG_OPER_OP_ORDER, data + count);
2686         AppendToBuffer(",0x");
2687         if (*data == 0x69) {
2688           count += PrintImmediate(data + count, operand_size());
2689         } else {
2690           count += PrintImmediate(data + count, OPERAND_BYTE_SIZE);
2691         }
2692         data += count;
2693         break;
2694       }
2695 
2696       case 0x81:  // fall through
2697       case 0x83:  // 0x81 with sign extension bit set
2698         data += PrintImmediateOp(data);
2699         break;
2700 
2701       case 0x0F:
2702         data += TwoByteOpcodeInstruction(data);
2703         break;
2704 
2705       case 0x8F: {
2706         data++;
2707         int mod, regop, rm;
2708         get_modrm(*data, &mod, &regop, &rm);
2709         if (regop == 0) {
2710           AppendToBuffer("pop ");
2711           data += PrintRightOperand(data);
2712         }
2713       } break;
2714 
2715       case 0xFF: {
2716         data++;
2717         int mod, regop, rm;
2718         get_modrm(*data, &mod, &regop, &rm);
2719         const char* mnem = nullptr;
2720         switch (regop) {
2721           case 0:
2722             mnem = "inc";
2723             break;
2724           case 1:
2725             mnem = "dec";
2726             break;
2727           case 2:
2728             mnem = "call";
2729             break;
2730           case 4:
2731             mnem = "jmp";
2732             break;
2733           case 6:
2734             mnem = "push";
2735             break;
2736           default:
2737             mnem = "???";
2738         }
2739         if (regop <= 1) {
2740           AppendToBuffer("%s%c ", mnem, operand_size_code());
2741         } else {
2742           AppendToBuffer("%s ", mnem);
2743         }
2744         data += PrintRightOperand(data);
2745       } break;
2746 
2747       case 0xC7:  // imm32, fall through
2748       case 0xC6:  // imm8
2749       {
2750         bool is_byte = *data == 0xC6;
2751         data++;
2752         if (is_byte) {
2753           AppendToBuffer("movb ");
2754           data += PrintRightByteOperand(data);
2755           int32_t imm = *data;
2756           AppendToBuffer(",0x%x", imm);
2757           data++;
2758         } else {
2759           AppendToBuffer("mov%c ", operand_size_code());
2760           data += PrintRightOperand(data);
2761           if (operand_size() == OPERAND_WORD_SIZE) {
2762             AppendToBuffer(",0x%x", Imm16(data));
2763             data += 2;
2764           } else {
2765             AppendToBuffer(",0x%x", Imm32(data));
2766             data += 4;
2767           }
2768         }
2769       } break;
2770 
2771       case 0x80: {
2772         data++;
2773         AppendToBuffer("cmpb ");
2774         data += PrintRightByteOperand(data);
2775         int32_t imm = *data;
2776         AppendToBuffer(",0x%x", imm);
2777         data++;
2778       } break;
2779 
2780       case 0x88:  // 8bit, fall through
2781       case 0x89:  // 32bit
2782       {
2783         bool is_byte = *data == 0x88;
2784         int mod, regop, rm;
2785         data++;
2786         get_modrm(*data, &mod, &regop, &rm);
2787         if (is_byte) {
2788           AppendToBuffer("movb ");
2789           data += PrintRightByteOperand(data);
2790           AppendToBuffer(",%s", NameOfByteCPURegister(regop));
2791         } else {
2792           AppendToBuffer("mov%c ", operand_size_code());
2793           data += PrintRightOperand(data);
2794           AppendToBuffer(",%s", NameOfCPURegister(regop));
2795         }
2796       } break;
2797 
2798       case 0x90:
2799       case 0x91:
2800       case 0x92:
2801       case 0x93:
2802       case 0x94:
2803       case 0x95:
2804       case 0x96:
2805       case 0x97: {
2806         int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
2807         if (group_1_prefix_ == 0xF3 && *data == 0x90) {
2808           AppendToBuffer("pause");
2809         } else if (reg == 0) {
2810           AppendToBuffer("nop");  // Common name for xchg rax,rax.
2811         } else {
2812           AppendToBuffer("xchg%c rax,%s", operand_size_code(),
2813                          NameOfCPURegister(reg));
2814         }
2815         data++;
2816       } break;
2817       case 0xB0:
2818       case 0xB1:
2819       case 0xB2:
2820       case 0xB3:
2821       case 0xB4:
2822       case 0xB5:
2823       case 0xB6:
2824       case 0xB7:
2825       case 0xB8:
2826       case 0xB9:
2827       case 0xBA:
2828       case 0xBB:
2829       case 0xBC:
2830       case 0xBD:
2831       case 0xBE:
2832       case 0xBF: {
2833         // mov reg8,imm8 or mov reg32,imm32
2834         byte opcode = *data;
2835         data++;
2836         bool is_32bit = (opcode >= 0xB8);
2837         int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
2838         if (is_32bit) {
2839           AppendToBuffer("mov%c %s,", operand_size_code(),
2840                          NameOfCPURegister(reg));
2841           data += PrintImmediate(data, OPERAND_DOUBLEWORD_SIZE);
2842         } else {
2843           AppendToBuffer("movb %s,", NameOfByteCPURegister(reg));
2844           data += PrintImmediate(data, OPERAND_BYTE_SIZE);
2845         }
2846         break;
2847       }
2848       case 0xFE: {
2849         data++;
2850         int mod, regop, rm;
2851         get_modrm(*data, &mod, &regop, &rm);
2852         if (regop == 1) {
2853           AppendToBuffer("decb ");
2854           data += PrintRightByteOperand(data);
2855         } else {
2856           UnimplementedInstruction();
2857         }
2858         break;
2859       }
2860       case 0x68:
2861         AppendToBuffer("push 0x%x", Imm32(data + 1));
2862         data += 5;
2863         break;
2864 
2865       case 0x6A:
2866         AppendToBuffer("push 0x%x", Imm8(data + 1));
2867         data += 2;
2868         break;
2869 
2870       case 0xA1:  // Fall through.
2871       case 0xA3:
2872         switch (operand_size()) {
2873           case OPERAND_DOUBLEWORD_SIZE: {
2874             const char* memory_location =
2875                 NameOfAddress(reinterpret_cast<byte*>(Imm32(data + 1)));
2876             if (*data == 0xA1) {  // Opcode 0xA1
2877               AppendToBuffer("movzxlq rax,(%s)", memory_location);
2878             } else {  // Opcode 0xA3
2879               AppendToBuffer("movzxlq (%s),rax", memory_location);
2880             }
2881             data += 5;
2882             break;
2883           }
2884           case OPERAND_QUADWORD_SIZE: {
2885             // New x64 instruction mov rax,(imm_64).
2886             const char* memory_location =
2887                 NameOfAddress(reinterpret_cast<byte*>(Imm64(data + 1)));
2888             if (*data == 0xA1) {  // Opcode 0xA1
2889               AppendToBuffer("movq rax,(%s)", memory_location);
2890             } else {  // Opcode 0xA3
2891               AppendToBuffer("movq (%s),rax", memory_location);
2892             }
2893             data += 9;
2894             break;
2895           }
2896           default:
2897             UnimplementedInstruction();
2898             data += 2;
2899         }
2900         break;
2901 
2902       case 0xA8:
2903         AppendToBuffer("test al,0x%x", Imm8_U(data + 1));
2904         data += 2;
2905         break;
2906 
2907       case 0xA9: {
2908         int64_t value = 0;
2909         switch (operand_size()) {
2910           case OPERAND_WORD_SIZE:
2911             value = Imm16_U(data + 1);
2912             data += 3;
2913             break;
2914           case OPERAND_DOUBLEWORD_SIZE:
2915             value = Imm32_U(data + 1);
2916             data += 5;
2917             break;
2918           case OPERAND_QUADWORD_SIZE:
2919             value = Imm32(data + 1);
2920             data += 5;
2921             break;
2922           default:
2923             UNREACHABLE();
2924         }
2925         AppendToBuffer("test%c rax,0x%" PRIx64, operand_size_code(), value);
2926         break;
2927       }
2928       case 0xD1:  // fall through
2929       case 0xD3:  // fall through
2930       case 0xC1:
2931         data += ShiftInstruction(data);
2932         break;
2933       case 0xD0:  // fall through
2934       case 0xD2:  // fall through
2935       case 0xC0:
2936         byte_size_operand_ = true;
2937         data += ShiftInstruction(data);
2938         break;
2939 
2940       case 0xD9:  // fall through
2941       case 0xDA:  // fall through
2942       case 0xDB:  // fall through
2943       case 0xDC:  // fall through
2944       case 0xDD:  // fall through
2945       case 0xDE:  // fall through
2946       case 0xDF:
2947         data += FPUInstruction(data);
2948         break;
2949 
2950       case 0xEB:
2951         data += JumpShort(data);
2952         break;
2953 
2954       case 0xF6:
2955         byte_size_operand_ = true;
2956         V8_FALLTHROUGH;
2957       case 0xF7:
2958         data += F6F7Instruction(data);
2959         break;
2960 
2961       case 0x3C:
2962         AppendToBuffer("cmp al,0x%x", Imm8(data + 1));
2963         data += 2;
2964         break;
2965 
2966       default:
2967         UnimplementedInstruction();
2968         data += 1;
2969     }
2970   }  // !processed
2971 
2972   if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
2973     tmp_buffer_[tmp_buffer_pos_] = '\0';
2974   }
2975 
2976   int instr_len = static_cast<int>(data - instr);
2977   DCHECK_GT(instr_len, 0);  // Ensure progress.
2978 
2979   int outp = 0;
2980   // Instruction bytes.
2981   for (byte* bp = instr; bp < data; bp++) {
2982     outp += v8::internal::SNPrintF(out_buffer + outp, "%02x", *bp);
2983   }
2984   for (int i = 6 - instr_len; i >= 0; i--) {
2985     outp += v8::internal::SNPrintF(out_buffer + outp, "  ");
2986   }
2987 
2988   outp += v8::internal::SNPrintF(out_buffer + outp, " %s", tmp_buffer_.begin());
2989   return instr_len;
2990 }
2991 
2992 //------------------------------------------------------------------------------
2993 
2994 static const char* const cpu_regs[16] = {
2995     "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
2996     "r8",  "r9",  "r10", "r11", "r12", "r13", "r14", "r15"};
2997 
2998 static const char* const byte_cpu_regs[16] = {
2999     "al",  "cl",  "dl",   "bl",   "spl",  "bpl",  "sil",  "dil",
3000     "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"};
3001 
3002 static const char* const xmm_regs[16] = {
3003     "xmm0", "xmm1", "xmm2",  "xmm3",  "xmm4",  "xmm5",  "xmm6",  "xmm7",
3004     "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"};
3005 
NameOfAddress(byte * addr) const3006 const char* NameConverter::NameOfAddress(byte* addr) const {
3007   v8::internal::SNPrintF(tmp_buffer_, "%p", static_cast<void*>(addr));
3008   return tmp_buffer_.begin();
3009 }
3010 
NameOfConstant(byte * addr) const3011 const char* NameConverter::NameOfConstant(byte* addr) const {
3012   return NameOfAddress(addr);
3013 }
3014 
NameOfCPURegister(int reg) const3015 const char* NameConverter::NameOfCPURegister(int reg) const {
3016   if (0 <= reg && reg < 16) return cpu_regs[reg];
3017   return "noreg";
3018 }
3019 
NameOfByteCPURegister(int reg) const3020 const char* NameConverter::NameOfByteCPURegister(int reg) const {
3021   if (0 <= reg && reg < 16) return byte_cpu_regs[reg];
3022   return "noreg";
3023 }
3024 
NameOfXMMRegister(int reg) const3025 const char* NameConverter::NameOfXMMRegister(int reg) const {
3026   if (0 <= reg && reg < 16) return xmm_regs[reg];
3027   return "noxmmreg";
3028 }
3029 
NameInCode(byte * addr) const3030 const char* NameConverter::NameInCode(byte* addr) const {
3031   // X64 does not embed debug strings at the moment.
3032   UNREACHABLE();
3033 }
3034 
3035 //------------------------------------------------------------------------------
3036 
InstructionDecode(v8::internal::Vector<char> buffer,byte * instruction)3037 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
3038                                     byte* instruction) {
3039   DisassemblerX64 d(converter_, unimplemented_opcode_action());
3040   return d.InstructionDecode(buffer, instruction);
3041 }
3042 
3043 // The X64 assembler does not use constant pools.
ConstantPoolSizeAt(byte * instruction)3044 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; }
3045 
Disassemble(FILE * f,byte * begin,byte * end,UnimplementedOpcodeAction unimplemented_action)3046 void Disassembler::Disassemble(FILE* f, byte* begin, byte* end,
3047                                UnimplementedOpcodeAction unimplemented_action) {
3048   NameConverter converter;
3049   Disassembler d(converter, unimplemented_action);
3050   for (byte* pc = begin; pc < end;) {
3051     v8::internal::EmbeddedVector<char, 128> buffer;
3052     buffer[0] = '\0';
3053     byte* prev_pc = pc;
3054     pc += d.InstructionDecode(buffer, pc);
3055     fprintf(f, "%p", static_cast<void*>(prev_pc));
3056     fprintf(f, "    ");
3057 
3058     for (byte* bp = prev_pc; bp < pc; bp++) {
3059       fprintf(f, "%02x", *bp);
3060     }
3061     for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) {
3062       fprintf(f, "  ");
3063     }
3064     fprintf(f, "  %s\n", buffer.begin());
3065   }
3066 }
3067 
3068 }  // namespace disasm
3069 
3070 #endif  // V8_TARGET_ARCH_X64
3071