mirror of
https://github.com/torvalds/linux.git
synced 2026-05-30 18:13:41 +02:00
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_GROUP("Options:"),
|
||||||
OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"),
|
OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"),
|
||||||
OPT_BOOLEAN(0, "backup", &opts.backup, "create backup (.orig) file on warning/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, "dry-run", &opts.dryrun, "don't write modifications"),
|
||||||
OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"),
|
OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"),
|
||||||
OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"),
|
OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"),
|
||||||
|
|
@ -168,6 +169,11 @@ static bool opts_valid(void)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
if (opts.debug_checksum && !opts.checksum) {
|
||||||
|
ERROR("--debug-checksum requires --checksum");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (opts.checksum ||
|
if (opts.checksum ||
|
||||||
opts.hack_jump_label ||
|
opts.hack_jump_label ||
|
||||||
opts.hack_noinstr ||
|
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;
|
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,
|
static void checksum_update_insn(struct objtool_file *file, struct symbol *func,
|
||||||
struct instruction *insn)
|
struct instruction *insn)
|
||||||
{
|
{
|
||||||
|
|
@ -4818,6 +4856,10 @@ int check(struct objtool_file *file)
|
||||||
cfi_hash_add(&init_cfi);
|
cfi_hash_add(&init_cfi);
|
||||||
cfi_hash_add(&func_cfi);
|
cfi_hash_add(&func_cfi);
|
||||||
|
|
||||||
|
ret = checksum_debug_init(file);
|
||||||
|
if (ret)
|
||||||
|
goto out;
|
||||||
|
|
||||||
ret = decode_sections(file);
|
ret = decode_sections(file);
|
||||||
if (ret)
|
if (ret)
|
||||||
goto out;
|
goto out;
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,7 @@ struct opts {
|
||||||
/* options: */
|
/* options: */
|
||||||
bool backtrace;
|
bool backtrace;
|
||||||
bool backup;
|
bool backup;
|
||||||
|
const char *debug_checksum;
|
||||||
bool dryrun;
|
bool dryrun;
|
||||||
bool link;
|
bool link;
|
||||||
bool mnop;
|
bool mnop;
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@ static inline void checksum_update(struct symbol *func,
|
||||||
const void *data, size_t size)
|
const void *data, size_t size)
|
||||||
{
|
{
|
||||||
XXH3_64bits_update(func->csum.state, data, 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)
|
static inline void checksum_finish(struct symbol *func)
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ struct symbol {
|
||||||
u8 nocfi : 1;
|
u8 nocfi : 1;
|
||||||
u8 cold : 1;
|
u8 cold : 1;
|
||||||
u8 prefix : 1;
|
u8 prefix : 1;
|
||||||
|
u8 debug_checksum : 1;
|
||||||
struct list_head pv_target;
|
struct list_head pv_target;
|
||||||
struct reloc *relocs;
|
struct reloc *relocs;
|
||||||
struct section *group_sec;
|
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_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 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 */
|
#endif /* _WARN_H */
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user