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