From: Alexandre Chartre Date: Fri, 21 Nov 2025 09:53:27 +0000 (+0100) Subject: objtool: Add the --disas= action X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=5f326c88973691232c0e56ced83c199d53d86766;p=thirdparty%2Fkernel%2Flinux.git objtool: Add the --disas= action Add the --disas= actions to disassemble the specified functions. The function pattern can be a single function name (e.g. --disas foo to disassemble the function with the name "foo"), or a shell wildcard pattern (e.g. --disas foo* to disassemble all functions with a name starting with "foo"). Signed-off-by: Alexandre Chartre Signed-off-by: Peter Zijlstra (Intel) Acked-by: Josh Poimboeuf Link: https://patch.msgid.link/20251121095340.464045-18-alexandre.chartre@oracle.com --- diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index 3329d370006b4..a0371312fe55a 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -75,6 +75,7 @@ static const struct option check_options[] = { OPT_GROUP("Actions:"), OPT_BOOLEAN(0, "checksum", &opts.checksum, "generate per-function checksums"), OPT_BOOLEAN(0, "cfi", &opts.cfi, "annotate kernel control flow integrity (kCFI) function preambles"), + OPT_STRING_OPTARG('d', "disas", &opts.disas, "function-pattern", "disassemble functions", "*"), OPT_CALLBACK_OPTARG('h', "hacks", NULL, NULL, "jump_label,noinstr,skylake", "patch toolchain bugs/limitations", parse_hacks), OPT_BOOLEAN('i', "ibt", &opts.ibt, "validate and annotate IBT"), OPT_BOOLEAN('m', "mcount", &opts.mcount, "annotate mcount/fentry calls for ftrace"), @@ -176,6 +177,7 @@ static bool opts_valid(void) } if (opts.checksum || + opts.disas || opts.hack_jump_label || opts.hack_noinstr || opts.ibt || diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 4ebadf94f8af2..9cd9f9d4f6565 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -2611,7 +2611,7 @@ static int decode_sections(struct objtool_file *file) * Must be before add_jump_destinations(), which depends on 'func' * being set for alternatives, to enable proper sibling call detection. */ - if (validate_branch_enabled() || opts.noinstr || opts.hack_jump_label) { + if (validate_branch_enabled() || opts.noinstr || opts.hack_jump_label || opts.disas) { if (add_special_section_alts(file)) return -1; } @@ -4915,14 +4915,15 @@ int check(struct objtool_file *file) int ret = 0, warnings = 0; /* - * If the verbose or backtrace option is used then we need a - * disassembly context to disassemble instruction or function - * on warning or backtrace. + * Create a disassembly context if we might disassemble any + * instruction or function. */ - if (opts.verbose || opts.backtrace || opts.trace) { + if (opts.verbose || opts.backtrace || opts.trace || opts.disas) { disas_ctx = disas_context_create(file); - if (!disas_ctx) + if (!disas_ctx) { + opts.disas = false; opts.trace = false; + } objtool_disas_ctx = disas_ctx; } @@ -5054,20 +5055,20 @@ int check(struct objtool_file *file) } out: - if (!ret && !warnings) { - free_insns(file); - return 0; - } - - if (opts.werror && warnings) - ret = 1; - - if (opts.verbose) { + if (ret || warnings) { if (opts.werror && warnings) - WARN("%d warning(s) upgraded to errors", warnings); - disas_warned_funcs(disas_ctx); + ret = 1; + + if (opts.verbose) { + if (opts.werror && warnings) + WARN("%d warning(s) upgraded to errors", warnings); + disas_warned_funcs(disas_ctx); + } } + if (opts.disas) + disas_funcs(disas_ctx); + if (disas_ctx) { disas_context_destroy(disas_ctx); objtool_disas_ctx = NULL; @@ -5075,6 +5076,9 @@ out: free_insns(file); + if (!ret && !warnings) + return 0; + if (opts.backup && make_backup()) return 1; diff --git a/tools/objtool/disas.c b/tools/objtool/disas.c index b53be240825da..9cc952e03c356 100644 --- a/tools/objtool/disas.c +++ b/tools/objtool/disas.c @@ -4,6 +4,7 @@ */ #define _GNU_SOURCE +#include #include #include @@ -556,3 +557,29 @@ void disas_warned_funcs(struct disas_context *dctx) disas_func(dctx, sym); } } + +void disas_funcs(struct disas_context *dctx) +{ + bool disas_all = !strcmp(opts.disas, "*"); + struct section *sec; + struct symbol *sym; + + for_each_sec(dctx->file->elf, sec) { + + if (!(sec->sh.sh_flags & SHF_EXECINSTR)) + continue; + + sec_for_each_sym(sec, sym) { + /* + * If the function had a warning and the verbose + * option is used then the function was already + * disassemble. + */ + if (opts.verbose && sym->warned) + continue; + + if (disas_all || fnmatch(opts.disas, sym->name, 0) == 0) + disas_func(dctx, sym); + } + } +} diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h index 991365c10f0e9..e3af664864f30 100644 --- a/tools/objtool/include/objtool/builtin.h +++ b/tools/objtool/include/objtool/builtin.h @@ -28,6 +28,7 @@ struct opts { bool static_call; bool uaccess; int prefix; + const char *disas; /* options: */ bool backtrace; diff --git a/tools/objtool/include/objtool/disas.h b/tools/objtool/include/objtool/disas.h index 8959d4c455622..e8f395eff1598 100644 --- a/tools/objtool/include/objtool/disas.h +++ b/tools/objtool/include/objtool/disas.h @@ -15,6 +15,7 @@ struct disassemble_info; struct disas_context *disas_context_create(struct objtool_file *file); void disas_context_destroy(struct disas_context *dctx); void disas_warned_funcs(struct disas_context *dctx); +void disas_funcs(struct disas_context *dctx); int disas_info_init(struct disassemble_info *dinfo, int arch, int mach32, int mach64, const char *options); @@ -40,6 +41,7 @@ static inline struct disas_context *disas_context_create(struct objtool_file *fi static inline void disas_context_destroy(struct disas_context *dctx) {} static inline void disas_warned_funcs(struct disas_context *dctx) {} +static inline void disas_funcs(struct disas_context *dctx) {} static inline int disas_info_init(struct disassemble_info *dinfo, int arch, int mach32, int mach64,