aboutsummaryrefslogtreecommitdiffstats
path: root/tools/objtool/check.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/objtool/check.c')
-rw-r--r--tools/objtool/check.c90
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) {