| OLD | NEW |
| 1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include <assert.h> | 5 #include <assert.h> |
| 6 #include <stdio.h> | 6 #include <stdio.h> |
| 7 #include <stdarg.h> | 7 #include <stdarg.h> |
| 8 | 8 |
| 9 #include "v8.h" | 9 #include "v8.h" |
| 10 | 10 |
| 11 #if V8_TARGET_ARCH_IA32 | 11 #if V8_TARGET_ARCH_X87 |
| 12 | 12 |
| 13 #include "disasm.h" | 13 #include "disasm.h" |
| 14 | 14 |
| 15 namespace disasm { | 15 namespace disasm { |
| 16 | 16 |
| 17 enum OperandOrder { | 17 enum OperandOrder { |
| 18 UNSET_OP_ORDER = 0, | 18 UNSET_OP_ORDER = 0, |
| 19 REG_OPER_OP_ORDER, | 19 REG_OPER_OP_ORDER, |
| 20 OPER_REG_OP_ORDER | 20 OPER_REG_OP_ORDER |
| 21 }; | 21 }; |
| (...skipping 211 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 233 void InstructionTable::AddJumpConditionalShort() { | 233 void InstructionTable::AddJumpConditionalShort() { |
| 234 for (byte b = 0x70; b <= 0x7F; b++) { | 234 for (byte b = 0x70; b <= 0x7F; b++) { |
| 235 InstructionDesc* id = &instructions_[b]; | 235 InstructionDesc* id = &instructions_[b]; |
| 236 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered. | 236 ASSERT_EQ(NO_INSTR, id->type); // Information not already entered. |
| 237 id->mnem = jump_conditional_mnem[b & 0x0F]; | 237 id->mnem = jump_conditional_mnem[b & 0x0F]; |
| 238 id->type = JUMP_CONDITIONAL_SHORT_INSTR; | 238 id->type = JUMP_CONDITIONAL_SHORT_INSTR; |
| 239 } | 239 } |
| 240 } | 240 } |
| 241 | 241 |
| 242 | 242 |
| 243 // The IA32 disassembler implementation. | 243 // The X87 disassembler implementation. |
| 244 class DisassemblerIA32 { | 244 class DisassemblerX87 { |
| 245 public: | 245 public: |
| 246 DisassemblerIA32(const NameConverter& converter, | 246 DisassemblerX87(const NameConverter& converter, |
| 247 bool abort_on_unimplemented = true) | 247 bool abort_on_unimplemented = true) |
| 248 : converter_(converter), | 248 : converter_(converter), |
| 249 instruction_table_(InstructionTable::get_instance()), | 249 instruction_table_(InstructionTable::get_instance()), |
| 250 tmp_buffer_pos_(0), | 250 tmp_buffer_pos_(0), |
| 251 abort_on_unimplemented_(abort_on_unimplemented) { | 251 abort_on_unimplemented_(abort_on_unimplemented) { |
| 252 tmp_buffer_[0] = '\0'; | 252 tmp_buffer_[0] = '\0'; |
| 253 } | 253 } |
| 254 | 254 |
| 255 virtual ~DisassemblerIA32() {} | 255 virtual ~DisassemblerX87() {} |
| 256 | 256 |
| 257 // Writes one disassembled instruction into 'buffer' (0-terminated). | 257 // Writes one disassembled instruction into 'buffer' (0-terminated). |
| 258 // Returns the length of the disassembled machine instruction in bytes. | 258 // Returns the length of the disassembled machine instruction in bytes. |
| 259 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); | 259 int InstructionDecode(v8::internal::Vector<char> buffer, byte* instruction); |
| 260 | 260 |
| 261 private: | 261 private: |
| 262 const NameConverter& converter_; | 262 const NameConverter& converter_; |
| 263 InstructionTable* instruction_table_; | 263 InstructionTable* instruction_table_; |
| 264 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; | 264 v8::internal::EmbeddedVector<char, 128> tmp_buffer_; |
| 265 unsigned int tmp_buffer_pos_; | 265 unsigned int tmp_buffer_pos_; |
| (...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 315 *rm = data & 7; | 315 *rm = data & 7; |
| 316 } | 316 } |
| 317 | 317 |
| 318 | 318 |
| 319 static void get_sib(byte data, int* scale, int* index, int* base) { | 319 static void get_sib(byte data, int* scale, int* index, int* base) { |
| 320 *scale = (data >> 6) & 3; | 320 *scale = (data >> 6) & 3; |
| 321 *index = (data >> 3) & 7; | 321 *index = (data >> 3) & 7; |
| 322 *base = data & 7; | 322 *base = data & 7; |
| 323 } | 323 } |
| 324 | 324 |
| 325 typedef const char* (DisassemblerIA32::*RegisterNameMapping)(int reg) const; | 325 typedef const char* (DisassemblerX87::*RegisterNameMapping)(int reg) const; |
| 326 | 326 |
| 327 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name); | 327 int PrintRightOperandHelper(byte* modrmp, RegisterNameMapping register_name); |
| 328 int PrintRightOperand(byte* modrmp); | 328 int PrintRightOperand(byte* modrmp); |
| 329 int PrintRightByteOperand(byte* modrmp); | 329 int PrintRightByteOperand(byte* modrmp); |
| 330 int PrintRightXMMOperand(byte* modrmp); | 330 int PrintRightXMMOperand(byte* modrmp); |
| 331 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data); | 331 int PrintOperands(const char* mnem, OperandOrder op_order, byte* data); |
| 332 int PrintImmediateOp(byte* data); | 332 int PrintImmediateOp(byte* data); |
| 333 int F7Instruction(byte* data); | 333 int F7Instruction(byte* data); |
| 334 int D1D3C1Instruction(byte* data); | 334 int D1D3C1Instruction(byte* data); |
| 335 int JumpShort(byte* data); | 335 int JumpShort(byte* data); |
| (...skipping 10 matching lines...) Expand all Loading... |
| 346 void UnimplementedInstruction() { | 346 void UnimplementedInstruction() { |
| 347 if (abort_on_unimplemented_) { | 347 if (abort_on_unimplemented_) { |
| 348 UNIMPLEMENTED(); | 348 UNIMPLEMENTED(); |
| 349 } else { | 349 } else { |
| 350 AppendToBuffer("'Unimplemented Instruction'"); | 350 AppendToBuffer("'Unimplemented Instruction'"); |
| 351 } | 351 } |
| 352 } | 352 } |
| 353 }; | 353 }; |
| 354 | 354 |
| 355 | 355 |
| 356 void DisassemblerIA32::AppendToBuffer(const char* format, ...) { | 356 void DisassemblerX87::AppendToBuffer(const char* format, ...) { |
| 357 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_; | 357 v8::internal::Vector<char> buf = tmp_buffer_ + tmp_buffer_pos_; |
| 358 va_list args; | 358 va_list args; |
| 359 va_start(args, format); | 359 va_start(args, format); |
| 360 int result = v8::internal::OS::VSNPrintF(buf, format, args); | 360 int result = v8::internal::OS::VSNPrintF(buf, format, args); |
| 361 va_end(args); | 361 va_end(args); |
| 362 tmp_buffer_pos_ += result; | 362 tmp_buffer_pos_ += result; |
| 363 } | 363 } |
| 364 | 364 |
| 365 int DisassemblerIA32::PrintRightOperandHelper( | 365 int DisassemblerX87::PrintRightOperandHelper( |
| 366 byte* modrmp, | 366 byte* modrmp, |
| 367 RegisterNameMapping direct_register_name) { | 367 RegisterNameMapping direct_register_name) { |
| 368 int mod, regop, rm; | 368 int mod, regop, rm; |
| 369 get_modrm(*modrmp, &mod, ®op, &rm); | 369 get_modrm(*modrmp, &mod, ®op, &rm); |
| 370 RegisterNameMapping register_name = (mod == 3) ? direct_register_name : | 370 RegisterNameMapping register_name = (mod == 3) ? direct_register_name : |
| 371 &DisassemblerIA32::NameOfCPURegister; | 371 &DisassemblerX87::NameOfCPURegister; |
| 372 switch (mod) { | 372 switch (mod) { |
| 373 case 0: | 373 case 0: |
| 374 if (rm == ebp) { | 374 if (rm == ebp) { |
| 375 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1); | 375 int32_t disp = *reinterpret_cast<int32_t*>(modrmp+1); |
| 376 AppendToBuffer("[0x%x]", disp); | 376 AppendToBuffer("[0x%x]", disp); |
| 377 return 5; | 377 return 5; |
| 378 } else if (rm == esp) { | 378 } else if (rm == esp) { |
| 379 byte sib = *(modrmp + 1); | 379 byte sib = *(modrmp + 1); |
| 380 int scale, index, base; | 380 int scale, index, base; |
| 381 get_sib(sib, &scale, &index, &base); | 381 get_sib(sib, &scale, &index, &base); |
| (...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 443 AppendToBuffer("%s", (this->*register_name)(rm)); | 443 AppendToBuffer("%s", (this->*register_name)(rm)); |
| 444 return 1; | 444 return 1; |
| 445 default: | 445 default: |
| 446 UnimplementedInstruction(); | 446 UnimplementedInstruction(); |
| 447 return 1; | 447 return 1; |
| 448 } | 448 } |
| 449 UNREACHABLE(); | 449 UNREACHABLE(); |
| 450 } | 450 } |
| 451 | 451 |
| 452 | 452 |
| 453 int DisassemblerIA32::PrintRightOperand(byte* modrmp) { | 453 int DisassemblerX87::PrintRightOperand(byte* modrmp) { |
| 454 return PrintRightOperandHelper(modrmp, &DisassemblerIA32::NameOfCPURegister); | 454 return PrintRightOperandHelper(modrmp, &DisassemblerX87::NameOfCPURegister); |
| 455 } | 455 } |
| 456 | 456 |
| 457 | 457 |
| 458 int DisassemblerIA32::PrintRightByteOperand(byte* modrmp) { | 458 int DisassemblerX87::PrintRightByteOperand(byte* modrmp) { |
| 459 return PrintRightOperandHelper(modrmp, | 459 return PrintRightOperandHelper(modrmp, |
| 460 &DisassemblerIA32::NameOfByteCPURegister); | 460 &DisassemblerX87::NameOfByteCPURegister); |
| 461 } | 461 } |
| 462 | 462 |
| 463 | 463 |
| 464 int DisassemblerIA32::PrintRightXMMOperand(byte* modrmp) { | 464 int DisassemblerX87::PrintRightXMMOperand(byte* modrmp) { |
| 465 return PrintRightOperandHelper(modrmp, | 465 return PrintRightOperandHelper(modrmp, |
| 466 &DisassemblerIA32::NameOfXMMRegister); | 466 &DisassemblerX87::NameOfXMMRegister); |
| 467 } | 467 } |
| 468 | 468 |
| 469 | 469 |
| 470 // Returns number of bytes used including the current *data. | 470 // Returns number of bytes used including the current *data. |
| 471 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. | 471 // Writes instruction's mnemonic, left and right operands to 'tmp_buffer_'. |
| 472 int DisassemblerIA32::PrintOperands(const char* mnem, | 472 int DisassemblerX87::PrintOperands(const char* mnem, |
| 473 OperandOrder op_order, | 473 OperandOrder op_order, |
| 474 byte* data) { | 474 byte* data) { |
| 475 byte modrm = *data; | 475 byte modrm = *data; |
| 476 int mod, regop, rm; | 476 int mod, regop, rm; |
| 477 get_modrm(modrm, &mod, ®op, &rm); | 477 get_modrm(modrm, &mod, ®op, &rm); |
| 478 int advance = 0; | 478 int advance = 0; |
| 479 switch (op_order) { | 479 switch (op_order) { |
| 480 case REG_OPER_OP_ORDER: { | 480 case REG_OPER_OP_ORDER: { |
| 481 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop)); | 481 AppendToBuffer("%s %s,", mnem, NameOfCPURegister(regop)); |
| 482 advance = PrintRightOperand(data); | 482 advance = PrintRightOperand(data); |
| 483 break; | 483 break; |
| 484 } | 484 } |
| 485 case OPER_REG_OP_ORDER: { | 485 case OPER_REG_OP_ORDER: { |
| 486 AppendToBuffer("%s ", mnem); | 486 AppendToBuffer("%s ", mnem); |
| 487 advance = PrintRightOperand(data); | 487 advance = PrintRightOperand(data); |
| 488 AppendToBuffer(",%s", NameOfCPURegister(regop)); | 488 AppendToBuffer(",%s", NameOfCPURegister(regop)); |
| 489 break; | 489 break; |
| 490 } | 490 } |
| 491 default: | 491 default: |
| 492 UNREACHABLE(); | 492 UNREACHABLE(); |
| 493 break; | 493 break; |
| 494 } | 494 } |
| 495 return advance; | 495 return advance; |
| 496 } | 496 } |
| 497 | 497 |
| 498 | 498 |
| 499 // Returns number of bytes used by machine instruction, including *data byte. | 499 // Returns number of bytes used by machine instruction, including *data byte. |
| 500 // Writes immediate instructions to 'tmp_buffer_'. | 500 // Writes immediate instructions to 'tmp_buffer_'. |
| 501 int DisassemblerIA32::PrintImmediateOp(byte* data) { | 501 int DisassemblerX87::PrintImmediateOp(byte* data) { |
| 502 bool sign_extension_bit = (*data & 0x02) != 0; | 502 bool sign_extension_bit = (*data & 0x02) != 0; |
| 503 byte modrm = *(data+1); | 503 byte modrm = *(data+1); |
| 504 int mod, regop, rm; | 504 int mod, regop, rm; |
| 505 get_modrm(modrm, &mod, ®op, &rm); | 505 get_modrm(modrm, &mod, ®op, &rm); |
| 506 const char* mnem = "Imm???"; | 506 const char* mnem = "Imm???"; |
| 507 switch (regop) { | 507 switch (regop) { |
| 508 case 0: mnem = "add"; break; | 508 case 0: mnem = "add"; break; |
| 509 case 1: mnem = "or"; break; | 509 case 1: mnem = "or"; break; |
| 510 case 2: mnem = "adc"; break; | 510 case 2: mnem = "adc"; break; |
| 511 case 4: mnem = "and"; break; | 511 case 4: mnem = "and"; break; |
| 512 case 5: mnem = "sub"; break; | 512 case 5: mnem = "sub"; break; |
| 513 case 6: mnem = "xor"; break; | 513 case 6: mnem = "xor"; break; |
| 514 case 7: mnem = "cmp"; break; | 514 case 7: mnem = "cmp"; break; |
| 515 default: UnimplementedInstruction(); | 515 default: UnimplementedInstruction(); |
| 516 } | 516 } |
| 517 AppendToBuffer("%s ", mnem); | 517 AppendToBuffer("%s ", mnem); |
| 518 int count = PrintRightOperand(data+1); | 518 int count = PrintRightOperand(data+1); |
| 519 if (sign_extension_bit) { | 519 if (sign_extension_bit) { |
| 520 AppendToBuffer(",0x%x", *(data + 1 + count)); | 520 AppendToBuffer(",0x%x", *(data + 1 + count)); |
| 521 return 1 + count + 1 /*int8*/; | 521 return 1 + count + 1 /*int8*/; |
| 522 } else { | 522 } else { |
| 523 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count)); | 523 AppendToBuffer(",0x%x", *reinterpret_cast<int32_t*>(data + 1 + count)); |
| 524 return 1 + count + 4 /*int32_t*/; | 524 return 1 + count + 4 /*int32_t*/; |
| 525 } | 525 } |
| 526 } | 526 } |
| 527 | 527 |
| 528 | 528 |
| 529 // Returns number of bytes used, including *data. | 529 // Returns number of bytes used, including *data. |
| 530 int DisassemblerIA32::F7Instruction(byte* data) { | 530 int DisassemblerX87::F7Instruction(byte* data) { |
| 531 ASSERT_EQ(0xF7, *data); | 531 ASSERT_EQ(0xF7, *data); |
| 532 byte modrm = *(data+1); | 532 byte modrm = *(data+1); |
| 533 int mod, regop, rm; | 533 int mod, regop, rm; |
| 534 get_modrm(modrm, &mod, ®op, &rm); | 534 get_modrm(modrm, &mod, ®op, &rm); |
| 535 if (mod == 3 && regop != 0) { | 535 if (mod == 3 && regop != 0) { |
| 536 const char* mnem = NULL; | 536 const char* mnem = NULL; |
| 537 switch (regop) { | 537 switch (regop) { |
| 538 case 2: mnem = "not"; break; | 538 case 2: mnem = "not"; break; |
| 539 case 3: mnem = "neg"; break; | 539 case 3: mnem = "neg"; break; |
| 540 case 4: mnem = "mul"; break; | 540 case 4: mnem = "mul"; break; |
| (...skipping 13 matching lines...) Expand all Loading... |
| 554 int32_t imm = *reinterpret_cast<int32_t*>(data+1+count); | 554 int32_t imm = *reinterpret_cast<int32_t*>(data+1+count); |
| 555 AppendToBuffer(",0x%x", imm); | 555 AppendToBuffer(",0x%x", imm); |
| 556 return 1+count+4 /*int32_t*/; | 556 return 1+count+4 /*int32_t*/; |
| 557 } else { | 557 } else { |
| 558 UnimplementedInstruction(); | 558 UnimplementedInstruction(); |
| 559 return 2; | 559 return 2; |
| 560 } | 560 } |
| 561 } | 561 } |
| 562 | 562 |
| 563 | 563 |
| 564 int DisassemblerIA32::D1D3C1Instruction(byte* data) { | 564 int DisassemblerX87::D1D3C1Instruction(byte* data) { |
| 565 byte op = *data; | 565 byte op = *data; |
| 566 ASSERT(op == 0xD1 || op == 0xD3 || op == 0xC1); | 566 ASSERT(op == 0xD1 || op == 0xD3 || op == 0xC1); |
| 567 byte modrm = *(data+1); | 567 byte modrm = *(data+1); |
| 568 int mod, regop, rm; | 568 int mod, regop, rm; |
| 569 get_modrm(modrm, &mod, ®op, &rm); | 569 get_modrm(modrm, &mod, ®op, &rm); |
| 570 int imm8 = -1; | 570 int imm8 = -1; |
| 571 int num_bytes = 2; | 571 int num_bytes = 2; |
| 572 if (mod == 3) { | 572 if (mod == 3) { |
| 573 const char* mnem = NULL; | 573 const char* mnem = NULL; |
| 574 switch (regop) { | 574 switch (regop) { |
| (...skipping 22 matching lines...) Expand all Loading... |
| 597 AppendToBuffer("cl"); | 597 AppendToBuffer("cl"); |
| 598 } | 598 } |
| 599 } else { | 599 } else { |
| 600 UnimplementedInstruction(); | 600 UnimplementedInstruction(); |
| 601 } | 601 } |
| 602 return num_bytes; | 602 return num_bytes; |
| 603 } | 603 } |
| 604 | 604 |
| 605 | 605 |
| 606 // Returns number of bytes used, including *data. | 606 // Returns number of bytes used, including *data. |
| 607 int DisassemblerIA32::JumpShort(byte* data) { | 607 int DisassemblerX87::JumpShort(byte* data) { |
| 608 ASSERT_EQ(0xEB, *data); | 608 ASSERT_EQ(0xEB, *data); |
| 609 byte b = *(data+1); | 609 byte b = *(data+1); |
| 610 byte* dest = data + static_cast<int8_t>(b) + 2; | 610 byte* dest = data + static_cast<int8_t>(b) + 2; |
| 611 AppendToBuffer("jmp %s", NameOfAddress(dest)); | 611 AppendToBuffer("jmp %s", NameOfAddress(dest)); |
| 612 return 2; | 612 return 2; |
| 613 } | 613 } |
| 614 | 614 |
| 615 | 615 |
| 616 // Returns number of bytes used, including *data. | 616 // Returns number of bytes used, including *data. |
| 617 int DisassemblerIA32::JumpConditional(byte* data, const char* comment) { | 617 int DisassemblerX87::JumpConditional(byte* data, const char* comment) { |
| 618 ASSERT_EQ(0x0F, *data); | 618 ASSERT_EQ(0x0F, *data); |
| 619 byte cond = *(data+1) & 0x0F; | 619 byte cond = *(data+1) & 0x0F; |
| 620 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6; | 620 byte* dest = data + *reinterpret_cast<int32_t*>(data+2) + 6; |
| 621 const char* mnem = jump_conditional_mnem[cond]; | 621 const char* mnem = jump_conditional_mnem[cond]; |
| 622 AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); | 622 AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); |
| 623 if (comment != NULL) { | 623 if (comment != NULL) { |
| 624 AppendToBuffer(", %s", comment); | 624 AppendToBuffer(", %s", comment); |
| 625 } | 625 } |
| 626 return 6; // includes 0x0F | 626 return 6; // includes 0x0F |
| 627 } | 627 } |
| 628 | 628 |
| 629 | 629 |
| 630 // Returns number of bytes used, including *data. | 630 // Returns number of bytes used, including *data. |
| 631 int DisassemblerIA32::JumpConditionalShort(byte* data, const char* comment) { | 631 int DisassemblerX87::JumpConditionalShort(byte* data, const char* comment) { |
| 632 byte cond = *data & 0x0F; | 632 byte cond = *data & 0x0F; |
| 633 byte b = *(data+1); | 633 byte b = *(data+1); |
| 634 byte* dest = data + static_cast<int8_t>(b) + 2; | 634 byte* dest = data + static_cast<int8_t>(b) + 2; |
| 635 const char* mnem = jump_conditional_mnem[cond]; | 635 const char* mnem = jump_conditional_mnem[cond]; |
| 636 AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); | 636 AppendToBuffer("%s %s", mnem, NameOfAddress(dest)); |
| 637 if (comment != NULL) { | 637 if (comment != NULL) { |
| 638 AppendToBuffer(", %s", comment); | 638 AppendToBuffer(", %s", comment); |
| 639 } | 639 } |
| 640 return 2; | 640 return 2; |
| 641 } | 641 } |
| 642 | 642 |
| 643 | 643 |
| 644 // Returns number of bytes used, including *data. | 644 // Returns number of bytes used, including *data. |
| 645 int DisassemblerIA32::SetCC(byte* data) { | 645 int DisassemblerX87::SetCC(byte* data) { |
| 646 ASSERT_EQ(0x0F, *data); | 646 ASSERT_EQ(0x0F, *data); |
| 647 byte cond = *(data+1) & 0x0F; | 647 byte cond = *(data+1) & 0x0F; |
| 648 const char* mnem = set_conditional_mnem[cond]; | 648 const char* mnem = set_conditional_mnem[cond]; |
| 649 AppendToBuffer("%s ", mnem); | 649 AppendToBuffer("%s ", mnem); |
| 650 PrintRightByteOperand(data+2); | 650 PrintRightByteOperand(data+2); |
| 651 return 3; // Includes 0x0F. | 651 return 3; // Includes 0x0F. |
| 652 } | 652 } |
| 653 | 653 |
| 654 | 654 |
| 655 // Returns number of bytes used, including *data. | 655 // Returns number of bytes used, including *data. |
| 656 int DisassemblerIA32::CMov(byte* data) { | 656 int DisassemblerX87::CMov(byte* data) { |
| 657 ASSERT_EQ(0x0F, *data); | 657 ASSERT_EQ(0x0F, *data); |
| 658 byte cond = *(data + 1) & 0x0F; | 658 byte cond = *(data + 1) & 0x0F; |
| 659 const char* mnem = conditional_move_mnem[cond]; | 659 const char* mnem = conditional_move_mnem[cond]; |
| 660 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2); | 660 int op_size = PrintOperands(mnem, REG_OPER_OP_ORDER, data + 2); |
| 661 return 2 + op_size; // includes 0x0F | 661 return 2 + op_size; // includes 0x0F |
| 662 } | 662 } |
| 663 | 663 |
| 664 | 664 |
| 665 // Returns number of bytes used, including *data. | 665 // Returns number of bytes used, including *data. |
| 666 int DisassemblerIA32::FPUInstruction(byte* data) { | 666 int DisassemblerX87::FPUInstruction(byte* data) { |
| 667 byte escape_opcode = *data; | 667 byte escape_opcode = *data; |
| 668 ASSERT_EQ(0xD8, escape_opcode & 0xF8); | 668 ASSERT_EQ(0xD8, escape_opcode & 0xF8); |
| 669 byte modrm_byte = *(data+1); | 669 byte modrm_byte = *(data+1); |
| 670 | 670 |
| 671 if (modrm_byte >= 0xC0) { | 671 if (modrm_byte >= 0xC0) { |
| 672 return RegisterFPUInstruction(escape_opcode, modrm_byte); | 672 return RegisterFPUInstruction(escape_opcode, modrm_byte); |
| 673 } else { | 673 } else { |
| 674 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1); | 674 return MemoryFPUInstruction(escape_opcode, modrm_byte, data+1); |
| 675 } | 675 } |
| 676 } | 676 } |
| 677 | 677 |
| 678 int DisassemblerIA32::MemoryFPUInstruction(int escape_opcode, | 678 int DisassemblerX87::MemoryFPUInstruction(int escape_opcode, |
| 679 int modrm_byte, | 679 int modrm_byte, |
| 680 byte* modrm_start) { | 680 byte* modrm_start) { |
| 681 const char* mnem = "?"; | 681 const char* mnem = "?"; |
| 682 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte. | 682 int regop = (modrm_byte >> 3) & 0x7; // reg/op field of modrm byte. |
| 683 switch (escape_opcode) { | 683 switch (escape_opcode) { |
| 684 case 0xD9: switch (regop) { | 684 case 0xD9: switch (regop) { |
| 685 case 0: mnem = "fld_s"; break; | 685 case 0: mnem = "fld_s"; break; |
| 686 case 2: mnem = "fst_s"; break; | 686 case 2: mnem = "fst_s"; break; |
| 687 case 3: mnem = "fstp_s"; break; | 687 case 3: mnem = "fstp_s"; break; |
| 688 case 7: mnem = "fstcw"; break; | 688 case 7: mnem = "fstcw"; break; |
| (...skipping 26 matching lines...) Expand all Loading... |
| 715 } | 715 } |
| 716 break; | 716 break; |
| 717 | 717 |
| 718 default: UnimplementedInstruction(); | 718 default: UnimplementedInstruction(); |
| 719 } | 719 } |
| 720 AppendToBuffer("%s ", mnem); | 720 AppendToBuffer("%s ", mnem); |
| 721 int count = PrintRightOperand(modrm_start); | 721 int count = PrintRightOperand(modrm_start); |
| 722 return count + 1; | 722 return count + 1; |
| 723 } | 723 } |
| 724 | 724 |
| 725 int DisassemblerIA32::RegisterFPUInstruction(int escape_opcode, | 725 int DisassemblerX87::RegisterFPUInstruction(int escape_opcode, |
| 726 byte modrm_byte) { | 726 byte modrm_byte) { |
| 727 bool has_register = false; // Is the FPU register encoded in modrm_byte? | 727 bool has_register = false; // Is the FPU register encoded in modrm_byte? |
| 728 const char* mnem = "?"; | 728 const char* mnem = "?"; |
| 729 | 729 |
| 730 switch (escape_opcode) { | 730 switch (escape_opcode) { |
| 731 case 0xD8: | 731 case 0xD8: |
| 732 has_register = true; | 732 has_register = true; |
| 733 switch (modrm_byte & 0xF8) { | 733 switch (modrm_byte & 0xF8) { |
| 734 case 0xC0: mnem = "fadd_i"; break; | 734 case 0xC0: mnem = "fadd_i"; break; |
| 735 case 0xE0: mnem = "fsub_i"; break; | 735 case 0xE0: mnem = "fsub_i"; break; |
| (...skipping 130 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 866 case 0xAD: return "shrd"; | 866 case 0xAD: return "shrd"; |
| 867 case 0xAC: return "shrd"; // 3-operand version. | 867 case 0xAC: return "shrd"; // 3-operand version. |
| 868 case 0xAB: return "bts"; | 868 case 0xAB: return "bts"; |
| 869 case 0xBD: return "bsr"; | 869 case 0xBD: return "bsr"; |
| 870 default: return NULL; | 870 default: return NULL; |
| 871 } | 871 } |
| 872 } | 872 } |
| 873 | 873 |
| 874 | 874 |
| 875 // Disassembled instruction '*instr' and writes it into 'out_buffer'. | 875 // Disassembled instruction '*instr' and writes it into 'out_buffer'. |
| 876 int DisassemblerIA32::InstructionDecode(v8::internal::Vector<char> out_buffer, | 876 int DisassemblerX87::InstructionDecode(v8::internal::Vector<char> out_buffer, |
| 877 byte* instr) { | 877 byte* instr) { |
| 878 tmp_buffer_pos_ = 0; // starting to write as position 0 | 878 tmp_buffer_pos_ = 0; // starting to write as position 0 |
| 879 byte* data = instr; | 879 byte* data = instr; |
| 880 // Check for hints. | 880 // Check for hints. |
| 881 const char* branch_hint = NULL; | 881 const char* branch_hint = NULL; |
| 882 // We use these two prefixes only with branch prediction | 882 // We use these two prefixes only with branch prediction |
| 883 if (*data == 0x3E /*ds*/) { | 883 if (*data == 0x3E /*ds*/) { |
| 884 branch_hint = "predicted taken"; | 884 branch_hint = "predicted taken"; |
| 885 data++; | 885 data++; |
| 886 } else if (*data == 0x2E /*cs*/) { | 886 } else if (*data == 0x2E /*cs*/) { |
| (...skipping 815 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1702 } | 1702 } |
| 1703 | 1703 |
| 1704 | 1704 |
| 1705 const char* NameConverter::NameOfXMMRegister(int reg) const { | 1705 const char* NameConverter::NameOfXMMRegister(int reg) const { |
| 1706 if (0 <= reg && reg < 8) return xmm_regs[reg]; | 1706 if (0 <= reg && reg < 8) return xmm_regs[reg]; |
| 1707 return "noxmmreg"; | 1707 return "noxmmreg"; |
| 1708 } | 1708 } |
| 1709 | 1709 |
| 1710 | 1710 |
| 1711 const char* NameConverter::NameInCode(byte* addr) const { | 1711 const char* NameConverter::NameInCode(byte* addr) const { |
| 1712 // IA32 does not embed debug strings at the moment. | 1712 // X87 does not embed debug strings at the moment. |
| 1713 UNREACHABLE(); | 1713 UNREACHABLE(); |
| 1714 return ""; | 1714 return ""; |
| 1715 } | 1715 } |
| 1716 | 1716 |
| 1717 | 1717 |
| 1718 //------------------------------------------------------------------------------ | 1718 //------------------------------------------------------------------------------ |
| 1719 | 1719 |
| 1720 Disassembler::Disassembler(const NameConverter& converter) | 1720 Disassembler::Disassembler(const NameConverter& converter) |
| 1721 : converter_(converter) {} | 1721 : converter_(converter) {} |
| 1722 | 1722 |
| 1723 | 1723 |
| 1724 Disassembler::~Disassembler() {} | 1724 Disassembler::~Disassembler() {} |
| 1725 | 1725 |
| 1726 | 1726 |
| 1727 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer, | 1727 int Disassembler::InstructionDecode(v8::internal::Vector<char> buffer, |
| 1728 byte* instruction) { | 1728 byte* instruction) { |
| 1729 DisassemblerIA32 d(converter_, false /*do not crash if unimplemented*/); | 1729 DisassemblerX87 d(converter_, false /*do not crash if unimplemented*/); |
| 1730 return d.InstructionDecode(buffer, instruction); | 1730 return d.InstructionDecode(buffer, instruction); |
| 1731 } | 1731 } |
| 1732 | 1732 |
| 1733 | 1733 |
| 1734 // The IA-32 assembler does not currently use constant pools. | 1734 // The IA-32 assembler does not currently use constant pools. |
| 1735 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; } | 1735 int Disassembler::ConstantPoolSizeAt(byte* instruction) { return -1; } |
| 1736 | 1736 |
| 1737 | 1737 |
| 1738 /*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) { | 1738 /*static*/ void Disassembler::Disassemble(FILE* f, byte* begin, byte* end) { |
| 1739 NameConverter converter; | 1739 NameConverter converter; |
| (...skipping 12 matching lines...) Expand all Loading... |
| 1752 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { | 1752 for (int i = 6 - (pc - prev_pc); i >= 0; i--) { |
| 1753 fprintf(f, " "); | 1753 fprintf(f, " "); |
| 1754 } | 1754 } |
| 1755 fprintf(f, " %s\n", buffer.start()); | 1755 fprintf(f, " %s\n", buffer.start()); |
| 1756 } | 1756 } |
| 1757 } | 1757 } |
| 1758 | 1758 |
| 1759 | 1759 |
| 1760 } // namespace disasm | 1760 } // namespace disasm |
| 1761 | 1761 |
| 1762 #endif // V8_TARGET_ARCH_IA32 | 1762 #endif // V8_TARGET_ARCH_X87 |
| OLD | NEW |