OSDN Git Service

objtool: Add verbose option for disassembling affected functions
authorJosh Poimboeuf <jpoimboe@kernel.org>
Tue, 18 Apr 2023 21:27:48 +0000 (14:27 -0700)
committerJosh Poimboeuf <jpoimboe@kernel.org>
Tue, 16 May 2023 13:31:51 +0000 (06:31 -0700)
When a warning is associated with a function, add an option to
disassemble that function.

This makes it easier for reporters to submit the information needed to
diagnose objtool warnings.

Reviewed-by: Miroslav Benes <mbenes@suse.cz>
Link: https://lore.kernel.org/r/dd0fe13428ede186f09c74059a8001f4adcea5fc.1681853186.git.jpoimboe@kernel.org
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
tools/objtool/Documentation/objtool.txt
tools/objtool/builtin-check.c
tools/objtool/check.c
tools/objtool/include/objtool/builtin.h

index 744db42..8db1f29 100644 (file)
@@ -244,6 +244,11 @@ To achieve the validation, objtool enforces the following rules:
 Objtool warnings
 ----------------
 
+NOTE: When requesting help with an objtool warning, please recreate with
+OBJTOOL_VERBOSE=1 (e.g., "make OBJTOOL_VERBOSE=1") and send the full
+output, including any disassembly below the warning, to the objtool
+maintainers.
+
 For asm files, if you're getting an error which doesn't make sense,
 first make sure that the affected code follows the above rules.
 
index 7c17519..5e21cfb 100644 (file)
@@ -93,6 +93,7 @@ static const struct option check_options[] = {
        OPT_BOOLEAN(0, "no-unreachable", &opts.no_unreachable, "skip 'unreachable instruction' warnings"),
        OPT_BOOLEAN(0, "sec-address", &opts.sec_address, "print section addresses in warnings"),
        OPT_BOOLEAN(0, "stats", &opts.stats, "print statistics"),
+       OPT_BOOLEAN('v', "verbose", &opts.verbose, "verbose warnings"),
 
        OPT_END(),
 };
@@ -118,6 +119,10 @@ int cmd_parse_options(int argc, const char **argv, const char * const usage[])
                parse_options(envc, envv, check_options, env_usage, 0);
        }
 
+       env = getenv("OBJTOOL_VERBOSE");
+       if (env && !strcmp(env, "1"))
+               opts.verbose = true;
+
        argc = parse_options(argc, argv, check_options, usage, 0);
        if (argc != 1)
                usage_with_options(usage, check_options);
index 98e6c3b..0bd0ca4 100644 (file)
@@ -4530,6 +4530,81 @@ static int validate_reachable_instructions(struct objtool_file *file)
        return warnings;
 }
 
+/* 'funcs' is a space-separated list of function names */
+static int disas_funcs(const char *funcs)
+{
+       const char *objdump_str, *cross_compile;
+       int size, ret;
+       char *cmd;
+
+       cross_compile = getenv("CROSS_COMPILE");
+
+       objdump_str = "%sobjdump -wdr %s | gawk -M -v _funcs='%s' '"
+                       "BEGIN { split(_funcs, funcs); }"
+                       "/^$/ { func_match = 0; }"
+                       "/<.*>:/ { "
+                               "f = gensub(/.*<(.*)>:/, \"\\\\1\", 1);"
+                               "for (i in funcs) {"
+                                       "if (funcs[i] == f) {"
+                                               "func_match = 1;"
+                                               "base = strtonum(\"0x\" $1);"
+                                               "break;"
+                                       "}"
+                               "}"
+                       "}"
+                       "{"
+                               "if (func_match) {"
+                                       "addr = strtonum(\"0x\" $1);"
+                                       "printf(\"%%04x \", addr - base);"
+                                       "print;"
+                               "}"
+                       "}' 1>&2";
+
+       /* fake snprintf() to calculate the size */
+       size = snprintf(NULL, 0, objdump_str, cross_compile, objname, funcs) + 1;
+       if (size <= 0) {
+               WARN("objdump string size calculation failed");
+               return -1;
+       }
+
+       cmd = malloc(size);
+
+       /* real snprintf() */
+       snprintf(cmd, size, objdump_str, cross_compile, objname, funcs);
+       ret = system(cmd);
+       if (ret) {
+               WARN("disassembly failed: %d", ret);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int disas_warned_funcs(struct objtool_file *file)
+{
+       struct symbol *sym;
+       char *funcs = NULL, *tmp;
+
+       for_each_sym(file, sym) {
+               if (sym->warned) {
+                       if (!funcs) {
+                               funcs = malloc(strlen(sym->name) + 1);
+                               strcpy(funcs, sym->name);
+                       } else {
+                               tmp = malloc(strlen(funcs) + strlen(sym->name) + 2);
+                               sprintf(tmp, "%s %s", funcs, sym->name);
+                               free(funcs);
+                               funcs = tmp;
+                       }
+               }
+       }
+
+       if (funcs)
+               disas_funcs(funcs);
+
+       return 0;
+}
+
 int check(struct objtool_file *file)
 {
        int ret, warnings = 0;
@@ -4674,6 +4749,8 @@ int check(struct objtool_file *file)
                warnings += ret;
        }
 
+       if (opts.verbose)
+               disas_warned_funcs(file);
 
        if (opts.stats) {
                printf("nr_insns_visited: %ld\n", nr_insns_visited);
index 2a108e6..fcca666 100644 (file)
@@ -37,6 +37,7 @@ struct opts {
        bool no_unreachable;
        bool sec_address;
        bool stats;
+       bool verbose;
 };
 
 extern struct opts opts;