diff options
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/objtool/arch.h | 5 | ||||
| -rw-r--r-- | tools/objtool/arch/x86/decode.c | 3 | ||||
| -rw-r--r-- | tools/objtool/builtin-check.c | 60 |
3 files changed, 58 insertions, 10 deletions
diff --git a/tools/objtool/arch.h b/tools/objtool/arch.h index f7350fcedc70..a59e061c0b4a 100644 --- a/tools/objtool/arch.h +++ b/tools/objtool/arch.h | |||
| @@ -31,9 +31,8 @@ | |||
| 31 | #define INSN_CALL_DYNAMIC 8 | 31 | #define INSN_CALL_DYNAMIC 8 |
| 32 | #define INSN_RETURN 9 | 32 | #define INSN_RETURN 9 |
| 33 | #define INSN_CONTEXT_SWITCH 10 | 33 | #define INSN_CONTEXT_SWITCH 10 |
| 34 | #define INSN_BUG 11 | 34 | #define INSN_NOP 11 |
| 35 | #define INSN_NOP 12 | 35 | #define INSN_OTHER 12 |
| 36 | #define INSN_OTHER 13 | ||
| 37 | #define INSN_LAST INSN_OTHER | 36 | #define INSN_LAST INSN_OTHER |
| 38 | 37 | ||
| 39 | int arch_decode_instruction(struct elf *elf, struct section *sec, | 38 | int arch_decode_instruction(struct elf *elf, struct section *sec, |
diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decode.c index 039636ffb6c8..6ac99e3266eb 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c | |||
| @@ -118,9 +118,6 @@ int arch_decode_instruction(struct elf *elf, struct section *sec, | |||
| 118 | op2 == 0x35) | 118 | op2 == 0x35) |
| 119 | /* sysenter, sysret */ | 119 | /* sysenter, sysret */ |
| 120 | *type = INSN_CONTEXT_SWITCH; | 120 | *type = INSN_CONTEXT_SWITCH; |
| 121 | else if (op2 == 0x0b || op2 == 0xb9) | ||
| 122 | /* ud2 */ | ||
| 123 | *type = INSN_BUG; | ||
| 124 | else if (op2 == 0x0d || op2 == 0x1f) | 121 | else if (op2 == 0x0d || op2 == 0x1f) |
| 125 | /* nopl/nopw */ | 122 | /* nopl/nopw */ |
| 126 | *type = INSN_NOP; | 123 | *type = INSN_NOP; |
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); |
