summaryrefslogtreecommitdiffstats
path: root/tools/objtool/check.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/objtool/check.c')
-rw-r--r--tools/objtool/check.c53
1 files changed, 48 insertions, 5 deletions
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index b00b1896547e..a8cb69a26576 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -852,8 +852,14 @@ static int add_switch_table(struct objtool_file *file, struct symbol *func,
852 * This is a fairly uncommon pattern which is new for GCC 6. As of this 852 * This is a fairly uncommon pattern which is new for GCC 6. As of this
853 * writing, there are 11 occurrences of it in the allmodconfig kernel. 853 * writing, there are 11 occurrences of it in the allmodconfig kernel.
854 * 854 *
855 * As of GCC 7 there are quite a few more of these and the 'in between' code
856 * is significant. Esp. with KASAN enabled some of the code between the mov
857 * and jmpq uses .rodata itself, which can confuse things.
858 *
855 * TODO: Once we have DWARF CFI and smarter instruction decoding logic, 859 * TODO: Once we have DWARF CFI and smarter instruction decoding logic,
856 * ensure the same register is used in the mov and jump instructions. 860 * ensure the same register is used in the mov and jump instructions.
861 *
862 * NOTE: RETPOLINE made it harder still to decode dynamic jumps.
857 */ 863 */
858static struct rela *find_switch_table(struct objtool_file *file, 864static struct rela *find_switch_table(struct objtool_file *file,
859 struct symbol *func, 865 struct symbol *func,
@@ -875,12 +881,25 @@ static struct rela *find_switch_table(struct objtool_file *file,
875 text_rela->addend + 4); 881 text_rela->addend + 4);
876 if (!rodata_rela) 882 if (!rodata_rela)
877 return NULL; 883 return NULL;
884
878 file->ignore_unreachables = true; 885 file->ignore_unreachables = true;
879 return rodata_rela; 886 return rodata_rela;
880 } 887 }
881 888
882 /* case 3 */ 889 /* case 3 */
883 func_for_each_insn_continue_reverse(file, func, insn) { 890 /*
891 * Backward search using the @first_jump_src links, these help avoid
892 * much of the 'in between' code. Which avoids us getting confused by
893 * it.
894 */
895 for (insn = list_prev_entry(insn, list);
896
897 &insn->list != &file->insn_list &&
898 insn->sec == func->sec &&
899 insn->offset >= func->offset;
900
901 insn = insn->first_jump_src ?: list_prev_entry(insn, list)) {
902
884 if (insn->type == INSN_JUMP_DYNAMIC) 903 if (insn->type == INSN_JUMP_DYNAMIC)
885 break; 904 break;
886 905
@@ -910,14 +929,32 @@ static struct rela *find_switch_table(struct objtool_file *file,
910 return NULL; 929 return NULL;
911} 930}
912 931
932
913static int add_func_switch_tables(struct objtool_file *file, 933static int add_func_switch_tables(struct objtool_file *file,
914 struct symbol *func) 934 struct symbol *func)
915{ 935{
916 struct instruction *insn, *prev_jump = NULL; 936 struct instruction *insn, *last = NULL, *prev_jump = NULL;
917 struct rela *rela, *prev_rela = NULL; 937 struct rela *rela, *prev_rela = NULL;
918 int ret; 938 int ret;
919 939
920 func_for_each_insn(file, func, insn) { 940 func_for_each_insn(file, func, insn) {
941 if (!last)
942 last = insn;
943
944 /*
945 * Store back-pointers for unconditional forward jumps such
946 * that find_switch_table() can back-track using those and
947 * avoid some potentially confusing code.
948 */
949 if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest &&
950 insn->offset > last->offset &&
951 insn->jump_dest->offset > insn->offset &&
952 !insn->jump_dest->first_jump_src) {
953
954 insn->jump_dest->first_jump_src = insn;
955 last = insn->jump_dest;
956 }
957
921 if (insn->type != INSN_JUMP_DYNAMIC) 958 if (insn->type != INSN_JUMP_DYNAMIC)
922 continue; 959 continue;
923 960
@@ -1899,13 +1936,19 @@ static bool ignore_unreachable_insn(struct instruction *insn)
1899 if (is_kasan_insn(insn) || is_ubsan_insn(insn)) 1936 if (is_kasan_insn(insn) || is_ubsan_insn(insn))
1900 return true; 1937 return true;
1901 1938
1902 if (insn->type == INSN_JUMP_UNCONDITIONAL && insn->jump_dest) { 1939 if (insn->type == INSN_JUMP_UNCONDITIONAL) {
1903 insn = insn->jump_dest; 1940 if (insn->jump_dest &&
1904 continue; 1941 insn->jump_dest->func == insn->func) {
1942 insn = insn->jump_dest;
1943 continue;
1944 }
1945
1946 break;
1905 } 1947 }
1906 1948
1907 if (insn->offset + insn->len >= insn->func->offset + insn->func->len) 1949 if (insn->offset + insn->len >= insn->func->offset + insn->func->len)
1908 break; 1950 break;
1951
1909 insn = list_next_entry(insn, list); 1952 insn = list_next_entry(insn, list);
1910 } 1953 }
1911 1954