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