Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* | 1 /* |
| 2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. | 2 * Copyright (c) 2011 The Native Client Authors. All rights reserved. |
| 3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
| 4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
| 5 */ | 5 */ |
| 6 | 6 |
| 7 #include "native_client/src/trusted/validator_arm/inst_classes.h" | 7 #include "native_client/src/trusted/validator_arm/inst_classes.h" |
| 8 | 8 // TODO(mrm) remove when debug is gone |
| 9 #include <stdio.h> | |
| 9 /* | 10 /* |
| 10 * Implementations of instruction classes, for those not completely defined in | 11 * Implementations of instruction classes, for those not completely defined in |
| 11 * the header. | 12 * the header. |
| 12 */ | 13 */ |
| 13 | 14 |
| 14 namespace nacl_arm_dec { | 15 namespace nacl_arm_dec { |
| 15 | 16 |
| 16 /* | 17 /* |
| 17 * A utility function: given a modified-immediate-form instruction, extracts | 18 * A utility function: given a modified-immediate-form instruction, extracts |
| 18 * the immediate value. This is used to analyze BIC and TST. | 19 * the immediate value. This is used to analyze BIC and TST. |
| (...skipping 393 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 412 RegisterList Branch::defs(const Instruction i) const { | 413 RegisterList Branch::defs(const Instruction i) const { |
| 413 return kRegisterPc + (i.bit(24)? kRegisterLink : kRegisterNone); | 414 return kRegisterPc + (i.bit(24)? kRegisterLink : kRegisterNone); |
| 414 } | 415 } |
| 415 | 416 |
| 416 int32_t Branch::branch_target_offset(const Instruction i) const { | 417 int32_t Branch::branch_target_offset(const Instruction i) const { |
| 417 // Sign extend and shift left 2: | 418 // Sign extend and shift left 2: |
| 418 int32_t offset = (int32_t)(i.bits(23, 0) << 8) >> 6; | 419 int32_t offset = (int32_t)(i.bits(23, 0) << 8) >> 6; |
| 419 return offset + 8; // because r15 reads as 8 bytes ahead | 420 return offset + 8; // because r15 reads as 8 bytes ahead |
| 420 } | 421 } |
| 421 | 422 |
| 423 /* Thumb Functions */ | |
| 424 SafetyLevel Def3::safety(Instruction i) const { | |
| 425 /* If it tries to write to PC, unsafe */ | |
| 426 if (defs(i)[kRegisterPc]) { | |
| 427 return FORBIDDEN_OPERANDS; | |
| 428 } | |
| 429 return MAY_BE_SAFE; | |
| 430 } | |
| 431 | |
| 432 RegisterList Def3::defs(Instruction i) const { | |
| 433 return i.reg(3, 0); | |
| 434 } | |
| 435 | |
| 436 SafetyLevel Def8_10::safety(Instruction i) const { | |
| 437 // TODO(mrm) should be encoding impossible, check | |
| 438 if (defs(i)[kRegisterPc]) { | |
| 439 return FORBIDDEN_OPERANDS; | |
| 440 } | |
| 441 return MAY_BE_SAFE; | |
| 442 } | |
| 443 | |
| 444 RegisterList Def8_10::defs(Instruction i) const { | |
| 445 return i.reg(10, 8); | |
| 446 } | |
| 447 | |
| 448 SafetyLevel MemOpThumb::safety(Instruction i) const { | |
| 449 // Don't let addressing writeback alter PC. | |
| 450 // TODO(mrm): Check if this is possible, we may be able to remove this. | |
| 451 if (defs(i)[kRegisterPc]) return FORBIDDEN_OPERANDS; | |
| 452 | |
| 453 return MAY_BE_SAFE; | |
| 454 } | |
| 455 | |
| 456 Register MemOpThumb::base_address_register(Instruction i) const { | |
| 457 return i.reg(5, 3); | |
| 458 } | |
| 459 | |
| 460 RegisterList MemOpThumbLoad::defs(Instruction i) const { | |
| 461 return i.reg(2, 0); | |
| 462 } | |
| 463 | |
| 464 // TODO(mrm) double check, this is suspect | |
| 465 // Specifically, double check if I need to +4 things? | |
| 466 int32_t CmpBrZ::branch_target_offset(Instruction i) const { | |
| 467 return int32_t ((i.bits(9, 9) << 6) & (i.bits(7, 3) << 1)); | |
| 468 } | |
| 469 | |
| 470 RegisterList PopMult::defs(Instruction i) const { | |
| 471 return RegisterList(i.bits(7, 0)) + kRegisterStack; | |
| 472 } | |
| 473 | |
| 474 SafetyLevel BranchTCond::safety(Instruction i) const { | |
| 475 if ((condition(i) & 14) != 14) | |
| 476 return MAY_BE_SAFE; | |
| 477 return FORBIDDEN_OPERANDS; | |
| 478 } | |
| 479 | |
| 480 // TODO(mrm) Check if I need to +4 | |
| 481 int32_t BranchT1::branch_target_offset(Instruction i) const { | |
| 482 // Sign extend and left shift by one | |
| 483 return ((int32_t)(i.bits(7, 0) << 24)) >> 23; | |
| 484 } | |
| 485 | |
| 486 // TODO(mrm) write test | |
| 487 Instruction::Condition BranchT1::condition(Instruction i) const { | |
| 488 return (Instruction::Condition)i.bits(11, 8); | |
| 489 } | |
| 490 | |
| 491 // TODO(mrm) Check if I need to +4 | |
| 492 int32_t BranchT2::branch_target_offset(Instruction i) const { | |
| 493 // Sign extend and left shift by one. | |
| 494 return ((int32_t)(i.bits(10, 0) << 21)) >> 20; | |
| 495 } | |
| 496 | |
| 497 // TODO(mrm) Check if I need to +4 | |
| 498 int32_t BranchT3::branch_target_offset(Instruction i) const { | |
| 499 // Construct the value | |
| 500 uint32_t val = ((((((((i.bit(10) << 1) | i.bit(27)) << 1) | i.bit(29)) << 6) | |
| 501 | i.bits(5, 0)) << 11) | i.bits(26, 16)) << 1; | |
|
Karl
2011/08/30 19:53:52
My head huts trying to figure out what this statem
| |
| 502 // Sign extend it. | |
| 503 return ((int32_t)(val << 9)) >> 9; | |
|
Karl
2011/08/30 19:53:52
Again, there must be some knowledge here that I do
| |
| 504 } | |
| 505 | |
| 506 Instruction::Condition BranchT3::condition(Instruction i) const { | |
| 507 return (Instruction::Condition)i.bits(9, 6); | |
| 508 } | |
| 509 | |
| 510 int32_t get_stretched_immediate(Instruction i) { | |
| 511 uint32_t s = i.bit(10); | |
| 512 uint32_t i1 = (~(i.bit(27) ^ s)) & 1; | |
| 513 uint32_t i2 = (~(i.bit(29) ^ s)) & 1; | |
| 514 // Construct the value | |
| 515 uint32_t val = ((((((((i.bit(10) << 1) | i1) << 1) | i2) << 10) | |
| 516 | i.bits(9, 0)) << 11) | i.bits(26, 16)) << 1; | |
|
Karl
2011/08/30 19:53:52
Again, a better comment might be added here.
| |
| 517 // Sign extend it, adjust for pc shift | |
| 518 return (((int32_t)(val << 9)) >> 9); | |
| 519 } | |
| 520 | |
| 521 int32_t BranchT4::branch_target_offset(Instruction i) const { | |
| 522 return get_stretched_immediate(i) + 4; | |
| 523 } | |
| 524 | |
| 525 // TODO(mrm) LDMT1/STMT1 could be cleaned up | |
| 526 RegisterList LDMT1::defs(Instruction i) const { | |
| 527 return RegisterList(i.bits(7, 0)); | |
| 528 } | |
| 529 | |
| 530 RegisterList STMT1::defs(Instruction i) const { | |
| 531 return RegisterList(i.bits(7, 0)) + i.reg(10, 8); | |
| 532 } | |
| 533 | |
| 534 RegisterList STMT1::immediate_addressing_defs(Instruction i) const { | |
| 535 return i.reg(10, 8); | |
| 536 } | |
| 537 | |
| 538 Register STMT1::base_address_register(Instruction i) const { | |
| 539 return i.reg(10, 8); | |
| 540 } | |
| 541 | |
| 542 RegisterList LDRLitT1::defs(Instruction i) const { | |
| 543 return i.reg(10, 8); | |
| 544 } | |
| 545 | |
| 546 RegisterList ADRT1::defs(Instruction i) const { | |
| 547 return i.reg(10, 8); | |
| 548 } | |
| 549 | |
| 550 RegisterList MemOpSPThumbLoad::defs(Instruction i) const { | |
| 551 return i.reg(10, 8); | |
| 552 } | |
| 553 | |
| 554 RegisterList DPMImm::defs(Instruction i) const { | |
| 555 return i.reg(27, 24); | |
| 556 } | |
| 557 | |
| 558 uint32_t get_thumb_modified_immediate(Instruction i) { | |
| 559 uint32_t raw = i.bits(23, 16); | |
| 560 uint8_t shift_mode = (((i.bits(10, 10) << 3) | i.bits(30, 28)) << 1) | |
| 561 | i.bits(23, 23); | |
| 562 switch (shift_mode >> 1) { | |
| 563 case 0: return raw; | |
| 564 case 1: return (raw << 16) | raw; | |
| 565 case 2: return ((raw << 16) | raw) << 8; | |
| 566 case 3: return (((((raw << 8) | raw) << 8) | raw) << 8) | raw; | |
| 567 default: return (raw | (1 << 7)) << (31 - 7 - (shift_mode - 8)); | |
| 568 }; | |
| 569 } | |
| 570 | |
| 571 bool BicModImmT::clears_bits(Instruction i, uint32_t mask) const { | |
| 572 return (get_thumb_modified_immediate(i) & mask) == mask; | |
| 573 } | |
| 574 | |
| 575 bool OrrModImmT::sets_bits(Instruction i, uint32_t mask) const { | |
| 576 return get_thumb_modified_immediate(i) == mask; | |
| 577 } | |
| 578 | |
| 579 RegisterList MovT::defs(Instruction i) const { | |
| 580 return Register((i.bits(7, 7) << 3) | i.bits(2, 0)); | |
| 581 } | |
| 582 | |
| 583 Register BXT::branch_target_register(Instruction i) const { | |
| 584 return i.reg(6, 3); | |
| 585 } | |
| 586 | |
| 587 int32_t BLT::branch_target_offset(Instruction i) const { | |
| 588 return get_stretched_immediate(i); | |
| 589 } | |
| 590 | |
| 591 ITCond IT::it_sequence(Instruction i) const { | |
| 592 uint8_t firstmask = i.bit(4); | |
| 593 ITCond base = it_set(0, THEN, 0); | |
| 594 uint8_t maskdex = 0; | |
| 595 while (i.bit(maskdex) == 0) | |
| 596 maskdex++; | |
| 597 // TODO(mrm) Add a guard to the parse table to make sure the mask is never 0 | |
|
Karl
2011/08/30 19:53:52
This scares me. What if the value is all zero?
| |
| 598 maskdex++; | |
| 599 for (uint8_t conddex = 1; maskdex < 4; maskdex++, conddex++) { | |
| 600 base = it_set(conddex, i.bit(maskdex) == firstmask ? THEN : ELSE, base); | |
| 601 } | |
| 602 return base; | |
| 603 } | |
| 604 | |
| 605 Instruction::Condition IT::condition(Instruction i) const { | |
| 606 return (Instruction::Condition)i.bits(7, 4); | |
| 607 } | |
| 608 | |
| 609 RegisterList STMTD::defs(Instruction i) const { | |
| 610 return i.reg(3, 0); | |
| 611 } | |
| 612 | |
| 613 Register STMTD::base_address_register(Instruction i) const { | |
| 614 return i.reg(3, 0); | |
| 615 } | |
| 616 | |
| 617 RegisterList STMTD::immediate_addressing_defs(Instruction i) const { | |
| 618 return base_address_register(i); | |
| 619 } | |
| 620 | |
| 621 RegisterList LDMTD::defs(Instruction i) const { | |
| 622 return i.reg(3, 0) + RegisterList(i.bits(12, 0)); | |
| 623 } | |
| 624 | |
| 625 Register StrS::base_address_register(Instruction i) const { | |
| 626 return i.reg(3, 0); | |
| 627 } | |
| 628 | |
| 629 // Note that while this doesn't always write something to i.reg(3, 0), it is | |
| 630 // safe to pretend that it does. | |
| 631 RegisterList StrS::defs(Instruction i) const { | |
| 632 return i.reg(3, 0); | |
| 633 } | |
| 634 | |
| 635 Register LDRImmT3::base_address_register(Instruction i) const { | |
| 636 return i.reg(3, 0); | |
| 637 } | |
| 638 | |
| 639 RegisterList LDRImmT4::defs(Instruction i) const { | |
| 640 if (i.bit(8 + 16)) { | |
| 641 return base_address_register(i); // Writeback | |
| 642 } else { | |
| 643 return kRegisterNone; | |
| 644 } | |
| 645 } | |
| 646 | |
| 647 RegisterList LDRImmT4::immediate_addressing_defs(Instruction i) const { | |
| 648 return defs(i); | |
| 649 } | |
| 650 | |
| 651 RegisterList Def31_18::defs(Instruction i) const { | |
| 652 return i.reg(31, 18); | |
| 653 } | |
| 654 | |
| 655 RegisterList StrEx::defs(Instruction i) const { | |
| 656 return immediate_addressing_defs(i) + i.reg(11 + 16, 8 + 16); | |
| 657 } | |
| 658 | |
| 659 RegisterList StrEx::immediate_addressing_defs(Instruction i) const { | |
| 660 if (i.bit(5)) | |
| 661 return base_address_register(i); | |
| 662 return kRegisterNone; | |
| 663 } | |
| 664 | |
| 665 Register StrEx::base_address_register(Instruction i) const { | |
| 666 return i.reg(3, 0); | |
| 667 } | |
| 668 | |
| 669 RegisterList LdrEx::defs(Instruction i) const { | |
| 670 return immediate_addressing_defs(i) + i.reg(15 + 16, 12 + 16); | |
|
Karl
2011/08/30 19:53:52
I notice that numbers like 8/16 are used a lot. It
| |
| 671 } | |
| 672 | |
| 673 RegisterList StrD::defs(Instruction i) const { | |
| 674 return immediate_addressing_defs(i); | |
| 675 } | |
| 676 | |
| 677 RegisterList LdrD::defs(Instruction i) const { | |
| 678 return immediate_addressing_defs(i) + i.reg(11 + 16, 8 + 16) | |
| 679 + i.reg(15 + 16, 12 + 16); | |
| 680 } | |
| 681 | |
| 682 RegisterList Def27_24::defs(Instruction i) const { | |
| 683 return i.reg(27, 24); | |
| 684 } | |
| 685 | |
| 686 bool ThumbBreakpoint::is_literal_pool_head(Instruction i) const { | |
| 687 UNREFERENCED_PARAMETER(i); | |
| 688 return true; //TODO We ideally want to think about conditions, but due to the | |
| 689 //rule that IT cannot straddle a boundary, and this has to start | |
| 690 //a bundle, we're fine. | |
| 691 } | |
| 692 | |
| 422 } // namespace | 693 } // namespace |
| OLD | NEW |