Commit ca653464 authored by Josh Poimboeuf's avatar Josh Poimboeuf

objtool: Add verbose option for disassembling affected functions

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: default avatarMiroslav Benes <mbenes@suse.cz>
Link: https://lore.kernel.org/r/dd0fe13428ede186f09c74059a8001f4adcea5fc.1681853186.git.jpoimboe@kernel.orgSigned-off-by: default avatarJosh Poimboeuf <jpoimboe@kernel.org>
parent 5e3992fe
......@@ -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.
......
......@@ -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);
......
......@@ -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);
......
......@@ -37,6 +37,7 @@ struct opts {
bool no_unreachable;
bool sec_address;
bool stats;
bool verbose;
};
extern struct opts opts;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment