disasm-x64.cc revision 257744e915dfc84d6d07a6b2accf8402d9ffc708
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 if (third_byte == 0x0b) { 1025 get_modrm(*current, &mod, ®op, &rm); 1026 // roundsd xmm, xmm/m64, imm8 1027 AppendToBuffer("roundsd %s, ", NameOfCPURegister(regop)); 1028 current += PrintRightOperand(current); 1029 AppendToBuffer(", %d", (*current) & 3); 1030 current += 1; 1031 } else { 1032 UnimplementedInstruction(); 1033 } 1034 } else { 1035 get_modrm(*current, &mod, ®op, &rm); 1036 if (opcode == 0x28) { 1037 AppendToBuffer("movapd %s, ", NameOfXMMRegister(regop)); 1038 current += PrintRightXMMOperand(current); 1039 } else if (opcode == 0x29) { 1040 AppendToBuffer("movapd "); 1041 current += PrintRightXMMOperand(current); 1042 AppendToBuffer(", %s", NameOfXMMRegister(regop)); 1043 } else if (opcode == 0x6E) { 1044 AppendToBuffer("mov%c %s,", 1045 rex_w() ? 'q' : 'd', 1046 NameOfXMMRegister(regop)); 1047 current += PrintRightOperand(current); 1048 } else if (opcode == 0x6F) { 1049 AppendToBuffer("movdqa %s,", 1050 NameOfXMMRegister(regop)); 1051 current += PrintRightXMMOperand(current); 1052 } else if (opcode == 0x7E) { 1053 AppendToBuffer("mov%c ", 1054 rex_w() ? 'q' : 'd'); 1055 current += PrintRightOperand(current); 1056 AppendToBuffer(", %s", NameOfXMMRegister(regop)); 1057 } else if (opcode == 0x7F) { 1058 AppendToBuffer("movdqa "); 1059 current += PrintRightXMMOperand(current); 1060 AppendToBuffer(", %s", NameOfXMMRegister(regop)); 1061 } else if (opcode == 0xD6) { 1062 AppendToBuffer("movq "); 1063 current += PrintRightXMMOperand(current); 1064 AppendToBuffer(", %s", NameOfXMMRegister(regop)); 1065 } else { 1066 const char* mnemonic = "?"; 1067 if (opcode == 0x50) { 1068 mnemonic = "movmskpd"; 1069 } else if (opcode == 0x54) { 1070 mnemonic = "andpd"; 1071 } else if (opcode == 0x56) { 1072 mnemonic = "orpd"; 1073 } else if (opcode == 0x57) { 1074 mnemonic = "xorpd"; 1075 } else if (opcode == 0x2E) { 1076 mnemonic = "ucomisd"; 1077 } else if (opcode == 0x2F) { 1078 mnemonic = "comisd"; 1079 } else { 1080 UnimplementedInstruction(); 1081 } 1082 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop)); 1083 current += PrintRightXMMOperand(current); 1084 } 1085 } 1086 } else if (group_1_prefix_ == 0xF2) { 1087 // Beginning of instructions with prefix 0xF2. 1088 1089 if (opcode == 0x11 || opcode == 0x10) { 1090 // MOVSD: Move scalar double-precision fp to/from/between XMM registers. 1091 AppendToBuffer("movsd "); 1092 int mod, regop, rm; 1093 get_modrm(*current, &mod, ®op, &rm); 1094 if (opcode == 0x11) { 1095 current += PrintRightXMMOperand(current); 1096 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1097 } else { 1098 AppendToBuffer("%s,", NameOfXMMRegister(regop)); 1099 current += PrintRightXMMOperand(current); 1100 } 1101 } else if (opcode == 0x2A) { 1102 // CVTSI2SD: integer to XMM double conversion. 1103 int mod, regop, rm; 1104 get_modrm(*current, &mod, ®op, &rm); 1105 AppendToBuffer("%sd %s,", mnemonic, NameOfXMMRegister(regop)); 1106 current += PrintRightOperand(current); 1107 } else if (opcode == 0x2C) { 1108 // CVTTSD2SI: 1109 // Convert with truncation scalar double-precision FP to integer. 1110 int mod, regop, rm; 1111 get_modrm(*current, &mod, ®op, &rm); 1112 AppendToBuffer("cvttsd2si%c %s,", 1113 operand_size_code(), NameOfCPURegister(regop)); 1114 current += PrintRightXMMOperand(current); 1115 } else if (opcode == 0x2D) { 1116 // CVTSD2SI: Convert scalar double-precision FP to integer. 1117 int mod, regop, rm; 1118 get_modrm(*current, &mod, ®op, &rm); 1119 AppendToBuffer("cvtsd2si%c %s,", 1120 operand_size_code(), NameOfCPURegister(regop)); 1121 current += PrintRightXMMOperand(current); 1122 } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) { 1123 // XMM arithmetic. Mnemonic was retrieved at the start of this function. 1124 int mod, regop, rm; 1125 get_modrm(*current, &mod, ®op, &rm); 1126 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop)); 1127 current += PrintRightXMMOperand(current); 1128 } else { 1129 UnimplementedInstruction(); 1130 } 1131 } else if (group_1_prefix_ == 0xF3) { 1132 // Instructions with prefix 0xF3. 1133 if (opcode == 0x11 || opcode == 0x10) { 1134 // MOVSS: Move scalar double-precision fp to/from/between XMM registers. 1135 AppendToBuffer("movss "); 1136 int mod, regop, rm; 1137 get_modrm(*current, &mod, ®op, &rm); 1138 if (opcode == 0x11) { 1139 current += PrintRightOperand(current); 1140 AppendToBuffer(",%s", NameOfXMMRegister(regop)); 1141 } else { 1142 AppendToBuffer("%s,", NameOfXMMRegister(regop)); 1143 current += PrintRightOperand(current); 1144 } 1145 } else if (opcode == 0x2A) { 1146 // CVTSI2SS: integer to XMM single conversion. 1147 int mod, regop, rm; 1148 get_modrm(*current, &mod, ®op, &rm); 1149 AppendToBuffer("%ss %s,", mnemonic, NameOfXMMRegister(regop)); 1150 current += PrintRightOperand(current); 1151 } else if (opcode == 0x2C) { 1152 // CVTTSS2SI: 1153 // Convert with truncation scalar single-precision FP to dword integer. 1154 int mod, regop, rm; 1155 get_modrm(*current, &mod, ®op, &rm); 1156 AppendToBuffer("cvttss2si%c %s,", 1157 operand_size_code(), NameOfCPURegister(regop)); 1158 current += PrintRightXMMOperand(current); 1159 } else if (opcode == 0x5A) { 1160 // CVTSS2SD: 1161 // Convert scalar single-precision FP to scalar double-precision FP. 1162 int mod, regop, rm; 1163 get_modrm(*current, &mod, ®op, &rm); 1164 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop)); 1165 current += PrintRightXMMOperand(current); 1166 } else if (opcode == 0x7E) { 1167 int mod, regop, rm; 1168 get_modrm(*current, &mod, ®op, &rm); 1169 AppendToBuffer("movq %s, ", NameOfXMMRegister(regop)); 1170 current += PrintRightXMMOperand(current); 1171 } else { 1172 UnimplementedInstruction(); 1173 } 1174 } else if (opcode == 0x1F) { 1175 // NOP 1176 int mod, regop, rm; 1177 get_modrm(*current, &mod, ®op, &rm); 1178 current++; 1179 if (regop == 4) { // SIB byte present. 1180 current++; 1181 } 1182 if (mod == 1) { // Byte displacement. 1183 current += 1; 1184 } else if (mod == 2) { // 32-bit displacement. 1185 current += 4; 1186 } // else no immediate displacement. 1187 AppendToBuffer("nop"); 1188 1189 } else if (opcode == 0x28) { 1190 // movaps xmm, xmm/m128 1191 int mod, regop, rm; 1192 get_modrm(*current, &mod, ®op, &rm); 1193 AppendToBuffer("movaps %s, ", NameOfXMMRegister(regop)); 1194 current += PrintRightXMMOperand(current); 1195 1196 } else if (opcode == 0x29) { 1197 // movaps xmm/m128, xmm 1198 int mod, regop, rm; 1199 get_modrm(*current, &mod, ®op, &rm); 1200 AppendToBuffer("movaps "); 1201 current += PrintRightXMMOperand(current); 1202 AppendToBuffer(", %s", NameOfXMMRegister(regop)); 1203 1204 } else if (opcode == 0xA2 || opcode == 0x31) { 1205 // RDTSC or CPUID 1206 AppendToBuffer("%s", mnemonic); 1207 1208 } else if ((opcode & 0xF0) == 0x40) { 1209 // CMOVcc: conditional move. 1210 int condition = opcode & 0x0F; 1211 const InstructionDesc& idesc = cmov_instructions[condition]; 1212 byte_size_operand_ = idesc.byte_size_operation; 1213 current += PrintOperands(idesc.mnem, idesc.op_order_, current); 1214 1215 } else if (opcode == 0x57) { 1216 // xorps xmm, xmm/m128 1217 int mod, regop, rm; 1218 get_modrm(*current, &mod, ®op, &rm); 1219 AppendToBuffer("xorps %s, ", NameOfXMMRegister(regop)); 1220 current += PrintRightXMMOperand(current); 1221 1222 } else if ((opcode & 0xF0) == 0x80) { 1223 // Jcc: Conditional jump (branch). 1224 current = data + JumpConditional(data); 1225 1226 } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 || 1227 opcode == 0xB7 || opcode == 0xAF) { 1228 // Size-extending moves, IMUL. 1229 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current); 1230 1231 } else if ((opcode & 0xF0) == 0x90) { 1232 // SETcc: Set byte on condition. Needs pointer to beginning of instruction. 1233 current = data + SetCC(data); 1234 1235 } else if (opcode == 0xAB || opcode == 0xA5 || opcode == 0xAD) { 1236 // SHLD, SHRD (double-precision shift), BTS (bit set). 1237 AppendToBuffer("%s ", mnemonic); 1238 int mod, regop, rm; 1239 get_modrm(*current, &mod, ®op, &rm); 1240 current += PrintRightOperand(current); 1241 if (opcode == 0xAB) { 1242 AppendToBuffer(",%s", NameOfCPURegister(regop)); 1243 } else { 1244 AppendToBuffer(",%s,cl", NameOfCPURegister(regop)); 1245 } 1246 } else { 1247 UnimplementedInstruction(); 1248 } 1249 return static_cast<int>(current - data); 1250} 1251 1252 1253// Mnemonics for two-byte opcode instructions starting with 0x0F. 1254// The argument is the second byte of the two-byte opcode. 1255// Returns NULL if the instruction is not handled here. 1256const char* DisassemblerX64::TwoByteMnemonic(byte opcode) { 1257 switch (opcode) { 1258 case 0x1F: 1259 return "nop"; 1260 case 0x2A: // F2/F3 prefix. 1261 return "cvtsi2s"; 1262 case 0x31: 1263 return "rdtsc"; 1264 case 0x51: // F2 prefix. 1265 return "sqrtsd"; 1266 case 0x58: // F2 prefix. 1267 return "addsd"; 1268 case 0x59: // F2 prefix. 1269 return "mulsd"; 1270 case 0x5C: // F2 prefix. 1271 return "subsd"; 1272 case 0x5E: // F2 prefix. 1273 return "divsd"; 1274 case 0xA2: 1275 return "cpuid"; 1276 case 0xA5: 1277 return "shld"; 1278 case 0xAB: 1279 return "bts"; 1280 case 0xAD: 1281 return "shrd"; 1282 case 0xAF: 1283 return "imul"; 1284 case 0xB6: 1285 return "movzxb"; 1286 case 0xB7: 1287 return "movzxw"; 1288 case 0xBE: 1289 return "movsxb"; 1290 case 0xBF: 1291 return "movsxw"; 1292 default: 1293 return NULL; 1294 } 1295} 1296 1297 1298// Disassembles the instruction at instr, and writes it into out_buffer. 1299int DisassemblerX64::InstructionDecode(v8::internal::Vector<char> out_buffer, 1300 byte* instr) { 1301 tmp_buffer_pos_ = 0; // starting to write as position 0 1302 byte* data = instr; 1303 bool processed = true; // Will be set to false if the current instruction 1304 // is not in 'instructions' table. 1305 byte current; 1306 1307 // Scan for prefixes. 1308 while (true) { 1309 current = *data; 1310 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix. 1311 operand_size_ = current; 1312 } else if ((current & 0xF0) == 0x40) { // REX prefix. 1313 setRex(current); 1314 if (rex_w()) AppendToBuffer("REX.W "); 1315 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3). 1316 group_1_prefix_ = current; 1317 } else { // Not a prefix - an opcode. 1318 break; 1319 } 1320 data++; 1321 } 1322 1323 const InstructionDesc& idesc = instruction_table.Get(current); 1324 byte_size_operand_ = idesc.byte_size_operation; 1325 switch (idesc.type) { 1326 case ZERO_OPERANDS_INSTR: 1327 if (current >= 0xA4 && current <= 0xA7) { 1328 // String move or compare operations. 1329 if (group_1_prefix_ == REP_PREFIX) { 1330 // REP. 1331 AppendToBuffer("rep "); 1332 } 1333 if (rex_w()) AppendToBuffer("REX.W "); 1334 AppendToBuffer("%s%c", idesc.mnem, operand_size_code()); 1335 } else { 1336 AppendToBuffer("%s", idesc.mnem, operand_size_code()); 1337 } 1338 data++; 1339 break; 1340 1341 case TWO_OPERANDS_INSTR: 1342 data++; 1343 data += PrintOperands(idesc.mnem, idesc.op_order_, data); 1344 break; 1345 1346 case JUMP_CONDITIONAL_SHORT_INSTR: 1347 data += JumpConditionalShort(data); 1348 break; 1349 1350 case REGISTER_INSTR: 1351 AppendToBuffer("%s%c %s", 1352 idesc.mnem, 1353 operand_size_code(), 1354 NameOfCPURegister(base_reg(current & 0x07))); 1355 data++; 1356 break; 1357 case PUSHPOP_INSTR: 1358 AppendToBuffer("%s %s", 1359 idesc.mnem, 1360 NameOfCPURegister(base_reg(current & 0x07))); 1361 data++; 1362 break; 1363 case MOVE_REG_INSTR: { 1364 byte* addr = NULL; 1365 switch (operand_size()) { 1366 case WORD_SIZE: 1367 addr = reinterpret_cast<byte*>(*reinterpret_cast<int16_t*>(data + 1)); 1368 data += 3; 1369 break; 1370 case DOUBLEWORD_SIZE: 1371 addr = reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1)); 1372 data += 5; 1373 break; 1374 case QUADWORD_SIZE: 1375 addr = reinterpret_cast<byte*>(*reinterpret_cast<int64_t*>(data + 1)); 1376 data += 9; 1377 break; 1378 default: 1379 UNREACHABLE(); 1380 } 1381 AppendToBuffer("mov%c %s,%s", 1382 operand_size_code(), 1383 NameOfCPURegister(base_reg(current & 0x07)), 1384 NameOfAddress(addr)); 1385 break; 1386 } 1387 1388 case CALL_JUMP_INSTR: { 1389 byte* addr = data + *reinterpret_cast<int32_t*>(data + 1) + 5; 1390 AppendToBuffer("%s %s", idesc.mnem, NameOfAddress(addr)); 1391 data += 5; 1392 break; 1393 } 1394 1395 case SHORT_IMMEDIATE_INSTR: { 1396 byte* addr = 1397 reinterpret_cast<byte*>(*reinterpret_cast<int32_t*>(data + 1)); 1398 AppendToBuffer("%s rax, %s", idesc.mnem, NameOfAddress(addr)); 1399 data += 5; 1400 break; 1401 } 1402 1403 case NO_INSTR: 1404 processed = false; 1405 break; 1406 1407 default: 1408 UNIMPLEMENTED(); // This type is not implemented. 1409 } 1410 1411 // The first byte didn't match any of the simple opcodes, so we 1412 // need to do special processing on it. 1413 if (!processed) { 1414 switch (*data) { 1415 case 0xC2: 1416 AppendToBuffer("ret 0x%x", *reinterpret_cast<uint16_t*>(data + 1)); 1417 data += 3; 1418 break; 1419 1420 case 0x69: // fall through 1421 case 0x6B: { 1422 int mod, regop, rm; 1423 get_modrm(*(data + 1), &mod, ®op, &rm); 1424 int32_t imm = *data == 0x6B ? *(data + 2) 1425 : *reinterpret_cast<int32_t*>(data + 2); 1426 AppendToBuffer("imul%c %s,%s,0x%x", 1427 operand_size_code(), 1428 NameOfCPURegister(regop), 1429 NameOfCPURegister(rm), imm); 1430 data += 2 + (*data == 0x6B ? 1 : 4); 1431 break; 1432 } 1433 1434 case 0x81: // fall through 1435 case 0x83: // 0x81 with sign extension bit set 1436 data += PrintImmediateOp(data); 1437 break; 1438 1439 case 0x0F: 1440 data += TwoByteOpcodeInstruction(data); 1441 break; 1442 1443 case 0x8F: { 1444 data++; 1445 int mod, regop, rm; 1446 get_modrm(*data, &mod, ®op, &rm); 1447 if (regop == 0) { 1448 AppendToBuffer("pop "); 1449 data += PrintRightOperand(data); 1450 } 1451 } 1452 break; 1453 1454 case 0xFF: { 1455 data++; 1456 int mod, regop, rm; 1457 get_modrm(*data, &mod, ®op, &rm); 1458 const char* mnem = NULL; 1459 switch (regop) { 1460 case 0: 1461 mnem = "inc"; 1462 break; 1463 case 1: 1464 mnem = "dec"; 1465 break; 1466 case 2: 1467 mnem = "call"; 1468 break; 1469 case 4: 1470 mnem = "jmp"; 1471 break; 1472 case 6: 1473 mnem = "push"; 1474 break; 1475 default: 1476 mnem = "???"; 1477 } 1478 AppendToBuffer(((regop <= 1) ? "%s%c " : "%s "), 1479 mnem, 1480 operand_size_code()); 1481 data += PrintRightOperand(data); 1482 } 1483 break; 1484 1485 case 0xC7: // imm32, fall through 1486 case 0xC6: // imm8 1487 { 1488 bool is_byte = *data == 0xC6; 1489 data++; 1490 if (is_byte) { 1491 AppendToBuffer("movb "); 1492 data += PrintRightByteOperand(data); 1493 int32_t imm = *data; 1494 AppendToBuffer(",0x%x", imm); 1495 data++; 1496 } else { 1497 AppendToBuffer("mov%c ", operand_size_code()); 1498 data += PrintRightOperand(data); 1499 int32_t imm = *reinterpret_cast<int32_t*>(data); 1500 AppendToBuffer(",0x%x", imm); 1501 data += 4; 1502 } 1503 } 1504 break; 1505 1506 case 0x80: { 1507 data++; 1508 AppendToBuffer("cmpb "); 1509 data += PrintRightByteOperand(data); 1510 int32_t imm = *data; 1511 AppendToBuffer(",0x%x", imm); 1512 data++; 1513 } 1514 break; 1515 1516 case 0x88: // 8bit, fall through 1517 case 0x89: // 32bit 1518 { 1519 bool is_byte = *data == 0x88; 1520 int mod, regop, rm; 1521 data++; 1522 get_modrm(*data, &mod, ®op, &rm); 1523 if (is_byte) { 1524 AppendToBuffer("movb "); 1525 data += PrintRightByteOperand(data); 1526 AppendToBuffer(",%s", NameOfByteCPURegister(regop)); 1527 } else { 1528 AppendToBuffer("mov%c ", operand_size_code()); 1529 data += PrintRightOperand(data); 1530 AppendToBuffer(",%s", NameOfCPURegister(regop)); 1531 } 1532 } 1533 break; 1534 1535 case 0x90: 1536 case 0x91: 1537 case 0x92: 1538 case 0x93: 1539 case 0x94: 1540 case 0x95: 1541 case 0x96: 1542 case 0x97: { 1543 int reg = (*data & 0x7) | (rex_b() ? 8 : 0); 1544 if (reg == 0) { 1545 AppendToBuffer("nop"); // Common name for xchg rax,rax. 1546 } else { 1547 AppendToBuffer("xchg%c rax, %s", 1548 operand_size_code(), 1549 NameOfCPURegister(reg)); 1550 } 1551 data++; 1552 } 1553 break; 1554 case 0xB0: 1555 case 0xB1: 1556 case 0xB2: 1557 case 0xB3: 1558 case 0xB4: 1559 case 0xB5: 1560 case 0xB6: 1561 case 0xB7: 1562 case 0xB8: 1563 case 0xB9: 1564 case 0xBA: 1565 case 0xBB: 1566 case 0xBC: 1567 case 0xBD: 1568 case 0xBE: 1569 case 0xBF: { 1570 // mov reg8,imm8 or mov reg32,imm32 1571 byte opcode = *data; 1572 data++; 1573 bool is_32bit = (opcode >= 0xB8); 1574 int reg = (opcode & 0x7) | (rex_b() ? 8 : 0); 1575 if (is_32bit) { 1576 AppendToBuffer("mov%c %s, ", 1577 operand_size_code(), 1578 NameOfCPURegister(reg)); 1579 data += PrintImmediate(data, DOUBLEWORD_SIZE); 1580 } else { 1581 AppendToBuffer("movb %s, ", 1582 NameOfByteCPURegister(reg)); 1583 data += PrintImmediate(data, BYTE_SIZE); 1584 } 1585 break; 1586 } 1587 case 0xFE: { 1588 data++; 1589 int mod, regop, rm; 1590 get_modrm(*data, &mod, ®op, &rm); 1591 if (regop == 1) { 1592 AppendToBuffer("decb "); 1593 data += PrintRightByteOperand(data); 1594 } else { 1595 UnimplementedInstruction(); 1596 } 1597 break; 1598 } 1599 case 0x68: 1600 AppendToBuffer("push 0x%x", *reinterpret_cast<int32_t*>(data + 1)); 1601 data += 5; 1602 break; 1603 1604 case 0x6A: 1605 AppendToBuffer("push 0x%x", *reinterpret_cast<int8_t*>(data + 1)); 1606 data += 2; 1607 break; 1608 1609 case 0xA1: // Fall through. 1610 case 0xA3: 1611 switch (operand_size()) { 1612 case DOUBLEWORD_SIZE: { 1613 const char* memory_location = NameOfAddress( 1614 reinterpret_cast<byte*>( 1615 *reinterpret_cast<int32_t*>(data + 1))); 1616 if (*data == 0xA1) { // Opcode 0xA1 1617 AppendToBuffer("movzxlq rax,(%s)", memory_location); 1618 } else { // Opcode 0xA3 1619 AppendToBuffer("movzxlq (%s),rax", memory_location); 1620 } 1621 data += 5; 1622 break; 1623 } 1624 case QUADWORD_SIZE: { 1625 // New x64 instruction mov rax,(imm_64). 1626 const char* memory_location = NameOfAddress( 1627 *reinterpret_cast<byte**>(data + 1)); 1628 if (*data == 0xA1) { // Opcode 0xA1 1629 AppendToBuffer("movq rax,(%s)", memory_location); 1630 } else { // Opcode 0xA3 1631 AppendToBuffer("movq (%s),rax", memory_location); 1632 } 1633 data += 9; 1634 break; 1635 } 1636 default: 1637 UnimplementedInstruction(); 1638 data += 2; 1639 } 1640 break; 1641 1642 case 0xA8: 1643 AppendToBuffer("test al,0x%x", *reinterpret_cast<uint8_t*>(data + 1)); 1644 data += 2; 1645 break; 1646 1647 case 0xA9: { 1648 int64_t value = 0; 1649 switch (operand_size()) { 1650 case WORD_SIZE: 1651 value = *reinterpret_cast<uint16_t*>(data + 1); 1652 data += 3; 1653 break; 1654 case DOUBLEWORD_SIZE: 1655 value = *reinterpret_cast<uint32_t*>(data + 1); 1656 data += 5; 1657 break; 1658 case QUADWORD_SIZE: 1659 value = *reinterpret_cast<int32_t*>(data + 1); 1660 data += 5; 1661 break; 1662 default: 1663 UNREACHABLE(); 1664 } 1665 AppendToBuffer("test%c rax,0x%"V8_PTR_PREFIX"x", 1666 operand_size_code(), 1667 value); 1668 break; 1669 } 1670 case 0xD1: // fall through 1671 case 0xD3: // fall through 1672 case 0xC1: 1673 data += ShiftInstruction(data); 1674 break; 1675 case 0xD0: // fall through 1676 case 0xD2: // fall through 1677 case 0xC0: 1678 byte_size_operand_ = true; 1679 data += ShiftInstruction(data); 1680 break; 1681 1682 case 0xD9: // fall through 1683 case 0xDA: // fall through 1684 case 0xDB: // fall through 1685 case 0xDC: // fall through 1686 case 0xDD: // fall through 1687 case 0xDE: // fall through 1688 case 0xDF: 1689 data += FPUInstruction(data); 1690 break; 1691 1692 case 0xEB: 1693 data += JumpShort(data); 1694 break; 1695 1696 case 0xF6: 1697 byte_size_operand_ = true; // fall through 1698 case 0xF7: 1699 data += F6F7Instruction(data); 1700 break; 1701 1702 default: 1703 UnimplementedInstruction(); 1704 data += 1; 1705 } 1706 } // !processed 1707 1708 if (tmp_buffer_pos_ < sizeof tmp_buffer_) { 1709 tmp_buffer_[tmp_buffer_pos_] = '\0'; 1710 } 1711 1712 int instr_len = static_cast<int>(data - instr); 1713 ASSERT(instr_len > 0); // Ensure progress. 1714 1715 int outp = 0; 1716 // Instruction bytes. 1717 for (byte* bp = instr; bp < data; bp++) { 1718 outp += v8::internal::OS::SNPrintF(out_buffer + outp, "%02x", *bp); 1719 } 1720 for (int i = 6 - instr_len; i >= 0; i--) { 1721 outp += v8::internal::OS::SNPrintF(out_buffer + outp, " "); 1722 } 1723 1724 outp += v8::internal::OS::SNPrintF(out_buffer + outp, " %s", 1725 tmp_buffer_.start()); 1726 return instr_len; 1727} 1728 1729//------------------------------------------------------------------------------ 1730 1731 1732static const char* cpu_regs[16] = { 1733 "rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi", 1734 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15" 1735}; 1736 1737 1738static const char* byte_cpu_regs[16] = { 1739 "al", "cl", "dl", "bl", "spl", "bpl", "sil", "dil", 1740 "r8l", "r9l", "r10l", "r11l", "r12l", "r13l", "r14l", "r15l" 1741}; 1742 1743 1744static const char* xmm_regs[16] = { 1745 "xmm0", "xmm1", "xmm2", "xmm3", "xmm4", "xmm5", "xmm6", "xmm7", 1746 "xmm8", "xmm9", "xmm10", "xmm11", "xmm12", "xmm13", "xmm14", "xmm15" 1747}; 1748 1749 1750const char* NameConverter::NameOfAddress(byte* addr) const { 1751 v8::internal::OS::SNPrintF(tmp_buffer_, "%p", addr); 1752 return tmp_buffer_.start(); 1753} 1754 1755 1756const char* NameConverter::NameOfConstant(byte* addr) const { 1757 return NameOfAddress(addr); 1758} 1759 1760 1761const char* NameConverter::NameOfCPURegister(int reg) const { 1762 if (0 <= reg && reg < 16) 1763 return cpu_regs[reg]; 1764 return "noreg"; 1765} 1766 1767 1768const char* NameConverter::NameOfByteCPURegister(int reg) const { 1769 if (0 <= reg && reg < 16) 1770 return byte_cpu_regs[reg]; 1771 return "noreg"; 1772} 1773 1774 1775const char* NameConverter::NameOfXMMRegister(int reg) const { 1776 if (0 <= reg && reg < 16) 1777 return xmm_regs[reg]; 1778 return "noxmmreg"; 1779} 1780 1781 1782const char* NameConverter::NameInCode(byte* addr) const { 1783 // X64 does not embed debug strings at the moment. 1784 UNREACHABLE(); 1785 return ""; 1786} 1787 1788//------------------------------------------------------------------------------ 1789 1790Disassembler::Disassembler(const NameConverter& converter) 1791 : converter_(converter) { } 1792 1793Disassembler::~Disassembler() { } 1794 1795 1796int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer, 1797 byte* instruction) { 1798 DisassemblerX64 d(converter_, CONTINUE_ON_UNIMPLEMENTED_OPCODE); 1799 return d.InstructionDecode(buffer, instruction); 1800} 1801 1802 1803// The X64 assembler does not use constant pools. 1804int Disassembler::ConstantPoolSizeAt(byte* instruction) { 1805 return -1; 1806} 1807 1808 1809void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) { 1810 NameConverter converter; 1811 Disassembler d(converter); 1812 for (byte* pc = begin; pc < end;) { 1813 v8::internal::EmbeddedVector<char, 128> buffer; 1814 buffer[0] = '\0'; 1815 byte* prev_pc = pc; 1816 pc += d.InstructionDecode(buffer, pc); 1817 fprintf(f, "%p", prev_pc); 1818 fprintf(f, " "); 1819 1820 for (byte* bp = prev_pc; bp < pc; bp++) { 1821 fprintf(f, "%02x", *bp); 1822 } 1823 for (int i = 6 - static_cast<int>(pc - prev_pc); i >= 0; i--) { 1824 fprintf(f, " "); 1825 } 1826 fprintf(f, " %s\n", buffer.start()); 1827 } 1828} 1829 1830} // namespace disasm 1831 1832#endif // V8_TARGET_ARCH_X64 1833