blob: 0b43e766e6849d9f59939395cac2c6b19bcc5d1c [file] [log] [blame]
Steve Blocka7e24c12009-10-30 11:49:00 +00001// Copyright 2009 the V8 project authors. All rights reserved.
2// Redistribution and use in source and binary forms, with or without
3// modification, are permitted provided that the following conditions are
4// met:
5//
6// * Redistributions of source code must retain the above copyright
7// notice, this list of conditions and the following disclaimer.
8// * Redistributions in binary form must reproduce the above
9// copyright notice, this list of conditions and the following
10// disclaimer in the documentation and/or other materials provided
11// with the distribution.
12// * Neither the name of Google Inc. nor the names of its
13// contributors may be used to endorse or promote products derived
14// from this software without specific prior written permission.
15//
16// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
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.
27
28#include <assert.h>
29#include <stdio.h>
30#include <stdarg.h>
31
32#include "v8.h"
33#include "disasm.h"
34
35namespace disasm {
36
37enum OperandType {
38 UNSET_OP_ORDER = 0,
39 // Operand size decides between 16, 32 and 64 bit operands.
40 REG_OPER_OP_ORDER = 1, // Register destination, operand source.
41 OPER_REG_OP_ORDER = 2, // Operand destination, register source.
42 // Fixed 8-bit operands.
43 BYTE_SIZE_OPERAND_FLAG = 4,
44 BYTE_REG_OPER_OP_ORDER = REG_OPER_OP_ORDER | BYTE_SIZE_OPERAND_FLAG,
45 BYTE_OPER_REG_OP_ORDER = OPER_REG_OP_ORDER | BYTE_SIZE_OPERAND_FLAG
46};
47
48//------------------------------------------------------------------
49// Tables
50//------------------------------------------------------------------
51struct ByteMnemonic {
52 int b; // -1 terminates, otherwise must be in range (0..255)
53 OperandType op_order_;
54 const char* mnem;
55};
56
57
58static ByteMnemonic two_operands_instr[] = {
59 { 0x00, BYTE_OPER_REG_OP_ORDER, "add" },
60 { 0x01, OPER_REG_OP_ORDER, "add" },
61 { 0x02, BYTE_REG_OPER_OP_ORDER, "add" },
62 { 0x03, REG_OPER_OP_ORDER, "add" },
63 { 0x08, BYTE_OPER_REG_OP_ORDER, "or" },
64 { 0x09, OPER_REG_OP_ORDER, "or" },
65 { 0x0A, BYTE_REG_OPER_OP_ORDER, "or" },
66 { 0x0B, REG_OPER_OP_ORDER, "or" },
67 { 0x10, BYTE_OPER_REG_OP_ORDER, "adc" },
68 { 0x11, OPER_REG_OP_ORDER, "adc" },
69 { 0x12, BYTE_REG_OPER_OP_ORDER, "adc" },
70 { 0x13, REG_OPER_OP_ORDER, "adc" },
71 { 0x18, BYTE_OPER_REG_OP_ORDER, "sbb" },
72 { 0x19, OPER_REG_OP_ORDER, "sbb" },
73 { 0x1A, BYTE_REG_OPER_OP_ORDER, "sbb" },
74 { 0x1B, REG_OPER_OP_ORDER, "sbb" },
75 { 0x20, BYTE_OPER_REG_OP_ORDER, "and" },
76 { 0x21, OPER_REG_OP_ORDER, "and" },
77 { 0x22, BYTE_REG_OPER_OP_ORDER, "and" },
78 { 0x23, REG_OPER_OP_ORDER, "and" },
79 { 0x28, BYTE_OPER_REG_OP_ORDER, "sub" },
80 { 0x29, OPER_REG_OP_ORDER, "sub" },
81 { 0x2A, BYTE_REG_OPER_OP_ORDER, "sub" },
82 { 0x2B, REG_OPER_OP_ORDER, "sub" },
83 { 0x30, BYTE_OPER_REG_OP_ORDER, "xor" },
84 { 0x31, OPER_REG_OP_ORDER, "xor" },
85 { 0x32, BYTE_REG_OPER_OP_ORDER, "xor" },
86 { 0x33, REG_OPER_OP_ORDER, "xor" },
87 { 0x38, BYTE_OPER_REG_OP_ORDER, "cmp" },
88 { 0x39, OPER_REG_OP_ORDER, "cmp" },
89 { 0x3A, BYTE_REG_OPER_OP_ORDER, "cmp" },
90 { 0x3B, REG_OPER_OP_ORDER, "cmp" },
91 { 0x63, REG_OPER_OP_ORDER, "movsxlq" },
92 { 0x84, BYTE_REG_OPER_OP_ORDER, "test" },
93 { 0x85, REG_OPER_OP_ORDER, "test" },
94 { 0x86, BYTE_REG_OPER_OP_ORDER, "xchg" },
95 { 0x87, REG_OPER_OP_ORDER, "xchg" },
96 { 0x88, BYTE_OPER_REG_OP_ORDER, "mov" },
97 { 0x89, OPER_REG_OP_ORDER, "mov" },
98 { 0x8A, BYTE_REG_OPER_OP_ORDER, "mov" },
99 { 0x8B, REG_OPER_OP_ORDER, "mov" },
100 { 0x8D, REG_OPER_OP_ORDER, "lea" },
101 { -1, UNSET_OP_ORDER, "" }
102};
103
104
105static ByteMnemonic zero_operands_instr[] = {
106 { 0xC3, UNSET_OP_ORDER, "ret" },
107 { 0xC9, UNSET_OP_ORDER, "leave" },
108 { 0xF4, UNSET_OP_ORDER, "hlt" },
109 { 0xCC, UNSET_OP_ORDER, "int3" },
110 { 0x60, UNSET_OP_ORDER, "pushad" },
111 { 0x61, UNSET_OP_ORDER, "popad" },
112 { 0x9C, UNSET_OP_ORDER, "pushfd" },
113 { 0x9D, UNSET_OP_ORDER, "popfd" },
114 { 0x9E, UNSET_OP_ORDER, "sahf" },
115 { 0x99, UNSET_OP_ORDER, "cdq" },
116 { 0x9B, UNSET_OP_ORDER, "fwait" },
117 { -1, UNSET_OP_ORDER, "" }
118};
119
120
121static ByteMnemonic call_jump_instr[] = {
122 { 0xE8, UNSET_OP_ORDER, "call" },
123 { 0xE9, UNSET_OP_ORDER, "jmp" },
124 { -1, UNSET_OP_ORDER, "" }
125};
126
127
128static ByteMnemonic short_immediate_instr[] = {
129 { 0x05, UNSET_OP_ORDER, "add" },
130 { 0x0D, UNSET_OP_ORDER, "or" },
131 { 0x15, UNSET_OP_ORDER, "adc" },
132 { 0x1D, UNSET_OP_ORDER, "sbb" },
133 { 0x25, UNSET_OP_ORDER, "and" },
134 { 0x2D, UNSET_OP_ORDER, "sub" },
135 { 0x35, UNSET_OP_ORDER, "xor" },
136 { 0x3D, UNSET_OP_ORDER, "cmp" },
137 { -1, UNSET_OP_ORDER, "" }
138};
139
140
141static const char* conditional_code_suffix[] = {
142 "o", "no", "c", "nc", "z", "nz", "na", "a",
143 "s", "ns", "pe", "po", "l", "ge", "le", "g"
144};
145
146
147enum InstructionType {
148 NO_INSTR,
149 ZERO_OPERANDS_INSTR,
150 TWO_OPERANDS_INSTR,
151 JUMP_CONDITIONAL_SHORT_INSTR,
152 REGISTER_INSTR,
153 PUSHPOP_INSTR, // Has implicit 64-bit operand size.
154 MOVE_REG_INSTR,
155 CALL_JUMP_INSTR,
156 SHORT_IMMEDIATE_INSTR
157};
158
159
160struct InstructionDesc {
161 const char* mnem;
162 InstructionType type;
163 OperandType op_order_;
164 bool byte_size_operation; // Fixed 8-bit operation.
165};
166
167
168class InstructionTable {
169 public:
170 InstructionTable();
171 const InstructionDesc& Get(byte x) const {
172 return instructions_[x];
173 }
174
175 private:
176 InstructionDesc instructions_[256];
177 void Clear();
178 void Init();
179 void CopyTable(ByteMnemonic bm[], InstructionType type);
180 void SetTableRange(InstructionType type, byte start, byte end, bool byte_size,
181 const char* mnem);
182 void AddJumpConditionalShort();
183};
184
185
186InstructionTable::InstructionTable() {
187 Clear();
188 Init();
189}
190
191
192void InstructionTable::Clear() {
193 for (int i = 0; i < 256; i++) {
194 instructions_[i].mnem = "(bad)";
195 instructions_[i].type = NO_INSTR;
196 instructions_[i].op_order_ = UNSET_OP_ORDER;
197 instructions_[i].byte_size_operation = false;
198 }
199}
200
201
202void InstructionTable::Init() {
203 CopyTable(two_operands_instr, TWO_OPERANDS_INSTR);
204 CopyTable(zero_operands_instr, ZERO_OPERANDS_INSTR);
205 CopyTable(call_jump_instr, CALL_JUMP_INSTR);
206 CopyTable(short_immediate_instr, SHORT_IMMEDIATE_INSTR);
207 AddJumpConditionalShort();
208 SetTableRange(PUSHPOP_INSTR, 0x50, 0x57, false, "push");
209 SetTableRange(PUSHPOP_INSTR, 0x58, 0x5F, false, "pop");
210 SetTableRange(MOVE_REG_INSTR, 0xB8, 0xBF, false, "mov");
211}
212
213
214void InstructionTable::CopyTable(ByteMnemonic bm[], InstructionType type) {
215 for (int i = 0; bm[i].b >= 0; i++) {
216 InstructionDesc* id = &instructions_[bm[i].b];
217 id->mnem = bm[i].mnem;
218 OperandType op_order = bm[i].op_order_;
219 id->op_order_ =
220 static_cast<OperandType>(op_order & ~BYTE_SIZE_OPERAND_FLAG);
Steve Blockd0582a62009-12-15 09:54:21 +0000221 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered
Steve Blocka7e24c12009-10-30 11:49:00 +0000222 id->type = type;
223 id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
224 }
225}
226
227
228void InstructionTable::SetTableRange(InstructionType type,
229 byte start,
230 byte end,
231 bool byte_size,
232 const char* mnem) {
233 for (byte b = start; b <= end; b++) {
234 InstructionDesc* id = &instructions_[b];
Steve Blockd0582a62009-12-15 09:54:21 +0000235 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered
Steve Blocka7e24c12009-10-30 11:49:00 +0000236 id->mnem = mnem;
237 id->type = type;
238 id->byte_size_operation = byte_size;
239 }
240}
241
242
243void InstructionTable::AddJumpConditionalShort() {
244 for (byte b = 0x70; b <= 0x7F; b++) {
245 InstructionDesc* id = &instructions_[b];
Steve Blockd0582a62009-12-15 09:54:21 +0000246 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered
Steve Blocka7e24c12009-10-30 11:49:00 +0000247 id->mnem = NULL; // Computed depending on condition code.
248 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
249 }
250}
251
252
253static InstructionTable instruction_table;
254
255static InstructionDesc cmov_instructions[16] = {
256 {"cmovo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
257 {"cmovno", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
258 {"cmovc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
259 {"cmovnc", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
260 {"cmovz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
261 {"cmovnz", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
262 {"cmovna", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
263 {"cmova", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
264 {"cmovs", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
265 {"cmovns", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
266 {"cmovpe", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
267 {"cmovpo", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
268 {"cmovl", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
269 {"cmovge", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
270 {"cmovle", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false},
271 {"cmovg", TWO_OPERANDS_INSTR, REG_OPER_OP_ORDER, false}
272};
273
274//------------------------------------------------------------------------------
275// DisassemblerX64 implementation.
276
277enum UnimplementedOpcodeAction {
278 CONTINUE_ON_UNIMPLEMENTED_OPCODE,
279 ABORT_ON_UNIMPLEMENTED_OPCODE
280};
281
282// A new DisassemblerX64 object is created to disassemble each instruction.
283// The object can only disassemble a single instruction.
284class DisassemblerX64 {
285 public:
286 DisassemblerX64(const NameConverter& converter,
287 UnimplementedOpcodeAction unimplemented_action =
288 ABORT_ON_UNIMPLEMENTED_OPCODE)
289 : converter_(converter),
290 tmp_buffer_pos_(0),
291 abort_on_unimplemented_(
292 unimplemented_action == ABORT_ON_UNIMPLEMENTED_OPCODE),
293 rex_(0),
294 operand_size_(0),
295 group_1_prefix_(0),
296 byte_size_operand_(false) {
297 tmp_buffer_[0] = '\0';
298 }
299
300 virtual ~DisassemblerX64() {
301 }
302
303 // Writes one disassembled instruction into 'buffer' (0-terminated).
304 // Returns the length of the disassembled machine instruction in bytes.
305 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction);
306
307 private:
308 enum OperandSize {
309 BYTE_SIZE = 0,
310 WORD_SIZE = 1,
311 DOUBLEWORD_SIZE = 2,
312 QUADWORD_SIZE = 3
313 };
314
315 const NameConverter& converter_;
316 v8::internal::EmbeddedVector<char, 128> tmp_buffer_;
317 unsigned int tmp_buffer_pos_;
318 bool abort_on_unimplemented_;
319 // Prefixes parsed
320 byte rex_;
321 byte operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0.
322 byte group_1_prefix_; // 0xF2, 0xF3, or (if no group 1 prefix is present) 0.
323 // Byte size operand override.
324 bool byte_size_operand_;
325
326 void setRex(byte rex) {
327 ASSERT_EQ(0x40, rex & 0xF0);
328 rex_ = rex;
329 }
330
331 bool rex() { return rex_ != 0; }
332
333 bool rex_b() { return (rex_ & 0x01) != 0; }
334
335 // Actual number of base register given the low bits and the rex.b state.
336 int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); }
337
338 bool rex_x() { return (rex_ & 0x02) != 0; }
339
340 bool rex_r() { return (rex_ & 0x04) != 0; }
341
342 bool rex_w() { return (rex_ & 0x08) != 0; }
343
344 OperandSize operand_size() {
345 if (byte_size_operand_) return BYTE_SIZE;
346 if (rex_w()) return QUADWORD_SIZE;
347 if (operand_size_ != 0) return WORD_SIZE;
348 return DOUBLEWORD_SIZE;
349 }
350
351 char operand_size_code() {
352 return "bwlq"[operand_size()];
353 }
354
355 const char* NameOfCPURegister(int reg) const {
356 return converter_.NameOfCPURegister(reg);
357 }
358
359 const char* NameOfByteCPURegister(int reg) const {
360 return converter_.NameOfByteCPURegister(reg);
361 }
362
363 const char* NameOfXMMRegister(int reg) const {
364 return converter_.NameOfXMMRegister(reg);
365 }
366
367 const char* NameOfAddress(byte* addr) const {
368 return converter_.NameOfAddress(addr);
369 }
370
371 // Disassembler helper functions.
372 void get_modrm(byte data,
373 int* mod,
374 int* regop,
375 int* rm) {
376 *mod = (data >> 6) & 3;
377 *regop = ((data & 0x38) >> 3) | (rex_r() ? 8 : 0);
378 *rm = (data & 7) | (rex_b() ? 8 : 0);
379 }
380
381 void get_sib(byte data,
382 int* scale,
383 int* index,
384 int* base) {
385 *scale = (data >> 6) & 3;
386 *index = ((data >> 3) & 7) | (rex_x() ? 8 : 0);
387 *base = (data & 7) | (rex_b() ? 8 : 0);
388 }
389
390 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const;
391
392 int PrintRightOperandHelper(byte* modrmp,
393 RegisterNameMapping register_name);
394 int PrintRightOperand(byte* modrmp);
395 int PrintRightByteOperand(byte* modrmp);
Steve Blockd0582a62009-12-15 09:54:21 +0000396 int PrintRightXMMOperand(byte* modrmp);
Steve Blocka7e24c12009-10-30 11:49:00 +0000397 int PrintOperands(const char* mnem,
398 OperandType op_order,
399 byte* data);
400 int PrintImmediate(byte* data, OperandSize size);
401 int PrintImmediateOp(byte* data);
402 const char* TwoByteMnemonic(byte opcode);
403 int TwoByteOpcodeInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000404 int F6F7Instruction(byte* data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000405 int ShiftInstruction(byte* data);
406 int JumpShort(byte* data);
407 int JumpConditional(byte* data);
408 int JumpConditionalShort(byte* data);
409 int SetCC(byte* data);
410 int FPUInstruction(byte* data);
Steve Blockd0582a62009-12-15 09:54:21 +0000411 int MemoryFPUInstruction(int escape_opcode, int regop, byte* modrm_start);
412 int RegisterFPUInstruction(int escape_opcode, byte modrm_byte);
Steve Blocka7e24c12009-10-30 11:49:00 +0000413 void AppendToBuffer(const char* format, ...);
414
415 void UnimplementedInstruction() {
416 if (abort_on_unimplemented_) {
417 CHECK(false);
418 } else {
419 AppendToBuffer("'Unimplemented Instruction'");
420 }
421 }
422};
423
424
425void DisassemblerX64::AppendToBuffer(const char* format, ...) {
426 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
427 va_list args;
428 va_start(args, format);
429 int result = v8::internal::OS::VSNPrintF(buf, format, args);
430 va_end(args);
431 tmp_buffer_pos_ += result;
432}
433
434
435int DisassemblerX64::PrintRightOperandHelper(
436 byte* modrmp,
437 RegisterNameMapping register_name) {
438 int mod, regop, rm;
439 get_modrm(*modrmp, &mod, &regop, &rm);
440 switch (mod) {
441 case 0:
442 if ((rm & 7) == 5) {
443 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1);
444 AppendToBuffer("[0x%x]", disp);
445 return 5;
446 } else if ((rm & 7) == 4) {
447 // Codes for SIB byte.
448 byte sib = *(modrmp + 1);
449 int scale, index, base;
450 get_sib(sib, &scale, &index, &base);
451 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
452 // index == rsp means no index. Only use sib byte with no index for
453 // rsp and r12 base.
454 AppendToBuffer("[%s]", (this->*register_name)(base));
455 return 2;
456 } else if (base == 5) {
457 // base == rbp means no base register (when mod == 0).
458 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
459 AppendToBuffer("[%s*%d+0x%x]",
460 (this->*register_name)(index),
461 1 << scale, disp);
462 return 6;
463 } else if (index != 4 && base != 5) {
464 // [base+index*scale]
465 AppendToBuffer("[%s+%s*%d]",
466 (this->*register_name)(base),
467 (this->*register_name)(index),
468 1 << scale);
469 return 2;
470 } else {
471 UnimplementedInstruction();
472 return 1;
473 }
474 } else {
475 AppendToBuffer("[%s]", (this->*register_name)(rm));
476 return 1;
477 }
478 break;
479 case 1: // fall through
480 case 2:
481 if ((rm & 7) == 4) {
482 byte sib = *(modrmp + 1);
483 int scale, index, base;
484 get_sib(sib, &scale, &index, &base);
485 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2)
486 : *reinterpret_cast<char*>(modrmp + 2);
487 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
488 if (-disp > 0) {
489 AppendToBuffer("[%s-0x%x]", (this->*register_name)(base), -disp);
490 } else {
491 AppendToBuffer("[%s+0x%x]", (this->*register_name)(base), disp);
492 }
493 } else {
494 if (-disp > 0) {
495 AppendToBuffer("[%s+%s*%d-0x%x]",
496 (this->*register_name)(base),
497 (this->*register_name)(index),
498 1 << scale,
499 -disp);
500 } else {
501 AppendToBuffer("[%s+%s*%d+0x%x]",
502 (this->*register_name)(base),
503 (this->*register_name)(index),
504 1 << scale,
505 disp);
506 }
507 }
508 return mod == 2 ? 6 : 3;
509 } else {
510 // No sib.
511 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1)
512 : *reinterpret_cast<char*>(modrmp + 1);
513 if (-disp > 0) {
514 AppendToBuffer("[%s-0x%x]", (this->*register_name)(rm), -disp);
515 } else {
516 AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp);
517 }
518 return (mod == 2) ? 5 : 2;
519 }
520 break;
521 case 3:
522 AppendToBuffer("%s", (this->*register_name)(rm));
523 return 1;
524 default:
525 UnimplementedInstruction();
526 return 1;
527 }
528 UNREACHABLE();
529}
530
531
532int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) {
533 int64_t value;
534 int count;
535 switch (size) {
536 case BYTE_SIZE:
537 value = *data;
538 count = 1;
539 break;
540 case WORD_SIZE:
541 value = *reinterpret_cast<int16_t*>(data);
542 count = 2;
543 break;
544 case DOUBLEWORD_SIZE:
545 value = *reinterpret_cast<uint32_t*>(data);
546 count = 4;
547 break;
548 case QUADWORD_SIZE:
549 value = *reinterpret_cast<int32_t*>(data);
550 count = 4;
551 break;
552 default:
553 UNREACHABLE();
554 value = 0; // Initialize variables on all paths to satisfy the compiler.
555 count = 0;
556 }
557 AppendToBuffer("%" V8_PTR_PREFIX "x", value);
558 return count;
559}
560
561
562int DisassemblerX64::PrintRightOperand(byte* modrmp) {
563 return PrintRightOperandHelper(modrmp,
564 &DisassemblerX64::NameOfCPURegister);
565}
566
567
568int DisassemblerX64::PrintRightByteOperand(byte* modrmp) {
569 return PrintRightOperandHelper(modrmp,
570 &DisassemblerX64::NameOfByteCPURegister);
571}
572
573
Steve Blockd0582a62009-12-15 09:54:21 +0000574int DisassemblerX64::PrintRightXMMOperand(byte* modrmp) {
575 return PrintRightOperandHelper(modrmp,
576 &DisassemblerX64::NameOfXMMRegister);
577}
578
579
Steve Blocka7e24c12009-10-30 11:49:00 +0000580// Returns number of bytes used including the current *data.
581// Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
582int DisassemblerX64::PrintOperands(const char* mnem,
583 OperandType op_order,
584 byte* data) {
585 byte modrm = *data;
586 int mod, regop, rm;
587 get_modrm(modrm, &mod, &regop, &rm);
588 int advance = 0;
589 const char* register_name =
590 byte_size_operand_ ? NameOfByteCPURegister(regop)
591 : NameOfCPURegister(regop);
592 switch (op_order) {
593 case REG_OPER_OP_ORDER: {
594 AppendToBuffer("%s%c %s,",
595 mnem,
596 operand_size_code(),
597 register_name);
598 advance = byte_size_operand_ ? PrintRightByteOperand(data)
599 : PrintRightOperand(data);
600 break;
601 }
602 case OPER_REG_OP_ORDER: {
603 AppendToBuffer("%s%c ", mnem, operand_size_code());
604 advance = byte_size_operand_ ? PrintRightByteOperand(data)
605 : PrintRightOperand(data);
606 AppendToBuffer(",%s", register_name);
607 break;
608 }
609 default:
610 UNREACHABLE();
611 break;
612 }
613 return advance;
614}
615
616
617// Returns number of bytes used by machine instruction, including *data byte.
618// Writes immediate instructions to 'tmp_buffer_'.
619int DisassemblerX64::PrintImmediateOp(byte* data) {
620 bool byte_size_immediate = (*data & 0x02) != 0;
621 byte modrm = *(data + 1);
622 int mod, regop, rm;
623 get_modrm(modrm, &mod, &regop, &rm);
624 const char* mnem = "Imm???";
625 switch (regop) {
626 case 0:
627 mnem = "add";
628 break;
629 case 1:
630 mnem = "or";
631 break;
632 case 2:
633 mnem = "adc";
634 break;
635 case 4:
636 mnem = "and";
637 break;
638 case 5:
639 mnem = "sub";
640 break;
641 case 6:
642 mnem = "xor";
643 break;
644 case 7:
645 mnem = "cmp";
646 break;
647 default:
648 UnimplementedInstruction();
649 }
650 AppendToBuffer("%s%c ", mnem, operand_size_code());
651 int count = PrintRightOperand(data + 1);
652 AppendToBuffer(",0x");
653 OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size();
654 count += PrintImmediate(data + 1 + count, immediate_size);
655 return 1 + count;
656}
657
658
659// Returns number of bytes used, including *data.
Steve Blockd0582a62009-12-15 09:54:21 +0000660int DisassemblerX64::F6F7Instruction(byte* data) {
661 ASSERT(*data == 0xF7 || *data == 0xF6);
Steve Blocka7e24c12009-10-30 11:49:00 +0000662 byte modrm = *(data + 1);
663 int mod, regop, rm;
664 get_modrm(modrm, &mod, &regop, &rm);
665 if (mod == 3 && regop != 0) {
666 const char* mnem = NULL;
667 switch (regop) {
668 case 2:
669 mnem = "not";
670 break;
671 case 3:
672 mnem = "neg";
673 break;
674 case 4:
675 mnem = "mul";
676 break;
677 case 7:
678 mnem = "idiv";
679 break;
680 default:
681 UnimplementedInstruction();
682 }
683 AppendToBuffer("%s%c %s",
684 mnem,
685 operand_size_code(),
686 NameOfCPURegister(rm));
687 return 2;
Steve Blocka7e24c12009-10-30 11:49:00 +0000688 } else if (regop == 0) {
689 AppendToBuffer("test%c ", operand_size_code());
Steve Blockd0582a62009-12-15 09:54:21 +0000690 int count = PrintRightOperand(data + 1); // Use name of 64-bit register.
691 AppendToBuffer(",0x");
692 count += PrintImmediate(data + 1 + count, operand_size());
693 return 1 + count;
Steve Blocka7e24c12009-10-30 11:49:00 +0000694 } else {
695 UnimplementedInstruction();
696 return 2;
697 }
698}
699
700
701int DisassemblerX64::ShiftInstruction(byte* data) {
702 byte op = *data & (~1);
703 if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
704 UnimplementedInstruction();
705 return 1;
706 }
707 byte modrm = *(data + 1);
708 int mod, regop, rm;
709 get_modrm(modrm, &mod, &regop, &rm);
710 regop &= 0x7; // The REX.R bit does not affect the operation.
711 int imm8 = -1;
712 int num_bytes = 2;
713 if (mod != 3) {
714 UnimplementedInstruction();
715 return num_bytes;
716 }
717 const char* mnem = NULL;
718 switch (regop) {
719 case 0:
720 mnem = "rol";
721 break;
722 case 1:
723 mnem = "ror";
724 break;
725 case 2:
726 mnem = "rcl";
727 break;
728 case 3:
729 mnem = "rcr";
730 break;
731 case 4:
732 mnem = "shl";
733 break;
734 case 5:
735 mnem = "shr";
736 break;
737 case 7:
738 mnem = "sar";
739 break;
740 default:
741 UnimplementedInstruction();
742 return num_bytes;
743 }
Steve Blockd0582a62009-12-15 09:54:21 +0000744 ASSERT_NE(NULL, mnem);
Steve Blocka7e24c12009-10-30 11:49:00 +0000745 if (op == 0xD0) {
746 imm8 = 1;
747 } else if (op == 0xC0) {
748 imm8 = *(data + 2);
749 num_bytes = 3;
750 }
751 AppendToBuffer("%s%c %s,",
752 mnem,
753 operand_size_code(),
754 byte_size_operand_ ? NameOfByteCPURegister(rm)
755 : NameOfCPURegister(rm));
756 if (op == 0xD2) {
757 AppendToBuffer("cl");
758 } else {
759 AppendToBuffer("%d", imm8);
760 }
761 return num_bytes;
762}
763
764
765// Returns number of bytes used, including *data.
766int DisassemblerX64::JumpShort(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000767 ASSERT_EQ(0xEB, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000768 byte b = *(data + 1);
769 byte* dest = data + static_cast<int8_t>(b) + 2;
770 AppendToBuffer("jmp %s", NameOfAddress(dest));
771 return 2;
772}
773
774
775// Returns number of bytes used, including *data.
776int DisassemblerX64::JumpConditional(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000777 ASSERT_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000778 byte cond = *(data + 1) & 0x0F;
779 byte* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6;
780 const char* mnem = conditional_code_suffix[cond];
781 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
782 return 6; // includes 0x0F
783}
784
785
786// Returns number of bytes used, including *data.
787int DisassemblerX64::JumpConditionalShort(byte* data) {
788 byte cond = *data & 0x0F;
789 byte b = *(data + 1);
790 byte* dest = data + static_cast<int8_t>(b) + 2;
791 const char* mnem = conditional_code_suffix[cond];
792 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
793 return 2;
794}
795
796
797// Returns number of bytes used, including *data.
798int DisassemblerX64::SetCC(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000799 ASSERT_EQ(0x0F, *data);
Steve Blocka7e24c12009-10-30 11:49:00 +0000800 byte cond = *(data + 1) & 0x0F;
801 const char* mnem = conditional_code_suffix[cond];
802 AppendToBuffer("set%s%c ", mnem, operand_size_code());
803 PrintRightByteOperand(data + 2);
804 return 3; // includes 0x0F
805}
806
807
808// Returns number of bytes used, including *data.
809int DisassemblerX64::FPUInstruction(byte* data) {
Steve Blockd0582a62009-12-15 09:54:21 +0000810 byte escape_opcode = *data;
811 ASSERT_EQ(0xD8, escape_opcode & 0xF8);
812 byte modrm_byte = *(data+1);
813
814 if (modrm_byte >= 0xC0) {
815 return RegisterFPUInstruction(escape_opcode, modrm_byte);
816 } else {
817 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1);
Steve Blocka7e24c12009-10-30 11:49:00 +0000818 }
Steve Blockd0582a62009-12-15 09:54:21 +0000819}
820
821int DisassemblerX64::MemoryFPUInstruction(int escape_opcode,
822 int modrm_byte,
823 byte* modrm_start) {
824 const char* mnem = "?";
825 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte.
826 switch (escape_opcode) {
827 case 0xD9: switch (regop) {
828 case 0: mnem = "fld_s"; break;
829 case 3: mnem = "fstp_s"; break;
830 case 7: mnem = "fstcw"; break;
831 default: UnimplementedInstruction();
832 }
833 break;
834
835 case 0xDB: switch (regop) {
836 case 0: mnem = "fild_s"; break;
837 case 1: mnem = "fisttp_s"; break;
838 case 2: mnem = "fist_s"; break;
839 case 3: mnem = "fistp_s"; break;
840 default: UnimplementedInstruction();
841 }
842 break;
843
844 case 0xDD: switch (regop) {
845 case 0: mnem = "fld_d"; break;
846 case 3: mnem = "fstp_d"; break;
847 default: UnimplementedInstruction();
848 }
849 break;
850
851 case 0xDF: switch (regop) {
852 case 5: mnem = "fild_d"; break;
853 case 7: mnem = "fistp_d"; break;
854 default: UnimplementedInstruction();
855 }
856 break;
857
858 default: UnimplementedInstruction();
859 }
860 AppendToBuffer("%s ", mnem);
861 int count = PrintRightOperand(modrm_start);
862 return count + 1;
863}
864
865int DisassemblerX64::RegisterFPUInstruction(int escape_opcode,
866 byte modrm_byte) {
867 bool has_register = false; // Is the FPU register encoded in modrm_byte?
868 const char* mnem = "?";
869
870 switch (escape_opcode) {
871 case 0xD8:
872 UnimplementedInstruction();
873 break;
874
875 case 0xD9:
876 switch (modrm_byte & 0xF8) {
877 case 0xC8:
878 mnem = "fxch";
879 has_register = true;
880 break;
881 default:
882 switch (modrm_byte) {
883 case 0xE0: mnem = "fchs"; break;
884 case 0xE1: mnem = "fabs"; break;
885 case 0xE4: mnem = "ftst"; break;
886 case 0xE8: mnem = "fld1"; break;
887 case 0xEE: mnem = "fldz"; break;
888 case 0xF5: mnem = "fprem1"; break;
889 case 0xF7: mnem = "fincstp"; break;
890 case 0xF8: mnem = "fprem"; break;
891 case 0xFE: mnem = "fsin"; break;
892 case 0xFF: mnem = "fcos"; break;
893 default: UnimplementedInstruction();
894 }
895 }
896 break;
897
898 case 0xDA:
899 if (modrm_byte == 0xE9) {
900 mnem = "fucompp";
901 } else {
902 UnimplementedInstruction();
903 }
904 break;
905
906 case 0xDB:
907 if ((modrm_byte & 0xF8) == 0xE8) {
908 mnem = "fucomi";
909 has_register = true;
910 } else if (modrm_byte == 0xE2) {
911 mnem = "fclex";
912 } else {
913 UnimplementedInstruction();
914 }
915 break;
916
917 case 0xDC:
918 has_register = true;
919 switch (modrm_byte & 0xF8) {
920 case 0xC0: mnem = "fadd"; break;
921 case 0xE8: mnem = "fsub"; break;
922 case 0xC8: mnem = "fmul"; break;
923 case 0xF8: mnem = "fdiv"; break;
924 default: UnimplementedInstruction();
925 }
926 break;
927
928 case 0xDD:
929 has_register = true;
930 switch (modrm_byte & 0xF8) {
931 case 0xC0: mnem = "ffree"; break;
932 case 0xD8: mnem = "fstp"; break;
933 default: UnimplementedInstruction();
934 }
935 break;
936
937 case 0xDE:
938 if (modrm_byte == 0xD9) {
939 mnem = "fcompp";
940 } else {
941 has_register = true;
942 switch (modrm_byte & 0xF8) {
943 case 0xC0: mnem = "faddp"; break;
944 case 0xE8: mnem = "fsubp"; break;
945 case 0xC8: mnem = "fmulp"; break;
946 case 0xF8: mnem = "fdivp"; break;
947 default: UnimplementedInstruction();
948 }
949 }
950 break;
951
952 case 0xDF:
953 if (modrm_byte == 0xE0) {
954 mnem = "fnstsw_ax";
955 } else if ((modrm_byte & 0xF8) == 0xE8) {
956 mnem = "fucomip";
957 has_register = true;
958 }
959 break;
960
961 default: UnimplementedInstruction();
962 }
963
964 if (has_register) {
965 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7);
966 } else {
967 AppendToBuffer("%s", mnem);
968 }
Steve Blocka7e24c12009-10-30 11:49:00 +0000969 return 2;
970}
971
972
Steve Blockd0582a62009-12-15 09:54:21 +0000973
Steve Blocka7e24c12009-10-30 11:49:00 +0000974// Handle all two-byte opcodes, which start with 0x0F.
975// These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
976// We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
977int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
978 byte opcode = *(data + 1);
979 byte* current = data + 2;
980 // At return, "current" points to the start of the next instruction.
981 const char* mnemonic = TwoByteMnemonic(opcode);
982 if (opcode == 0x1F) {
983 // NOP
984 int mod, regop, rm;
985 get_modrm(*current, &mod, &regop, &rm);
986 current++;
987 if (regop == 4) { // SIB byte present.
988 current++;
989 }
990 if (mod == 1) { // Byte displacement.
991 current += 1;
992 } else if (mod == 2) { // 32-bit displacement.
993 current += 4;
994 } // else no immediate displacement.
995 AppendToBuffer("nop");
996
997 } else if (opcode == 0xA2 || opcode == 0x31) {
998 // RDTSC or CPUID
999 AppendToBuffer("%s", mnemonic);
1000
1001 } else if ((opcode & 0xF0) == 0x40) {
1002 // CMOVcc: conditional move.
1003 int condition = opcode & 0x0F;
1004 const InstructionDesc& idesc = cmov_instructions[condition];
1005 byte_size_operand_ = idesc.byte_size_operation;
1006 current += PrintOperands(idesc.mnem, idesc.op_order_, current);
1007
1008 } else if ((opcode & 0xF0) == 0x80) {
1009 // Jcc: Conditional jump (branch).
1010 current = data + JumpConditional(data);
1011
1012 } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
1013 opcode == 0xB7 || opcode == 0xAF) {
1014 // Size-extending moves, IMUL.
1015 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1016
1017 } else if ((opcode & 0xF0) == 0x90) {
1018 // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
1019 current = data + SetCC(data);
1020
1021 } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
1022 // SHLD, SHRD (double-precision shift), BTS (bit set).
1023 AppendToBuffer("%s ", mnemonic);
1024 int mod, regop, rm;
1025 get_modrm(*current, &mod, &regop, &rm);
1026 current += PrintRightOperand(current);
1027 if (opcode == 0xAB) {
1028 AppendToBuffer(",%s", NameOfCPURegister(regop));
1029 } else {
1030 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1031 }
1032 } else if (group_1_prefix_ == 0xF2) {
1033 // Beginning of instructions with prefix 0xF2.
1034
1035 if (opcode == 0x11 || opcode == 0x10) {
1036 // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
1037 AppendToBuffer("movsd ");
1038 int mod, regop, rm;
1039 get_modrm(*current, &mod, &regop, &rm);
1040 if (opcode == 0x11) {
1041 current += PrintRightOperand(current);
1042 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1043 } else {
1044 AppendToBuffer("%s,", NameOfXMMRegister(regop));
1045 current += PrintRightOperand(current);
1046 }
1047 } else if (opcode == 0x2A) {
1048 // CVTSI2SD: integer to XMM double conversion.
1049 int mod, regop, rm;
1050 get_modrm(*current, &mod, &regop, &rm);
1051 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
Steve Blockd0582a62009-12-15 09:54:21 +00001052 current += PrintRightOperand(current);
Steve Blocka7e24c12009-10-30 11:49:00 +00001053 } else if ((opcode & 0xF8) == 0x58) {
1054 // XMM arithmetic. Mnemonic was retrieved at the start of this function.
1055 int mod, regop, rm;
1056 get_modrm(*current, &mod, &regop, &rm);
Steve Blockd0582a62009-12-15 09:54:21 +00001057 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1058 current += PrintRightXMMOperand(current);
Steve Blocka7e24c12009-10-30 11:49:00 +00001059 } else {
1060 UnimplementedInstruction();
1061 }
1062 } else if (opcode == 0x2C && group_1_prefix_ == 0xF3) {
1063 // Instruction with prefix 0xF3.
1064
1065 // CVTTSS2SI: Convert scalar single-precision FP to dword integer.
1066 // Assert that mod is not 3, so source is memory, not an XMM register.
Steve Blockd0582a62009-12-15 09:54:21 +00001067 ASSERT_NE(0xC0, *current & 0xC0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001068 current += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, current);
1069 } else {
1070 UnimplementedInstruction();
1071 }
Steve Blockd0582a62009-12-15 09:54:21 +00001072 return static_cast<int>(current - data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001073}
1074
1075
1076// Mnemonics for two-byte opcode instructions starting with 0x0F.
1077// The argument is the second byte of the two-byte opcode.
1078// Returns NULL if the instruction is not handled here.
1079const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
1080 switch (opcode) {
1081 case 0x1F:
1082 return "nop";
1083 case 0x2A: // F2 prefix.
1084 return "cvtsi2sd";
1085 case 0x31:
1086 return "rdtsc";
1087 case 0x58: // F2 prefix.
1088 return "addsd";
1089 case 0x59: // F2 prefix.
1090 return "mulsd";
1091 case 0x5C: // F2 prefix.
1092 return "subsd";
1093 case 0x5E: // F2 prefix.
1094 return "divsd";
1095 case 0xA2:
1096 return "cpuid";
1097 case 0xA5:
1098 return "shld";
1099 case 0xAB:
1100 return "bts";
1101 case 0xAD:
1102 return "shrd";
1103 case 0xAF:
1104 return "imul";
1105 case 0xB6:
1106 return "movzxb";
1107 case 0xB7:
1108 return "movzxw";
1109 case 0xBE:
1110 return "movsxb";
1111 case 0xBF:
1112 return "movsxw";
1113 default:
1114 return NULL;
1115 }
1116}
1117
1118
1119// Disassembles the instruction at instr, and writes it into out_buffer.
1120int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
1121 byte* instr) {
1122 tmp_buffer_pos_ = 0; // starting to write as position 0
1123 byte* data = instr;
1124 bool processed = true; // Will be set to false if the current instruction
1125 // is not in 'instructions' table.
1126 byte current;
1127
1128 // Scan for prefixes.
1129 while (true) {
1130 current = *data;
1131 if (current == 0x66) { // Group 3 prefix.
1132 operand_size_ = current;
1133 } else if ((current & 0xF0) == 0x40) { // REX prefix.
1134 setRex(current);
1135 if (rex_w()) AppendToBuffer("REX.W ");
1136 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix.
1137 group_1_prefix_ = current;
1138 } else { // Not a prefix - an opcode.
1139 break;
1140 }
1141 data++;
1142 }
1143
1144 const InstructionDesc& idesc = instruction_table.Get(current);
1145 byte_size_operand_ = idesc.byte_size_operation;
1146 switch (idesc.type) {
1147 case ZERO_OPERANDS_INSTR:
1148 AppendToBuffer(idesc.mnem);
1149 data++;
1150 break;
1151
1152 case TWO_OPERANDS_INSTR:
1153 data++;
1154 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1155 break;
1156
1157 case JUMP_CONDITIONAL_SHORT_INSTR:
1158 data += JumpConditionalShort(data);
1159 break;
1160
1161 case REGISTER_INSTR:
1162 AppendToBuffer("%s%c %s",
1163 idesc.mnem,
1164 operand_size_code(),
1165 NameOfCPURegister(base_reg(current & 0x07)));
1166 data++;
1167 break;
1168 case PUSHPOP_INSTR:
1169 AppendToBuffer("%s %s",
1170 idesc.mnem,
1171 NameOfCPURegister(base_reg(current & 0x07)));
1172 data++;
1173 break;
1174 case MOVE_REG_INSTR: {
1175 byte* addr = NULL;
1176 switch (operand_size()) {
1177 case WORD_SIZE:
1178 addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
1179 data += 3;
1180 break;
1181 case DOUBLEWORD_SIZE:
1182 addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1183 data += 5;
1184 break;
1185 case QUADWORD_SIZE:
1186 addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
1187 data += 9;
1188 break;
1189 default:
1190 UNREACHABLE();
1191 }
1192 AppendToBuffer("mov%c %s,%s",
1193 operand_size_code(),
1194 NameOfCPURegister(base_reg(current & 0x07)),
1195 NameOfAddress(addr));
1196 break;
1197 }
1198
1199 case CALL_JUMP_INSTR: {
1200 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
1201 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1202 data += 5;
1203 break;
1204 }
1205
1206 case SHORT_IMMEDIATE_INSTR: {
1207 byte* addr =
1208 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1209 AppendToBuffer("%s rax, %s", idesc.mnem, NameOfAddress(addr));
1210 data += 5;
1211 break;
1212 }
1213
1214 case NO_INSTR:
1215 processed = false;
1216 break;
1217
1218 default:
1219 UNIMPLEMENTED(); // This type is not implemented.
1220 }
1221
1222 // The first byte didn't match any of the simple opcodes, so we
1223 // need to do special processing on it.
1224 if (!processed) {
1225 switch (*data) {
1226 case 0xC2:
1227 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
1228 data += 3;
1229 break;
1230
1231 case 0x69: // fall through
1232 case 0x6B: {
1233 int mod, regop, rm;
1234 get_modrm(*(data + 1), &mod, &regop, &rm);
1235 int32_t imm = *data == 0x6B ? *(data + 2)
1236 : *reinterpret_cast<int32_t*>(data + 2);
1237 AppendToBuffer("imul %s,%s,0x%x", NameOfCPURegister(regop),
1238 NameOfCPURegister(rm), imm);
1239 data += 2 + (*data == 0x6B ? 1 : 4);
1240 break;
1241 }
1242
Steve Blocka7e24c12009-10-30 11:49:00 +00001243 case 0x81: // fall through
1244 case 0x83: // 0x81 with sign extension bit set
1245 data += PrintImmediateOp(data);
1246 break;
1247
1248 case 0x0F:
1249 data += TwoByteOpcodeInstruction(data);
1250 break;
1251
1252 case 0x8F: {
1253 data++;
1254 int mod, regop, rm;
1255 get_modrm(*data, &mod, &regop, &rm);
1256 if (regop == 0) {
1257 AppendToBuffer("pop ");
1258 data += PrintRightOperand(data);
1259 }
1260 }
1261 break;
1262
1263 case 0xFF: {
1264 data++;
1265 int mod, regop, rm;
1266 get_modrm(*data, &mod, &regop, &rm);
1267 const char* mnem = NULL;
1268 switch (regop) {
1269 case 0:
1270 mnem = "inc";
1271 break;
1272 case 1:
1273 mnem = "dec";
1274 break;
1275 case 2:
1276 mnem = "call";
1277 break;
1278 case 4:
1279 mnem = "jmp";
1280 break;
1281 case 6:
1282 mnem = "push";
1283 break;
1284 default:
1285 mnem = "???";
1286 }
1287 AppendToBuffer(((regop <= 1) ? "%s%c " : "%s "),
1288 mnem,
1289 operand_size_code());
1290 data += PrintRightOperand(data);
1291 }
1292 break;
1293
1294 case 0xC7: // imm32, fall through
1295 case 0xC6: // imm8
1296 {
1297 bool is_byte = *data == 0xC6;
1298 data++;
1299
1300 AppendToBuffer("mov%c ", is_byte ? 'b' : operand_size_code());
1301 data += PrintRightOperand(data);
1302 int32_t imm = is_byte ? *data : *reinterpret_cast<int32_t*>(data);
1303 AppendToBuffer(",0x%x", imm);
1304 data += is_byte ? 1 : 4;
1305 }
1306 break;
1307
1308 case 0x80: {
1309 data++;
1310 AppendToBuffer("cmpb ");
1311 data += PrintRightOperand(data);
1312 int32_t imm = *data;
1313 AppendToBuffer(",0x%x", imm);
1314 data++;
1315 }
1316 break;
1317
1318 case 0x88: // 8bit, fall through
1319 case 0x89: // 32bit
1320 {
1321 bool is_byte = *data == 0x88;
1322 int mod, regop, rm;
1323 data++;
1324 get_modrm(*data, &mod, &regop, &rm);
1325 AppendToBuffer("mov%c ", is_byte ? 'b' : operand_size_code());
1326 data += PrintRightOperand(data);
1327 AppendToBuffer(",%s", NameOfCPURegister(regop));
1328 }
1329 break;
1330
1331 case 0x90:
1332 case 0x91:
1333 case 0x92:
1334 case 0x93:
1335 case 0x94:
1336 case 0x95:
1337 case 0x96:
1338 case 0x97: {
Steve Blockd0582a62009-12-15 09:54:21 +00001339 int reg = (*data & 0x7) | (rex_b() ? 8 : 0);
Steve Blocka7e24c12009-10-30 11:49:00 +00001340 if (reg == 0) {
1341 AppendToBuffer("nop"); // Common name for xchg rax,rax.
1342 } else {
1343 AppendToBuffer("xchg%c rax, %s",
1344 operand_size_code(),
1345 NameOfCPURegister(reg));
1346 }
Steve Blockd0582a62009-12-15 09:54:21 +00001347 data++;
Steve Blocka7e24c12009-10-30 11:49:00 +00001348 }
Steve Blockd0582a62009-12-15 09:54:21 +00001349 break;
Steve Blocka7e24c12009-10-30 11:49:00 +00001350
1351 case 0xFE: {
1352 data++;
1353 int mod, regop, rm;
1354 get_modrm(*data, &mod, &regop, &rm);
1355 if (mod == 3 && regop == 1) {
1356 AppendToBuffer("decb %s", NameOfCPURegister(rm));
1357 } else {
1358 UnimplementedInstruction();
1359 }
1360 data++;
1361 }
1362 break;
1363
1364 case 0x68:
1365 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
1366 data += 5;
1367 break;
1368
1369 case 0x6A:
1370 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1371 data += 2;
1372 break;
1373
1374 case 0xA1: // Fall through.
1375 case 0xA3:
1376 switch (operand_size()) {
1377 case DOUBLEWORD_SIZE: {
1378 const char* memory_location = NameOfAddress(
1379 reinterpret_cast<byte*>(
1380 *reinterpret_cast<int32_t*>(data + 1)));
1381 if (*data == 0xA1) { // Opcode 0xA1
1382 AppendToBuffer("movzxlq rax,(%s)", memory_location);
1383 } else { // Opcode 0xA3
1384 AppendToBuffer("movzxlq (%s),rax", memory_location);
1385 }
1386 data += 5;
1387 break;
1388 }
1389 case QUADWORD_SIZE: {
1390 // New x64 instruction mov rax,(imm_64).
1391 const char* memory_location = NameOfAddress(
1392 *reinterpret_cast<byte**>(data + 1));
1393 if (*data == 0xA1) { // Opcode 0xA1
1394 AppendToBuffer("movq rax,(%s)", memory_location);
1395 } else { // Opcode 0xA3
1396 AppendToBuffer("movq (%s),rax", memory_location);
1397 }
1398 data += 9;
1399 break;
1400 }
1401 default:
1402 UnimplementedInstruction();
1403 data += 2;
1404 }
1405 break;
1406
1407 case 0xA8:
1408 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
1409 data += 2;
1410 break;
1411
1412 case 0xA9: {
1413 int64_t value = 0;
1414 switch (operand_size()) {
1415 case WORD_SIZE:
1416 value = *reinterpret_cast<uint16_t*>(data + 1);
1417 data += 3;
1418 break;
1419 case DOUBLEWORD_SIZE:
1420 value = *reinterpret_cast<uint32_t*>(data + 1);
1421 data += 5;
1422 break;
1423 case QUADWORD_SIZE:
1424 value = *reinterpret_cast<int32_t*>(data + 1);
1425 data += 5;
1426 break;
1427 default:
1428 UNREACHABLE();
1429 }
1430 AppendToBuffer("test%c rax,0x%"V8_PTR_PREFIX"x",
1431 operand_size_code(),
1432 value);
1433 break;
1434 }
1435 case 0xD1: // fall through
1436 case 0xD3: // fall through
1437 case 0xC1:
1438 data += ShiftInstruction(data);
1439 break;
1440 case 0xD0: // fall through
1441 case 0xD2: // fall through
1442 case 0xC0:
1443 byte_size_operand_ = true;
1444 data += ShiftInstruction(data);
1445 break;
1446
1447 case 0xD9: // fall through
1448 case 0xDA: // fall through
1449 case 0xDB: // fall through
1450 case 0xDC: // fall through
1451 case 0xDD: // fall through
1452 case 0xDE: // fall through
1453 case 0xDF:
1454 data += FPUInstruction(data);
1455 break;
1456
1457 case 0xEB:
1458 data += JumpShort(data);
1459 break;
1460
Steve Blockd0582a62009-12-15 09:54:21 +00001461 case 0xF6:
1462 byte_size_operand_ = true; // fall through
Steve Blocka7e24c12009-10-30 11:49:00 +00001463 case 0xF7:
Steve Blockd0582a62009-12-15 09:54:21 +00001464 data += F6F7Instruction(data);
Steve Blocka7e24c12009-10-30 11:49:00 +00001465 break;
1466
1467 default:
1468 UnimplementedInstruction();
1469 data += 1;
1470 }
1471 } // !processed
1472
1473 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1474 tmp_buffer_[tmp_buffer_pos_] = '\0';
1475 }
1476
Steve Blockd0582a62009-12-15 09:54:21 +00001477 int instr_len = static_cast<int>(data - instr);
Steve Blocka7e24c12009-10-30 11:49:00 +00001478 ASSERT(instr_len > 0); // Ensure progress.
1479
1480 int outp = 0;
1481 // Instruction bytes.
1482 for (byte* bp = instr; bp < data; bp++) {
1483 outp += v8::internal::OS::SNPrintF(out_buffer + outp, "%02x", *bp);
1484 }
1485 for (int i = 6 - instr_len; i >= 0; i--) {
1486 outp += v8::internal::OS::SNPrintF(out_buffer + outp, " ");
1487 }
1488
1489 outp += v8::internal::OS::SNPrintF(out_buffer + outp, " %s",
1490 tmp_buffer_.start());
1491 return instr_len;
1492}
1493
1494//------------------------------------------------------------------------------
1495
1496
1497static const char* cpu_regs[16] = {
1498 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
1499 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
1500};
1501
1502
1503static const char* byte_cpu_regs[16] = {
1504 "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
1505 "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
1506};
1507
1508
1509static const char* xmm_regs[16] = {
1510 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
1511 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
1512};
1513
1514
1515const char* NameConverter::NameOfAddress(byte* addr) const {
1516 static v8::internal::EmbeddedVector<char, 32> tmp_buffer;
1517 v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr);
1518 return tmp_buffer.start();
1519}
1520
1521
1522const char* NameConverter::NameOfConstant(byte* addr) const {
1523 return NameOfAddress(addr);
1524}
1525
1526
1527const char* NameConverter::NameOfCPURegister(int reg) const {
1528 if (0 <= reg && reg < 16)
1529 return cpu_regs[reg];
1530 return "noreg";
1531}
1532
1533
1534const char* NameConverter::NameOfByteCPURegister(int reg) const {
1535 if (0 <= reg && reg < 16)
1536 return byte_cpu_regs[reg];
1537 return "noreg";
1538}
1539
1540
1541const char* NameConverter::NameOfXMMRegister(int reg) const {
1542 if (0 <= reg && reg < 16)
1543 return xmm_regs[reg];
1544 return "noxmmreg";
1545}
1546
1547
1548const char* NameConverter::NameInCode(byte* addr) const {
1549 // X64 does not embed debug strings at the moment.
1550 UNREACHABLE();
1551 return "";
1552}
1553
1554//------------------------------------------------------------------------------
1555
1556Disassembler::Disassembler(const NameConverter& converter)
1557 : converter_(converter) { }
1558
1559Disassembler::~Disassembler() { }
1560
1561
1562int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1563 byte* instruction) {
1564 DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE);
1565 return d.InstructionDecode(buffer, instruction);
1566}
1567
1568
1569// The X64 assembler does not use constant pools.
1570int Disassembler::ConstantPoolSizeAt(byte* instruction) {
1571 return -1;
1572}
1573
1574
1575void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1576 NameConverter converter;
1577 Disassembler d(converter);
1578 for (byte* pc = begin; pc < end;) {
1579 v8::internal::EmbeddedVector<char, 128> buffer;
1580 buffer[0] = '\0';
1581 byte* prev_pc = pc;
1582 pc += d.InstructionDecode(buffer, pc);
1583 fprintf(f, "%p", prev_pc);
1584 fprintf(f, " ");
1585
1586 for (byte* bp = prev_pc; bp < pc; bp++) {
1587 fprintf(f, "%02x", *bp);
1588 }
Steve Blockd0582a62009-12-15 09:54:21 +00001589 for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) {
Steve Blocka7e24c12009-10-30 11:49:00 +00001590 fprintf(f, " ");
1591 }
1592 fprintf(f, " %s\n", buffer.start());
1593 }
1594}
1595
1596} // namespace disasm