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