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


Reply via email to