The following commit has been merged into the objtool/core branch of tip: Commit-ID: d8ca70ffc3537f6fbc1c7e03ad80ff9ffe470076 Gitweb: https://git.kernel.org/tip/d8ca70ffc3537f6fbc1c7e03ad80ff9ffe470076 Author: Peter Zijlstra <peterz@xxxxxxxxxxxxx> AuthorDate: Mon, 23 Mar 2020 18:26:03 +01:00 Committer: Peter Zijlstra <peterz@xxxxxxxxxxxxx> CommitterDate: Wed, 22 Apr 2020 23:10:08 +02:00 objtool: Add STT_NOTYPE noinstr validation Make sure to also check STT_NOTYPE symbols for noinstr violations. Signed-off-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx> Reviewed-by: Miroslav Benes <mbenes@xxxxxxx> Reviewed-by: Alexandre Chartre <alexandre.chartre@xxxxxxxxxx> Acked-by: Josh Poimboeuf <jpoimboe@xxxxxxxxxx> Link: https://lkml.kernel.org/r/20200416115119.465335884@xxxxxxxxxxxxx --- tools/objtool/check.c | 46 +++++++++++++++++++++++++++--------------- 1 file changed, 30 insertions(+), 16 deletions(-) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 1d455d6..f51c325 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; } /* @@ -2370,24 +2378,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; @@ -2534,19 +2552,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)); @@ -2561,12 +2571,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) @@ -2651,7 +2665,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;