Alternative replacement instructions awkwardly have insn->sym set to the function they get patched to rather than the symbol (or rather lack thereof) they belong to in the file.
This makes it difficult to know where a given instruction actually lives. Add a new insn_sym() helper which preserves the existing semantic of insn->sym. Rename insn->sym to insn->_sym, which contains the actual ELF binary symbol (or NULL, for alternative replacements) an instruction lives in. The private insn->_sym value will be needed for a subsequent patch. Signed-off-by: Josh Poimboeuf <[email protected]> --- tools/objtool/check.c | 31 ++++++++++++--------------- tools/objtool/disas.c | 22 +++++++++---------- tools/objtool/include/objtool/check.h | 19 ++++++++++++++-- tools/objtool/include/objtool/warn.h | 6 +++--- tools/objtool/trace.c | 8 +++---- 5 files changed, 48 insertions(+), 38 deletions(-) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index ae047be919c5..410061aeed26 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -495,7 +495,7 @@ static int decode_instructions(struct objtool_file *file) } sym_for_each_insn(file, func, insn) { - insn->sym = func; + insn->_sym = func; if (is_func_sym(func) && insn->type == INSN_ENDBR && list_empty(&insn->call_node)) { @@ -859,15 +859,14 @@ static int create_ibt_endbr_seal_sections(struct objtool_file *file) list_for_each_entry(insn, &file->endbr_list, call_node) { int *site = (int *)sec->data->d_buf + idx; - struct symbol *sym = insn->sym; + struct symbol *func = insn_func(insn); *site = 0; - if (opts.module && sym && is_func_sym(sym) && - insn->offset == sym->offset && - (!strcmp(sym->name, "init_module") || - !strcmp(sym->name, "cleanup_module"))) { + if (opts.module && func && insn->offset == func->offset && + (!strcmp(func->name, "init_module") || + !strcmp(func->name, "cleanup_module"))) { ERROR("%s(): Magic init_module() function name is deprecated, use module_init(fn) instead", - sym->name); + func->name); return -1; } @@ -1581,7 +1580,7 @@ static int add_jump_destinations(struct objtool_file *file) } if (!dest_sym || is_sec_sym(dest_sym)) { - dest_sym = dest_insn->sym; + dest_sym = insn_sym(dest_insn); if (!dest_sym) goto set_jump_dest; } @@ -1597,7 +1596,7 @@ static int add_jump_destinations(struct objtool_file *file) continue; } - if (!insn->sym || insn->sym->pfunc == dest_sym->pfunc) + if (!insn_sym(insn) || insn_sym(insn)->pfunc == dest_sym->pfunc) goto set_jump_dest; /* @@ -1770,7 +1769,6 @@ static int handle_group_alt(struct objtool_file *file, nop->offset = special_alt->new_off + special_alt->new_len; nop->len = special_alt->orig_len - special_alt->new_len; nop->type = INSN_NOP; - nop->sym = orig_insn->sym; nop->alt_group = new_alt_group; nop->fake = 1; } @@ -1789,7 +1787,6 @@ static int handle_group_alt(struct objtool_file *file, last_new_insn = insn; - insn->sym = orig_insn->sym; insn->alt_group = new_alt_group; /* @@ -2432,12 +2429,12 @@ static int __annotate_late(struct objtool_file *file, int type, struct instructi break; case ANNOTYPE_NOCFI: - sym = insn->sym; + sym = insn_sym(insn); if (!sym) { ERROR_INSN(insn, "dodgy NOCFI annotation"); return -1; } - insn->sym->nocfi = 1; + insn_sym(insn)->nocfi = 1; break; default: @@ -2538,7 +2535,7 @@ static void mark_holes(struct objtool_file *file) * favour of a regular symbol, but leaves the code in place. */ for_each_insn(file, insn) { - if (insn->sym || !find_symbol_hole_containing(insn->sec, insn->offset)) { + if (insn_sym(insn) || !find_symbol_hole_containing(insn->sec, insn->offset)) { in_hole = false; continue; } @@ -2982,7 +2979,7 @@ static int update_cfi_state(struct instruction *insn, } if (op->dest.reg == CFI_BP && op->src.reg == CFI_SP && - insn->sym->frame_pointer) { + insn_sym(insn)->frame_pointer) { /* addi.d fp,sp,imm on LoongArch */ if (cfa->base == CFI_SP && cfa->offset == op->src.offset) { cfa->base = CFI_BP; @@ -2994,7 +2991,7 @@ static int update_cfi_state(struct instruction *insn, if (op->dest.reg == CFI_SP && op->src.reg == CFI_BP) { /* addi.d sp,fp,imm on LoongArch */ if (cfa->base == CFI_BP && cfa->offset == 0) { - if (insn->sym->frame_pointer) { + if (insn_sym(insn)->frame_pointer) { cfa->base = CFI_SP; cfa->offset = -op->src.offset; } @@ -4171,7 +4168,7 @@ static int validate_retpoline(struct objtool_file *file) * broken. */ list_for_each_entry(insn, &file->retpoline_call_list, call_node) { - struct symbol *sym = insn->sym; + struct symbol *sym = insn_sym(insn); if (sym && (is_notype_sym(sym) || is_func_sym(sym)) && !sym->nocfi) { diff --git a/tools/objtool/disas.c b/tools/objtool/disas.c index 59090234af19..e6a54a83605c 100644 --- a/tools/objtool/disas.c +++ b/tools/objtool/disas.c @@ -210,7 +210,7 @@ static bool disas_print_addr_alt(bfd_vma addr, struct disassemble_info *dinfo) offset = addr - alt_group->first_insn->offset; addr = orig_first_insn->offset + offset; - sym = orig_first_insn->sym; + sym = insn_sym(orig_first_insn); disas_print_addr_sym(orig_first_insn->sec, sym, addr, dinfo); @@ -222,15 +222,13 @@ static void disas_print_addr_noreloc(bfd_vma addr, { struct disas_context *dctx = dinfo->application_data; struct instruction *insn = dctx->insn; - struct symbol *sym = NULL; + struct symbol *sym = insn_sym(insn); if (disas_print_addr_alt(addr, dinfo)) return; - if (insn->sym && addr >= insn->sym->offset && - addr < insn->sym->offset + insn->sym->len) { - sym = insn->sym; - } + if (sym && (addr < sym->offset || addr >= sym->offset + sym->len)) + sym = NULL; disas_print_addr_sym(insn->sec, sym, addr, dinfo); } @@ -291,9 +289,9 @@ static void disas_print_address(bfd_vma addr, struct disassemble_info *dinfo) * up. So check it first. */ jump_dest = insn->jump_dest; - if (jump_dest && jump_dest->sym && jump_dest->offset == addr) { + if (jump_dest && insn_sym(jump_dest) && jump_dest->offset == addr) { if (!disas_print_addr_alt(addr, dinfo)) - disas_print_addr_sym(jump_dest->sec, jump_dest->sym, + disas_print_addr_sym(jump_dest->sec, insn_sym(jump_dest), addr, dinfo); return; } @@ -768,8 +766,8 @@ static int disas_alt_jump(struct disas_alt *dalt) if (orig_insn->len == 5) suffix[0] = 'q'; str = strfmt("jmp%-3s %lx <%s+0x%lx>", suffix, - dest_insn->offset, dest_insn->sym->name, - dest_insn->offset - dest_insn->sym->offset); + dest_insn->offset, insn_sym(dest_insn)->name, + dest_insn->offset - insn_sym(dest_insn)->offset); nops = 0; } else { str = strfmt("nop%d", orig_insn->len); @@ -794,8 +792,8 @@ static int disas_alt_extable(struct disas_alt *dalt) alt_insn = dalt->alt->insn; str = strfmt("resume at 0x%lx <%s+0x%lx>", - alt_insn->offset, alt_insn->sym->name, - alt_insn->offset - alt_insn->sym->offset); + alt_insn->offset, insn_sym(alt_insn)->name, + alt_insn->offset - insn_sym(alt_insn)->offset); if (!str) return -1; diff --git a/tools/objtool/include/objtool/check.h b/tools/objtool/include/objtool/check.h index eea64728d39b..0c53476528a8 100644 --- a/tools/objtool/include/objtool/check.h +++ b/tools/objtool/include/objtool/check.h @@ -94,14 +94,29 @@ struct instruction { }; }; struct alternative *alts; - struct symbol *sym; + struct symbol *_sym; struct stack_op *stack_ops; struct cfi_state *cfi; }; +/* + * Return the symbol associated with an instruction. For alternative + * replacements, return the symbol of the original code being replaced rather + * than NULL. insn->_sym reflects the actual location in the ELF file. + */ +static inline struct symbol *insn_sym(struct instruction *insn) +{ + struct symbol *sym = insn->_sym; + + if (!sym && insn->alt_group && insn->alt_group->orig_group) + sym = insn->alt_group->orig_group->first_insn->_sym; + + return sym; +} + static inline struct symbol *insn_func(struct instruction *insn) { - struct symbol *sym = insn->sym; + struct symbol *sym = insn_sym(insn); if (sym && sym->type != STT_FUNC) sym = NULL; diff --git a/tools/objtool/include/objtool/warn.h b/tools/objtool/include/objtool/warn.h index a9936d60980c..870e147f3a56 100644 --- a/tools/objtool/include/objtool/warn.h +++ b/tools/objtool/include/objtool/warn.h @@ -77,13 +77,13 @@ static inline char *offstr(struct section *sec, unsigned long offset) #define WARN_INSN(insn, format, ...) \ ({ \ struct instruction *_insn = (insn); \ - if (!_insn->sym || !_insn->sym->warned) { \ + if (!insn_sym(_insn) || !insn_sym(_insn)->warned) { \ WARN_FUNC(_insn->sec, _insn->offset, format, \ ##__VA_ARGS__); \ BT_INSN(_insn, ""); \ } \ - if (_insn->sym) \ - _insn->sym->warned = 1; \ + if (insn_sym(_insn)) \ + insn_sym(_insn)->warned = 1; \ }) #define BT_INSN(insn, format, ...) \ diff --git a/tools/objtool/trace.c b/tools/objtool/trace.c index 5dec44dab781..61c6aa302bc3 100644 --- a/tools/objtool/trace.c +++ b/tools/objtool/trace.c @@ -169,8 +169,8 @@ void trace_alt_begin(struct instruction *orig_insn, struct alternative *alt, */ TRACE_ALT_INFO_NOADDR(orig_insn, "/ ", "%s for instruction at 0x%lx <%s+0x%lx>", alt_name, - orig_insn->offset, orig_insn->sym->name, - orig_insn->offset - orig_insn->sym->offset); + orig_insn->offset, insn_sym(orig_insn)->name, + orig_insn->offset - insn_sym(orig_insn)->offset); } else { TRACE_ALT_INFO_NOADDR(orig_insn, "/ ", "%s", alt_name); } @@ -185,8 +185,8 @@ void trace_alt_begin(struct instruction *orig_insn, struct alternative *alt, if (orig_insn->type == INSN_NOP) { suffix[0] = (orig_insn->len == 5) ? 'q' : '\0'; TRACE_ADDR(orig_insn, "jmp%-3s %lx <%s+0x%lx>", suffix, - alt_insn->offset, alt_insn->sym->name, - alt_insn->offset - alt_insn->sym->offset); + alt_insn->offset, insn_sym(alt_insn)->name, + alt_insn->offset - insn_sym(alt_insn)->offset); } else { TRACE_ADDR(orig_insn, "nop%d", orig_insn->len); trace_depth--; -- 2.53.0

