diff options
Diffstat (limited to 'tools/objtool/check.c')
-rw-r--r-- | tools/objtool/check.c | 46 |
1 files changed, 30 insertions, 16 deletions
diff --git a/tools/objtool/check.c b/tools/objtool/check.c index f49bf83e0501..0d9f9cfc27be 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -229,10 +229,18 @@ static void init_cfi_state(struct cfi_state *cfi) cfi->drap_offset = -1; } -static void clear_insn_state(struct insn_state *state) +static void init_insn_state(struct insn_state *state, struct section *sec) { memset(state, 0, sizeof(*state)); init_cfi_state(&state->cfi); + + /* + * We need the full vmlinux for noinstr validation, otherwise we can + * not correctly determine insn->call_dest->sec (external symbols do + * not have a section). + */ + if (vmlinux && sec) + state->noinstr = sec->noinstr; } /* @@ -2354,24 +2362,34 @@ static int validate_branch(struct objtool_file *file, struct symbol *func, return 0; } -static int validate_unwind_hints(struct objtool_file *file) +static int validate_unwind_hints(struct objtool_file *file, struct section *sec) { struct instruction *insn; - int ret, warnings = 0; struct insn_state state; + int ret, warnings = 0; if (!file->hints) return 0; - clear_insn_state(&state); + init_insn_state(&state, sec); - for_each_insn(file, insn) { + if (sec) { + insn = find_insn(file, sec, 0); + if (!insn) + return 0; + } else { + insn = list_first_entry(&file->insn_list, typeof(*insn), list); + } + + while (&insn->list != &file->insn_list && (!sec || insn->sec == sec)) { if (insn->hint && !insn->visited) { ret = validate_branch(file, insn->func, insn, state); if (ret && backtrace) BT_FUNC("<=== (hint)", insn); warnings += ret; } + + insn = list_next_entry(insn, list); } return warnings; @@ -2518,19 +2536,11 @@ static int validate_section(struct objtool_file *file, struct section *sec) struct symbol *func; int warnings = 0; - /* - * We need the full vmlinux for noinstr validation, otherwise we can - * not correctly determine insn->call_dest->sec (external symbols do - * not have a section). - */ - if (vmlinux) - state.noinstr = sec->noinstr; - list_for_each_entry(func, &sec->symbol_list, list) { if (func->type != STT_FUNC) continue; - clear_insn_state(&state); + init_insn_state(&state, sec); state.cfi.cfa = initial_func_cfi.cfa; memcpy(&state.cfi.regs, &initial_func_cfi.regs, CFI_NUM_REGS * sizeof(struct cfi_reg)); @@ -2545,12 +2555,16 @@ static int validate_section(struct objtool_file *file, struct section *sec) static int validate_vmlinux_functions(struct objtool_file *file) { struct section *sec; + int warnings = 0; sec = find_section_by_name(file->elf, ".noinstr.text"); if (!sec) return 0; - return validate_section(file, sec); + warnings += validate_section(file, sec); + warnings += validate_unwind_hints(file, sec); + + return warnings; } static int validate_functions(struct objtool_file *file) @@ -2635,7 +2649,7 @@ int check(const char *_objname, bool orc) goto out; warnings += ret; - ret = validate_unwind_hints(&file); + ret = validate_unwind_hints(&file, NULL); if (ret < 0) goto out; warnings += ret; |