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