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