diff options
| author | Josh Poimboeuf <jpoimboe@kernel.org> | 2025-09-17 09:04:00 -0700 |
|---|---|---|
| committer | Josh Poimboeuf <jpoimboe@kernel.org> | 2025-10-14 14:50:18 -0700 |
| commit | 7c2575a6406fb85946b05d8dcc856686d3156354 (patch) | |
| tree | bdc79df5a36ce0f3770a052fba807f277403e692 /tools/objtool/klp-diff.c | |
| parent | dd590d4d57ebeeb826823c288741f2ed20f452af (diff) | |
objtool/klp: Add --debug option to show cloning decisions
Add a --debug option to klp diff which prints cloning decisions and an
indented dependency tree for all cloned symbols and relocations. This
helps visualize which symbols and relocations were included and why.
Acked-by: Petr Mladek <pmladek@suse.com>
Tested-by: Joe Lawrence <joe.lawrence@redhat.com>
Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
Diffstat (limited to 'tools/objtool/klp-diff.c')
| -rw-r--r-- | tools/objtool/klp-diff.c | 75 |
1 files changed, 75 insertions, 0 deletions
diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c index 0d69b621a26c..817d44394a78 100644 --- a/tools/objtool/klp-diff.c +++ b/tools/objtool/klp-diff.c @@ -38,6 +38,8 @@ static const char * const klp_diff_usage[] = { }; static const struct option klp_diff_options[] = { + OPT_GROUP("Options:"), + OPT_BOOLEAN('d', "debug", &debug, "enable debug output"), OPT_END(), }; @@ -48,6 +50,38 @@ static inline u32 str_hash(const char *str) return jhash(str, strlen(str), 0); } +static char *escape_str(const char *orig) +{ + size_t len = 0; + const char *a; + char *b, *new; + + for (a = orig; *a; a++) { + switch (*a) { + case '\001': len += 5; break; + case '\n': + case '\t': len += 2; break; + default: len++; + } + } + + new = malloc(len + 1); + if (!new) + return NULL; + + for (a = orig, b = new; *a; a++) { + switch (*a) { + case '\001': memcpy(b, "<SOH>", 5); b += 5; break; + case '\n': *b++ = '\\'; *b++ = 'n'; break; + case '\t': *b++ = '\\'; *b++ = 't'; break; + default: *b++ = *a; + } + } + + *b = '\0'; + return new; +} + static int read_exports(void) { const char *symvers = "Module.symvers"; @@ -528,6 +562,28 @@ sym_created: return out_sym; } +static const char *sym_type(struct symbol *sym) +{ + switch (sym->type) { + case STT_NOTYPE: return "NOTYPE"; + case STT_OBJECT: return "OBJECT"; + case STT_FUNC: return "FUNC"; + case STT_SECTION: return "SECTION"; + case STT_FILE: return "FILE"; + default: return "UNKNOWN"; + } +} + +static const char *sym_bind(struct symbol *sym) +{ + switch (sym->bind) { + case STB_LOCAL: return "LOCAL"; + case STB_GLOBAL: return "GLOBAL"; + case STB_WEAK: return "WEAK"; + default: return "UNKNOWN"; + } +} + /* * Copy a symbol to the output object, optionally including its data and * relocations. @@ -540,6 +596,8 @@ static struct symbol *clone_symbol(struct elfs *e, struct symbol *patched_sym, if (patched_sym->clone) return patched_sym->clone; + dbg_indent("%s%s", patched_sym->name, data_too ? " [+DATA]" : ""); + /* Make sure the prefix gets cloned first */ if (is_func_sym(patched_sym) && data_too) { pfx = get_func_prefix(patched_sym); @@ -902,6 +960,8 @@ static int clone_reloc_klp(struct elfs *e, struct reloc *patched_reloc, klp_sym = find_symbol_by_name(e->out, sym_name); if (!klp_sym) { + __dbg_indent("%s", sym_name); + /* STB_WEAK: avoid modpost undefined symbol warnings */ klp_sym = elf_create_symbol(e->out, sym_name, NULL, STB_WEAK, patched_sym->type, 0, 0); @@ -950,6 +1010,17 @@ static int clone_reloc_klp(struct elfs *e, struct reloc *patched_reloc, return 0; } +#define dbg_clone_reloc(sec, offset, patched_sym, addend, export, klp) \ + dbg_indent("%s+0x%lx: %s%s0x%lx [%s%s%s%s%s%s]", \ + sec->name, offset, patched_sym->name, \ + addend >= 0 ? "+" : "-", labs(addend), \ + sym_type(patched_sym), \ + patched_sym->type == STT_SECTION ? "" : " ", \ + patched_sym->type == STT_SECTION ? "" : sym_bind(patched_sym), \ + is_undef_sym(patched_sym) ? " UNDEF" : "", \ + export ? " EXPORTED" : "", \ + klp ? " KLP" : "") + /* Copy a reloc and its symbol to the output object */ static int clone_reloc(struct elfs *e, struct reloc *patched_reloc, struct section *sec, unsigned long offset) @@ -969,6 +1040,8 @@ static int clone_reloc(struct elfs *e, struct reloc *patched_reloc, klp = klp_reloc_needed(patched_reloc); + dbg_clone_reloc(sec, offset, patched_sym, addend, export, klp); + if (klp) { if (clone_reloc_klp(e, patched_reloc, sec, offset, export)) return -1; @@ -1000,6 +1073,8 @@ static int clone_reloc(struct elfs *e, struct reloc *patched_reloc, if (is_string_sec(patched_sym->sec)) { const char *str = patched_sym->sec->data->d_buf + addend; + __dbg_indent("\"%s\"", escape_str(str)); + addend = elf_add_string(e->out, out_sym->sec, str); if (addend == -1) return -1; |
