mirror of https://github.com/torvalds/linux.git
objtool/klp: Add --debug-checksum=<funcs> to show per-instruction checksums
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. Acked-by: Petr Mladek <pmladek@suse.com> Tested-by: Joe Lawrence <joe.lawrence@redhat.com> Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
This commit is contained in:
parent
0d83da43b1
commit
a3493b3338
|
|
@ -94,6 +94,7 @@ static const struct option check_options[] = {
|
|||
OPT_GROUP("Options:"),
|
||||
OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"),
|
||||
OPT_BOOLEAN(0, "backup", &opts.backup, "create backup (.orig) file on warning/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"),
|
||||
|
|
@ -168,6 +169,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 ||
|
||||
|
|
|
|||
|
|
@ -3580,6 +3580,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)
|
||||
{
|
||||
|
|
@ -4818,6 +4856,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;
|
||||
|
|
|
|||
|
|
@ -32,6 +32,7 @@ struct opts {
|
|||
/* options: */
|
||||
bool backtrace;
|
||||
bool backup;
|
||||
const char *debug_checksum;
|
||||
bool dryrun;
|
||||
bool link;
|
||||
bool mnop;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ struct symbol {
|
|||
u8 nocfi : 1;
|
||||
u8 cold : 1;
|
||||
u8 prefix : 1;
|
||||
u8 debug_checksum : 1;
|
||||
struct list_head pv_target;
|
||||
struct reloc *relocs;
|
||||
struct section *group_sec;
|
||||
|
|
|
|||
|
|
@ -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 */
|
||||
|
|
|
|||
Loading…
Reference in New Issue