Flutter Engine
The Flutter Engine
disassembler_x86.cc
Go to the documentation of this file.
1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5// A combined disassembler for IA32 and X64.
6
7#include "vm/globals.h" // Needed here to get TARGET_ARCH_xxx.
8#if defined(TARGET_ARCH_X64) || defined(TARGET_ARCH_IA32)
9
11
12#include "platform/unaligned.h"
13#include "platform/utils.h"
14#include "vm/allocation.h"
15#include "vm/constants_x86.h"
16#include "vm/heap/heap.h"
17#include "vm/instructions.h"
18#include "vm/os.h"
19#include "vm/stack_frame.h"
20#include "vm/stub_code.h"
21
22namespace dart {
23
24#if !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
25
26enum OperandType {
27 UNSET_OP_ORDER = 0,
28 // Operand size decides between 16, 32 and 64 bit operands.
29 REG_OPER_OP_ORDER = 1, // Register destination, operand source.
30 OPER_REG_OP_ORDER = 2, // Operand destination, register source.
31 // Fixed 8-bit operands.
32 BYTE_SIZE_OPERAND_FLAG = 4,
33 BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG,
34 BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
35};
36
37//------------------------------------------------------------------
38// Tables
39//------------------------------------------------------------------
40struct ByteMnemonic {
41 int b; // -1 terminates, otherwise must be in range (0..255)
42 OperandType op_order_;
43 const char* mnem;
44};
45
46#define ALU_ENTRY(name, code) \
47 {code * 8 + 0, BYTE_OPER_REG_OP_ORDER, #name}, \
48 {code * 8 + 1, OPER_REG_OP_ORDER, #name}, \
49 {code * 8 + 2, BYTE_REG_OPER_OP_ORDER, #name}, \
50 {code * 8 + 3, REG_OPER_OP_ORDER, #name},
51static const ByteMnemonic two_operands_instr[] = {
52 X86_ALU_CODES(ALU_ENTRY){0x63, REG_OPER_OP_ORDER, "movsxd"},
53 {0x84, BYTE_REG_OPER_OP_ORDER, "test"},
54 {0x85, REG_OPER_OP_ORDER, "test"},
55 {0x86, BYTE_REG_OPER_OP_ORDER, "xchg"},
56 {0x87, REG_OPER_OP_ORDER, "xchg"},
57 {0x88, BYTE_OPER_REG_OP_ORDER, "mov"},
58 {0x89, OPER_REG_OP_ORDER, "mov"},
59 {0x8A, BYTE_REG_OPER_OP_ORDER, "mov"},
60 {0x8B, REG_OPER_OP_ORDER, "mov"},
61 {0x8D, REG_OPER_OP_ORDER, "lea"},
62 {-1, UNSET_OP_ORDER, ""}};
63
64#define ZERO_OPERAND_ENTRY(name, opcode) {opcode, UNSET_OP_ORDER, #name},
65static const ByteMnemonic zero_operands_instr[] = {
66 X86_ZERO_OPERAND_1_BYTE_INSTRUCTIONS(ZERO_OPERAND_ENTRY){-1, UNSET_OP_ORDER,
67 ""}};
68
69static const ByteMnemonic call_jump_instr[] = {{0xE8, UNSET_OP_ORDER, "call"},
70 {0xE9, UNSET_OP_ORDER, "jmp"},
71 {-1, UNSET_OP_ORDER, ""}};
72
73#define SHORT_IMMEDIATE_ENTRY(name, code) {code * 8 + 5, UNSET_OP_ORDER, #name},
74static const ByteMnemonic short_immediate_instr[] = {
75 X86_ALU_CODES(SHORT_IMMEDIATE_ENTRY){-1, UNSET_OP_ORDER, ""}};
76
77static const char* const conditional_code_suffix[] = {
78#define STRINGIFY(name, number) #name,
80#undef STRINGIFY
81};
82
83#define STRINGIFY_NAME(name, code) #name,
84static const char* const xmm_conditional_code_suffix[] = {
85 XMM_CONDITIONAL_CODES(STRINGIFY_NAME)};
86#undef STRINGIFY_NAME
87
88enum InstructionType {
89 NO_INSTR,
90 ZERO_OPERANDS_INSTR,
91 TWO_OPERANDS_INSTR,
92 JUMP_CONDITIONAL_SHORT_INSTR,
93 REGISTER_INSTR,
94 PUSHPOP_INSTR, // Has implicit 64-bit operand size.
95 MOVE_REG_INSTR,
96 CALL_JUMP_INSTR,
97 SHORT_IMMEDIATE_INSTR
98};
99
100enum Prefixes {
101 ESCAPE_PREFIX = 0x0F,
102 OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
103 ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
104 REPNE_PREFIX = 0xF2,
105 REP_PREFIX = 0xF3,
106 REPEQ_PREFIX = REP_PREFIX
107};
108
109struct XmmMnemonic {
110 const char* ps_name;
111 const char* pd_name;
112 const char* ss_name;
113 const char* sd_name;
114};
115
116#define XMM_INSTRUCTION_ENTRY(name, code) \
117 {#name "ps", #name "pd", #name "ss", #name "sd"},
118static const XmmMnemonic xmm_instructions[] = {
119 XMM_ALU_CODES(XMM_INSTRUCTION_ENTRY)};
120
121struct InstructionDesc {
122 const char* mnem;
123 InstructionType type;
124 OperandType op_order_;
125 bool byte_size_operation; // Fixed 8-bit operation.
126};
127
128class InstructionTable : public ValueObject {
129 public:
130 InstructionTable();
131 const InstructionDesc& Get(uint8_t x) const { return instructions_[x]; }
132
133 private:
134 InstructionDesc instructions_[256];
135 void Clear();
136 void Init();
137 void CopyTable(const ByteMnemonic bm[], InstructionType type);
138 void SetTableRange(InstructionType type,
139 uint8_t start,
140 uint8_t end,
141 bool byte_size,
142 const char* mnem);
143 void AddJumpConditionalShort();
144
145 DISALLOW_COPY_AND_ASSIGN(InstructionTable);
146};
147
148InstructionTable::InstructionTable() {
149 Clear();
150 Init();
151}
152
153void InstructionTable::Clear() {
154 for (int i = 0; i < 256; i++) {
155 instructions_[i].mnem = "(bad)";
156 instructions_[i].type = NO_INSTR;
157 instructions_[i].op_order_ = UNSET_OP_ORDER;
158 instructions_[i].byte_size_operation = false;
159 }
160}
161
163 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
164 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
165 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
166 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
167 AddJumpConditionalShort();
168 SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push");
169 SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop");
170 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov");
171}
172
173void InstructionTable::CopyTable(const ByteMnemonic bm[],
174 InstructionType type) {
175 for (int i = 0; bm[i].b >= 0; i++) {
176 InstructionDesc* id = &instructions_[bm[i].b];
177 id->mnem = bm[i].mnem;
178 OperandType op_order = bm[i].op_order_;
179 id->op_order_ =
180 static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
181 ASSERT(NO_INSTR == id->type); // Information not already entered
182 id->type = type;
183 id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
184 }
185}
186
187void InstructionTable::SetTableRange(InstructionType type,
188 uint8_t start,
189 uint8_t end,
190 bool byte_size,
191 const char* mnem) {
192 for (uint8_t b = start; b <= end; b++) {
193 InstructionDesc* id = &instructions_[b];
194 ASSERT(NO_INSTR == id->type); // Information not already entered
195 id->mnem = mnem;
196 id->type = type;
197 id->byte_size_operation = byte_size;
198 }
199}
200
201void InstructionTable::AddJumpConditionalShort() {
202 for (uint8_t b = 0x70; b <= 0x7F; b++) {
203 InstructionDesc* id = &instructions_[b];
204 ASSERT(NO_INSTR == id->type); // Information not already entered
205 id->mnem = nullptr; // Computed depending on condition code.
206 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
207 }
208}
209
210static InstructionTable instruction_table;
211
212static const InstructionDesc cmov_instructions[16] = {
213 {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
214 {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
215 {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
216 {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
217 {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
218 {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
219 {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
220 {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
221 {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
222 {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
223 {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
224 {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
225 {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
226 {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
227 {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
228 {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}};
229
230//-------------------------------------------------
231// DisassemblerX64 implementation.
232
233static constexpr int kMaxXmmRegisters = 16;
234static const char* xmm_regs[kMaxXmmRegisters] = {
235 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
236 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"};
237
238class DisassemblerX64 : public ValueObject {
239 public:
240 DisassemblerX64(char* buffer, intptr_t buffer_size)
241 : buffer_(buffer),
242 buffer_size_(buffer_size),
243 buffer_pos_(0),
244 rex_(0),
245 operand_size_(0),
246 group_1_prefix_(0),
247 byte_size_operand_(false) {
248 buffer_[buffer_pos_] = '\0';
249 }
250
251 virtual ~DisassemblerX64() {}
252
253 int InstructionDecode(uword pc);
254
255 private:
256 enum OperandSize {
257 BYTE_SIZE = 0,
258 WORD_SIZE = 1,
259 DOUBLEWORD_SIZE = 2,
260 QUADWORD_SIZE = 3
261 };
262
263 void setRex(uint8_t rex) {
264 ASSERT(0x40 == (rex & 0xF0));
265 rex_ = rex;
266 }
267
268 bool rex() { return rex_ != 0; }
269
270 bool rex_b() { return (rex_ & 0x01) != 0; }
271
272 // Actual number of base register given the low bits and the rex.b state.
273 int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); }
274
275 bool rex_x() { return (rex_ & 0x02) != 0; }
276
277 bool rex_r() { return (rex_ & 0x04) != 0; }
278
279 bool rex_w() { return (rex_ & 0x08) != 0; }
280
281 OperandSize operand_size() {
282 if (byte_size_operand_) return BYTE_SIZE;
283 if (rex_w()) return QUADWORD_SIZE;
284 if (operand_size_ != 0) return WORD_SIZE;
285 return DOUBLEWORD_SIZE;
286 }
287
288 const char* operand_size_code() {
289#if defined(TARGET_ARCH_X64)
290 return &"b\0w\0l\0q\0"[2 * operand_size()];
291#else
292 // We omit the 'l' suffix on IA32.
293 return &"b\0w\0\0\0q\0"[2 * operand_size()];
294#endif
295 }
296
297 // Disassembler helper functions.
298 void get_modrm(uint8_t data, int* mod, int* regop, int* rm) {
299 *mod = (data >> 6) & 3;
300 *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0);
301 *rm = (data & 7) | (rex_b() ? 8 : 0);
303 }
304
305 void get_sib(uint8_t data, int* scale, int* index, int* base) {
306 *scale = (data >> 6) & 3;
307 *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
308 *base = (data & 7) | (rex_b() ? 8 : 0);
310 }
311
312 const char* NameOfCPURegister(int reg) const {
313 return RegisterNames::RegisterName(static_cast<Register>(reg));
314 }
315
316 const char* NameOfByteCPURegister(int reg) const {
317 return RegisterNames::RegisterByteName(static_cast<ByteRegister>(reg));
318 }
319
320 // A way to get rax or eax's name.
321 const char* Rax() const { return NameOfCPURegister(0); }
322
323 const char* NameOfXMMRegister(int reg) const {
324 ASSERT((0 <= reg) && (reg < kMaxXmmRegisters));
325 return xmm_regs[reg];
326 }
327
328 void Print(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
329 void PrintJump(uint8_t* pc, int32_t disp);
330 void PrintAddress(uint8_t* addr);
331
332 int PrintOperands(const char* mnem, OperandType op_order, uint8_t* data);
333
334 typedef const char* (DisassemblerX64::* RegisterNameMapping)(int reg) const;
335
336 int PrintRightOperandHelper(uint8_t* modrmp,
337 RegisterNameMapping register_name);
338 int PrintRightOperand(uint8_t* modrmp);
339 int PrintRightByteOperand(uint8_t* modrmp);
340 int PrintRightXMMOperand(uint8_t* modrmp);
341 void PrintDisp(int disp, const char* after);
342 int PrintImmediate(uint8_t* data, OperandSize size, bool sign_extend = false);
343 void PrintImmediateValue(int64_t value,
344 bool signed_value = false,
345 int byte_count = -1);
346 int PrintImmediateOp(uint8_t* data);
347 const char* TwoByteMnemonic(uint8_t opcode);
348 int TwoByteOpcodeInstruction(uint8_t* data);
349 int Print660F38Instruction(uint8_t* data);
350
351 int F6F7Instruction(uint8_t* data);
352 int ShiftInstruction(uint8_t* data);
353 int JumpShort(uint8_t* data);
354 int JumpConditional(uint8_t* data);
355 int JumpConditionalShort(uint8_t* data);
356 int SetCC(uint8_t* data);
357 int FPUInstruction(uint8_t* data);
358 int MemoryFPUInstruction(int escape_opcode, int regop, uint8_t* modrm_start);
359 int RegisterFPUInstruction(int escape_opcode, uint8_t modrm_byte);
360
361 bool DecodeInstructionType(uint8_t** data);
362
363 void UnimplementedInstruction(uint8_t byte);
364
365 char* buffer_; // Decode instructions into this buffer.
366 intptr_t buffer_size_; // The size of the buffer_.
367 intptr_t buffer_pos_; // Current character position in the buffer_.
368
369 // Prefixes parsed
370 uint8_t rex_;
371 uint8_t operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0.
372 // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
373 uint8_t group_1_prefix_;
374 // Byte size operand override.
375 bool byte_size_operand_;
376
377 DISALLOW_COPY_AND_ASSIGN(DisassemblerX64);
378};
379
380// Append the str to the output buffer.
381void DisassemblerX64::Print(const char* format, ...) {
382 intptr_t available = buffer_size_ - buffer_pos_;
383 if (available <= 1) {
384 ASSERT(buffer_[buffer_pos_] == '\0');
385 return;
386 }
387 char* buf = buffer_ + buffer_pos_;
388 va_list args;
390 int length = Utils::VSNPrint(buf, available, format, args);
391 va_end(args);
392 buffer_pos_ =
393 (length >= available) ? (buffer_size_ - 1) : (buffer_pos_ + length);
394 ASSERT(buffer_pos_ < buffer_size_);
395}
396
397int DisassemblerX64::PrintRightOperandHelper(
398 uint8_t* modrmp,
399 RegisterNameMapping direct_register_name) {
400 int mod, regop, rm;
401 get_modrm(*modrmp, &mod, &regop, &rm);
402 RegisterNameMapping register_name =
403 (mod == 3) ? direct_register_name : &DisassemblerX64::NameOfCPURegister;
404 switch (mod) {
405 case 0:
406 if ((rm & 7) == 5) {
407#if defined(TARGET_ARCH_IA32)
408 int32_t abs = LoadUnaligned(reinterpret_cast<int32_t*>(modrmp + 1));
409 Print("[0x%08x]", abs);
410#else
411 int32_t disp = LoadUnaligned(reinterpret_cast<int32_t*>(modrmp + 1));
412 Print("[rip");
413 PrintDisp(disp, "]");
414#endif
415 return 5;
416 } else if ((rm & 7) == 4) {
417 // Codes for SIB byte.
418 uint8_t sib = *(modrmp + 1);
419 int scale, index, base;
420 get_sib(sib, &scale, &index, &base);
421 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
422 // index == rsp means no index. Only use sib byte with no index for
423 // rsp and r12 base.
424 Print("[%s]", NameOfCPURegister(base));
425 return 2;
426 } else if (base == 5) {
427 // base == rbp means no base register (when mod == 0).
428 int32_t disp = LoadUnaligned(reinterpret_cast<int32_t*>(modrmp + 2));
429 Print("[%s*%d", NameOfCPURegister(index), 1 << scale);
430 PrintDisp(disp, "]");
431 return 6;
432 } else if (index != 4 && base != 5) {
433 // [base+index*scale]
434 Print("[%s+%s*%d]", NameOfCPURegister(base), NameOfCPURegister(index),
435 1 << scale);
436 return 2;
437 } else {
438 UnimplementedInstruction(*modrmp);
439 return 1;
440 }
441 } else {
442 Print("[%s]", NameOfCPURegister(rm));
443 return 1;
444 }
445 break;
446 case 1:
448 case 2:
449 if ((rm & 7) == 4) {
450 uint8_t sib = *(modrmp + 1);
451 int scale, index, base;
452 get_sib(sib, &scale, &index, &base);
453 int disp = (mod == 2)
454 ? LoadUnaligned(reinterpret_cast<int32_t*>(modrmp + 2))
455 : *reinterpret_cast<int8_t*>(modrmp + 2);
456 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
457 Print("[%s", NameOfCPURegister(base));
458 PrintDisp(disp, "]");
459 } else {
460 Print("[%s+%s*%d", NameOfCPURegister(base), NameOfCPURegister(index),
461 1 << scale);
462 PrintDisp(disp, "]");
463 }
464 return mod == 2 ? 6 : 3;
465 } else {
466 // No sib.
467 int disp = (mod == 2)
468 ? LoadUnaligned(reinterpret_cast<int32_t*>(modrmp + 1))
469 : *reinterpret_cast<int8_t*>(modrmp + 1);
470 Print("[%s", NameOfCPURegister(rm));
471 PrintDisp(disp, "]");
472 return (mod == 2) ? 5 : 2;
473 }
474 break;
475 case 3:
476 Print("%s", (this->*register_name)(rm));
477 return 1;
478 default:
479 UnimplementedInstruction(*modrmp);
480 return 1;
481 }
482 UNREACHABLE();
483}
484
485int DisassemblerX64::PrintImmediate(uint8_t* data,
487 bool sign_extend) {
488 int64_t value;
489 int count;
490 switch (size) {
491 case BYTE_SIZE:
492 if (sign_extend) {
493 value = *reinterpret_cast<int8_t*>(data);
494 } else {
495 value = *data;
496 }
497 count = 1;
498 break;
499 case WORD_SIZE:
500 if (sign_extend) {
501 value = LoadUnaligned(reinterpret_cast<int16_t*>(data));
502 } else {
503 value = LoadUnaligned(reinterpret_cast<uint16_t*>(data));
504 }
505 count = 2;
506 break;
507 case DOUBLEWORD_SIZE:
508 case QUADWORD_SIZE:
509 if (sign_extend) {
510 value = LoadUnaligned(reinterpret_cast<int32_t*>(data));
511 } else {
512 value = LoadUnaligned(reinterpret_cast<uint32_t*>(data));
513 }
514 count = 4;
515 break;
516 default:
517 UNREACHABLE();
518 value = 0; // Initialize variables on all paths to satisfy the compiler.
519 count = 0;
520 }
521 PrintImmediateValue(value, sign_extend, count);
522 return count;
523}
524
525void DisassemblerX64::PrintImmediateValue(int64_t value,
526 bool signed_value,
527 int byte_count) {
528 if ((value >= 0) && (value <= 9)) {
529 Print("%" Pd64, value);
530 } else if (signed_value && (value < 0) && (value >= -9)) {
531 Print("-%" Pd64, -value);
532 } else {
533 if (byte_count == 1) {
534 int8_t v8 = static_cast<int8_t>(value);
535 if (v8 < 0 && signed_value) {
536 Print("-%#" Px32, -static_cast<uint8_t>(v8));
537 } else {
538 Print("%#" Px32, static_cast<uint8_t>(v8));
539 }
540 } else if (byte_count == 2) {
541 int16_t v16 = static_cast<int16_t>(value);
542 if (v16 < 0 && signed_value) {
543 Print("-%#" Px32, -static_cast<uint16_t>(v16));
544 } else {
545 Print("%#" Px32, static_cast<uint16_t>(v16));
546 }
547 } else if (byte_count == 4) {
548 int32_t v32 = static_cast<int32_t>(value);
549 if (v32 < 0 && signed_value) {
550 Print("-%#010" Px32, -static_cast<uint32_t>(v32));
551 } else {
552 if (v32 > 0xffff) {
553 Print("%#010" Px32, v32);
554 } else {
555 Print("%#" Px32, v32);
556 }
557 }
558 } else if (byte_count == 8) {
559 int64_t v64 = static_cast<int64_t>(value);
560 if (v64 < 0 && signed_value) {
561 Print("-%#018" Px64, -static_cast<uint64_t>(v64));
562 } else {
563 if (v64 > 0xffffffffll) {
564 Print("%#018" Px64, v64);
565 } else {
566 Print("%#" Px64, v64);
567 }
568 }
569 } else {
570// Natural-sized immediates.
571#if defined(TARGET_ARCH_X64)
572 if (value < 0 && signed_value) {
573 Print("-%#" Px64, -value);
574 } else {
575 Print("%#" Px64, value);
576 }
577#else
578 int32_t v32 = static_cast<int32_t>(value);
579 if (v32 < 0 && signed_value) {
580 Print("-%#" Px32, -v32);
581 } else {
582 Print("%#" Px32, v32);
583 }
584#endif
585 }
586 }
587}
588
589void DisassemblerX64::PrintDisp(int disp, const char* after) {
590 if (-disp > 0) {
591 Print("-%#x", -disp);
592 } else {
593 Print("+%#x", disp);
594 }
595 if (after != nullptr) Print("%s", after);
596}
597
598// Returns number of bytes used by machine instruction, including *data byte.
599// Writes immediate instructions to 'tmp_buffer_'.
600int DisassemblerX64::PrintImmediateOp(uint8_t* data) {
601 bool byte_size_immediate = (*data & 0x03) != 1;
602 uint8_t modrm = *(data + 1);
603 int mod, regop, rm;
604 get_modrm(modrm, &mod, &regop, &rm);
605 const char* mnem = "Imm???";
606 switch (regop) {
607 case 0:
608 mnem = "add";
609 break;
610 case 1:
611 mnem = "or";
612 break;
613 case 2:
614 mnem = "adc";
615 break;
616 case 3:
617 mnem = "sbb";
618 break;
619 case 4:
620 mnem = "and";
621 break;
622 case 5:
623 mnem = "sub";
624 break;
625 case 6:
626 mnem = "xor";
627 break;
628 case 7:
629 mnem = "cmp";
630 break;
631 default:
632 UnimplementedInstruction(*data);
633 return 1;
634 }
635 Print("%s%s ", mnem, operand_size_code());
636 int count = PrintRightOperand(data + 1);
637 Print(",");
638 OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size();
639 count +=
640 PrintImmediate(data + 1 + count, immediate_size, byte_size_immediate);
641 return 1 + count;
642}
643
644// Returns number of bytes used, including *data.
645int DisassemblerX64::F6F7Instruction(uint8_t* data) {
646 ASSERT(*data == 0xF7 || *data == 0xF6);
647 uint8_t modrm = *(data + 1);
648 int mod, regop, rm;
649 get_modrm(modrm, &mod, &regop, &rm);
650 static const char* const mnemonics[] = {"test", nullptr, "not", "neg",
651 "mul", "imul", "div", "idiv"};
652 const char* mnem = mnemonics[regop];
653 if (mod == 3 && regop != 0) {
654 if (regop > 3) {
655 // These are instructions like idiv that implicitly use EAX and EDX as a
656 // source and destination. We make this explicit in the disassembly.
657 Print("%s%s (%s,%s),%s", mnem, operand_size_code(), Rax(),
658 NameOfCPURegister(2), NameOfCPURegister(rm));
659 } else {
660 Print("%s%s %s", mnem, operand_size_code(), NameOfCPURegister(rm));
661 }
662 return 2;
663 } else if (regop == 0) {
664 Print("test%s ", operand_size_code());
665 int count = PrintRightOperand(data + 1); // Use name of 64-bit register.
666 Print(",");
667 count += PrintImmediate(data + 1 + count, operand_size());
668 return 1 + count;
669 } else if (regop >= 4) {
670 Print("%s%s (%s,%s),", mnem, operand_size_code(), Rax(),
671 NameOfCPURegister(2));
672 return 1 + PrintRightOperand(data + 1);
673 } else {
674 UnimplementedInstruction(*data);
675 return 1;
676 }
677}
678
679int DisassemblerX64::ShiftInstruction(uint8_t* data) {
680 // C0/C1: Shift Imm8
681 // D0/D1: Shift 1
682 // D2/D3: Shift CL
683 uint8_t op = *data & (~1);
684 if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
685 UnimplementedInstruction(*data);
686 return 1;
687 }
688 uint8_t* modrm = data + 1;
689 int mod, regop, rm;
690 get_modrm(*modrm, &mod, &regop, &rm);
691 regop &= 0x7; // The REX.R bit does not affect the operation.
692 int num_bytes = 1;
693 const char* mnem = nullptr;
694 switch (regop) {
695 case 0:
696 mnem = "rol";
697 break;
698 case 1:
699 mnem = "ror";
700 break;
701 case 2:
702 mnem = "rcl";
703 break;
704 case 3:
705 mnem = "rcr";
706 break;
707 case 4:
708 mnem = "shl";
709 break;
710 case 5:
711 mnem = "shr";
712 break;
713 case 7:
714 mnem = "sar";
715 break;
716 default:
717 UnimplementedInstruction(*data);
718 return 1;
719 }
720 ASSERT(nullptr != mnem);
721 Print("%s%s ", mnem, operand_size_code());
722 if (byte_size_operand_) {
723 num_bytes += PrintRightByteOperand(modrm);
724 } else {
725 num_bytes += PrintRightOperand(modrm);
726 }
727
728 if (op == 0xD0) {
729 Print(",1");
730 } else if (op == 0xC0) {
731 uint8_t imm8 = *(data + num_bytes);
732 Print(",%d", imm8);
733 num_bytes++;
734 } else {
735 ASSERT(op == 0xD2);
736 Print(",cl");
737 }
738 return num_bytes;
739}
740
741int DisassemblerX64::PrintRightOperand(uint8_t* modrmp) {
742 return PrintRightOperandHelper(modrmp, &DisassemblerX64::NameOfCPURegister);
743}
744
745int DisassemblerX64::PrintRightByteOperand(uint8_t* modrmp) {
746 return PrintRightOperandHelper(modrmp,
747 &DisassemblerX64::NameOfByteCPURegister);
748}
749
750int DisassemblerX64::PrintRightXMMOperand(uint8_t* modrmp) {
751 return PrintRightOperandHelper(modrmp, &DisassemblerX64::NameOfXMMRegister);
752}
753
754// Returns number of bytes used including the current *data.
755// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
756int DisassemblerX64::PrintOperands(const char* mnem,
757 OperandType op_order,
758 uint8_t* data) {
759 uint8_t modrm = *data;
760 int mod, regop, rm;
761 get_modrm(modrm, &mod, &regop, &rm);
762 int advance = 0;
763 const char* register_name = byte_size_operand_ ? NameOfByteCPURegister(regop)
764 : NameOfCPURegister(regop);
765 switch (op_order) {
766 case REG_OPER_OP_ORDER: {
767 Print("%s%s %s,", mnem, operand_size_code(), register_name);
768 advance = byte_size_operand_ ? PrintRightByteOperand(data)
769 : PrintRightOperand(data);
770 break;
771 }
772 case OPER_REG_OP_ORDER: {
773 Print("%s%s ", mnem, operand_size_code());
774 advance = byte_size_operand_ ? PrintRightByteOperand(data)
775 : PrintRightOperand(data);
776 Print(",%s", register_name);
777 break;
778 }
779 default:
780 UNREACHABLE();
781 break;
782 }
783 return advance;
784}
785
786void DisassemblerX64::PrintJump(uint8_t* pc, int32_t disp) {
787 if (FLAG_disassemble_relative) {
788 Print("%+d", disp);
789 } else {
790 PrintAddress(
791 reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(pc) + disp));
792 }
793}
794
795void DisassemblerX64::PrintAddress(uint8_t* addr_byte_ptr) {
796#if defined(TARGET_ARCH_X64)
797 Print("%#018" Px64 "", reinterpret_cast<uint64_t>(addr_byte_ptr));
798#else
799 Print("%#010" Px32 "", reinterpret_cast<uint32_t>(addr_byte_ptr));
800#endif
801
802 // Try to print as stub name.
803 uword addr = reinterpret_cast<uword>(addr_byte_ptr);
804 const char* name_of_stub = StubCode::NameOfStub(addr);
805 if (name_of_stub != nullptr) {
806 Print(" [stub: %s]", name_of_stub);
807 }
808}
809// Returns number of bytes used, including *data.
810int DisassemblerX64::JumpShort(uint8_t* data) {
811 ASSERT(0xEB == *data);
812 uint8_t b = *(data + 1);
813 int32_t disp = static_cast<int8_t>(b) + 2;
814 Print("jmp ");
815 PrintJump(data, disp);
816 return 2;
817}
818
819// Returns number of bytes used, including *data.
820int DisassemblerX64::JumpConditional(uint8_t* data) {
821 ASSERT(0x0F == *data);
822 uint8_t cond = *(data + 1) & 0x0F;
823 int32_t disp = LoadUnaligned(reinterpret_cast<int32_t*>(data + 2)) + 6;
824 const char* mnem = conditional_code_suffix[cond];
825 Print("j%s ", mnem);
826 PrintJump(data, disp);
827 return 6; // includes 0x0F
828}
829
830// Returns number of bytes used, including *data.
831int DisassemblerX64::JumpConditionalShort(uint8_t* data) {
832 uint8_t cond = *data & 0x0F;
833 uint8_t b = *(data + 1);
834 int32_t disp = static_cast<int8_t>(b) + 2;
835 const char* mnem = conditional_code_suffix[cond];
836 Print("j%s ", mnem);
837 PrintJump(data, disp);
838 return 2;
839}
840
841// Returns number of bytes used, including *data.
842int DisassemblerX64::SetCC(uint8_t* data) {
843 ASSERT(0x0F == *data);
844 uint8_t cond = *(data + 1) & 0x0F;
845 const char* mnem = conditional_code_suffix[cond];
846 Print("set%s ", mnem);
847 PrintRightByteOperand(data + 2);
848 return 3; // includes 0x0F
849}
850
851// Returns number of bytes used, including *data.
852int DisassemblerX64::FPUInstruction(uint8_t* data) {
853 uint8_t escape_opcode = *data;
854 ASSERT(0xD8 == (escape_opcode & 0xF8));
855 uint8_t modrm_byte = *(data + 1);
856
857 if (modrm_byte >= 0xC0) {
858 return RegisterFPUInstruction(escape_opcode, modrm_byte);
859 } else {
860 return MemoryFPUInstruction(escape_opcode, modrm_byte, data + 1);
861 }
862}
863
864int DisassemblerX64::MemoryFPUInstruction(int escape_opcode,
865 int modrm_byte,
866 uint8_t* modrm_start) {
867 const char* mnem = nullptr;
868 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
869 switch (escape_opcode) {
870 case 0xD9:
871 switch (regop) {
872 case 0:
873 mnem = "fld_s";
874 break;
875 case 3:
876 mnem = "fstp_s";
877 break;
878 case 5:
879 mnem = "fldcw";
880 break;
881 case 7:
882 mnem = "fnstcw";
883 break;
884 }
885 break;
886
887 case 0xDB:
888 switch (regop) {
889 case 0:
890 mnem = "fild_s";
891 break;
892 case 1:
893 mnem = "fisttp_s";
894 break;
895 case 2:
896 mnem = "fist_s";
897 break;
898 case 3:
899 mnem = "fistp_s";
900 break;
901 }
902 break;
903
904 case 0xDD:
905 switch (regop) {
906 case 0:
907 mnem = "fld_d";
908 break;
909 case 3:
910 mnem = "fstp_d";
911 break;
912 }
913 break;
914
915 case 0xDF:
916 switch (regop) {
917 case 5:
918 mnem = "fild_d";
919 break;
920 case 7:
921 mnem = "fistp_d";
922 break;
923 }
924 break;
925 }
926 if (mnem == nullptr) {
927 UnimplementedInstruction(escape_opcode);
928 return 1;
929 }
930 Print("%s ", mnem);
931 int count = PrintRightOperand(modrm_start);
932 return count + 1;
933}
934
935int DisassemblerX64::RegisterFPUInstruction(int escape_opcode,
936 uint8_t modrm_byte) {
937 bool has_register = false; // Is the FPU register encoded in modrm_byte?
938 const char* mnem = "?";
939
940 switch (escape_opcode) {
941 case 0xD8:
942 UnimplementedInstruction(escape_opcode);
943 return 1;
944
945 case 0xD9:
946 switch (modrm_byte & 0xF8) {
947 case 0xC0:
948 mnem = "fld";
949 has_register = true;
950 break;
951 case 0xC8:
952 mnem = "fxch";
953 has_register = true;
954 break;
955 default:
956 switch (modrm_byte) {
957 case 0xE0:
958 mnem = "fchs";
959 break;
960 case 0xE1:
961 mnem = "fabs";
962 break;
963 case 0xE3:
964 mnem = "fninit";
965 break;
966 case 0xE4:
967 mnem = "ftst";
968 break;
969 case 0xE8:
970 mnem = "fld1";
971 break;
972 case 0xEB:
973 mnem = "fldpi";
974 break;
975 case 0xED:
976 mnem = "fldln2";
977 break;
978 case 0xEE:
979 mnem = "fldz";
980 break;
981 case 0xF0:
982 mnem = "f2xm1";
983 break;
984 case 0xF1:
985 mnem = "fyl2x";
986 break;
987 case 0xF2:
988 mnem = "fptan";
989 break;
990 case 0xF5:
991 mnem = "fprem1";
992 break;
993 case 0xF7:
994 mnem = "fincstp";
995 break;
996 case 0xF8:
997 mnem = "fprem";
998 break;
999 case 0xFB:
1000 mnem = "fsincos";
1001 break;
1002 case 0xFD:
1003 mnem = "fscale";
1004 break;
1005 case 0xFE:
1006 mnem = "fsin";
1007 break;
1008 case 0xFF:
1009 mnem = "fcos";
1010 break;
1011 default:
1012 UnimplementedInstruction(escape_opcode);
1013 return 1;
1014 }
1015 }
1016 break;
1017
1018 case 0xDA:
1019 if (modrm_byte == 0xE9) {
1020 mnem = "fucompp";
1021 } else {
1022 UnimplementedInstruction(escape_opcode);
1023 return 1;
1024 }
1025 break;
1026
1027 case 0xDB:
1028 if ((modrm_byte & 0xF8) == 0xE8) {
1029 mnem = "fucomi";
1030 has_register = true;
1031 } else if (modrm_byte == 0xE2) {
1032 mnem = "fclex";
1033 } else {
1034 UnimplementedInstruction(escape_opcode);
1035 return 1;
1036 }
1037 break;
1038
1039 case 0xDC:
1040 has_register = true;
1041 switch (modrm_byte & 0xF8) {
1042 case 0xC0:
1043 mnem = "fadd";
1044 break;
1045 case 0xE8:
1046 mnem = "fsub";
1047 break;
1048 case 0xC8:
1049 mnem = "fmul";
1050 break;
1051 case 0xF8:
1052 mnem = "fdiv";
1053 break;
1054 default:
1055 UnimplementedInstruction(escape_opcode);
1056 return 1;
1057 }
1058 break;
1059
1060 case 0xDD:
1061 has_register = true;
1062 switch (modrm_byte & 0xF8) {
1063 case 0xC0:
1064 mnem = "ffree";
1065 break;
1066 case 0xD8:
1067 mnem = "fstp";
1068 break;
1069 default:
1070 UnimplementedInstruction(escape_opcode);
1071 return 1;
1072 }
1073 break;
1074
1075 case 0xDE:
1076 if (modrm_byte == 0xD9) {
1077 mnem = "fcompp";
1078 } else {
1079 has_register = true;
1080 switch (modrm_byte & 0xF8) {
1081 case 0xC0:
1082 mnem = "faddp";
1083 break;
1084 case 0xE8:
1085 mnem = "fsubp";
1086 break;
1087 case 0xC8:
1088 mnem = "fmulp";
1089 break;
1090 case 0xF8:
1091 mnem = "fdivp";
1092 break;
1093 default:
1094 UnimplementedInstruction(escape_opcode);
1095 return 1;
1096 }
1097 }
1098 break;
1099
1100 case 0xDF:
1101 if (modrm_byte == 0xE0) {
1102 mnem = "fnstsw_ax";
1103 } else if ((modrm_byte & 0xF8) == 0xE8) {
1104 mnem = "fucomip";
1105 has_register = true;
1106 }
1107 break;
1108
1109 default:
1110 UnimplementedInstruction(escape_opcode);
1111 return 1;
1112 }
1113
1114 if (has_register) {
1115 Print("%s st%d", mnem, modrm_byte & 0x7);
1116 } else {
1117 Print("%s", mnem);
1118 }
1119 return 2;
1120}
1121
1122// TODO(srdjan): Should we add a branch hint argument?
1123bool DisassemblerX64::DecodeInstructionType(uint8_t** data) {
1124 uint8_t current;
1125
1126 // Scan for prefixes.
1127 while (true) {
1128 current = **data;
1129 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix.
1130 operand_size_ = current;
1131#if defined(TARGET_ARCH_X64)
1132 } else if ((current & 0xF0) == 0x40) {
1133 // REX prefix.
1134 setRex(current);
1135// TODO(srdjan): Should we enable printing of REX.W?
1136// if (rex_w()) Print("REX.W ");
1137#endif
1138 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3).
1139 group_1_prefix_ = current;
1140 } else if (current == 0xF0) {
1141 Print("lock ");
1142 } else { // Not a prefix - an opcode.
1143 break;
1144 }
1145 (*data)++;
1146 }
1147
1148 const InstructionDesc& idesc = instruction_table.Get(current);
1149 byte_size_operand_ = idesc.byte_size_operation;
1150
1151 switch (idesc.type) {
1152 case ZERO_OPERANDS_INSTR:
1153 if (current >= 0xA4 && current <= 0xA7) {
1154 // String move or compare operations.
1155 if (group_1_prefix_ == REP_PREFIX) {
1156 // REP.
1157 Print("rep ");
1158 }
1159 if ((current & 0x01) == 0x01) {
1160 // Operation size: word, dword or qword
1161 switch (operand_size()) {
1162 case WORD_SIZE:
1163 Print("%sw", idesc.mnem);
1164 break;
1165 case DOUBLEWORD_SIZE:
1166 Print("%sl", idesc.mnem);
1167 break;
1168 case QUADWORD_SIZE:
1169 Print("%sq", idesc.mnem);
1170 break;
1171 default:
1172 UNREACHABLE();
1173 }
1174 } else {
1175 // Operation size: byte
1176 Print("%s", idesc.mnem);
1177 }
1178 } else if (current == 0x99 && rex_w()) {
1179 Print("cqo"); // Cdql is called cdq and cdqq is called cqo.
1180 } else {
1181 Print("%s", idesc.mnem);
1182 }
1183 (*data)++;
1184 break;
1185
1186 case TWO_OPERANDS_INSTR:
1187 (*data)++;
1188 (*data) += PrintOperands(idesc.mnem, idesc.op_order_, *data);
1189 break;
1190
1191 case JUMP_CONDITIONAL_SHORT_INSTR:
1192 (*data) += JumpConditionalShort(*data);
1193 break;
1194
1195 case REGISTER_INSTR:
1196 Print("%s%s %s", idesc.mnem, operand_size_code(),
1197 NameOfCPURegister(base_reg(current & 0x07)));
1198 (*data)++;
1199 break;
1200 case PUSHPOP_INSTR:
1201 Print("%s %s", idesc.mnem, NameOfCPURegister(base_reg(current & 0x07)));
1202 (*data)++;
1203 break;
1204 case MOVE_REG_INSTR: {
1205 intptr_t addr = 0;
1206 int imm_bytes = 0;
1207 switch (operand_size()) {
1208 case WORD_SIZE:
1209 addr = LoadUnaligned(reinterpret_cast<int16_t*>(*data + 1));
1210 imm_bytes = 2;
1211 break;
1212 case DOUBLEWORD_SIZE:
1213 addr = LoadUnaligned(reinterpret_cast<int32_t*>(*data + 1));
1214 imm_bytes = 4;
1215 break;
1216 case QUADWORD_SIZE:
1217 addr = LoadUnaligned(reinterpret_cast<int64_t*>(*data + 1));
1218 imm_bytes = 8;
1219 break;
1220 default:
1221 UNREACHABLE();
1222 }
1223 (*data) += 1 + imm_bytes;
1224 Print("mov%s %s,", operand_size_code(),
1225 NameOfCPURegister(base_reg(current & 0x07)));
1226 PrintImmediateValue(addr, /* signed = */ false, imm_bytes);
1227 break;
1228 }
1229
1230 case CALL_JUMP_INSTR: {
1231 int32_t disp = LoadUnaligned(reinterpret_cast<int32_t*>(*data + 1)) + 5;
1232 Print("%s ", idesc.mnem);
1233 PrintJump(*data, disp);
1234 (*data) += 5;
1235 break;
1236 }
1237
1238 case SHORT_IMMEDIATE_INSTR: {
1239 Print("%s%s %s,", idesc.mnem, operand_size_code(), Rax());
1240 PrintImmediate(*data + 1, DOUBLEWORD_SIZE);
1241 (*data) += 5;
1242 break;
1243 }
1244
1245 case NO_INSTR:
1246 return false;
1247
1248 default:
1249 UNIMPLEMENTED(); // This type is not implemented.
1250 }
1251 return true;
1252}
1253
1254int DisassemblerX64::Print660F38Instruction(uint8_t* current) {
1255 int mod, regop, rm;
1256 if (*current == 0x25) {
1257 get_modrm(*(current + 1), &mod, &regop, &rm);
1258 Print("pmovsxdq %s,", NameOfXMMRegister(regop));
1259 return 1 + PrintRightXMMOperand(current + 1);
1260 } else if (*current == 0x29) {
1261 get_modrm(*(current + 1), &mod, &regop, &rm);
1262 Print("pcmpeqq %s,", NameOfXMMRegister(regop));
1263 return 1 + PrintRightXMMOperand(current + 1);
1264 } else {
1265 UnimplementedInstruction(*current);
1266 return 1;
1267 }
1268}
1269
1270// Handle all two-byte opcodes, which start with 0x0F.
1271// These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
1272// We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
1273int DisassemblerX64::TwoByteOpcodeInstruction(uint8_t* data) {
1274 uint8_t opcode = *(data + 1);
1275 uint8_t* current = data + 2;
1276 // At return, "current" points to the start of the next instruction.
1277 const char* mnemonic = TwoByteMnemonic(opcode);
1278 if (operand_size_ == 0x66) {
1279 // 0x66 0x0F prefix.
1280 int mod, regop, rm;
1281 if (opcode == 0xC6) {
1282 int mod, regop, rm;
1283 get_modrm(*current, &mod, &regop, &rm);
1284 Print("shufpd %s, ", NameOfXMMRegister(regop));
1285 current += PrintRightXMMOperand(current);
1286 Print(" [%x]", *current);
1287 current++;
1288 } else if (opcode == 0x3A) {
1289 uint8_t third_byte = *current;
1290 current = data + 3;
1291 if (third_byte == 0x16) {
1292 get_modrm(*current, &mod, &regop, &rm);
1293 Print("pextrd "); // reg/m32, xmm, imm8
1294 current += PrintRightOperand(current);
1295 Print(",%s,%d", NameOfXMMRegister(regop), (*current) & 7);
1296 current += 1;
1297 } else if (third_byte == 0x17) {
1298 get_modrm(*current, &mod, &regop, &rm);
1299 Print("extractps "); // reg/m32, xmm, imm8
1300 current += PrintRightOperand(current);
1301 Print(", %s, %d", NameOfCPURegister(regop), (*current) & 3);
1302 current += 1;
1303 } else if (third_byte == 0x0b) {
1304 get_modrm(*current, &mod, &regop, &rm);
1305 // roundsd xmm, xmm/m64, imm8
1306 Print("roundsd %s, ", NameOfCPURegister(regop));
1307 current += PrintRightOperand(current);
1308 Print(", %d", (*current) & 3);
1309 current += 1;
1310 } else {
1311 UnimplementedInstruction(*data);
1312 return 1;
1313 }
1314 } else {
1315 get_modrm(*current, &mod, &regop, &rm);
1316 if (opcode == 0x1f) {
1317 current++;
1318 if (rm == 4) { // SIB byte present.
1319 current++;
1320 }
1321 if (mod == 1) { // Byte displacement.
1322 current += 1;
1323 } else if (mod == 2) { // 32-bit displacement.
1324 current += 4;
1325 } // else no immediate displacement.
1326 Print("nop");
1327 } else if (opcode == 0x28) {
1328 Print("movapd %s, ", NameOfXMMRegister(regop));
1329 current += PrintRightXMMOperand(current);
1330 } else if (opcode == 0x29) {
1331 Print("movapd ");
1332 current += PrintRightXMMOperand(current);
1333 Print(", %s", NameOfXMMRegister(regop));
1334 } else if (opcode == 0x38) {
1335 current += Print660F38Instruction(current);
1336 } else if (opcode == 0x6E) {
1337 Print("mov%c %s,", rex_w() ? 'q' : 'd', NameOfXMMRegister(regop));
1338 current += PrintRightOperand(current);
1339 } else if (opcode == 0x6F) {
1340 Print("movdqa %s,", NameOfXMMRegister(regop));
1341 current += PrintRightXMMOperand(current);
1342 } else if (opcode == 0x7E) {
1343 Print("mov%c ", rex_w() ? 'q' : 'd');
1344 current += PrintRightOperand(current);
1345 Print(",%s", NameOfXMMRegister(regop));
1346 } else if (opcode == 0x7F) {
1347 Print("movdqa ");
1348 current += PrintRightXMMOperand(current);
1349 Print(",%s", NameOfXMMRegister(regop));
1350 } else if (opcode == 0xD6) {
1351 Print("movq ");
1352 current += PrintRightXMMOperand(current);
1353 Print(",%s", NameOfXMMRegister(regop));
1354 } else if (opcode == 0x50) {
1355 Print("movmskpd %s,", NameOfCPURegister(regop));
1356 current += PrintRightXMMOperand(current);
1357 } else if (opcode == 0xD7) {
1358 Print("pmovmskb %s,", NameOfCPURegister(regop));
1359 current += PrintRightXMMOperand(current);
1360 } else {
1361 const char* mnemonic = "?";
1362 if (opcode == 0x5A) {
1363 mnemonic = "cvtpd2ps";
1364 } else if (0x51 <= opcode && opcode <= 0x5F) {
1365 mnemonic = xmm_instructions[opcode & 0xF].pd_name;
1366 } else if (opcode == 0x14) {
1367 mnemonic = "unpcklpd";
1368 } else if (opcode == 0x15) {
1369 mnemonic = "unpckhpd";
1370 } else if (opcode == 0x2E) {
1371 mnemonic = "ucomisd";
1372 } else if (opcode == 0x2F) {
1373 mnemonic = "comisd";
1374 } else if (opcode == 0xFE) {
1375 mnemonic = "paddd";
1376 } else if (opcode == 0xFA) {
1377 mnemonic = "psubd";
1378 } else if (opcode == 0xEF) {
1379 mnemonic = "pxor";
1380 } else {
1381 UnimplementedInstruction(*data);
1382 return 1;
1383 }
1384 Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
1385 current += PrintRightXMMOperand(current);
1386 }
1387 }
1388 } else if (group_1_prefix_ == 0xF2) {
1389 // Beginning of instructions with prefix 0xF2.
1390
1391 if (opcode == 0x11 || opcode == 0x10) {
1392 // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
1393 Print("movsd ");
1394 int mod, regop, rm;
1395 get_modrm(*current, &mod, &regop, &rm);
1396 if (opcode == 0x11) {
1397 current += PrintRightXMMOperand(current);
1398 Print(",%s", NameOfXMMRegister(regop));
1399 } else {
1400 Print("%s,", NameOfXMMRegister(regop));
1401 current += PrintRightXMMOperand(current);
1402 }
1403 } else if (opcode == 0x2A) {
1404 // CVTSI2SD: integer to XMM double conversion.
1405 int mod, regop, rm;
1406 get_modrm(*current, &mod, &regop, &rm);
1407 Print("%sd %s,", mnemonic, NameOfXMMRegister(regop));
1408 current += PrintRightOperand(current);
1409 } else if (opcode == 0x2C) {
1410 // CVTTSD2SI:
1411 // Convert with truncation scalar double-precision FP to integer.
1412 int mod, regop, rm;
1413 get_modrm(*current, &mod, &regop, &rm);
1414 Print("cvttsd2si%s %s,", operand_size_code(), NameOfCPURegister(regop));
1415 current += PrintRightXMMOperand(current);
1416 } else if (opcode == 0x2D) {
1417 // CVTSD2SI: Convert scalar double-precision FP to integer.
1418 int mod, regop, rm;
1419 get_modrm(*current, &mod, &regop, &rm);
1420 Print("cvtsd2si%s %s,", operand_size_code(), NameOfCPURegister(regop));
1421 current += PrintRightXMMOperand(current);
1422 } else if (0x51 <= opcode && opcode <= 0x5F) {
1423 // XMM arithmetic. Get the F2 0F prefix version of the mnemonic.
1424 int mod, regop, rm;
1425 get_modrm(*current, &mod, &regop, &rm);
1426 const char* mnemonic =
1427 opcode == 0x5A ? "cvtsd2ss" : xmm_instructions[opcode & 0xF].sd_name;
1428 Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
1429 current += PrintRightXMMOperand(current);
1430 } else {
1431 UnimplementedInstruction(*data);
1432 return 1;
1433 }
1434 } else if (group_1_prefix_ == 0xF3) {
1435 // Instructions with prefix 0xF3.
1436 if (opcode == 0x11 || opcode == 0x10) {
1437 // MOVSS: Move scalar double-precision fp to/from/between XMM registers.
1438 Print("movss ");
1439 int mod, regop, rm;
1440 get_modrm(*current, &mod, &regop, &rm);
1441 if (opcode == 0x11) {
1442 current += PrintRightOperand(current);
1443 Print(",%s", NameOfXMMRegister(regop));
1444 } else {
1445 Print("%s,", NameOfXMMRegister(regop));
1446 current += PrintRightOperand(current);
1447 }
1448 } else if (opcode == 0x2A) {
1449 // CVTSI2SS: integer to XMM single conversion.
1450 int mod, regop, rm;
1451 get_modrm(*current, &mod, &regop, &rm);
1452 Print("%ss %s,", mnemonic, NameOfXMMRegister(regop));
1453 current += PrintRightOperand(current);
1454 } else if (opcode == 0x2C || opcode == 0x2D) {
1455 bool truncating = (opcode & 1) == 0;
1456 // CVTTSS2SI/CVTSS2SI:
1457 // Convert (with truncation) scalar single-precision FP to dword integer.
1458 int mod, regop, rm;
1459 get_modrm(*current, &mod, &regop, &rm);
1460 Print("cvt%sss2si%s %s,", truncating ? "t" : "", operand_size_code(),
1461 NameOfCPURegister(regop));
1462 current += PrintRightXMMOperand(current);
1463 } else if (0x51 <= opcode && opcode <= 0x5F) {
1464 int mod, regop, rm;
1465 get_modrm(*current, &mod, &regop, &rm);
1466 const char* mnemonic =
1467 opcode == 0x5A ? "cvtss2sd" : xmm_instructions[opcode & 0xF].ss_name;
1468 Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
1469 current += PrintRightXMMOperand(current);
1470 } else if (opcode == 0x7E) {
1471 int mod, regop, rm;
1472 get_modrm(*current, &mod, &regop, &rm);
1473 Print("movq %s, ", NameOfXMMRegister(regop));
1474 current += PrintRightXMMOperand(current);
1475 } else if (opcode == 0xE6) {
1476 int mod, regop, rm;
1477 get_modrm(*current, &mod, &regop, &rm);
1478 Print("cvtdq2pd %s,", NameOfXMMRegister(regop));
1479 current += PrintRightXMMOperand(current);
1480 } else if (opcode == 0xB8) {
1481 // POPCNT.
1482 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1483 } else if (opcode == 0xBD) {
1484 // LZCNT (rep BSR encoding).
1485 current += PrintOperands("lzcnt", REG_OPER_OP_ORDER, current);
1486 } else {
1487 UnimplementedInstruction(*data);
1488 return 1;
1489 }
1490 } else if (opcode == 0x1F) {
1491 // NOP
1492 int mod, regop, rm;
1493 get_modrm(*current, &mod, &regop, &rm);
1494 current++;
1495 if (rm == 4) { // SIB byte present.
1496 current++;
1497 }
1498 if (mod == 1) { // Byte displacement.
1499 current += 1;
1500 } else if (mod == 2) { // 32-bit displacement.
1501 current += 4;
1502 } // else no immediate displacement.
1503 Print("nop");
1504
1505 } else if (opcode == 0x28 || opcode == 0x2f) {
1506 // ...s xmm, xmm/m128
1507 int mod, regop, rm;
1508 get_modrm(*current, &mod, &regop, &rm);
1509 const char* mnemonic = opcode == 0x28 ? "movaps" : "comiss";
1510 Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
1511 current += PrintRightXMMOperand(current);
1512 } else if (opcode == 0x29) {
1513 // movaps xmm/m128, xmm
1514 int mod, regop, rm;
1515 get_modrm(*current, &mod, &regop, &rm);
1516 Print("movaps ");
1517 current += PrintRightXMMOperand(current);
1518 Print(",%s", NameOfXMMRegister(regop));
1519 } else if (opcode == 0x11) {
1520 // movups xmm/m128, xmm
1521 int mod, regop, rm;
1522 get_modrm(*current, &mod, &regop, &rm);
1523 Print("movups ");
1524 current += PrintRightXMMOperand(current);
1525 Print(",%s", NameOfXMMRegister(regop));
1526 } else if (opcode == 0x50) {
1527 int mod, regop, rm;
1528 get_modrm(*current, &mod, &regop, &rm);
1529 Print("movmskps %s,", NameOfCPURegister(regop));
1530 current += PrintRightXMMOperand(current);
1531 } else if (opcode == 0xA2 || opcode == 0x31) {
1532 // RDTSC or CPUID
1533 Print("%s", mnemonic);
1534 } else if ((opcode & 0xF0) == 0x40) {
1535 // CMOVcc: conditional move.
1536 int condition = opcode & 0x0F;
1537 const InstructionDesc& idesc = cmov_instructions[condition];
1538 byte_size_operand_ = idesc.byte_size_operation;
1539 current += PrintOperands(idesc.mnem, idesc.op_order_, current);
1540 } else if (0x10 <= opcode && opcode <= 0x16) {
1541 // ...ps xmm, xmm/m128
1542 static const char* const mnemonics[] = {"movups", nullptr, "movhlps",
1543 nullptr, "unpcklps", "unpckhps",
1544 "movlhps"};
1545 const char* mnemonic = mnemonics[opcode - 0x10];
1546 if (mnemonic == nullptr) {
1547 UnimplementedInstruction(*data);
1548 return 1;
1549 }
1550 int mod, regop, rm;
1551 get_modrm(*current, &mod, &regop, &rm);
1552 Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
1553 current += PrintRightXMMOperand(current);
1554 } else if (0x51 <= opcode && opcode <= 0x5F) {
1555 int mod, regop, rm;
1556 get_modrm(*current, &mod, &regop, &rm);
1557 const char* mnemonic =
1558 opcode == 0x5A ? "cvtps2pd" : xmm_instructions[opcode & 0xF].ps_name;
1559 Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
1560 current += PrintRightXMMOperand(current);
1561 } else if (opcode == 0xC2 || opcode == 0xC6) {
1562 int mod, regop, rm;
1563 get_modrm(*current, &mod, &regop, &rm);
1564 if (opcode == 0xC2) {
1565 Print("cmpps %s,", NameOfXMMRegister(regop));
1566 current += PrintRightXMMOperand(current);
1567 Print(" [%s]", xmm_conditional_code_suffix[*current]);
1568 } else {
1569 ASSERT(opcode == 0xC6);
1570 Print("shufps %s,", NameOfXMMRegister(regop));
1571 current += PrintRightXMMOperand(current);
1572 Print(" [%x]", *current);
1573 }
1574 current++;
1575 } else if ((opcode & 0xF0) == 0x80) {
1576 // Jcc: Conditional jump (branch).
1577 current = data + JumpConditional(data);
1578
1579 } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
1580 opcode == 0xB7 || opcode == 0xAF || opcode == 0xB0 ||
1581 opcode == 0xB1 || opcode == 0xBC || opcode == 0xBD) {
1582 // Size-extending moves, IMUL, cmpxchg, BSF, BSR.
1583 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1584 } else if ((opcode & 0xF0) == 0x90) {
1585 // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
1586 current = data + SetCC(data);
1587 } else if (((opcode & 0xFE) == 0xA4) || ((opcode & 0xFE) == 0xAC) ||
1588 (opcode == 0xAB) || (opcode == 0xA3)) {
1589 // SHLD, SHRD (double-prec. shift), BTS (bit test and set), BT (bit test).
1590 Print("%s%s ", mnemonic, operand_size_code());
1591 int mod, regop, rm;
1592 get_modrm(*current, &mod, &regop, &rm);
1593 current += PrintRightOperand(current);
1594 Print(",%s", NameOfCPURegister(regop));
1595 if ((opcode == 0xAB) || (opcode == 0xA3) || (opcode == 0xBD)) {
1596 // Done.
1597 } else if ((opcode == 0xA5) || (opcode == 0xAD)) {
1598 Print(",cl");
1599 } else {
1600 Print(",");
1601 current += PrintImmediate(current, BYTE_SIZE);
1602 }
1603 } else if (opcode == 0xBA && (*current & 0x60) == 0x60) {
1604 // bt? immediate instruction
1605 int r = (*current >> 3) & 7;
1606 static const char* const names[4] = {"bt", "bts", "btr", "btc"};
1607 Print("%s ", names[r - 4]);
1608 current += PrintRightOperand(current);
1609 uint8_t bit = *current++;
1610 Print(",%d", bit);
1611 } else {
1612 UnimplementedInstruction(*data);
1613 return 1;
1614 }
1615 return static_cast<int>(current - data);
1616}
1617
1618// Mnemonics for two-byte opcode instructions starting with 0x0F.
1619// The argument is the second byte of the two-byte opcode.
1620// Returns nullptr if the instruction is not handled here.
1621const char* DisassemblerX64::TwoByteMnemonic(uint8_t opcode) {
1622 if (opcode == 0x5A) {
1623 return "cvtps2pd";
1624 } else if (0x51 <= opcode && opcode <= 0x5F) {
1625 return xmm_instructions[opcode & 0xF].ps_name;
1626 }
1627 if (0xA2 <= opcode && opcode <= 0xBF) {
1628 static const char* const mnemonics[] = {
1629 "cpuid", "bt", "shld", "shld", nullptr, nullptr,
1630 nullptr, nullptr, nullptr, "bts", "shrd", "shrd",
1631 nullptr, "imul", "cmpxchg", "cmpxchg", nullptr, nullptr,
1632 nullptr, nullptr, "movzxb", "movzxw", "popcnt", nullptr,
1633 nullptr, nullptr, "bsf", "bsr", "movsxb", "movsxw"};
1634 return mnemonics[opcode - 0xA2];
1635 }
1636 switch (opcode) {
1637 case 0x12:
1638 return "movhlps";
1639 case 0x16:
1640 return "movlhps";
1641 case 0x1F:
1642 return "nop";
1643 case 0x2A: // F2/F3 prefix.
1644 return "cvtsi2s";
1645 case 0x31:
1646 return "rdtsc";
1647 default:
1648 return nullptr;
1649 }
1650}
1651
1652int DisassemblerX64::InstructionDecode(uword pc) {
1653 uint8_t* data = reinterpret_cast<uint8_t*>(pc);
1654
1655 const bool processed = DecodeInstructionType(&data);
1656
1657 if (!processed) {
1658 switch (*data) {
1659 case 0xC2:
1660 Print("ret ");
1661 PrintImmediateValue(*reinterpret_cast<uint16_t*>(data + 1));
1662 data += 3;
1663 break;
1664
1665 case 0xC8:
1666 Print("enter %d, %d", *reinterpret_cast<uint16_t*>(data + 1), data[3]);
1667 data += 4;
1668 break;
1669
1670 case 0x69:
1672 case 0x6B: {
1673 int mod, regop, rm;
1674 get_modrm(*(data + 1), &mod, &regop, &rm);
1675 int32_t imm = *data == 0x6B
1676 ? *(data + 2)
1677 : LoadUnaligned(reinterpret_cast<int32_t*>(data + 2));
1678 Print("imul%s %s,%s,", operand_size_code(), NameOfCPURegister(regop),
1679 NameOfCPURegister(rm));
1680 PrintImmediateValue(imm);
1681 data += 2 + (*data == 0x6B ? 1 : 4);
1682 break;
1683 }
1684
1685 case 0x81:
1687 case 0x83: // 0x81 with sign extension bit set
1688 data += PrintImmediateOp(data);
1689 break;
1690
1691 case 0x0F:
1692 data += TwoByteOpcodeInstruction(data);
1693 break;
1694
1695 case 0x8F: {
1696 data++;
1697 int mod, regop, rm;
1698 get_modrm(*data, &mod, &regop, &rm);
1699 if (regop == 0) {
1700 Print("pop ");
1701 data += PrintRightOperand(data);
1702 }
1703 } break;
1704
1705 case 0xFF: {
1706 data++;
1707 int mod, regop, rm;
1708 get_modrm(*data, &mod, &regop, &rm);
1709 const char* mnem = nullptr;
1710 switch (regop) {
1711 case 0:
1712 mnem = "inc";
1713 break;
1714 case 1:
1715 mnem = "dec";
1716 break;
1717 case 2:
1718 mnem = "call";
1719 break;
1720 case 4:
1721 mnem = "jmp";
1722 break;
1723 case 6:
1724 mnem = "push";
1725 break;
1726 default:
1727 mnem = "???";
1728 }
1729 if (regop <= 1) {
1730 Print("%s%s ", mnem, operand_size_code());
1731 } else {
1732 Print("%s ", mnem);
1733 }
1734 data += PrintRightOperand(data);
1735 } break;
1736
1737 case 0xC7: // imm32, fall through
1738 case 0xC6: // imm8
1739 {
1740 bool is_byte = *data == 0xC6;
1741 data++;
1742 if (is_byte) {
1743 Print("movb ");
1744 data += PrintRightByteOperand(data);
1745 Print(",");
1746 data += PrintImmediate(data, BYTE_SIZE);
1747 } else {
1748 Print("mov%s ", operand_size_code());
1749 data += PrintRightOperand(data);
1750 Print(",");
1751 data +=
1752 PrintImmediate(data, operand_size(), /* sign extend = */ true);
1753 }
1754 } break;
1755
1756 case 0x80: {
1757 byte_size_operand_ = true;
1758 data += PrintImmediateOp(data);
1759 } break;
1760
1761 case 0x88: // 8bit, fall through
1762 case 0x89: // 32bit
1763 {
1764 bool is_byte = *data == 0x88;
1765 int mod, regop, rm;
1766 data++;
1767 get_modrm(*data, &mod, &regop, &rm);
1768 if (is_byte) {
1769 Print("movb ");
1770 data += PrintRightByteOperand(data);
1771 Print(",%s", NameOfByteCPURegister(regop));
1772 } else {
1773 Print("mov%s ", operand_size_code());
1774 data += PrintRightOperand(data);
1775 Print(",%s", NameOfCPURegister(regop));
1776 }
1777 } break;
1778
1779 case 0x90:
1780 case 0x91:
1781 case 0x92:
1782 case 0x93:
1783 case 0x94:
1784 case 0x95:
1785 case 0x96:
1786 case 0x97: {
1787 int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
1788 if (reg == 0) {
1789 Print("nop"); // Common name for xchg rax,rax.
1790 } else {
1791 Print("xchg%s %s, %s", operand_size_code(), Rax(),
1792 NameOfCPURegister(reg));
1793 }
1794 data++;
1795 } break;
1796 case 0xB0:
1797 case 0xB1:
1798 case 0xB2:
1799 case 0xB3:
1800 case 0xB4:
1801 case 0xB5:
1802 case 0xB6:
1803 case 0xB7:
1804 case 0xB8:
1805 case 0xB9:
1806 case 0xBA:
1807 case 0xBB:
1808 case 0xBC:
1809 case 0xBD:
1810 case 0xBE:
1811 case 0xBF: {
1812 // mov reg8,imm8 or mov reg32,imm32
1813 uint8_t opcode = *data;
1814 data++;
1815 const bool is_not_8bit = opcode >= 0xB8;
1816 int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
1817 if (is_not_8bit) {
1818 Print("mov%s %s,", operand_size_code(), NameOfCPURegister(reg));
1819 data +=
1820 PrintImmediate(data, operand_size(), /* sign extend = */ false);
1821 } else {
1822 Print("movb %s,", NameOfByteCPURegister(reg));
1823 data += PrintImmediate(data, BYTE_SIZE, /* sign extend = */ false);
1824 }
1825 break;
1826 }
1827 case 0xFE: {
1828 data++;
1829 int mod, regop, rm;
1830 get_modrm(*data, &mod, &regop, &rm);
1831 if (regop == 1) {
1832 Print("decb ");
1833 data += PrintRightByteOperand(data);
1834 } else {
1835 UnimplementedInstruction(*data);
1836 return 1;
1837 }
1838 break;
1839 }
1840 case 0x68:
1841 Print("push ");
1842 PrintImmediateValue(
1843 LoadUnaligned(reinterpret_cast<int32_t*>(data + 1)));
1844 data += 5;
1845 break;
1846
1847 case 0x6A:
1848 Print("push ");
1849 PrintImmediateValue(*reinterpret_cast<int8_t*>(data + 1));
1850 data += 2;
1851 break;
1852
1853 case 0xA1:
1855 case 0xA3:
1856 switch (operand_size()) {
1857 case DOUBLEWORD_SIZE: {
1858 PrintAddress(reinterpret_cast<uint8_t*>(
1859 *reinterpret_cast<int32_t*>(data + 1)));
1860 if (*data == 0xA1) { // Opcode 0xA1
1861 Print("movzxlq %s,(", Rax());
1862 PrintAddress(reinterpret_cast<uint8_t*>(
1863 *reinterpret_cast<int32_t*>(data + 1)));
1864 Print(")");
1865 } else { // Opcode 0xA3
1866 Print("movzxlq (");
1867 PrintAddress(reinterpret_cast<uint8_t*>(
1868 *reinterpret_cast<int32_t*>(data + 1)));
1869 Print("),%s", Rax());
1870 }
1871 data += 5;
1872 break;
1873 }
1874 case QUADWORD_SIZE: {
1875 // New x64 instruction mov rax,(imm_64).
1876 if (*data == 0xA1) { // Opcode 0xA1
1877 Print("movq %s,(", Rax());
1878 PrintAddress(*reinterpret_cast<uint8_t**>(data + 1));
1879 Print(")");
1880 } else { // Opcode 0xA3
1881 Print("movq (");
1882 PrintAddress(*reinterpret_cast<uint8_t**>(data + 1));
1883 Print("),%s", Rax());
1884 }
1885 data += 9;
1886 break;
1887 }
1888 default:
1889 UnimplementedInstruction(*data);
1890 return 1;
1891 }
1892 break;
1893
1894 case 0xA8:
1895 Print("test al,");
1896 PrintImmediateValue(*reinterpret_cast<uint8_t*>(data + 1));
1897 data += 2;
1898 break;
1899
1900 case 0xA9: {
1901 data++;
1902 Print("test%s %s,", operand_size_code(), Rax());
1903 data += PrintImmediate(data, operand_size());
1904 break;
1905 }
1906 case 0xD1:
1908 case 0xD3:
1910 case 0xC1:
1911 data += ShiftInstruction(data);
1912 break;
1913 case 0xD0:
1915 case 0xD2:
1917 case 0xC0:
1918 byte_size_operand_ = true;
1919 data += ShiftInstruction(data);
1920 break;
1921
1922 case 0xD9:
1924 case 0xDA:
1926 case 0xDB:
1928 case 0xDC:
1930 case 0xDD:
1932 case 0xDE:
1934 case 0xDF:
1935 data += FPUInstruction(data);
1936 break;
1937
1938 case 0xEB:
1939 data += JumpShort(data);
1940 break;
1941
1942 case 0xF6:
1943 byte_size_operand_ = true;
1945 case 0xF7:
1946 data += F6F7Instruction(data);
1947 break;
1948
1949 // These encodings for inc and dec are IA32 only, but we don't get here
1950 // on X64 - the REX prefix recognizer catches them earlier.
1951 case 0x40:
1952 case 0x41:
1953 case 0x42:
1954 case 0x43:
1955 case 0x44:
1956 case 0x45:
1957 case 0x46:
1958 case 0x47:
1959 Print("inc %s", NameOfCPURegister(*data & 7));
1960 data += 1;
1961 break;
1962
1963 case 0x48:
1964 case 0x49:
1965 case 0x4a:
1966 case 0x4b:
1967 case 0x4c:
1968 case 0x4d:
1969 case 0x4e:
1970 case 0x4f:
1971 Print("dec %s", NameOfCPURegister(*data & 7));
1972 data += 1;
1973 break;
1974
1975#if defined(TARGET_ARCH_IA32)
1976 case 0x61:
1977 Print("popad");
1978 break;
1979
1980 case 0x60:
1981 Print("pushad");
1982 break;
1983#endif
1984
1985 default:
1986 UnimplementedInstruction(*data);
1987 return 1;
1988 }
1989 } // !processed
1990
1991 ASSERT(buffer_[buffer_pos_] == '\0');
1992
1993 int instr_len = data - reinterpret_cast<uint8_t*>(pc);
1994 ASSERT(instr_len > 0); // Ensure progress.
1995
1996 return instr_len;
1997}
1998
1999void DisassemblerX64::UnimplementedInstruction(uint8_t byte) {
2000 Print("unknown");
2001}
2002
2003void Disassembler::DecodeInstruction(char* hex_buffer,
2004 intptr_t hex_size,
2005 char* human_buffer,
2006 intptr_t human_size,
2007 int* out_instr_len,
2008 const Code& code,
2009 Object** object,
2010 uword pc) {
2011 ASSERT(hex_size > 0);
2012 ASSERT(human_size > 0);
2013 DisassemblerX64 decoder(human_buffer, human_size);
2014 int instruction_length = decoder.InstructionDecode(pc);
2015 uint8_t* pc_ptr = reinterpret_cast<uint8_t*>(pc);
2016 int hex_index = 0;
2017 int remaining_size = hex_size - hex_index;
2018 for (int i = 0; (i < instruction_length) && (remaining_size > 2); ++i) {
2019 Utils::SNPrint(&hex_buffer[hex_index], remaining_size, "%02x", pc_ptr[i]);
2020 hex_index += 2;
2021 remaining_size -= 2;
2022 }
2023 hex_buffer[hex_index] = '\0';
2024 if (out_instr_len != nullptr) {
2025 *out_instr_len = instruction_length;
2026 }
2027
2028 *object = nullptr;
2029#if defined(TARGET_ARCH_X64)
2030 if (!code.IsNull()) {
2031 *object = &Object::Handle();
2032 if (!DecodeLoadObjectFromPoolOrThread(pc, code, *object)) {
2033 *object = nullptr;
2034 }
2035 }
2036#else
2037 if (!code.IsNull() && code.is_alive()) {
2038 intptr_t offsets_length = code.pointer_offsets_length();
2039 for (intptr_t i = 0; i < offsets_length; i++) {
2040 uword addr = code.GetPointerOffsetAt(i) + code.PayloadStart();
2041 if ((pc <= addr) && (addr < (pc + instruction_length))) {
2042 *object =
2043 &Object::Handle(LoadUnaligned(reinterpret_cast<ObjectPtr*>(addr)));
2044 break;
2045 }
2046 }
2047 }
2048#endif
2049}
2050
2051#endif // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
2052
2053} // namespace dart
2054
2055#endif // defined(TARGET_ARCH_X64) || defined (TARGET_ARCH_IA32)
int count
Definition: FontMgrTest.cpp:50
static uint32_t buffer_size(uint32_t offset, uint32_t maxAlignment)
#define UNREACHABLE()
Definition: assert.h:248
GLenum type
static void DecodeInstruction(char *hex_buffer, intptr_t hex_size, char *human_buffer, intptr_t human_size, int *out_instr_len, const Code &code, Object **object, uword pc)
static Object & Handle()
Definition: object.h:407
static const char * RegisterName(Register reg)
Definition: constants.h:46
static const char * NameOfStub(uword entry_point)
Definition: stub_code.cc:330
static int SNPrint(char *str, size_t size, const char *format,...) PRINTF_ATTRIBUTE(3
static int static int VSNPrint(char *str, size_t size, const char *format, va_list args)
#define XMM_ALU_CODES(F)
Definition: constants_x86.h:95
#define X86_CONDITIONAL_SUFFIXES(F)
#define XMM_CONDITIONAL_CODES(F)
#define X86_ALU_CODES(F)
Definition: constants_x86.h:85
#define X86_ZERO_OPERAND_1_BYTE_INSTRUCTIONS(F)
Definition: constants_x86.h:65
#define UNIMPLEMENTED
#define ASSERT(E)
static bool b
glong glong end
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
uint8_t value
uint32_t uint32_t * format
void Init()
size_t length
double x
const GrXPFactory * Get(SkBlendMode mode)
va_start(args, format)
va_end(args)
Definition: dart_vm.cc:33
static const char *const names[]
Definition: symbols.cc:24
uintptr_t uword
Definition: globals.h:501
@ kNumberOfCpuRegisters
Definition: constants_arm.h:98
intx_t sign_extend(int32_t x)
bool DecodeLoadObjectFromPoolOrThread(uword pc, const Code &code, Object *obj)
static T LoadUnaligned(const T *ptr)
Definition: unaligned.h:14
static int8_t data[kExtLength]
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir Path to the cache directory This is different from the persistent_cache_path in embedder which is used for Skia shader cache icu native lib Path to the library file that exports the ICU data vm service The hostname IP address on which the Dart VM Service should be served If not defaults to or::depending on whether ipv6 is specified vm service A custom Dart VM Service port The default is to pick a randomly available open port disable vm Disable the Dart VM Service The Dart VM Service is never available in release mode disable vm service Disable mDNS Dart VM Service publication Bind to the IPv6 localhost address for the Dart VM Service Ignored if vm service host is set endless trace buffer
Definition: switches.h:126
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition: switches.h:259
SIN Vec< N, float > abs(const Vec< N, float > &x)
Definition: SkVx.h:707
#define Px32
Definition: globals.h:414
#define FALL_THROUGH
Definition: globals.h:15
#define Pd64
Definition: globals.h:416
#define Px64
Definition: globals.h:418
#define PRINTF_ATTRIBUTE(string_index, first_to_check)
Definition: globals.h:697
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: globals.h:581
const Scalar scale
const uintptr_t id