]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
objtool: Add the --disas=<function-pattern> action
authorAlexandre Chartre <alexandre.chartre@oracle.com>
Fri, 21 Nov 2025 09:53:27 +0000 (10:53 +0100)
committerPeter Zijlstra <peterz@infradead.org>
Fri, 21 Nov 2025 14:30:12 +0000 (15:30 +0100)
Add the --disas=<function-pattern> 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 <alexandre.chartre@oracle.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Josh Poimboeuf <jpoimboe@kernel.org>
Link: https://patch.msgid.link/20251121095340.464045-18-alexandre.chartre@oracle.com
tools/objtool/builtin-check.c
tools/objtool/check.c
tools/objtool/disas.c
tools/objtool/include/objtool/builtin.h
tools/objtool/include/objtool/disas.h

index 3329d370006b4faf4b4fbfd6bf9739e629743060..a0371312fe55af9c48cc575627f6e444ede53df7 100644 (file)
@@ -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                    ||
index 4ebadf94f8af238cc67dce1378a7dbbdd27bb09a..9cd9f9d4f65650caed72d954f0ca57882f512039 100644 (file)
@@ -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;
 
index b53be240825da0207bf4194b750f626297731748..9cc952e03c356edce6e5cb99447869c53d1bde43 100644 (file)
@@ -4,6 +4,7 @@
  */
 
 #define _GNU_SOURCE
+#include <fnmatch.h>
 
 #include <objtool/arch.h>
 #include <objtool/check.h>
@@ -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);
+               }
+       }
+}
index 991365c10f0e9191133557a468d28e53882955df..e3af664864f300acc5fd28d0ea32a32004a5a21b 100644 (file)
@@ -28,6 +28,7 @@ struct opts {
        bool static_call;
        bool uaccess;
        int prefix;
+       const char *disas;
 
        /* options: */
        bool backtrace;
index 8959d4c4556225f83471ec9acf5032de3140aee5..e8f395eff1598594310fa510ab0261d6e97beec6 100644 (file)
@@ -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,