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