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