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