Add a --debug-checksum=<funcs> option to the check subcommand to print the calculated checksum of each instruction in the given functions.
This is useful for determining where two versions of a function begin to diverge. Signed-off-by: Josh Poimboeuf <jpoim...@kernel.org> --- tools/objtool/builtin-check.c | 6 ++++ tools/objtool/check.c | 42 ++++++++++++++++++++++++ tools/objtool/include/objtool/builtin.h | 1 + tools/objtool/include/objtool/checksum.h | 1 + tools/objtool/include/objtool/elf.h | 1 + tools/objtool/include/objtool/warn.h | 19 +++++++++++ 6 files changed, 70 insertions(+) diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index 9bb26138bb56..84918593d935 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -92,6 +92,7 @@ static const struct option check_options[] = { OPT_GROUP("Options:"), OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"), + OPT_STRING(0, "debug-checksum", &opts.debug_checksum, "funcs", "enable checksum debug output"), OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"), OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"), OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"), @@ -167,6 +168,11 @@ static bool opts_valid(void) } #endif + if (opts.debug_checksum && !opts.checksum) { + ERROR("--debug-checksum requires --checksum"); + return false; + } + if (opts.checksum || opts.hack_jump_label || opts.hack_noinstr || diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 4ca4d5190f35..30a5eb725931 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -3622,6 +3622,44 @@ static bool skip_alt_group(struct instruction *insn) return alt_insn->type == INSN_CLAC || alt_insn->type == INSN_STAC; } +static int checksum_debug_init(struct objtool_file *file) +{ + char *dup, *s; + + if (!opts.debug_checksum) + return 0; + + dup = strdup(opts.debug_checksum); + if (!dup) { + ERROR_GLIBC("strdup"); + return -1; + } + + s = dup; + while (*s) { + struct symbol *func; + char *comma; + + comma = strchr(s, ','); + if (comma) + *comma = '\0'; + + func = find_symbol_by_name(file->elf, s); + if (!func || !is_func_sym(func)) + WARN("--debug-checksum: can't find '%s'", s); + else + func->debug_checksum = 1; + + if (!comma) + break; + + s = comma + 1; + } + + free(dup); + return 0; +} + static void checksum_update_insn(struct objtool_file *file, struct symbol *func, struct instruction *insn) { @@ -4789,6 +4827,10 @@ int check(struct objtool_file *file) cfi_hash_add(&init_cfi); cfi_hash_add(&func_cfi); + ret = checksum_debug_init(file); + if (ret) + goto out; + ret = decode_sections(file); if (ret) goto out; diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/include/objtool/builtin.h index 3ec233406cda..ceabafb43327 100644 --- a/tools/objtool/include/objtool/builtin.h +++ b/tools/objtool/include/objtool/builtin.h @@ -30,6 +30,7 @@ struct opts { /* options: */ bool backtrace; + const char *debug_checksum; bool dryrun; bool link; bool mnop; diff --git a/tools/objtool/include/objtool/checksum.h b/tools/objtool/include/objtool/checksum.h index 927ca74b5c39..7fe21608722a 100644 --- a/tools/objtool/include/objtool/checksum.h +++ b/tools/objtool/include/objtool/checksum.h @@ -19,6 +19,7 @@ static inline void checksum_update(struct symbol *func, const void *data, size_t size) { XXH3_64bits_update(func->csum.state, data, size); + dbg_checksum(func, insn, XXH3_64bits_digest(func->csum.state)); } static inline void checksum_finish(struct symbol *func) diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/objtool/elf.h index 4d1023fdb700..4cfd09e66cb5 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -78,6 +78,7 @@ struct symbol { u8 ignore : 1; u8 cold : 1; u8 prefix : 1; + u8 debug_checksum : 1; struct list_head pv_target; struct reloc *relocs; struct section *group_sec; diff --git a/tools/objtool/include/objtool/warn.h b/tools/objtool/include/objtool/warn.h index cb8fe846d9dd..29173a1368d7 100644 --- a/tools/objtool/include/objtool/warn.h +++ b/tools/objtool/include/objtool/warn.h @@ -102,4 +102,23 @@ static inline char *offstr(struct section *sec, unsigned long offset) #define ERROR_FUNC(sec, offset, format, ...) __WARN_FUNC(ERROR_STR, sec, offset, format, ##__VA_ARGS__) #define ERROR_INSN(insn, format, ...) WARN_FUNC(insn->sec, insn->offset, format, ##__VA_ARGS__) + +#define __dbg(format, ...) \ + fprintf(stderr, \ + "DEBUG: %s%s" format "\n", \ + objname ?: "", \ + objname ? ": " : "", \ + ##__VA_ARGS__) + +#define dbg_checksum(func, insn, checksum) \ +({ \ + if (unlikely(insn->sym && insn->sym->pfunc && \ + insn->sym->pfunc->debug_checksum)) { \ + char *insn_off = offstr(insn->sec, insn->offset); \ + __dbg("checksum: %s %s %016lx", \ + func->name, insn_off, checksum); \ + free(insn_off); \ + } \ +}) + #endif /* _WARN_H */ -- 2.49.0