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