| OLD | NEW |
| 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
| 3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 #include "vm/disassembler.h" | 5 #include "vm/disassembler.h" |
| 6 | 6 |
| 7 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. | 7 #include "vm/globals.h" // Needed here to get TARGET_ARCH_IA32. |
| 8 #if defined(TARGET_ARCH_X64) | 8 #if defined(TARGET_ARCH_X64) |
| 9 #include "platform/utils.h" | 9 #include "platform/utils.h" |
| 10 #include "vm/allocation.h" | 10 #include "vm/allocation.h" |
| (...skipping 356 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 367 | 367 |
| 368 const char* NameOfByteCPURegister(int reg) const { | 368 const char* NameOfByteCPURegister(int reg) const { |
| 369 return NameOfCPURegister(reg); | 369 return NameOfCPURegister(reg); |
| 370 } | 370 } |
| 371 | 371 |
| 372 const char* NameOfXMMRegister(int reg) const { | 372 const char* NameOfXMMRegister(int reg) const { |
| 373 ASSERT((0 <= reg) && (reg < kMaxXmmRegisters)); | 373 ASSERT((0 <= reg) && (reg < kMaxXmmRegisters)); |
| 374 return xmm_regs[reg]; | 374 return xmm_regs[reg]; |
| 375 } | 375 } |
| 376 | 376 |
| 377 void AppendToBuffer(const char* format, ...) PRINTF_ATTRIBUTE(2, 3); | 377 void Print(const char* format, ...) PRINTF_ATTRIBUTE(2, 3); |
| 378 void AppendAddressToBuffer(uint8_t* addr); | 378 void PrintAddress(uint8_t* addr); |
| 379 | 379 |
| 380 int PrintOperands(const char* mnem, | 380 int PrintOperands(const char* mnem, |
| 381 OperandType op_order, | 381 OperandType op_order, |
| 382 uint8_t* data); | 382 uint8_t* data); |
| 383 | 383 |
| 384 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const; | 384 typedef const char* (DisassemblerX64::*RegisterNameMapping)(int reg) const; |
| 385 | 385 |
| 386 int PrintRightOperandHelper(uint8_t* modrmp, | 386 int PrintRightOperandHelper(uint8_t* modrmp, |
| 387 RegisterNameMapping register_name); | 387 RegisterNameMapping register_name); |
| 388 int PrintRightOperand(uint8_t* modrmp); | 388 int PrintRightOperand(uint8_t* modrmp); |
| 389 int PrintRightByteOperand(uint8_t* modrmp); | 389 int PrintRightByteOperand(uint8_t* modrmp); |
| 390 int PrintRightXMMOperand(uint8_t* modrmp); | 390 int PrintRightXMMOperand(uint8_t* modrmp); |
| 391 void PrintDisp(int disp, const char* after); |
| 391 int PrintImmediate(uint8_t* data, OperandSize size); | 392 int PrintImmediate(uint8_t* data, OperandSize size); |
| 393 void PrintImmediateValue(int64_t value); |
| 392 int PrintImmediateOp(uint8_t* data); | 394 int PrintImmediateOp(uint8_t* data); |
| 393 const char* TwoByteMnemonic(uint8_t opcode); | 395 const char* TwoByteMnemonic(uint8_t opcode); |
| 394 int TwoByteOpcodeInstruction(uint8_t* data); | 396 int TwoByteOpcodeInstruction(uint8_t* data); |
| 395 | 397 |
| 396 int F6F7Instruction(uint8_t* data); | 398 int F6F7Instruction(uint8_t* data); |
| 397 int ShiftInstruction(uint8_t* data); | 399 int ShiftInstruction(uint8_t* data); |
| 398 int JumpShort(uint8_t* data); | 400 int JumpShort(uint8_t* data); |
| 399 int JumpConditional(uint8_t* data); | 401 int JumpConditional(uint8_t* data); |
| 400 int JumpConditionalShort(uint8_t* data); | 402 int JumpConditionalShort(uint8_t* data); |
| 401 int SetCC(uint8_t* data); | 403 int SetCC(uint8_t* data); |
| 402 int FPUInstruction(uint8_t* data); | 404 int FPUInstruction(uint8_t* data); |
| 403 int MemoryFPUInstruction(int escape_opcode, int regop, uint8_t* modrm_start); | 405 int MemoryFPUInstruction(int escape_opcode, int regop, uint8_t* modrm_start); |
| 404 int RegisterFPUInstruction(int escape_opcode, uint8_t modrm_byte); | 406 int RegisterFPUInstruction(int escape_opcode, uint8_t modrm_byte); |
| 405 | 407 |
| 406 bool DecodeInstructionType(uint8_t** data); | 408 bool DecodeInstructionType(uint8_t** data); |
| 407 | 409 |
| 408 void UnimplementedInstruction() { | 410 void UnimplementedInstruction() { |
| 409 AppendToBuffer("'Unimplemented Instruction'"); | 411 Print("'Unimplemented Instruction'"); |
| 410 } | 412 } |
| 411 | 413 |
| 412 char* buffer_; // Decode instructions into this buffer. | 414 char* buffer_; // Decode instructions into this buffer. |
| 413 intptr_t buffer_size_; // The size of the buffer_. | 415 intptr_t buffer_size_; // The size of the buffer_. |
| 414 intptr_t buffer_pos_; // Current character position in the buffer_. | 416 intptr_t buffer_pos_; // Current character position in the buffer_. |
| 415 | 417 |
| 416 // Prefixes parsed | 418 // Prefixes parsed |
| 417 uint8_t rex_; | 419 uint8_t rex_; |
| 418 uint8_t operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0. | 420 uint8_t operand_size_; // 0x66 or (if no group 3 prefix is present) 0x0. |
| 419 // 0xF2, 0xF3, or (if no group 1 prefix is present) 0. | 421 // 0xF2, 0xF3, or (if no group 1 prefix is present) 0. |
| 420 uint8_t group_1_prefix_; | 422 uint8_t group_1_prefix_; |
| 421 // Byte size operand override. | 423 // Byte size operand override. |
| 422 bool byte_size_operand_; | 424 bool byte_size_operand_; |
| 423 | 425 |
| 424 DISALLOW_COPY_AND_ASSIGN(DisassemblerX64); | 426 DISALLOW_COPY_AND_ASSIGN(DisassemblerX64); |
| 425 }; | 427 }; |
| 426 | 428 |
| 427 | 429 |
| 428 // Append the str to the output buffer. | 430 // Append the str to the output buffer. |
| 429 void DisassemblerX64::AppendToBuffer(const char* format, ...) { | 431 void DisassemblerX64::Print(const char* format, ...) { |
| 430 intptr_t available = buffer_size_ - buffer_pos_; | 432 intptr_t available = buffer_size_ - buffer_pos_; |
| 431 if (available <= 1) { | 433 if (available <= 1) { |
| 432 ASSERT(buffer_[buffer_pos_] == '\0'); | 434 ASSERT(buffer_[buffer_pos_] == '\0'); |
| 433 return; | 435 return; |
| 434 } | 436 } |
| 435 char* buf = buffer_ + buffer_pos_; | 437 char* buf = buffer_ + buffer_pos_; |
| 436 va_list args; | 438 va_list args; |
| 437 va_start(args, format); | 439 va_start(args, format); |
| 438 int length = OS::VSNPrint(buf, available, format, args); | 440 int length = OS::VSNPrint(buf, available, format, args); |
| 439 va_end(args); | 441 va_end(args); |
| 440 buffer_pos_ = | 442 buffer_pos_ = |
| 441 (length >= available) ? (buffer_size_ - 1) : (buffer_pos_ + length); | 443 (length >= available) ? (buffer_size_ - 1) : (buffer_pos_ + length); |
| 442 ASSERT(buffer_pos_ < buffer_size_); | 444 ASSERT(buffer_pos_ < buffer_size_); |
| 443 } | 445 } |
| 444 | 446 |
| 445 | 447 |
| 446 int DisassemblerX64::PrintRightOperandHelper( | 448 int DisassemblerX64::PrintRightOperandHelper( |
| 447 uint8_t* modrmp, | 449 uint8_t* modrmp, |
| 448 RegisterNameMapping direct_register_name) { | 450 RegisterNameMapping direct_register_name) { |
| 449 int mod, regop, rm; | 451 int mod, regop, rm; |
| 450 get_modrm(*modrmp, &mod, ®op, &rm); | 452 get_modrm(*modrmp, &mod, ®op, &rm); |
| 451 RegisterNameMapping register_name = (mod == 3) ? direct_register_name : | 453 RegisterNameMapping register_name = (mod == 3) ? direct_register_name : |
| 452 &DisassemblerX64::NameOfCPURegister; | 454 &DisassemblerX64::NameOfCPURegister; |
| 453 switch (mod) { | 455 switch (mod) { |
| 454 case 0: | 456 case 0: |
| 455 if ((rm & 7) == 5) { | 457 if ((rm & 7) == 5) { |
| 456 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1); | 458 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 1); |
| 457 AppendToBuffer("[rip%s%#x]", disp < 0 ? "-" : "+", Utils::Abs(disp)); | 459 Print("[rip"); |
| 460 PrintDisp(disp, "]"); |
| 458 return 5; | 461 return 5; |
| 459 } else if ((rm & 7) == 4) { | 462 } else if ((rm & 7) == 4) { |
| 460 // Codes for SIB byte. | 463 // Codes for SIB byte. |
| 461 uint8_t sib = *(modrmp + 1); | 464 uint8_t sib = *(modrmp + 1); |
| 462 int scale, index, base; | 465 int scale, index, base; |
| 463 get_sib(sib, &scale, &index, &base); | 466 get_sib(sib, &scale, &index, &base); |
| 464 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) { | 467 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) { |
| 465 // index == rsp means no index. Only use sib byte with no index for | 468 // index == rsp means no index. Only use sib byte with no index for |
| 466 // rsp and r12 base. | 469 // rsp and r12 base. |
| 467 AppendToBuffer("[%s]", NameOfCPURegister(base)); | 470 Print("[%s]", NameOfCPURegister(base)); |
| 468 return 2; | 471 return 2; |
| 469 } else if (base == 5) { | 472 } else if (base == 5) { |
| 470 // base == rbp means no base register (when mod == 0). | 473 // base == rbp means no base register (when mod == 0). |
| 471 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2); | 474 int32_t disp = *reinterpret_cast<int32_t*>(modrmp + 2); |
| 472 AppendToBuffer("[%s*%d+%#x]", | 475 Print("[%s*%d", NameOfCPURegister(index), 1 << scale); |
| 473 NameOfCPURegister(index), | 476 PrintDisp(disp, "]"); |
| 474 1 << scale, disp); | |
| 475 return 6; | 477 return 6; |
| 476 } else if (index != 4 && base != 5) { | 478 } else if (index != 4 && base != 5) { |
| 477 // [base+index*scale] | 479 // [base+index*scale] |
| 478 AppendToBuffer("[%s+%s*%d]", | 480 Print("[%s+%s*%d]", |
| 479 NameOfCPURegister(base), | 481 NameOfCPURegister(base), |
| 480 NameOfCPURegister(index), | 482 NameOfCPURegister(index), |
| 481 1 << scale); | 483 1 << scale); |
| 482 return 2; | 484 return 2; |
| 483 } else { | 485 } else { |
| 484 UnimplementedInstruction(); | 486 UnimplementedInstruction(); |
| 485 return 1; | 487 return 1; |
| 486 } | 488 } |
| 487 } else { | 489 } else { |
| 488 AppendToBuffer("[%s]", NameOfCPURegister(rm)); | 490 Print("[%s]", NameOfCPURegister(rm)); |
| 489 return 1; | 491 return 1; |
| 490 } | 492 } |
| 491 break; | 493 break; |
| 492 case 1: // fall through | 494 case 1: // fall through |
| 493 case 2: | 495 case 2: |
| 494 if ((rm & 7) == 4) { | 496 if ((rm & 7) == 4) { |
| 495 uint8_t sib = *(modrmp + 1); | 497 uint8_t sib = *(modrmp + 1); |
| 496 int scale, index, base; | 498 int scale, index, base; |
| 497 get_sib(sib, &scale, &index, &base); | 499 get_sib(sib, &scale, &index, &base); |
| 498 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2) | 500 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 2) |
| 499 : *reinterpret_cast<char*>(modrmp + 2); | 501 : *reinterpret_cast<char*>(modrmp + 2); |
| 500 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) { | 502 if (index == 4 && (base & 7) == 4 && scale == 0 /*times_1*/) { |
| 501 if (-disp > 0) { | 503 Print("[%s", NameOfCPURegister(base)); |
| 502 AppendToBuffer("[%s-%#x]", NameOfCPURegister(base), -disp); | 504 PrintDisp(disp, "]"); |
| 503 } else { | |
| 504 AppendToBuffer("[%s+%#x]", NameOfCPURegister(base), disp); | |
| 505 } | |
| 506 } else { | 505 } else { |
| 507 if (-disp > 0) { | 506 Print("[%s+%s*%d", |
| 508 AppendToBuffer("[%s+%s*%d-%#x]", | 507 NameOfCPURegister(base), |
| 509 NameOfCPURegister(base), | 508 NameOfCPURegister(index), |
| 510 NameOfCPURegister(index), | 509 1 << scale); |
| 511 1 << scale, | 510 PrintDisp(disp, "]"); |
| 512 -disp); | |
| 513 } else { | |
| 514 AppendToBuffer("[%s+%s*%d+%#x]", | |
| 515 NameOfCPURegister(base), | |
| 516 NameOfCPURegister(index), | |
| 517 1 << scale, | |
| 518 disp); | |
| 519 } | |
| 520 } | 511 } |
| 521 return mod == 2 ? 6 : 3; | 512 return mod == 2 ? 6 : 3; |
| 522 } else { | 513 } else { |
| 523 // No sib. | 514 // No sib. |
| 524 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1) | 515 int disp = (mod == 2) ? *reinterpret_cast<int32_t*>(modrmp + 1) |
| 525 : *reinterpret_cast<char*>(modrmp + 1); | 516 : *reinterpret_cast<char*>(modrmp + 1); |
| 526 if (-disp > 0) { | 517 Print("[%s", NameOfCPURegister(rm)); |
| 527 AppendToBuffer("[%s-%#x]", NameOfCPURegister(rm), -disp); | 518 PrintDisp(disp, "]"); |
| 528 } else { | |
| 529 AppendToBuffer("[%s+%#x]", NameOfCPURegister(rm), disp); | |
| 530 } | |
| 531 return (mod == 2) ? 5 : 2; | 519 return (mod == 2) ? 5 : 2; |
| 532 } | 520 } |
| 533 break; | 521 break; |
| 534 case 3: | 522 case 3: |
| 535 AppendToBuffer("%s", (this->*register_name)(rm)); | 523 Print("%s", (this->*register_name)(rm)); |
| 536 return 1; | 524 return 1; |
| 537 default: | 525 default: |
| 538 UnimplementedInstruction(); | 526 UnimplementedInstruction(); |
| 539 return 1; | 527 return 1; |
| 540 } | 528 } |
| 541 UNREACHABLE(); | 529 UNREACHABLE(); |
| 542 } | 530 } |
| 543 | 531 |
| 544 | 532 |
| 545 int DisassemblerX64::PrintImmediate(uint8_t* data, OperandSize size) { | 533 int DisassemblerX64::PrintImmediate(uint8_t* data, OperandSize size) { |
| (...skipping 14 matching lines...) Expand all Loading... |
| 560 break; | 548 break; |
| 561 case QUADWORD_SIZE: | 549 case QUADWORD_SIZE: |
| 562 value = *reinterpret_cast<int32_t*>(data); | 550 value = *reinterpret_cast<int32_t*>(data); |
| 563 count = 4; | 551 count = 4; |
| 564 break; | 552 break; |
| 565 default: | 553 default: |
| 566 UNREACHABLE(); | 554 UNREACHABLE(); |
| 567 value = 0; // Initialize variables on all paths to satisfy the compiler. | 555 value = 0; // Initialize variables on all paths to satisfy the compiler. |
| 568 count = 0; | 556 count = 0; |
| 569 } | 557 } |
| 570 AppendToBuffer("%#" Px64 "", value); | 558 PrintImmediateValue(value); |
| 571 return count; | 559 return count; |
| 572 } | 560 } |
| 573 | 561 |
| 562 void DisassemblerX64::PrintImmediateValue(int64_t value) { |
| 563 if ((value >= 0) && (value <= 9)) { |
| 564 Print("%" Pd64 "", value); |
| 565 } else { |
| 566 Print("%#" Px64 "", value); |
| 567 } |
| 568 } |
| 569 |
| 570 void DisassemblerX64::PrintDisp(int disp, const char* after) { |
| 571 if (-disp > 0) { |
| 572 Print("-%#x", -disp); |
| 573 } else { |
| 574 Print("+%#x", disp); |
| 575 } |
| 576 if (after != NULL) Print("%s", after); |
| 577 } |
| 578 |
| 579 |
| 580 |
| 574 | 581 |
| 575 // Returns number of bytes used by machine instruction, including *data byte. | 582 // Returns number of bytes used by machine instruction, including *data byte. |
| 576 // Writes immediate instructions to 'tmp_buffer_'. | 583 // Writes immediate instructions to 'tmp_buffer_'. |
| 577 int DisassemblerX64::PrintImmediateOp(uint8_t* data) { | 584 int DisassemblerX64::PrintImmediateOp(uint8_t* data) { |
| 578 bool byte_size_immediate = (*data & 0x02) != 0; | 585 bool byte_size_immediate = (*data & 0x02) != 0; |
| 579 uint8_t modrm = *(data + 1); | 586 uint8_t modrm = *(data + 1); |
| 580 int mod, regop, rm; | 587 int mod, regop, rm; |
| 581 get_modrm(modrm, &mod, ®op, &rm); | 588 get_modrm(modrm, &mod, ®op, &rm); |
| 582 const char* mnem = "Imm???"; | 589 const char* mnem = "Imm???"; |
| 583 switch (regop) { | 590 switch (regop) { |
| (...skipping 17 matching lines...) Expand all Loading... |
| 601 break; | 608 break; |
| 602 case 6: | 609 case 6: |
| 603 mnem = "xor"; | 610 mnem = "xor"; |
| 604 break; | 611 break; |
| 605 case 7: | 612 case 7: |
| 606 mnem = "cmp"; | 613 mnem = "cmp"; |
| 607 break; | 614 break; |
| 608 default: | 615 default: |
| 609 UnimplementedInstruction(); | 616 UnimplementedInstruction(); |
| 610 } | 617 } |
| 611 AppendToBuffer("%s%c ", mnem, operand_size_code()); | 618 Print("%s%c ", mnem, operand_size_code()); |
| 612 int count = PrintRightOperand(data + 1); | 619 int count = PrintRightOperand(data + 1); |
| 613 AppendToBuffer(","); | 620 Print(","); |
| 614 OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size(); | 621 OperandSize immediate_size = byte_size_immediate ? BYTE_SIZE : operand_size(); |
| 615 count += PrintImmediate(data + 1 + count, immediate_size); | 622 count += PrintImmediate(data + 1 + count, immediate_size); |
| 616 return 1 + count; | 623 return 1 + count; |
| 617 } | 624 } |
| 618 | 625 |
| 619 | 626 |
| 620 // Returns number of bytes used, including *data. | 627 // Returns number of bytes used, including *data. |
| 621 int DisassemblerX64::F6F7Instruction(uint8_t* data) { | 628 int DisassemblerX64::F6F7Instruction(uint8_t* data) { |
| 622 ASSERT(*data == 0xF7 || *data == 0xF6); | 629 ASSERT(*data == 0xF7 || *data == 0xF6); |
| 623 uint8_t modrm = *(data + 1); | 630 uint8_t modrm = *(data + 1); |
| (...skipping 13 matching lines...) Expand all Loading... |
| 637 break; | 644 break; |
| 638 case 6: | 645 case 6: |
| 639 mnem = "div"; | 646 mnem = "div"; |
| 640 break; | 647 break; |
| 641 case 7: | 648 case 7: |
| 642 mnem = "idiv"; | 649 mnem = "idiv"; |
| 643 break; | 650 break; |
| 644 default: | 651 default: |
| 645 UnimplementedInstruction(); | 652 UnimplementedInstruction(); |
| 646 } | 653 } |
| 647 AppendToBuffer("%s%c %s", | 654 Print("%s%c %s", |
| 648 mnem, | 655 mnem, |
| 649 operand_size_code(), | 656 operand_size_code(), |
| 650 NameOfCPURegister(rm)); | 657 NameOfCPURegister(rm)); |
| 651 return 2; | 658 return 2; |
| 652 } else if (regop == 0) { | 659 } else if (regop == 0) { |
| 653 AppendToBuffer("test%c ", operand_size_code()); | 660 Print("test%c ", operand_size_code()); |
| 654 int count = PrintRightOperand(data + 1); // Use name of 64-bit register. | 661 int count = PrintRightOperand(data + 1); // Use name of 64-bit register. |
| 655 AppendToBuffer(",0x"); | 662 Print(","); |
| 656 count += PrintImmediate(data + 1 + count, operand_size()); | 663 count += PrintImmediate(data + 1 + count, operand_size()); |
| 657 return 1 + count; | 664 return 1 + count; |
| 658 } else { | 665 } else { |
| 659 UnimplementedInstruction(); | 666 UnimplementedInstruction(); |
| 660 return 2; | 667 return 2; |
| 661 } | 668 } |
| 662 } | 669 } |
| 663 | 670 |
| 664 | 671 |
| 665 int DisassemblerX64::ShiftInstruction(uint8_t* data) { | 672 int DisassemblerX64::ShiftInstruction(uint8_t* data) { |
| (...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 705 UnimplementedInstruction(); | 712 UnimplementedInstruction(); |
| 706 return num_bytes; | 713 return num_bytes; |
| 707 } | 714 } |
| 708 ASSERT(NULL != mnem); | 715 ASSERT(NULL != mnem); |
| 709 if (op == 0xD0) { | 716 if (op == 0xD0) { |
| 710 imm8 = 1; | 717 imm8 = 1; |
| 711 } else if (op == 0xC0) { | 718 } else if (op == 0xC0) { |
| 712 imm8 = *(data + 2); | 719 imm8 = *(data + 2); |
| 713 num_bytes = 3; | 720 num_bytes = 3; |
| 714 } | 721 } |
| 715 AppendToBuffer("%s%c %s,", | 722 Print("%s%c %s,", |
| 716 mnem, | 723 mnem, |
| 717 operand_size_code(), | 724 operand_size_code(), |
| 718 byte_size_operand_ ? NameOfByteCPURegister(rm) | 725 byte_size_operand_ ? NameOfByteCPURegister(rm) |
| 719 : NameOfCPURegister(rm)); | 726 : NameOfCPURegister(rm)); |
| 720 if (op == 0xD2) { | 727 if (op == 0xD2) { |
| 721 AppendToBuffer("cl"); | 728 Print("cl"); |
| 722 } else { | 729 } else { |
| 723 AppendToBuffer("%d", imm8); | 730 Print("%d", imm8); |
| 724 } | 731 } |
| 725 return num_bytes; | 732 return num_bytes; |
| 726 } | 733 } |
| 727 | 734 |
| 728 | 735 |
| 729 int DisassemblerX64::PrintRightOperand(uint8_t* modrmp) { | 736 int DisassemblerX64::PrintRightOperand(uint8_t* modrmp) { |
| 730 return PrintRightOperandHelper(modrmp, | 737 return PrintRightOperandHelper(modrmp, |
| 731 &DisassemblerX64::NameOfCPURegister); | 738 &DisassemblerX64::NameOfCPURegister); |
| 732 } | 739 } |
| 733 | 740 |
| (...skipping 17 matching lines...) Expand all Loading... |
| 751 uint8_t* data) { | 758 uint8_t* data) { |
| 752 uint8_t modrm = *data; | 759 uint8_t modrm = *data; |
| 753 int mod, regop, rm; | 760 int mod, regop, rm; |
| 754 get_modrm(modrm, &mod, ®op, &rm); | 761 get_modrm(modrm, &mod, ®op, &rm); |
| 755 int advance = 0; | 762 int advance = 0; |
| 756 const char* register_name = | 763 const char* register_name = |
| 757 byte_size_operand_ ? NameOfByteCPURegister(regop) | 764 byte_size_operand_ ? NameOfByteCPURegister(regop) |
| 758 : NameOfCPURegister(regop); | 765 : NameOfCPURegister(regop); |
| 759 switch (op_order) { | 766 switch (op_order) { |
| 760 case REG_OPER_OP_ORDER: { | 767 case REG_OPER_OP_ORDER: { |
| 761 AppendToBuffer("%s%c %s,", | 768 Print("%s%c %s,", mnem, operand_size_code(), register_name); |
| 762 mnem, | |
| 763 operand_size_code(), | |
| 764 register_name); | |
| 765 advance = byte_size_operand_ ? PrintRightByteOperand(data) | 769 advance = byte_size_operand_ ? PrintRightByteOperand(data) |
| 766 : PrintRightOperand(data); | 770 : PrintRightOperand(data); |
| 767 break; | 771 break; |
| 768 } | 772 } |
| 769 case OPER_REG_OP_ORDER: { | 773 case OPER_REG_OP_ORDER: { |
| 770 AppendToBuffer("%s%c ", mnem, operand_size_code()); | 774 Print("%s%c ", mnem, operand_size_code()); |
| 771 advance = byte_size_operand_ ? PrintRightByteOperand(data) | 775 advance = byte_size_operand_ ? PrintRightByteOperand(data) |
| 772 : PrintRightOperand(data); | 776 : PrintRightOperand(data); |
| 773 AppendToBuffer(",%s", register_name); | 777 Print(",%s", register_name); |
| 774 break; | 778 break; |
| 775 } | 779 } |
| 776 default: | 780 default: |
| 777 UNREACHABLE(); | 781 UNREACHABLE(); |
| 778 break; | 782 break; |
| 779 } | 783 } |
| 780 return advance; | 784 return advance; |
| 781 } | 785 } |
| 782 | 786 |
| 783 | 787 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 796 return obj.ToCString(); | 800 return obj.ToCString(); |
| 797 } | 801 } |
| 798 | 802 |
| 799 const Class& clazz = Class::Handle(obj.clazz()); | 803 const Class& clazz = Class::Handle(obj.clazz()); |
| 800 const char* full_class_name = clazz.ToCString(); | 804 const char* full_class_name = clazz.ToCString(); |
| 801 return OS::SCreate(Thread::Current()->zone(), | 805 return OS::SCreate(Thread::Current()->zone(), |
| 802 "instance of %s", full_class_name); | 806 "instance of %s", full_class_name); |
| 803 } | 807 } |
| 804 | 808 |
| 805 | 809 |
| 806 void DisassemblerX64::AppendAddressToBuffer(uint8_t* addr_byte_ptr) { | 810 void DisassemblerX64::PrintAddress(uint8_t* addr_byte_ptr) { |
| 807 uword addr = reinterpret_cast<uword>(addr_byte_ptr); | 811 uword addr = reinterpret_cast<uword>(addr_byte_ptr); |
| 808 AppendToBuffer("%#" Px "", addr); | 812 Print("%#" Px "", addr); |
| 809 // Try to print as heap object or stub name | 813 // Try to print as heap object or stub name |
| 810 if (((addr & kSmiTagMask) == kHeapObjectTag) && | 814 if (((addr & kSmiTagMask) == kHeapObjectTag) && |
| 811 reinterpret_cast<RawObject*>(addr)->IsWellFormed() && | 815 reinterpret_cast<RawObject*>(addr)->IsWellFormed() && |
| 812 reinterpret_cast<RawObject*>(addr)->IsOldObject() && | 816 reinterpret_cast<RawObject*>(addr)->IsOldObject() && |
| 813 !Dart::vm_isolate()->heap()->CodeContains(addr) && | 817 !Dart::vm_isolate()->heap()->CodeContains(addr) && |
| 814 !Isolate::Current()->heap()->CodeContains(addr) && | 818 !Isolate::Current()->heap()->CodeContains(addr) && |
| 815 Disassembler::CanFindOldObject(addr)) { | 819 Disassembler::CanFindOldObject(addr)) { |
| 816 NoSafepointScope no_safepoint; | 820 NoSafepointScope no_safepoint; |
| 817 const Object& obj = Object::Handle(reinterpret_cast<RawObject*>(addr)); | 821 const Object& obj = Object::Handle(reinterpret_cast<RawObject*>(addr)); |
| 818 if (obj.IsArray()) { | 822 if (obj.IsArray()) { |
| 819 const Array& arr = Array::Cast(obj); | 823 const Array& arr = Array::Cast(obj); |
| 820 intptr_t len = arr.Length(); | 824 intptr_t len = arr.Length(); |
| 821 if (len > 5) len = 5; // Print a max of 5 elements. | 825 if (len > 5) len = 5; // Print a max of 5 elements. |
| 822 AppendToBuffer(" Array["); | 826 Print(" Array["); |
| 823 int i = 0; | 827 int i = 0; |
| 824 Object& element = Object::Handle(); | 828 Object& element = Object::Handle(); |
| 825 while (i < len) { | 829 while (i < len) { |
| 826 element = arr.At(i); | 830 element = arr.At(i); |
| 827 if (i > 0) AppendToBuffer(", "); | 831 if (i > 0) Print(", "); |
| 828 AppendToBuffer("%s", ObjectToCStringNoGC(element)); | 832 Print("%s", ObjectToCStringNoGC(element)); |
| 829 i++; | 833 i++; |
| 830 } | 834 } |
| 831 if (i < arr.Length()) AppendToBuffer(", ..."); | 835 if (i < arr.Length()) Print(", ..."); |
| 832 AppendToBuffer("]"); | 836 Print("]"); |
| 833 return; | 837 return; |
| 834 } | 838 } |
| 835 AppendToBuffer(" '%s'", ObjectToCStringNoGC(obj)); | 839 Print(" '%s'", ObjectToCStringNoGC(obj)); |
| 836 } else { | 840 } else { |
| 837 // 'addr' is not an object, but probably a code address. | 841 // 'addr' is not an object, but probably a code address. |
| 838 const char* name_of_stub = StubCode::NameOfStub(addr); | 842 const char* name_of_stub = StubCode::NameOfStub(addr); |
| 839 if (name_of_stub != NULL) { | 843 if (name_of_stub != NULL) { |
| 840 AppendToBuffer(" [stub: %s]", name_of_stub); | 844 Print(" [stub: %s]", name_of_stub); |
| 841 } | 845 } |
| 842 } | 846 } |
| 843 } | 847 } |
| 844 | 848 |
| 845 | 849 |
| 846 // Returns number of bytes used, including *data. | 850 // Returns number of bytes used, including *data. |
| 847 int DisassemblerX64::JumpShort(uint8_t* data) { | 851 int DisassemblerX64::JumpShort(uint8_t* data) { |
| 848 ASSERT(0xEB == *data); | 852 ASSERT(0xEB == *data); |
| 849 uint8_t b = *(data + 1); | 853 uint8_t b = *(data + 1); |
| 850 uint8_t* dest = data + static_cast<int8_t>(b) + 2; | 854 uint8_t* dest = data + static_cast<int8_t>(b) + 2; |
| 851 AppendToBuffer("jmp "); | 855 Print("jmp "); |
| 852 AppendAddressToBuffer(dest); | 856 PrintAddress(dest); |
| 853 return 2; | 857 return 2; |
| 854 } | 858 } |
| 855 | 859 |
| 856 | 860 |
| 857 // Returns number of bytes used, including *data. | 861 // Returns number of bytes used, including *data. |
| 858 int DisassemblerX64::JumpConditional(uint8_t* data) { | 862 int DisassemblerX64::JumpConditional(uint8_t* data) { |
| 859 ASSERT(0x0F == *data); | 863 ASSERT(0x0F == *data); |
| 860 uint8_t cond = *(data + 1) & 0x0F; | 864 uint8_t cond = *(data + 1) & 0x0F; |
| 861 uint8_t* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6; | 865 uint8_t* dest = data + *reinterpret_cast<int32_t*>(data + 2) + 6; |
| 862 const char* mnem = conditional_code_suffix[cond]; | 866 const char* mnem = conditional_code_suffix[cond]; |
| 863 AppendToBuffer("j%s ", mnem); | 867 Print("j%s ", mnem); |
| 864 AppendAddressToBuffer(dest); | 868 PrintAddress(dest); |
| 865 return 6; // includes 0x0F | 869 return 6; // includes 0x0F |
| 866 } | 870 } |
| 867 | 871 |
| 868 | 872 |
| 869 // Returns number of bytes used, including *data. | 873 // Returns number of bytes used, including *data. |
| 870 int DisassemblerX64::JumpConditionalShort(uint8_t* data) { | 874 int DisassemblerX64::JumpConditionalShort(uint8_t* data) { |
| 871 uint8_t cond = *data & 0x0F; | 875 uint8_t cond = *data & 0x0F; |
| 872 uint8_t b = *(data + 1); | 876 uint8_t b = *(data + 1); |
| 873 uint8_t* dest = data + static_cast<int8_t>(b) + 2; | 877 uint8_t* dest = data + static_cast<int8_t>(b) + 2; |
| 874 const char* mnem = conditional_code_suffix[cond]; | 878 const char* mnem = conditional_code_suffix[cond]; |
| 875 AppendToBuffer("j%s ", mnem); | 879 Print("j%s ", mnem); |
| 876 AppendAddressToBuffer(dest); | 880 PrintAddress(dest); |
| 877 return 2; | 881 return 2; |
| 878 } | 882 } |
| 879 | 883 |
| 880 | 884 |
| 881 // Returns number of bytes used, including *data. | 885 // Returns number of bytes used, including *data. |
| 882 int DisassemblerX64::SetCC(uint8_t* data) { | 886 int DisassemblerX64::SetCC(uint8_t* data) { |
| 883 ASSERT(0x0F == *data); | 887 ASSERT(0x0F == *data); |
| 884 uint8_t cond = *(data + 1) & 0x0F; | 888 uint8_t cond = *(data + 1) & 0x0F; |
| 885 const char* mnem = conditional_code_suffix[cond]; | 889 const char* mnem = conditional_code_suffix[cond]; |
| 886 AppendToBuffer("set%s%c ", mnem, operand_size_code()); | 890 Print("set%s%c ", mnem, operand_size_code()); |
| 887 PrintRightByteOperand(data + 2); | 891 PrintRightByteOperand(data + 2); |
| 888 return 3; // includes 0x0F | 892 return 3; // includes 0x0F |
| 889 } | 893 } |
| 890 | 894 |
| 891 | 895 |
| 892 // Returns number of bytes used, including *data. | 896 // Returns number of bytes used, including *data. |
| 893 int DisassemblerX64::FPUInstruction(uint8_t* data) { | 897 int DisassemblerX64::FPUInstruction(uint8_t* data) { |
| 894 uint8_t escape_opcode = *data; | 898 uint8_t escape_opcode = *data; |
| 895 ASSERT(0xD8 == (escape_opcode & 0xF8)); | 899 ASSERT(0xD8 == (escape_opcode & 0xF8)); |
| 896 uint8_t modrm_byte = *(data+1); | 900 uint8_t modrm_byte = *(data+1); |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 935 | 939 |
| 936 case 0xDF: switch (regop) { | 940 case 0xDF: switch (regop) { |
| 937 case 5: mnem = "fild_d"; break; | 941 case 5: mnem = "fild_d"; break; |
| 938 case 7: mnem = "fistp_d"; break; | 942 case 7: mnem = "fistp_d"; break; |
| 939 default: UnimplementedInstruction(); | 943 default: UnimplementedInstruction(); |
| 940 } | 944 } |
| 941 break; | 945 break; |
| 942 | 946 |
| 943 default: UnimplementedInstruction(); | 947 default: UnimplementedInstruction(); |
| 944 } | 948 } |
| 945 AppendToBuffer("%s ", mnem); | 949 Print("%s ", mnem); |
| 946 int count = PrintRightOperand(modrm_start); | 950 int count = PrintRightOperand(modrm_start); |
| 947 return count + 1; | 951 return count + 1; |
| 948 } | 952 } |
| 949 | 953 |
| 950 int DisassemblerX64::RegisterFPUInstruction(int escape_opcode, | 954 int DisassemblerX64::RegisterFPUInstruction(int escape_opcode, |
| 951 uint8_t modrm_byte) { | 955 uint8_t modrm_byte) { |
| 952 bool has_register = false; // Is the FPU register encoded in modrm_byte? | 956 bool has_register = false; // Is the FPU register encoded in modrm_byte? |
| 953 const char* mnem = "?"; | 957 const char* mnem = "?"; |
| 954 | 958 |
| 955 switch (escape_opcode) { | 959 switch (escape_opcode) { |
| (...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1051 } else if ((modrm_byte & 0xF8) == 0xE8) { | 1055 } else if ((modrm_byte & 0xF8) == 0xE8) { |
| 1052 mnem = "fucomip"; | 1056 mnem = "fucomip"; |
| 1053 has_register = true; | 1057 has_register = true; |
| 1054 } | 1058 } |
| 1055 break; | 1059 break; |
| 1056 | 1060 |
| 1057 default: UnimplementedInstruction(); | 1061 default: UnimplementedInstruction(); |
| 1058 } | 1062 } |
| 1059 | 1063 |
| 1060 if (has_register) { | 1064 if (has_register) { |
| 1061 AppendToBuffer("%s st%d", mnem, modrm_byte & 0x7); | 1065 Print("%s st%d", mnem, modrm_byte & 0x7); |
| 1062 } else { | 1066 } else { |
| 1063 AppendToBuffer("%s", mnem); | 1067 Print("%s", mnem); |
| 1064 } | 1068 } |
| 1065 return 2; | 1069 return 2; |
| 1066 } | 1070 } |
| 1067 | 1071 |
| 1068 | 1072 |
| 1069 // TODO(srdjan): Should we add a branch hint argument? | 1073 // TODO(srdjan): Should we add a branch hint argument? |
| 1070 bool DisassemblerX64::DecodeInstructionType(uint8_t** data) { | 1074 bool DisassemblerX64::DecodeInstructionType(uint8_t** data) { |
| 1071 uint8_t current; | 1075 uint8_t current; |
| 1072 | 1076 |
| 1073 // Scan for prefixes. | 1077 // Scan for prefixes. |
| 1074 while (true) { | 1078 while (true) { |
| 1075 current = **data; | 1079 current = **data; |
| 1076 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix. | 1080 if (current == OPERAND_SIZE_OVERRIDE_PREFIX) { // Group 3 prefix. |
| 1077 operand_size_ = current; | 1081 operand_size_ = current; |
| 1078 } else if ((current & 0xF0) == 0x40) { // REX prefix. | 1082 } else if ((current & 0xF0) == 0x40) { // REX prefix. |
| 1079 setRex(current); | 1083 setRex(current); |
| 1080 // TODO(srdjan): Should we enable printing of REX.W? | 1084 // TODO(srdjan): Should we enable printing of REX.W? |
| 1081 // if (rex_w()) AppendToBuffer("REX.W "); | 1085 // if (rex_w()) Print("REX.W "); |
| 1082 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3). | 1086 } else if ((current & 0xFE) == 0xF2) { // Group 1 prefix (0xF2 or 0xF3). |
| 1083 group_1_prefix_ = current; | 1087 group_1_prefix_ = current; |
| 1084 } else if (current == 0xF0) { | 1088 } else if (current == 0xF0) { |
| 1085 AppendToBuffer("lock "); | 1089 Print("lock "); |
| 1086 } else { // Not a prefix - an opcode. | 1090 } else { // Not a prefix - an opcode. |
| 1087 break; | 1091 break; |
| 1088 } | 1092 } |
| 1089 (*data)++; | 1093 (*data)++; |
| 1090 } | 1094 } |
| 1091 | 1095 |
| 1092 const InstructionDesc& idesc = instruction_table.Get(current); | 1096 const InstructionDesc& idesc = instruction_table.Get(current); |
| 1093 byte_size_operand_ = idesc.byte_size_operation; | 1097 byte_size_operand_ = idesc.byte_size_operation; |
| 1094 | 1098 |
| 1095 switch (idesc.type) { | 1099 switch (idesc.type) { |
| 1096 case ZERO_OPERANDS_INSTR: | 1100 case ZERO_OPERANDS_INSTR: |
| 1097 if (current >= 0xA4 && current <= 0xA7) { | 1101 if (current >= 0xA4 && current <= 0xA7) { |
| 1098 // String move or compare operations. | 1102 // String move or compare operations. |
| 1099 if (group_1_prefix_ == REP_PREFIX) { | 1103 if (group_1_prefix_ == REP_PREFIX) { |
| 1100 // REP. | 1104 // REP. |
| 1101 AppendToBuffer("rep "); | 1105 Print("rep "); |
| 1102 } | 1106 } |
| 1103 // TODO(srdjan): Should we enable printing of REX.W? | 1107 // TODO(srdjan): Should we enable printing of REX.W? |
| 1104 // if (rex_w()) AppendToBuffer("REX.W "); | 1108 // if (rex_w()) Print("REX.W "); |
| 1105 AppendToBuffer("%s%c", idesc.mnem, operand_size_code()); | 1109 Print("%s%c", idesc.mnem, operand_size_code()); |
| 1106 } else { | 1110 } else { |
| 1107 AppendToBuffer("%s%c", idesc.mnem, operand_size_code()); | 1111 Print("%s%c", idesc.mnem, operand_size_code()); |
| 1108 } | 1112 } |
| 1109 (*data)++; | 1113 (*data)++; |
| 1110 break; | 1114 break; |
| 1111 | 1115 |
| 1112 case TWO_OPERANDS_INSTR: | 1116 case TWO_OPERANDS_INSTR: |
| 1113 (*data)++; | 1117 (*data)++; |
| 1114 (*data) += PrintOperands(idesc.mnem, idesc.op_order_, *data); | 1118 (*data) += PrintOperands(idesc.mnem, idesc.op_order_, *data); |
| 1115 break; | 1119 break; |
| 1116 | 1120 |
| 1117 case JUMP_CONDITIONAL_SHORT_INSTR: | 1121 case JUMP_CONDITIONAL_SHORT_INSTR: |
| 1118 (*data) += JumpConditionalShort(*data); | 1122 (*data) += JumpConditionalShort(*data); |
| 1119 break; | 1123 break; |
| 1120 | 1124 |
| 1121 case REGISTER_INSTR: | 1125 case REGISTER_INSTR: |
| 1122 AppendToBuffer("%s%c %s", | 1126 Print("%s%c %s", |
| 1123 idesc.mnem, | 1127 idesc.mnem, |
| 1124 operand_size_code(), | 1128 operand_size_code(), |
| 1125 NameOfCPURegister(base_reg(current & 0x07))); | 1129 NameOfCPURegister(base_reg(current & 0x07))); |
| 1126 (*data)++; | 1130 (*data)++; |
| 1127 break; | 1131 break; |
| 1128 case PUSHPOP_INSTR: | 1132 case PUSHPOP_INSTR: |
| 1129 AppendToBuffer("%s %s", | 1133 Print("%s %s", |
| 1130 idesc.mnem, | 1134 idesc.mnem, |
| 1131 NameOfCPURegister(base_reg(current & 0x07))); | 1135 NameOfCPURegister(base_reg(current & 0x07))); |
| 1132 (*data)++; | 1136 (*data)++; |
| 1133 break; | 1137 break; |
| 1134 case MOVE_REG_INSTR: { | 1138 case MOVE_REG_INSTR: { |
| 1135 uint8_t* addr = NULL; | 1139 uint8_t* addr = NULL; |
| 1136 switch (operand_size()) { | 1140 switch (operand_size()) { |
| 1137 case WORD_SIZE: | 1141 case WORD_SIZE: |
| 1138 addr = reinterpret_cast<uint8_t*>( | 1142 addr = reinterpret_cast<uint8_t*>( |
| 1139 *reinterpret_cast<int16_t*>(*data + 1)); | 1143 *reinterpret_cast<int16_t*>(*data + 1)); |
| 1140 (*data) += 3; | 1144 (*data) += 3; |
| 1141 break; | 1145 break; |
| 1142 case DOUBLEWORD_SIZE: | 1146 case DOUBLEWORD_SIZE: |
| 1143 addr = reinterpret_cast<uint8_t*>( | 1147 addr = reinterpret_cast<uint8_t*>( |
| 1144 *reinterpret_cast<int32_t*>(*data + 1)); | 1148 *reinterpret_cast<int32_t*>(*data + 1)); |
| 1145 (*data) += 5; | 1149 (*data) += 5; |
| 1146 break; | 1150 break; |
| 1147 case QUADWORD_SIZE: | 1151 case QUADWORD_SIZE: |
| 1148 addr = reinterpret_cast<uint8_t*>( | 1152 addr = reinterpret_cast<uint8_t*>( |
| 1149 *reinterpret_cast<int64_t*>(*data + 1)); | 1153 *reinterpret_cast<int64_t*>(*data + 1)); |
| 1150 (*data) += 9; | 1154 (*data) += 9; |
| 1151 break; | 1155 break; |
| 1152 default: | 1156 default: |
| 1153 UNREACHABLE(); | 1157 UNREACHABLE(); |
| 1154 } | 1158 } |
| 1155 AppendToBuffer("mov%c %s,", | 1159 Print("mov%c %s,", |
| 1156 operand_size_code(), | 1160 operand_size_code(), |
| 1157 NameOfCPURegister(base_reg(current & 0x07))); | 1161 NameOfCPURegister(base_reg(current & 0x07))); |
| 1158 AppendAddressToBuffer(addr); | 1162 PrintAddress(addr); |
| 1159 break; | 1163 break; |
| 1160 } | 1164 } |
| 1161 | 1165 |
| 1162 case CALL_JUMP_INSTR: { | 1166 case CALL_JUMP_INSTR: { |
| 1163 uint8_t* addr = *data + *reinterpret_cast<int32_t*>(*data + 1) + 5; | 1167 uint8_t* addr = *data + *reinterpret_cast<int32_t*>(*data + 1) + 5; |
| 1164 AppendToBuffer("%s ", idesc.mnem); | 1168 Print("%s ", idesc.mnem); |
| 1165 AppendAddressToBuffer(addr); | 1169 PrintAddress(addr); |
| 1166 (*data) += 5; | 1170 (*data) += 5; |
| 1167 break; | 1171 break; |
| 1168 } | 1172 } |
| 1169 | 1173 |
| 1170 case SHORT_IMMEDIATE_INSTR: { | 1174 case SHORT_IMMEDIATE_INSTR: { |
| 1171 uint8_t* addr = | 1175 uint8_t* addr = |
| 1172 reinterpret_cast<uint8_t*>(*reinterpret_cast<int32_t*>(*data + 1)); | 1176 reinterpret_cast<uint8_t*>(*reinterpret_cast<int32_t*>(*data + 1)); |
| 1173 AppendToBuffer("%s rax, ", idesc.mnem); | 1177 Print("%s rax, ", idesc.mnem); |
| 1174 AppendAddressToBuffer(addr); | 1178 PrintAddress(addr); |
| 1175 (*data) += 5; | 1179 (*data) += 5; |
| 1176 break; | 1180 break; |
| 1177 } | 1181 } |
| 1178 | 1182 |
| 1179 case NO_INSTR: | 1183 case NO_INSTR: |
| 1180 return false; | 1184 return false; |
| 1181 | 1185 |
| 1182 default: | 1186 default: |
| 1183 UNIMPLEMENTED(); // This type is not implemented. | 1187 UNIMPLEMENTED(); // This type is not implemented. |
| 1184 } | 1188 } |
| 1185 return true; | 1189 return true; |
| 1186 } | 1190 } |
| 1187 | 1191 |
| 1188 | 1192 |
| 1189 // Handle all two-byte opcodes, which start with 0x0F. | 1193 // Handle all two-byte opcodes, which start with 0x0F. |
| 1190 // These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix. | 1194 // These instructions may be affected by an 0x66, 0xF2, or 0xF3 prefix. |
| 1191 // We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A. | 1195 // We do not use any three-byte opcodes, which start with 0x0F38 or 0x0F3A. |
| 1192 int DisassemblerX64::TwoByteOpcodeInstruction(uint8_t* data) { | 1196 int DisassemblerX64::TwoByteOpcodeInstruction(uint8_t* data) { |
| 1193 uint8_t opcode = *(data + 1); | 1197 uint8_t opcode = *(data + 1); |
| 1194 uint8_t* current = data + 2; | 1198 uint8_t* current = data + 2; |
| 1195 // At return, "current" points to the start of the next instruction. | 1199 // At return, "current" points to the start of the next instruction. |
| 1196 const char* mnemonic = TwoByteMnemonic(opcode); | 1200 const char* mnemonic = TwoByteMnemonic(opcode); |
| 1197 if (operand_size_ == 0x66) { | 1201 if (operand_size_ == 0x66) { |
| 1198 // 0x66 0x0F prefix. | 1202 // 0x66 0x0F prefix. |
| 1199 int mod, regop, rm; | 1203 int mod, regop, rm; |
| 1200 if (opcode == 0xC6) { | 1204 if (opcode == 0xC6) { |
| 1201 int mod, regop, rm; | 1205 int mod, regop, rm; |
| 1202 get_modrm(*current, &mod, ®op, &rm); | 1206 get_modrm(*current, &mod, ®op, &rm); |
| 1203 AppendToBuffer("shufpd %s, ", NameOfXMMRegister(regop)); | 1207 Print("shufpd %s, ", NameOfXMMRegister(regop)); |
| 1204 current += PrintRightXMMOperand(current); | 1208 current += PrintRightXMMOperand(current); |
| 1205 AppendToBuffer(" [%x]", *current); | 1209 Print(" [%x]", *current); |
| 1206 current++; | 1210 current++; |
| 1207 } else if (opcode == 0x3A) { | 1211 } else if (opcode == 0x3A) { |
| 1208 uint8_t third_byte = *current; | 1212 uint8_t third_byte = *current; |
| 1209 current = data + 3; | 1213 current = data + 3; |
| 1210 if (third_byte == 0x17) { | 1214 if (third_byte == 0x17) { |
| 1211 get_modrm(*current, &mod, ®op, &rm); | 1215 get_modrm(*current, &mod, ®op, &rm); |
| 1212 AppendToBuffer("extractps "); // reg/m32, xmm, imm8 | 1216 Print("extractps "); // reg/m32, xmm, imm8 |
| 1213 current += PrintRightOperand(current); | 1217 current += PrintRightOperand(current); |
| 1214 AppendToBuffer(", %s, %d", NameOfCPURegister(regop), (*current) & 3); | 1218 Print(", %s, %d", NameOfCPURegister(regop), (*current) & 3); |
| 1215 current += 1; | 1219 current += 1; |
| 1216 } else if (third_byte == 0x0b) { | 1220 } else if (third_byte == 0x0b) { |
| 1217 get_modrm(*current, &mod, ®op, &rm); | 1221 get_modrm(*current, &mod, ®op, &rm); |
| 1218 // roundsd xmm, xmm/m64, imm8 | 1222 // roundsd xmm, xmm/m64, imm8 |
| 1219 AppendToBuffer("roundsd %s, ", NameOfCPURegister(regop)); | 1223 Print("roundsd %s, ", NameOfCPURegister(regop)); |
| 1220 current += PrintRightOperand(current); | 1224 current += PrintRightOperand(current); |
| 1221 AppendToBuffer(", %d", (*current) & 3); | 1225 Print(", %d", (*current) & 3); |
| 1222 current += 1; | 1226 current += 1; |
| 1223 } else { | 1227 } else { |
| 1224 UnimplementedInstruction(); | 1228 UnimplementedInstruction(); |
| 1225 } | 1229 } |
| 1226 } else { | 1230 } else { |
| 1227 get_modrm(*current, &mod, ®op, &rm); | 1231 get_modrm(*current, &mod, ®op, &rm); |
| 1228 if (opcode == 0x1f) { | 1232 if (opcode == 0x1f) { |
| 1229 current++; | 1233 current++; |
| 1230 if (rm == 4) { // SIB byte present. | 1234 if (rm == 4) { // SIB byte present. |
| 1231 current++; | 1235 current++; |
| 1232 } | 1236 } |
| 1233 if (mod == 1) { // Byte displacement. | 1237 if (mod == 1) { // Byte displacement. |
| 1234 current += 1; | 1238 current += 1; |
| 1235 } else if (mod == 2) { // 32-bit displacement. | 1239 } else if (mod == 2) { // 32-bit displacement. |
| 1236 current += 4; | 1240 current += 4; |
| 1237 } // else no immediate displacement. | 1241 } // else no immediate displacement. |
| 1238 AppendToBuffer("nop"); | 1242 Print("nop"); |
| 1239 } else if (opcode == 0x28) { | 1243 } else if (opcode == 0x28) { |
| 1240 AppendToBuffer("movapd %s, ", NameOfXMMRegister(regop)); | 1244 Print("movapd %s, ", NameOfXMMRegister(regop)); |
| 1241 current += PrintRightXMMOperand(current); | 1245 current += PrintRightXMMOperand(current); |
| 1242 } else if (opcode == 0x29) { | 1246 } else if (opcode == 0x29) { |
| 1243 AppendToBuffer("movapd "); | 1247 Print("movapd "); |
| 1244 current += PrintRightXMMOperand(current); | 1248 current += PrintRightXMMOperand(current); |
| 1245 AppendToBuffer(", %s", NameOfXMMRegister(regop)); | 1249 Print(", %s", NameOfXMMRegister(regop)); |
| 1246 } else if (opcode == 0x6E) { | 1250 } else if (opcode == 0x6E) { |
| 1247 AppendToBuffer("mov%c %s,", | 1251 Print("mov%c %s,", |
| 1248 rex_w() ? 'q' : 'd', | 1252 rex_w() ? 'q' : 'd', |
| 1249 NameOfXMMRegister(regop)); | 1253 NameOfXMMRegister(regop)); |
| 1250 current += PrintRightOperand(current); | 1254 current += PrintRightOperand(current); |
| 1251 } else if (opcode == 0x6F) { | 1255 } else if (opcode == 0x6F) { |
| 1252 AppendToBuffer("movdqa %s,", | 1256 Print("movdqa %s,", |
| 1253 NameOfXMMRegister(regop)); | 1257 NameOfXMMRegister(regop)); |
| 1254 current += PrintRightXMMOperand(current); | 1258 current += PrintRightXMMOperand(current); |
| 1255 } else if (opcode == 0x7E) { | 1259 } else if (opcode == 0x7E) { |
| 1256 AppendToBuffer("mov%c ", | 1260 Print("mov%c ", |
| 1257 rex_w() ? 'q' : 'd'); | 1261 rex_w() ? 'q' : 'd'); |
| 1258 current += PrintRightOperand(current); | 1262 current += PrintRightOperand(current); |
| 1259 AppendToBuffer(", %s", NameOfXMMRegister(regop)); | 1263 Print(", %s", NameOfXMMRegister(regop)); |
| 1260 } else if (opcode == 0x7F) { | 1264 } else if (opcode == 0x7F) { |
| 1261 AppendToBuffer("movdqa "); | 1265 Print("movdqa "); |
| 1262 current += PrintRightXMMOperand(current); | 1266 current += PrintRightXMMOperand(current); |
| 1263 AppendToBuffer(", %s", NameOfXMMRegister(regop)); | 1267 Print(", %s", NameOfXMMRegister(regop)); |
| 1264 } else if (opcode == 0xD6) { | 1268 } else if (opcode == 0xD6) { |
| 1265 AppendToBuffer("movq "); | 1269 Print("movq "); |
| 1266 current += PrintRightXMMOperand(current); | 1270 current += PrintRightXMMOperand(current); |
| 1267 AppendToBuffer(", %s", NameOfXMMRegister(regop)); | 1271 Print(", %s", NameOfXMMRegister(regop)); |
| 1268 } else if (opcode == 0x50) { | 1272 } else if (opcode == 0x50) { |
| 1269 AppendToBuffer("movmskpd %s,", NameOfCPURegister(regop)); | 1273 Print("movmskpd %s,", NameOfCPURegister(regop)); |
| 1270 current += PrintRightXMMOperand(current); | 1274 current += PrintRightXMMOperand(current); |
| 1271 } else { | 1275 } else { |
| 1272 const char* mnemonic = "?"; | 1276 const char* mnemonic = "?"; |
| 1273 if (opcode == 0x14) { | 1277 if (opcode == 0x14) { |
| 1274 mnemonic = "unpcklpd"; | 1278 mnemonic = "unpcklpd"; |
| 1275 } else if (opcode == 0x15) { | 1279 } else if (opcode == 0x15) { |
| 1276 mnemonic = "unpckhpd"; | 1280 mnemonic = "unpckhpd"; |
| 1277 } else if (opcode == 0x54) { | 1281 } else if (opcode == 0x54) { |
| 1278 mnemonic = "andpd"; | 1282 mnemonic = "andpd"; |
| 1279 } else if (opcode == 0x56) { | 1283 } else if (opcode == 0x56) { |
| (...skipping 20 matching lines...) Expand all Loading... |
| 1300 mnemonic = "minpd"; | 1304 mnemonic = "minpd"; |
| 1301 } else if (opcode == 0x5F) { | 1305 } else if (opcode == 0x5F) { |
| 1302 mnemonic = "maxpd"; | 1306 mnemonic = "maxpd"; |
| 1303 } else if (opcode == 0x51) { | 1307 } else if (opcode == 0x51) { |
| 1304 mnemonic = "sqrtpd"; | 1308 mnemonic = "sqrtpd"; |
| 1305 } else if (opcode == 0x5A) { | 1309 } else if (opcode == 0x5A) { |
| 1306 mnemonic = "cvtpd2ps"; | 1310 mnemonic = "cvtpd2ps"; |
| 1307 } else { | 1311 } else { |
| 1308 UnimplementedInstruction(); | 1312 UnimplementedInstruction(); |
| 1309 } | 1313 } |
| 1310 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop)); | 1314 Print("%s %s,", mnemonic, NameOfXMMRegister(regop)); |
| 1311 current += PrintRightXMMOperand(current); | 1315 current += PrintRightXMMOperand(current); |
| 1312 } | 1316 } |
| 1313 } | 1317 } |
| 1314 } else if (group_1_prefix_ == 0xF2) { | 1318 } else if (group_1_prefix_ == 0xF2) { |
| 1315 // Beginning of instructions with prefix 0xF2. | 1319 // Beginning of instructions with prefix 0xF2. |
| 1316 | 1320 |
| 1317 if (opcode == 0x11 || opcode == 0x10) { | 1321 if (opcode == 0x11 || opcode == 0x10) { |
| 1318 // MOVSD: Move scalar double-precision fp to/from/between XMM registers. | 1322 // MOVSD: Move scalar double-precision fp to/from/between XMM registers. |
| 1319 AppendToBuffer("movsd "); | 1323 Print("movsd "); |
| 1320 int mod, regop, rm; | 1324 int mod, regop, rm; |
| 1321 get_modrm(*current, &mod, ®op, &rm); | 1325 get_modrm(*current, &mod, ®op, &rm); |
| 1322 if (opcode == 0x11) { | 1326 if (opcode == 0x11) { |
| 1323 current += PrintRightXMMOperand(current); | 1327 current += PrintRightXMMOperand(current); |
| 1324 AppendToBuffer(",%s", NameOfXMMRegister(regop)); | 1328 Print(",%s", NameOfXMMRegister(regop)); |
| 1325 } else { | 1329 } else { |
| 1326 AppendToBuffer("%s,", NameOfXMMRegister(regop)); | 1330 Print("%s,", NameOfXMMRegister(regop)); |
| 1327 current += PrintRightXMMOperand(current); | 1331 current += PrintRightXMMOperand(current); |
| 1328 } | 1332 } |
| 1329 } else if (opcode == 0x2A) { | 1333 } else if (opcode == 0x2A) { |
| 1330 // CVTSI2SD: integer to XMM double conversion. | 1334 // CVTSI2SD: integer to XMM double conversion. |
| 1331 int mod, regop, rm; | 1335 int mod, regop, rm; |
| 1332 get_modrm(*current, &mod, ®op, &rm); | 1336 get_modrm(*current, &mod, ®op, &rm); |
| 1333 AppendToBuffer("%sd %s,", mnemonic, NameOfXMMRegister(regop)); | 1337 Print("%sd %s,", mnemonic, NameOfXMMRegister(regop)); |
| 1334 current += PrintRightOperand(current); | 1338 current += PrintRightOperand(current); |
| 1335 } else if (opcode == 0x2C) { | 1339 } else if (opcode == 0x2C) { |
| 1336 // CVTTSD2SI: | 1340 // CVTTSD2SI: |
| 1337 // Convert with truncation scalar double-precision FP to integer. | 1341 // Convert with truncation scalar double-precision FP to integer. |
| 1338 int mod, regop, rm; | 1342 int mod, regop, rm; |
| 1339 get_modrm(*current, &mod, ®op, &rm); | 1343 get_modrm(*current, &mod, ®op, &rm); |
| 1340 AppendToBuffer("cvttsd2si%c %s,", | 1344 Print("cvttsd2si%c %s,", |
| 1341 operand_size_code(), NameOfCPURegister(regop)); | 1345 operand_size_code(), NameOfCPURegister(regop)); |
| 1342 current += PrintRightXMMOperand(current); | 1346 current += PrintRightXMMOperand(current); |
| 1343 } else if (opcode == 0x2D) { | 1347 } else if (opcode == 0x2D) { |
| 1344 // CVTSD2SI: Convert scalar double-precision FP to integer. | 1348 // CVTSD2SI: Convert scalar double-precision FP to integer. |
| 1345 int mod, regop, rm; | 1349 int mod, regop, rm; |
| 1346 get_modrm(*current, &mod, ®op, &rm); | 1350 get_modrm(*current, &mod, ®op, &rm); |
| 1347 AppendToBuffer("cvtsd2si%c %s,", | 1351 Print("cvtsd2si%c %s,", |
| 1348 operand_size_code(), NameOfCPURegister(regop)); | 1352 operand_size_code(), NameOfCPURegister(regop)); |
| 1349 current += PrintRightXMMOperand(current); | 1353 current += PrintRightXMMOperand(current); |
| 1350 } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) { | 1354 } else if ((opcode & 0xF8) == 0x58 || opcode == 0x51) { |
| 1351 // XMM arithmetic. Mnemonic was retrieved at the start of this function. | 1355 // XMM arithmetic. Mnemonic was retrieved at the start of this function. |
| 1352 int mod, regop, rm; | 1356 int mod, regop, rm; |
| 1353 get_modrm(*current, &mod, ®op, &rm); | 1357 get_modrm(*current, &mod, ®op, &rm); |
| 1354 AppendToBuffer("%s %s,", mnemonic, NameOfXMMRegister(regop)); | 1358 Print("%s %s,", mnemonic, NameOfXMMRegister(regop)); |
| 1355 current += PrintRightXMMOperand(current); | 1359 current += PrintRightXMMOperand(current); |
| 1356 } else { | 1360 } else { |
| 1357 UnimplementedInstruction(); | 1361 UnimplementedInstruction(); |
| 1358 } | 1362 } |
| 1359 } else if (group_1_prefix_ == 0xF3) { | 1363 } else if (group_1_prefix_ == 0xF3) { |
| 1360 // Instructions with prefix 0xF3. | 1364 // Instructions with prefix 0xF3. |
| 1361 if (opcode == 0x11 || opcode == 0x10) { | 1365 if (opcode == 0x11 || opcode == 0x10) { |
| 1362 // MOVSS: Move scalar double-precision fp to/from/between XMM registers. | 1366 // MOVSS: Move scalar double-precision fp to/from/between XMM registers. |
| 1363 AppendToBuffer("movss "); | 1367 Print("movss "); |
| 1364 int mod, regop, rm; | 1368 int mod, regop, rm; |
| 1365 get_modrm(*current, &mod, ®op, &rm); | 1369 get_modrm(*current, &mod, ®op, &rm); |
| 1366 if (opcode == 0x11) { | 1370 if (opcode == 0x11) { |
| 1367 current += PrintRightOperand(current); | 1371 current += PrintRightOperand(current); |
| 1368 AppendToBuffer(",%s", NameOfXMMRegister(regop)); | 1372 Print(",%s", NameOfXMMRegister(regop)); |
| 1369 } else { | 1373 } else { |
| 1370 AppendToBuffer("%s,", NameOfXMMRegister(regop)); | 1374 Print("%s,", NameOfXMMRegister(regop)); |
| 1371 current += PrintRightOperand(current); | 1375 current += PrintRightOperand(current); |
| 1372 } | 1376 } |
| 1373 } else if (opcode == 0x2A) { | 1377 } else if (opcode == 0x2A) { |
| 1374 // CVTSI2SS: integer to XMM single conversion. | 1378 // CVTSI2SS: integer to XMM single conversion. |
| 1375 int mod, regop, rm; | 1379 int mod, regop, rm; |
| 1376 get_modrm(*current, &mod, ®op, &rm); | 1380 get_modrm(*current, &mod, ®op, &rm); |
| 1377 AppendToBuffer("%ss %s,", mnemonic, NameOfXMMRegister(regop)); | 1381 Print("%ss %s,", mnemonic, NameOfXMMRegister(regop)); |
| 1378 current += PrintRightOperand(current); | 1382 current += PrintRightOperand(current); |
| 1379 } else if (opcode == 0x2C) { | 1383 } else if (opcode == 0x2C) { |
| 1380 // CVTTSS2SI: | 1384 // CVTTSS2SI: |
| 1381 // Convert with truncation scalar single-precision FP to dword integer. | 1385 // Convert with truncation scalar single-precision FP to dword integer. |
| 1382 int mod, regop, rm; | 1386 int mod, regop, rm; |
| 1383 get_modrm(*current, &mod, ®op, &rm); | 1387 get_modrm(*current, &mod, ®op, &rm); |
| 1384 AppendToBuffer("cvttss2si%c %s,", | 1388 Print("cvttss2si%c %s,", |
| 1385 operand_size_code(), NameOfCPURegister(regop)); | 1389 operand_size_code(), NameOfCPURegister(regop)); |
| 1386 current += PrintRightXMMOperand(current); | 1390 current += PrintRightXMMOperand(current); |
| 1387 } else if (opcode == 0x5A) { | 1391 } else if (opcode == 0x5A) { |
| 1388 // CVTSS2SD: | 1392 // CVTSS2SD: |
| 1389 // Convert scalar single-precision FP to scalar double-precision FP. | 1393 // Convert scalar single-precision FP to scalar double-precision FP. |
| 1390 int mod, regop, rm; | 1394 int mod, regop, rm; |
| 1391 get_modrm(*current, &mod, ®op, &rm); | 1395 get_modrm(*current, &mod, ®op, &rm); |
| 1392 AppendToBuffer("cvtss2sd %s,", NameOfXMMRegister(regop)); | 1396 Print("cvtss2sd %s,", NameOfXMMRegister(regop)); |
| 1393 current += PrintRightXMMOperand(current); | 1397 current += PrintRightXMMOperand(current); |
| 1394 } else if (opcode == 0x7E) { | 1398 } else if (opcode == 0x7E) { |
| 1395 int mod, regop, rm; | 1399 int mod, regop, rm; |
| 1396 get_modrm(*current, &mod, ®op, &rm); | 1400 get_modrm(*current, &mod, ®op, &rm); |
| 1397 AppendToBuffer("movq %s, ", NameOfXMMRegister(regop)); | 1401 Print("movq %s, ", NameOfXMMRegister(regop)); |
| 1398 current += PrintRightXMMOperand(current); | 1402 current += PrintRightXMMOperand(current); |
| 1399 } else if (opcode == 0x58) { | 1403 } else if (opcode == 0x58) { |
| 1400 int mod, regop, rm; | 1404 int mod, regop, rm; |
| 1401 get_modrm(*current, &mod, ®op, &rm); | 1405 get_modrm(*current, &mod, ®op, &rm); |
| 1402 AppendToBuffer("addss %s,", NameOfXMMRegister(regop)); | 1406 Print("addss %s,", NameOfXMMRegister(regop)); |
| 1403 current += PrintRightXMMOperand(current); | 1407 current += PrintRightXMMOperand(current); |
| 1404 } else { | 1408 } else { |
| 1405 UnimplementedInstruction(); | 1409 UnimplementedInstruction(); |
| 1406 } | 1410 } |
| 1407 } else if (opcode == 0x1F) { | 1411 } else if (opcode == 0x1F) { |
| 1408 // NOP | 1412 // NOP |
| 1409 int mod, regop, rm; | 1413 int mod, regop, rm; |
| 1410 get_modrm(*current, &mod, ®op, &rm); | 1414 get_modrm(*current, &mod, ®op, &rm); |
| 1411 current++; | 1415 current++; |
| 1412 if (rm == 4) { // SIB byte present. | 1416 if (rm == 4) { // SIB byte present. |
| 1413 current++; | 1417 current++; |
| 1414 } | 1418 } |
| 1415 if (mod == 1) { // Byte displacement. | 1419 if (mod == 1) { // Byte displacement. |
| 1416 current += 1; | 1420 current += 1; |
| 1417 } else if (mod == 2) { // 32-bit displacement. | 1421 } else if (mod == 2) { // 32-bit displacement. |
| 1418 current += 4; | 1422 current += 4; |
| 1419 } // else no immediate displacement. | 1423 } // else no immediate displacement. |
| 1420 AppendToBuffer("nop"); | 1424 Print("nop"); |
| 1421 | 1425 |
| 1422 } else if (opcode == 0x28) { | 1426 } else if (opcode == 0x28) { |
| 1423 // movaps xmm, xmm/m128 | 1427 // movaps xmm, xmm/m128 |
| 1424 int mod, regop, rm; | 1428 int mod, regop, rm; |
| 1425 get_modrm(*current, &mod, ®op, &rm); | 1429 get_modrm(*current, &mod, ®op, &rm); |
| 1426 AppendToBuffer("movaps %s, ", NameOfXMMRegister(regop)); | 1430 Print("movaps %s, ", NameOfXMMRegister(regop)); |
| 1427 current += PrintRightXMMOperand(current); | 1431 current += PrintRightXMMOperand(current); |
| 1428 } else if (opcode == 0x29) { | 1432 } else if (opcode == 0x29) { |
| 1429 // movaps xmm/m128, xmm | 1433 // movaps xmm/m128, xmm |
| 1430 int mod, regop, rm; | 1434 int mod, regop, rm; |
| 1431 get_modrm(*current, &mod, ®op, &rm); | 1435 get_modrm(*current, &mod, ®op, &rm); |
| 1432 AppendToBuffer("movaps "); | 1436 Print("movaps "); |
| 1433 current += PrintRightXMMOperand(current); | 1437 current += PrintRightXMMOperand(current); |
| 1434 AppendToBuffer(", %s", NameOfXMMRegister(regop)); | 1438 Print(", %s", NameOfXMMRegister(regop)); |
| 1435 } else if (opcode == 0x11) { | 1439 } else if (opcode == 0x11) { |
| 1436 // movups xmm/m128, xmm | 1440 // movups xmm/m128, xmm |
| 1437 int mod, regop, rm; | 1441 int mod, regop, rm; |
| 1438 get_modrm(*current, &mod, ®op, &rm); | 1442 get_modrm(*current, &mod, ®op, &rm); |
| 1439 AppendToBuffer("movups "); | 1443 Print("movups "); |
| 1440 current += PrintRightXMMOperand(current); | 1444 current += PrintRightXMMOperand(current); |
| 1441 AppendToBuffer(", %s", NameOfXMMRegister(regop)); | 1445 Print(", %s", NameOfXMMRegister(regop)); |
| 1442 } else if (opcode == 0x10) { | 1446 } else if (opcode == 0x10) { |
| 1443 // movups xmm, xmm/m128 | 1447 // movups xmm, xmm/m128 |
| 1444 int mod, regop, rm; | 1448 int mod, regop, rm; |
| 1445 get_modrm(*current, &mod, ®op, &rm); | 1449 get_modrm(*current, &mod, ®op, &rm); |
| 1446 AppendToBuffer("movups %s, ", NameOfXMMRegister(regop)); | 1450 Print("movups %s, ", NameOfXMMRegister(regop)); |
| 1447 current += PrintRightXMMOperand(current); | 1451 current += PrintRightXMMOperand(current); |
| 1448 } else if (opcode == 0x50) { | 1452 } else if (opcode == 0x50) { |
| 1449 int mod, regop, rm; | 1453 int mod, regop, rm; |
| 1450 get_modrm(*current, &mod, ®op, &rm); | 1454 get_modrm(*current, &mod, ®op, &rm); |
| 1451 AppendToBuffer("movmskps %s,", NameOfCPURegister(regop)); | 1455 Print("movmskps %s,", NameOfCPURegister(regop)); |
| 1452 current += PrintRightXMMOperand(current); | 1456 current += PrintRightXMMOperand(current); |
| 1453 } else if (opcode == 0xA2 || opcode == 0x31) { | 1457 } else if (opcode == 0xA2 || opcode == 0x31) { |
| 1454 // RDTSC or CPUID | 1458 // RDTSC or CPUID |
| 1455 AppendToBuffer("%s", mnemonic); | 1459 Print("%s", mnemonic); |
| 1456 | 1460 |
| 1457 } else if ((opcode & 0xF0) == 0x40) { | 1461 } else if ((opcode & 0xF0) == 0x40) { |
| 1458 // CMOVcc: conditional move. | 1462 // CMOVcc: conditional move. |
| 1459 int condition = opcode & 0x0F; | 1463 int condition = opcode & 0x0F; |
| 1460 const InstructionDesc& idesc = cmov_instructions[condition]; | 1464 const InstructionDesc& idesc = cmov_instructions[condition]; |
| 1461 byte_size_operand_ = idesc.byte_size_operation; | 1465 byte_size_operand_ = idesc.byte_size_operation; |
| 1462 current += PrintOperands(idesc.mnem, idesc.op_order_, current); | 1466 current += PrintOperands(idesc.mnem, idesc.op_order_, current); |
| 1463 | 1467 |
| 1464 } else if (opcode == 0x12 || opcode == 0x14 || opcode == 0x15 || | 1468 } else if (opcode == 0x12 || opcode == 0x14 || opcode == 0x15 || |
| 1465 opcode == 0x16 || opcode == 0x51 || opcode == 0x52 || | 1469 opcode == 0x16 || opcode == 0x51 || opcode == 0x52 || |
| (...skipping 17 matching lines...) Expand all Loading... |
| 1483 case 0x59: mnemonic = "mulps"; break; | 1487 case 0x59: mnemonic = "mulps"; break; |
| 1484 case 0x5A: mnemonic = "cvtsd2ss"; break; | 1488 case 0x5A: mnemonic = "cvtsd2ss"; break; |
| 1485 case 0x5C: mnemonic = "subps"; break; | 1489 case 0x5C: mnemonic = "subps"; break; |
| 1486 case 0x5D: mnemonic = "minps"; break; | 1490 case 0x5D: mnemonic = "minps"; break; |
| 1487 case 0x5E: mnemonic = "divps"; break; | 1491 case 0x5E: mnemonic = "divps"; break; |
| 1488 case 0x5F: mnemonic = "maxps"; break; | 1492 case 0x5F: mnemonic = "maxps"; break; |
| 1489 default: UNREACHABLE(); | 1493 default: UNREACHABLE(); |
| 1490 } | 1494 } |
| 1491 int mod, regop, rm; | 1495 int mod, regop, rm; |
| 1492 get_modrm(*current, &mod, ®op, &rm); | 1496 get_modrm(*current, &mod, ®op, &rm); |
| 1493 AppendToBuffer("%s %s, ", mnemonic, NameOfXMMRegister(regop)); | 1497 Print("%s %s, ", mnemonic, NameOfXMMRegister(regop)); |
| 1494 current += PrintRightXMMOperand(current); | 1498 current += PrintRightXMMOperand(current); |
| 1495 } else if (opcode == 0xC2 || opcode == 0xC6) { | 1499 } else if (opcode == 0xC2 || opcode == 0xC6) { |
| 1496 int mod, regop, rm; | 1500 int mod, regop, rm; |
| 1497 get_modrm(*current, &mod, ®op, &rm); | 1501 get_modrm(*current, &mod, ®op, &rm); |
| 1498 if (opcode == 0xC2) { | 1502 if (opcode == 0xC2) { |
| 1499 AppendToBuffer("cmpps %s, ", NameOfXMMRegister(regop)); | 1503 Print("cmpps %s, ", NameOfXMMRegister(regop)); |
| 1500 } else { | 1504 } else { |
| 1501 ASSERT(opcode == 0xC6); | 1505 ASSERT(opcode == 0xC6); |
| 1502 AppendToBuffer("shufps %s, ", NameOfXMMRegister(regop)); | 1506 Print("shufps %s, ", NameOfXMMRegister(regop)); |
| 1503 } | 1507 } |
| 1504 current += PrintRightXMMOperand(current); | 1508 current += PrintRightXMMOperand(current); |
| 1505 AppendToBuffer(" [%x]", *current); | 1509 Print(" [%x]", *current); |
| 1506 current++; | 1510 current++; |
| 1507 } else if ((opcode & 0xF0) == 0x80) { | 1511 } else if ((opcode & 0xF0) == 0x80) { |
| 1508 // Jcc: Conditional jump (branch). | 1512 // Jcc: Conditional jump (branch). |
| 1509 current = data + JumpConditional(data); | 1513 current = data + JumpConditional(data); |
| 1510 | 1514 |
| 1511 } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 || | 1515 } else if (opcode == 0xBE || opcode == 0xBF || opcode == 0xB6 || |
| 1512 opcode == 0xB7 || opcode == 0xAF || opcode == 0xB0 || | 1516 opcode == 0xB7 || opcode == 0xAF || opcode == 0xB0 || |
| 1513 opcode == 0xB1) { | 1517 opcode == 0xB1) { |
| 1514 // Size-extending moves, IMUL, cmpxchg. | 1518 // Size-extending moves, IMUL, cmpxchg. |
| 1515 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current); | 1519 current += PrintOperands(mnemonic, REG_OPER_OP_ORDER, current); |
| 1516 | 1520 |
| 1517 } else if ((opcode & 0xF0) == 0x90) { | 1521 } else if ((opcode & 0xF0) == 0x90) { |
| 1518 // SETcc: Set byte on condition. Needs pointer to beginning of instruction. | 1522 // SETcc: Set byte on condition. Needs pointer to beginning of instruction. |
| 1519 current = data + SetCC(data); | 1523 current = data + SetCC(data); |
| 1520 | 1524 |
| 1521 } else if (((opcode & 0xFE) == 0xA4) || ((opcode & 0xFE) == 0xAC) || | 1525 } else if (((opcode & 0xFE) == 0xA4) || ((opcode & 0xFE) == 0xAC) || |
| 1522 (opcode == 0xAB) || (opcode == 0xA3) || (opcode == 0xBD)) { | 1526 (opcode == 0xAB) || (opcode == 0xA3) || (opcode == 0xBD)) { |
| 1523 // SHLD, SHRD (double-prec. shift), BTS (bit test and set), BT (bit test). | 1527 // SHLD, SHRD (double-prec. shift), BTS (bit test and set), BT (bit test). |
| 1524 AppendToBuffer("%s%c ", mnemonic, operand_size_code()); | 1528 Print("%s%c ", mnemonic, operand_size_code()); |
| 1525 int mod, regop, rm; | 1529 int mod, regop, rm; |
| 1526 get_modrm(*current, &mod, ®op, &rm); | 1530 get_modrm(*current, &mod, ®op, &rm); |
| 1527 current += PrintRightOperand(current); | 1531 current += PrintRightOperand(current); |
| 1528 AppendToBuffer(",%s", NameOfCPURegister(regop)); | 1532 Print(",%s", NameOfCPURegister(regop)); |
| 1529 if ((opcode == 0xAB) || (opcode == 0xA3) || (opcode == 0xBD)) { | 1533 if ((opcode == 0xAB) || (opcode == 0xA3) || (opcode == 0xBD)) { |
| 1530 // Done. | 1534 // Done. |
| 1531 } else if ((opcode == 0xA5) || (opcode == 0xAD)) { | 1535 } else if ((opcode == 0xA5) || (opcode == 0xAD)) { |
| 1532 AppendToBuffer(",cl"); | 1536 Print(",cl"); |
| 1533 } else { | 1537 } else { |
| 1534 AppendToBuffer(","); | 1538 Print(","); |
| 1535 current += PrintImmediate(current, BYTE_SIZE); | 1539 current += PrintImmediate(current, BYTE_SIZE); |
| 1536 } | 1540 } |
| 1537 } else { | 1541 } else { |
| 1538 UnimplementedInstruction(); | 1542 UnimplementedInstruction(); |
| 1539 } | 1543 } |
| 1540 return static_cast<int>(current - data); | 1544 return static_cast<int>(current - data); |
| 1541 } | 1545 } |
| 1542 | 1546 |
| 1543 | 1547 |
| 1544 // Mnemonics for two-byte opcode instructions starting with 0x0F. | 1548 // Mnemonics for two-byte opcode instructions starting with 0x0F. |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1600 | 1604 |
| 1601 | 1605 |
| 1602 int DisassemblerX64::InstructionDecode(uword pc) { | 1606 int DisassemblerX64::InstructionDecode(uword pc) { |
| 1603 uint8_t* data = reinterpret_cast<uint8_t*>(pc); | 1607 uint8_t* data = reinterpret_cast<uint8_t*>(pc); |
| 1604 | 1608 |
| 1605 const bool processed = DecodeInstructionType(&data); | 1609 const bool processed = DecodeInstructionType(&data); |
| 1606 | 1610 |
| 1607 if (!processed) { | 1611 if (!processed) { |
| 1608 switch (*data) { | 1612 switch (*data) { |
| 1609 case 0xC2: | 1613 case 0xC2: |
| 1610 AppendToBuffer("ret %#x", *reinterpret_cast<uint16_t*>(data + 1)); | 1614 Print("ret "); |
| 1615 PrintImmediateValue(*reinterpret_cast<uint16_t*>(data + 1)); |
| 1611 data += 3; | 1616 data += 3; |
| 1612 break; | 1617 break; |
| 1613 | 1618 |
| 1614 case 0xC8: | 1619 case 0xC8: |
| 1615 AppendToBuffer("enter %d, %d", | 1620 Print("enter %d, %d", |
| 1616 *reinterpret_cast<uint16_t*>(data + 1), | 1621 *reinterpret_cast<uint16_t*>(data + 1), |
| 1617 data[3]); | 1622 data[3]); |
| 1618 data += 4; | 1623 data += 4; |
| 1619 break; | 1624 break; |
| 1620 | 1625 |
| 1621 case 0x69: // fall through | 1626 case 0x69: // fall through |
| 1622 case 0x6B: { | 1627 case 0x6B: { |
| 1623 int mod, regop, rm; | 1628 int mod, regop, rm; |
| 1624 get_modrm(*(data + 1), &mod, ®op, &rm); | 1629 get_modrm(*(data + 1), &mod, ®op, &rm); |
| 1625 int32_t imm = *data == 0x6B ? *(data + 2) | 1630 int32_t imm = *data == 0x6B ? *(data + 2) |
| 1626 : *reinterpret_cast<int32_t*>(data + 2); | 1631 : *reinterpret_cast<int32_t*>(data + 2); |
| 1627 AppendToBuffer("imul%c %s,%s,%#x", | 1632 Print("imul%c %s,%s,", |
| 1628 operand_size_code(), | 1633 operand_size_code(), |
| 1629 NameOfCPURegister(regop), | 1634 NameOfCPURegister(regop), |
| 1630 NameOfCPURegister(rm), imm); | 1635 NameOfCPURegister(rm)); |
| 1636 PrintImmediateValue(imm); |
| 1631 data += 2 + (*data == 0x6B ? 1 : 4); | 1637 data += 2 + (*data == 0x6B ? 1 : 4); |
| 1632 break; | 1638 break; |
| 1633 } | 1639 } |
| 1634 | 1640 |
| 1635 case 0x81: // fall through | 1641 case 0x81: // fall through |
| 1636 case 0x83: // 0x81 with sign extension bit set | 1642 case 0x83: // 0x81 with sign extension bit set |
| 1637 data += PrintImmediateOp(data); | 1643 data += PrintImmediateOp(data); |
| 1638 break; | 1644 break; |
| 1639 | 1645 |
| 1640 case 0x0F: | 1646 case 0x0F: |
| 1641 data += TwoByteOpcodeInstruction(data); | 1647 data += TwoByteOpcodeInstruction(data); |
| 1642 break; | 1648 break; |
| 1643 | 1649 |
| 1644 case 0x8F: { | 1650 case 0x8F: { |
| 1645 data++; | 1651 data++; |
| 1646 int mod, regop, rm; | 1652 int mod, regop, rm; |
| 1647 get_modrm(*data, &mod, ®op, &rm); | 1653 get_modrm(*data, &mod, ®op, &rm); |
| 1648 if (regop == 0) { | 1654 if (regop == 0) { |
| 1649 AppendToBuffer("pop "); | 1655 Print("pop "); |
| 1650 data += PrintRightOperand(data); | 1656 data += PrintRightOperand(data); |
| 1651 } | 1657 } |
| 1652 } | 1658 } |
| 1653 break; | 1659 break; |
| 1654 | 1660 |
| 1655 case 0xFF: { | 1661 case 0xFF: { |
| 1656 data++; | 1662 data++; |
| 1657 int mod, regop, rm; | 1663 int mod, regop, rm; |
| 1658 get_modrm(*data, &mod, ®op, &rm); | 1664 get_modrm(*data, &mod, ®op, &rm); |
| 1659 const char* mnem = NULL; | 1665 const char* mnem = NULL; |
| (...skipping 10 matching lines...) Expand all Loading... |
| 1670 case 4: | 1676 case 4: |
| 1671 mnem = "jmp"; | 1677 mnem = "jmp"; |
| 1672 break; | 1678 break; |
| 1673 case 6: | 1679 case 6: |
| 1674 mnem = "push"; | 1680 mnem = "push"; |
| 1675 break; | 1681 break; |
| 1676 default: | 1682 default: |
| 1677 mnem = "???"; | 1683 mnem = "???"; |
| 1678 } | 1684 } |
| 1679 if (regop <= 1) { | 1685 if (regop <= 1) { |
| 1680 AppendToBuffer("%s%c ", mnem, operand_size_code()); | 1686 Print("%s%c ", mnem, operand_size_code()); |
| 1681 } else { | 1687 } else { |
| 1682 AppendToBuffer("%s ", mnem); | 1688 Print("%s ", mnem); |
| 1683 } | 1689 } |
| 1684 data += PrintRightOperand(data); | 1690 data += PrintRightOperand(data); |
| 1685 } | 1691 } |
| 1686 break; | 1692 break; |
| 1687 | 1693 |
| 1688 case 0xC7: // imm32, fall through | 1694 case 0xC7: // imm32, fall through |
| 1689 case 0xC6: // imm8 | 1695 case 0xC6: // imm8 |
| 1690 { | 1696 { |
| 1691 bool is_byte = *data == 0xC6; | 1697 bool is_byte = *data == 0xC6; |
| 1692 data++; | 1698 data++; |
| 1693 if (is_byte) { | 1699 if (is_byte) { |
| 1694 AppendToBuffer("movb "); | 1700 Print("movb "); |
| 1695 data += PrintRightByteOperand(data); | 1701 data += PrintRightByteOperand(data); |
| 1696 int32_t imm = *data; | 1702 int32_t imm = *data; |
| 1697 AppendToBuffer(",%#x", imm); | 1703 Print(","); |
| 1704 PrintImmediateValue(imm); |
| 1698 data++; | 1705 data++; |
| 1699 } else { | 1706 } else { |
| 1700 AppendToBuffer("mov%c ", operand_size_code()); | 1707 Print("mov%c ", operand_size_code()); |
| 1701 data += PrintRightOperand(data); | 1708 data += PrintRightOperand(data); |
| 1702 int32_t imm = *reinterpret_cast<int32_t*>(data); | 1709 int32_t imm = *reinterpret_cast<int32_t*>(data); |
| 1703 AppendToBuffer(",%#x", imm); | 1710 Print(","); |
| 1711 PrintImmediateValue(imm); |
| 1704 data += 4; | 1712 data += 4; |
| 1705 } | 1713 } |
| 1706 } | 1714 } |
| 1707 break; | 1715 break; |
| 1708 | 1716 |
| 1709 case 0x80: { | 1717 case 0x80: { |
| 1710 data++; | 1718 data++; |
| 1711 AppendToBuffer("cmpb "); | 1719 Print("cmpb "); |
| 1712 data += PrintRightByteOperand(data); | 1720 data += PrintRightByteOperand(data); |
| 1713 int32_t imm = *data; | 1721 int32_t imm = *data; |
| 1714 AppendToBuffer(",%#x", imm); | 1722 Print(","); |
| 1723 PrintImmediateValue(imm); |
| 1715 data++; | 1724 data++; |
| 1716 } | 1725 } |
| 1717 break; | 1726 break; |
| 1718 | 1727 |
| 1719 case 0x88: // 8bit, fall through | 1728 case 0x88: // 8bit, fall through |
| 1720 case 0x89: // 32bit | 1729 case 0x89: // 32bit |
| 1721 { | 1730 { |
| 1722 bool is_byte = *data == 0x88; | 1731 bool is_byte = *data == 0x88; |
| 1723 int mod, regop, rm; | 1732 int mod, regop, rm; |
| 1724 data++; | 1733 data++; |
| 1725 get_modrm(*data, &mod, ®op, &rm); | 1734 get_modrm(*data, &mod, ®op, &rm); |
| 1726 if (is_byte) { | 1735 if (is_byte) { |
| 1727 AppendToBuffer("movb "); | 1736 Print("movb "); |
| 1728 data += PrintRightByteOperand(data); | 1737 data += PrintRightByteOperand(data); |
| 1729 AppendToBuffer(",%s", NameOfByteCPURegister(regop)); | 1738 Print(",%s", NameOfByteCPURegister(regop)); |
| 1730 } else { | 1739 } else { |
| 1731 AppendToBuffer("mov%c ", operand_size_code()); | 1740 Print("mov%c ", operand_size_code()); |
| 1732 data += PrintRightOperand(data); | 1741 data += PrintRightOperand(data); |
| 1733 AppendToBuffer(",%s", NameOfCPURegister(regop)); | 1742 Print(",%s", NameOfCPURegister(regop)); |
| 1734 } | 1743 } |
| 1735 } | 1744 } |
| 1736 break; | 1745 break; |
| 1737 | 1746 |
| 1738 case 0x90: | 1747 case 0x90: |
| 1739 case 0x91: | 1748 case 0x91: |
| 1740 case 0x92: | 1749 case 0x92: |
| 1741 case 0x93: | 1750 case 0x93: |
| 1742 case 0x94: | 1751 case 0x94: |
| 1743 case 0x95: | 1752 case 0x95: |
| 1744 case 0x96: | 1753 case 0x96: |
| 1745 case 0x97: { | 1754 case 0x97: { |
| 1746 int reg = (*data & 0x7) | (rex_b() ? 8 : 0); | 1755 int reg = (*data & 0x7) | (rex_b() ? 8 : 0); |
| 1747 if (reg == 0) { | 1756 if (reg == 0) { |
| 1748 AppendToBuffer("nop"); // Common name for xchg rax,rax. | 1757 Print("nop"); // Common name for xchg rax,rax. |
| 1749 } else { | 1758 } else { |
| 1750 AppendToBuffer("xchg%c rax, %s", | 1759 Print("xchg%c rax, %s", operand_size_code(), NameOfCPURegister(reg)); |
| 1751 operand_size_code(), | |
| 1752 NameOfCPURegister(reg)); | |
| 1753 } | 1760 } |
| 1754 data++; | 1761 data++; |
| 1755 } | 1762 } |
| 1756 break; | 1763 break; |
| 1757 case 0xB0: | 1764 case 0xB0: |
| 1758 case 0xB1: | 1765 case 0xB1: |
| 1759 case 0xB2: | 1766 case 0xB2: |
| 1760 case 0xB3: | 1767 case 0xB3: |
| 1761 case 0xB4: | 1768 case 0xB4: |
| 1762 case 0xB5: | 1769 case 0xB5: |
| 1763 case 0xB6: | 1770 case 0xB6: |
| 1764 case 0xB7: | 1771 case 0xB7: |
| 1765 case 0xB8: | 1772 case 0xB8: |
| 1766 case 0xB9: | 1773 case 0xB9: |
| 1767 case 0xBA: | 1774 case 0xBA: |
| 1768 case 0xBB: | 1775 case 0xBB: |
| 1769 case 0xBC: | 1776 case 0xBC: |
| 1770 case 0xBD: | 1777 case 0xBD: |
| 1771 case 0xBE: | 1778 case 0xBE: |
| 1772 case 0xBF: { | 1779 case 0xBF: { |
| 1773 // mov reg8,imm8 or mov reg32,imm32 | 1780 // mov reg8,imm8 or mov reg32,imm32 |
| 1774 uint8_t opcode = *data; | 1781 uint8_t opcode = *data; |
| 1775 data++; | 1782 data++; |
| 1776 uint8_t is_32bit = (opcode >= 0xB8); | 1783 uint8_t is_32bit = (opcode >= 0xB8); |
| 1777 int reg = (opcode & 0x7) | (rex_b() ? 8 : 0); | 1784 int reg = (opcode & 0x7) | (rex_b() ? 8 : 0); |
| 1778 if (is_32bit) { | 1785 if (is_32bit) { |
| 1779 AppendToBuffer("mov%c %s, ", | 1786 Print("mov%c %s,", operand_size_code(), NameOfCPURegister(reg)); |
| 1780 operand_size_code(), | |
| 1781 NameOfCPURegister(reg)); | |
| 1782 data += PrintImmediate(data, DOUBLEWORD_SIZE); | 1787 data += PrintImmediate(data, DOUBLEWORD_SIZE); |
| 1783 } else { | 1788 } else { |
| 1784 AppendToBuffer("movb %s, ", | 1789 Print("movb %s,", NameOfByteCPURegister(reg)); |
| 1785 NameOfByteCPURegister(reg)); | |
| 1786 data += PrintImmediate(data, BYTE_SIZE); | 1790 data += PrintImmediate(data, BYTE_SIZE); |
| 1787 } | 1791 } |
| 1788 break; | 1792 break; |
| 1789 } | 1793 } |
| 1790 case 0xFE: { | 1794 case 0xFE: { |
| 1791 data++; | 1795 data++; |
| 1792 int mod, regop, rm; | 1796 int mod, regop, rm; |
| 1793 get_modrm(*data, &mod, ®op, &rm); | 1797 get_modrm(*data, &mod, ®op, &rm); |
| 1794 if (regop == 1) { | 1798 if (regop == 1) { |
| 1795 AppendToBuffer("decb "); | 1799 Print("decb "); |
| 1796 data += PrintRightByteOperand(data); | 1800 data += PrintRightByteOperand(data); |
| 1797 } else { | 1801 } else { |
| 1798 UnimplementedInstruction(); | 1802 UnimplementedInstruction(); |
| 1799 } | 1803 } |
| 1800 break; | 1804 break; |
| 1801 } | 1805 } |
| 1802 case 0x68: | 1806 case 0x68: |
| 1803 AppendToBuffer("push %#x", *reinterpret_cast<int32_t*>(data + 1)); | 1807 Print("push "); |
| 1808 PrintImmediateValue(*reinterpret_cast<int32_t*>(data + 1)); |
| 1804 data += 5; | 1809 data += 5; |
| 1805 break; | 1810 break; |
| 1806 | 1811 |
| 1807 case 0x6A: | 1812 case 0x6A: |
| 1808 AppendToBuffer("push %#x", *reinterpret_cast<int8_t*>(data + 1)); | 1813 Print("push "); |
| 1814 PrintImmediateValue(*reinterpret_cast<int8_t*>(data + 1)); |
| 1809 data += 2; | 1815 data += 2; |
| 1810 break; | 1816 break; |
| 1811 | 1817 |
| 1812 case 0xA1: // Fall through. | 1818 case 0xA1: // Fall through. |
| 1813 case 0xA3: | 1819 case 0xA3: |
| 1814 switch (operand_size()) { | 1820 switch (operand_size()) { |
| 1815 case DOUBLEWORD_SIZE: { | 1821 case DOUBLEWORD_SIZE: { |
| 1816 AppendAddressToBuffer( | 1822 PrintAddress( |
| 1817 reinterpret_cast<uint8_t*>( | 1823 reinterpret_cast<uint8_t*>( |
| 1818 *reinterpret_cast<int32_t*>(data + 1))); | 1824 *reinterpret_cast<int32_t*>(data + 1))); |
| 1819 if (*data == 0xA1) { // Opcode 0xA1 | 1825 if (*data == 0xA1) { // Opcode 0xA1 |
| 1820 AppendToBuffer("movzxlq rax,("); | 1826 Print("movzxlq rax,("); |
| 1821 AppendAddressToBuffer( | 1827 PrintAddress( |
| 1822 reinterpret_cast<uint8_t*>( | 1828 reinterpret_cast<uint8_t*>( |
| 1823 *reinterpret_cast<int32_t*>(data + 1))); | 1829 *reinterpret_cast<int32_t*>(data + 1))); |
| 1824 AppendToBuffer(")"); | 1830 Print(")"); |
| 1825 } else { // Opcode 0xA3 | 1831 } else { // Opcode 0xA3 |
| 1826 AppendToBuffer("movzxlq ("); | 1832 Print("movzxlq ("); |
| 1827 AppendAddressToBuffer( | 1833 PrintAddress( |
| 1828 reinterpret_cast<uint8_t*>( | 1834 reinterpret_cast<uint8_t*>( |
| 1829 *reinterpret_cast<int32_t*>(data + 1))); | 1835 *reinterpret_cast<int32_t*>(data + 1))); |
| 1830 AppendToBuffer("),rax"); | 1836 Print("),rax"); |
| 1831 } | 1837 } |
| 1832 data += 5; | 1838 data += 5; |
| 1833 break; | 1839 break; |
| 1834 } | 1840 } |
| 1835 case QUADWORD_SIZE: { | 1841 case QUADWORD_SIZE: { |
| 1836 // New x64 instruction mov rax,(imm_64). | 1842 // New x64 instruction mov rax,(imm_64). |
| 1837 if (*data == 0xA1) { // Opcode 0xA1 | 1843 if (*data == 0xA1) { // Opcode 0xA1 |
| 1838 AppendToBuffer("movq rax,("); | 1844 Print("movq rax,("); |
| 1839 AppendAddressToBuffer(*reinterpret_cast<uint8_t**>(data + 1)); | 1845 PrintAddress(*reinterpret_cast<uint8_t**>(data + 1)); |
| 1840 AppendToBuffer(")"); | 1846 Print(")"); |
| 1841 } else { // Opcode 0xA3 | 1847 } else { // Opcode 0xA3 |
| 1842 AppendToBuffer("movq ("); | 1848 Print("movq ("); |
| 1843 AppendAddressToBuffer(*reinterpret_cast<uint8_t**>(data + 1)); | 1849 PrintAddress(*reinterpret_cast<uint8_t**>(data + 1)); |
| 1844 AppendToBuffer("),rax"); | 1850 Print("),rax"); |
| 1845 } | 1851 } |
| 1846 data += 9; | 1852 data += 9; |
| 1847 break; | 1853 break; |
| 1848 } | 1854 } |
| 1849 default: | 1855 default: |
| 1850 UnimplementedInstruction(); | 1856 UnimplementedInstruction(); |
| 1851 data += 2; | 1857 data += 2; |
| 1852 } | 1858 } |
| 1853 break; | 1859 break; |
| 1854 | 1860 |
| 1855 case 0xA8: | 1861 case 0xA8: |
| 1856 AppendToBuffer("test al,%#x", *reinterpret_cast<uint8_t*>(data + 1)); | 1862 Print("test al,"); |
| 1863 PrintImmediateValue(*reinterpret_cast<uint8_t*>(data + 1)); |
| 1857 data += 2; | 1864 data += 2; |
| 1858 break; | 1865 break; |
| 1859 | 1866 |
| 1860 case 0xA9: { | 1867 case 0xA9: { |
| 1861 int64_t value = 0; | 1868 int64_t value = 0; |
| 1862 switch (operand_size()) { | 1869 switch (operand_size()) { |
| 1863 case WORD_SIZE: | 1870 case WORD_SIZE: |
| 1864 value = *reinterpret_cast<uint16_t*>(data + 1); | 1871 value = *reinterpret_cast<uint16_t*>(data + 1); |
| 1865 data += 3; | 1872 data += 3; |
| 1866 break; | 1873 break; |
| 1867 case DOUBLEWORD_SIZE: | 1874 case DOUBLEWORD_SIZE: |
| 1868 value = *reinterpret_cast<uint32_t*>(data + 1); | 1875 value = *reinterpret_cast<uint32_t*>(data + 1); |
| 1869 data += 5; | 1876 data += 5; |
| 1870 break; | 1877 break; |
| 1871 case QUADWORD_SIZE: | 1878 case QUADWORD_SIZE: |
| 1872 value = *reinterpret_cast<int32_t*>(data + 1); | 1879 value = *reinterpret_cast<int32_t*>(data + 1); |
| 1873 data += 5; | 1880 data += 5; |
| 1874 break; | 1881 break; |
| 1875 default: | 1882 default: |
| 1876 UNREACHABLE(); | 1883 UNREACHABLE(); |
| 1877 } | 1884 } |
| 1878 AppendToBuffer("test%c rax,%#" Px64 "", | 1885 Print("test%c rax,", operand_size_code()); |
| 1879 operand_size_code(), | 1886 PrintImmediateValue(value); |
| 1880 value); | |
| 1881 break; | 1887 break; |
| 1882 } | 1888 } |
| 1883 case 0xD1: // fall through | 1889 case 0xD1: // fall through |
| 1884 case 0xD3: // fall through | 1890 case 0xD3: // fall through |
| 1885 case 0xC1: | 1891 case 0xC1: |
| 1886 data += ShiftInstruction(data); | 1892 data += ShiftInstruction(data); |
| 1887 break; | 1893 break; |
| 1888 case 0xD0: // fall through | 1894 case 0xD0: // fall through |
| 1889 case 0xD2: // fall through | 1895 case 0xD2: // fall through |
| 1890 case 0xC0: | 1896 case 0xC0: |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1946 if (out_instr_len) { | 1952 if (out_instr_len) { |
| 1947 *out_instr_len = instruction_length; | 1953 *out_instr_len = instruction_length; |
| 1948 } | 1954 } |
| 1949 } | 1955 } |
| 1950 | 1956 |
| 1951 #endif // !PRODUCT | 1957 #endif // !PRODUCT |
| 1952 | 1958 |
| 1953 } // namespace dart | 1959 } // namespace dart |
| 1954 | 1960 |
| 1955 #endif // defined TARGET_ARCH_X64 | 1961 #endif // defined TARGET_ARCH_X64 |
| OLD | NEW |