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
10#include "vm/compiler/assembler/disassembler.h"
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,
79 X86_CONDITIONAL_SUFFIXES(STRINGIFY)
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
162void InstructionTable::Init() {
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 = NULL; // Computed depending on condition code.
206 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
207 }
208}
209
210static InstructionTable instruction_table;
211
212static 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 const 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);
302 ASSERT(*rm < kNumberOfCpuRegisters);
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);
309 ASSERT(*base < kNumberOfCpuRegisters);
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 NameOfCPURegister(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() { UNREACHABLE(); }
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;
389 va_start(args, format);
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 int32_t disp = LoadUnaligned(reinterpret_cast<int32_t*>(modrmp + 1));
408 Print("[rip");
409 PrintDisp(disp, "]");
410 return 5;
411 } else if ((rm & 7) == 4) {
412 // Codes for SIB byte.
413 uint8_t sib = *(modrmp + 1);
414 int scale, index, base;
415 get_sib(sib, &scale, &index, &base);
416 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
417 // index == rsp means no index. Only use sib byte with no index for
418 // rsp and r12 base.
419 Print("[%s]", NameOfCPURegister(base));
420 return 2;
421 } else if (base == 5) {
422 // base == rbp means no base register (when mod == 0).
423 int32_t disp = LoadUnaligned(reinterpret_cast<int32_t*>(modrmp + 2));
424 Print("[%s*%d", NameOfCPURegister(index), 1 << scale);
425 PrintDisp(disp, "]");
426 return 6;
427 } else if (index != 4 && base != 5) {
428 // [base+index*scale]
429 Print("[%s+%s*%d]", NameOfCPURegister(base), NameOfCPURegister(index),
430 1 << scale);
431 return 2;
432 } else {
433 UnimplementedInstruction();
434 return 1;
435 }
436 } else {
437 Print("[%s]", NameOfCPURegister(rm));
438 return 1;
439 }
440 break;
441 case 1:
442 FALL_THROUGH;
443 case 2:
444 if ((rm & 7) == 4) {
445 uint8_t sib = *(modrmp + 1);
446 int scale, index, base;
447 get_sib(sib, &scale, &index, &base);
448 int disp = (mod == 2)
449 ? LoadUnaligned(reinterpret_cast<int32_t*>(modrmp + 2))
450 : *reinterpret_cast<int8_t*>(modrmp + 2);
451 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
452 Print("[%s", NameOfCPURegister(base));
453 PrintDisp(disp, "]");
454 } else {
455 Print("[%s+%s*%d", NameOfCPURegister(base), NameOfCPURegister(index),
456 1 << scale);
457 PrintDisp(disp, "]");
458 }
459 return mod == 2 ? 6 : 3;
460 } else {
461 // No sib.
462 int disp = (mod == 2)
463 ? LoadUnaligned(reinterpret_cast<int32_t*>(modrmp + 1))
464 : *reinterpret_cast<int8_t*>(modrmp + 1);
465 Print("[%s", NameOfCPURegister(rm));
466 PrintDisp(disp, "]");
467 return (mod == 2) ? 5 : 2;
468 }
469 break;
470 case 3:
471 Print("%s", (this->*register_name)(rm));
472 return 1;
473 default:
474 UnimplementedInstruction();
475 return 1;
476 }
477 UNREACHABLE();
478}
479
480int DisassemblerX64::PrintImmediate(uint8_t* data,
481 OperandSize size,
482 bool sign_extend) {
483 int64_t value;
484 int count;
485 switch (size) {
486 case BYTE_SIZE:
487 if (sign_extend) {
488 value = *reinterpret_cast<int8_t*>(data);
489 } else {
490 value = *data;
491 }
492 count = 1;
493 break;
494 case WORD_SIZE:
495 if (sign_extend) {
496 value = LoadUnaligned(reinterpret_cast<int16_t*>(data));
497 } else {
498 value = LoadUnaligned(reinterpret_cast<uint16_t*>(data));
499 }
500 count = 2;
501 break;
502 case DOUBLEWORD_SIZE:
503 case QUADWORD_SIZE:
504 if (sign_extend) {
505 value = LoadUnaligned(reinterpret_cast<int32_t*>(data));
506 } else {
507 value = LoadUnaligned(reinterpret_cast<uint32_t*>(data));
508 }
509 count = 4;
510 break;
511 default:
512 UNREACHABLE();
513 value = 0; // Initialize variables on all paths to satisfy the compiler.
514 count = 0;
515 }
516 PrintImmediateValue(value, sign_extend, count);
517 return count;
518}
519
520void DisassemblerX64::PrintImmediateValue(int64_t value,
521 bool signed_value,
522 int byte_count) {
523 if ((value >= 0) && (value <= 9)) {
524 Print("%" Pd64, value);
525 } else if (signed_value && (value < 0) && (value >= -9)) {
526 Print("-%" Pd64, -value);
527 } else {
528 if (byte_count == 1) {
529 int8_t v8 = static_cast<int8_t>(value);
530 if (v8 < 0 && signed_value) {
531 Print("-%#" Px32, -static_cast<uint8_t>(v8));
532 } else {
533 Print("%#" Px32, static_cast<uint8_t>(v8));
534 }
535 } else if (byte_count == 2) {
536 int16_t v16 = static_cast<int16_t>(value);
537 if (v16 < 0 && signed_value) {
538 Print("-%#" Px32, -static_cast<uint16_t>(v16));
539 } else {
540 Print("%#" Px32, static_cast<uint16_t>(v16));
541 }
542 } else if (byte_count == 4) {
543 int32_t v32 = static_cast<int32_t>(value);
544 if (v32 < 0 && signed_value) {
545 Print("-%#010" Px32, -static_cast<uint32_t>(v32));
546 } else {
547 if (v32 > 0xffff) {
548 Print("%#010" Px32, v32);
549 } else {
550 Print("%#" Px32, v32);
551 }
552 }
553 } else if (byte_count == 8) {
554 int64_t v64 = static_cast<int64_t>(value);
555 if (v64 < 0 && signed_value) {
556 Print("-%#018" Px64, -static_cast<uint64_t>(v64));
557 } else {
558 if (v64 > 0xffffffffll) {
559 Print("%#018" Px64, v64);
560 } else {
561 Print("%#" Px64, v64);
562 }
563 }
564 } else {
565// Natural-sized immediates.
566#if defined(TARGET_ARCH_X64)
567 if (value < 0 && signed_value) {
568 Print("-%#" Px64, -value);
569 } else {
570 Print("%#" Px64, value);
571 }
572#else
573 int32_t v32 = static_cast<int32_t>(value);
574 if (v32 < 0 && signed_value) {
575 Print("-%#" Px32, -v32);
576 } else {
577 Print("%#" Px32, v32);
578 }
579#endif
580 }
581 }
582}
583
584void DisassemblerX64::PrintDisp(int disp, const char* after) {
585 if (-disp > 0) {
586 Print("-%#x", -disp);
587 } else {
588 Print("+%#x", disp);
589 }
590 if (after != NULL) Print("%s", after);
591}
592
593// Returns number of bytes used by machine instruction, including *data byte.
594// Writes immediate instructions to 'tmp_buffer_'.
595int DisassemblerX64::PrintImmediateOp(uint8_t* data) {
596 bool byte_size_immediate = (*data & 0x03) != 1;
597 uint8_t modrm = *(data + 1);
598 int mod, regop, rm;
599 get_modrm(modrm, &mod, &regop, &rm);
600 const char* mnem = "Imm???";
601 switch (regop) {
602 case 0:
603 mnem = "add";
604 break;
605 case 1:
606 mnem = "or";
607 break;
608 case 2:
609 mnem = "adc";
610 break;
611 case 3:
612 mnem = "sbb";
613 break;
614 case 4:
615 mnem = "and";
616 break;
617 case 5:
618 mnem = "sub";
619 break;
620 case 6:
621 mnem = "xor";
622 break;
623 case 7:
624 mnem = "cmp";
625 break;
626 default:
627 UnimplementedInstruction();
628 }
629 Print("%s%s ", mnem, operand_size_code());
630 int count = PrintRightOperand(data + 1);
631 Print(",");
632 OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size();
633 count +=
634 PrintImmediate(data + 1 + count, immediate_size, byte_size_immediate);
635 return 1 + count;
636}
637
638// Returns number of bytes used, including *data.
639int DisassemblerX64::F6F7Instruction(uint8_t* data) {
640 ASSERT(*data == 0xF7 || *data == 0xF6);
641 uint8_t modrm = *(data + 1);
642 int mod, regop, rm;
643 get_modrm(modrm, &mod, &regop, &rm);
644 static const char* mnemonics[] = {"test", NULL, "not", "neg",
645 "mul", "imul", "div", "idiv"};
646 const char* mnem = mnemonics[regop];
647 if (mod == 3 && regop != 0) {
648 if (regop > 3) {
649 // These are instructions like idiv that implicitly use EAX and EDX as a
650 // source and destination. We make this explicit in the disassembly.
651 Print("%s%s (%s,%s),%s", mnem, operand_size_code(), Rax(),
652 NameOfCPURegister(2), NameOfCPURegister(rm));
653 } else {
654 Print("%s%s %s", mnem, operand_size_code(), NameOfCPURegister(rm));
655 }
656 return 2;
657 } else if (regop == 0) {
658 Print("test%s ", operand_size_code());
659 int count = PrintRightOperand(data + 1); // Use name of 64-bit register.
660 Print(",");
661 count += PrintImmediate(data + 1 + count, operand_size());
662 return 1 + count;
663 } else if (regop >= 4) {
664 Print("%s%s (%s,%s),", mnem, operand_size_code(), Rax(),
665 NameOfCPURegister(2));
666 return 1 + PrintRightOperand(data + 1);
667 } else {
668 UnimplementedInstruction();
669 return 2;
670 }
671}
672
673int DisassemblerX64::ShiftInstruction(uint8_t* data) {
674 // C0/C1: Shift Imm8
675 // D0/D1: Shift 1
676 // D2/D3: Shift CL
677 uint8_t op = *data & (~1);
678 if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
679 UnimplementedInstruction();
680 return 1;
681 }
682 uint8_t* modrm = data + 1;
683 int mod, regop, rm;
684 get_modrm(*modrm, &mod, &regop, &rm);
685 regop &= 0x7; // The REX.R bit does not affect the operation.
686 int num_bytes = 1;
687 const char* mnem = NULL;
688 switch (regop) {
689 case 0:
690 mnem = "rol";
691 break;
692 case 1:
693 mnem = "ror";
694 break;
695 case 2:
696 mnem = "rcl";
697 break;
698 case 3:
699 mnem = "rcr";
700 break;
701 case 4:
702 mnem = "shl";
703 break;
704 case 5:
705 mnem = "shr";
706 break;
707 case 7:
708 mnem = "sar";
709 break;
710 default:
711 UnimplementedInstruction();
712 return num_bytes;
713 }
714 ASSERT(NULL != mnem);
715 Print("%s%s ", mnem, operand_size_code());
716 if (byte_size_operand_) {
717 num_bytes += PrintRightByteOperand(modrm);
718 } else {
719 num_bytes += PrintRightOperand(modrm);
720 }
721
722 if (op == 0xD0) {
723 Print(",1");
724 } else if (op == 0xC0) {
725 uint8_t imm8 = *(data + num_bytes);
726 Print(",%d", imm8);
727 num_bytes++;
728 } else {
729 ASSERT(op == 0xD2);
730 Print(",cl");
731 }
732 return num_bytes;
733}
734
735int DisassemblerX64::PrintRightOperand(uint8_t* modrmp) {
736 return PrintRightOperandHelper(modrmp, &DisassemblerX64::NameOfCPURegister);
737}
738
739int DisassemblerX64::PrintRightByteOperand(uint8_t* modrmp) {
740 return PrintRightOperandHelper(modrmp,
741 &DisassemblerX64::NameOfByteCPURegister);
742}
743
744int DisassemblerX64::PrintRightXMMOperand(uint8_t* modrmp) {
745 return PrintRightOperandHelper(modrmp, &DisassemblerX64::NameOfXMMRegister);
746}
747
748// Returns number of bytes used including the current *data.
749// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
750int DisassemblerX64::PrintOperands(const char* mnem,
751 OperandType op_order,
752 uint8_t* data) {
753 uint8_t modrm = *data;
754 int mod, regop, rm;
755 get_modrm(modrm, &mod, &regop, &rm);
756 int advance = 0;
757 const char* register_name = byte_size_operand_ ? NameOfByteCPURegister(regop)
758 : NameOfCPURegister(regop);
759 switch (op_order) {
760 case REG_OPER_OP_ORDER: {
761 Print("%s%s %s,", mnem, operand_size_code(), register_name);
762 advance = byte_size_operand_ ? PrintRightByteOperand(data)
763 : PrintRightOperand(data);
764 break;
765 }
766 case OPER_REG_OP_ORDER: {
767 Print("%s%s ", mnem, operand_size_code());
768 advance = byte_size_operand_ ? PrintRightByteOperand(data)
769 : PrintRightOperand(data);
770 Print(",%s", register_name);
771 break;
772 }
773 default:
774 UNREACHABLE();
775 break;
776 }
777 return advance;
778}
779
780void DisassemblerX64::PrintJump(uint8_t* pc, int32_t disp) {
781 if (FLAG_disassemble_relative) {
782 Print("%+d", disp);
783 } else {
784 PrintAddress(
785 reinterpret_cast<uint8_t*>(reinterpret_cast<uintptr_t>(pc) + disp));
786 }
787}
788
789void DisassemblerX64::PrintAddress(uint8_t* addr_byte_ptr) {
790#if defined(TARGET_ARCH_X64)
791 Print("%#018" Px64 "", reinterpret_cast<uint64_t>(addr_byte_ptr));
792#else
793 Print("%#010" Px32 "", reinterpret_cast<uint32_t>(addr_byte_ptr));
794#endif
795
796 // Try to print as stub name.
797 uword addr = reinterpret_cast<uword>(addr_byte_ptr);
798 const char* name_of_stub = StubCode::NameOfStub(addr);
799 if (name_of_stub != NULL) {
800 Print(" [stub: %s]", name_of_stub);
801 }
802}
803// Returns number of bytes used, including *data.
804int DisassemblerX64::JumpShort(uint8_t* data) {
805 ASSERT(0xEB == *data);
806 uint8_t b = *(data + 1);
807 int32_t disp = static_cast<int8_t>(b) + 2;
808 Print("jmp ");
809 PrintJump(data, disp);
810 return 2;
811}
812
813// Returns number of bytes used, including *data.
814int DisassemblerX64::JumpConditional(uint8_t* data) {
815 ASSERT(0x0F == *data);
816 uint8_t cond = *(data + 1) & 0x0F;
817 int32_t disp = LoadUnaligned(reinterpret_cast<int32_t*>(data + 2)) + 6;
818 const char* mnem = conditional_code_suffix[cond];
819 Print("j%s ", mnem);
820 PrintJump(data, disp);
821 return 6; // includes 0x0F
822}
823
824// Returns number of bytes used, including *data.
825int DisassemblerX64::JumpConditionalShort(uint8_t* data) {
826 uint8_t cond = *data & 0x0F;
827 uint8_t b = *(data + 1);
828 int32_t disp = static_cast<int8_t>(b) + 2;
829 const char* mnem = conditional_code_suffix[cond];
830 Print("j%s ", mnem);
831 PrintJump(data, disp);
832 return 2;
833}
834
835// Returns number of bytes used, including *data.
836int DisassemblerX64::SetCC(uint8_t* data) {
837 ASSERT(0x0F == *data);
838 uint8_t cond = *(data + 1) & 0x0F;
839 const char* mnem = conditional_code_suffix[cond];
840 Print("set%s%s ", mnem, operand_size_code());
841 PrintRightByteOperand(data + 2);
842 return 3; // includes 0x0F
843}
844
845// Returns number of bytes used, including *data.
846int DisassemblerX64::FPUInstruction(uint8_t* data) {
847 uint8_t escape_opcode = *data;
848 ASSERT(0xD8 == (escape_opcode & 0xF8));
849 uint8_t modrm_byte = *(data + 1);
850
851 if (modrm_byte >= 0xC0) {
852 return RegisterFPUInstruction(escape_opcode, modrm_byte);
853 } else {
854 return MemoryFPUInstruction(escape_opcode, modrm_byte, data + 1);
855 }
856}
857
858int DisassemblerX64::MemoryFPUInstruction(int escape_opcode,
859 int modrm_byte,
860 uint8_t* modrm_start) {
861 const char* mnem = "?";
862 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
863 switch (escape_opcode) {
864 case 0xD9:
865 switch (regop) {
866 case 0:
867 mnem = "fld_s";
868 break;
869 case 3:
870 mnem = "fstp_s";
871 break;
872 case 5:
873 mnem = "fldcw";
874 break;
875 case 7:
876 mnem = "fnstcw";
877 break;
878 default:
879 UnimplementedInstruction();
880 }
881 break;
882
883 case 0xDB:
884 switch (regop) {
885 case 0:
886 mnem = "fild_s";
887 break;
888 case 1:
889 mnem = "fisttp_s";
890 break;
891 case 2:
892 mnem = "fist_s";
893 break;
894 case 3:
895 mnem = "fistp_s";
896 break;
897 default:
898 UnimplementedInstruction();
899 }
900 break;
901
902 case 0xDD:
903 switch (regop) {
904 case 0:
905 mnem = "fld_d";
906 break;
907 case 3:
908 mnem = "fstp_d";
909 break;
910 default:
911 UnimplementedInstruction();
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 default:
924 UnimplementedInstruction();
925 }
926 break;
927
928 default:
929 UnimplementedInstruction();
930 }
931 Print("%s ", mnem);
932 int count = PrintRightOperand(modrm_start);
933 return count + 1;
934}
935
936int DisassemblerX64::RegisterFPUInstruction(int escape_opcode,
937 uint8_t modrm_byte) {
938 bool has_register = false; // Is the FPU register encoded in modrm_byte?
939 const char* mnem = "?";
940
941 switch (escape_opcode) {
942 case 0xD8:
943 UnimplementedInstruction();
944 break;
945
946 case 0xD9:
947 switch (modrm_byte & 0xF8) {
948 case 0xC0:
949 mnem = "fld";
950 has_register = true;
951 break;
952 case 0xC8:
953 mnem = "fxch";
954 has_register = true;
955 break;
956 default:
957 switch (modrm_byte) {
958 case 0xE0:
959 mnem = "fchs";
960 break;
961 case 0xE1:
962 mnem = "fabs";
963 break;
964 case 0xE3:
965 mnem = "fninit";
966 break;
967 case 0xE4:
968 mnem = "ftst";
969 break;
970 case 0xE8:
971 mnem = "fld1";
972 break;
973 case 0xEB:
974 mnem = "fldpi";
975 break;
976 case 0xED:
977 mnem = "fldln2";
978 break;
979 case 0xEE:
980 mnem = "fldz";
981 break;
982 case 0xF0:
983 mnem = "f2xm1";
984 break;
985 case 0xF1:
986 mnem = "fyl2x";
987 break;
988 case 0xF2:
989 mnem = "fptan";
990 break;
991 case 0xF5:
992 mnem = "fprem1";
993 break;
994 case 0xF7:
995 mnem = "fincstp";
996 break;
997 case 0xF8:
998 mnem = "fprem";
999 break;
1000 case 0xFB:
1001 mnem = "fsincos";
1002 break;
1003 case 0xFD:
1004 mnem = "fscale";
1005 break;
1006 case 0xFE:
1007 mnem = "fsin";
1008 break;
1009 case 0xFF:
1010 mnem = "fcos";
1011 break;
1012 default:
1013 UnimplementedInstruction();
1014 }
1015 }
1016 break;
1017
1018 case 0xDA:
1019 if (modrm_byte == 0xE9) {
1020 mnem = "fucompp";
1021 } else {
1022 UnimplementedInstruction();
1023 }
1024 break;
1025
1026 case 0xDB:
1027 if ((modrm_byte & 0xF8) == 0xE8) {
1028 mnem = "fucomi";
1029 has_register = true;
1030 } else if (modrm_byte == 0xE2) {
1031 mnem = "fclex";
1032 } else {
1033 UnimplementedInstruction();
1034 }
1035 break;
1036
1037 case 0xDC:
1038 has_register = true;
1039 switch (modrm_byte & 0xF8) {
1040 case 0xC0:
1041 mnem = "fadd";
1042 break;
1043 case 0xE8:
1044 mnem = "fsub";
1045 break;
1046 case 0xC8:
1047 mnem = "fmul";
1048 break;
1049 case 0xF8:
1050 mnem = "fdiv";
1051 break;
1052 default:
1053 UnimplementedInstruction();
1054 }
1055 break;
1056
1057 case 0xDD:
1058 has_register = true;
1059 switch (modrm_byte & 0xF8) {
1060 case 0xC0:
1061 mnem = "ffree";
1062 break;
1063 case 0xD8:
1064 mnem = "fstp";
1065 break;
1066 default:
1067 UnimplementedInstruction();
1068 }
1069 break;
1070
1071 case 0xDE:
1072 if (modrm_byte == 0xD9) {
1073 mnem = "fcompp";
1074 } else {
1075 has_register = true;
1076 switch (modrm_byte & 0xF8) {
1077 case 0xC0:
1078 mnem = "faddp";
1079 break;
1080 case 0xE8:
1081 mnem = "fsubp";
1082 break;
1083 case 0xC8:
1084 mnem = "fmulp";
1085 break;
1086 case 0xF8:
1087 mnem = "fdivp";
1088 break;
1089 default:
1090 UnimplementedInstruction();
1091 }
1092 }
1093 break;
1094
1095 case 0xDF:
1096 if (modrm_byte == 0xE0) {
1097 mnem = "fnstsw_ax";
1098 } else if ((modrm_byte & 0xF8) == 0xE8) {
1099 mnem = "fucomip";
1100 has_register = true;
1101 }
1102 break;
1103
1104 default:
1105 UnimplementedInstruction();
1106 }
1107
1108 if (has_register) {
1109 Print("%s st%d", mnem, modrm_byte & 0x7);
1110 } else {
1111 Print("%s", mnem);
1112 }
1113 return 2;
1114}
1115
1116// TODO(srdjan): Should we add a branch hint argument?
1117bool DisassemblerX64::DecodeInstructionType(uint8_t** data) {
1118 uint8_t current;
1119
1120 // Scan for prefixes.
1121 while (true) {
1122 current = **data;
1123 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix.
1124 operand_size_ = current;
1125#if defined(TARGET_ARCH_X64)
1126 } else if ((current & 0xF0) == 0x40) {
1127 // REX prefix.
1128 setRex(current);
1129// TODO(srdjan): Should we enable printing of REX.W?
1130// if (rex_w()) Print("REX.W ");
1131#endif
1132 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3).
1133 group_1_prefix_ = current;
1134 } else if (current == 0xF0) {
1135 Print("lock ");
1136 } else { // Not a prefix - an opcode.
1137 break;
1138 }
1139 (*data)++;
1140 }
1141
1142 const InstructionDesc& idesc = instruction_table.Get(current);
1143 byte_size_operand_ = idesc.byte_size_operation;
1144
1145 switch (idesc.type) {
1146 case ZERO_OPERANDS_INSTR:
1147 if (current >= 0xA4 && current <= 0xA7) {
1148 // String move or compare operations.
1149 if (group_1_prefix_ == REP_PREFIX) {
1150 // REP.
1151 Print("rep ");
1152 }
1153 if ((current & 0x01) == 0x01) {
1154 // Operation size: word, dword or qword
1155 switch (operand_size()) {
1156 case WORD_SIZE:
1157 Print("%sw", idesc.mnem);
1158 break;
1159 case DOUBLEWORD_SIZE:
1160 Print("%sl", idesc.mnem);
1161 break;
1162 case QUADWORD_SIZE:
1163 Print("%sq", idesc.mnem);
1164 break;
1165 default:
1166 UNREACHABLE();
1167 }
1168 } else {
1169 // Operation size: byte
1170 Print("%s", idesc.mnem);
1171 }
1172 } else if (current == 0x99 && rex_w()) {
1173 Print("cqo"); // Cdql is called cdq and cdqq is called cqo.
1174 } else {
1175 Print("%s", idesc.mnem);
1176 }
1177 (*data)++;
1178 break;
1179
1180 case TWO_OPERANDS_INSTR:
1181 (*data)++;
1182 (*data) += PrintOperands(idesc.mnem, idesc.op_order_, *data);
1183 break;
1184
1185 case JUMP_CONDITIONAL_SHORT_INSTR:
1186 (*data) += JumpConditionalShort(*data);
1187 break;
1188
1189 case REGISTER_INSTR:
1190 Print("%s%s %s", idesc.mnem, operand_size_code(),
1191 NameOfCPURegister(base_reg(current & 0x07)));
1192 (*data)++;
1193 break;
1194 case PUSHPOP_INSTR:
1195 Print("%s %s", idesc.mnem, NameOfCPURegister(base_reg(current & 0x07)));
1196 (*data)++;
1197 break;
1198 case MOVE_REG_INSTR: {
1199 intptr_t addr = 0;
1200 int imm_bytes = 0;
1201 switch (operand_size()) {
1202 case WORD_SIZE:
1203 addr = LoadUnaligned(reinterpret_cast<int16_t*>(*data + 1));
1204 imm_bytes = 2;
1205 break;
1206 case DOUBLEWORD_SIZE:
1207 addr = LoadUnaligned(reinterpret_cast<int32_t*>(*data + 1));
1208 imm_bytes = 4;
1209 break;
1210 case QUADWORD_SIZE:
1211 addr = LoadUnaligned(reinterpret_cast<int64_t*>(*data + 1));
1212 imm_bytes = 8;
1213 break;
1214 default:
1215 UNREACHABLE();
1216 }
1217 (*data) += 1 + imm_bytes;
1218 Print("mov%s %s,", operand_size_code(),
1219 NameOfCPURegister(base_reg(current & 0x07)));
1220 PrintImmediateValue(addr, /* signed = */ false, imm_bytes);
1221 break;
1222 }
1223
1224 case CALL_JUMP_INSTR: {
1225 int32_t disp = LoadUnaligned(reinterpret_cast<int32_t*>(*data + 1)) + 5;
1226 Print("%s ", idesc.mnem);
1227 PrintJump(*data, disp);
1228 (*data) += 5;
1229 break;
1230 }
1231
1232 case SHORT_IMMEDIATE_INSTR: {
1233 Print("%s%s %s,", idesc.mnem, operand_size_code(), Rax());
1234 PrintImmediate(*data + 1, DOUBLEWORD_SIZE);
1235 (*data) += 5;
1236 break;
1237 }
1238
1239 case NO_INSTR:
1240 return false;
1241
1242 default:
1243 UNIMPLEMENTED(); // This type is not implemented.
1244 }
1245 return true;
1246}
1247
1248int DisassemblerX64::Print660F38Instruction(uint8_t* current) {
1249 int mod, regop, rm;
1250 if (*current == 0x25) {
1251 get_modrm(*(current + 1), &mod, &regop, &rm);
1252 Print("pmovsxdq %s,", NameOfXMMRegister(regop));
1253 return 1 + PrintRightXMMOperand(current + 1);
1254 } else if (*current == 0x29) {
1255 get_modrm(*(current + 1), &mod, &regop, &rm);
1256 Print("pcmpeqq %s,", NameOfXMMRegister(regop));
1257 return 1 + PrintRightXMMOperand(current + 1);
1258 } else {
1259 UnimplementedInstruction();
1260 return 1;
1261 }
1262}
1263
1264// Handle all two-byte opcodes, which start with 0x0F.
1265// These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
1266// We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
1267int DisassemblerX64::TwoByteOpcodeInstruction(uint8_t* data) {
1268 uint8_t opcode = *(data + 1);
1269 uint8_t* current = data + 2;
1270 // At return, "current" points to the start of the next instruction.
1271 const char* mnemonic = TwoByteMnemonic(opcode);
1272 if (operand_size_ == 0x66) {
1273 // 0x66 0x0F prefix.
1274 int mod, regop, rm;
1275 if (opcode == 0xC6) {
1276 int mod, regop, rm;
1277 get_modrm(*current, &mod, &regop, &rm);
1278 Print("shufpd %s, ", NameOfXMMRegister(regop));
1279 current += PrintRightXMMOperand(current);
1280 Print(" [%x]", *current);
1281 current++;
1282 } else if (opcode == 0x3A) {
1283 uint8_t third_byte = *current;
1284 current = data + 3;
1285 if (third_byte == 0x16) {
1286 get_modrm(*current, &mod, &regop, &rm);
1287 Print("pextrd "); // reg/m32, xmm, imm8
1288 current += PrintRightOperand(current);
1289 Print(",%s,%d", NameOfXMMRegister(regop), (*current) & 7);
1290 current += 1;
1291 } else if (third_byte == 0x17) {
1292 get_modrm(*current, &mod, &regop, &rm);
1293 Print("extractps "); // reg/m32, xmm, imm8
1294 current += PrintRightOperand(current);
1295 Print(", %s, %d", NameOfCPURegister(regop), (*current) & 3);
1296 current += 1;
1297 } else if (third_byte == 0x0b) {
1298 get_modrm(*current, &mod, &regop, &rm);
1299 // roundsd xmm, xmm/m64, imm8
1300 Print("roundsd %s, ", NameOfCPURegister(regop));
1301 current += PrintRightOperand(current);
1302 Print(", %d", (*current) & 3);
1303 current += 1;
1304 } else {
1305 UnimplementedInstruction();
1306 }
1307 } else {
1308 get_modrm(*current, &mod, &regop, &rm);
1309 if (opcode == 0x1f) {
1310 current++;
1311 if (rm == 4) { // SIB byte present.
1312 current++;
1313 }
1314 if (mod == 1) { // Byte displacement.
1315 current += 1;
1316 } else if (mod == 2) { // 32-bit displacement.
1317 current += 4;
1318 } // else no immediate displacement.
1319 Print("nop");
1320 } else if (opcode == 0x28) {
1321 Print("movapd %s, ", NameOfXMMRegister(regop));
1322 current += PrintRightXMMOperand(current);
1323 } else if (opcode == 0x29) {
1324 Print("movapd ");
1325 current += PrintRightXMMOperand(current);
1326 Print(", %s", NameOfXMMRegister(regop));
1327 } else if (opcode == 0x38) {
1328 current += Print660F38Instruction(current);
1329 } else if (opcode == 0x6E) {
1330 Print("mov%c %s,", rex_w() ? 'q' : 'd', NameOfXMMRegister(regop));
1331 current += PrintRightOperand(current);
1332 } else if (opcode == 0x6F) {
1333 Print("movdqa %s,", NameOfXMMRegister(regop));
1334 current += PrintRightXMMOperand(current);
1335 } else if (opcode == 0x7E) {
1336 Print("mov%c ", rex_w() ? 'q' : 'd');
1337 current += PrintRightOperand(current);
1338 Print(",%s", NameOfXMMRegister(regop));
1339 } else if (opcode == 0x7F) {
1340 Print("movdqa ");
1341 current += PrintRightXMMOperand(current);
1342 Print(",%s", NameOfXMMRegister(regop));
1343 } else if (opcode == 0xD6) {
1344 Print("movq ");
1345 current += PrintRightXMMOperand(current);
1346 Print(",%s", NameOfXMMRegister(regop));
1347 } else if (opcode == 0x50) {
1348 Print("movmskpd %s,", NameOfCPURegister(regop));
1349 current += PrintRightXMMOperand(current);
1350 } else if (opcode == 0xD7) {
1351 Print("pmovmskb %s,", NameOfCPURegister(regop));
1352 current += PrintRightXMMOperand(current);
1353 } else {
1354 const char* mnemonic = "?";
1355 if (opcode == 0x5A) {
1356 mnemonic = "cvtpd2ps";
1357 } else if (0x51 <= opcode && opcode <= 0x5F) {
1358 mnemonic = xmm_instructions[opcode & 0xF].pd_name;
1359 } else if (opcode == 0x14) {
1360 mnemonic = "unpcklpd";
1361 } else if (opcode == 0x15) {
1362 mnemonic = "unpckhpd";
1363 } else if (opcode == 0x2E) {
1364 mnemonic = "ucomisd";
1365 } else if (opcode == 0x2F) {
1366 mnemonic = "comisd";
1367 } else if (opcode == 0xFE) {
1368 mnemonic = "paddd";
1369 } else if (opcode == 0xFA) {
1370 mnemonic = "psubd";
1371 } else if (opcode == 0xEF) {
1372 mnemonic = "pxor";
1373 } else {
1374 UnimplementedInstruction();
1375 }
1376 Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
1377 current += PrintRightXMMOperand(current);
1378 }
1379 }
1380 } else if (group_1_prefix_ == 0xF2) {
1381 // Beginning of instructions with prefix 0xF2.
1382
1383 if (opcode == 0x11 || opcode == 0x10) {
1384 // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
1385 Print("movsd ");
1386 int mod, regop, rm;
1387 get_modrm(*current, &mod, &regop, &rm);
1388 if (opcode == 0x11) {
1389 current += PrintRightXMMOperand(current);
1390 Print(",%s", NameOfXMMRegister(regop));
1391 } else {
1392 Print("%s,", NameOfXMMRegister(regop));
1393 current += PrintRightXMMOperand(current);
1394 }
1395 } else if (opcode == 0x2A) {
1396 // CVTSI2SD: integer to XMM double conversion.
1397 int mod, regop, rm;
1398 get_modrm(*current, &mod, &regop, &rm);
1399 Print("%sd %s,", mnemonic, NameOfXMMRegister(regop));
1400 current += PrintRightOperand(current);
1401 } else if (opcode == 0x2C) {
1402 // CVTTSD2SI:
1403 // Convert with truncation scalar double-precision FP to integer.
1404 int mod, regop, rm;
1405 get_modrm(*current, &mod, &regop, &rm);
1406 Print("cvttsd2si%s %s,", operand_size_code(), NameOfCPURegister(regop));
1407 current += PrintRightXMMOperand(current);
1408 } else if (opcode == 0x2D) {
1409 // CVTSD2SI: Convert scalar double-precision FP to integer.
1410 int mod, regop, rm;
1411 get_modrm(*current, &mod, &regop, &rm);
1412 Print("cvtsd2si%s %s,", operand_size_code(), NameOfCPURegister(regop));
1413 current += PrintRightXMMOperand(current);
1414 } else if (0x51 <= opcode && opcode <= 0x5F) {
1415 // XMM arithmetic. Get the F2 0F prefix version of the mnemonic.
1416 int mod, regop, rm;
1417 get_modrm(*current, &mod, &regop, &rm);
1418 const char* mnemonic =
1419 opcode == 0x5A ? "cvtsd2ss" : xmm_instructions[opcode & 0xF].sd_name;
1420 Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
1421 current += PrintRightXMMOperand(current);
1422 } else {
1423 UnimplementedInstruction();
1424 }
1425 } else if (group_1_prefix_ == 0xF3) {
1426 // Instructions with prefix 0xF3.
1427 if (opcode == 0x11 || opcode == 0x10) {
1428 // MOVSS: Move scalar double-precision fp to/from/between XMM registers.
1429 Print("movss ");
1430 int mod, regop, rm;
1431 get_modrm(*current, &mod, &regop, &rm);
1432 if (opcode == 0x11) {
1433 current += PrintRightOperand(current);
1434 Print(",%s", NameOfXMMRegister(regop));
1435 } else {
1436 Print("%s,", NameOfXMMRegister(regop));
1437 current += PrintRightOperand(current);
1438 }
1439 } else if (opcode == 0x2A) {
1440 // CVTSI2SS: integer to XMM single conversion.
1441 int mod, regop, rm;
1442 get_modrm(*current, &mod, &regop, &rm);
1443 Print("%ss %s,", mnemonic, NameOfXMMRegister(regop));
1444 current += PrintRightOperand(current);
1445 } else if (opcode == 0x2C || opcode == 0x2D) {
1446 bool truncating = (opcode & 1) == 0;
1447 // CVTTSS2SI/CVTSS2SI:
1448 // Convert (with truncation) scalar single-precision FP to dword integer.
1449 int mod, regop, rm;
1450 get_modrm(*current, &mod, &regop, &rm);
1451 Print("cvt%sss2si%s %s,", truncating ? "t" : "", operand_size_code(),
1452 NameOfCPURegister(regop));
1453 current += PrintRightXMMOperand(current);
1454 } else if (0x51 <= opcode && opcode <= 0x5F) {
1455 int mod, regop, rm;
1456 get_modrm(*current, &mod, &regop, &rm);
1457 const char* mnemonic =
1458 opcode == 0x5A ? "cvtss2sd" : xmm_instructions[opcode & 0xF].ss_name;
1459 Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
1460 current += PrintRightXMMOperand(current);
1461 } else if (opcode == 0x7E) {
1462 int mod, regop, rm;
1463 get_modrm(*current, &mod, &regop, &rm);
1464 Print("movq %s, ", NameOfXMMRegister(regop));
1465 current += PrintRightXMMOperand(current);
1466 } else if (opcode == 0xE6) {
1467 int mod, regop, rm;
1468 get_modrm(*current, &mod, &regop, &rm);
1469 Print("cvtdq2pd %s,", NameOfXMMRegister(regop));
1470 current += PrintRightXMMOperand(current);
1471 } else if (opcode == 0xB8) {
1472 // POPCNT.
1473 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1474 } else if (opcode == 0xBD) {
1475 // LZCNT (rep BSR encoding).
1476 current += PrintOperands("lzcnt", REG_OPER_OP_ORDER, current);
1477 } else {
1478 UnimplementedInstruction();
1479 }
1480 } else if (opcode == 0x1F) {
1481 // NOP
1482 int mod, regop, rm;
1483 get_modrm(*current, &mod, &regop, &rm);
1484 current++;
1485 if (rm == 4) { // SIB byte present.
1486 current++;
1487 }
1488 if (mod == 1) { // Byte displacement.
1489 current += 1;
1490 } else if (mod == 2) { // 32-bit displacement.
1491 current += 4;
1492 } // else no immediate displacement.
1493 Print("nop");
1494
1495 } else if (opcode == 0x28 || opcode == 0x2f) {
1496 // ...s xmm, xmm/m128
1497 int mod, regop, rm;
1498 get_modrm(*current, &mod, &regop, &rm);
1499 const char* mnemonic = opcode == 0x28 ? "movaps" : "comiss";
1500 Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
1501 current += PrintRightXMMOperand(current);
1502 } else if (opcode == 0x29) {
1503 // movaps xmm/m128, xmm
1504 int mod, regop, rm;
1505 get_modrm(*current, &mod, &regop, &rm);
1506 Print("movaps ");
1507 current += PrintRightXMMOperand(current);
1508 Print(",%s", NameOfXMMRegister(regop));
1509 } else if (opcode == 0x11) {
1510 // movups xmm/m128, xmm
1511 int mod, regop, rm;
1512 get_modrm(*current, &mod, &regop, &rm);
1513 Print("movups ");
1514 current += PrintRightXMMOperand(current);
1515 Print(",%s", NameOfXMMRegister(regop));
1516 } else if (opcode == 0x50) {
1517 int mod, regop, rm;
1518 get_modrm(*current, &mod, &regop, &rm);
1519 Print("movmskps %s,", NameOfCPURegister(regop));
1520 current += PrintRightXMMOperand(current);
1521 } else if (opcode == 0xA2 || opcode == 0x31) {
1522 // RDTSC or CPUID
1523 Print("%s", mnemonic);
1524 } else if ((opcode & 0xF0) == 0x40) {
1525 // CMOVcc: conditional move.
1526 int condition = opcode & 0x0F;
1527 const InstructionDesc& idesc = cmov_instructions[condition];
1528 byte_size_operand_ = idesc.byte_size_operation;
1529 current += PrintOperands(idesc.mnem, idesc.op_order_, current);
1530 } else if (0x10 <= opcode && opcode <= 0x16) {
1531 // ...ps xmm, xmm/m128
1532 static const char* mnemonics[] = {"movups", NULL, "movhlps", NULL,
1533 "unpcklps", "unpckhps", "movlhps"};
1534 const char* mnemonic = mnemonics[opcode - 0x10];
1535 if (mnemonic == NULL) {
1536 UnimplementedInstruction();
1537 mnemonic = "???";
1538 }
1539 int mod, regop, rm;
1540 get_modrm(*current, &mod, &regop, &rm);
1541 Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
1542 current += PrintRightXMMOperand(current);
1543 } else if (0x51 <= opcode && opcode <= 0x5F) {
1544 int mod, regop, rm;
1545 get_modrm(*current, &mod, &regop, &rm);
1546 const char* mnemonic =
1547 opcode == 0x5A ? "cvtps2pd" : xmm_instructions[opcode & 0xF].ps_name;
1548 Print("%s %s,", mnemonic, NameOfXMMRegister(regop));
1549 current += PrintRightXMMOperand(current);
1550 } else if (opcode == 0xC2 || opcode == 0xC6) {
1551 int mod, regop, rm;
1552 get_modrm(*current, &mod, &regop, &rm);
1553 if (opcode == 0xC2) {
1554 Print("cmpps %s,", NameOfXMMRegister(regop));
1555 current += PrintRightXMMOperand(current);
1556 Print(" [%s]", xmm_conditional_code_suffix[*current]);
1557 } else {
1558 ASSERT(opcode == 0xC6);
1559 Print("shufps %s,", NameOfXMMRegister(regop));
1560 current += PrintRightXMMOperand(current);
1561 Print(" [%x]", *current);
1562 }
1563 current++;
1564 } else if ((opcode & 0xF0) == 0x80) {
1565 // Jcc: Conditional jump (branch).
1566 current = data + JumpConditional(data);
1567
1568 } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
1569 opcode == 0xB7 || opcode == 0xAF || opcode == 0xB0 ||
1570 opcode == 0xB1 || opcode == 0xBC || opcode == 0xBD) {
1571 // Size-extending moves, IMUL, cmpxchg, BSF, BSR.
1572 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1573 } else if ((opcode & 0xF0) == 0x90) {
1574 // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
1575 current = data + SetCC(data);
1576 } else if (((opcode & 0xFE) == 0xA4) || ((opcode & 0xFE) == 0xAC) ||
1577 (opcode == 0xAB) || (opcode == 0xA3)) {
1578 // SHLD, SHRD (double-prec. shift), BTS (bit test and set), BT (bit test).
1579 Print("%s%s ", mnemonic, operand_size_code());
1580 int mod, regop, rm;
1581 get_modrm(*current, &mod, &regop, &rm);
1582 current += PrintRightOperand(current);
1583 Print(",%s", NameOfCPURegister(regop));
1584 if ((opcode == 0xAB) || (opcode == 0xA3) || (opcode == 0xBD)) {
1585 // Done.
1586 } else if ((opcode == 0xA5) || (opcode == 0xAD)) {
1587 Print(",cl");
1588 } else {
1589 Print(",");
1590 current += PrintImmediate(current, BYTE_SIZE);
1591 }
1592 } else if (opcode == 0xBA && (*current & 0x60) == 0x60) {
1593 // bt? immediate instruction
1594 int r = (*current >> 3) & 7;
1595 static const char* const names[4] = {"bt", "bts", "btr", "btc"};
1596 Print("%s ", names[r - 4]);
1597 current += PrintRightOperand(current);
1598 uint8_t bit = *current++;
1599 Print(",%d", bit);
1600 } else {
1601 UnimplementedInstruction();
1602 }
1603 return static_cast<int>(current - data);
1604}
1605
1606// Mnemonics for two-byte opcode instructions starting with 0x0F.
1607// The argument is the second byte of the two-byte opcode.
1608// Returns NULL if the instruction is not handled here.
1609const char* DisassemblerX64::TwoByteMnemonic(uint8_t opcode) {
1610 if (opcode == 0x5A) {
1611 return "cvtps2pd";
1612 } else if (0x51 <= opcode && opcode <= 0x5F) {
1613 return xmm_instructions[opcode & 0xF].ps_name;
1614 }
1615 if (0xA2 <= opcode && opcode <= 0xBF) {
1616 static const char* mnemonics[] = {
1617 "cpuid", "bt", "shld", "shld", NULL, NULL,
1618 NULL, NULL, NULL, "bts", "shrd", "shrd",
1619 NULL, "imul", "cmpxchg", "cmpxchg", NULL, NULL,
1620 NULL, NULL, "movzxb", "movzxw", "popcnt", NULL,
1621 NULL, NULL, "bsf", "bsr", "movsxb", "movsxw"};
1622 return mnemonics[opcode - 0xA2];
1623 }
1624 switch (opcode) {
1625 case 0x12:
1626 return "movhlps";
1627 case 0x16:
1628 return "movlhps";
1629 case 0x1F:
1630 return "nop";
1631 case 0x2A: // F2/F3 prefix.
1632 return "cvtsi2s";
1633 case 0x31:
1634 return "rdtsc";
1635 default:
1636 return NULL;
1637 }
1638}
1639
1640int DisassemblerX64::InstructionDecode(uword pc) {
1641 uint8_t* data = reinterpret_cast<uint8_t*>(pc);
1642
1643 const bool processed = DecodeInstructionType(&data);
1644
1645 if (!processed) {
1646 switch (*data) {
1647 case 0xC2:
1648 Print("ret ");
1649 PrintImmediateValue(*reinterpret_cast<uint16_t*>(data + 1));
1650 data += 3;
1651 break;
1652
1653 case 0xC8:
1654 Print("enter %d, %d", *reinterpret_cast<uint16_t*>(data + 1), data[3]);
1655 data += 4;
1656 break;
1657
1658 case 0x69:
1659 FALL_THROUGH;
1660 case 0x6B: {
1661 int mod, regop, rm;
1662 get_modrm(*(data + 1), &mod, &regop, &rm);
1663 int32_t imm = *data == 0x6B
1664 ? *(data + 2)
1665 : LoadUnaligned(reinterpret_cast<int32_t*>(data + 2));
1666 Print("imul%s %s,%s,", operand_size_code(), NameOfCPURegister(regop),
1667 NameOfCPURegister(rm));
1668 PrintImmediateValue(imm);
1669 data += 2 + (*data == 0x6B ? 1 : 4);
1670 break;
1671 }
1672
1673 case 0x81:
1674 FALL_THROUGH;
1675 case 0x83: // 0x81 with sign extension bit set
1676 data += PrintImmediateOp(data);
1677 break;
1678
1679 case 0x0F:
1680 data += TwoByteOpcodeInstruction(data);
1681 break;
1682
1683 case 0x8F: {
1684 data++;
1685 int mod, regop, rm;
1686 get_modrm(*data, &mod, &regop, &rm);
1687 if (regop == 0) {
1688 Print("pop ");
1689 data += PrintRightOperand(data);
1690 }
1691 } break;
1692
1693 case 0xFF: {
1694 data++;
1695 int mod, regop, rm;
1696 get_modrm(*data, &mod, &regop, &rm);
1697 const char* mnem = NULL;
1698 switch (regop) {
1699 case 0:
1700 mnem = "inc";
1701 break;
1702 case 1:
1703 mnem = "dec";
1704 break;
1705 case 2:
1706 mnem = "call";
1707 break;
1708 case 4:
1709 mnem = "jmp";
1710 break;
1711 case 6:
1712 mnem = "push";
1713 break;
1714 default:
1715 mnem = "???";
1716 }
1717 if (regop <= 1) {
1718 Print("%s%s ", mnem, operand_size_code());
1719 } else {
1720 Print("%s ", mnem);
1721 }
1722 data += PrintRightOperand(data);
1723 } break;
1724
1725 case 0xC7: // imm32, fall through
1726 case 0xC6: // imm8
1727 {
1728 bool is_byte = *data == 0xC6;
1729 data++;
1730 if (is_byte) {
1731 Print("movb ");
1732 data += PrintRightByteOperand(data);
1733 Print(",");
1734 data += PrintImmediate(data, BYTE_SIZE);
1735 } else {
1736 Print("mov%s ", operand_size_code());
1737 data += PrintRightOperand(data);
1738 Print(",");
1739 data +=
1740 PrintImmediate(data, operand_size(), /* sign extend = */ true);
1741 }
1742 } break;
1743
1744 case 0x80: {
1745 byte_size_operand_ = true;
1746 data += PrintImmediateOp(data);
1747 } break;
1748
1749 case 0x88: // 8bit, fall through
1750 case 0x89: // 32bit
1751 {
1752 bool is_byte = *data == 0x88;
1753 int mod, regop, rm;
1754 data++;
1755 get_modrm(*data, &mod, &regop, &rm);
1756 if (is_byte) {
1757 Print("movb ");
1758 data += PrintRightByteOperand(data);
1759 Print(",%s", NameOfByteCPURegister(regop));
1760 } else {
1761 Print("mov%s ", operand_size_code());
1762 data += PrintRightOperand(data);
1763 Print(",%s", NameOfCPURegister(regop));
1764 }
1765 } break;
1766
1767 case 0x90:
1768 case 0x91:
1769 case 0x92:
1770 case 0x93:
1771 case 0x94:
1772 case 0x95:
1773 case 0x96:
1774 case 0x97: {
1775 int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
1776 if (reg == 0) {
1777 Print("nop"); // Common name for xchg rax,rax.
1778 } else {
1779 Print("xchg%s %s, %s", operand_size_code(), Rax(),
1780 NameOfCPURegister(reg));
1781 }
1782 data++;
1783 } break;
1784 case 0xB0:
1785 case 0xB1:
1786 case 0xB2:
1787 case 0xB3:
1788 case 0xB4:
1789 case 0xB5:
1790 case 0xB6:
1791 case 0xB7:
1792 case 0xB8:
1793 case 0xB9:
1794 case 0xBA:
1795 case 0xBB:
1796 case 0xBC:
1797 case 0xBD:
1798 case 0xBE:
1799 case 0xBF: {
1800 // mov reg8,imm8 or mov reg32,imm32
1801 uint8_t opcode = *data;
1802 data++;
1803 const bool is_not_8bit = opcode >= 0xB8;
1804 int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
1805 if (is_not_8bit) {
1806 Print("mov%s %s,", operand_size_code(), NameOfCPURegister(reg));
1807 data +=
1808 PrintImmediate(data, operand_size(), /* sign extend = */ false);
1809 } else {
1810 Print("movb %s,", NameOfByteCPURegister(reg));
1811 data += PrintImmediate(data, BYTE_SIZE, /* sign extend = */ false);
1812 }
1813 break;
1814 }
1815 case 0xFE: {
1816 data++;
1817 int mod, regop, rm;
1818 get_modrm(*data, &mod, &regop, &rm);
1819 if (regop == 1) {
1820 Print("decb ");
1821 data += PrintRightByteOperand(data);
1822 } else {
1823 UnimplementedInstruction();
1824 }
1825 break;
1826 }
1827 case 0x68:
1828 Print("push ");
1829 PrintImmediateValue(
1830 LoadUnaligned(reinterpret_cast<int32_t*>(data + 1)));
1831 data += 5;
1832 break;
1833
1834 case 0x6A:
1835 Print("push ");
1836 PrintImmediateValue(*reinterpret_cast<int8_t*>(data + 1));
1837 data += 2;
1838 break;
1839
1840 case 0xA1:
1841 FALL_THROUGH;
1842 case 0xA3:
1843 switch (operand_size()) {
1844 case DOUBLEWORD_SIZE: {
1845 PrintAddress(reinterpret_cast<uint8_t*>(
1846 *reinterpret_cast<int32_t*>(data + 1)));
1847 if (*data == 0xA1) { // Opcode 0xA1
1848 Print("movzxlq %s,(", Rax());
1849 PrintAddress(reinterpret_cast<uint8_t*>(
1850 *reinterpret_cast<int32_t*>(data + 1)));
1851 Print(")");
1852 } else { // Opcode 0xA3
1853 Print("movzxlq (");
1854 PrintAddress(reinterpret_cast<uint8_t*>(
1855 *reinterpret_cast<int32_t*>(data + 1)));
1856 Print("),%s", Rax());
1857 }
1858 data += 5;
1859 break;
1860 }
1861 case QUADWORD_SIZE: {
1862 // New x64 instruction mov rax,(imm_64).
1863 if (*data == 0xA1) { // Opcode 0xA1
1864 Print("movq %s,(", Rax());
1865 PrintAddress(*reinterpret_cast<uint8_t**>(data + 1));
1866 Print(")");
1867 } else { // Opcode 0xA3
1868 Print("movq (");
1869 PrintAddress(*reinterpret_cast<uint8_t**>(data + 1));
1870 Print("),%s", Rax());
1871 }
1872 data += 9;
1873 break;
1874 }
1875 default:
1876 UnimplementedInstruction();
1877 data += 2;
1878 }
1879 break;
1880
1881 case 0xA8:
1882 Print("test al,");
1883 PrintImmediateValue(*reinterpret_cast<uint8_t*>(data + 1));
1884 data += 2;
1885 break;
1886
1887 case 0xA9: {
1888 data++;
1889 Print("test%s %s,", operand_size_code(), Rax());
1890 data += PrintImmediate(data, operand_size());
1891 break;
1892 }
1893 case 0xD1:
1894 FALL_THROUGH;
1895 case 0xD3:
1896 FALL_THROUGH;
1897 case 0xC1:
1898 data += ShiftInstruction(data);
1899 break;
1900 case 0xD0:
1901 FALL_THROUGH;
1902 case 0xD2:
1903 FALL_THROUGH;
1904 case 0xC0:
1905 byte_size_operand_ = true;
1906 data += ShiftInstruction(data);
1907 break;
1908
1909 case 0xD9:
1910 FALL_THROUGH;
1911 case 0xDA:
1912 FALL_THROUGH;
1913 case 0xDB:
1914 FALL_THROUGH;
1915 case 0xDC:
1916 FALL_THROUGH;
1917 case 0xDD:
1918 FALL_THROUGH;
1919 case 0xDE:
1920 FALL_THROUGH;
1921 case 0xDF:
1922 data += FPUInstruction(data);
1923 break;
1924
1925 case 0xEB:
1926 data += JumpShort(data);
1927 break;
1928
1929 case 0xF6:
1930 byte_size_operand_ = true;
1931 FALL_THROUGH;
1932 case 0xF7:
1933 data += F6F7Instruction(data);
1934 break;
1935
1936 // These encodings for inc and dec are IA32 only, but we don't get here
1937 // on X64 - the REX prefix recoginizer catches them earlier.
1938 case 0x40:
1939 case 0x41:
1940 case 0x42:
1941 case 0x43:
1942 case 0x44:
1943 case 0x45:
1944 case 0x46:
1945 case 0x47:
1946 Print("inc %s", NameOfCPURegister(*data & 7));
1947 data += 1;
1948 break;
1949
1950 case 0x48:
1951 case 0x49:
1952 case 0x4a:
1953 case 0x4b:
1954 case 0x4c:
1955 case 0x4d:
1956 case 0x4e:
1957 case 0x4f:
1958 Print("dec %s", NameOfCPURegister(*data & 7));
1959 data += 1;
1960 break;
1961
1962#if defined(TARGET_ARCH_IA32)
1963 case 0x61:
1964 Print("popad");
1965 break;
1966
1967 case 0x60:
1968 Print("pushad");
1969 break;
1970#endif
1971
1972 default:
1973 UnimplementedInstruction();
1974 data += 1;
1975 }
1976 } // !processed
1977
1978 ASSERT(buffer_[buffer_pos_] == '\0');
1979
1980 int instr_len = data - reinterpret_cast<uint8_t*>(pc);
1981 ASSERT(instr_len > 0); // Ensure progress.
1982
1983 return instr_len;
1984}
1985
1986void Disassembler::DecodeInstruction(char* hex_buffer,
1987 intptr_t hex_size,
1988 char* human_buffer,
1989 intptr_t human_size,
1990 int* out_instr_len,
1991 const Code& code,
1992 Object** object,
1993 uword pc) {
1994 ASSERT(hex_size > 0);
1995 ASSERT(human_size > 0);
1996 DisassemblerX64 decoder(human_buffer, human_size);
1997 int instruction_length = decoder.InstructionDecode(pc);
1998 uint8_t* pc_ptr = reinterpret_cast<uint8_t*>(pc);
1999 int hex_index = 0;
2000 int remaining_size = hex_size - hex_index;
2001 for (int i = 0; (i < instruction_length) && (remaining_size > 2); ++i) {
2002 Utils::SNPrint(&hex_buffer[hex_index], remaining_size, "%02x", pc_ptr[i]);
2003 hex_index += 2;
2004 remaining_size -= 2;
2005 }
2006 hex_buffer[hex_index] = '\0';
2007 if (out_instr_len != nullptr) {
2008 *out_instr_len = instruction_length;
2009 }
2010
2011 *object = NULL;
2012#if defined(TARGET_ARCH_X64)
2013 if (!code.IsNull()) {
2014 *object = &Object::Handle();
2015 if (!DecodeLoadObjectFromPoolOrThread(pc, code, *object)) {
2016 *object = NULL;
2017 }
2018 }
2019#else
2020 if (!code.IsNull() && code.is_alive()) {
2021 intptr_t offsets_length = code.pointer_offsets_length();
2022 for (intptr_t i = 0; i < offsets_length; i++) {
2023 uword addr = code.GetPointerOffsetAt(i) + code.PayloadStart();
2024 if ((pc <= addr) && (addr < (pc + instruction_length))) {
2025 *object =
2026 &Object::Handle(LoadUnaligned(reinterpret_cast<ObjectPtr*>(addr)));
2027 break;
2028 }
2029 }
2030 }
2031#endif
2032}
2033
2034#endif // !defined(PRODUCT) || defined(FORCE_INCLUDE_DISASSEMBLER)
2035
2036} // namespace dart
2037
2038#endif // defined(TARGET_ARCH_X64) || defined (TARGET_ARCH_IA32)
2039