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