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 |