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

Configure Feed

Select the types of activity you want to include in your feed.

objtool: Print symbol during disassembly

Print symbols referenced during disassembly instead of just printing
raw addresses. Also handle address relocation.

Signed-off-by: Alexandre Chartre <alexandre.chartre@oracle.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Acked-by: Josh Poimboeuf <jpoimboe@kernel.org>
Link: https://patch.msgid.link/20251121095340.464045-6-alexandre.chartre@oracle.com

authored by

Alexandre Chartre and committed by
Peter Zijlstra
5d859dff f348a44c

+143 -9
-9
tools/objtool/check.c
··· 134 134 for (insn = next_insn_same_sec(file, insn); insn; \ 135 135 insn = next_insn_same_sec(file, insn)) 136 136 137 - static inline struct symbol *insn_call_dest(struct instruction *insn) 138 - { 139 - if (insn->type == INSN_JUMP_DYNAMIC || 140 - insn->type == INSN_CALL_DYNAMIC) 141 - return NULL; 142 - 143 - return insn->_call_dest; 144 - } 145 - 146 137 static inline struct reloc *insn_jump_table(struct instruction *insn) 147 138 { 148 139 if (insn->type == INSN_JUMP_DYNAMIC ||
+134
tools/objtool/disas.c
··· 14 14 15 15 struct disas_context { 16 16 struct objtool_file *file; 17 + struct instruction *insn; 17 18 disassembler_ftype disassembler; 18 19 struct disassemble_info info; 19 20 }; 20 21 22 + static int sprint_name(char *str, const char *name, unsigned long offset) 23 + { 24 + int len; 25 + 26 + if (offset) 27 + len = sprintf(str, "%s+0x%lx", name, offset); 28 + else 29 + len = sprintf(str, "%s", name); 30 + 31 + return len; 32 + } 33 + 21 34 #define DINFO_FPRINTF(dinfo, ...) \ 22 35 ((*(dinfo)->fprintf_func)((dinfo)->stream, __VA_ARGS__)) 36 + 37 + static void disas_print_addr_sym(struct section *sec, struct symbol *sym, 38 + bfd_vma addr, struct disassemble_info *dinfo) 39 + { 40 + char symstr[1024]; 41 + char *str; 42 + 43 + if (sym) { 44 + sprint_name(symstr, sym->name, addr - sym->offset); 45 + DINFO_FPRINTF(dinfo, "0x%lx <%s>", addr, symstr); 46 + } else { 47 + str = offstr(sec, addr); 48 + DINFO_FPRINTF(dinfo, "0x%lx <%s>", addr, str); 49 + free(str); 50 + } 51 + } 52 + 53 + static void disas_print_addr_noreloc(bfd_vma addr, 54 + struct disassemble_info *dinfo) 55 + { 56 + struct disas_context *dctx = dinfo->application_data; 57 + struct instruction *insn = dctx->insn; 58 + struct symbol *sym = NULL; 59 + 60 + if (insn->sym && addr >= insn->sym->offset && 61 + addr < insn->sym->offset + insn->sym->len) { 62 + sym = insn->sym; 63 + } 64 + 65 + disas_print_addr_sym(insn->sec, sym, addr, dinfo); 66 + } 67 + 68 + static void disas_print_addr_reloc(bfd_vma addr, struct disassemble_info *dinfo) 69 + { 70 + struct disas_context *dctx = dinfo->application_data; 71 + struct instruction *insn = dctx->insn; 72 + unsigned long offset; 73 + struct reloc *reloc; 74 + char symstr[1024]; 75 + char *str; 76 + 77 + reloc = find_reloc_by_dest_range(dctx->file->elf, insn->sec, 78 + insn->offset, insn->len); 79 + if (!reloc) { 80 + /* 81 + * There is no relocation for this instruction although 82 + * the address to resolve points to the next instruction. 83 + * So this is an effective reference to the next IP, for 84 + * example: "lea 0x0(%rip),%rdi". The kernel can reference 85 + * the next IP with _THIS_IP_ macro. 86 + */ 87 + DINFO_FPRINTF(dinfo, "0x%lx <_THIS_IP_>", addr); 88 + return; 89 + } 90 + 91 + offset = arch_insn_adjusted_addend(insn, reloc); 92 + 93 + /* 94 + * If the relocation symbol is a section name (for example ".bss") 95 + * then we try to further resolve the name. 96 + */ 97 + if (reloc->sym->type == STT_SECTION) { 98 + str = offstr(reloc->sym->sec, reloc->sym->offset + offset); 99 + DINFO_FPRINTF(dinfo, "0x%lx <%s>", addr, str); 100 + free(str); 101 + } else { 102 + sprint_name(symstr, reloc->sym->name, offset); 103 + DINFO_FPRINTF(dinfo, "0x%lx <%s>", addr, symstr); 104 + } 105 + } 106 + 107 + /* 108 + * Resolve an address into a "<symbol>+<offset>" string. 109 + */ 110 + static void disas_print_address(bfd_vma addr, struct disassemble_info *dinfo) 111 + { 112 + struct disas_context *dctx = dinfo->application_data; 113 + struct instruction *insn = dctx->insn; 114 + struct instruction *jump_dest; 115 + struct symbol *sym; 116 + bool is_reloc; 117 + 118 + /* 119 + * If the instruction is a call/jump and it references a 120 + * destination then this is likely the address we are looking 121 + * up. So check it first. 122 + */ 123 + jump_dest = insn->jump_dest; 124 + if (jump_dest && jump_dest->sym && jump_dest->offset == addr) { 125 + disas_print_addr_sym(jump_dest->sec, jump_dest->sym, 126 + addr, dinfo); 127 + return; 128 + } 129 + 130 + /* 131 + * If the address points to the next instruction then there is 132 + * probably a relocation. It can be a false positive when the 133 + * current instruction is referencing the address of the next 134 + * instruction. This particular case will be handled in 135 + * disas_print_addr_reloc(). 136 + */ 137 + is_reloc = (addr == insn->offset + insn->len); 138 + 139 + /* 140 + * The call destination offset can be the address we are looking 141 + * up, or 0 if there is a relocation. 142 + */ 143 + sym = insn_call_dest(insn); 144 + if (sym && (sym->offset == addr || (sym->offset == 0 && is_reloc))) { 145 + DINFO_FPRINTF(dinfo, "0x%lx <%s>", addr, sym->name); 146 + return; 147 + } 148 + 149 + if (!is_reloc) 150 + disas_print_addr_noreloc(addr, dinfo); 151 + else 152 + disas_print_addr_reloc(addr, dinfo); 153 + } 23 154 24 155 /* 25 156 * Initialize disassemble info arch, mach (32 or 64-bit) and options. ··· 200 69 fprintf_styled); 201 70 202 71 dinfo->read_memory_func = buffer_read_memory; 72 + dinfo->print_address_func = disas_print_address; 203 73 dinfo->application_data = dctx; 204 74 205 75 /* ··· 252 120 { 253 121 disassembler_ftype disasm = dctx->disassembler; 254 122 struct disassemble_info *dinfo = &dctx->info; 123 + 124 + dctx->insn = insn; 255 125 256 126 if (insn->type == INSN_NOP) { 257 127 DINFO_FPRINTF(dinfo, "nop%d", insn->len);
+9
tools/objtool/include/objtool/check.h
··· 117 117 return is_static_jump(insn) || is_dynamic_jump(insn); 118 118 } 119 119 120 + static inline struct symbol *insn_call_dest(struct instruction *insn) 121 + { 122 + if (insn->type == INSN_JUMP_DYNAMIC || 123 + insn->type == INSN_CALL_DYNAMIC) 124 + return NULL; 125 + 126 + return insn->_call_dest; 127 + } 128 + 120 129 struct instruction *find_insn(struct objtool_file *file, 121 130 struct section *sec, unsigned long offset); 122 131