diff options
Diffstat (limited to 'tools/objtool/check.c')
-rw-r--r-- | tools/objtool/check.c | 90 |
1 files changed, 48 insertions, 42 deletions
diff --git a/tools/objtool/check.c b/tools/objtool/check.c index f40d46e24bcc..b00b1896547e 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c | |||
@@ -138,6 +138,7 @@ static int __dead_end_function(struct objtool_file *file, struct symbol *func, | |||
138 | "__reiserfs_panic", | 138 | "__reiserfs_panic", |
139 | "lbug_with_loc", | 139 | "lbug_with_loc", |
140 | "fortify_panic", | 140 | "fortify_panic", |
141 | "usercopy_abort", | ||
141 | }; | 142 | }; |
142 | 143 | ||
143 | if (func->bind == STB_WEAK) | 144 | if (func->bind == STB_WEAK) |
@@ -543,18 +544,14 @@ static int add_call_destinations(struct objtool_file *file) | |||
543 | dest_off = insn->offset + insn->len + insn->immediate; | 544 | dest_off = insn->offset + insn->len + insn->immediate; |
544 | insn->call_dest = find_symbol_by_offset(insn->sec, | 545 | insn->call_dest = find_symbol_by_offset(insn->sec, |
545 | dest_off); | 546 | dest_off); |
546 | /* | 547 | |
547 | * FIXME: Thanks to retpolines, it's now considered | 548 | if (!insn->call_dest && !insn->ignore) { |
548 | * normal for a function to call within itself. So | 549 | WARN_FUNC("unsupported intra-function call", |
549 | * disable this warning for now. | 550 | insn->sec, insn->offset); |
550 | */ | 551 | WARN("If this is a retpoline, please patch it in with alternatives and annotate it with ANNOTATE_NOSPEC_ALTERNATIVE."); |
551 | #if 0 | ||
552 | if (!insn->call_dest) { | ||
553 | WARN_FUNC("can't find call dest symbol at offset 0x%lx", | ||
554 | insn->sec, insn->offset, dest_off); | ||
555 | return -1; | 552 | return -1; |
556 | } | 553 | } |
557 | #endif | 554 | |
558 | } else if (rela->sym->type == STT_SECTION) { | 555 | } else if (rela->sym->type == STT_SECTION) { |
559 | insn->call_dest = find_symbol_by_offset(rela->sym->sec, | 556 | insn->call_dest = find_symbol_by_offset(rela->sym->sec, |
560 | rela->addend+4); | 557 | rela->addend+4); |
@@ -598,7 +595,7 @@ static int handle_group_alt(struct objtool_file *file, | |||
598 | struct instruction *orig_insn, | 595 | struct instruction *orig_insn, |
599 | struct instruction **new_insn) | 596 | struct instruction **new_insn) |
600 | { | 597 | { |
601 | struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump; | 598 | struct instruction *last_orig_insn, *last_new_insn, *insn, *fake_jump = NULL; |
602 | unsigned long dest_off; | 599 | unsigned long dest_off; |
603 | 600 | ||
604 | last_orig_insn = NULL; | 601 | last_orig_insn = NULL; |
@@ -614,28 +611,30 @@ static int handle_group_alt(struct objtool_file *file, | |||
614 | last_orig_insn = insn; | 611 | last_orig_insn = insn; |
615 | } | 612 | } |
616 | 613 | ||
617 | if (!next_insn_same_sec(file, last_orig_insn)) { | 614 | if (next_insn_same_sec(file, last_orig_insn)) { |
618 | WARN("%s: don't know how to handle alternatives at end of section", | 615 | fake_jump = malloc(sizeof(*fake_jump)); |
619 | special_alt->orig_sec->name); | 616 | if (!fake_jump) { |
620 | return -1; | 617 | WARN("malloc failed"); |
621 | } | 618 | return -1; |
622 | 619 | } | |
623 | fake_jump = malloc(sizeof(*fake_jump)); | 620 | memset(fake_jump, 0, sizeof(*fake_jump)); |
624 | if (!fake_jump) { | 621 | INIT_LIST_HEAD(&fake_jump->alts); |
625 | WARN("malloc failed"); | 622 | clear_insn_state(&fake_jump->state); |
626 | return -1; | 623 | |
624 | fake_jump->sec = special_alt->new_sec; | ||
625 | fake_jump->offset = -1; | ||
626 | fake_jump->type = INSN_JUMP_UNCONDITIONAL; | ||
627 | fake_jump->jump_dest = list_next_entry(last_orig_insn, list); | ||
628 | fake_jump->ignore = true; | ||
627 | } | 629 | } |
628 | memset(fake_jump, 0, sizeof(*fake_jump)); | ||
629 | INIT_LIST_HEAD(&fake_jump->alts); | ||
630 | clear_insn_state(&fake_jump->state); | ||
631 | |||
632 | fake_jump->sec = special_alt->new_sec; | ||
633 | fake_jump->offset = -1; | ||
634 | fake_jump->type = INSN_JUMP_UNCONDITIONAL; | ||
635 | fake_jump->jump_dest = list_next_entry(last_orig_insn, list); | ||
636 | fake_jump->ignore = true; | ||
637 | 630 | ||
638 | if (!special_alt->new_len) { | 631 | if (!special_alt->new_len) { |
632 | if (!fake_jump) { | ||
633 | WARN("%s: empty alternative at end of section", | ||
634 | special_alt->orig_sec->name); | ||
635 | return -1; | ||
636 | } | ||
637 | |||
639 | *new_insn = fake_jump; | 638 | *new_insn = fake_jump; |
640 | return 0; | 639 | return 0; |
641 | } | 640 | } |
@@ -648,6 +647,8 @@ static int handle_group_alt(struct objtool_file *file, | |||
648 | 647 | ||
649 | last_new_insn = insn; | 648 | last_new_insn = insn; |
650 | 649 | ||
650 | insn->ignore = orig_insn->ignore_alts; | ||
651 | |||
651 | if (insn->type != INSN_JUMP_CONDITIONAL && | 652 | if (insn->type != INSN_JUMP_CONDITIONAL && |
652 | insn->type != INSN_JUMP_UNCONDITIONAL) | 653 | insn->type != INSN_JUMP_UNCONDITIONAL) |
653 | continue; | 654 | continue; |
@@ -656,8 +657,14 @@ static int handle_group_alt(struct objtool_file *file, | |||
656 | continue; | 657 | continue; |
657 | 658 | ||
658 | dest_off = insn->offset + insn->len + insn->immediate; | 659 | dest_off = insn->offset + insn->len + insn->immediate; |
659 | if (dest_off == special_alt->new_off + special_alt->new_len) | 660 | if (dest_off == special_alt->new_off + special_alt->new_len) { |
661 | if (!fake_jump) { | ||
662 | WARN("%s: alternative jump to end of section", | ||
663 | special_alt->orig_sec->name); | ||
664 | return -1; | ||
665 | } | ||
660 | insn->jump_dest = fake_jump; | 666 | insn->jump_dest = fake_jump; |
667 | } | ||
661 | 668 | ||
662 | if (!insn->jump_dest) { | 669 | if (!insn->jump_dest) { |
663 | WARN_FUNC("can't find alternative jump destination", | 670 | WARN_FUNC("can't find alternative jump destination", |
@@ -672,7 +679,8 @@ static int handle_group_alt(struct objtool_file *file, | |||
672 | return -1; | 679 | return -1; |
673 | } | 680 | } |
674 | 681 | ||
675 | list_add(&fake_jump->list, &last_new_insn->list); | 682 | if (fake_jump) |
683 | list_add(&fake_jump->list, &last_new_insn->list); | ||
676 | 684 | ||
677 | return 0; | 685 | return 0; |
678 | } | 686 | } |
@@ -729,10 +737,6 @@ static int add_special_section_alts(struct objtool_file *file) | |||
729 | goto out; | 737 | goto out; |
730 | } | 738 | } |
731 | 739 | ||
732 | /* Ignore retpoline alternatives. */ | ||
733 | if (orig_insn->ignore_alts) | ||
734 | continue; | ||
735 | |||
736 | new_insn = NULL; | 740 | new_insn = NULL; |
737 | if (!special_alt->group || special_alt->new_len) { | 741 | if (!special_alt->group || special_alt->new_len) { |
738 | new_insn = find_insn(file, special_alt->new_sec, | 742 | new_insn = find_insn(file, special_alt->new_sec, |
@@ -1089,11 +1093,11 @@ static int decode_sections(struct objtool_file *file) | |||
1089 | if (ret) | 1093 | if (ret) |
1090 | return ret; | 1094 | return ret; |
1091 | 1095 | ||
1092 | ret = add_call_destinations(file); | 1096 | ret = add_special_section_alts(file); |
1093 | if (ret) | 1097 | if (ret) |
1094 | return ret; | 1098 | return ret; |
1095 | 1099 | ||
1096 | ret = add_special_section_alts(file); | 1100 | ret = add_call_destinations(file); |
1097 | if (ret) | 1101 | if (ret) |
1098 | return ret; | 1102 | return ret; |
1099 | 1103 | ||
@@ -1720,10 +1724,12 @@ static int validate_branch(struct objtool_file *file, struct instruction *first, | |||
1720 | 1724 | ||
1721 | insn->visited = true; | 1725 | insn->visited = true; |
1722 | 1726 | ||
1723 | list_for_each_entry(alt, &insn->alts, list) { | 1727 | if (!insn->ignore_alts) { |
1724 | ret = validate_branch(file, alt->insn, state); | 1728 | list_for_each_entry(alt, &insn->alts, list) { |
1725 | if (ret) | 1729 | ret = validate_branch(file, alt->insn, state); |
1726 | return 1; | 1730 | if (ret) |
1731 | return 1; | ||
1732 | } | ||
1727 | } | 1733 | } |
1728 | 1734 | ||
1729 | switch (insn->type) { | 1735 | switch (insn->type) { |