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

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>

+99
+21
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 + extern bool debug; 106 + extern int indent; 107 + 108 + static inline void unindent(int *unused) { indent--; } 105 109 106 110 #define __dbg(format, ...) \ 107 111 fprintf(stderr, \ ··· 113 109 objname ?: "", \ 114 110 objname ? ": " : "", \ 115 111 ##__VA_ARGS__) 112 + 113 + #define dbg(args...) \ 114 + ({ \ 115 + if (unlikely(debug)) \ 116 + __dbg(args); \ 117 + }) 118 + 119 + #define __dbg_indent(format, ...) \ 120 + ({ \ 121 + if (unlikely(debug)) \ 122 + __dbg("%*s" format, indent * 8, "", ##__VA_ARGS__); \ 123 + }) 124 + 125 + #define dbg_indent(args...) \ 126 + int __attribute__((cleanup(unindent))) __dummy_##__COUNTER__; \ 127 + __dbg_indent(args); \ 128 + indent++ 116 129 117 130 #define dbg_checksum(func, insn, checksum) \ 118 131 ({ \
+75
tools/objtool/klp-diff.c
··· 38 38 }; 39 39 40 40 static const struct option klp_diff_options[] = { 41 + OPT_GROUP("Options:"), 42 + OPT_BOOLEAN('d', "debug", &debug, "enable debug output"), 41 43 OPT_END(), 42 44 }; 43 45 ··· 48 46 static inline u32 str_hash(const char *str) 49 47 { 50 48 return jhash(str, strlen(str), 0); 49 + } 50 + 51 + static char *escape_str(const char *orig) 52 + { 53 + size_t len = 0; 54 + const char *a; 55 + char *b, *new; 56 + 57 + for (a = orig; *a; a++) { 58 + switch (*a) { 59 + case '\001': len += 5; break; 60 + case '\n': 61 + case '\t': len += 2; break; 62 + default: len++; 63 + } 64 + } 65 + 66 + new = malloc(len + 1); 67 + if (!new) 68 + return NULL; 69 + 70 + for (a = orig, b = new; *a; a++) { 71 + switch (*a) { 72 + case '\001': memcpy(b, "<SOH>", 5); b += 5; break; 73 + case '\n': *b++ = '\\'; *b++ = 'n'; break; 74 + case '\t': *b++ = '\\'; *b++ = 't'; break; 75 + default: *b++ = *a; 76 + } 77 + } 78 + 79 + *b = '\0'; 80 + return new; 51 81 } 52 82 53 83 static int read_exports(void) ··· 562 528 return out_sym; 563 529 } 564 530 531 + static const char *sym_type(struct symbol *sym) 532 + { 533 + switch (sym->type) { 534 + case STT_NOTYPE: return "NOTYPE"; 535 + case STT_OBJECT: return "OBJECT"; 536 + case STT_FUNC: return "FUNC"; 537 + case STT_SECTION: return "SECTION"; 538 + case STT_FILE: return "FILE"; 539 + default: return "UNKNOWN"; 540 + } 541 + } 542 + 543 + static const char *sym_bind(struct symbol *sym) 544 + { 545 + switch (sym->bind) { 546 + case STB_LOCAL: return "LOCAL"; 547 + case STB_GLOBAL: return "GLOBAL"; 548 + case STB_WEAK: return "WEAK"; 549 + default: return "UNKNOWN"; 550 + } 551 + } 552 + 565 553 /* 566 554 * Copy a symbol to the output object, optionally including its data and 567 555 * relocations. ··· 595 539 596 540 if (patched_sym->clone) 597 541 return patched_sym->clone; 542 + 543 + dbg_indent("%s%s", patched_sym->name, data_too ? " [+DATA]" : ""); 598 544 599 545 /* Make sure the prefix gets cloned first */ 600 546 if (is_func_sym(patched_sym) && data_too) { ··· 960 902 961 903 klp_sym = find_symbol_by_name(e->out, sym_name); 962 904 if (!klp_sym) { 905 + __dbg_indent("%s", sym_name); 906 + 963 907 /* STB_WEAK: avoid modpost undefined symbol warnings */ 964 908 klp_sym = elf_create_symbol(e->out, sym_name, NULL, 965 909 STB_WEAK, patched_sym->type, 0, 0); ··· 1010 950 return 0; 1011 951 } 1012 952 953 + #define dbg_clone_reloc(sec, offset, patched_sym, addend, export, klp) \ 954 + dbg_indent("%s+0x%lx: %s%s0x%lx [%s%s%s%s%s%s]", \ 955 + sec->name, offset, patched_sym->name, \ 956 + addend >= 0 ? "+" : "-", labs(addend), \ 957 + sym_type(patched_sym), \ 958 + patched_sym->type == STT_SECTION ? "" : " ", \ 959 + patched_sym->type == STT_SECTION ? "" : sym_bind(patched_sym), \ 960 + is_undef_sym(patched_sym) ? " UNDEF" : "", \ 961 + export ? " EXPORTED" : "", \ 962 + klp ? " KLP" : "") 963 + 1013 964 /* Copy a reloc and its symbol to the output object */ 1014 965 static int clone_reloc(struct elfs *e, struct reloc *patched_reloc, 1015 966 struct section *sec, unsigned long offset) ··· 1039 968 } 1040 969 1041 970 klp = klp_reloc_needed(patched_reloc); 971 + 972 + dbg_clone_reloc(sec, offset, patched_sym, addend, export, klp); 1042 973 1043 974 if (klp) { 1044 975 if (clone_reloc_klp(e, patched_reloc, sec, offset, export)) ··· 1072 999 */ 1073 1000 if (is_string_sec(patched_sym->sec)) { 1074 1001 const char *str = patched_sym->sec->data->d_buf + addend; 1002 + 1003 + __dbg_indent("\"%s\"", escape_str(str)); 1075 1004 1076 1005 addend = elf_add_string(e->out, out_sym->sec, str); 1077 1006 if (addend == -1)
+3
tools/objtool/objtool.c
··· 16 16 #include <objtool/objtool.h> 17 17 #include <objtool/warn.h> 18 18 19 + bool debug; 20 + int indent; 21 + 19 22 static struct objtool_file file; 20 23 21 24 struct objtool_file *objtool_open_read(const char *filename)