diff options
Diffstat (limited to 'tools/objtool/builtin-check.c')
-rw-r--r-- | tools/objtool/builtin-check.c | 128 |
1 files changed, 55 insertions, 73 deletions
diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index fe248044415b..46a898595390 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -66,9 +66,8 @@ struct objtool_file { const char *objname; static bool nofp; -static struct instruction *find_instruction(struct objtool_file *file, - struct section *sec, - unsigned long offset) +static struct instruction *find_insn(struct objtool_file *file, + struct section *sec, unsigned long offset) { struct instruction *insn; @@ -79,6 +78,31 @@ static struct instruction *find_instruction(struct objtool_file *file, return NULL; } +static struct instruction *next_insn_same_sec(struct objtool_file *file, + struct instruction *insn) +{ + struct instruction *next = list_next_entry(insn, list); + + if (&next->list == &file->insns || next->sec != insn->sec) + return NULL; + + return next; +} + +#define for_each_insn(file, insn) \ + list_for_each_entry(insn, &file->insns, list) + +#define func_for_each_insn(file, func, insn) \ + for (insn = find_insn(file, func->sec, func->offset); \ + insn && &insn->list != &file->insns && \ + insn->sec == func->sec && \ + insn->offset < func->offset + func->len; \ + insn = list_next_entry(insn, list)) + +#define sec_for_each_insn_from(file, insn) \ + for (; insn; insn = next_insn_same_sec(file, insn)) + + /* * Check if the function has been manually whitelisted with the * STACK_FRAME_NON_STANDARD macro, or if it should be automatically whitelisted @@ -99,16 +123,9 @@ static bool ignore_func(struct objtool_file *file, struct symbol *func) return true; /* check if it has a context switching instruction */ - insn = find_instruction(file, func->sec, func->offset); - if (!insn) - return false; - list_for_each_entry_from(insn, &file->insns, list) { - if (insn->sec != func->sec || - insn->offset >= func->offset + func->len) - break; + func_for_each_insn(file, func, insn) if (insn->type == INSN_CONTEXT_SWITCH) return true; - } return false; } @@ -131,7 +148,7 @@ static int __dead_end_function(struct objtool_file *file, struct symbol *func, int recursion) { int i; - struct instruction *insn, *func_insn; + struct instruction *insn; bool empty = true; /* @@ -160,16 +177,7 @@ static int __dead_end_function(struct objtool_file *file, struct symbol *func, if (!func->sec) return 0; - func_insn = find_instruction(file, func->sec, func->offset); - if (!func_insn) - return 0; - - insn = func_insn; - list_for_each_entry_from(insn, &file->insns, list) { - if (insn->sec != func->sec || - insn->offset >= func->offset + func->len) - break; - + func_for_each_insn(file, func, insn) { empty = false; if (insn->type == INSN_RETURN) @@ -184,8 +192,7 @@ static int __dead_end_function(struct objtool_file *file, struct symbol *func, * case, the function's dead-end status depends on whether the target * of the sibling call returns. */ - insn = func_insn; - list_for_each_entry_from(insn, &file->insns, list) { + func_for_each_insn(file, func, insn) { if (insn->sec != func->sec || insn->offset >= func->offset + func->len) break; @@ -294,17 +301,8 @@ static void get_ignores(struct objtool_file *file) if (!ignore_func(file, func)) continue; - insn = find_instruction(file, sec, func->offset); - if (!insn) - continue; - - list_for_each_entry_from(insn, &file->insns, list) { - if (insn->sec != func->sec || - insn->offset >= func->offset + func->len) - break; - + func_for_each_insn(file, func, insn) insn->visited = true; - } } } } @@ -319,7 +317,7 @@ static int get_jump_destinations(struct objtool_file *file) struct section *dest_sec; unsigned long dest_off; - list_for_each_entry(insn, &file->insns, list) { + for_each_insn(file, insn) { if (insn->type != INSN_JUMP_CONDITIONAL && insn->type != INSN_JUMP_UNCONDITIONAL) continue; @@ -345,7 +343,7 @@ static int get_jump_destinations(struct objtool_file *file) continue; } - insn->jump_dest = find_instruction(file, dest_sec, dest_off); + insn->jump_dest = find_insn(file, dest_sec, dest_off); if (!insn->jump_dest) { /* @@ -375,7 +373,7 @@ static int get_call_destinations(struct objtool_file *file) unsigned long dest_off; struct rela *rela; - list_for_each_entry(insn, &file->insns, list) { + for_each_insn(file, insn) { if (insn->type != INSN_CALL) continue; @@ -438,9 +436,8 @@ static int handle_group_alt(struct objtool_file *file, last_orig_insn = NULL; insn = orig_insn; - list_for_each_entry_from(insn, &file->insns, list) { - if (insn->sec != special_alt->orig_sec || - insn->offset >= special_alt->orig_off + special_alt->orig_len) + sec_for_each_insn_from(file, insn) { + if (insn->offset >= special_alt->orig_off + special_alt->orig_len) break; if (special_alt->skip_orig) @@ -450,8 +447,7 @@ static int handle_group_alt(struct objtool_file *file, last_orig_insn = insn; } - if (list_is_last(&last_orig_insn->list, &file->insns) || - list_next_entry(last_orig_insn, list)->sec != special_alt->orig_sec) { + if (!next_insn_same_sec(file, last_orig_insn)) { WARN("%s: don't know how to handle alternatives at end of section", special_alt->orig_sec->name); return -1; @@ -476,9 +472,8 @@ static int handle_group_alt(struct objtool_file *file, last_new_insn = NULL; insn = *new_insn; - list_for_each_entry_from(insn, &file->insns, list) { - if (insn->sec != special_alt->new_sec || - insn->offset >= special_alt->new_off + special_alt->new_len) + sec_for_each_insn_from(file, insn) { + if (insn->offset >= special_alt->new_off + special_alt->new_len) break; last_new_insn = insn; @@ -561,8 +556,8 @@ static int get_special_section_alts(struct objtool_file *file) goto out; } - orig_insn = find_instruction(file, special_alt->orig_sec, - special_alt->orig_off); + orig_insn = find_insn(file, special_alt->orig_sec, + special_alt->orig_off); if (!orig_insn) { WARN_FUNC("special: can't find orig instruction", special_alt->orig_sec, special_alt->orig_off); @@ -572,8 +567,8 @@ static int get_special_section_alts(struct objtool_file *file) new_insn = NULL; if (!special_alt->group || special_alt->new_len) { - new_insn = find_instruction(file, special_alt->new_sec, - special_alt->new_off); + new_insn = find_insn(file, special_alt->new_sec, + special_alt->new_off); if (!new_insn) { WARN_FUNC("special: can't find new instruction", special_alt->new_sec, @@ -619,7 +614,7 @@ static int get_switch_alts(struct objtool_file *file) struct symbol *func; struct alternative *alt; - list_for_each_entry(insn, &file->insns, list) { + for_each_insn(file, insn) { if (insn->type != INSN_JUMP_DYNAMIC) continue; @@ -655,8 +650,7 @@ static int get_switch_alts(struct objtool_file *file) rela->addend >= func->offset + func->len) break; - alt_insn = find_instruction(file, insn->sec, - rela->addend); + alt_insn = find_insn(file, insn->sec, rela->addend); if (!alt_insn) { WARN("%s: can't find instruction at %s+0x%x", rodata->rela->name, insn->sec->name, @@ -881,9 +875,8 @@ static int validate_branch(struct objtool_file *file, break; } - insn = list_next_entry(insn, list); - - if (&insn->list == &file->insns || insn->sec != sec) { + insn = next_insn_same_sec(file, insn); + if (!insn) { WARN("%s: unexpected end of section", sec->name); warnings++; return warnings; @@ -934,8 +927,8 @@ static bool is_ubsan_insn(struct instruction *insn) "__ubsan_handle_builtin_unreachable")); } -static bool ignore_unreachable_insn(struct instruction *insn, - unsigned long func_end) +static bool ignore_unreachable_insn(struct symbol *func, + struct instruction *insn) { int i; @@ -961,7 +954,7 @@ static bool ignore_unreachable_insn(struct instruction *insn, continue; } - if (insn->offset + insn->len >= func_end) + if (insn->offset + insn->len >= func->offset + func->len) break; insn = list_next_entry(insn, list); } @@ -974,7 +967,6 @@ static int validate_functions(struct objtool_file *file) struct section *sec; struct symbol *func; struct instruction *insn; - unsigned long func_end; int ret, warnings = 0; list_for_each_entry(sec, &file->elf->sections, list) { @@ -982,7 +974,7 @@ static int validate_functions(struct objtool_file *file) if (func->type != STT_FUNC) continue; - insn = find_instruction(file, sec, func->offset); + insn = find_insn(file, sec, func->offset); if (!insn) { WARN("%s(): can't find starting instruction", func->name); @@ -1000,21 +992,11 @@ static int validate_functions(struct objtool_file *file) if (func->type != STT_FUNC) continue; - insn = find_instruction(file, sec, func->offset); - if (!insn) - continue; - - func_end = func->offset + func->len; - - list_for_each_entry_from(insn, &file->insns, list) { - if (insn->sec != func->sec || - insn->offset >= func_end) - break; - + func_for_each_insn(file, func, insn) { if (insn->visited) continue; - if (!ignore_unreachable_insn(insn, func_end)) { + if (!ignore_unreachable_insn(func, insn)) { WARN_FUNC("function has unreachable instruction", insn->sec, insn->offset); warnings++; } @@ -1032,7 +1014,7 @@ static int validate_uncallable_instructions(struct objtool_file *file) struct instruction *insn; int warnings = 0; - list_for_each_entry(insn, &file->insns, list) { + for_each_insn(file, insn) { if (!insn->visited && insn->type == INSN_RETURN) { WARN_FUNC("return instruction outside of a callable function", insn->sec, insn->offset); |