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