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

Side by Side Diff: src/x64/disasm-x64.cc

Issue 155087: X64: Disassembler updated to using REX, extended registers and some X64 opcodes. (Closed)
Patch Set: Addressed review comments. Added few more features. Major lint check. Created 11 years, 5 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
« no previous file with comments | « src/x64/assembler-x64.cc ('k') | src/x64/macro-assembler-x64.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2009 the V8 project authors. All rights reserved. 1 // Copyright 2009 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution. 11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its 12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived 13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission. 14 // from this software without specific prior written permission.
15 // 15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28 #include <assert.h>
29 #include <stdio.h>
30 #include <stdarg.h>
31
28 #include "v8.h" 32 #include "v8.h"
29 #include "disasm.h" 33 #include "disasm.h"
30 34
31 namespace disasm { 35 namespace disasm {
32 36
33 Disassembler::Disassembler(NameConverter const& converter) 37 enum OperandOrder {
34 : converter_(converter) { 38 UNSET_OP_ORDER = 0, REG_OPER_OP_ORDER, OPER_REG_OP_ORDER
35 UNIMPLEMENTED(); 39 };
36 } 40
37 41 //------------------------------------------------------------------
38 42 // Tables
39 Disassembler::~Disassembler() { 43 //------------------------------------------------------------------
40 UNIMPLEMENTED(); 44 struct ByteMnemonic {
41 } 45 int b; // -1 terminates, otherwise must be in range (0..255)
42 46 OperandOrder op_order_;
43 47 const char* mnem;
44 const char* NameConverter::NameOfAddress(unsigned char* addr) const { 48 };
45 UNIMPLEMENTED(); 49
46 return NULL; 50
51 static ByteMnemonic two_operands_instr[] = {
52 { 0x03, REG_OPER_OP_ORDER, "add" },
53 { 0x21, OPER_REG_OP_ORDER, "and" },
54 { 0x23, REG_OPER_OP_ORDER, "and" },
55 { 0x3B, REG_OPER_OP_ORDER, "cmp" },
56 { 0x8D, REG_OPER_OP_ORDER, "lea" },
57 { 0x09, OPER_REG_OP_ORDER, "or" },
58 { 0x0B, REG_OPER_OP_ORDER, "or" },
59 { 0x1B, REG_OPER_OP_ORDER, "sbb" },
60 { 0x29, OPER_REG_OP_ORDER, "sub" },
61 { 0x2B, REG_OPER_OP_ORDER, "sub" },
62 { 0x85, REG_OPER_OP_ORDER, "test" },
63 { 0x31, OPER_REG_OP_ORDER, "xor" },
64 { 0x33, REG_OPER_OP_ORDER, "xor" },
65 { 0x87, REG_OPER_OP_ORDER, "xchg" },
66 { 0x8A, REG_OPER_OP_ORDER, "movb" },
67 { 0x8B, REG_OPER_OP_ORDER, "mov" },
68 { -1, UNSET_OP_ORDER, "" }
69 };
70
71
72 static ByteMnemonic zero_operands_instr[] = {
73 { 0xC3, UNSET_OP_ORDER, "ret" },
74 { 0xC9, UNSET_OP_ORDER, "leave" },
75 { 0x90, UNSET_OP_ORDER, "nop" },
76 { 0xF4, UNSET_OP_ORDER, "hlt" },
77 { 0xCC, UNSET_OP_ORDER, "int3" },
78 { 0x60, UNSET_OP_ORDER, "pushad" },
79 { 0x61, UNSET_OP_ORDER, "popad" },
80 { 0x9C, UNSET_OP_ORDER, "pushfd" },
81 { 0x9D, UNSET_OP_ORDER, "popfd" },
82 { 0x9E, UNSET_OP_ORDER, "sahf" },
83 { 0x99, UNSET_OP_ORDER, "cdq" },
84 { 0x9B, UNSET_OP_ORDER, "fwait" },
85 { -1, UNSET_OP_ORDER, "" }
86 };
87
88
89 static ByteMnemonic call_jump_instr[] = {
90 { 0xE8, UNSET_OP_ORDER, "call" },
91 { 0xE9, UNSET_OP_ORDER, "jmp" },
92 { -1, UNSET_OP_ORDER, "" }
93 };
94
95
96 static ByteMnemonic short_immediate_instr[] = {
97 { 0x05, UNSET_OP_ORDER, "add" },
98 { 0x0D, UNSET_OP_ORDER, "or" },
99 { 0x15, UNSET_OP_ORDER, "adc" },
100 { 0x25, UNSET_OP_ORDER, "and" },
101 { 0x2D, UNSET_OP_ORDER, "sub" },
102 { 0x35, UNSET_OP_ORDER, "xor" },
103 { 0x3D, UNSET_OP_ORDER, "cmp" },
104 { -1, UNSET_OP_ORDER, "" }
105 };
106
107
108 static const char* conditional_code_suffix[] = {
109 "o", "no", "c", "nc", "z", "nz", "a", "na",
110 "s", "ns", "pe", "po", "l", "ge", "le", "g"
111 };
112
113
114 enum InstructionType {
115 NO_INSTR,
116 ZERO_OPERANDS_INSTR,
117 TWO_OPERANDS_INSTR,
118 JUMP_CONDITIONAL_SHORT_INSTR,
119 REGISTER_INSTR,
120 PUSHPOP_INSTR, // Has implicit 64-bit operand size.
121 MOVE_REG_INSTR,
122 CALL_JUMP_INSTR,
123 SHORT_IMMEDIATE_INSTR
124 };
125
126
127 struct InstructionDesc {
128 const char* mnem;
129 InstructionType type;
130 OperandOrder op_order_;
131 };
132
133
134 class InstructionTable {
135 public:
136 InstructionTable();
137 const InstructionDesc& Get(byte x) const {
138 return instructions_[x];
139 }
140
141 private:
142 InstructionDesc instructions_[256];
143 void Clear();
144 void Init();
145 void CopyTable(ByteMnemonic bm[], InstructionType type);
146 void SetTableRange(InstructionType type, byte start, byte end,
147 const char* mnem);
148 void AddJumpConditionalShort();
149 };
150
151
152 InstructionTable::InstructionTable() {
153 Clear();
154 Init();
155 }
156
157
158 void InstructionTable::Clear() {
159 for (int i = 0; i < 256; i++) {
160 instructions_[i].mnem = "";
161 instructions_[i].type = NO_INSTR;
162 instructions_[i].op_order_ = UNSET_OP_ORDER;
163 }
164 }
165
166
167 void InstructionTable::Init() {
168 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
169 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
170 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
171 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
172 AddJumpConditionalShort();
173 SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, "push");
174 SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, "pop");
175 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, "mov");
176 }
177
178
179 void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) {
180 for (int i = 0; bm[i].b >= 0; i++) {
181 InstructionDesc* id = &instructions_[bm[i].b];
182 id->mnem = bm[i].mnem;
183 id->op_order_ = bm[i].op_order_;
184 assert(id->type == NO_INSTR); // Information already entered
185 id->type = type;
186 }
187 }
188
189
190 void InstructionTable::SetTableRange(InstructionType type, byte start,
191 byte end, const char* mnem) {
192 for (byte b = start; b <= end; b++) {
193 InstructionDesc* id = &instructions_[b];
194 assert(id->type == NO_INSTR); // Information already entered
195 id->mnem = mnem;
196 id->type = type;
197 }
198 }
199
200
201 void InstructionTable::AddJumpConditionalShort() {
202 for (byte b = 0x70; b <= 0x7F; b++) {
203 InstructionDesc* id = &instructions_[b];
204 assert(id->type == NO_INSTR); // Information already entered
205 id->mnem = NULL; // Computed depending on condition code.
206 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
207 }
208 }
209
210
211 static InstructionTable instruction_table;
212
213
214 // The X64 disassembler implementation.
215 enum UnimplementedOpcodeAction {
216 CONTINUE_ON_UNIMPLEMENTED_OPCODE,
217 ABORT_ON_UNIMPLEMENTED_OPCODE
218 };
219
220
221 class DisassemblerX64 {
222 public:
223 DisassemblerX64(const NameConverter& converter,
224 UnimplementedOpcodeAction unimplemented_action =
225 ABORT_ON_UNIMPLEMENTED_OPCODE)
226 : converter_(converter),
227 tmp_buffer_pos_(0),
228 abort_on_unimplemented_(
229 unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE),
230 rex_(0),
231 operand_size_(0) {
232 tmp_buffer_[0] = '\0';
233 }
234
235 virtual ~DisassemblerX64() {
236 }
237
238 // Writes one disassembled instruction into 'buffer' (0-terminated).
239 // Returns the length of the disassembled machine instruction in bytes.
240 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
241
242 private:
243
244 const NameConverter& converter_;
245 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
246 unsigned int tmp_buffer_pos_;
247 bool abort_on_unimplemented_;
248 // Prefixes parsed
249 byte rex_;
250 byte operand_size_;
251
252 void setOperandSizePrefix(byte prefix) {
253 ASSERT_EQ(0x66, prefix);
254 operand_size_ = prefix;
255 }
256
257 void setRex(byte rex) {
258 ASSERT_EQ(0x40, rex & 0xF0);
259 rex_ = rex;
260 }
261
262 bool rex() { return rex_ != 0; }
263
264 bool rex_b() { return (rex_ & 0x01) != 0; }
265
266 // Actual number of base register given the low bits and the rex.b state.
267 int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); }
268
269 bool rex_x() { return (rex_ & 0x02) != 0; }
270
271 bool rex_r() { return (rex_ & 0x04) != 0; }
272
273 bool rex_w() { return (rex_ & 0x08) != 0; }
274
275 int operand_size() {
276 return rex_w() ? 64 : (operand_size_ != 0) ? 16 : 32;
277 }
278
279 char operand_size_code() {
280 return rex_w() ? 'q' : (operand_size_ != 0) ? 'w' : 'l';
281 }
282
283 const char* NameOfCPURegister(int reg) const {
284 return converter_.NameOfCPURegister(reg);
285 }
286
287 const char* NameOfByteCPURegister(int reg) const {
288 return converter_.NameOfByteCPURegister(reg);
289 }
290
291 const char* NameOfXMMRegister(int reg) const {
292 return converter_.NameOfXMMRegister(reg);
293 }
294
295 const char* NameOfAddress(byte* addr) const {
296 return converter_.NameOfAddress(addr);
297 }
298
299 // Disassembler helper functions.
300 void get_modrm(byte data,
301 int* mod,
302 int* regop,
303 int* rm) {
304 *mod = (data >> 6) & 3;
305 *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0);
306 *rm = (data & 7) | (rex_b() ? 8 : 0);
307 }
308
309 void get_sib(byte data,
310 int* scale,
311 int* index,
312 int* base) {
313 *scale = (data >> 6) & 3;
314 *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
315 *base = data & 7 | (rex_b() ? 8 : 0);
316 }
317
318 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const;
319
320 int PrintRightOperandHelper(byte* modrmp,
321 RegisterNameMapping register_name);
322 int PrintRightOperand(byte* modrmp);
323 int PrintRightByteOperand(byte* modrmp);
324 int PrintOperands(const char* mnem,
325 OperandOrder op_order,
326 byte* data);
327 int PrintImmediateOp(byte* data);
328 int F7Instruction(byte* data);
329 int D1D3C1Instruction(byte* data);
330 int JumpShort(byte* data);
331 int JumpConditional(byte* data);
332 int JumpConditionalShort(byte* data);
333 int SetCC(byte* data);
334 int FPUInstruction(byte* data);
335 void AppendToBuffer(const char* format, ...);
336
337 void UnimplementedInstruction() {
338 if (abort_on_unimplemented_) {
339 UNIMPLEMENTED();
340 } else {
341 AppendToBuffer("'Unimplemented Instruction'");
342 }
343 }
344 };
345
346
347 void DisassemblerX64::AppendToBuffer(const char* format, ...) {
348 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
349 va_list args;
350 va_start(args, format);
351 int result = v8::internal::OS::VSNPrintF(buf, format, args);
352 va_end(args);
353 tmp_buffer_pos_ += result;
354 }
355
356
357 int DisassemblerX64::PrintRightOperandHelper(
358 byte* modrmp,
359 RegisterNameMapping register_name) {
360 int mod, regop, rm;
361 get_modrm(*modrmp, &mod, &regop, &rm);
362 switch (mod) {
363 case 0:
364 if ((rm & 7) == 5) {
365 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1);
366 AppendToBuffer("[0x%x]", disp);
367 return 5;
368 } else if ((rm & 7) == 4) {
369 // Codes for SIB byte.
370 byte sib = *(modrmp + 1);
371 int scale, index, base;
372 get_sib(sib, &scale, &index, &base);
373 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
374 // index == rsp means no index. Only use sib byte with no index for
375 // rsp and r12 base.
376 AppendToBuffer("[%s]", (this->*register_name)(base));
377 return 2;
378 } else if (base == 5) {
379 // base == rbp means no base register (when mod == 0).
380 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
381 AppendToBuffer("[%s*%d+0x%x]",
382 (this->*register_name)(index),
383 1 << scale, disp);
384 return 6;
385 } else if (index != 4 && base != 5) {
386 // [base+index*scale]
387 AppendToBuffer("[%s+%s*%d]",
388 (this->*register_name)(base),
389 (this->*register_name)(index),
390 1 << scale);
391 return 2;
392 } else {
393 UnimplementedInstruction();
394 return 1;
395 }
396 } else {
397 AppendToBuffer("[%s]", (this->*register_name)(rm));
398 return 1;
399 }
400 break;
401 case 1: // fall through
402 case 2:
403 if ((rm & 7) == 4) {
404 byte sib = *(modrmp + 1);
405 int scale, index, base;
406 get_sib(sib, &scale, &index, &base);
407 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2)
408 : *reinterpret_cast<char*>(modrmp + 2);
409 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
410 if (-disp > 0) {
411 AppendToBuffer("[%s-0x%x]", (this->*register_name)(base), -disp);
412 } else {
413 AppendToBuffer("[%s+0x%x]", (this->*register_name)(base), disp);
414 }
415 } else {
416 if (-disp > 0) {
417 AppendToBuffer("[%s+%s*%d-0x%x]",
418 (this->*register_name)(base),
419 (this->*register_name)(index),
420 1 << scale,
421 -disp);
422 } else {
423 AppendToBuffer("[%s+%s*%d+0x%x]",
424 (this->*register_name)(base),
425 (this->*register_name)(index),
426 1 << scale,
427 disp);
428 }
429 }
430 return mod == 2 ? 6 : 3;
431 } else {
432 // No sib.
433 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1)
434 : *reinterpret_cast<char*>(modrmp + 1);
435 if (-disp > 0) {
436 AppendToBuffer("[%s-0x%x]", (this->*register_name)(rm), -disp);
437 } else {
438 AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp);
439 }
440 return (mod == 2) ? 5 : 2;
441 }
442 break;
443 case 3:
444 AppendToBuffer("%s", (this->*register_name)(rm));
445 return 1;
446 default:
447 UnimplementedInstruction();
448 return 1;
449 }
450 UNREACHABLE();
451 }
452
453
454 int DisassemblerX64::PrintRightOperand(byte* modrmp) {
455 return PrintRightOperandHelper(modrmp,
456 &DisassemblerX64::NameOfCPURegister);
457 }
458
459
460 int DisassemblerX64::PrintRightByteOperand(byte* modrmp) {
461 return PrintRightOperandHelper(modrmp,
462 &DisassemblerX64::NameOfByteCPURegister);
463 }
464
465
466 // Returns number of bytes used including the current *data.
467 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
468 int DisassemblerX64::PrintOperands(const char* mnem,
469 OperandOrder op_order,
470 byte* data) {
471 byte modrm = *data;
472 int mod, regop, rm;
473 get_modrm(modrm, &mod, &regop, &rm);
474 int advance = 0;
475 switch (op_order) {
476 case REG_OPER_OP_ORDER: {
477 AppendToBuffer("%s%c %s,",
478 mnem,
479 operand_size_code(),
480 NameOfCPURegister(regop));
481 advance = PrintRightOperand(data);
482 break;
483 }
484 case OPER_REG_OP_ORDER: {
485 AppendToBuffer("%s%c ", mnem, operand_size_code());
486 advance = PrintRightOperand(data);
487 AppendToBuffer(",%s", NameOfCPURegister(regop));
488 break;
489 }
490 default:
491 UNREACHABLE();
492 break;
493 }
494 return advance;
495 }
496
497
498 // Returns number of bytes used by machine instruction, including *data byte.
499 // Writes immediate instructions to 'tmp_buffer_'.
500 int DisassemblerX64::PrintImmediateOp(byte* data) {
501 bool sign_extension_bit = (*data & 0x02) != 0;
502 byte modrm = *(data + 1);
503 int mod, regop, rm;
504 get_modrm(modrm, &mod, &regop, &rm);
505 const char* mnem = "Imm???";
506 switch (regop) {
507 case 0:
508 mnem = "add";
509 break;
510 case 1:
511 mnem = "or";
512 break;
513 case 2:
514 mnem = "adc";
515 break;
516 case 4:
517 mnem = "and";
518 break;
519 case 5:
520 mnem = "sub";
521 break;
522 case 6:
523 mnem = "xor";
524 break;
525 case 7:
526 mnem = "cmp";
527 break;
528 default:
529 UnimplementedInstruction();
530 }
531 AppendToBuffer("%s ", mnem);
532 int count = PrintRightOperand(data + 1);
533 if (sign_extension_bit) {
534 AppendToBuffer(",0x%x", *(data + 1 + count));
535 return 1 + count + 1 /*int8*/;
536 } else {
537 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count));
538 return 1 + count + 4 /*int32_t*/;
539 }
540 }
541
542
543 // Returns number of bytes used, including *data.
544 int DisassemblerX64::F7Instruction(byte* data) {
545 assert(*data == 0xF7);
546 byte modrm = *(data + 1);
547 int mod, regop, rm;
548 get_modrm(modrm, &mod, &regop, &rm);
549 if (mod == 3 && regop != 0) {
550 const char* mnem = NULL;
551 switch (regop) {
552 case 2:
553 mnem = "not";
554 break;
555 case 3:
556 mnem = "neg";
557 break;
558 case 4:
559 mnem = "mul";
560 break;
561 case 7:
562 mnem = "idiv";
563 break;
564 default:
565 UnimplementedInstruction();
566 }
567 AppendToBuffer("%s%c %s",
568 mnem,
569 operand_size_code(),
570 NameOfCPURegister(rm));
571 return 2;
572 } else if (mod == 3 && regop == 0) {
573 int32_t imm = *reinterpret_cast<int32_t*>(data + 2);
574 AppendToBuffer("test%c %s,0x%x",
575 operand_size_code(),
576 NameOfCPURegister(rm),
577 imm);
578 return 6;
579 } else if (regop == 0) {
580 AppendToBuffer("test%c ", operand_size_code());
581 int count = PrintRightOperand(data + 1);
582 int32_t imm = *reinterpret_cast<int32_t*>(data + 1 + count);
583 AppendToBuffer(",0x%x", imm);
584 return 1 + count + 4 /*int32_t*/;
585 } else {
586 UnimplementedInstruction();
587 return 2;
588 }
589 }
590
591
592 int DisassemblerX64::D1D3C1Instruction(byte* data) {
593 byte op = *data;
594 assert(op == 0xD1 || op == 0xD3 || op == 0xC1);
595 byte modrm = *(data + 1);
596 int mod, regop, rm;
597 get_modrm(modrm, &mod, &regop, &rm);
598 ASSERT(regop < 8);
599 int imm8 = -1;
600 int num_bytes = 2;
601 if (mod == 3) {
602 const char* mnem = NULL;
603 if (op == 0xD1) {
604 imm8 = 1;
605 switch (regop) {
606 case 2:
607 mnem = "rcl";
608 break;
609 case 7:
610 mnem = "sar";
611 break;
612 case 4:
613 mnem = "shl";
614 break;
615 default:
616 UnimplementedInstruction();
617 }
618 } else if (op == 0xC1) {
619 imm8 = *(data + 2);
620 num_bytes = 3;
621 switch (regop) {
622 case 2:
623 mnem = "rcl";
624 break;
625 case 4:
626 mnem = "shl";
627 break;
628 case 5:
629 mnem = "shr";
630 break;
631 case 7:
632 mnem = "sar";
633 break;
634 default:
635 UnimplementedInstruction();
636 }
637 } else if (op == 0xD3) {
638 switch (regop) {
639 case 4:
640 mnem = "shl";
641 break;
642 case 5:
643 mnem = "shr";
644 break;
645 case 7:
646 mnem = "sar";
647 break;
648 default:
649 UnimplementedInstruction();
650 }
651 }
652 assert(mnem != NULL);
653 AppendToBuffer("%s%c %s,",
654 mnem,
655 operand_size_code(),
656 NameOfCPURegister(rm));
657 if (imm8 > 0) {
658 AppendToBuffer("%d", imm8);
659 } else {
660 AppendToBuffer("cl");
661 }
662 } else {
663 UnimplementedInstruction();
664 }
665 return num_bytes;
666 }
667
668
669 // Returns number of bytes used, including *data.
670 int DisassemblerX64::JumpShort(byte* data) {
671 assert(*data == 0xEB);
672 byte b = *(data + 1);
673 byte* dest = data + static_cast<int8_t>(b) + 2;
674 AppendToBuffer("jmp %s", NameOfAddress(dest));
675 return 2;
676 }
677
678
679 // Returns number of bytes used, including *data.
680 int DisassemblerX64::JumpConditional(byte* data) {
681 assert(*data == 0x0F);
682 byte cond = *(data + 1) & 0x0F;
683 byte* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6;
684 const char* mnem = conditional_code_suffix[cond];
685 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
686 return 6; // includes 0x0F
687 }
688
689
690 // Returns number of bytes used, including *data.
691 int DisassemblerX64::JumpConditionalShort(byte* data) {
692 byte cond = *data & 0x0F;
693 byte b = *(data + 1);
694 byte* dest = data + static_cast<int8_t>(b) + 2;
695 const char* mnem = conditional_code_suffix[cond];
696 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
697 return 2;
698 }
699
700
701 // Returns number of bytes used, including *data.
702 int DisassemblerX64::SetCC(byte* data) {
703 assert(*data == 0x0F);
704 byte cond = *(data + 1) & 0x0F;
705 const char* mnem = conditional_code_suffix[cond];
706 AppendToBuffer("set%s%c ", mnem, operand_size_code());
707 PrintRightByteOperand(data + 2);
708 return 3; // includes 0x0F
709 }
710
711
712 // Returns number of bytes used, including *data.
713 int DisassemblerX64::FPUInstruction(byte* data) {
714 byte b1 = *data;
715 byte b2 = *(data + 1);
716 if (b1 == 0xD9) {
717 const char* mnem = NULL;
718 switch (b2) {
719 case 0xE8:
720 mnem = "fld1";
721 break;
722 case 0xEE:
723 mnem = "fldz";
724 break;
725 case 0xE1:
726 mnem = "fabs";
727 break;
728 case 0xE0:
729 mnem = "fchs";
730 break;
731 case 0xF8:
732 mnem = "fprem";
733 break;
734 case 0xF5:
735 mnem = "fprem1";
736 break;
737 case 0xF7:
738 mnem = "fincstp";
739 break;
740 case 0xE4:
741 mnem = "ftst";
742 break;
743 }
744 if (mnem != NULL) {
745 AppendToBuffer("%s", mnem);
746 return 2;
747 } else if ((b2 & 0xF8) == 0xC8) {
748 AppendToBuffer("fxch st%d", b2 & 0x7);
749 return 2;
750 } else {
751 int mod, regop, rm;
752 get_modrm(*(data + 1), &mod, &regop, &rm);
753 const char* mnem = "?";
754 switch (regop) {
755 case 0:
756 mnem = "fld_s";
757 break;
758 case 3:
759 mnem = "fstp_s";
760 break;
761 default:
762 UnimplementedInstruction();
763 }
764 AppendToBuffer("%s ", mnem);
765 int count = PrintRightOperand(data + 1);
766 return count + 1;
767 }
768 } else if (b1 == 0xDD) {
769 if ((b2 & 0xF8) == 0xC0) {
770 AppendToBuffer("ffree st%d", b2 & 0x7);
771 return 2;
772 } else {
773 int mod, regop, rm;
774 get_modrm(*(data + 1), &mod, &regop, &rm);
775 const char* mnem = "?";
776 switch (regop) {
777 case 0:
778 mnem = "fld_d";
779 break;
780 case 3:
781 mnem = "fstp_d";
782 break;
783 default:
784 UnimplementedInstruction();
785 }
786 AppendToBuffer("%s ", mnem);
787 int count = PrintRightOperand(data + 1);
788 return count + 1;
789 }
790 } else if (b1 == 0xDB) {
791 int mod, regop, rm;
792 get_modrm(*(data + 1), &mod, &regop, &rm);
793 const char* mnem = "?";
794 switch (regop) {
795 case 0:
796 mnem = "fild_s";
797 break;
798 case 2:
799 mnem = "fist_s";
800 break;
801 case 3:
802 mnem = "fistp_s";
803 break;
804 default:
805 UnimplementedInstruction();
806 }
807 AppendToBuffer("%s ", mnem);
808 int count = PrintRightOperand(data + 1);
809 return count + 1;
810 } else if (b1 == 0xDF) {
811 if (b2 == 0xE0) {
812 AppendToBuffer("fnstsw_ax");
813 return 2;
814 }
815 int mod, regop, rm;
816 get_modrm(*(data + 1), &mod, &regop, &rm);
817 const char* mnem = "?";
818 switch (regop) {
819 case 5:
820 mnem = "fild_d";
821 break;
822 case 7:
823 mnem = "fistp_d";
824 break;
825 default:
826 UnimplementedInstruction();
827 }
828 AppendToBuffer("%s ", mnem);
829 int count = PrintRightOperand(data + 1);
830 return count + 1;
831 } else if (b1 == 0xDC || b1 == 0xDE) {
832 bool is_pop = (b1 == 0xDE);
833 if (is_pop && b2 == 0xD9) {
834 AppendToBuffer("fcompp");
835 return 2;
836 }
837 const char* mnem = "FP0xDC";
838 switch (b2 & 0xF8) {
839 case 0xC0:
840 mnem = "fadd";
841 break;
842 case 0xE8:
843 mnem = "fsub";
844 break;
845 case 0xC8:
846 mnem = "fmul";
847 break;
848 case 0xF8:
849 mnem = "fdiv";
850 break;
851 default:
852 UnimplementedInstruction();
853 }
854 AppendToBuffer("%s%s st%d", mnem, is_pop ? "p" : "", b2 & 0x7);
855 return 2;
856 } else if (b1 == 0xDA && b2 == 0xE9) {
857 const char* mnem = "fucompp";
858 AppendToBuffer("%s", mnem);
859 return 2;
860 }
861 AppendToBuffer("Unknown FP instruction");
862 return 2;
863 }
864
865 // Mnemonics for instructions 0xF0 byte.
866 // Returns NULL if the instruction is not handled here.
867 static const char* F0Mnem(byte f0byte) {
868 switch (f0byte) {
869 case 0x1F:
870 return "nop";
871 case 0x31:
872 return "rdtsc";
873 case 0xA2:
874 return "cpuid";
875 case 0xBE:
876 return "movsxb";
877 case 0xBF:
878 return "movsxw";
879 case 0xB6:
880 return "movzxb";
881 case 0xB7:
882 return "movzxw";
883 case 0xAF:
884 return "imul";
885 case 0xA5:
886 return "shld";
887 case 0xAD:
888 return "shrd";
889 case 0xAB:
890 return "bts";
891 default:
892 return NULL;
893 }
894 }
895
896 // Disassembled instruction '*instr' and writes it into 'out_buffer'.
897 int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
898 byte* instr) {
899 tmp_buffer_pos_ = 0; // starting to write as position 0
900 byte* data = instr;
901 bool processed = true; // Will be set to false if the current instruction
902 // is not in 'instructions' table.
903 byte current;
904
905 // Scan for prefixes.
906 while (true) {
907 current = *data;
908 if (current == 0x66) {
909 setOperandSizePrefix(current);
910 data++;
911 } else if ((current & 0xF0) == 0x40) {
912 setRex(current);
913 if (rex_w()) AppendToBuffer("REX.W ");
914 data++;
915 } else {
916 break;
917 }
918 }
919
920 const InstructionDesc& idesc = instruction_table.Get(current);
921 switch (idesc.type) {
922 case ZERO_OPERANDS_INSTR:
923 AppendToBuffer(idesc.mnem);
924 data++;
925 break;
926
927 case TWO_OPERANDS_INSTR:
928 data++;
929 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
930 break;
931
932 case JUMP_CONDITIONAL_SHORT_INSTR:
933 data += JumpConditionalShort(data);
934 break;
935
936 case REGISTER_INSTR:
937 AppendToBuffer("%s%c %s",
938 idesc.mnem,
939 operand_size_code(),
940 NameOfCPURegister(base_reg(current & 0x07)));
941 data++;
942 break;
943 case PUSHPOP_INSTR:
944 AppendToBuffer("%s %s",
945 idesc.mnem,
946 NameOfCPURegister(base_reg(current & 0x07)));
947 data++;
948 break;
949 case MOVE_REG_INSTR: {
950 byte* addr = NULL;
951 switch (operand_size()) {
952 case 16:
953 addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
954 data += 3;
955 break;
956 case 32:
957 addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
958 data += 5;
959 break;
960 case 64:
961 addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
962 data += 9;
963 break;
964 default:
965 UNREACHABLE();
966 }
967 AppendToBuffer("mov%c %s,%s",
968 operand_size_code(),
969 NameOfCPURegister(base_reg(current & 0x07)),
970 NameOfAddress(addr));
971 break;
972 }
973
974 case CALL_JUMP_INSTR: {
975 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
976 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
977 data += 5;
978 break;
979 }
980
981 case SHORT_IMMEDIATE_INSTR: {
982 byte* addr =
983 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
984 AppendToBuffer("%s rax, %s", idesc.mnem, NameOfAddress(addr));
985 data += 5;
986 break;
987 }
988
989 case NO_INSTR:
990 processed = false;
991 break;
992
993 default:
994 UNIMPLEMENTED(); // This type is not implemented.
995 }
996 //----------------------------
William Hesse 2009/07/07 12:30:59 This isn't really standard. Couldn't you put an e
997 if (!processed) {
998 switch (*data) {
999 case 0xC2:
1000 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
1001 data += 3;
1002 break;
1003
1004 case 0x69: // fall through
1005 case 0x6B: {
1006 int mod, regop, rm;
1007 get_modrm(*(data + 1), &mod, &regop, &rm);
1008 int32_t imm = *data == 0x6B ? *(data + 2)
1009 : *reinterpret_cast<int32_t*>(data + 2);
1010 AppendToBuffer("imul %s,%s,0x%x", NameOfCPURegister(regop),
1011 NameOfCPURegister(rm), imm);
1012 data += 2 + (*data == 0x6B ? 1 : 4);
1013 }
1014 break;
1015
1016 case 0xF6: {
1017 int mod, regop, rm;
1018 get_modrm(*(data + 1), &mod, &regop, &rm);
1019 if (mod == 3 && regop == 0) {
1020 AppendToBuffer("testb %s,%d", NameOfCPURegister(rm), *(data + 2));
1021 } else {
1022 UnimplementedInstruction();
1023 }
1024 data += 3;
1025 }
1026 break;
1027
1028 case 0x81: // fall through
1029 case 0x83: // 0x81 with sign extension bit set
1030 data += PrintImmediateOp(data);
1031 break;
1032
1033 case 0x0F: {
1034 byte f0byte = *(data + 1);
1035 const char* f0mnem = F0Mnem(f0byte);
1036 if (f0byte == 0x1F) {
1037 data += 1;
1038 byte modrm = *data;
1039 data += 1;
1040 if (((modrm >> 3) & 7) == 4) {
1041 // SIB byte present.
1042 data += 1;
1043 }
1044 int mod = modrm >> 6;
1045 if (mod == 1) {
1046 // Byte displacement.
1047 data += 1;
1048 } else if (mod == 2) {
1049 // 32-bit displacement.
1050 data += 4;
1051 }
1052 AppendToBuffer("nop");
1053 } else if (f0byte == 0xA2 || f0byte == 0x31) {
1054 AppendToBuffer("%s", f0mnem);
1055 data += 2;
1056 } else if ((f0byte & 0xF0) == 0x80) {
1057 data += JumpConditional(data);
1058 } else if (f0byte == 0xBE || f0byte == 0xBF || f0byte == 0xB6 || f0byte
1059 == 0xB7 || f0byte == 0xAF) {
1060 data += 2;
1061 data += PrintOperands(f0mnem, REG_OPER_OP_ORDER, data);
1062 } else if ((f0byte & 0xF0) == 0x90) {
1063 data += SetCC(data);
1064 } else {
1065 data += 2;
1066 if (f0byte == 0xAB || f0byte == 0xA5 || f0byte == 0xAD) {
1067 // shrd, shld, bts
1068 AppendToBuffer("%s ", f0mnem);
1069 int mod, regop, rm;
1070 get_modrm(*data, &mod, &regop, &rm);
1071 data += PrintRightOperand(data);
1072 if (f0byte == 0xAB) {
1073 AppendToBuffer(",%s", NameOfCPURegister(regop));
1074 } else {
1075 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1076 }
1077 } else {
1078 UnimplementedInstruction();
1079 }
1080 }
1081 }
1082 break;
1083
1084 case 0x8F: {
1085 data++;
1086 int mod, regop, rm;
1087 get_modrm(*data, &mod, &regop, &rm);
1088 if (regop == 0) {
1089 AppendToBuffer("pop ");
1090 data += PrintRightOperand(data);
1091 }
1092 }
1093 break;
1094
1095 case 0xFF: {
1096 data++;
1097 int mod, regop, rm;
1098 get_modrm(*data, &mod, &regop, &rm);
1099 const char* mnem = NULL;
1100 switch (regop) {
1101 case 0:
1102 mnem = "inc";
1103 break;
1104 case 1:
1105 mnem = "dec";
1106 break;
1107 case 2:
1108 mnem = "call";
1109 break;
1110 case 4:
1111 mnem = "jmp";
1112 break;
1113 case 6:
1114 mnem = "push";
1115 break;
1116 default:
1117 mnem = "???";
1118 }
1119 AppendToBuffer(((regop <= 1) ? "%s%c " : "%s "),
1120 mnem,
1121 operand_size_code());
1122 data += PrintRightOperand(data);
1123 }
1124 break;
1125
1126 case 0xC7: // imm32, fall through
1127 case 0xC6: // imm8
1128 {
1129 bool is_byte = *data == 0xC6;
1130 data++;
1131
1132 AppendToBuffer("mov%c ", is_byte ? 'b' : operand_size_code());
1133 data += PrintRightOperand(data);
1134 int32_t imm = is_byte ? *data : *reinterpret_cast<int32_t*>(data);
1135 AppendToBuffer(",0x%x", imm);
1136 data += is_byte ? 1 : 4;
1137 }
1138 break;
1139
1140 case 0x80: {
1141 data++;
1142 AppendToBuffer("cmpb ");
1143 data += PrintRightOperand(data);
1144 int32_t imm = *data;
1145 AppendToBuffer(",0x%x", imm);
1146 data++;
1147 }
1148 break;
1149
1150 case 0x88: // 8bit, fall through
1151 case 0x89: // 32bit
1152 {
1153 bool is_byte = *data == 0x88;
1154 int mod, regop, rm;
1155 data++;
1156 get_modrm(*data, &mod, &regop, &rm);
1157 AppendToBuffer("mov%c ", is_byte ? 'b' : operand_size_code());
1158 data += PrintRightOperand(data);
1159 AppendToBuffer(",%s", NameOfCPURegister(regop));
1160 }
1161 break;
1162
1163 case 0x90:
1164 case 0x91:
1165 case 0x92:
1166 case 0x93:
1167 case 0x94:
1168 case 0x95:
1169 case 0x96:
1170 case 0x97: {
1171 int reg = current & 0x7 | (rex_b() ? 8 : 0);
1172 if (reg == 0) {
1173 AppendToBuffer("nop"); // Common name for xchg rax,rax.
1174 } else {
1175 AppendToBuffer("xchg%c rax, %s",
1176 operand_size_code(),
1177 NameOfByteCPURegister(reg));
1178 }
1179 }
1180
1181
1182 case 0xFE: {
1183 data++;
1184 int mod, regop, rm;
1185 get_modrm(*data, &mod, &regop, &rm);
1186 if (mod == 3 && regop == 1) {
1187 AppendToBuffer("decb %s", NameOfCPURegister(rm));
1188 } else {
1189 UnimplementedInstruction();
1190 }
1191 data++;
1192 }
1193 break;
1194
1195 case 0x68:
1196 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
1197 data += 5;
1198 break;
1199
1200 case 0x6A:
1201 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1202 data += 2;
1203 break;
1204
1205 case 0xA8:
1206 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
1207 data += 2;
1208 break;
1209
1210 case 0xA9:
1211 AppendToBuffer("test%c rax,0x%x", // CHECKME!
1212 operand_size_code(),
1213 *reinterpret_cast<int32_t*>(data + 1));
1214 data += 5;
1215 break;
1216
1217 case 0xD1: // fall through
1218 case 0xD3: // fall through
1219 case 0xC1:
1220 data += D1D3C1Instruction(data);
1221 break;
1222
1223 case 0xD9: // fall through
1224 case 0xDA: // fall through
1225 case 0xDB: // fall through
1226 case 0xDC: // fall through
1227 case 0xDD: // fall through
1228 case 0xDE: // fall through
1229 case 0xDF:
1230 data += FPUInstruction(data);
1231 break;
1232
1233 case 0xEB:
1234 data += JumpShort(data);
1235 break;
1236
1237 case 0xF2:
1238 if (*(data + 1) == 0x0F) {
1239 byte b2 = *(data + 2);
1240 if (b2 == 0x11) {
1241 AppendToBuffer("movsd ");
1242 data += 3;
1243 int mod, regop, rm;
1244 get_modrm(*data, &mod, &regop, &rm);
1245 data += PrintRightOperand(data);
1246 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1247 } else if (b2 == 0x10) {
1248 data += 3;
1249 int mod, regop, rm;
1250 get_modrm(*data, &mod, &regop, &rm);
1251 AppendToBuffer("movsd %s,", NameOfXMMRegister(regop));
1252 data += PrintRightOperand(data);
1253 } else {
1254 const char* mnem = "?";
1255 switch (b2) {
1256 case 0x2A:
1257 mnem = "cvtsi2sd";
1258 break;
1259 case 0x58:
1260 mnem = "addsd";
1261 break;
1262 case 0x59:
1263 mnem = "mulsd";
1264 break;
1265 case 0x5C:
1266 mnem = "subsd";
1267 break;
1268 case 0x5E:
1269 mnem = "divsd";
1270 break;
1271 }
1272 data += 3;
1273 int mod, regop, rm;
1274 get_modrm(*data, &mod, &regop, &rm);
1275 if (b2 == 0x2A) {
1276 AppendToBuffer("%s %s,", mnem, NameOfXMMRegister(regop));
1277 data += PrintRightOperand(data);
1278 } else {
1279 AppendToBuffer("%s %s,%s", mnem, NameOfXMMRegister(regop),
1280 NameOfXMMRegister(rm));
1281 data++;
1282 }
1283 }
1284 } else {
1285 UnimplementedInstruction();
1286 }
1287 break;
1288
1289 case 0xF3:
1290 if (*(data + 1) == 0x0F && *(data + 2) == 0x2C) {
1291 data += 3;
1292 data += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, data);
1293 } else {
1294 UnimplementedInstruction();
1295 }
1296 break;
1297
1298 case 0xF7:
1299 data += F7Instruction(data);
1300 break;
1301
1302 default:
1303 UnimplementedInstruction();
1304 }
1305 }
1306
1307 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1308 tmp_buffer_[tmp_buffer_pos_] = '\0';
1309 }
1310
1311 int instr_len = data - instr;
1312 ASSERT(instr_len > 0); // Ensure progress.
1313
1314 int outp = 0;
1315 // Instruction bytes.
1316 for (byte* bp = instr; bp < data; bp++) {
1317 outp += v8::internal::OS::SNPrintF(out_buffer + outp, "%02x", *bp);
1318 }
1319 for (int i = 6 - instr_len; i >= 0; i--) {
1320 outp += v8::internal::OS::SNPrintF(out_buffer + outp, " ");
1321 }
1322
1323 outp += v8::internal::OS::SNPrintF(out_buffer + outp, " %s",
1324 tmp_buffer_.start());
1325 return instr_len;
1326 }
1327
1328 //------------------------------------------------------------------------------
1329
1330
1331 static const char* cpu_regs[16] = {
1332 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
1333 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
1334 };
1335
1336
1337 static const char* byte_cpu_regs[16] = {
1338 "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
1339 "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
1340 };
1341
1342
1343 static const char* xmm_regs[16] = {
1344 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
1345 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
1346 };
1347
1348
1349 const char* NameConverter::NameOfAddress(byte* addr) const {
1350 static v8::internal::EmbeddedVector<char, 32> tmp_buffer;
1351 v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr);
1352 return tmp_buffer.start();
1353 }
1354
1355
1356 const char* NameConverter::NameOfConstant(byte* addr) const {
1357 return NameOfAddress(addr);
47 } 1358 }
48 1359
49 1360
50 const char* NameConverter::NameOfCPURegister(int reg) const { 1361 const char* NameConverter::NameOfCPURegister(int reg) const {
51 UNIMPLEMENTED(); 1362 if (0 <= reg && reg < 16)
52 return NULL; 1363 return cpu_regs[reg];
53 } 1364 return "noreg";
54 1365 }
55 1366
56 int Disassembler::ConstantPoolSizeAt(unsigned char* addr) { 1367
57 UNIMPLEMENTED(); 1368 const char* NameConverter::NameOfByteCPURegister(int reg) const {
58 return 0; 1369 if (0 <= reg && reg < 16)
59 } 1370 return byte_cpu_regs[reg];
1371 return "noreg";
1372 }
1373
1374
1375 const char* NameConverter::NameOfXMMRegister(int reg) const {
1376 if (0 <= reg && reg < 16)
1377 return xmm_regs[reg];
1378 return "noxmmreg";
1379 }
1380
1381
1382 const char* NameConverter::NameInCode(byte* addr) const {
1383 // X64 does not embed debug strings at the moment.
1384 UNREACHABLE();
1385 return "";
1386 }
1387
1388 //------------------------------------------------------------------------------
1389
1390 Disassembler::Disassembler(const NameConverter& converter)
1391 : converter_(converter) { }
1392
1393 Disassembler::~Disassembler() { }
60 1394
61 1395
62 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer, 1396 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
63 unsigned char* instruction) { 1397 byte* instruction) {
64 UNIMPLEMENTED(); 1398 DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE);
65 return 0; 1399 return d.InstructionDecode(buffer, instruction);
66 } 1400 }
67 1401
68 const char* NameConverter::NameOfByteCPURegister(int a) const { 1402
69 UNIMPLEMENTED(); 1403 // The X64 assembler does not use constant pools.
70 return NULL; 1404 int Disassembler::ConstantPoolSizeAt(byte* instruction) {
71 } 1405 return -1;
72 1406 }
73 const char* NameConverter::NameOfXMMRegister(int a) const { 1407
74 UNIMPLEMENTED(); 1408
75 return NULL; 1409 void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
76 } 1410 NameConverter converter;
77 1411 Disassembler d(converter);
78 const char* NameConverter::NameOfConstant(unsigned char* a) const { 1412 for (byte* pc = begin; pc < end;) {
79 UNIMPLEMENTED(); 1413 v8::internal::EmbeddedVector<char, 128> buffer;
80 return NULL; 1414 buffer[0] = '\0';
81 } 1415 byte* prev_pc = pc;
82 1416 pc += d.InstructionDecode(buffer, pc);
83 const char* NameConverter::NameInCode(unsigned char* a) const { 1417 fprintf(f, "%p", prev_pc);
84 UNIMPLEMENTED(); 1418 fprintf(f, " ");
85 return NULL; 1419
1420 for (byte* bp = prev_pc; bp < pc; bp++) {
1421 fprintf(f, "%02x", *bp);
1422 }
1423 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
1424 fprintf(f, " ");
1425 }
1426 fprintf(f, " %s\n", buffer.start());
1427 }
86 } 1428 }
87 1429
88 } // namespace disasm 1430 } // namespace disasm
OLDNEW
« no previous file with comments | « src/x64/assembler-x64.cc ('k') | src/x64/macro-assembler-x64.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698