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