From nobody Tue Apr 7 14:04:29 2026 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CDF3BC4332F for ; Mon, 17 Oct 2022 14:55:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231321AbiJQOzX (ORCPT ); Mon, 17 Oct 2022 10:55:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59136 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230523AbiJQOyE (ORCPT ); Mon, 17 Oct 2022 10:54:04 -0400 Received: from galois.linutronix.de (Galois.linutronix.de [193.142.43.55]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 8578569193; Mon, 17 Oct 2022 07:54:00 -0700 (PDT) Date: Mon, 17 Oct 2022 14:53:55 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020; t=1666018437; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=37AqhZ1J99hqvkzmvycFPVAzkOg4xUbgrKK3c22m2ek=; b=b/A4vVp8svKLLKA3mPCdv2grjAG23G+l/pxVLeI1s9etnefs8mDSSxsbZVYrkU+968+87B Py9BnxKOVFkM5EiLAATvE2iXDrYOCg+gzwQC/CCIPXgFvP8xkFGp2bDl63jxU4t+BqwE5I uOnLSghEI0rbmuPrFx4CqIS5IxMQmDksLlV1xDS76kNT4M4bBCPFGBaEqpvtN4KJIQi/9J hLQvA4L7bhMtr4aVWe4gLqDz7xpOKOQwliJ2OIwxGyYJ+z5bVGuNvqwIQ3hJiGx0zR8Bs8 yANXW5tFKdV0Xn8SDPzo6VjqiBIXWjGLukEfkkmwGpOgPdwHCM5f+9PndGWgpw== DKIM-Signature: v=1; a=ed25519-sha256; c=relaxed/relaxed; d=linutronix.de; s=2020e; t=1666018437; h=from:from:sender:sender:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=37AqhZ1J99hqvkzmvycFPVAzkOg4xUbgrKK3c22m2ek=; b=5EPyL8s/dXp+fZiEGIFaDIawtFd74sgRHOMTw2/qn6KB3eu4H80vccgcZm2GlAT5xfUJPF 270XbDGedT+Tk3BQ== From: "tip-bot2 for Peter Zijlstra" Sender: tip-bot2@linutronix.de Reply-to: linux-kernel@vger.kernel.org To: linux-tip-commits@vger.kernel.org Subject: [tip: x86/core] objtool: Rework instruction -> symbol mapping Cc: "Peter Zijlstra (Intel)" , x86@kernel.org, linux-kernel@vger.kernel.org MIME-Version: 1.0 Message-ID: <166601843578.401.7005725839416716951.tip-bot2@tip-bot2> Robot-ID: Robot-Unsubscribe: Contact to get blacklisted from these emails Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The following commit has been merged into the x86/core branch of tip: Commit-ID: dbcdbdfdf137b49144204571f1a5e5dc01b8aaad Gitweb: https://git.kernel.org/tip/dbcdbdfdf137b49144204571f1a5e5dc0= 1b8aaad Author: Peter Zijlstra AuthorDate: Thu, 22 Sep 2022 22:03:50 +02:00 Committer: Peter Zijlstra CommitterDate: Mon, 17 Oct 2022 16:41:08 +02:00 objtool: Rework instruction -> symbol mapping Currently insn->func contains a instruction -> symbol link for STT_FUNC symbols. A NULL value is assumed to mean STT_NOTYPE. However, there are also instructions not covered by any symbol at all. This can happen due to __weak symbols for example. Since the current scheme cannot differentiate between no symbol and STT_NOTYPE symbol, change things around. Make insn->sym point to any symbol type such that !insn->sym means no symbol and add a helper insn_func() that check the sym->type to retain the old functionality. This then prepares the way to add code that depends on the distinction between STT_NOTYPE and no symbol at all. Signed-off-by: Peter Zijlstra (Intel) --- tools/objtool/check.c | 105 +++++++++++++------------ tools/objtool/include/objtool/check.h | 12 ++- 2 files changed, 66 insertions(+), 51 deletions(-) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 3f46f46..e532efb 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -62,12 +62,12 @@ static struct instruction *next_insn_same_func(struct o= bjtool_file *file, struct instruction *insn) { struct instruction *next =3D list_next_entry(insn, list); - struct symbol *func =3D insn->func; + struct symbol *func =3D insn_func(insn); =20 if (!func) return NULL; =20 - if (&next->list !=3D &file->insn_list && next->func =3D=3D func) + if (&next->list !=3D &file->insn_list && insn_func(next) =3D=3D func) return next; =20 /* Check if we're already in the subfunction: */ @@ -83,7 +83,7 @@ static struct instruction *prev_insn_same_sym(struct objt= ool_file *file, { struct instruction *prev =3D list_prev_entry(insn, list); =20 - if (&prev->list !=3D &file->insn_list && prev->func =3D=3D insn->func) + if (&prev->list !=3D &file->insn_list && insn_func(prev) =3D=3D insn_func= (insn)) return prev; =20 return NULL; @@ -133,7 +133,7 @@ static bool is_sibling_call(struct instruction *insn) * sibling call detection consistency between vmlinux.o and individual * objects. */ - if (!insn->func) + if (!insn_func(insn)) return false; =20 /* An indirect jump is either a sibling call or a jump to a table. */ @@ -207,7 +207,7 @@ static bool __dead_end_function(struct objtool_file *fi= le, struct symbol *func, return false; =20 insn =3D find_insn(file, func->sec, func->offset); - if (!insn->func) + if (!insn_func(insn)) return false; =20 func_for_each_insn(file, func, insn) { @@ -243,7 +243,7 @@ static bool __dead_end_function(struct objtool_file *fi= le, struct symbol *func, return false; } =20 - return __dead_end_function(file, dest->func, recursion+1); + return __dead_end_function(file, insn_func(dest), recursion+1); } } =20 @@ -427,7 +427,10 @@ static int decode_instructions(struct objtool_file *fi= le) } =20 list_for_each_entry(func, &sec->symbol_list, list) { - if (func->type !=3D STT_FUNC || func->alias !=3D func) + if (func->type !=3D STT_NOTYPE && func->type !=3D STT_FUNC) + continue; + + if (func->return_thunk || func->alias !=3D func) continue; =20 if (!find_insn(file, sec, func->offset)) { @@ -437,9 +440,11 @@ static int decode_instructions(struct objtool_file *fi= le) } =20 sym_for_each_insn(file, func, insn) { - insn->func =3D func; - if (insn->type =3D=3D INSN_ENDBR && list_empty(&insn->call_node)) { - if (insn->offset =3D=3D insn->func->offset) { + insn->sym =3D func; + if (func->type =3D=3D STT_FUNC && + insn->type =3D=3D INSN_ENDBR && + list_empty(&insn->call_node)) { + if (insn->offset =3D=3D func->offset) { list_add_tail(&insn->call_node, &file->endbr_list); file->nr_endbr++; } else { @@ -1397,19 +1402,19 @@ static void add_return_call(struct objtool_file *fi= le, struct instruction *insn, =20 static bool same_function(struct instruction *insn1, struct instruction *i= nsn2) { - return insn1->func->pfunc =3D=3D insn2->func->pfunc; + return insn_func(insn1)->pfunc =3D=3D insn_func(insn2)->pfunc; } =20 static bool is_first_func_insn(struct objtool_file *file, struct instructi= on *insn) { - if (insn->offset =3D=3D insn->func->offset) + if (insn->offset =3D=3D insn_func(insn)->offset) return true; =20 if (opts.ibt) { struct instruction *prev =3D prev_insn_same_sym(file, insn); =20 if (prev && prev->type =3D=3D INSN_ENDBR && - insn->offset =3D=3D insn->func->offset + prev->len) + insn->offset =3D=3D insn_func(insn)->offset + prev->len) return true; } =20 @@ -1450,7 +1455,7 @@ static int add_jump_destinations(struct objtool_file = *file) } else if (reloc->sym->return_thunk) { add_return_call(file, insn, true); continue; - } else if (insn->func) { + } else if (insn_func(insn)) { /* * External sibling call or internal sibling call with * STT_FUNC reloc. @@ -1492,8 +1497,8 @@ static int add_jump_destinations(struct objtool_file = *file) /* * Cross-function jump. */ - if (insn->func && jump_dest->func && - insn->func !=3D jump_dest->func) { + if (insn_func(insn) && insn_func(jump_dest) && + insn_func(insn) !=3D insn_func(jump_dest)) { =20 /* * For GCC 8+, create parent/child links for any cold @@ -1510,10 +1515,10 @@ static int add_jump_destinations(struct objtool_fil= e *file) * case where the parent function's only reference to a * subfunction is through a jump table. */ - if (!strstr(insn->func->name, ".cold") && - strstr(jump_dest->func->name, ".cold")) { - insn->func->cfunc =3D jump_dest->func; - jump_dest->func->pfunc =3D insn->func; + if (!strstr(insn_func(insn)->name, ".cold") && + strstr(insn_func(jump_dest)->name, ".cold")) { + insn_func(insn)->cfunc =3D insn_func(jump_dest); + insn_func(jump_dest)->pfunc =3D insn_func(insn); =20 } else if (!same_function(insn, jump_dest) && is_first_func_insn(file, jump_dest)) { @@ -1521,7 +1526,7 @@ static int add_jump_destinations(struct objtool_file = *file) * Internal sibling call without reloc or with * STT_SECTION reloc. */ - add_call_dest(file, insn, jump_dest->func, true); + add_call_dest(file, insn, insn_func(jump_dest), true); continue; } } @@ -1572,7 +1577,7 @@ static int add_call_destinations(struct objtool_file = *file) return -1; } =20 - if (insn->func && insn->call_dest->type !=3D STT_FUNC) { + if (insn_func(insn) && insn->call_dest->type !=3D STT_FUNC) { WARN_FUNC("unsupported call to non-function", insn->sec, insn->offset); return -1; @@ -1668,7 +1673,7 @@ static int handle_group_alt(struct objtool_file *file, nop->offset =3D special_alt->new_off + special_alt->new_len; nop->len =3D special_alt->orig_len - special_alt->new_len; nop->type =3D INSN_NOP; - nop->func =3D orig_insn->func; + nop->sym =3D orig_insn->sym; nop->alt_group =3D new_alt_group; nop->ignore =3D orig_insn->ignore_alts; } @@ -1688,7 +1693,7 @@ static int handle_group_alt(struct objtool_file *file, last_new_insn =3D insn; =20 insn->ignore =3D orig_insn->ignore_alts; - insn->func =3D orig_insn->func; + insn->sym =3D orig_insn->sym; insn->alt_group =3D new_alt_group; =20 /* @@ -1882,7 +1887,7 @@ static int add_jump_table(struct objtool_file *file, = struct instruction *insn, struct reloc *reloc =3D table; struct instruction *dest_insn; struct alternative *alt; - struct symbol *pfunc =3D insn->func->pfunc; + struct symbol *pfunc =3D insn_func(insn)->pfunc; unsigned int prev_offset =3D 0; =20 /* @@ -1909,7 +1914,7 @@ static int add_jump_table(struct objtool_file *file, = struct instruction *insn, break; =20 /* Make sure the destination is in the same function: */ - if (!dest_insn->func || dest_insn->func->pfunc !=3D pfunc) + if (!insn_func(dest_insn) || insn_func(dest_insn)->pfunc !=3D pfunc) break; =20 alt =3D malloc(sizeof(*alt)); @@ -1949,7 +1954,7 @@ static struct reloc *find_jump_table(struct objtool_f= ile *file, * it. */ for (; - insn && insn->func && insn->func->pfunc =3D=3D func; + insn && insn_func(insn) && insn_func(insn)->pfunc =3D=3D func; insn =3D insn->first_jump_src ?: prev_insn_same_sym(file, insn)) { =20 if (insn !=3D orig_insn && insn->type =3D=3D INSN_JUMP_DYNAMIC) @@ -1966,7 +1971,7 @@ static struct reloc *find_jump_table(struct objtool_f= ile *file, if (!table_reloc) continue; dest_insn =3D find_insn(file, table_reloc->sym->sec, table_reloc->addend= ); - if (!dest_insn || !dest_insn->func || dest_insn->func->pfunc !=3D func) + if (!dest_insn || !insn_func(dest_insn) || insn_func(dest_insn)->pfunc != =3D func) continue; =20 return table_reloc; @@ -2415,6 +2420,13 @@ static int decode_sections(struct objtool_file *file) if (ret) return ret; =20 + /* + * Must be before add_{jump_call}_destination. + */ + ret =3D classify_symbols(file); + if (ret) + return ret; + ret =3D decode_instructions(file); if (ret) return ret; @@ -2434,13 +2446,6 @@ static int decode_sections(struct objtool_file *file) return ret; =20 /* - * Must be before add_{jump_call}_destination. - */ - ret =3D classify_symbols(file); - if (ret) - return ret; - - /* * Must be before add_jump_destinations(), which depends on 'func' * being set for alternatives, to enable proper sibling call detection. */ @@ -2648,7 +2653,7 @@ static int update_cfi_state(struct instruction *insn, =20 /* stack operations don't make sense with an undefined CFA */ if (cfa->base =3D=3D CFI_UNDEFINED) { - if (insn->func) { + if (insn_func(insn)) { WARN_FUNC("undefined stack state", insn->sec, insn->offset); return -1; } @@ -2994,7 +2999,7 @@ static int update_cfi_state(struct instruction *insn, } =20 /* detect when asm code uses rbp as a scratch register */ - if (opts.stackval && insn->func && op->src.reg =3D=3D CFI_BP && + if (opts.stackval && insn_func(insn) && op->src.reg =3D=3D CFI_BP && cfa->base !=3D CFI_BP) cfi->bp_scratch =3D true; break; @@ -3390,13 +3395,13 @@ static int validate_branch(struct objtool_file *fil= e, struct symbol *func, while (1) { next_insn =3D next_insn_to_validate(file, insn); =20 - if (func && insn->func && func !=3D insn->func->pfunc) { + if (func && insn_func(insn) && func !=3D insn_func(insn)->pfunc) { /* Ignore KCFI type preambles, which always fall through */ if (!strncmp(func->name, "__cfi_", 6)) return 0; =20 WARN("%s() falls through to next function %s()", - func->name, insn->func->name); + func->name, insn_func(insn)->name); return 1; } =20 @@ -3638,7 +3643,7 @@ static int validate_unwind_hints(struct objtool_file = *file, struct section *sec) =20 while (&insn->list !=3D &file->insn_list && (!sec || insn->sec =3D=3D sec= )) { if (insn->hint && !insn->visited && !insn->ignore) { - ret =3D validate_branch(file, insn->func, insn, state); + ret =3D validate_branch(file, insn_func(insn), insn, state); if (ret && opts.backtrace) BT_FUNC("<=3D=3D=3D (hint)", insn); warnings +=3D ret; @@ -3861,7 +3866,7 @@ static bool ignore_unreachable_insn(struct objtool_fi= le *file, struct instructio * In this case we'll find a piece of code (whole function) that is not * covered by a !section symbol. Ignore them. */ - if (opts.link && !insn->func) { + if (opts.link && !insn_func(insn)) { int size =3D find_symbol_hole_containing(insn->sec, insn->offset); unsigned long end =3D insn->offset + size; =20 @@ -3885,10 +3890,10 @@ static bool ignore_unreachable_insn(struct objtool_= file *file, struct instructio /* * If this hole jumps to a .cold function, mark it ignore too. */ - if (insn->jump_dest && insn->jump_dest->func && - strstr(insn->jump_dest->func->name, ".cold")) { + if (insn->jump_dest && insn_func(insn->jump_dest) && + strstr(insn_func(insn->jump_dest)->name, ".cold")) { struct instruction *dest =3D insn->jump_dest; - func_for_each_insn(file, dest->func, dest) + func_for_each_insn(file, insn_func(dest), dest) dest->ignore =3D true; } } @@ -3896,10 +3901,10 @@ static bool ignore_unreachable_insn(struct objtool_= file *file, struct instructio return false; } =20 - if (!insn->func) + if (!insn_func(insn)) return false; =20 - if (insn->func->static_call_tramp) + if (insn_func(insn)->static_call_tramp) return true; =20 /* @@ -3930,7 +3935,7 @@ static bool ignore_unreachable_insn(struct objtool_fi= le *file, struct instructio =20 if (insn->type =3D=3D INSN_JUMP_UNCONDITIONAL) { if (insn->jump_dest && - insn->jump_dest->func =3D=3D insn->func) { + insn_func(insn->jump_dest) =3D=3D insn_func(insn)) { insn =3D insn->jump_dest; continue; } @@ -3938,7 +3943,7 @@ static bool ignore_unreachable_insn(struct objtool_fi= le *file, struct instructio break; } =20 - if (insn->offset + insn->len >=3D insn->func->offset + insn->func->len) + if (insn->offset + insn->len >=3D insn_func(insn)->offset + insn_func(in= sn)->len) break; =20 insn =3D list_next_entry(insn, list); @@ -3967,7 +3972,7 @@ static int validate_symbol(struct objtool_file *file,= struct section *sec, =20 state->uaccess =3D sym->uaccess_safe; =20 - ret =3D validate_branch(file, insn->func, insn, *state); + ret =3D validate_branch(file, insn_func(insn), insn, *state); if (ret && opts.backtrace) BT_FUNC("<=3D=3D=3D (sym)", insn); return ret; @@ -4104,7 +4109,7 @@ static int validate_ibt_insn(struct objtool_file *fil= e, struct instruction *insn continue; } =20 - if (dest->func && dest->func =3D=3D insn->func) { + if (insn_func(dest) && insn_func(dest) =3D=3D insn_func(insn)) { /* * Anything from->to self is either _THIS_IP_ or * IRET-to-self. diff --git a/tools/objtool/include/objtool/check.h b/tools/objtool/include/= objtool/check.h index 036129c..acd7fae 100644 --- a/tools/objtool/include/objtool/check.h +++ b/tools/objtool/include/objtool/check.h @@ -67,11 +67,21 @@ struct instruction { struct reloc *jump_table; struct reloc *reloc; struct list_head alts; - struct symbol *func; + struct symbol *sym; struct list_head stack_ops; struct cfi_state *cfi; }; =20 +static inline struct symbol *insn_func(struct instruction *insn) +{ + struct symbol *sym =3D insn->sym; + + if (sym && sym->type !=3D STT_FUNC) + sym =3D NULL; + + return sym; +} + #define VISITED_BRANCH 0x01 #define VISITED_BRANCH_UACCESS 0x02 #define VISITED_BRANCH_MASK 0x03