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