1 // 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
35 namespace disasm {
36
37 enum 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 //------------------------------------------------------------------
51 struct ByteMnemonic {
52 int b; // -1 terminates, otherwise must be in range (0..255)
53 OperandType op_order_;
54 const char* mnem;
55 };
56
57
58 static 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
105 static 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
121 static ByteMnemonic call_jump_instr[] = {
122 { 0xE8, UNSET_OP_ORDER, "call" },
123 { 0xE9, UNSET_OP_ORDER, "jmp" },
124 { -1, UNSET_OP_ORDER, "" }
125 };
126
127
128 static 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
141 static 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
147 enum 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
160 struct InstructionDesc {
161 const char* mnem;
162 InstructionType type;
163 OperandType op_order_;
164 bool byte_size_operation; // Fixed 8-bit operation.
165 };
166
167
168 class InstructionTable {
169 public:
170 InstructionTable();
Get(byte x) const171 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
InstructionTable()186 InstructionTable::InstructionTable() {
187 Clear();
188 Init();
189 }
190
191
Clear()192 void 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
Init()202 void 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
CopyTable(ByteMnemonic bm[],InstructionType type)214 void 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);
221 assert(id->type == NO_INSTR); // Information not already entered
222 id->type = type;
223 id->byte_size_operation = ((op_order & BYTE_SIZE_OPERAND_FLAG) != 0);
224 }
225 }
226
227
SetTableRange(InstructionType type,byte start,byte end,bool byte_size,const char * mnem)228 void 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];
235 assert(id->type == NO_INSTR); // Information already entered
236 id->mnem = mnem;
237 id->type = type;
238 id->byte_size_operation = byte_size;
239 }
240 }
241
242
AddJumpConditionalShort()243 void InstructionTable::AddJumpConditionalShort() {
244 for (byte b = 0x70; b <= 0x7F; b++) {
245 InstructionDesc* id = &instructions_[b];
246 assert(id->type == NO_INSTR); // Information already entered
247 id->mnem = NULL; // Computed depending on condition code.
248 id->type = JUMP_CONDITIONAL_SHORT_INSTR;
249 }
250 }
251
252
253 static InstructionTable instruction_table;
254
255 static 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
277 enum 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.
284 class DisassemblerX64 {
285 public:
DisassemblerX64(const NameConverter & converter,UnimplementedOpcodeAction unimplemented_action=ABORT_ON_UNIMPLEMENTED_OPCODE)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
~DisassemblerX64()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
setRex(byte rex)326 void setRex(byte rex) {
327 ASSERT_EQ(0x40, rex & 0xF0);
328 rex_ = rex;
329 }
330
rex()331 bool rex() { return rex_ != 0; }
332
rex_b()333 bool rex_b() { return (rex_ & 0x01) != 0; }
334
335 // Actual number of base register given the low bits and the rex.b state.
base_reg(int low_bits)336 int base_reg(int low_bits) { return low_bits | ((rex_ & 0x01) << 3); }
337
rex_x()338 bool rex_x() { return (rex_ & 0x02) != 0; }
339
rex_r()340 bool rex_r() { return (rex_ & 0x04) != 0; }
341
rex_w()342 bool rex_w() { return (rex_ & 0x08) != 0; }
343
operand_size()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
operand_size_code()351 char operand_size_code() {
352 return "bwlq"[operand_size()];
353 }
354
NameOfCPURegister(int reg) const355 const char* NameOfCPURegister(int reg) const {
356 return converter_.NameOfCPURegister(reg);
357 }
358
NameOfByteCPURegister(int reg) const359 const char* NameOfByteCPURegister(int reg) const {
360 return converter_.NameOfByteCPURegister(reg);
361 }
362
NameOfXMMRegister(int reg) const363 const char* NameOfXMMRegister(int reg) const {
364 return converter_.NameOfXMMRegister(reg);
365 }
366
NameOfAddress(byte * addr) const367 const char* NameOfAddress(byte* addr) const {
368 return converter_.NameOfAddress(addr);
369 }
370
371 // Disassembler helper functions.
get_modrm(byte data,int * mod,int * regop,int * rm)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
get_sib(byte data,int * scale,int * index,int * base)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);
396 int PrintOperands(const char* mnem,
397 OperandType op_order,
398 byte* data);
399 int PrintImmediate(byte* data, OperandSize size);
400 int PrintImmediateOp(byte* data);
401 const char* TwoByteMnemonic(byte opcode);
402 int TwoByteOpcodeInstruction(byte* data);
403 int F7Instruction(byte* data);
404 int ShiftInstruction(byte* data);
405 int JumpShort(byte* data);
406 int JumpConditional(byte* data);
407 int JumpConditionalShort(byte* data);
408 int SetCC(byte* data);
409 int FPUInstruction(byte* data);
410 void AppendToBuffer(const char* format, ...);
411
UnimplementedInstruction()412 void UnimplementedInstruction() {
413 if (abort_on_unimplemented_) {
414 CHECK(false);
415 } else {
416 AppendToBuffer("'Unimplemented Instruction'");
417 }
418 }
419 };
420
421
AppendToBuffer(const char * format,...)422 void DisassemblerX64::AppendToBuffer(const char* format, ...) {
423 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_;
424 va_list args;
425 va_start(args, format);
426 int result = v8::internal::OS::VSNPrintF(buf, format, args);
427 va_end(args);
428 tmp_buffer_pos_ += result;
429 }
430
431
PrintRightOperandHelper(byte * modrmp,RegisterNameMapping register_name)432 int DisassemblerX64::PrintRightOperandHelper(
433 byte* modrmp,
434 RegisterNameMapping register_name) {
435 int mod, regop, rm;
436 get_modrm(*modrmp, &mod, ®op, &rm);
437 switch (mod) {
438 case 0:
439 if ((rm & 7) == 5) {
440 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1);
441 AppendToBuffer("[0x%x]", disp);
442 return 5;
443 } else if ((rm & 7) == 4) {
444 // Codes for SIB byte.
445 byte sib = *(modrmp + 1);
446 int scale, index, base;
447 get_sib(sib, &scale, &index, &base);
448 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
449 // index == rsp means no index. Only use sib byte with no index for
450 // rsp and r12 base.
451 AppendToBuffer("[%s]", (this->*register_name)(base));
452 return 2;
453 } else if (base == 5) {
454 // base == rbp means no base register (when mod == 0).
455 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2);
456 AppendToBuffer("[%s*%d+0x%x]",
457 (this->*register_name)(index),
458 1 << scale, disp);
459 return 6;
460 } else if (index != 4 && base != 5) {
461 // [base+index*scale]
462 AppendToBuffer("[%s+%s*%d]",
463 (this->*register_name)(base),
464 (this->*register_name)(index),
465 1 << scale);
466 return 2;
467 } else {
468 UnimplementedInstruction();
469 return 1;
470 }
471 } else {
472 AppendToBuffer("[%s]", (this->*register_name)(rm));
473 return 1;
474 }
475 break;
476 case 1: // fall through
477 case 2:
478 if ((rm & 7) == 4) {
479 byte sib = *(modrmp + 1);
480 int scale, index, base;
481 get_sib(sib, &scale, &index, &base);
482 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2)
483 : *reinterpret_cast<char*>(modrmp + 2);
484 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) {
485 if (-disp > 0) {
486 AppendToBuffer("[%s-0x%x]", (this->*register_name)(base), -disp);
487 } else {
488 AppendToBuffer("[%s+0x%x]", (this->*register_name)(base), disp);
489 }
490 } else {
491 if (-disp > 0) {
492 AppendToBuffer("[%s+%s*%d-0x%x]",
493 (this->*register_name)(base),
494 (this->*register_name)(index),
495 1 << scale,
496 -disp);
497 } else {
498 AppendToBuffer("[%s+%s*%d+0x%x]",
499 (this->*register_name)(base),
500 (this->*register_name)(index),
501 1 << scale,
502 disp);
503 }
504 }
505 return mod == 2 ? 6 : 3;
506 } else {
507 // No sib.
508 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1)
509 : *reinterpret_cast<char*>(modrmp + 1);
510 if (-disp > 0) {
511 AppendToBuffer("[%s-0x%x]", (this->*register_name)(rm), -disp);
512 } else {
513 AppendToBuffer("[%s+0x%x]", (this->*register_name)(rm), disp);
514 }
515 return (mod == 2) ? 5 : 2;
516 }
517 break;
518 case 3:
519 AppendToBuffer("%s", (this->*register_name)(rm));
520 return 1;
521 default:
522 UnimplementedInstruction();
523 return 1;
524 }
525 UNREACHABLE();
526 }
527
528
PrintImmediate(byte * data,OperandSize size)529 int DisassemblerX64::PrintImmediate(byte* data, OperandSize size) {
530 int64_t value;
531 int count;
532 switch (size) {
533 case BYTE_SIZE:
534 value = *data;
535 count = 1;
536 break;
537 case WORD_SIZE:
538 value = *reinterpret_cast<int16_t*>(data);
539 count = 2;
540 break;
541 case DOUBLEWORD_SIZE:
542 value = *reinterpret_cast<uint32_t*>(data);
543 count = 4;
544 break;
545 case QUADWORD_SIZE:
546 value = *reinterpret_cast<int32_t*>(data);
547 count = 4;
548 break;
549 default:
550 UNREACHABLE();
551 value = 0; // Initialize variables on all paths to satisfy the compiler.
552 count = 0;
553 }
554 AppendToBuffer("%" V8_PTR_PREFIX "x", value);
555 return count;
556 }
557
558
PrintRightOperand(byte * modrmp)559 int DisassemblerX64::PrintRightOperand(byte* modrmp) {
560 return PrintRightOperandHelper(modrmp,
561 &DisassemblerX64::NameOfCPURegister);
562 }
563
564
PrintRightByteOperand(byte * modrmp)565 int DisassemblerX64::PrintRightByteOperand(byte* modrmp) {
566 return PrintRightOperandHelper(modrmp,
567 &DisassemblerX64::NameOfByteCPURegister);
568 }
569
570
571 // Returns number of bytes used including the current *data.
572 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'.
PrintOperands(const char * mnem,OperandType op_order,byte * data)573 int DisassemblerX64::PrintOperands(const char* mnem,
574 OperandType op_order,
575 byte* data) {
576 byte modrm = *data;
577 int mod, regop, rm;
578 get_modrm(modrm, &mod, ®op, &rm);
579 int advance = 0;
580 const char* register_name =
581 byte_size_operand_ ? NameOfByteCPURegister(regop)
582 : NameOfCPURegister(regop);
583 switch (op_order) {
584 case REG_OPER_OP_ORDER: {
585 AppendToBuffer("%s%c %s,",
586 mnem,
587 operand_size_code(),
588 register_name);
589 advance = byte_size_operand_ ? PrintRightByteOperand(data)
590 : PrintRightOperand(data);
591 break;
592 }
593 case OPER_REG_OP_ORDER: {
594 AppendToBuffer("%s%c ", mnem, operand_size_code());
595 advance = byte_size_operand_ ? PrintRightByteOperand(data)
596 : PrintRightOperand(data);
597 AppendToBuffer(",%s", register_name);
598 break;
599 }
600 default:
601 UNREACHABLE();
602 break;
603 }
604 return advance;
605 }
606
607
608 // Returns number of bytes used by machine instruction, including *data byte.
609 // Writes immediate instructions to 'tmp_buffer_'.
PrintImmediateOp(byte * data)610 int DisassemblerX64::PrintImmediateOp(byte* data) {
611 bool byte_size_immediate = (*data & 0x02) != 0;
612 byte modrm = *(data + 1);
613 int mod, regop, rm;
614 get_modrm(modrm, &mod, ®op, &rm);
615 const char* mnem = "Imm???";
616 switch (regop) {
617 case 0:
618 mnem = "add";
619 break;
620 case 1:
621 mnem = "or";
622 break;
623 case 2:
624 mnem = "adc";
625 break;
626 case 4:
627 mnem = "and";
628 break;
629 case 5:
630 mnem = "sub";
631 break;
632 case 6:
633 mnem = "xor";
634 break;
635 case 7:
636 mnem = "cmp";
637 break;
638 default:
639 UnimplementedInstruction();
640 }
641 AppendToBuffer("%s%c ", mnem, operand_size_code());
642 int count = PrintRightOperand(data + 1);
643 AppendToBuffer(",0x");
644 OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size();
645 count += PrintImmediate(data + 1 + count, immediate_size);
646 return 1 + count;
647 }
648
649
650 // Returns number of bytes used, including *data.
F7Instruction(byte * data)651 int DisassemblerX64::F7Instruction(byte* data) {
652 assert(*data == 0xF7);
653 byte modrm = *(data + 1);
654 int mod, regop, rm;
655 get_modrm(modrm, &mod, ®op, &rm);
656 if (mod == 3 && regop != 0) {
657 const char* mnem = NULL;
658 switch (regop) {
659 case 2:
660 mnem = "not";
661 break;
662 case 3:
663 mnem = "neg";
664 break;
665 case 4:
666 mnem = "mul";
667 break;
668 case 7:
669 mnem = "idiv";
670 break;
671 default:
672 UnimplementedInstruction();
673 }
674 AppendToBuffer("%s%c %s",
675 mnem,
676 operand_size_code(),
677 NameOfCPURegister(rm));
678 return 2;
679 } else if (mod == 3 && regop == 0) {
680 int32_t imm = *reinterpret_cast<int32_t*>(data + 2);
681 AppendToBuffer("test%c %s,0x%x",
682 operand_size_code(),
683 NameOfCPURegister(rm),
684 imm);
685 return 6;
686 } else if (regop == 0) {
687 AppendToBuffer("test%c ", operand_size_code());
688 int count = PrintRightOperand(data + 1);
689 int32_t imm = *reinterpret_cast<int32_t*>(data + 1 + count);
690 AppendToBuffer(",0x%x", imm);
691 return 1 + count + 4 /*int32_t*/;
692 } else {
693 UnimplementedInstruction();
694 return 2;
695 }
696 }
697
698
ShiftInstruction(byte * data)699 int DisassemblerX64::ShiftInstruction(byte* data) {
700 byte op = *data & (~1);
701 if (op != 0xD0 && op != 0xD2 && op != 0xC0) {
702 UnimplementedInstruction();
703 return 1;
704 }
705 byte modrm = *(data + 1);
706 int mod, regop, rm;
707 get_modrm(modrm, &mod, ®op, &rm);
708 regop &= 0x7; // The REX.R bit does not affect the operation.
709 int imm8 = -1;
710 int num_bytes = 2;
711 if (mod != 3) {
712 UnimplementedInstruction();
713 return num_bytes;
714 }
715 const char* mnem = NULL;
716 switch (regop) {
717 case 0:
718 mnem = "rol";
719 break;
720 case 1:
721 mnem = "ror";
722 break;
723 case 2:
724 mnem = "rcl";
725 break;
726 case 3:
727 mnem = "rcr";
728 break;
729 case 4:
730 mnem = "shl";
731 break;
732 case 5:
733 mnem = "shr";
734 break;
735 case 7:
736 mnem = "sar";
737 break;
738 default:
739 UnimplementedInstruction();
740 return num_bytes;
741 }
742 assert(mnem != NULL);
743 if (op == 0xD0) {
744 imm8 = 1;
745 } else if (op == 0xC0) {
746 imm8 = *(data + 2);
747 num_bytes = 3;
748 }
749 AppendToBuffer("%s%c %s,",
750 mnem,
751 operand_size_code(),
752 byte_size_operand_ ? NameOfByteCPURegister(rm)
753 : NameOfCPURegister(rm));
754 if (op == 0xD2) {
755 AppendToBuffer("cl");
756 } else {
757 AppendToBuffer("%d", imm8);
758 }
759 return num_bytes;
760 }
761
762
763 // Returns number of bytes used, including *data.
JumpShort(byte * data)764 int DisassemblerX64::JumpShort(byte* data) {
765 assert(*data == 0xEB);
766 byte b = *(data + 1);
767 byte* dest = data + static_cast<int8_t>(b) + 2;
768 AppendToBuffer("jmp %s", NameOfAddress(dest));
769 return 2;
770 }
771
772
773 // Returns number of bytes used, including *data.
JumpConditional(byte * data)774 int DisassemblerX64::JumpConditional(byte* data) {
775 assert(*data == 0x0F);
776 byte cond = *(data + 1) & 0x0F;
777 byte* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6;
778 const char* mnem = conditional_code_suffix[cond];
779 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
780 return 6; // includes 0x0F
781 }
782
783
784 // Returns number of bytes used, including *data.
JumpConditionalShort(byte * data)785 int DisassemblerX64::JumpConditionalShort(byte* data) {
786 byte cond = *data & 0x0F;
787 byte b = *(data + 1);
788 byte* dest = data + static_cast<int8_t>(b) + 2;
789 const char* mnem = conditional_code_suffix[cond];
790 AppendToBuffer("j%s %s", mnem, NameOfAddress(dest));
791 return 2;
792 }
793
794
795 // Returns number of bytes used, including *data.
SetCC(byte * data)796 int DisassemblerX64::SetCC(byte* data) {
797 assert(*data == 0x0F);
798 byte cond = *(data + 1) & 0x0F;
799 const char* mnem = conditional_code_suffix[cond];
800 AppendToBuffer("set%s%c ", mnem, operand_size_code());
801 PrintRightByteOperand(data + 2);
802 return 3; // includes 0x0F
803 }
804
805
806 // Returns number of bytes used, including *data.
FPUInstruction(byte * data)807 int DisassemblerX64::FPUInstruction(byte* data) {
808 byte b1 = *data;
809 byte b2 = *(data + 1);
810 if (b1 == 0xD9) {
811 const char* mnem = NULL;
812 switch (b2) {
813 case 0xE0:
814 mnem = "fchs";
815 break;
816 case 0xE1:
817 mnem = "fabs";
818 break;
819 case 0xE4:
820 mnem = "ftst";
821 break;
822 case 0xF5:
823 mnem = "fprem1";
824 break;
825 case 0xF7:
826 mnem = "fincstp";
827 break;
828 case 0xE8:
829 mnem = "fld1";
830 break;
831 case 0xEE:
832 mnem = "fldz";
833 break;
834 case 0xF8:
835 mnem = "fprem";
836 break;
837 }
838 if (mnem != NULL) {
839 AppendToBuffer("%s", mnem);
840 return 2;
841 } else if ((b2 & 0xF8) == 0xC8) {
842 AppendToBuffer("fxch st%d", b2 & 0x7);
843 return 2;
844 } else {
845 int mod, regop, rm;
846 get_modrm(*(data + 1), &mod, ®op, &rm);
847 const char* mnem = "?";
848 switch (regop) {
849 case 0:
850 mnem = "fld_s";
851 break;
852 case 3:
853 mnem = "fstp_s";
854 break;
855 default:
856 UnimplementedInstruction();
857 }
858 AppendToBuffer("%s ", mnem);
859 int count = PrintRightOperand(data + 1);
860 return count + 1;
861 }
862 } else if (b1 == 0xDD) {
863 if ((b2 & 0xF8) == 0xC0) {
864 AppendToBuffer("ffree st%d", b2 & 0x7);
865 return 2;
866 } else {
867 int mod, regop, rm;
868 get_modrm(*(data + 1), &mod, ®op, &rm);
869 const char* mnem = "?";
870 switch (regop) {
871 case 0:
872 mnem = "fld_d";
873 break;
874 case 3:
875 mnem = "fstp_d";
876 break;
877 default:
878 UnimplementedInstruction();
879 }
880 AppendToBuffer("%s ", mnem);
881 int count = PrintRightOperand(data + 1);
882 return count + 1;
883 }
884 } else if (b1 == 0xDB) {
885 int mod, regop, rm;
886 get_modrm(*(data + 1), &mod, ®op, &rm);
887 const char* mnem = "?";
888 switch (regop) {
889 case 0:
890 mnem = "fild_s";
891 break;
892 case 2:
893 mnem = "fist_s";
894 break;
895 case 3:
896 mnem = "fistp_s";
897 break;
898 default:
899 UnimplementedInstruction();
900 }
901 AppendToBuffer("%s ", mnem);
902 int count = PrintRightOperand(data + 1);
903 return count + 1;
904 } else if (b1 == 0xDF) {
905 if (b2 == 0xE0) {
906 AppendToBuffer("fnstsw_ax");
907 return 2;
908 }
909 int mod, regop, rm;
910 get_modrm(*(data + 1), &mod, ®op, &rm);
911 const char* mnem = "?";
912 switch (regop) {
913 case 5:
914 mnem = "fild_d";
915 break;
916 case 7:
917 mnem = "fistp_d";
918 break;
919 default:
920 UnimplementedInstruction();
921 }
922 AppendToBuffer("%s ", mnem);
923 int count = PrintRightOperand(data + 1);
924 return count + 1;
925 } else if (b1 == 0xDC || b1 == 0xDE) {
926 bool is_pop = (b1 == 0xDE);
927 if (is_pop && b2 == 0xD9) {
928 AppendToBuffer("fcompp");
929 return 2;
930 }
931 const char* mnem = "FP0xDC";
932 switch (b2 & 0xF8) {
933 case 0xC0:
934 mnem = "fadd";
935 break;
936 case 0xE8:
937 mnem = "fsub";
938 break;
939 case 0xC8:
940 mnem = "fmul";
941 break;
942 case 0xF8:
943 mnem = "fdiv";
944 break;
945 default:
946 UnimplementedInstruction();
947 }
948 AppendToBuffer("%s%s st%d", mnem, is_pop ? "p" : "", b2 & 0x7);
949 return 2;
950 } else if (b1 == 0xDA && b2 == 0xE9) {
951 const char* mnem = "fucompp";
952 AppendToBuffer("%s", mnem);
953 return 2;
954 }
955 AppendToBuffer("Unknown FP instruction");
956 return 2;
957 }
958
959
960 // Handle all two-byte opcodes, which start with 0x0F.
961 // These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix.
962 // We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A.
TwoByteOpcodeInstruction(byte * data)963 int DisassemblerX64::TwoByteOpcodeInstruction(byte* data) {
964 byte opcode = *(data + 1);
965 byte* current = data + 2;
966 // At return, "current" points to the start of the next instruction.
967 const char* mnemonic = TwoByteMnemonic(opcode);
968 if (opcode == 0x1F) {
969 // NOP
970 int mod, regop, rm;
971 get_modrm(*current, &mod, ®op, &rm);
972 current++;
973 if (regop == 4) { // SIB byte present.
974 current++;
975 }
976 if (mod == 1) { // Byte displacement.
977 current += 1;
978 } else if (mod == 2) { // 32-bit displacement.
979 current += 4;
980 } // else no immediate displacement.
981 AppendToBuffer("nop");
982
983 } else if (opcode == 0xA2 || opcode == 0x31) {
984 // RDTSC or CPUID
985 AppendToBuffer("%s", mnemonic);
986
987 } else if ((opcode & 0xF0) == 0x40) {
988 // CMOVcc: conditional move.
989 int condition = opcode & 0x0F;
990 const InstructionDesc& idesc = cmov_instructions[condition];
991 byte_size_operand_ = idesc.byte_size_operation;
992 current += PrintOperands(idesc.mnem, idesc.op_order_, current);
993
994 } else if ((opcode & 0xF0) == 0x80) {
995 // Jcc: Conditional jump (branch).
996 current = data + JumpConditional(data);
997
998 } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 ||
999 opcode == 0xB7 || opcode == 0xAF) {
1000 // Size-extending moves, IMUL.
1001 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current);
1002
1003 } else if ((opcode & 0xF0) == 0x90) {
1004 // SETcc: Set byte on condition. Needs pointer to beginning of instruction.
1005 current = data + SetCC(data);
1006
1007 } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) {
1008 // SHLD, SHRD (double-precision shift), BTS (bit set).
1009 AppendToBuffer("%s ", mnemonic);
1010 int mod, regop, rm;
1011 get_modrm(*current, &mod, ®op, &rm);
1012 current += PrintRightOperand(current);
1013 if (opcode == 0xAB) {
1014 AppendToBuffer(",%s", NameOfCPURegister(regop));
1015 } else {
1016 AppendToBuffer(",%s,cl", NameOfCPURegister(regop));
1017 }
1018 } else if (group_1_prefix_ == 0xF2) {
1019 // Beginning of instructions with prefix 0xF2.
1020
1021 if (opcode == 0x11 || opcode == 0x10) {
1022 // MOVSD: Move scalar double-precision fp to/from/between XMM registers.
1023 AppendToBuffer("movsd ");
1024 int mod, regop, rm;
1025 get_modrm(*current, &mod, ®op, &rm);
1026 if (opcode == 0x11) {
1027 current += PrintRightOperand(current);
1028 AppendToBuffer(",%s", NameOfXMMRegister(regop));
1029 } else {
1030 AppendToBuffer("%s,", NameOfXMMRegister(regop));
1031 current += PrintRightOperand(current);
1032 }
1033 } else if (opcode == 0x2A) {
1034 // CVTSI2SD: integer to XMM double conversion.
1035 int mod, regop, rm;
1036 get_modrm(*current, &mod, ®op, &rm);
1037 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop));
1038 data += PrintRightOperand(data);
1039 } else if ((opcode & 0xF8) == 0x58) {
1040 // XMM arithmetic. Mnemonic was retrieved at the start of this function.
1041 int mod, regop, rm;
1042 get_modrm(*current, &mod, ®op, &rm);
1043 AppendToBuffer("%s %s,%s", mnemonic, NameOfXMMRegister(regop),
1044 NameOfXMMRegister(rm));
1045 } else {
1046 UnimplementedInstruction();
1047 }
1048 } else if (opcode == 0x2C && group_1_prefix_ == 0xF3) {
1049 // Instruction with prefix 0xF3.
1050
1051 // CVTTSS2SI: Convert scalar single-precision FP to dword integer.
1052 // Assert that mod is not 3, so source is memory, not an XMM register.
1053 ASSERT((*current & 0xC0) != 0xC0);
1054 current += PrintOperands("cvttss2si", REG_OPER_OP_ORDER, current);
1055 } else {
1056 UnimplementedInstruction();
1057 }
1058 return current - data;
1059 }
1060
1061
1062 // Mnemonics for two-byte opcode instructions starting with 0x0F.
1063 // The argument is the second byte of the two-byte opcode.
1064 // Returns NULL if the instruction is not handled here.
TwoByteMnemonic(byte opcode)1065 const char* DisassemblerX64::TwoByteMnemonic(byte opcode) {
1066 switch (opcode) {
1067 case 0x1F:
1068 return "nop";
1069 case 0x2A: // F2 prefix.
1070 return "cvtsi2sd";
1071 case 0x31:
1072 return "rdtsc";
1073 case 0x58: // F2 prefix.
1074 return "addsd";
1075 case 0x59: // F2 prefix.
1076 return "mulsd";
1077 case 0x5C: // F2 prefix.
1078 return "subsd";
1079 case 0x5E: // F2 prefix.
1080 return "divsd";
1081 case 0xA2:
1082 return "cpuid";
1083 case 0xA5:
1084 return "shld";
1085 case 0xAB:
1086 return "bts";
1087 case 0xAD:
1088 return "shrd";
1089 case 0xAF:
1090 return "imul";
1091 case 0xB6:
1092 return "movzxb";
1093 case 0xB7:
1094 return "movzxw";
1095 case 0xBE:
1096 return "movsxb";
1097 case 0xBF:
1098 return "movsxw";
1099 default:
1100 return NULL;
1101 }
1102 }
1103
1104
1105 // Disassembles the instruction at instr, and writes it into out_buffer.
InstructionDecode(v8::internal::Vector<char> out_buffer,byte * instr)1106 int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer,
1107 byte* instr) {
1108 tmp_buffer_pos_ = 0; // starting to write as position 0
1109 byte* data = instr;
1110 bool processed = true; // Will be set to false if the current instruction
1111 // is not in 'instructions' table.
1112 byte current;
1113
1114 // Scan for prefixes.
1115 while (true) {
1116 current = *data;
1117 if (current == 0x66) { // Group 3 prefix.
1118 operand_size_ = current;
1119 } else if ((current & 0xF0) == 0x40) { // REX prefix.
1120 setRex(current);
1121 if (rex_w()) AppendToBuffer("REX.W ");
1122 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix.
1123 group_1_prefix_ = current;
1124 } else { // Not a prefix - an opcode.
1125 break;
1126 }
1127 data++;
1128 }
1129
1130 const InstructionDesc& idesc = instruction_table.Get(current);
1131 byte_size_operand_ = idesc.byte_size_operation;
1132 switch (idesc.type) {
1133 case ZERO_OPERANDS_INSTR:
1134 AppendToBuffer(idesc.mnem);
1135 data++;
1136 break;
1137
1138 case TWO_OPERANDS_INSTR:
1139 data++;
1140 data += PrintOperands(idesc.mnem, idesc.op_order_, data);
1141 break;
1142
1143 case JUMP_CONDITIONAL_SHORT_INSTR:
1144 data += JumpConditionalShort(data);
1145 break;
1146
1147 case REGISTER_INSTR:
1148 AppendToBuffer("%s%c %s",
1149 idesc.mnem,
1150 operand_size_code(),
1151 NameOfCPURegister(base_reg(current & 0x07)));
1152 data++;
1153 break;
1154 case PUSHPOP_INSTR:
1155 AppendToBuffer("%s %s",
1156 idesc.mnem,
1157 NameOfCPURegister(base_reg(current & 0x07)));
1158 data++;
1159 break;
1160 case MOVE_REG_INSTR: {
1161 byte* addr = NULL;
1162 switch (operand_size()) {
1163 case WORD_SIZE:
1164 addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1));
1165 data += 3;
1166 break;
1167 case DOUBLEWORD_SIZE:
1168 addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1169 data += 5;
1170 break;
1171 case QUADWORD_SIZE:
1172 addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1));
1173 data += 9;
1174 break;
1175 default:
1176 UNREACHABLE();
1177 }
1178 AppendToBuffer("mov%c %s,%s",
1179 operand_size_code(),
1180 NameOfCPURegister(base_reg(current & 0x07)),
1181 NameOfAddress(addr));
1182 break;
1183 }
1184
1185 case CALL_JUMP_INSTR: {
1186 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5;
1187 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr));
1188 data += 5;
1189 break;
1190 }
1191
1192 case SHORT_IMMEDIATE_INSTR: {
1193 byte* addr =
1194 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1));
1195 AppendToBuffer("%s rax, %s", idesc.mnem, NameOfAddress(addr));
1196 data += 5;
1197 break;
1198 }
1199
1200 case NO_INSTR:
1201 processed = false;
1202 break;
1203
1204 default:
1205 UNIMPLEMENTED(); // This type is not implemented.
1206 }
1207
1208 // The first byte didn't match any of the simple opcodes, so we
1209 // need to do special processing on it.
1210 if (!processed) {
1211 switch (*data) {
1212 case 0xC2:
1213 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1));
1214 data += 3;
1215 break;
1216
1217 case 0x69: // fall through
1218 case 0x6B: {
1219 int mod, regop, rm;
1220 get_modrm(*(data + 1), &mod, ®op, &rm);
1221 int32_t imm = *data == 0x6B ? *(data + 2)
1222 : *reinterpret_cast<int32_t*>(data + 2);
1223 AppendToBuffer("imul %s,%s,0x%x", NameOfCPURegister(regop),
1224 NameOfCPURegister(rm), imm);
1225 data += 2 + (*data == 0x6B ? 1 : 4);
1226 break;
1227 }
1228
1229 case 0xF6: {
1230 int mod, regop, rm;
1231 get_modrm(*(data + 1), &mod, ®op, &rm);
1232 if (mod == 3 && regop == 0) {
1233 AppendToBuffer("testb %s,%d", NameOfCPURegister(rm), *(data + 2));
1234 } else {
1235 UnimplementedInstruction();
1236 }
1237 data += 3;
1238 break;
1239 }
1240
1241 case 0x81: // fall through
1242 case 0x83: // 0x81 with sign extension bit set
1243 data += PrintImmediateOp(data);
1244 break;
1245
1246 case 0x0F:
1247 data += TwoByteOpcodeInstruction(data);
1248 break;
1249
1250 case 0x8F: {
1251 data++;
1252 int mod, regop, rm;
1253 get_modrm(*data, &mod, ®op, &rm);
1254 if (regop == 0) {
1255 AppendToBuffer("pop ");
1256 data += PrintRightOperand(data);
1257 }
1258 }
1259 break;
1260
1261 case 0xFF: {
1262 data++;
1263 int mod, regop, rm;
1264 get_modrm(*data, &mod, ®op, &rm);
1265 const char* mnem = NULL;
1266 switch (regop) {
1267 case 0:
1268 mnem = "inc";
1269 break;
1270 case 1:
1271 mnem = "dec";
1272 break;
1273 case 2:
1274 mnem = "call";
1275 break;
1276 case 4:
1277 mnem = "jmp";
1278 break;
1279 case 6:
1280 mnem = "push";
1281 break;
1282 default:
1283 mnem = "???";
1284 }
1285 AppendToBuffer(((regop <= 1) ? "%s%c " : "%s "),
1286 mnem,
1287 operand_size_code());
1288 data += PrintRightOperand(data);
1289 }
1290 break;
1291
1292 case 0xC7: // imm32, fall through
1293 case 0xC6: // imm8
1294 {
1295 bool is_byte = *data == 0xC6;
1296 data++;
1297
1298 AppendToBuffer("mov%c ", is_byte ? 'b' : operand_size_code());
1299 data += PrintRightOperand(data);
1300 int32_t imm = is_byte ? *data : *reinterpret_cast<int32_t*>(data);
1301 AppendToBuffer(",0x%x", imm);
1302 data += is_byte ? 1 : 4;
1303 }
1304 break;
1305
1306 case 0x80: {
1307 data++;
1308 AppendToBuffer("cmpb ");
1309 data += PrintRightOperand(data);
1310 int32_t imm = *data;
1311 AppendToBuffer(",0x%x", imm);
1312 data++;
1313 }
1314 break;
1315
1316 case 0x88: // 8bit, fall through
1317 case 0x89: // 32bit
1318 {
1319 bool is_byte = *data == 0x88;
1320 int mod, regop, rm;
1321 data++;
1322 get_modrm(*data, &mod, ®op, &rm);
1323 AppendToBuffer("mov%c ", is_byte ? 'b' : operand_size_code());
1324 data += PrintRightOperand(data);
1325 AppendToBuffer(",%s", NameOfCPURegister(regop));
1326 }
1327 break;
1328
1329 case 0x90:
1330 case 0x91:
1331 case 0x92:
1332 case 0x93:
1333 case 0x94:
1334 case 0x95:
1335 case 0x96:
1336 case 0x97: {
1337 int reg = (current & 0x7) | (rex_b() ? 8 : 0);
1338 if (reg == 0) {
1339 AppendToBuffer("nop"); // Common name for xchg rax,rax.
1340 } else {
1341 AppendToBuffer("xchg%c rax, %s",
1342 operand_size_code(),
1343 NameOfCPURegister(reg));
1344 }
1345 }
1346
1347
1348 case 0xFE: {
1349 data++;
1350 int mod, regop, rm;
1351 get_modrm(*data, &mod, ®op, &rm);
1352 if (mod == 3 && regop == 1) {
1353 AppendToBuffer("decb %s", NameOfCPURegister(rm));
1354 } else {
1355 UnimplementedInstruction();
1356 }
1357 data++;
1358 }
1359 break;
1360
1361 case 0x68:
1362 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1));
1363 data += 5;
1364 break;
1365
1366 case 0x6A:
1367 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1));
1368 data += 2;
1369 break;
1370
1371 case 0xA1: // Fall through.
1372 case 0xA3:
1373 switch (operand_size()) {
1374 case DOUBLEWORD_SIZE: {
1375 const char* memory_location = NameOfAddress(
1376 reinterpret_cast<byte*>(
1377 *reinterpret_cast<int32_t*>(data + 1)));
1378 if (*data == 0xA1) { // Opcode 0xA1
1379 AppendToBuffer("movzxlq rax,(%s)", memory_location);
1380 } else { // Opcode 0xA3
1381 AppendToBuffer("movzxlq (%s),rax", memory_location);
1382 }
1383 data += 5;
1384 break;
1385 }
1386 case QUADWORD_SIZE: {
1387 // New x64 instruction mov rax,(imm_64).
1388 const char* memory_location = NameOfAddress(
1389 *reinterpret_cast<byte**>(data + 1));
1390 if (*data == 0xA1) { // Opcode 0xA1
1391 AppendToBuffer("movq rax,(%s)", memory_location);
1392 } else { // Opcode 0xA3
1393 AppendToBuffer("movq (%s),rax", memory_location);
1394 }
1395 data += 9;
1396 break;
1397 }
1398 default:
1399 UnimplementedInstruction();
1400 data += 2;
1401 }
1402 break;
1403
1404 case 0xA8:
1405 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1));
1406 data += 2;
1407 break;
1408
1409 case 0xA9: {
1410 int64_t value = 0;
1411 switch (operand_size()) {
1412 case WORD_SIZE:
1413 value = *reinterpret_cast<uint16_t*>(data + 1);
1414 data += 3;
1415 break;
1416 case DOUBLEWORD_SIZE:
1417 value = *reinterpret_cast<uint32_t*>(data + 1);
1418 data += 5;
1419 break;
1420 case QUADWORD_SIZE:
1421 value = *reinterpret_cast<int32_t*>(data + 1);
1422 data += 5;
1423 break;
1424 default:
1425 UNREACHABLE();
1426 }
1427 AppendToBuffer("test%c rax,0x%"V8_PTR_PREFIX"x",
1428 operand_size_code(),
1429 value);
1430 break;
1431 }
1432 case 0xD1: // fall through
1433 case 0xD3: // fall through
1434 case 0xC1:
1435 data += ShiftInstruction(data);
1436 break;
1437 case 0xD0: // fall through
1438 case 0xD2: // fall through
1439 case 0xC0:
1440 byte_size_operand_ = true;
1441 data += ShiftInstruction(data);
1442 break;
1443
1444 case 0xD9: // fall through
1445 case 0xDA: // fall through
1446 case 0xDB: // fall through
1447 case 0xDC: // fall through
1448 case 0xDD: // fall through
1449 case 0xDE: // fall through
1450 case 0xDF:
1451 data += FPUInstruction(data);
1452 break;
1453
1454 case 0xEB:
1455 data += JumpShort(data);
1456 break;
1457
1458 case 0xF7:
1459 data += F7Instruction(data);
1460 break;
1461
1462 default:
1463 UnimplementedInstruction();
1464 data += 1;
1465 }
1466 } // !processed
1467
1468 if (tmp_buffer_pos_ < sizeof tmp_buffer_) {
1469 tmp_buffer_[tmp_buffer_pos_] = '\0';
1470 }
1471
1472 int instr_len = data - instr;
1473 ASSERT(instr_len > 0); // Ensure progress.
1474
1475 int outp = 0;
1476 // Instruction bytes.
1477 for (byte* bp = instr; bp < data; bp++) {
1478 outp += v8::internal::OS::SNPrintF(out_buffer + outp, "%02x", *bp);
1479 }
1480 for (int i = 6 - instr_len; i >= 0; i--) {
1481 outp += v8::internal::OS::SNPrintF(out_buffer + outp, " ");
1482 }
1483
1484 outp += v8::internal::OS::SNPrintF(out_buffer + outp, " %s",
1485 tmp_buffer_.start());
1486 return instr_len;
1487 }
1488
1489 //------------------------------------------------------------------------------
1490
1491
1492 static const char* cpu_regs[16] = {
1493 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi",
1494 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15"
1495 };
1496
1497
1498 static const char* byte_cpu_regs[16] = {
1499 "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil",
1500 "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l"
1501 };
1502
1503
1504 static const char* xmm_regs[16] = {
1505 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7",
1506 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15"
1507 };
1508
1509
NameOfAddress(byte * addr) const1510 const char* NameConverter::NameOfAddress(byte* addr) const {
1511 static v8::internal::EmbeddedVector<char, 32> tmp_buffer;
1512 v8::internal::OS::SNPrintF(tmp_buffer, "%p", addr);
1513 return tmp_buffer.start();
1514 }
1515
1516
NameOfConstant(byte * addr) const1517 const char* NameConverter::NameOfConstant(byte* addr) const {
1518 return NameOfAddress(addr);
1519 }
1520
1521
NameOfCPURegister(int reg) const1522 const char* NameConverter::NameOfCPURegister(int reg) const {
1523 if (0 <= reg && reg < 16)
1524 return cpu_regs[reg];
1525 return "noreg";
1526 }
1527
1528
NameOfByteCPURegister(int reg) const1529 const char* NameConverter::NameOfByteCPURegister(int reg) const {
1530 if (0 <= reg && reg < 16)
1531 return byte_cpu_regs[reg];
1532 return "noreg";
1533 }
1534
1535
NameOfXMMRegister(int reg) const1536 const char* NameConverter::NameOfXMMRegister(int reg) const {
1537 if (0 <= reg && reg < 16)
1538 return xmm_regs[reg];
1539 return "noxmmreg";
1540 }
1541
1542
NameInCode(byte * addr) const1543 const char* NameConverter::NameInCode(byte* addr) const {
1544 // X64 does not embed debug strings at the moment.
1545 UNREACHABLE();
1546 return "";
1547 }
1548
1549 //------------------------------------------------------------------------------
1550
Disassembler(const NameConverter & converter)1551 Disassembler::Disassembler(const NameConverter& converter)
1552 : converter_(converter) { }
1553
~Disassembler()1554 Disassembler::~Disassembler() { }
1555
1556
InstructionDecode(v8::internal::Vector<char> buffer,byte * instruction)1557 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer,
1558 byte* instruction) {
1559 DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE);
1560 return d.InstructionDecode(buffer, instruction);
1561 }
1562
1563
1564 // The X64 assembler does not use constant pools.
ConstantPoolSizeAt(byte * instruction)1565 int Disassembler::ConstantPoolSizeAt(byte* instruction) {
1566 return -1;
1567 }
1568
1569
Disassemble(FILE * f,byte * begin,byte * end)1570 void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) {
1571 NameConverter converter;
1572 Disassembler d(converter);
1573 for (byte* pc = begin; pc < end;) {
1574 v8::internal::EmbeddedVector<char, 128> buffer;
1575 buffer[0] = '\0';
1576 byte* prev_pc = pc;
1577 pc += d.InstructionDecode(buffer, pc);
1578 fprintf(f, "%p", prev_pc);
1579 fprintf(f, " ");
1580
1581 for (byte* bp = prev_pc; bp < pc; bp++) {
1582 fprintf(f, "%02x", *bp);
1583 }
1584 for (int i = 6 - (pc - prev_pc); i >= 0; i--) {
1585 fprintf(f, " ");
1586 }
1587 fprintf(f, " %s\n", buffer.start());
1588 }
1589 }
1590
1591 } // namespace disasm
1592