In preparation for klp-build, enable "classic" objtool to work on livepatch modules:
- Avoid duplicate symbol/section warnings for prefix symbols and the .static_call_sites and __mcount_loc sections which may have already been extracted by klp diff. - Add __klp_funcs to the IBT function pointer section whitelist. - Prevent KLP symbols from getting incorrectly classified as cold subfunctions. Signed-off-by: Josh Poimboeuf <jpoim...@kernel.org> --- tools/objtool/check.c | 52 ++++++++++++++++++++++--- tools/objtool/elf.c | 5 ++- tools/objtool/include/objtool/elf.h | 1 + tools/objtool/include/objtool/objtool.h | 2 +- 4 files changed, 53 insertions(+), 7 deletions(-) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 6a9ce090a2cde..ba591a325d52e 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -3,6 +3,7 @@ * Copyright (C) 2015-2017 Josh Poimboeuf <jpoim...@redhat.com> */ +#define _GNU_SOURCE /* memmem() */ #include <string.h> #include <stdlib.h> #include <inttypes.h> @@ -611,6 +612,20 @@ static int init_pv_ops(struct objtool_file *file) return 0; } +static bool is_livepatch_module(struct objtool_file *file) +{ + struct section *sec; + + if (!opts.module) + return false; + + sec = find_section_by_name(file->elf, ".modinfo"); + if (!sec) + return false; + + return memmem(sec->data->d_buf, sec_size(sec), "\0livepatch=Y", 12); +} + static int create_static_call_sections(struct objtool_file *file) { struct static_call_site *site; @@ -622,7 +637,14 @@ static int create_static_call_sections(struct objtool_file *file) sec = find_section_by_name(file->elf, ".static_call_sites"); if (sec) { - WARN("file already has .static_call_sites section, skipping"); + /* + * Livepatch modules may have already extracted the static call + * site entries to take advantage of vmlinux static call + * privileges. + */ + if (!file->klp) + WARN("file already has .static_call_sites section, skipping"); + return 0; } @@ -666,7 +688,7 @@ static int create_static_call_sections(struct objtool_file *file) key_sym = find_symbol_by_name(file->elf, tmp); if (!key_sym) { - if (!opts.module) { + if (!opts.module || file->klp) { ERROR("static_call: can't find static_call_key symbol: %s", tmp); return -1; } @@ -885,7 +907,13 @@ static int create_mcount_loc_sections(struct objtool_file *file) sec = find_section_by_name(file->elf, "__mcount_loc"); if (sec) { - WARN("file already has __mcount_loc section, skipping"); + /* + * Livepatch modules have already extracted their __mcount_loc + * entries to cover the !CONFIG_FTRACE_MCOUNT_USE_OBJTOOL case. + */ + if (!file->klp) + WARN("file already has __mcount_loc section, skipping"); + return 0; } @@ -2579,6 +2607,8 @@ static bool validate_branch_enabled(void) static int decode_sections(struct objtool_file *file) { + file->klp = is_livepatch_module(file); + mark_rodata(file); if (init_pv_ops(file)) @@ -4254,6 +4284,9 @@ static bool ignore_unreachable_insn(struct objtool_file *file, struct instructio * - compiler cloned functions (*.cold, *.part0, etc) * - asm functions created with inline asm or without SYM_FUNC_START() * + * Also, the function may already have a prefix from a previous objtool run + * (livepatch extracted functions, or manually running objtool multiple times). + * * So return 0 if the NOPs are missing or the function already has a prefix * symbol. */ @@ -4276,6 +4309,14 @@ static int create_prefix_symbol(struct objtool_file *file, struct symbol *func) if (snprintf_check(name, SYM_NAME_LEN, "__pfx_%s", func->name)) return -1; + if (file->klp) { + struct symbol *pfx; + + pfx = find_symbol_by_offset(func->sec, func->offset - opts.prefix); + if (pfx && is_prefix_func(pfx) && !strcmp(pfx->name, name)) + return 0; + } + insn = find_insn(file, func->sec, func->offset); if (!insn) { WARN("%s: can't find starting instruction", func->name); @@ -4628,6 +4669,7 @@ static int validate_ibt(struct objtool_file *file) !strncmp(sec->name, ".debug", 6) || !strcmp(sec->name, ".altinstructions") || !strcmp(sec->name, ".ibt_endbr_seal") || + !strcmp(sec->name, ".kcfi_traps") || !strcmp(sec->name, ".orc_unwind_ip") || !strcmp(sec->name, ".retpoline_sites") || !strcmp(sec->name, ".smp_locks") || @@ -4637,12 +4679,12 @@ static int validate_ibt(struct objtool_file *file) !strcmp(sec->name, "__bug_table") || !strcmp(sec->name, "__ex_table") || !strcmp(sec->name, "__jump_table") || + !strcmp(sec->name, "__klp_funcs") || !strcmp(sec->name, "__mcount_loc") || - !strcmp(sec->name, ".kcfi_traps") || !strcmp(sec->name, ".llvm.call-graph-profile") || !strcmp(sec->name, ".llvm_bb_addr_map") || !strcmp(sec->name, "__tracepoints") || - strstr(sec->name, "__patchable_function_entries")) + !strcmp(sec->name, "__patchable_function_entries")) continue; for_each_reloc(sec->rsec, reloc) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 4bb7ce994b6a7..5feeefc7fc8f8 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -499,7 +499,10 @@ static int elf_add_symbol(struct elf *elf, struct symbol *sym) strstarts(sym->name, "__pi___cfi_"))) sym->prefix = 1; - if (is_func_sym(sym) && strstr(sym->name, ".cold")) + if (strstarts(sym->name, ".klp.sym")) + sym->klp = 1; + + if (!sym->klp && is_func_sym(sym) && strstr(sym->name, ".cold")) sym->cold = 1; sym->pfunc = sym->cfunc = sym; diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 60f844e43c5a2..21d8b825fd8f0 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -88,6 +88,7 @@ struct symbol { u8 debug_checksum : 1; u8 changed : 1; u8 included : 1; + u8 klp : 1; struct list_head pv_target; struct reloc *relocs; struct section *group_sec; diff --git a/tools/objtool/include/objtool/objtool.h b/tools/objtool/include/objtool/objtool.h index 7f70b41d1b8db..f7051bbe0bcb2 100644 --- a/tools/objtool/include/objtool/objtool.h +++ b/tools/objtool/include/objtool/objtool.h @@ -28,7 +28,7 @@ struct objtool_file { struct list_head mcount_loc_list; struct list_head endbr_list; struct list_head call_list; - bool ignore_unreachables, hints, rodata; + bool ignore_unreachables, hints, rodata, klp; unsigned int nr_endbr; unsigned int nr_endbr_int; -- 2.50.0