diff options
Diffstat (limited to 'tools/objtool/builtin-check.c')
-rw-r--r-- | tools/objtool/builtin-check.c | 60 |
1 files changed, 56 insertions, 4 deletions
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index e8a1f699058a..5fc52ee3264c 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c | |||
@@ -51,7 +51,7 @@ struct instruction { | |||
51 | unsigned int len, state; | 51 | unsigned int len, state; |
52 | unsigned char type; | 52 | unsigned char type; |
53 | unsigned long immediate; | 53 | unsigned long immediate; |
54 | bool alt_group, visited; | 54 | bool alt_group, visited, dead_end; |
55 | struct symbol *call_dest; | 55 | struct symbol *call_dest; |
56 | struct instruction *jump_dest; | 56 | struct instruction *jump_dest; |
57 | struct list_head alts; | 57 | struct list_head alts; |
@@ -330,6 +330,54 @@ static int decode_instructions(struct objtool_file *file) | |||
330 | } | 330 | } |
331 | 331 | ||
332 | /* | 332 | /* |
333 | * Find all uses of the unreachable() macro, which are code path dead ends. | ||
334 | */ | ||
335 | static int add_dead_ends(struct objtool_file *file) | ||
336 | { | ||
337 | struct section *sec; | ||
338 | struct rela *rela; | ||
339 | struct instruction *insn; | ||
340 | bool found; | ||
341 | |||
342 | sec = find_section_by_name(file->elf, ".rela__unreachable"); | ||
343 | if (!sec) | ||
344 | return 0; | ||
345 | |||
346 | list_for_each_entry(rela, &sec->rela_list, list) { | ||
347 | if (rela->sym->type != STT_SECTION) { | ||
348 | WARN("unexpected relocation symbol type in .rela__unreachable"); | ||
349 | return -1; | ||
350 | } | ||
351 | insn = find_insn(file, rela->sym->sec, rela->addend); | ||
352 | if (insn) | ||
353 | insn = list_prev_entry(insn, list); | ||
354 | else if (rela->addend == rela->sym->sec->len) { | ||
355 | found = false; | ||
356 | list_for_each_entry_reverse(insn, &file->insn_list, list) { | ||
357 | if (insn->sec == rela->sym->sec) { | ||
358 | found = true; | ||
359 | break; | ||
360 | } | ||
361 | } | ||
362 | |||
363 | if (!found) { | ||
364 | WARN("can't find unreachable insn at %s+0x%x", | ||
365 | rela->sym->sec->name, rela->addend); | ||
366 | return -1; | ||
367 | } | ||
368 | } else { | ||
369 | WARN("can't find unreachable insn at %s+0x%x", | ||
370 | rela->sym->sec->name, rela->addend); | ||
371 | return -1; | ||
372 | } | ||
373 | |||
374 | insn->dead_end = true; | ||
375 | } | ||
376 | |||
377 | return 0; | ||
378 | } | ||
379 | |||
380 | /* | ||
333 | * Warnings shouldn't be reported for ignored functions. | 381 | * Warnings shouldn't be reported for ignored functions. |
334 | */ | 382 | */ |
335 | static void add_ignores(struct objtool_file *file) | 383 | static void add_ignores(struct objtool_file *file) |
@@ -843,6 +891,10 @@ static int decode_sections(struct objtool_file *file) | |||
843 | if (ret) | 891 | if (ret) |
844 | return ret; | 892 | return ret; |
845 | 893 | ||
894 | ret = add_dead_ends(file); | ||
895 | if (ret) | ||
896 | return ret; | ||
897 | |||
846 | add_ignores(file); | 898 | add_ignores(file); |
847 | 899 | ||
848 | ret = add_jump_destinations(file); | 900 | ret = add_jump_destinations(file); |
@@ -1037,13 +1089,13 @@ static int validate_branch(struct objtool_file *file, | |||
1037 | 1089 | ||
1038 | return 0; | 1090 | return 0; |
1039 | 1091 | ||
1040 | case INSN_BUG: | ||
1041 | return 0; | ||
1042 | |||
1043 | default: | 1092 | default: |
1044 | break; | 1093 | break; |
1045 | } | 1094 | } |
1046 | 1095 | ||
1096 | if (insn->dead_end) | ||
1097 | return 0; | ||
1098 | |||
1047 | insn = next_insn_same_sec(file, insn); | 1099 | insn = next_insn_same_sec(file, insn); |
1048 | if (!insn) { | 1100 | if (!insn) { |
1049 | WARN("%s: unexpected end of section", sec->name); | 1101 | WARN("%s: unexpected end of section", sec->name); |