Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

+70
+6
tools/objtool/builtin-check.c
··· 94 94 OPT_GROUP("Options:"), 95 95 OPT_BOOLEAN(0, "backtrace", &opts.backtrace, "unwind on error"), 96 96 OPT_BOOLEAN(0, "backup", &opts.backup, "create backup (.orig) file on warning/error"), 97 + OPT_STRING(0, "debug-checksum", &opts.debug_checksum, "funcs", "enable checksum debug output"), 97 98 OPT_BOOLEAN(0, "dry-run", &opts.dryrun, "don't write modifications"), 98 99 OPT_BOOLEAN(0, "link", &opts.link, "object is a linked object"), 99 100 OPT_BOOLEAN(0, "module", &opts.module, "object is part of a kernel module"), ··· 168 167 return false; 169 168 } 170 169 #endif 170 + 171 + if (opts.debug_checksum && !opts.checksum) { 172 + ERROR("--debug-checksum requires --checksum"); 173 + return false; 174 + } 171 175 172 176 if (opts.checksum || 173 177 opts.hack_jump_label ||
+42
tools/objtool/check.c
··· 3580 3580 return alt_insn->type == INSN_CLAC || alt_insn->type == INSN_STAC; 3581 3581 } 3582 3582 3583 + static int checksum_debug_init(struct objtool_file *file) 3584 + { 3585 + char *dup, *s; 3586 + 3587 + if (!opts.debug_checksum) 3588 + return 0; 3589 + 3590 + dup = strdup(opts.debug_checksum); 3591 + if (!dup) { 3592 + ERROR_GLIBC("strdup"); 3593 + return -1; 3594 + } 3595 + 3596 + s = dup; 3597 + while (*s) { 3598 + struct symbol *func; 3599 + char *comma; 3600 + 3601 + comma = strchr(s, ','); 3602 + if (comma) 3603 + *comma = '\0'; 3604 + 3605 + func = find_symbol_by_name(file->elf, s); 3606 + if (!func || !is_func_sym(func)) 3607 + WARN("--debug-checksum: can't find '%s'", s); 3608 + else 3609 + func->debug_checksum = 1; 3610 + 3611 + if (!comma) 3612 + break; 3613 + 3614 + s = comma + 1; 3615 + } 3616 + 3617 + free(dup); 3618 + return 0; 3619 + } 3620 + 3583 3621 static void checksum_update_insn(struct objtool_file *file, struct symbol *func, 3584 3622 struct instruction *insn) 3585 3623 { ··· 4855 4817 4856 4818 cfi_hash_add(&init_cfi); 4857 4819 cfi_hash_add(&func_cfi); 4820 + 4821 + ret = checksum_debug_init(file); 4822 + if (ret) 4823 + goto out; 4858 4824 4859 4825 ret = decode_sections(file); 4860 4826 if (ret)
+1
tools/objtool/include/objtool/builtin.h
··· 32 32 /* options: */ 33 33 bool backtrace; 34 34 bool backup; 35 + const char *debug_checksum; 35 36 bool dryrun; 36 37 bool link; 37 38 bool mnop;
+1
tools/objtool/include/objtool/checksum.h
··· 19 19 const void *data, size_t size) 20 20 { 21 21 XXH3_64bits_update(func->csum.state, data, size); 22 + dbg_checksum(func, insn, XXH3_64bits_digest(func->csum.state)); 22 23 } 23 24 24 25 static inline void checksum_finish(struct symbol *func)
+1
tools/objtool/include/objtool/elf.h
··· 82 82 u8 nocfi : 1; 83 83 u8 cold : 1; 84 84 u8 prefix : 1; 85 + u8 debug_checksum : 1; 85 86 struct list_head pv_target; 86 87 struct reloc *relocs; 87 88 struct section *group_sec;
+19
tools/objtool/include/objtool/warn.h
··· 102 102 #define ERROR_FUNC(sec, offset, format, ...) __WARN_FUNC(ERROR_STR, sec, offset, format, ##__VA_ARGS__) 103 103 #define ERROR_INSN(insn, format, ...) WARN_FUNC(insn->sec, insn->offset, format, ##__VA_ARGS__) 104 104 105 + 106 + #define __dbg(format, ...) \ 107 + fprintf(stderr, \ 108 + "DEBUG: %s%s" format "\n", \ 109 + objname ?: "", \ 110 + objname ? ": " : "", \ 111 + ##__VA_ARGS__) 112 + 113 + #define dbg_checksum(func, insn, checksum) \ 114 + ({ \ 115 + if (unlikely(insn->sym && insn->sym->pfunc && \ 116 + insn->sym->pfunc->debug_checksum)) { \ 117 + char *insn_off = offstr(insn->sec, insn->offset); \ 118 + __dbg("checksum: %s %s %016lx", \ 119 + func->name, insn_off, checksum); \ 120 + free(insn_off); \ 121 + } \ 122 + }) 123 + 105 124 #endif /* _WARN_H */