Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(8)

Side by Side Diff: runtime/vm/disassembler_x64.cc

Issue 10826248: Add X64 assembler. (Closed) Base URL: http://dart.googlecode.com/svn/branches/bleeding_edge/dart/
Patch Set: Created 8 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « runtime/vm/disassembler.cc ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS 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 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. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 #include "vm/disassembler.h" 5 #include "vm/disassembler.h"
6 6
7 #if !defined(_WIN32) // Disassembler is not yet supported under WIN32. 7 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32.
8 #include <errno.h>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <unistd.h>
12 #endif
13
14 #include "vm/globals.h" // Needed here to get TARGET_ARCH_X64.
15 #if defined(TARGET_ARCH_X64) 8 #if defined(TARGET_ARCH_X64)
16 #include "platform/assert.h" 9 #include "platform/utils.h"
10 #include "vm/allocation.h"
11 #include "vm/heap.h"
12 #include "vm/os.h"
13 #include "vm/stack_frame.h"
14 #include "vm/stub_code.h"
17 15
18 namespace dart { 16 namespace dart {
19 17
18
19 enum OperandType {
20 UNSET_OP_ORDER = 0,
21 // Operand size decides between 16, 32 and 64 bit operands.
22 REG_OPER_OP_ORDER = 1, // Register destination, operand source.
23 OPER_REG_OP_ORDER = 2, // Operand destination, register source.
24 // Fixed 8-bit operands.
25 BYTE_SIZE_OPERAND_FLAG = 4,
26 BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG,
27 BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
28 };
29
30 //------------------------------------------------------------------
31 // Tables
32 //------------------------------------------------------------------
33 struct ByteMnemonic {
34 int b; // -1 terminates, otherwise must be in range (0..255)
35 OperandType op_order_;
36 const char* mnem;
37 };
38
39
40 static const ByteMnemonic two_operands_instr[] = {
41 { 0x00, BYTE_OPER_REG_OP_ORDER, "add" },
42 { 0x01, OPER_REG_OP_ORDER, "add" },
43 { 0x02, BYTE_REG_OPER_OP_ORDER, "add" },
44 { 0x03, REG_OPER_OP_ORDER, "add" },
45 { 0x08, BYTE_OPER_REG_OP_ORDER, "or" },
46 { 0x09, OPER_REG_OP_ORDER, "or" },
47 { 0x0A, BYTE_REG_OPER_OP_ORDER, "or" },
48 { 0x0B, REG_OPER_OP_ORDER, "or" },
49 { 0x10, BYTE_OPER_REG_OP_ORDER, "adc" },
50 { 0x11, OPER_REG_OP_ORDER, "adc" },
51 { 0x12, BYTE_REG_OPER_OP_ORDER, "adc" },
52 { 0x13, REG_OPER_OP_ORDER, "adc" },
53 { 0x18, BYTE_OPER_REG_OP_ORDER, "sbb" },
54 { 0x19, OPER_REG_OP_ORDER, "sbb" },
55 { 0x1A, BYTE_REG_OPER_OP_ORDER, "sbb" },
56 { 0x1B, REG_OPER_OP_ORDER, "sbb" },
57 { 0x20, BYTE_OPER_REG_OP_ORDER, "and" },
58 { 0x21, OPER_REG_OP_ORDER, "and" },
59 { 0x22, BYTE_REG_OPER_OP_ORDER, "and" },
60 { 0x23, REG_OPER_OP_ORDER, "and" },
61 { 0x28, BYTE_OPER_REG_OP_ORDER, "sub" },
62 { 0x29, OPER_REG_OP_ORDER, "sub" },
63 { 0x2A, BYTE_REG_OPER_OP_ORDER, "sub" },
64 { 0x2B, REG_OPER_OP_ORDER, "sub" },
65 { 0x30, BYTE_OPER_REG_OP_ORDER, "xor" },
66 { 0x31, OPER_REG_OP_ORDER, "xor" },
67 { 0x32, BYTE_REG_OPER_OP_ORDER, "xor" },
68 { 0x33, REG_OPER_OP_ORDER, "xor" },
69 { 0x38, BYTE_OPER_REG_OP_ORDER, "cmp" },
70 { 0x39, OPER_REG_OP_ORDER, "cmp" },
71 { 0x3A, BYTE_REG_OPER_OP_ORDER, "cmp" },
72 { 0x3B, REG_OPER_OP_ORDER, "cmp" },
73 { 0x63, REG_OPER_OP_ORDER, "movsxlq" },
74 { 0x84, BYTE_REG_OPER_OP_ORDER, "test" },
75 { 0x85, REG_OPER_OP_ORDER, "test" },
76 { 0x86, BYTE_REG_OPER_OP_ORDER, "xchg" },
77 { 0x87, REG_OPER_OP_ORDER, "xchg" },
78 { 0x88, BYTE_OPER_REG_OP_ORDER, "mov" },
79 { 0x89, OPER_REG_OP_ORDER, "mov" },
80 { 0x8A, BYTE_REG_OPER_OP_ORDER, "mov" },
81 { 0x8B, REG_OPER_OP_ORDER, "mov" },
82 { 0x8D, REG_OPER_OP_ORDER, "lea" },
83 { -1, UNSET_OP_ORDER, "" }
84 };
85
86
87 static const ByteMnemonic zero_operands_instr[] = {
88 { 0xC3, UNSET_OP_ORDER, "ret" },
89 { 0xC9, UNSET_OP_ORDER, "leave" },
90 { 0xF4, UNSET_OP_ORDER, "hlt" },
91 { 0xFC, UNSET_OP_ORDER, "cld" },
92 { 0xCC, UNSET_OP_ORDER, "int3" },
93 { 0x60, UNSET_OP_ORDER, "pushad" },
94 { 0x61, UNSET_OP_ORDER, "popad" },
95 { 0x9C, UNSET_OP_ORDER, "pushfd" },
96 { 0x9D, UNSET_OP_ORDER, "popfd" },
97 { 0x9E, UNSET_OP_ORDER, "sahf" },
98 { 0x99, UNSET_OP_ORDER, "cdq" },
99 { 0x9B, UNSET_OP_ORDER, "fwait" },
100 { 0xA4, UNSET_OP_ORDER, "movs" },
101 { 0xA5, UNSET_OP_ORDER, "movs" },
102 { 0xA6, UNSET_OP_ORDER, "cmps" },
103 { 0xA7, UNSET_OP_ORDER, "cmps" },
104 { -1, UNSET_OP_ORDER, "" }
105 };
106
107
108 static const ByteMnemonic call_jump_instr[] = {
109 { 0xE8, UNSET_OP_ORDER, "call" },
110 { 0xE9, UNSET_OP_ORDER, "jmp" },
111 { -1, UNSET_OP_ORDER, "" }
112 };
113
114
115 static const ByteMnemonic short_immediate_instr[] = {
116 { 0x05, UNSET_OP_ORDER, "add" },
117 { 0x0D, UNSET_OP_ORDER, "or" },
118 { 0x15, UNSET_OP_ORDER, "adc" },
119 { 0x1D, UNSET_OP_ORDER, "sbb" },
120 { 0x25, UNSET_OP_ORDER, "and" },
121 { 0x2D, UNSET_OP_ORDER, "sub" },
122 { 0x35, UNSET_OP_ORDER, "xor" },
123 { 0x3D, UNSET_OP_ORDER, "cmp" },
124 { -1, UNSET_OP_ORDER, "" }
125 };
126
127
128 static const char* const conditional_code_suffix[] = {
129 "o", "no", "c", "nc", "z", "nz", "na", "a",
130 "s", "ns", "pe", "po", "l", "ge", "le", "g"
131 };
132
133
134 enum InstructionType {
135 NO_INSTR,
136 ZERO_OPERANDS_INSTR,
137 TWO_OPERANDS_INSTR,
138 JUMP_CONDITIONAL_SHORT_INSTR,
139 REGISTER_INSTR,
140 PUSHPOP_INSTR, // Has implicit 64-bit operand size.
141 MOVE_REG_INSTR,
142 CALL_JUMP_INSTR,
143 SHORT_IMMEDIATE_INSTR
144 };
145
146
147 enum Prefixes {
148 ESCAPE_PREFIX = 0x0F,
149 OPERAND_SIZE_OVERRIDE_PREFIX = 0x66,
150 ADDRESS_SIZE_OVERRIDE_PREFIX = 0x67,
151 REPNE_PREFIX = 0xF2,
152 REP_PREFIX = 0xF3,
153 REPEQ_PREFIX = REP_PREFIX
154 };
155
156
157 struct InstructionDesc {
158 const char* mnem;
159 InstructionType type;
160 OperandType op_order_;
161 bool byte_size_operation; // Fixed 8-bit operation.
162 };
163
164
165 class InstructionTable : public ValueObject {
166 public:
167 InstructionTable();
168 const InstructionDesc& Get(uint8_t x) const {
169 return instructions_[x];
170 }
171
172 private:
173 InstructionDesc instructions_[256];
174 void Clear();
175 void Init();
176 void CopyTable(const ByteMnemonic bm[], InstructionType type);
177 void SetTableRange(InstructionType type,
178 uint8_t start,
179 uint8_t end,
180 bool byte_size,
181 const char* mnem);
182 void AddJumpConditionalShort();
183
184 DISALLOW_COPY_AND_ASSIGN(InstructionTable);
185 };
186
187
188 InstructionTable::InstructionTable() {
189 Clear();
190 Init();
191 }
192
193
194 void InstructionTable::Clear() {
195 for (int i = 0; i < 256; i++) {
196 instructions_[i].mnem = "(bad)";
197 instructions_[i].type = NO_INSTR;
198 instructions_[i].op_order_ = UNSET_OP_ORDER;
199 instructions_[i].byte_size_operation = false;
200 }
201 }
202
203
204 void InstructionTable::Init() {
205 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
206 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
207 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
208 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
209 AddJumpConditionalShort();
210 SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push");
211 SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop");
212 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov");
213 }
214
215
216 void InstructionTable::CopyTable(const ByteMnemonic bm[],
217 InstructionType type) {
218 for (int i = 0; bm[i].b >= 0; i++) {
219 InstructionDesc* id = &instructions_[bm[i].b];
220 id->mnem = bm[i].mnem;
221 OperandType op_order = bm[i].op_order_;
222 id->op_order_ =
223 static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
224 ASSERT(NO_INSTR == id->type); // Information not already entered
225 id->type = type;
226 id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
227 }
228 }
229
230
231 void InstructionTable::SetTableRange(InstructionType type,
232 uint8_t start,
233 uint8_t end,
234 bool byte_size,
235 const char* mnem) {
236 for (uint8_t b = start; b <= end; b++) {
237 InstructionDesc* id = &instructions_[b];
238 ASSERT(NO_INSTR == id->type); // Information not already entered
239 id->mnem = mnem;
240 id->type = type;
241 id->byte_size_operation = byte_size;
242 }
243 }
244
245
246 void InstructionTable::AddJumpConditionalShort() {
247 for (uint8_t b = 0x70; b <= 0x7F; b++) {
248 InstructionDesc* id = &instructions_[b];
249 ASSERT(NO_INSTR == id->type); // Information not already entered
250 id->mnem = NULL; // Computed depending on condition code.
251 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
252 }
253 }
254
255
256 static InstructionTable instruction_table;
257
258
259 static InstructionDesc cmov_instructions[16] = {
260 {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
261 {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
262 {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
263 {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
264 {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
265 {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
266 {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
267 {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
268 {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
269 {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
270 {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
271 {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
272 {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
273 {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
274 {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
275 {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}
276 };
277
278
279 //-------------------------------------------------
280 // DisassemblerX64 implementation.
281
282
283 static const int kMaxXmmRegisters = 16;
284 static const char* xmm_regs[kMaxXmmRegisters] = {
285 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
286 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
287 };
288
289 class DisassemblerX64 : public ValueObject {
290 public:
291 DisassemblerX64(char* buffer, intptr_t buffer_size)
292 : buffer_(buffer),
293 buffer_size_(buffer_size),
294 buffer_pos_(0) {
295 buffer_[buffer_pos_] = '\0';
296 }
297
298 virtual ~DisassemblerX64() {
299 }
300
301 int InstructionDecode(uword pc);
302
303 private:
304 enum OperandSize {
305 BYTE_SIZE = 0,
306 WORD_SIZE = 1,
307 DOUBLEWORD_SIZE = 2,
308 QUADWORD_SIZE = 3
309 };
310
311 void setRex(uint8_t rex) {
312 ASSERT(0x40 == (rex & 0xF0));
313 rex_ = rex;
314 }
315
316 bool rex() { return rex_ != 0; }
317
318 bool rex_b() { return (rex_ & 0x01) != 0; }
319
320 // Actual number of base register given the low bits and the rex.b state.
321 int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); }
322
323 bool rex_x() { return (rex_ & 0x02) != 0; }
324
325 bool rex_r() { return (rex_ & 0x04) != 0; }
326
327 bool rex_w() { return (rex_ & 0x08) != 0; }
328
329 OperandSize operand_size() {
330 if (byte_size_operand_) return BYTE_SIZE;
331 if (rex_w()) return QUADWORD_SIZE;
332 if (operand_size_ != 0) return WORD_SIZE;
333 return DOUBLEWORD_SIZE;
334 }
335
336 char operand_size_code() {
337 return "bwlq"[operand_size()];
338 }
339
340 // Disassembler helper functions.
341 void get_modrm(uint8_t data,
342 int* mod,
343 int* regop,
344 int* rm) {
345 *mod = (data >> 6) & 3;
346 *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0);
347 *rm = (data & 7) | (rex_b() ? 8 : 0);
348 }
349
350 void get_sib(uint8_t data,
351 int* scale,
352 int* index,
353 int* base) {
354 *scale = (data >> 6) & 3;
355 *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
356 *base = (data & 7) | (rex_b() ? 8 : 0);
357 }
358
359 const char* NameOfCPURegister(int reg) const {
360 return Assembler::RegisterName(static_cast<Register>(reg));
361 }
362
363 const char* NameOfByteCPURegister(int reg) const {
364 return NameOfCPURegister(reg);
365 }
366
367 const char* NameOfXMMRegister(int reg) const {
368 ASSERT((0 <= reg) && (reg < kMaxXmmRegisters));
369 return xmm_regs[reg];
370 }
371
372 void AppendToBuffer(const char* format, ...);
373 void AppendAddressToBuffer(uint8_t* addr);
374
375 int PrintOperands(const char* mnem,
376 OperandType op_order,
377 uint8_t* data);
378
379 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const;
380
381 int PrintRightOperandHelper(uint8_t* modrmp,
382 RegisterNameMapping register_name);
383 int PrintRightOperand(uint8_t* modrmp);
384 int PrintRightByteOperand(uint8_t* modrmp);
385 int PrintRightXMMOperand(uint8_t* modrmp);
386 int PrintImmediate(uint8_t* data, OperandSize size);
387 int PrintImmediateOp(uint8_t* data);
388 const char* TwoByteMnemonic(uint8_t opcode);
389 int TwoByteOpcodeInstruction(uint8_t* data);
390
391 int F6F7Instruction(uint8_t* data);
392 int ShiftInstruction(uint8_t* data);
393 int JumpShort(uint8_t* data);
394 int JumpConditional(uint8_t* data);
395 int JumpConditionalShort(uint8_t* data);
396 int SetCC(uint8_t* data);
397 int FPUInstruction(uint8_t* data);
398 int MemoryFPUInstruction(int escape_opcode, int regop, uint8_t* modrm_start);
399 int RegisterFPUInstruction(int escape_opcode, uint8_t modrm_byte);
400
401 bool DecodeInstructionType(const InstructionDesc& idesc, uint8_t** data);
402
403 void UnimplementedInstruction() {
404 AppendToBuffer("'Unimplemented Instruction'");
405 }
406
407 char* buffer_; // Decode instructions into this buffer.
408 intptr_t buffer_size_; // The size of the buffer_.
409 intptr_t buffer_pos_; // Current character position in the buffer_.
410
411 // Prefixes parsed
412 uint8_t rex_;
413 uint8_t operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0.
414 // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
415 uint8_t group_1_prefix_;
416 // Byte size operand override.
417 bool byte_size_operand_;
418
419 DISALLOW_COPY_AND_ASSIGN(DisassemblerX64);
420 };
421
422
423 // Append the str to the output buffer.
424 void DisassemblerX64::AppendToBuffer(const char* format, ...) {
425 char* buf = buffer_ + buffer_pos_;
426 va_list args;
427 va_start(args, format);
428 int retval = OS::VSNPrint(buf, buffer_size_, format, args);
429 va_end(args);
430 buffer_pos_ += retval;
431 }
432
433
434 int DisassemblerX64::PrintRightOperandHelper(
435 uint8_t* modrmp,
436 RegisterNameMapping direct_register_name) {
437 int mod, regop, rm;
438 get_modrm(*modrmp, &mod, &regop, &rm);
439 RegisterNameMapping register_name = (mod == 3) ? direct_register_name :
440 &DisassemblerX64::NameOfCPURegister;
441 switch (mod) {
442 case 0:
443 if ((rm & 7) == 5) {
444 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1);
445 AppendToBuffer("[0x%x]", disp);
446 return 5;
447 } else if ((rm & 7) == 4) {
448 // Codes for SIB byte.
449 uint8_t sib = *(modrmp + 1);
450 int scale, index, base;
451 get_sib(sib, &scale, &index, &base);
452 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
453 // index == rsp means no index. Only use sib byte with no index for
454 // rsp and r12 base.
455 AppendToBuffer("[%s]", NameOfCPURegister(base));
456 return 2;
457 } else if (base == 5) {
458 // base == rbp means no base register (when mod == 0).
459 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
460 AppendToBuffer("[%s*%d+0x%x]",
461 NameOfCPURegister(index),
462 1 << scale, disp);
463 return 6;
464 } else if (index != 4 && base != 5) {
465 // [base+index*scale]
466 AppendToBuffer("[%s+%s*%d]",
467 NameOfCPURegister(base),
468 NameOfCPURegister(index),
469 1 << scale);
470 return 2;
471 } else {
472 UnimplementedInstruction();
473 return 1;
474 }
475 } else {
476 AppendToBuffer("[%s]", NameOfCPURegister(rm));
477 return 1;
478 }
479 break;
480 case 1: // fall through
481 case 2:
482 if ((rm & 7) == 4) {
483 uint8_t sib = *(modrmp + 1);
484 int scale, index, base;
485 get_sib(sib, &scale, &index, &base);
486 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2)
487 : *reinterpret_cast<char*>(modrmp + 2);
488 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
489 if (-disp > 0) {
490 AppendToBuffer("[%s-0x%x]", NameOfCPURegister(base), -disp);
491 } else {
492 AppendToBuffer("[%s+0x%x]", NameOfCPURegister(base), disp);
493 }
494 } else {
495 if (-disp > 0) {
496 AppendToBuffer("[%s+%s*%d-0x%x]",
497 NameOfCPURegister(base),
498 NameOfCPURegister(index),
499 1 << scale,
500 -disp);
501 } else {
502 AppendToBuffer("[%s+%s*%d+0x%x]",
503 NameOfCPURegister(base),
504 NameOfCPURegister(index),
505 1 << scale,
506 disp);
507 }
508 }
509 return mod == 2 ? 6 : 3;
510 } else {
511 // No sib.
512 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1)
513 : *reinterpret_cast<char*>(modrmp + 1);
514 if (-disp > 0) {
515 AppendToBuffer("[%s-0x%x]", NameOfCPURegister(rm), -disp);
516 } else {
517 AppendToBuffer("[%s+0x%x]", NameOfCPURegister(rm), disp);
518 }
519 return (mod == 2) ? 5 : 2;
520 }
521 break;
522 case 3:
523 AppendToBuffer("%s", (this->*register_name)(rm));
524 return 1;
525 default:
526 UnimplementedInstruction();
527 return 1;
528 }
529 UNREACHABLE();
530 }
531
532
533 int DisassemblerX64::PrintImmediate(uint8_t* data, OperandSize size) {
534 int64_t value;
535 int count;
536 switch (size) {
537 case BYTE_SIZE:
538 value = *data;
539 count = 1;
540 break;
541 case WORD_SIZE:
542 value = *reinterpret_cast<int16_t*>(data);
543 count = 2;
544 break;
545 case DOUBLEWORD_SIZE:
546 value = *reinterpret_cast<uint32_t*>(data);
547 count = 4;
548 break;
549 case QUADWORD_SIZE:
550 value = *reinterpret_cast<int32_t*>(data);
551 count = 4;
552 break;
553 default:
554 UNREACHABLE();
555 value = 0; // Initialize variables on all paths to satisfy the compiler.
556 count = 0;
557 }
558 AppendToBuffer("%" PRIxPTR "", value);
559 return count;
560 }
561
562
563 // Returns number of bytes used by machine instruction, including *data byte.
564 // Writes immediate instructions to 'tmp_buffer_'.
565 int DisassemblerX64::PrintImmediateOp(uint8_t* data) {
566 bool byte_size_immediate = (*data & 0x02) != 0;
567 uint8_t modrm = *(data + 1);
568 int mod, regop, rm;
569 get_modrm(modrm, &mod, &regop, &rm);
570 const char* mnem = "Imm???";
571 switch (regop) {
572 case 0:
573 mnem = "add";
574 break;
575 case 1:
576 mnem = "or";
577 break;
578 case 2:
579 mnem = "adc";
580 break;
581 case 3:
582 mnem = "sbb";
583 break;
584 case 4:
585 mnem = "and";
586 break;
587 case 5:
588 mnem = "sub";
589 break;
590 case 6:
591 mnem = "xor";
592 break;
593 case 7:
594 mnem = "cmp";
595 break;
596 default:
597 UnimplementedInstruction();
598 }
599 AppendToBuffer("%s%c ", mnem, operand_size_code());
600 int count = PrintRightOperand(data + 1);
601 AppendToBuffer(",0x");
602 OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size();
603 count += PrintImmediate(data + 1 + count, immediate_size);
604 return 1 + count;
605 }
606
607
608 // Returns number of bytes used, including *data.
609 int DisassemblerX64::F6F7Instruction(uint8_t* data) {
610 ASSERT(*data == 0xF7 || *data == 0xF6);
611 uint8_t modrm = *(data + 1);
612 int mod, regop, rm;
613 get_modrm(modrm, &mod, &regop, &rm);
614 if (mod == 3 && regop != 0) {
615 const char* mnem = NULL;
616 switch (regop) {
617 case 2:
618 mnem = "not";
619 break;
620 case 3:
621 mnem = "neg";
622 break;
623 case 4:
624 mnem = "mul";
625 break;
626 case 7:
627 mnem = "idiv";
628 break;
629 default:
630 UnimplementedInstruction();
631 }
632 AppendToBuffer("%s%c %s",
633 mnem,
634 operand_size_code(),
635 NameOfCPURegister(rm));
636 return 2;
637 } else if (regop == 0) {
638 AppendToBuffer("test%c ", operand_size_code());
639 int count = PrintRightOperand(data + 1); // Use name of 64-bit register.
640 AppendToBuffer(",0x");
641 count += PrintImmediate(data + 1 + count, operand_size());
642 return 1 + count;
643 } else {
644 UnimplementedInstruction();
645 return 2;
646 }
647 }
648
649
650 int DisassemblerX64::ShiftInstruction(uint8_t* data) {
651 uint8_t op = *data & (~1);
652 if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
653 UnimplementedInstruction();
654 return 1;
655 }
656 uint8_t modrm = *(data + 1);
657 int mod, regop, rm;
658 get_modrm(modrm, &mod, &regop, &rm);
659 regop &= 0x7; // The REX.R bit does not affect the operation.
660 int imm8 = -1;
661 int num_bytes = 2;
662 if (mod != 3) {
663 UnimplementedInstruction();
664 return num_bytes;
665 }
666 const char* mnem = NULL;
667 switch (regop) {
668 case 0:
669 mnem = "rol";
670 break;
671 case 1:
672 mnem = "ror";
673 break;
674 case 2:
675 mnem = "rcl";
676 break;
677 case 3:
678 mnem = "rcr";
679 break;
680 case 4:
681 mnem = "shl";
682 break;
683 case 5:
684 mnem = "shr";
685 break;
686 case 7:
687 mnem = "sar";
688 break;
689 default:
690 UnimplementedInstruction();
691 return num_bytes;
692 }
693 ASSERT(NULL != mnem);
694 if (op == 0xD0) {
695 imm8 = 1;
696 } else if (op == 0xC0) {
697 imm8 = *(data + 2);
698 num_bytes = 3;
699 }
700 AppendToBuffer("%s%c %s,",
701 mnem,
702 operand_size_code(),
703 byte_size_operand_ ? NameOfByteCPURegister(rm)
704 : NameOfCPURegister(rm));
705 if (op == 0xD2) {
706 AppendToBuffer("cl");
707 } else {
708 AppendToBuffer("%d", imm8);
709 }
710 return num_bytes;
711 }
712
713
714 int DisassemblerX64::PrintRightOperand(uint8_t* modrmp) {
715 return PrintRightOperandHelper(modrmp,
716 &DisassemblerX64::NameOfCPURegister);
717 }
718
719
720 int DisassemblerX64::PrintRightByteOperand(uint8_t* modrmp) {
721 return PrintRightOperandHelper(modrmp,
722 &DisassemblerX64::NameOfByteCPURegister);
723 }
724
725
726 int DisassemblerX64::PrintRightXMMOperand(uint8_t* modrmp) {
727 return PrintRightOperandHelper(modrmp,
728 &DisassemblerX64::NameOfXMMRegister);
729 }
730
731
732 // Returns number of bytes used including the current *data.
733 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
734 int DisassemblerX64::PrintOperands(const char* mnem,
735 OperandType op_order,
736 uint8_t* data) {
737 uint8_t modrm = *data;
738 int mod, regop, rm;
739 get_modrm(modrm, &mod, &regop, &rm);
740 int advance = 0;
741 const char* register_name =
742 byte_size_operand_ ? NameOfByteCPURegister(regop)
743 : NameOfCPURegister(regop);
744 switch (op_order) {
745 case REG_OPER_OP_ORDER: {
746 AppendToBuffer("%s%c %s,",
747 mnem,
748 operand_size_code(),
749 register_name);
750 advance = byte_size_operand_ ? PrintRightByteOperand(data)
751 : PrintRightOperand(data);
752 break;
753 }
754 case OPER_REG_OP_ORDER: {
755 AppendToBuffer("%s%c ", mnem, operand_size_code());
756 advance = byte_size_operand_ ? PrintRightByteOperand(data)
757 : PrintRightOperand(data);
758 AppendToBuffer(",%s", register_name);
759 break;
760 }
761 default:
762 UNREACHABLE();
763 break;
764 }
765 return advance;
766 }
767
768
769 void DisassemblerX64::AppendAddressToBuffer(uint8_t* addr_byte_ptr) {
770 NoGCScope no_gc;
771 uword addr = reinterpret_cast<uword>(addr_byte_ptr);
772 AppendToBuffer("0x%0" PRIxPTR "", addr);
773 // Try to print as heap object or stub name
774 if (!Isolate::Current()->heap()->CodeContains(addr) &&
775 Isolate::Current()->heap()->Contains(addr - kHeapObjectTag)) {
776 Object& obj = Object::Handle(reinterpret_cast<RawObject*>(addr));
777 if (obj.IsArray()) {
778 const Array& arr = Array::CheckedHandle(obj.raw());
779 intptr_t len = arr.Length();
780 if (len > 5) len = 5; // Print a max of 5 elements.
781 AppendToBuffer(" Array[");
782 int i = 0;
783 while (i < len) {
784 obj = arr.At(i);
785 if (i > 0) AppendToBuffer(", ");
786 AppendToBuffer(obj.ToCString());
787 i++;
788 }
789 if (i < arr.Length()) AppendToBuffer(", ...");
790 AppendToBuffer("]");
791 return;
792 }
793 AppendToBuffer(" '%s'", obj.ToCString());
794 } else {
795 // 'addr' is not an object, but probably a code address.
796 const char* name_of_stub = StubCode::NameOfStub(addr);
797 if (name_of_stub != NULL) {
798 AppendToBuffer(" [stub: %s]", name_of_stub);
799 } else {
800 // Print only if jumping to entry point.
801 const Code& code = Code::Handle(Code::LookupCode(addr));
802 if (!code.IsNull() && (code.EntryPoint() == addr)) {
803 const Function& function = Function::Handle(code.function());
804 if (function.IsNull()) {
805 AppendToBuffer(" [ stub ]");
806 } else {
807 const char* name_of_function = function.ToFullyQualifiedCString();
808 AppendToBuffer(" [%s]", name_of_function);
809 }
810 }
811 }
812 }
813 }
814
815
816 // Returns number of bytes used, including *data.
817 int DisassemblerX64::JumpShort(uint8_t* data) {
818 ASSERT(0xEB == *data);
819 uint8_t b = *(data + 1);
820 uint8_t* dest = data + static_cast<int8_t>(b) + 2;
821 AppendToBuffer("jmp ");
822 AppendAddressToBuffer(dest);
823 return 2;
824 }
825
826
827 // Returns number of bytes used, including *data.
828 int DisassemblerX64::JumpConditional(uint8_t* data) {
829 ASSERT(0x0F == *data);
830 uint8_t cond = *(data + 1) & 0x0F;
831 uint8_t* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6;
832 const char* mnem = conditional_code_suffix[cond];
833 AppendToBuffer("j%s ", mnem);
834 AppendAddressToBuffer(dest);
835 return 6; // includes 0x0F
836 }
837
838
839 // Returns number of bytes used, including *data.
840 int DisassemblerX64::JumpConditionalShort(uint8_t* data) {
841 uint8_t cond = *data & 0x0F;
842 uint8_t b = *(data + 1);
843 uint8_t* dest = data + static_cast<uint8_t>(b) + 2;
844 const char* mnem = conditional_code_suffix[cond];
845 AppendToBuffer("j%s ", mnem);
846 AppendAddressToBuffer(dest);
847 return 2;
848 }
849
850
851 // Returns number of bytes used, including *data.
852 int DisassemblerX64::SetCC(uint8_t* data) {
853 ASSERT(0x0F == *data);
854 uint8_t cond = *(data + 1) & 0x0F;
855 const char* mnem = conditional_code_suffix[cond];
856 AppendToBuffer("set%s%c ", mnem, operand_size_code());
857 PrintRightByteOperand(data + 2);
858 return 3; // includes 0x0F
859 }
860
861
862 // Returns number of bytes used, including *data.
863 int DisassemblerX64::FPUInstruction(uint8_t* data) {
864 uint8_t escape_opcode = *data;
865 ASSERT(0xD8 == (escape_opcode & 0xF8));
866 uint8_t modrm_byte = *(data+1);
867
868 if (modrm_byte >= 0xC0) {
869 return RegisterFPUInstruction(escape_opcode, modrm_byte);
870 } else {
871 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
872 }
873 }
874
875
876 int DisassemblerX64::MemoryFPUInstruction(int escape_opcode,
877 int modrm_byte,
878 uint8_t* modrm_start) {
879 const char* mnem = "?";
880 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
881 switch (escape_opcode) {
882 case 0xD9: switch (regop) {
883 case 0: mnem = "fld_s"; break;
884 case 3: mnem = "fstp_s"; break;
885 case 7: mnem = "fstcw"; break;
886 default: UnimplementedInstruction();
887 }
888 break;
889
890 case 0xDB: switch (regop) {
891 case 0: mnem = "fild_s"; break;
892 case 1: mnem = "fisttp_s"; break;
893 case 2: mnem = "fist_s"; break;
894 case 3: mnem = "fistp_s"; break;
895 default: UnimplementedInstruction();
896 }
897 break;
898
899 case 0xDD: switch (regop) {
900 case 0: mnem = "fld_d"; break;
901 case 3: mnem = "fstp_d"; break;
902 default: UnimplementedInstruction();
903 }
904 break;
905
906 case 0xDF: switch (regop) {
907 case 5: mnem = "fild_d"; break;
908 case 7: mnem = "fistp_d"; break;
909 default: UnimplementedInstruction();
910 }
911 break;
912
913 default: UnimplementedInstruction();
914 }
915 AppendToBuffer("%s ", mnem);
916 int count = PrintRightOperand(modrm_start);
917 return count + 1;
918 }
919
920 int DisassemblerX64::RegisterFPUInstruction(int escape_opcode,
921 uint8_t modrm_byte) {
922 bool has_register = false; // Is the FPU register encoded in modrm_byte?
923 const char* mnem = "?";
924
925 switch (escape_opcode) {
926 case 0xD8:
927 UnimplementedInstruction();
928 break;
929
930 case 0xD9:
931 switch (modrm_byte & 0xF8) {
932 case 0xC0:
933 mnem = "fld";
934 has_register = true;
935 break;
936 case 0xC8:
937 mnem = "fxch";
938 has_register = true;
939 break;
940 default:
941 switch (modrm_byte) {
942 case 0xE0: mnem = "fchs"; break;
943 case 0xE1: mnem = "fabs"; break;
944 case 0xE3: mnem = "fninit"; break;
945 case 0xE4: mnem = "ftst"; break;
946 case 0xE8: mnem = "fld1"; break;
947 case 0xEB: mnem = "fldpi"; break;
948 case 0xED: mnem = "fldln2"; break;
949 case 0xEE: mnem = "fldz"; break;
950 case 0xF0: mnem = "f2xm1"; break;
951 case 0xF1: mnem = "fyl2x"; break;
952 case 0xF2: mnem = "fptan"; break;
953 case 0xF5: mnem = "fprem1"; break;
954 case 0xF7: mnem = "fincstp"; break;
955 case 0xF8: mnem = "fprem"; break;
956 case 0xFD: mnem = "fscale"; break;
957 case 0xFE: mnem = "fsin"; break;
958 case 0xFF: mnem = "fcos"; break;
959 default: UnimplementedInstruction();
960 }
961 }
962 break;
963
964 case 0xDA:
965 if (modrm_byte == 0xE9) {
966 mnem = "fucompp";
967 } else {
968 UnimplementedInstruction();
969 }
970 break;
971
972 case 0xDB:
973 if ((modrm_byte & 0xF8) == 0xE8) {
974 mnem = "fucomi";
975 has_register = true;
976 } else if (modrm_byte == 0xE2) {
977 mnem = "fclex";
978 } else {
979 UnimplementedInstruction();
980 }
981 break;
982
983 case 0xDC:
984 has_register = true;
985 switch (modrm_byte & 0xF8) {
986 case 0xC0: mnem = "fadd"; break;
987 case 0xE8: mnem = "fsub"; break;
988 case 0xC8: mnem = "fmul"; break;
989 case 0xF8: mnem = "fdiv"; break;
990 default: UnimplementedInstruction();
991 }
992 break;
993
994 case 0xDD:
995 has_register = true;
996 switch (modrm_byte & 0xF8) {
997 case 0xC0: mnem = "ffree"; break;
998 case 0xD8: mnem = "fstp"; break;
999 default: UnimplementedInstruction();
1000 }
1001 break;
1002
1003 case 0xDE:
1004 if (modrm_byte == 0xD9) {
1005 mnem = "fcompp";
1006 } else {
1007 has_register = true;
1008 switch (modrm_byte & 0xF8) {
1009 case 0xC0: mnem = "faddp"; break;
1010 case 0xE8: mnem = "fsubp"; break;
1011 case 0xC8: mnem = "fmulp"; break;
1012 case 0xF8: mnem = "fdivp"; break;
1013 default: UnimplementedInstruction();
1014 }
1015 }
1016 break;
1017
1018 case 0xDF:
1019 if (modrm_byte == 0xE0) {
1020 mnem = "fnstsw_ax";
1021 } else if ((modrm_byte & 0xF8) == 0xE8) {
1022 mnem = "fucomip";
1023 has_register = true;
1024 }
1025 break;
1026
1027 default: UnimplementedInstruction();
1028 }
1029
1030 if (has_register) {
1031 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
1032 } else {
1033 AppendToBuffer("%s", mnem);
1034 }
1035 return 2;
1036 }
1037
1038
1039 // TODO(srdjan): Should we add a branch hint argument?
1040 bool DisassemblerX64::DecodeInstructionType(const InstructionDesc& idesc,
1041 uint8_t** data) {
1042 uint8_t current = **data;
1043 switch (idesc.type) {
1044 case ZERO_OPERANDS_INSTR:
1045 if (current >= 0xA4 && current <= 0xA7) {
1046 // String move or compare operations.
1047 if (group_1_prefix_ == REP_PREFIX) {
1048 // REP.
1049 AppendToBuffer("rep ");
1050 }
1051 // TODO(srdjan): Should we enable printing of REX.W?
1052 // if (rex_w()) AppendToBuffer("REX.W ");
1053 AppendToBuffer("%s%c", idesc.mnem, operand_size_code());
1054 } else {
1055 AppendToBuffer("%s", idesc.mnem, operand_size_code());
1056 }
1057 (*data)++;
1058 break;
1059
1060 case TWO_OPERANDS_INSTR:
1061 (*data)++;
1062 (*data) += PrintOperands(idesc.mnem, idesc.op_order_, *data);
1063 break;
1064
1065 case JUMP_CONDITIONAL_SHORT_INSTR:
1066 (*data) += JumpConditionalShort(*data);
1067 break;
1068
1069 case REGISTER_INSTR:
1070 AppendToBuffer("%s%c %s",
1071 idesc.mnem,
1072 operand_size_code(),
1073 NameOfCPURegister(base_reg(current & 0x07)));
1074 (*data)++;
1075 break;
1076 case PUSHPOP_INSTR:
1077 AppendToBuffer("%s %s",
1078 idesc.mnem,
1079 NameOfCPURegister(base_reg(current & 0x07)));
1080 (*data)++;
1081 break;
1082 case MOVE_REG_INSTR: {
1083 uint8_t* addr = NULL;
1084 switch (operand_size()) {
1085 case WORD_SIZE:
1086 addr = reinterpret_cast<uint8_t*>(
1087 *reinterpret_cast<int16_t*>(*data + 1));
1088 (*data) += 3;
1089 break;
1090 case DOUBLEWORD_SIZE:
1091 addr = reinterpret_cast<uint8_t*>(
1092 *reinterpret_cast<int32_t*>(*data + 1));
1093 (*data) += 5;
1094 break;
1095 case QUADWORD_SIZE:
1096 addr = reinterpret_cast<uint8_t*>(
1097 *reinterpret_cast<int64_t*>(*data + 1));
1098 (*data) += 9;
1099 break;
1100 default:
1101 UNREACHABLE();
1102 }
1103 AppendToBuffer("mov%c %s,",
1104 operand_size_code(),
1105 NameOfCPURegister(base_reg(current & 0x07)));
1106 AppendAddressToBuffer(addr);
1107 break;
1108 }
1109
1110 case CALL_JUMP_INSTR: {
1111 uint8_t* addr = *data + *reinterpret_cast<int32_t*>(*data + 1) + 5;
1112 AppendToBuffer("%s ", idesc.mnem);
1113 AppendAddressToBuffer(addr);
1114 (*data) += 5;
1115 break;
1116 }
1117
1118 case SHORT_IMMEDIATE_INSTR: {
1119 uint8_t* addr =
1120 reinterpret_cast<uint8_t*>(*reinterpret_cast<int32_t*>(*data + 1));
1121 AppendToBuffer("%s rax, ", idesc.mnem);
1122 AppendAddressToBuffer(addr);
1123 (*data) += 5;
1124 break;
1125 }
1126
1127 case NO_INSTR:
1128 return false;
1129
1130 default:
1131 UNIMPLEMENTED(); // This type is not implemented.
1132 }
1133 return true;
1134 }
1135
1136
1137 // Handle all two-byte opcodes, which start with 0x0F.
1138 // These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
1139 // We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
1140 int DisassemblerX64::TwoByteOpcodeInstruction(uint8_t* data) {
1141 uint8_t opcode = *(data + 1);
1142 uint8_t* current = data + 2;
1143 // At return, "current" points to the start of the next instruction.
1144 const char* mnemonic = TwoByteMnemonic(opcode);
1145 if (operand_size_ == 0x66) {
1146 // 0x66 0x0F prefix.
1147 int mod, regop, rm;
1148 if (opcode == 0x3A) {
1149 uint8_t third_byte = *current;
1150 current = data + 3;
1151 if (third_byte == 0x17) {
1152 get_modrm(*current, &mod, &regop, &rm);
1153 AppendToBuffer("extractps "); // reg/m32, xmm, imm8
1154 current += PrintRightOperand(current);
1155 AppendToBuffer(", %s, %d", NameOfCPURegister(regop), (*current) & 3);
1156 current += 1;
1157 } else if (third_byte == 0x0b) {
1158 get_modrm(*current, &mod, &regop, &rm);
1159 // roundsd xmm, xmm/m64, imm8
1160 AppendToBuffer("roundsd %s, ", NameOfCPURegister(regop));
1161 current += PrintRightOperand(current);
1162 AppendToBuffer(", %d", (*current) & 3);
1163 current += 1;
1164 } else {
1165 UnimplementedInstruction();
1166 }
1167 } else {
1168 get_modrm(*current, &mod, &regop, &rm);
1169 if (opcode == 0x1f) {
1170 current++;
1171 if (rm == 4) { // SIB byte present.
1172 current++;
1173 }
1174 if (mod == 1) { // Byte displacement.
1175 current += 1;
1176 } else if (mod == 2) { // 32-bit displacement.
1177 current += 4;
1178 } // else no immediate displacement.
1179 AppendToBuffer("nop");
1180 } else if (opcode == 0x28) {
1181 AppendToBuffer("movapd %s, ", NameOfXMMRegister(regop));
1182 current += PrintRightXMMOperand(current);
1183 } else if (opcode == 0x29) {
1184 AppendToBuffer("movapd ");
1185 current += PrintRightXMMOperand(current);
1186 AppendToBuffer(", %s", NameOfXMMRegister(regop));
1187 } else if (opcode == 0x6E) {
1188 AppendToBuffer("mov%c %s,",
1189 rex_w() ? 'q' : 'd',
1190 NameOfXMMRegister(regop));
1191 current += PrintRightOperand(current);
1192 } else if (opcode == 0x6F) {
1193 AppendToBuffer("movdqa %s,",
1194 NameOfXMMRegister(regop));
1195 current += PrintRightXMMOperand(current);
1196 } else if (opcode == 0x7E) {
1197 AppendToBuffer("mov%c ",
1198 rex_w() ? 'q' : 'd');
1199 current += PrintRightOperand(current);
1200 AppendToBuffer(", %s", NameOfXMMRegister(regop));
1201 } else if (opcode == 0x7F) {
1202 AppendToBuffer("movdqa ");
1203 current += PrintRightXMMOperand(current);
1204 AppendToBuffer(", %s", NameOfXMMRegister(regop));
1205 } else if (opcode == 0xD6) {
1206 AppendToBuffer("movq ");
1207 current += PrintRightXMMOperand(current);
1208 AppendToBuffer(", %s", NameOfXMMRegister(regop));
1209 } else if (opcode == 0x50) {
1210 AppendToBuffer("movmskpd %s,", NameOfCPURegister(regop));
1211 current += PrintRightXMMOperand(current);
1212 } else {
1213 const char* mnemonic = "?";
1214 if (opcode == 0x54) {
1215 mnemonic = "andpd";
1216 } else if (opcode == 0x56) {
1217 mnemonic = "orpd";
1218 } else if (opcode == 0x57) {
1219 mnemonic = "xorpd";
1220 } else if (opcode == 0x2E) {
1221 mnemonic = "ucomisd";
1222 } else if (opcode == 0x2F) {
1223 mnemonic = "comisd";
1224 } else {
1225 UnimplementedInstruction();
1226 }
1227 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1228 current += PrintRightXMMOperand(current);
1229 }
1230 }
1231 } else if (group_1_prefix_ == 0xF2) {
1232 // Beginning of instructions with prefix 0xF2.
1233
1234 if (opcode == 0x11 || opcode == 0x10) {
1235 // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
1236 AppendToBuffer("movsd ");
1237 int mod, regop, rm;
1238 get_modrm(*current, &mod, &regop, &rm);
1239 if (opcode == 0x11) {
1240 current += PrintRightXMMOperand(current);
1241 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1242 } else {
1243 AppendToBuffer("%s,", NameOfXMMRegister(regop));
1244 current += PrintRightXMMOperand(current);
1245 }
1246 } else if (opcode == 0x2A) {
1247 // CVTSI2SD: integer to XMM double conversion.
1248 int mod, regop, rm;
1249 get_modrm(*current, &mod, &regop, &rm);
1250 AppendToBuffer("%sd %s,", mnemonic, NameOfXMMRegister(regop));
1251 current += PrintRightOperand(current);
1252 } else if (opcode == 0x2C) {
1253 // CVTTSD2SI:
1254 // Convert with truncation scalar double-precision FP to integer.
1255 int mod, regop, rm;
1256 get_modrm(*current, &mod, &regop, &rm);
1257 AppendToBuffer("cvttsd2si%c %s,",
1258 operand_size_code(), NameOfCPURegister(regop));
1259 current += PrintRightXMMOperand(current);
1260 } else if (opcode == 0x2D) {
1261 // CVTSD2SI: Convert scalar double-precision FP to integer.
1262 int mod, regop, rm;
1263 get_modrm(*current, &mod, &regop, &rm);
1264 AppendToBuffer("cvtsd2si%c %s,",
1265 operand_size_code(), NameOfCPURegister(regop));
1266 current += PrintRightXMMOperand(current);
1267 } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) {
1268 // XMM arithmetic. Mnemonic was retrieved at the start of this function.
1269 int mod, regop, rm;
1270 get_modrm(*current, &mod, &regop, &rm);
1271 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1272 current += PrintRightXMMOperand(current);
1273 } else {
1274 UnimplementedInstruction();
1275 }
1276 } else if (group_1_prefix_ == 0xF3) {
1277 // Instructions with prefix 0xF3.
1278 if (opcode == 0x11 || opcode == 0x10) {
1279 // MOVSS: Move scalar double-precision fp to/from/between XMM registers.
1280 AppendToBuffer("movss ");
1281 int mod, regop, rm;
1282 get_modrm(*current, &mod, &regop, &rm);
1283 if (opcode == 0x11) {
1284 current += PrintRightOperand(current);
1285 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1286 } else {
1287 AppendToBuffer("%s,", NameOfXMMRegister(regop));
1288 current += PrintRightOperand(current);
1289 }
1290 } else if (opcode == 0x2A) {
1291 // CVTSI2SS: integer to XMM single conversion.
1292 int mod, regop, rm;
1293 get_modrm(*current, &mod, &regop, &rm);
1294 AppendToBuffer("%ss %s,", mnemonic, NameOfXMMRegister(regop));
1295 current += PrintRightOperand(current);
1296 } else if (opcode == 0x2C) {
1297 // CVTTSS2SI:
1298 // Convert with truncation scalar single-precision FP to dword integer.
1299 int mod, regop, rm;
1300 get_modrm(*current, &mod, &regop, &rm);
1301 AppendToBuffer("cvttss2si%c %s,",
1302 operand_size_code(), NameOfCPURegister(regop));
1303 current += PrintRightXMMOperand(current);
1304 } else if (opcode == 0x5A) {
1305 // CVTSS2SD:
1306 // Convert scalar single-precision FP to scalar double-precision FP.
1307 int mod, regop, rm;
1308 get_modrm(*current, &mod, &regop, &rm);
1309 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop));
1310 current += PrintRightXMMOperand(current);
1311 } else if (opcode == 0x7E) {
1312 int mod, regop, rm;
1313 get_modrm(*current, &mod, &regop, &rm);
1314 AppendToBuffer("movq %s, ", NameOfXMMRegister(regop));
1315 current += PrintRightXMMOperand(current);
1316 } else {
1317 UnimplementedInstruction();
1318 }
1319 } else if (opcode == 0x1F) {
1320 // NOP
1321 int mod, regop, rm;
1322 get_modrm(*current, &mod, &regop, &rm);
1323 current++;
1324 if (rm == 4) { // SIB byte present.
1325 current++;
1326 }
1327 if (mod == 1) { // Byte displacement.
1328 current += 1;
1329 } else if (mod == 2) { // 32-bit displacement.
1330 current += 4;
1331 } // else no immediate displacement.
1332 AppendToBuffer("nop");
1333
1334 } else if (opcode == 0x28) {
1335 // movaps xmm, xmm/m128
1336 int mod, regop, rm;
1337 get_modrm(*current, &mod, &regop, &rm);
1338 AppendToBuffer("movaps %s, ", NameOfXMMRegister(regop));
1339 current += PrintRightXMMOperand(current);
1340
1341 } else if (opcode == 0x29) {
1342 // movaps xmm/m128, xmm
1343 int mod, regop, rm;
1344 get_modrm(*current, &mod, &regop, &rm);
1345 AppendToBuffer("movaps ");
1346 current += PrintRightXMMOperand(current);
1347 AppendToBuffer(", %s", NameOfXMMRegister(regop));
1348
1349 } else if (opcode == 0xA2 || opcode == 0x31) {
1350 // RDTSC or CPUID
1351 AppendToBuffer("%s", mnemonic);
1352
1353 } else if ((opcode & 0xF0) == 0x40) {
1354 // CMOVcc: conditional move.
1355 int condition = opcode & 0x0F;
1356 const InstructionDesc& idesc = cmov_instructions[condition];
1357 byte_size_operand_ = idesc.byte_size_operation;
1358 current += PrintOperands(idesc.mnem, idesc.op_order_, current);
1359
1360 } else if (opcode == 0x57) {
1361 // xorps xmm, xmm/m128
1362 int mod, regop, rm;
1363 get_modrm(*current, &mod, &regop, &rm);
1364 AppendToBuffer("xorps %s, ", NameOfXMMRegister(regop));
1365 current += PrintRightXMMOperand(current);
1366
1367 } else if ((opcode & 0xF0) == 0x80) {
1368 // Jcc: Conditional jump (branch).
1369 current = data + JumpConditional(data);
1370
1371 } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
1372 opcode == 0xB7 || opcode == 0xAF) {
1373 // Size-extending moves, IMUL.
1374 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1375
1376 } else if ((opcode & 0xF0) == 0x90) {
1377 // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
1378 current = data + SetCC(data);
1379
1380 } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
1381 // SHLD, SHRD (double-precision shift), BTS (bit set).
1382 AppendToBuffer("%s ", mnemonic);
1383 int mod, regop, rm;
1384 get_modrm(*current, &mod, &regop, &rm);
1385 current += PrintRightOperand(current);
1386 if (opcode == 0xAB) {
1387 AppendToBuffer(",%s", NameOfCPURegister(regop));
1388 } else {
1389 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1390 }
1391 } else {
1392 UnimplementedInstruction();
1393 }
1394 return static_cast<int>(current - data);
1395 }
1396
1397
1398 // Mnemonics for two-byte opcode instructions starting with 0x0F.
1399 // The argument is the second byte of the two-byte opcode.
1400 // Returns NULL if the instruction is not handled here.
1401 const char* DisassemblerX64::TwoByteMnemonic(uint8_t opcode) {
1402 switch (opcode) {
1403 case 0x1F:
1404 return "nop";
1405 case 0x2A: // F2/F3 prefix.
1406 return "cvtsi2s";
1407 case 0x31:
1408 return "rdtsc";
1409 case 0x51: // F2 prefix.
1410 return "sqrtsd";
1411 case 0x58: // F2 prefix.
1412 return "addsd";
1413 case 0x59: // F2 prefix.
1414 return "mulsd";
1415 case 0x5C: // F2 prefix.
1416 return "subsd";
1417 case 0x5E: // F2 prefix.
1418 return "divsd";
1419 case 0xA2:
1420 return "cpuid";
1421 case 0xA5:
1422 return "shld";
1423 case 0xAB:
1424 return "bts";
1425 case 0xAD:
1426 return "shrd";
1427 case 0xAF:
1428 return "imul";
1429 case 0xB6:
1430 return "movzxb";
1431 case 0xB7:
1432 return "movzxw";
1433 case 0xBE:
1434 return "movsxb";
1435 case 0xBF:
1436 return "movsxw";
1437 default:
1438 return NULL;
1439 }
1440 }
1441
1442
1443 int DisassemblerX64::InstructionDecode(uword pc) {
1444 uint8_t* data = reinterpret_cast<uint8_t*>(pc);
1445 uint8_t current;
1446
1447 // Scan for prefixes.
1448 while (true) {
1449 current = *data;
1450 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix.
1451 operand_size_ = current;
1452 } else if ((current & 0xF0) == 0x40) { // REX prefix.
1453 setRex(current);
1454 // TODO(srdjan): Should we enable printing of REX.W?
1455 // if (rex_w()) AppendToBuffer("REX.W ");
1456 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3).
1457 group_1_prefix_ = current;
1458 } else { // Not a prefix - an opcode.
1459 break;
1460 }
1461 data++;
1462 }
1463
1464 const InstructionDesc& idesc = instruction_table.Get(current);
1465 byte_size_operand_ = idesc.byte_size_operation;
1466 bool processed = DecodeInstructionType(idesc, &data);
1467
1468 if (!processed) {
1469 switch (*data) {
1470 case 0xC2:
1471 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
1472 data += 3;
1473 break;
1474
1475 case 0x69: // fall through
1476 case 0x6B: {
1477 int mod, regop, rm;
1478 get_modrm(*(data + 1), &mod, &regop, &rm);
1479 int32_t imm = *data == 0x6B ? *(data + 2)
1480 : *reinterpret_cast<int32_t*>(data + 2);
1481 AppendToBuffer("imul%c %s,%s,0x%x",
1482 operand_size_code(),
1483 NameOfCPURegister(regop),
1484 NameOfCPURegister(rm), imm);
1485 data += 2 + (*data == 0x6B ? 1 : 4);
1486 break;
1487 }
1488
1489 case 0x81: // fall through
1490 case 0x83: // 0x81 with sign extension bit set
1491 data += PrintImmediateOp(data);
1492 break;
1493
1494 case 0x0F:
1495 data += TwoByteOpcodeInstruction(data);
1496 break;
1497
1498 case 0x8F: {
1499 data++;
1500 int mod, regop, rm;
1501 get_modrm(*data, &mod, &regop, &rm);
1502 if (regop == 0) {
1503 AppendToBuffer("pop ");
1504 data += PrintRightOperand(data);
1505 }
1506 }
1507 break;
1508
1509 case 0xFF: {
1510 data++;
1511 int mod, regop, rm;
1512 get_modrm(*data, &mod, &regop, &rm);
1513 const char* mnem = NULL;
1514 switch (regop) {
1515 case 0:
1516 mnem = "inc";
1517 break;
1518 case 1:
1519 mnem = "dec";
1520 break;
1521 case 2:
1522 mnem = "call";
1523 break;
1524 case 4:
1525 mnem = "jmp";
1526 break;
1527 case 6:
1528 mnem = "push";
1529 break;
1530 default:
1531 mnem = "???";
1532 }
1533 AppendToBuffer(((regop <= 1) ? "%s%c " : "%s "),
1534 mnem,
1535 operand_size_code());
1536 data += PrintRightOperand(data);
1537 }
1538 break;
1539
1540 case 0xC7: // imm32, fall through
1541 case 0xC6: // imm8
1542 {
1543 bool is_byte = *data == 0xC6;
1544 data++;
1545 if (is_byte) {
1546 AppendToBuffer("movb ");
1547 data += PrintRightByteOperand(data);
1548 int32_t imm = *data;
1549 AppendToBuffer(",0x%x", imm);
1550 data++;
1551 } else {
1552 AppendToBuffer("mov%c ", operand_size_code());
1553 data += PrintRightOperand(data);
1554 int32_t imm = *reinterpret_cast<int32_t*>(data);
1555 AppendToBuffer(",0x%x", imm);
1556 data += 4;
1557 }
1558 }
1559 break;
1560
1561 case 0x80: {
1562 data++;
1563 AppendToBuffer("cmpb ");
1564 data += PrintRightByteOperand(data);
1565 int32_t imm = *data;
1566 AppendToBuffer(",0x%x", imm);
1567 data++;
1568 }
1569 break;
1570
1571 case 0x88: // 8bit, fall through
1572 case 0x89: // 32bit
1573 {
1574 bool is_byte = *data == 0x88;
1575 int mod, regop, rm;
1576 data++;
1577 get_modrm(*data, &mod, &regop, &rm);
1578 if (is_byte) {
1579 AppendToBuffer("movb ");
1580 data += PrintRightByteOperand(data);
1581 AppendToBuffer(",%s", NameOfByteCPURegister(regop));
1582 } else {
1583 AppendToBuffer("mov%c ", operand_size_code());
1584 data += PrintRightOperand(data);
1585 AppendToBuffer(",%s", NameOfCPURegister(regop));
1586 }
1587 }
1588 break;
1589
1590 case 0x90:
1591 case 0x91:
1592 case 0x92:
1593 case 0x93:
1594 case 0x94:
1595 case 0x95:
1596 case 0x96:
1597 case 0x97: {
1598 int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
1599 if (reg == 0) {
1600 AppendToBuffer("nop"); // Common name for xchg rax,rax.
1601 } else {
1602 AppendToBuffer("xchg%c rax, %s",
1603 operand_size_code(),
1604 NameOfCPURegister(reg));
1605 }
1606 data++;
1607 }
1608 break;
1609 case 0xB0:
1610 case 0xB1:
1611 case 0xB2:
1612 case 0xB3:
1613 case 0xB4:
1614 case 0xB5:
1615 case 0xB6:
1616 case 0xB7:
1617 case 0xB8:
1618 case 0xB9:
1619 case 0xBA:
1620 case 0xBB:
1621 case 0xBC:
1622 case 0xBD:
1623 case 0xBE:
1624 case 0xBF: {
1625 // mov reg8,imm8 or mov reg32,imm32
1626 uint8_t opcode = *data;
1627 data++;
1628 uint8_t is_32bit = (opcode >= 0xB8);
1629 int reg = (opcode & 0x7) | (rex_b() ? 8 : 0);
1630 if (is_32bit) {
1631 AppendToBuffer("mov%c %s, ",
1632 operand_size_code(),
1633 NameOfCPURegister(reg));
1634 data += PrintImmediate(data, DOUBLEWORD_SIZE);
1635 } else {
1636 AppendToBuffer("movb %s, ",
1637 NameOfByteCPURegister(reg));
1638 data += PrintImmediate(data, BYTE_SIZE);
1639 }
1640 break;
1641 }
1642 case 0xFE: {
1643 data++;
1644 int mod, regop, rm;
1645 get_modrm(*data, &mod, &regop, &rm);
1646 if (regop == 1) {
1647 AppendToBuffer("decb ");
1648 data += PrintRightByteOperand(data);
1649 } else {
1650 UnimplementedInstruction();
1651 }
1652 break;
1653 }
1654 case 0x68:
1655 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
1656 data += 5;
1657 break;
1658
1659 case 0x6A:
1660 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1661 data += 2;
1662 break;
1663
1664 case 0xA1: // Fall through.
1665 case 0xA3:
1666 switch (operand_size()) {
1667 case DOUBLEWORD_SIZE: {
1668 AppendAddressToBuffer(
1669 reinterpret_cast<uint8_t*>(
1670 *reinterpret_cast<int32_t*>(data + 1)));
1671 if (*data == 0xA1) { // Opcode 0xA1
1672 AppendToBuffer("movzxlq rax,(");
1673 AppendAddressToBuffer(
1674 reinterpret_cast<uint8_t*>(
1675 *reinterpret_cast<int32_t*>(data + 1)));
1676 AppendToBuffer(")");
1677 } else { // Opcode 0xA3
1678 AppendToBuffer("movzxlq (");
1679 AppendAddressToBuffer(
1680 reinterpret_cast<uint8_t*>(
1681 *reinterpret_cast<int32_t*>(data + 1)));
1682 AppendToBuffer("),rax");
1683 }
1684 data += 5;
1685 break;
1686 }
1687 case QUADWORD_SIZE: {
1688 // New x64 instruction mov rax,(imm_64).
1689 if (*data == 0xA1) { // Opcode 0xA1
1690 AppendToBuffer("movq rax,(");
1691 AppendAddressToBuffer(*reinterpret_cast<uint8_t**>(data + 1));
1692 AppendToBuffer(")");
1693 } else { // Opcode 0xA3
1694 AppendToBuffer("movq (");
1695 AppendAddressToBuffer(*reinterpret_cast<uint8_t**>(data + 1));
1696 AppendToBuffer("),rax");
1697 }
1698 data += 9;
1699 break;
1700 }
1701 default:
1702 UnimplementedInstruction();
1703 data += 2;
1704 }
1705 break;
1706
1707 case 0xA8:
1708 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
1709 data += 2;
1710 break;
1711
1712 case 0xA9: {
1713 int64_t value = 0;
1714 switch (operand_size()) {
1715 case WORD_SIZE:
1716 value = *reinterpret_cast<uint16_t*>(data + 1);
1717 data += 3;
1718 break;
1719 case DOUBLEWORD_SIZE:
1720 value = *reinterpret_cast<uint32_t*>(data + 1);
1721 data += 5;
1722 break;
1723 case QUADWORD_SIZE:
1724 value = *reinterpret_cast<int32_t*>(data + 1);
1725 data += 5;
1726 break;
1727 default:
1728 UNREACHABLE();
1729 }
1730 AppendToBuffer("test%c rax,0x%0" PRIxPTR "",
1731 operand_size_code(),
1732 value);
1733 break;
1734 }
1735 case 0xD1: // fall through
1736 case 0xD3: // fall through
1737 case 0xC1:
1738 data += ShiftInstruction(data);
1739 break;
1740 case 0xD0: // fall through
1741 case 0xD2: // fall through
1742 case 0xC0:
1743 byte_size_operand_ = true;
1744 data += ShiftInstruction(data);
1745 break;
1746
1747 case 0xD9: // fall through
1748 case 0xDA: // fall through
1749 case 0xDB: // fall through
1750 case 0xDC: // fall through
1751 case 0xDD: // fall through
1752 case 0xDE: // fall through
1753 case 0xDF:
1754 data += FPUInstruction(data);
1755 break;
1756
1757 case 0xEB:
1758 data += JumpShort(data);
1759 break;
1760
1761 case 0xF6:
1762 byte_size_operand_ = true; // fall through
1763 case 0xF7:
1764 data += F6F7Instruction(data);
1765 break;
1766
1767 default:
1768 UnimplementedInstruction();
1769 data += 1;
1770 }
1771 } // !processed
1772
1773 if (buffer_pos_ < buffer_size_) {
1774 buffer_[buffer_pos_] = '\0';
1775 }
1776
1777 int instr_len = data - reinterpret_cast<uint8_t*>(pc);
1778 ASSERT(instr_len > 0); // Ensure progress.
1779
1780 return instr_len;
1781 }
1782
1783
1784 int Disassembler::DecodeInstruction(char* hex_buffer, intptr_t hex_size,
1785 char* human_buffer, intptr_t human_size,
1786 uword pc) {
1787 ASSERT(hex_size > 0);
1788 ASSERT(human_size > 0);
1789 DisassemblerX64 decoder(human_buffer, human_size);
1790 int instruction_length = decoder.InstructionDecode(pc);
1791 uint8_t* pc_ptr = reinterpret_cast<uint8_t*>(pc);
1792 int hex_index = 0;
1793 int remaining_size = hex_size - hex_index;
1794 for (int i = 0; (i < instruction_length) && (remaining_size > 2); ++i) {
1795 OS::SNPrint(&hex_buffer[hex_index], remaining_size, "%02x", pc_ptr[i]);
1796 hex_index += 2;
1797 remaining_size -= 2;
1798 }
1799 hex_buffer[hex_index] = '\0';
1800 return instruction_length;
1801 }
1802
1803
20 void Disassembler::Disassemble(uword start, 1804 void Disassembler::Disassemble(uword start,
21 uword end, 1805 uword end,
22 DisassemblyFormatter* formatter, 1806 DisassemblyFormatter* formatter,
23 const Code::Comments& comments) { 1807 const Code::Comments& comments) {
24 // First print the actual addresses so that we know where in memory this is 1808 ASSERT(formatter != NULL);
25 // being disassembled from. 1809 char hex_buffer[kHexadecimalBufferSize]; // Instruction in hexadecimal form.
26 formatter->Print("start: %p end: %p\n", start, end); 1810 char human_buffer[kUserReadableBufferSize]; // Human-readable instruction.
27 1811 uword pc = start;
28 #if !defined(_WIN32) // Disassembler is not yet supported under WIN32. 1812 intptr_t comment_finger = 0;
29 // Write code block to tmp file. 1813 while (pc < end) {
30 char tmp[] = "/tmp/codeblock.XXXXXX"; 1814 const intptr_t offset = pc - start;
31 int fd = mkstemp(tmp); 1815 while (comment_finger < comments.Length() &&
32 if (fd < 0) { 1816 comments.PCOffsetAt(comment_finger) <= offset) {
33 int errsv = errno; 1817 formatter->Print(" ;; %s\n",
34 formatter->Print("Could not open tmp file %s, errno=%s\n", 1818 comments.CommentAt(comment_finger).ToCString());
35 tmp, 1819 comment_finger++;
36 strerror(errsv));
37 return; // failed
38 }
39 ssize_t size = write(fd, reinterpret_cast<const void*>(start), end - start);
40 if (size <= 0) {
41 if (size < 0) {
42 int errsv = errno;
43 formatter->Print("Could not write to tmp file %s, errno=%s\n",
44 tmp,
45 strerror(errsv));
46 } 1820 }
47 close(fd); 1821 int instruction_length = DecodeInstruction(hex_buffer,
48 remove(tmp); 1822 sizeof(hex_buffer),
49 return; 1823 human_buffer,
50 } 1824 sizeof(human_buffer),
51 close(fd); 1825 pc);
52 1826 formatter->ConsumeInstruction(hex_buffer,
53 // Disassemble tmp file to stdout. 1827 sizeof(hex_buffer),
54 char cmd[256]; 1828 human_buffer,
55 #if defined(__APPLE__) 1829 sizeof(human_buffer),
56 snprintf(cmd, sizeof(cmd), 1830 pc);
57 "( cat %1$s | " 1831 pc += instruction_length;
58 " hexdump -v -e '\".byte \" 1/1 \"0x%%02x\" \"\\n\"' | " 1832 }
59 " as - -arch x86_64 -o %1$s.o ; otool -tV %1$s.o"
60 ") </dev/null 2>&1", tmp);
61 #else
62 snprintf(cmd, sizeof(cmd), "( /usr/bin/objdump -b binary -m i386:x86-64 -D %s"
63 " ) </dev/null 2>&1", tmp);
64 #endif
65 FILE* output = popen(cmd, "r");
66 if (output == NULL) {
67 int errsv = errno;
68 formatter->Print("Could not run \"%s\", errno=%s\n", cmd, strerror(errsv));
69 remove(tmp);
70 return; // failed
71 }
72 const int kMaxOutputLine = 1024;
73 char line[kMaxOutputLine];
74 #if defined(__APPLE__)
75 const char* header = "(__TEXT,__text) section\n";
76 #else
77 const char* header = "<.data>:\n";
78 #endif
79 char* header_pos = NULL;
80 while (header_pos == NULL && fgets(line, sizeof(line), output) != NULL) {
81 header_pos = strstr(line, header);
82 if (header_pos != NULL) {
83 formatter->Print("%s", header_pos + strlen(header));
84 }
85 }
86
87
88 int comment_finger = 0;
89 while (fgets(line, sizeof(line), output) != NULL) {
90 char* tab = strchr(line, '\t');
91 if (tab != NULL) {
92 *tab = '\0';
93 intptr_t offset = 0;
94 sscanf(line, "%p", reinterpret_cast<void**>(&offset)); // NOLINT
95 while (comment_finger < comments.Length() &&
96 comments.PCOffsetAt(comment_finger) <= offset) {
97 formatter->Print(" ;; %s\n",
98 comments.CommentAt(comment_finger).ToCString());
99 comment_finger++;
100 }
101
102 formatter->Print("%016p %08x %s", start + offset, offset, tab + 1);
103 }
104 }
105 pclose(output);
106
107 // Delete tmp files.
108 remove(tmp);
109 #if defined(__APPLE__)
110 char tmp_o[32];
111 snprintf(tmp_o, sizeof(tmp_o), "%s.o", tmp);
112 remove(tmp_o);
113 #endif
114 #endif // !defined(_WIN32)
115 }
116
117
118 int Disassembler::DecodeInstruction(char* hexa_buffer, intptr_t hexa_size,
119 char* human_buffer, intptr_t human_size,
120 uword pc) {
121 UNIMPLEMENTED();
122 return 0;
123 } 1833 }
124 1834
125 } // namespace dart 1835 } // namespace dart
126 1836
127 #endif // defined TARGET_ARCH_X64 1837 #endif // defined TARGET_ARCH_X64
OLDNEW
« no previous file with comments | « runtime/vm/disassembler.cc ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698