From nobody Sat Feb 7 21:14:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DA4AA1CCEEC; Tue, 3 Sep 2024 04:00:29 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336030; cv=none; b=Rnqx4oSVjve3+oKAEcB8WN+07LdvOEx/88AxlTlhunelb3FBsd4L71fznZalgffKHEqVtl0DJWcSAHk85zLLMXs4yTFcrFaOxI7YKPNJW9cUDLTOKn1WWpcWN77WeI4L8iiBgus8imN+vn0BKvR+5EMcEdBgZWTK26O5Dl5DlvU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336030; c=relaxed/simple; bh=JEag57dK28BIYne3Wua4KqbjKLoJ1F9duI+dzY3ghqc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nTJIkcnJIBDV6ntW6qiW/rHuhSv/D4JkY1JP0NGJYLo0xjq8t4etmnJnEUa06x/5j06BD5KN6LA7ex7zfkouiNsfwYQ/WjCOZNxaTNyAcilsApcfp6uzKgr56XUiRPqWOSCZkrckLxhr2/mZry3AH/YrX+g3zpqMeWkxd9holsY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=pBvgJqZY; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="pBvgJqZY" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2309DC4CEC9; Tue, 3 Sep 2024 04:00:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336029; bh=JEag57dK28BIYne3Wua4KqbjKLoJ1F9duI+dzY3ghqc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=pBvgJqZYJ+iofZadXi9Id5oRzvNCiDGAF4PIlXI7SorgqaHaBKF29YPMXZEcElBLo LmgPCdPgoc9OrrYh3a0JGzcajK2O131yD+x5Lp9Fp4plh9EshzObeItDyWQhILPoGj Zc7lrls+ju3c3KS16euDNho2p2/+Nr8vDqGS1PcJlwGb0dsB1xFUijRuQ8lJW4ugeJ eFL4ykHG3p72Vrr4K3YnoaSUKMurU+4S9U+vt/daMOeH/WiA2Dbc66zNQfPCb7B2pH JruvME7FmHwrtpDhcGehCtZTDnAK32OUZFANGNYDDJSQi1SPbcunY9OU/wen+uw/dr Yh6JRaULJQU6Q== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 01/31] x86/alternative: Refactor INT3 call emulation selftest Date: Mon, 2 Sep 2024 20:59:44 -0700 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The INT3 call emulation selftest is a bit fragile as it relies on the compiler not inserting any extra instructions before the int3_selftest_ip() definition. Also, the int3_selftest_ip() symbol overlaps with the int3_selftest symbol(), which can confuse tooling like objtool. Fix those issues by slightly reworking the functionality and moving int3_selftest_ip() to a separate asm function. While at it, improve the naming. Signed-off-by: Josh Poimboeuf --- arch/x86/kernel/alternative.c | 51 +++++++++++++++++++---------------- 1 file changed, 28 insertions(+), 23 deletions(-) diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 89de61243272..56fca5e6ba23 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -1546,21 +1546,34 @@ int alternatives_text_reserved(void *start, void *e= nd) * See entry_{32,64}.S for more details. */ =20 -/* - * We define the int3_magic() function in assembly to control the calling - * convention such that we can 'call' it from assembly. - */ - -extern void int3_magic(unsigned int *ptr); /* defined in asm */ +extern void int3_selftest_asm(unsigned int *ptr); =20 asm ( " .pushsection .init.text, \"ax\", @progbits\n" -" .type int3_magic, @function\n" -"int3_magic:\n" +" .type int3_selftest_asm, @function\n" +"int3_selftest_asm:\n" ANNOTATE_NOENDBR -" movl $1, (%" _ASM_ARG1 ")\n" + /* + * INT3 padded with NOP to CALL_INSN_SIZE. The INT3 triggers an + * exception, then the int3_exception_nb notifier emulates a call to + * int3_selftest_callee(). + */ +" int3; nop; nop; nop; nop\n" ASM_RET -" .size int3_magic, .-int3_magic\n" +" .size int3_selftest_asm, . - int3_selftest_asm\n" +" .popsection\n" +); + +extern void int3_selftest_callee(unsigned int *ptr); + +asm ( +" .pushsection .init.text, \"ax\", @progbits\n" +" .type int3_selftest_callee, @function\n" +"int3_selftest_callee:\n" + ANNOTATE_NOENDBR +" movl $0x1234, (%" _ASM_ARG1 ")\n" + ASM_RET +" .size int3_selftest_callee, . - int3_selftest_callee\n" " .popsection\n" ); =20 @@ -1569,7 +1582,7 @@ extern void int3_selftest_ip(void); /* defined in asm= below */ static int __init int3_exception_notify(struct notifier_block *self, unsigned long val, void= *data) { - unsigned long selftest =3D (unsigned long)&int3_selftest_ip; + unsigned long selftest =3D (unsigned long)&int3_selftest_asm; struct die_args *args =3D data; struct pt_regs *regs =3D args->regs; =20 @@ -1584,7 +1597,7 @@ int3_exception_notify(struct notifier_block *self, un= signed long val, void *data if (regs->ip - INT3_INSN_SIZE !=3D selftest) return NOTIFY_DONE; =20 - int3_emulate_call(regs, (unsigned long)&int3_magic); + int3_emulate_call(regs, (unsigned long)&int3_selftest_callee); return NOTIFY_STOP; } =20 @@ -1600,19 +1613,11 @@ static noinline void __init int3_selftest(void) BUG_ON(register_die_notifier(&int3_exception_nb)); =20 /* - * Basically: int3_magic(&val); but really complicated :-) - * - * INT3 padded with NOP to CALL_INSN_SIZE. The int3_exception_nb - * notifier above will emulate CALL for us. + * Basically: int3_selftest_callee(&val); but really complicated :-) */ - asm volatile ("int3_selftest_ip:\n\t" - ANNOTATE_NOENDBR - " int3; nop; nop; nop; nop\n\t" - : ASM_CALL_CONSTRAINT - : __ASM_SEL_RAW(a, D) (&val) - : "memory"); + int3_selftest_asm(&val); =20 - BUG_ON(val !=3D 1); + BUG_ON(val !=3D 0x1234); =20 unregister_die_notifier(&int3_exception_nb); } --=20 2.45.2 From nobody Sat Feb 7 21:14:57 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8015F1CDFCD; Tue, 3 Sep 2024 04:00:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336030; cv=none; b=ZidGj+jBMIAdxtVLaFgM7xSN8EiVYTaaRD+CXZOAqNl6YdGAtJs89ylrkjFd5V7MYnucs/TtKxQcXT8+jOuM3m4vUi9UDOJFL6gAOpA0UZlrktGZ4Bj9FnzEWK/Jdq7e0YjDWL0iLcksxh0OWrJkw0uVFKIXbKYTqUp8WFp3vQs= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336030; c=relaxed/simple; bh=OdbgV1d6SagFMFieLlZ7F3BDtff8ypL3ANe3ldIaiP8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=baHn0axhe2l1LQup4VIG/JjMeFAS5zzGezsaYE1UmeAnszXcuRfSrcG9rHUeTABcTdRO6vgEimQWwW4TwdC0Bzh04mdXamft45rIBpgfidxLNZmLEgh+85PlhJiDMuQiiQwvEYfb1uBY1mgRO7boz8uAc5WfsRl2hLKgmURA0kw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=iLjARiSH; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="iLjARiSH" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A014EC4CECC; Tue, 3 Sep 2024 04:00:29 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336030; bh=OdbgV1d6SagFMFieLlZ7F3BDtff8ypL3ANe3ldIaiP8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=iLjARiSHag+1IRFGydMoZumBS5I064mp+8QcARiPbQp6p79PuL0YJox2Mcqlf4YxU ne8H9PlSTx7FlVW2A5e2+UWJMw92YBK7er+t2bC0jypAwI4kvRVU/EajhVKUe1s/Uc 1jnKaUZkNUEvBTqiKEgQrdymcx432i5RXNfEeZ5c6tuS+TtKyJCdg74V1q7dCELF2f gOEqgP0rcR7U0i3Pd8PWKqcsd5d0X+6bfN+BlSfaikZZIX5KquLAvL3gzfRytC/MCl O9dzo9Sx9yeQ7ZuOFhx7S5UIHsS53gt39DHNrjREEq5WdwIWBIINobKOfYHIxRrkVQ 44TfmqWLWpsgw== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 02/31] x86/module: Improve relocation error messages Date: Mon, 2 Sep 2024 20:59:45 -0700 Message-ID: <0e89228c265405d9125a3630c127b51d04f80232.1725334260.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add the section number and reloc index to relocation error messages to help find the faulty relocation. Signed-off-by: Josh Poimboeuf --- arch/x86/kernel/module.c | 15 +++++++++------ kernel/livepatch/core.c | 4 ++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/arch/x86/kernel/module.c b/arch/x86/kernel/module.c index 837450b6e882..c09651691dd6 100644 --- a/arch/x86/kernel/module.c +++ b/arch/x86/kernel/module.c @@ -96,6 +96,7 @@ static int __write_relocate_add(Elf64_Shdr *sechdrs, DEBUGP("%s relocate section %u to %u\n", apply ? "Applying" : "Clearing", relsec, sechdrs[relsec].sh_info); + for (i =3D 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { size_t size; =20 @@ -147,15 +148,17 @@ static int __write_relocate_add(Elf64_Shdr *sechdrs, =20 if (apply) { if (memcmp(loc, &zero, size)) { - pr_err("x86/modules: Invalid relocation target, existing value is nonz= ero for type %d, loc %p, val %Lx\n", - (int)ELF64_R_TYPE(rel[i].r_info), loc, val); + pr_err("x86/modules: Invalid relocation target, existing value is nonz= ero for sec %u, idx %u, type %d, loc %lx, val %Lx\n", + relsec, i, (int)ELF64_R_TYPE(rel[i].r_info), + (unsigned long)loc, val); return -ENOEXEC; } write(loc, &val, size); } else { if (memcmp(loc, &val, size)) { - pr_warn("x86/modules: Invalid relocation target, existing value does n= ot match expected value for type %d, loc %p, val %Lx\n", - (int)ELF64_R_TYPE(rel[i].r_info), loc, val); + pr_warn("x86/modules: Invalid relocation target, existing value does n= ot match expected value for sec %u, idx %u, type %d, loc %lx, val %Lx\n", + relsec, i, (int)ELF64_R_TYPE(rel[i].r_info), + (unsigned long)loc, val); return -ENOEXEC; } write(loc, &zero, size); @@ -164,8 +167,8 @@ static int __write_relocate_add(Elf64_Shdr *sechdrs, return 0; =20 overflow: - pr_err("overflow in relocation type %d val %Lx\n", - (int)ELF64_R_TYPE(rel[i].r_info), val); + pr_err("overflow in relocation type %d val %Lx sec %u idx %d\n", + (int)ELF64_R_TYPE(rel[i].r_info), val, relsec, i); pr_err("`%s' likely not compiled with -mcmodel=3Dkernel\n", me->name); return -ENOEXEC; diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 52426665eecc..76ffe29934d4 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -219,8 +219,8 @@ static int klp_resolve_symbols(Elf_Shdr *sechdrs, const= char *strtab, for (i =3D 0; i < relasec->sh_size / sizeof(Elf_Rela); i++) { sym =3D (Elf_Sym *)sechdrs[symndx].sh_addr + ELF_R_SYM(relas[i].r_info); if (sym->st_shndx !=3D SHN_LIVEPATCH) { - pr_err("symbol %s is not marked as a livepatch symbol\n", - strtab + sym->st_name); + pr_err("symbol %s at rela sec %u idx %d is not marked as a livepatch sy= mbol\n", + strtab + sym->st_name, symndx, i); return -EINVAL; } =20 --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 84C481CE702; Tue, 3 Sep 2024 04:00:30 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336031; cv=none; b=CXUyP24s6PX003wCBbV2rsQ3PSLLK/F5FF2NBtCpJVjSmfh2FK19riBSPolCXy+ct+aykbaXpfeGLZHPFm0TlDw4WNhcKF7LGxMT7LeevIAiJnMvdlUCB2JAT/FOnxzJS/rpqOZ/IQCz5EfIxbsa0lOP7cAdPiqF5EdSyh905oM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336031; c=relaxed/simple; bh=p+eNZnmbPNAzBwrF+DnHcCqKwjEEMYp4aw6pdpoU2q8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dgmdqMQvlKxRZwMBBNV98bftg6zJSQxp64m73lB/FcvlNBIkKoS2v6Wwnj08pjBmZquQZSg7dlZF0EP5X4/sqkQI1PnUlwvexDh0OMayUgrvqbUjh86Dms5Py7/hzeeAcNdve2Lp2D/Klab44yjamG8Y1YvIvZ4lZ5YrrxeOK6E= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ezFWIhFY; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ezFWIhFY" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2921FC4CED1; Tue, 3 Sep 2024 04:00:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336030; bh=p+eNZnmbPNAzBwrF+DnHcCqKwjEEMYp4aw6pdpoU2q8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ezFWIhFYecgcbF3EDR8Yup5jVRKouY6GLGQovs5q4c6ySWIEge1agxqTOrA8zQ3bW hx6YPjG/5JDQGWE0pq3wOuAVCWU8rIUgeF59306zNzQ8m2ZlgCV+xLlnrfFNxZyYrR QmVPCAQVWiBQJNPI9uj9adeAu5NUUZVfJ7b608V/73pY0z74Gp4/web9W461u/JLe+ 9w2gv7AO3nHCvKDAnGCIBFHwHihkcn0quGCbi2610A9oC944fAF8PghG0HUrTjIn80 Vo099bVM+dG49OU23LDtQRcinPMB+2zibxxmL4KURHPokE894sogc8U6CyzXrPmjiZ cVINuU7h1Fz7Q== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 03/31] x86/kprobes: Remove STACK_FRAME_NON_STANDARD annotation Date: Mon, 2 Sep 2024 20:59:46 -0700 Message-ID: <5902e2e9cfe2ed9224f165585d7e41f93bb04275.1725334260.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Since commit 877b145f0f47 ("x86/kprobes: Move trampoline code into RODATA"), the optprobe template code is no longer analyzed by objtool so it doesn't need to be ignored. Signed-off-by: Josh Poimboeuf --- arch/x86/kernel/kprobes/opt.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c index 36d6809c6c9e..e46d1710e785 100644 --- a/arch/x86/kernel/kprobes/opt.c +++ b/arch/x86/kernel/kprobes/opt.c @@ -103,7 +103,6 @@ static void synthesize_set_arg1(kprobe_opcode_t *addr, = unsigned long val) =20 asm ( ".pushsection .rodata\n" - "optprobe_template_func:\n" ".global optprobe_template_entry\n" "optprobe_template_entry:\n" #ifdef CONFIG_X86_64 @@ -160,9 +159,6 @@ asm ( "optprobe_template_end:\n" ".popsection\n"); =20 -void optprobe_template_func(void); -STACK_FRAME_NON_STANDARD(optprobe_template_func); - #define TMPL_CLAC_IDX \ ((long)optprobe_template_clac - (long)optprobe_template_entry) #define TMPL_MOVE_IDX \ --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 84C981CE708; Tue, 3 Sep 2024 04:00:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336031; cv=none; b=bii1qSSFVgrJJWLSK9VBNqNIjiq3WU3yIZCPW8i+P/39nX+SaLYWI1xPyoPpZgk/OpTzRL6FLWgJUz7x7jPXv0f4VolTNrvg9QcLuO5gEEDbtHVrpQpDEVTnLZcvxN2L+0kK+duc4xxBpZcq0D1Dmawq800zF0ISlGUdug8cVzI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336031; c=relaxed/simple; bh=eVWw//8hfsmd9PQaCYwE+A1M1gV4cGzk9SxhhPEd0cI=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZFLZai7SA7JsTlwbM5VyY/xHdxxDOKjsOCoJ03SEKm5E6Qg/Vw+K+hiJJQqJgwUP9PRfc/uZixSbsRHYQLFEgLOYqwHVp/DhJ8lUVFPpqNZ0dj0I0Ct2mU8pPbh2QLKMpqqvgX0X5kwM1oXDAYCP8isPh7EZ5cyiOT8hPOlq2Zw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=QfNtunj0; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="QfNtunj0" Received: by smtp.kernel.org (Postfix) with ESMTPSA id A57A9C4CECB; Tue, 3 Sep 2024 04:00:30 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336031; bh=eVWw//8hfsmd9PQaCYwE+A1M1gV4cGzk9SxhhPEd0cI=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=QfNtunj0JiQlTj5nRdl/EOKKUfmzCi7EDtEUtA6/QChRPMb/ZaNnnH3aQ76aIhIl9 UVEkM8pOuBNWGviqEULB+SAPZkhqlYdw/pwkXMZEKAHzJzKEg82xNfRFdQgYbcKo1s GXxGdQz7jNODyzs6raCTDjOp0RMcekvT3CZTsUGQ8dF7nCOdKCvjJIR7r8S/ZqHk7f sUwBVP/8VgXboRi1L+QbbukYqxf3+bDc8TPou2L6dLC/ML4UzyUYsE7OQMmjIthSYy 6d78LcQZN51BTJMhG5l3KQZw/agihIy+Dk6sWOZmlCkfOaBli/nErogSbBW02x/6xk iu5566KYCbEiA== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 04/31] kernel/sys: Don't reference UTS_RELEASE directly Date: Mon, 2 Sep 2024 20:59:47 -0700 Message-ID: <203eaa28b60bef8f4396beed554358e3c2483a07.1725334260.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Objtool will be getting a new feature to calculate build-time function checksums, so each function can be uniquely identified. A function's checksum is calculated based on its instructions, jump/call targets, alternatives, string literals, and more. When there are any changes to the git working tree, UTS_RELEASE is suffixed with "+". That can result in an undesired changed checksum for the functions which inline override_release() due to its direct reference of the UTS_RELEASE string literal. Convert the override_release() 'rest' variable to a static local so it won't affect function checksums. Signed-off-by: Josh Poimboeuf --- kernel/sys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kernel/sys.c b/kernel/sys.c index 3a2df1bd9f64..526464ea194b 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -1291,7 +1291,7 @@ static int override_release(char __user *release, siz= e_t len) int ret =3D 0; =20 if (current->personality & UNAME26) { - const char *rest =3D UTS_RELEASE; + static const char *rest =3D UTS_RELEASE; char buf[65] =3D { 0 }; int ndots =3D 0; unsigned v; --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B08221CE715; Tue, 3 Sep 2024 04:00:31 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336031; cv=none; b=fzf/grGLr3VDQKc+GRSiTJFyUNyhHHIW35l31wLXRHlYVAUiIU/ZGj9xeMii14B8Unje6bhvxR8CofOJx3zBsOlsgc0aIPd0zCFEWd5YE+7d0/F50mBTuA0HIZfWOebvJAcfIuMqPyaeWShX/2V3MGpApZ099EHfUGYvIJDHCew= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336031; c=relaxed/simple; bh=q2M88CS52CpmfIl0QNGMiagRm1TTYcO/UMxEQqGVUOg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=fYnH/YhuItZKdok6O1jigq82nUUaotjhvXP3eS+/7Y3z8utT5mnmkXlmpRE5WEvaiy1+VAWw4PTxbZalNlK+/2T5VI3PCtfynuIQpu98gS2Px3wx0QfZX3pH8dlmG8G5boFG7msC7TEixAd3V2SscP1gWHqyNbEgIvBQJGXDZpw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=IbrlWp1T; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="IbrlWp1T" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2FAD8C4CECD; Tue, 3 Sep 2024 04:00:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336031; bh=q2M88CS52CpmfIl0QNGMiagRm1TTYcO/UMxEQqGVUOg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=IbrlWp1TIJRiFfNFQbeCJ0wH21WhFV2v9bMa/lVC0IV4PutiC8o6MFSy+VmF6zV3r nUtGET+Incg0B141jBW7RFW0tVvZZhLU/LOd/qil5KbrZQ918v5tXsP1tKOo6+PcKD CROZwCaQ5nzqAOZ8RJF7go9GGddUKlE+5pko0k5NIevXwz7MHnocXGNh36piMdij8f IQteoBOdA3Gn/9HG9Joon4YxRsvy/RV9xqBq32ry9djAapUBRQHPpDD1qgYv7rafr4 t4C/99AS3slIfqWz6M1be2Mn9y7kMethXnH/5esB5yOofkMGFdLSGu4I8xH1qWraX3 8CzhHf9UsEujg== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 05/31] x86/compiler: Tweak __UNIQUE_ID naming Date: Mon, 2 Sep 2024 20:59:48 -0700 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add an underscore between the "name" and the counter so tooling can distinguish between the non-unique and unique portions of the symbol name. This will come in handy for "objtool klp diff". Signed-off-by: Josh Poimboeuf --- include/linux/compiler.h | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/include/linux/compiler.h b/include/linux/compiler.h index 8c252e073bd8..d3f100821d45 100644 --- a/include/linux/compiler.h +++ b/include/linux/compiler.h @@ -186,7 +186,11 @@ void ftrace_likely_update(struct ftrace_likely_data *f= , int val, __asm__ ("" : "=3Dr" (var) : "0" (var)) #endif =20 -#define __UNIQUE_ID(prefix) __PASTE(__PASTE(__UNIQUE_ID_, prefix), __COUNT= ER__) +/* Format: __UNIQUE_ID__<__COUNTER__> */ +#define __UNIQUE_ID(name) \ + __PASTE(__UNIQUE_ID_, \ + __PASTE(name, \ + __PASTE(_, __COUNTER__))) =20 /** * data_race - mark an expression as containing intentional data races @@ -218,7 +222,7 @@ void ftrace_likely_update(struct ftrace_likely_data *f,= int val, */ #define ___ADDRESSABLE(sym, __attrs) \ static void * __used __attrs \ - __UNIQUE_ID(__PASTE(__addressable_,sym)) =3D (void *)(uintptr_t)&sym; + __UNIQUE_ID(__PASTE(addressable_, sym)) =3D (void *)(uintptr_t)&sym; #define __ADDRESSABLE(sym) \ ___ADDRESSABLE(sym, __section(".discard.addressable")) =20 --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3303D1CEAC1; Tue, 3 Sep 2024 04:00:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336032; cv=none; b=ZcGLT5bMDgA9kumkJ7sQ12WwR2OQF/cYR4xUvTmHLp/t2ggnSIbuDP/PmFn4tJ9rDvfIWNIAjZh33Z/+5DsHL0OEGHLAyMEMJBvMtp55njzrlckSOr1cCmEgaNiOVRLR9N0pFrvZw+fsiOro36f2a0yzJNsqztJy6KnuSUSeeUI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336032; c=relaxed/simple; bh=D66bvgjTzEHS1IUZEykzKYLBEGl7MWwVq4oNeoxG36E=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JygVzhwRxloPDMXUMfJL/kJd42Rek30oWd0Xcbz81SXH/Qo65srWE0XckoQnbpkgBBkRei8Fg5qNEZ7G4MBIlynIAeXkrSYkBUKxebZxRTN3r5LLpESRbrjUjc9kZI8PIFnmWva3P98QByRwto9kKQetyUrpMjyChesJli0Hj6U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=iAIymmtP; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="iAIymmtP" Received: by smtp.kernel.org (Postfix) with ESMTPSA id AC36FC4CECB; Tue, 3 Sep 2024 04:00:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336032; bh=D66bvgjTzEHS1IUZEykzKYLBEGl7MWwVq4oNeoxG36E=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=iAIymmtPm0nMdV9Rz7kru4HMAeAVnXLd3+fmOd0mjcUlx4JuSb1FQyuLG6e0t+jCU sgmczaS/2dSI5bYVAQyncK2vXpzNfaVU4T83iY2zf5JGKW6++Vzy6y/bsVi/DOAElG Ygn6kPzndpOVbUFc9x3eCqeFgpFPBVxI11WX5YoxZJTCs1IP/3Q7uJVyjdYZozrMqK RNHFqDPHdtLMLuuj7GqArRfAMeg7yoJNRjcUBBgIXprXZH4pC5IcMOPeK5uOvA1nwT tNFtOVHvOd8EoMAsdU/3e00c7dMg+r7VhK49Ts8pmWKM9+2dhjuWmim2rC1zrNGR58 vkq0XTvV5sH0g== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 06/31] elfnote: Use __UNIQUE_ID() for note symbols Date: Mon, 2 Sep 2024 20:59:49 -0700 Message-ID: <4a9e9d529a2be6265999a669f921a39991bfdd63.1725334260.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The name of an ELF note symbol isn't important. It just needs to be unique. Simplify by using the existing __UNIQUE_ID() macro. Signed-off-by: Josh Poimboeuf --- include/linux/elfnote.h | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/include/linux/elfnote.h b/include/linux/elfnote.h index 69b136e4dd2b..6398af0bb601 100644 --- a/include/linux/elfnote.h +++ b/include/linux/elfnote.h @@ -64,19 +64,16 @@ * Use an anonymous structure which matches the shape of * Elf{32,64}_Nhdr, but includes the name and desc data. The size and * type of name and desc depend on the macro arguments. "name" must - * be a literal string, and "desc" must be passed by value. You may - * only define one note per line, since __LINE__ is used to generate - * unique symbols. + * be a literal string, and "desc" must be passed by value. */ -#define _ELFNOTE_PASTE(a,b) a##b -#define _ELFNOTE(size, name, unique, type, desc) \ +#define ELFNOTE(size, name, type, desc) \ static const struct { \ struct elf##size##_note _nhdr; \ unsigned char _name[sizeof(name)] \ __attribute__((aligned(sizeof(Elf##size##_Word)))); \ typeof(desc) _desc \ __attribute__((aligned(sizeof(Elf##size##_Word)))); \ - } _ELFNOTE_PASTE(_note_, unique) \ + } __UNIQUE_ID(note) \ __used \ __attribute__((section(".note." name), \ aligned(sizeof(Elf##size##_Word)), \ @@ -89,11 +86,10 @@ name, \ desc \ } -#define ELFNOTE(size, name, type, desc) \ - _ELFNOTE(size, name, __LINE__, type, desc) =20 #define ELFNOTE32(name, type, desc) ELFNOTE(32, name, type, desc) #define ELFNOTE64(name, type, desc) ELFNOTE(64, name, type, desc) + #endif /* __ASSEMBLER__ */ =20 #endif /* _LINUX_ELFNOTE_H */ --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 115831CFEBD; Tue, 3 Sep 2024 04:00:32 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336034; cv=none; b=DTvEv9p/PSDt7KpsfIUR3+lGPEMf9eX1sQTBHM1vW8no39FvynLDgIAca7yHM5sMZsxqJiV9DvBVXIjrcAb8ZhI7H/OuyUEdsxTt5c5ymP4fkoH5IsAQf7s+QrHjmbFu8QqIKi+mNEKw8h2bXo5NOnNykWctUUOlqZsPDTipfvE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336034; c=relaxed/simple; bh=BQEb3OPU43WZ4vRis1H8WUXjg0vebOt0ENV2ilISPVY=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UlZx8lnyisU6CpKdxa/WPbJ48KxstksfzLQrCjoVoNJx55HBrVyib3xMoemmOW+OPhIOV9bHX3fJH9ifdob5MGVS4jsRGBC+soDSSH35PGTXKmQwtHfTpNzPtP/Db8HI4PkacU9dtm0NcC1yWBSW4bVP2TNmM4XUadgqfGmhYAU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=qge5XARI; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="qge5XARI" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 35F3FC4CEC5; Tue, 3 Sep 2024 04:00:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336032; bh=BQEb3OPU43WZ4vRis1H8WUXjg0vebOt0ENV2ilISPVY=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=qge5XARI/yOoOY6J1JgB2tTtfvKuivdFfE6B8iqOBP4UyMZ4ilV5hwnA2Gd8TC8w+ OS1JMJ0fEELc1T15Z4VpH1eMSEsAEmE6LQGVx4GQIiLhsA9RMzIps8/RMuSaSPLK38 eyuTWIoq9Gr/WtiTCwqcJTcLORwO8VFlJjxG+NwNAoOtsyo35syb+7Ml1FNj0W6Jqh NeT2rGF1XC+s6595wFniyPWEosh37VUm5nAdlqEWjUe6oIvw9th8nVZYM741vd0ci2 VeosnEoFofdwLgPPU3sGUJVba9lq/j4+aWS3rBrtl5G1PQUi6dDxnD4kAEMSl5HwM7 ndPY+tr0juzLA== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 07/31] kbuild: Remove "kmod" prefix from __KBUILD_MODNAME Date: Mon, 2 Sep 2024 20:59:50 -0700 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Remove the arbitrary "kmod" prefix from __KBUILD_MODNAME and add it back manually in the __initcall_id() macro. This makes it more consistent, now __KBUILD_MODNAME is just the non-stringified version of KBUILD_MODNAME. It will come in handy for the upcoming "objtool klp diff". Signed-off-by: Josh Poimboeuf --- include/linux/init.h | 3 ++- scripts/Makefile.lib | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/include/linux/init.h b/include/linux/init.h index 58cef4c2e59a..b1921f4a7b7e 100644 --- a/include/linux/init.h +++ b/include/linux/init.h @@ -206,12 +206,13 @@ extern struct module __this_module; =20 /* Format: ____ */ #define __initcall_id(fn) \ + __PASTE(kmod_, \ __PASTE(__KBUILD_MODNAME, \ __PASTE(__, \ __PASTE(__COUNTER__, \ __PASTE(_, \ __PASTE(__LINE__, \ - __PASTE(_, fn)))))) + __PASTE(_, fn))))))) =20 /* Format: ____ */ #define __initcall_name(prefix, __iid, id) \ diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 9f06f6aaf7fc..8411e3d53938 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -130,7 +130,7 @@ name-fix-token =3D $(subst $(comma),_,$(subst -,_,$1)) name-fix =3D $(call stringify,$(call name-fix-token,$1)) basename_flags =3D -DKBUILD_BASENAME=3D$(call name-fix,$(basetarget)) modname_flags =3D -DKBUILD_MODNAME=3D$(call name-fix,$(modname)) \ - -D__KBUILD_MODNAME=3Dkmod_$(call name-fix-token,$(modname)) + -D__KBUILD_MODNAME=3D$(call name-fix-token,$(modname)) modfile_flags =3D -DKBUILD_MODFILE=3D$(call stringify,$(modfile)) =20 _c_flags =3D $(filter-out $(CFLAGS_REMOVE_$(target-stem).o), \ --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4A1CE1CF2AA; Tue, 3 Sep 2024 04:00:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336033; cv=none; b=BCUyawJWJefwVZxRPy6f03EehwbgNypGRlEoxmPpaRQrBJb7rJ6NQuzlQpK1Y4/DDhlpv2FLkWfFnQ0ziY16JvegSZQrTYI4AN4FMboCPrrGaQbW1i6Phi44md+b8MuBpxrcrHpnOockKKuoUR1M2pEILrYBFSSt/0ZyBKmE+QE= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336033; c=relaxed/simple; bh=8L3QglbaM3/yArmGhVUyyehtSdjxCRaSBZndVSMzeKE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=DMJoVGzK4VgNYV8rgGoGx3oDmmdPymqmQHjc5LhtQCWjyRF+4NbX4RoC/lysnXOBm4Nh/gvMk3/c9rwlEn5xMjXh423/Wn1nlXtZtLY7LkRQUsSIQaCTyGNMNIq8S80kEfsIsSKMei1642oBpfC2mlWczPDkc6Zb1ogsbW/gIBM= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=mJdrH2b3; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="mJdrH2b3" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B5B82C4CECD; Tue, 3 Sep 2024 04:00:32 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336033; bh=8L3QglbaM3/yArmGhVUyyehtSdjxCRaSBZndVSMzeKE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=mJdrH2b3yOgWrE1A1aZ7Y1g1nRHT00n3GbKJJdIbqzjKH55hSKvm7cUKuE/VosRE4 saZ+F67feTfx9qRoLwKc0p1mV0/b7VbdtZC5nvDd0AfzBuPqUq7hD8/1tuJesS6Z32 gr4stfCBJ/aWZOSgQk6JPv1rFhNhHo6bQCYetftaYGk1gNGNUEJh8wORlCkyDVjiVM DVQdUaJGFmEeT4TLdzfdfoiNfD1zewxB0Rl3ikI8Bb6QZHQWblGpSwSacrNGlgIUkP fZUSOhVb/iiI8AnmmwStBoOouDgAY9rX1sNwAiBhQGbAzBq/Gk2sXg9dqoYzlK1eFO E77NAvDqijUzQ== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 08/31] objtool: Remove .parainstructions reference Date: Mon, 2 Sep 2024 20:59:51 -0700 Message-ID: <121ee9edb1998fd7637f20b5c36b0c9d25e8bda3.1725334260.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The section no longer exists since commit 60bc276b129e ("x86/paravirt: Switch mixed paravirt/alternative calls to alternatives"). Signed-off-by: Josh Poimboeuf --- tools/objtool/check.c | 1 - 1 file changed, 1 deletion(-) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 0a33d9195b7a..a813a6194c61 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -4477,7 +4477,6 @@ static int validate_ibt(struct objtool_file *file) !strcmp(sec->name, ".altinstructions") || !strcmp(sec->name, ".ibt_endbr_seal") || !strcmp(sec->name, ".orc_unwind_ip") || - !strcmp(sec->name, ".parainstructions") || !strcmp(sec->name, ".retpoline_sites") || !strcmp(sec->name, ".smp_locks") || !strcmp(sec->name, ".static_call_sites") || --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 115281CFEBB; Tue, 3 Sep 2024 04:00:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336034; cv=none; b=m7S1rA0gY5DdvqEIilQWqGQKiYIQF2f6+0Y8yAVE4z84IhIrsFCF7ZZyvecQ6Hv1zVlv9RGOfVKnh3NfZsnnOzhvphYzh6IcWcISG6oTqYmMBdijMOxz0b2wCsxgkHomvgz4MEnRlXw5iJs/jmp/Nd1uffs9ddZkb0X8/F0BfBw= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336034; c=relaxed/simple; bh=hOnZJQAIf7DMQw4XeYc5i9YjThTL4d34Ct/XPnL/qk8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=QGV/Yw/cDMZdvM8koqUXuOJAGzc238Zqj/vGwbT/6ABWU1m6cRWk0I19Jwix1ZJZQbjgaGxfjVDDBtHTONXGgeaCMMY7I252hLIOOzsVCAV1jEOVUAcwEgX0bJApdwrIf9yhe255CiEQFNBSWoaARjpExw+0PsxdauNwh/RdK4w= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=OUqqo7Uy; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="OUqqo7Uy" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 4C87EC4CED0; Tue, 3 Sep 2024 04:00:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336033; bh=hOnZJQAIf7DMQw4XeYc5i9YjThTL4d34Ct/XPnL/qk8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=OUqqo7UyX0Vrh5wpavxgKqfl3R2LyrgGZ1yhtNDnPoLAqMbmyO2yM34BAW9zRsZ0V uP0KWte615CepuEs9mk/+nyezt9G1PlbImt8k1fSjHjlG0OvhKK39WK7ZIEcd9JETM Hsz5P/pln5XDg+9S+8cbYyHBQzwJ176M4KjVXAR+WdelHXb5MfR5hh2gy8sZAn5LFO q+HkWN9J5xnkuX20B5gsMnIT1AWszAbxqGxDYqZxGB7Ndnplj6feB4rP3G4bnY6qHg L0ILSISsD/PnbYS/K9arnm+eOwkZgkybkky75E/qfruUhgkWU75oe8t/g5uEwMLacp z7BOKccYJ8tgQ== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 09/31] objtool: Const string cleanup Date: Mon, 2 Sep 2024 20:59:52 -0700 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Use 'const char *' where applicable. Signed-off-by: Josh Poimboeuf --- tools/objtool/arch/loongarch/decode.c | 2 +- tools/objtool/arch/powerpc/decode.c | 2 +- tools/objtool/arch/x86/decode.c | 2 +- tools/objtool/elf.c | 6 +++--- tools/objtool/include/objtool/arch.h | 2 +- tools/objtool/include/objtool/elf.h | 6 +++--- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tools/objtool/arch/loongarch/decode.c b/tools/objtool/arch/loo= ngarch/decode.c index aee479d2191c..ef09996c772e 100644 --- a/tools/objtool/arch/loongarch/decode.c +++ b/tools/objtool/arch/loongarch/decode.c @@ -10,7 +10,7 @@ #define EM_LOONGARCH 258 #endif =20 -int arch_ftrace_match(char *name) +int arch_ftrace_match(const char *name) { return !strcmp(name, "_mcount"); } diff --git a/tools/objtool/arch/powerpc/decode.c b/tools/objtool/arch/power= pc/decode.c index 53b55690f320..29e05ad1b8b6 100644 --- a/tools/objtool/arch/powerpc/decode.c +++ b/tools/objtool/arch/powerpc/decode.c @@ -9,7 +9,7 @@ #include #include =20 -int arch_ftrace_match(char *name) +int arch_ftrace_match(const char *name) { return !strcmp(name, "_mcount"); } diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decod= e.c index 3a1d80a7878d..1b24b05eff09 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -23,7 +23,7 @@ #include #include =20 -int arch_ftrace_match(char *name) +int arch_ftrace_match(const char *name) { return !strcmp(name, "__fentry__"); } diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 3d27983dc908..b42ee4ef7015 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -814,7 +814,7 @@ elf_create_section_symbol(struct elf *elf, struct secti= on *sec) return sym; } =20 -static int elf_add_string(struct elf *elf, struct section *strtab, char *s= tr); +static int elf_add_string(struct elf *elf, struct section *strtab, const c= har *str); =20 struct symbol * elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size) @@ -1048,7 +1048,7 @@ struct elf *elf_open_read(const char *name, int flags) return NULL; } =20 -static int elf_add_string(struct elf *elf, struct section *strtab, char *s= tr) +static int elf_add_string(struct elf *elf, struct section *strtab, const c= har *str) { Elf_Data *data; Elf_Scn *s; @@ -1073,7 +1073,7 @@ static int elf_add_string(struct elf *elf, struct sec= tion *strtab, char *str) return -1; } =20 - data->d_buf =3D str; + data->d_buf =3D strdup(str); data->d_size =3D strlen(str) + 1; data->d_align =3D 1; =20 diff --git a/tools/objtool/include/objtool/arch.h b/tools/objtool/include/o= bjtool/arch.h index 0b303eba660e..f48f5109abb1 100644 --- a/tools/objtool/include/objtool/arch.h +++ b/tools/objtool/include/objtool/arch.h @@ -69,7 +69,7 @@ struct stack_op { =20 struct instruction; =20 -int arch_ftrace_match(char *name); +int arch_ftrace_match(const char *name); =20 void arch_initial_func_cfi_state(struct cfi_init_state *state); =20 diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/ob= jtool/elf.h index 2b8a69de4db8..a027fc34d605 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -40,7 +40,7 @@ struct section { struct section *base, *rsec; struct symbol *sym; Elf_Data *data; - char *name; + const char *name; int idx; bool _changed, text, rodata, noinstr, init, truncate; struct reloc *relocs; @@ -53,7 +53,7 @@ struct symbol { struct elf_hash_node name_hash; GElf_Sym sym; struct section *sec; - char *name; + const char *name; unsigned int idx, len; unsigned long offset; unsigned long __subtree_last; @@ -84,7 +84,7 @@ struct elf { GElf_Ehdr ehdr; int fd; bool changed; - char *name; + const char *name; unsigned int num_files; struct list_head sections; unsigned long num_relocs; --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 4D5C71CFED2; Tue, 3 Sep 2024 04:00:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336034; cv=none; b=UkjE8SBPwAy34RQf8OFQws1DhAhpzboRustniazYJ7UOMrIltYzV5ofljUY4vnH69GrvX1ilUqmRPHlvPBxTGs/aWCX4IeIg9ue0biwerCx5i4wCrXToDTzydh3cofFce9CT6BlZX3RpdCoXNXKPc3huiRedQTMFqHktGh0TDJU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336034; c=relaxed/simple; bh=9dCrDC0dI0bCabg/XMOLC9FAJQvbJGfs6BK4o9Tsleo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=AtHFHbmuRAS9DZm3pKqaCZ81iNr0FRrHNg0izhBccea4sOxiinWsEHL3R5wCHdgP6Pi9z5tMc4fSUqV7KFBkHDJRBWG4NZppF8wWZoFzoKZ03GDug/Zcz4Y8QZmZhn4+cfYRushlFai02Irhhrn6TiTwicsGSkWZeXT0oKw4bS8= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=aF0Kp2+/; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="aF0Kp2+/" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C9135C4CECA; Tue, 3 Sep 2024 04:00:33 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336034; bh=9dCrDC0dI0bCabg/XMOLC9FAJQvbJGfs6BK4o9Tsleo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=aF0Kp2+/G7I1VUa+hQVsLmLjc2DnkozVD1qomYO2Wk+DAUVM3T0naSgQavELeSTzt CM9OLiAFtg7ryc8qyeuYuoQxNFp/srOhGTPikmxdySORRzeAd+lYNGaQtpYb+PeCpW zNv0G6rkKXpHtsv2lnrSjrV8P1N4QZyqUgcYO63riVGcdsnM956P4q6JD44ErGxgTF JQD4kpWqupqgaCWUvzVzSx1UKurCB8lqgZDkgjT+e06FKBcLakfyGi3svhGYLoZ2Fs dcNX0c9x6Ji8IY14Qc4KWgfYasQDmvcqaqNMkZkOLgzQCTLr2ibxddaNWHGY6WFOD7 NLPsUehmFHYCQ== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 10/31] objtool: Use 'struct elf' in elf macros Date: Mon, 2 Sep 2024 20:59:53 -0700 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" 'struct objtool_file' is specific to the check code and doesn't belong in the elf code. Signed-off-by: Josh Poimboeuf --- tools/objtool/check.c | 22 +++++++++++----------- tools/objtool/include/objtool/elf.h | 8 ++++---- tools/objtool/orc_gen.c | 2 +- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index a813a6194c61..06e7b3f5481d 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -107,7 +107,7 @@ static struct instruction *prev_insn_same_sym(struct ob= jtool_file *file, #define for_each_insn(file, insn) \ for (struct section *__sec, *__fake =3D (struct section *)1; \ __fake; __fake =3D NULL) \ - for_each_sec(file, __sec) \ + for_each_sec(file->elf, __sec) \ sec_for_each_insn(file, __sec, insn) =20 #define func_for_each_insn(file, func, insn) \ @@ -374,7 +374,7 @@ static int decode_instructions(struct objtool_file *fil= e) struct instruction *insn; int ret; =20 - for_each_sec(file, sec) { + for_each_sec(file->elf, sec) { struct instruction *insns =3D NULL; u8 prev_len =3D 0; u8 idx =3D 0; @@ -899,7 +899,7 @@ static int create_cfi_sections(struct objtool_file *fil= e) } =20 idx =3D 0; - for_each_sym(file, sym) { + for_each_sym(file->elf, sym) { if (sym->type !=3D STT_FUNC) continue; =20 @@ -915,7 +915,7 @@ static int create_cfi_sections(struct objtool_file *fil= e) return -1; =20 idx =3D 0; - for_each_sym(file, sym) { + for_each_sym(file->elf, sym) { if (sym->type !=3D STT_FUNC) continue; =20 @@ -2198,7 +2198,7 @@ static int add_jump_table_alts(struct objtool_file *f= ile) if (!file->rodata) return 0; =20 - for_each_sym(file, func) { + for_each_sym(file->elf, func) { if (func->type !=3D STT_FUNC) continue; =20 @@ -2534,7 +2534,7 @@ static int classify_symbols(struct objtool_file *file) { struct symbol *func; =20 - for_each_sym(file, func) { + for_each_sym(file->elf, func) { if (func->type =3D=3D STT_NOTYPE && strstarts(func->name, ".L")) func->local_label =3D true; =20 @@ -2579,7 +2579,7 @@ static void mark_rodata(struct objtool_file *file) * * .rodata.str1.* sections are ignored; they don't contain jump tables. */ - for_each_sec(file, sec) { + for_each_sec(file->elf, sec) { if (!strncmp(sec->name, ".rodata", 7) && !strstr(sec->name, ".str1.")) { sec->rodata =3D true; @@ -4198,7 +4198,7 @@ static int add_prefix_symbols(struct objtool_file *fi= le) struct section *sec; struct symbol *func; =20 - for_each_sec(file, sec) { + for_each_sec(file->elf, sec) { if (!(sec->sh.sh_flags & SHF_EXECINSTR)) continue; =20 @@ -4289,7 +4289,7 @@ static int validate_functions(struct objtool_file *fi= le) struct section *sec; int warnings =3D 0; =20 - for_each_sec(file, sec) { + for_each_sec(file->elf, sec) { if (!(sec->sh.sh_flags & SHF_EXECINSTR)) continue; =20 @@ -4458,7 +4458,7 @@ static int validate_ibt(struct objtool_file *file) for_each_insn(file, insn) warnings +=3D validate_ibt_insn(file, insn); =20 - for_each_sec(file, sec) { + for_each_sec(file->elf, sec) { =20 /* Already done by validate_ibt_insn() */ if (sec->sh.sh_flags & SHF_EXECINSTR) @@ -4645,7 +4645,7 @@ static int disas_warned_funcs(struct objtool_file *fi= le) struct symbol *sym; char *funcs =3D NULL, *tmp; =20 - for_each_sym(file, sym) { + for_each_sym(file->elf, sym) { if (sym->warned) { if (!funcs) { funcs =3D malloc(strlen(sym->name) + 1); diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/ob= jtool/elf.h index a027fc34d605..7524510b5565 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -296,16 +296,16 @@ static inline void set_reloc_type(struct elf *elf, st= ruct reloc *reloc, unsigned mark_sec_changed(elf, reloc->sec, true); } =20 -#define for_each_sec(file, sec) \ - list_for_each_entry(sec, &file->elf->sections, list) +#define for_each_sec(elf, sec) \ + list_for_each_entry(sec, &elf->sections, list) =20 #define sec_for_each_sym(sec, sym) \ list_for_each_entry(sym, &sec->symbol_list, list) =20 -#define for_each_sym(file, sym) \ +#define for_each_sym(elf, sym) \ for (struct section *__sec, *__fake =3D (struct section *)1; \ __fake; __fake =3D NULL) \ - for_each_sec(file, __sec) \ + for_each_sec(elf, __sec) \ sec_for_each_sym(__sec, sym) =20 #define for_each_reloc(rsec, reloc) \ diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c index 922e6aac7cea..6eff3d6a125c 100644 --- a/tools/objtool/orc_gen.c +++ b/tools/objtool/orc_gen.c @@ -57,7 +57,7 @@ int orc_create(struct objtool_file *file) =20 /* Build a deduplicated list of ORC entries: */ INIT_LIST_HEAD(&orc_list); - for_each_sec(file, sec) { + for_each_sec(file->elf, sec) { struct orc_entry orc, prev_orc =3D {0}; struct instruction *insn; bool empty =3D true; --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id C7CF71CE702; Tue, 3 Sep 2024 04:00:34 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336034; cv=none; b=Q6Pjx9bORMYUbXuWOrWex/Gf9T649Objyg7zztN+9zj3huwd2i5AcibT8qC1pwDLbN36Kt1xTNNKh6SmuAm6Toxc906vgLi9u3MZ/mwtqss7wuE04XgcSjmJ1B2uzT/sT1EfvP58UVMuZoQq6HIxws99bi/Q0E+OYbY9l3bVvvo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336034; c=relaxed/simple; bh=OEqbNdqC0dxSvyjQ4fvXbWDvm270/3j2sh22+EBhvEg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=W3+pQoprQi6ipIvfgFG9R3UT+cTIn7n0uVjbFLWU4V7IlTyPNOc7gVBjMk4uihgfR8o9qWAjxxNjypYtlLnciYUvguIweG7OmN3kdNX/7OYeuZUzrkJiRNSnNDtZD2Vp0tVhDYI/dbPVx4sfTILDPnGOP0Zpyx0ehnhsPksWJTY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=vFfLNUDr; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="vFfLNUDr" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 50D45C4CECF; Tue, 3 Sep 2024 04:00:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336034; bh=OEqbNdqC0dxSvyjQ4fvXbWDvm270/3j2sh22+EBhvEg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=vFfLNUDreYzNXKGscIYivu1G93jT0bH7Bb3oVBmHck0b3odnwd4GaZFKJm2LlpbEa PJj8alvZXG0XtabG/sFLh5AUoPBcYYx5gIQ6YcRrsiako1kV9R6hUow/GIKArINgAY 7o8fqCqL4qzjwRvAtf0VXzxJkBVTRQHYG3GBC8SteCsbuwahSjZk06wK9JPP3wP5dV flzM8v9ztB2pg9RHzrm8aQ3IBaZ0HFsvkI0dDsFMncbD2+jatw+EEr17nYjoNyaG4G CJkoLyVdxKt+CJFfBm6kT9qROy3uIQzz6OtohLuhG0tNDV8YCLZGq2I9qFeK5vIZhy ScIn9vCVNZnVA== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 11/31] objtool: Add section/symbol type helpers Date: Mon, 2 Sep 2024 20:59:54 -0700 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add some helper macros to improve readability. Signed-off-by: Josh Poimboeuf --- tools/objtool/arch/x86/special.c | 2 +- tools/objtool/check.c | 66 +++++++++++++------------- tools/objtool/elf.c | 24 +++++----- tools/objtool/include/objtool/elf.h | 73 ++++++++++++++++++++++++++++- tools/objtool/special.c | 4 +- 5 files changed, 120 insertions(+), 49 deletions(-) diff --git a/tools/objtool/arch/x86/special.c b/tools/objtool/arch/x86/spec= ial.c index 4134d27c696b..b0e21b2e9f53 100644 --- a/tools/objtool/arch/x86/special.c +++ b/tools/objtool/arch/x86/special.c @@ -95,7 +95,7 @@ struct reloc *arch_find_switch_table(struct objtool_file = *file, /* look for a relocation which references .rodata */ text_reloc =3D find_reloc_by_dest_range(file->elf, insn->sec, insn->offset, insn->len); - if (!text_reloc || text_reloc->sym->type !=3D STT_SECTION || + if (!text_reloc || !is_section_symbol(text_reloc->sym) || !text_reloc->sym->sec->rodata) return NULL; =20 diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 06e7b3f5481d..95f5de0c293d 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -202,12 +202,12 @@ static bool __dead_end_function(struct objtool_file *= file, struct symbol *func, if (!func) return false; =20 - if (func->bind =3D=3D STB_GLOBAL || func->bind =3D=3D STB_WEAK) + if (!is_local_symbol(func)) for (i =3D 0; i < ARRAY_SIZE(global_noreturns); i++) if (!strcmp(func->name, global_noreturns[i])) return true; =20 - if (func->bind =3D=3D STB_WEAK) + if (is_weak_symbol(func)) return false; =20 if (!func->len) @@ -379,7 +379,7 @@ static int decode_instructions(struct objtool_file *fil= e) u8 prev_len =3D 0; u8 idx =3D 0; =20 - if (!(sec->sh.sh_flags & SHF_EXECINSTR)) + if (!is_text_section(sec)) continue; =20 if (strcmp(sec->name, ".altinstr_replacement") && @@ -402,7 +402,7 @@ static int decode_instructions(struct objtool_file *fil= e) if (!strcmp(sec->name, ".init.text") && !opts.module) sec->init =3D true; =20 - for (offset =3D 0; offset < sec->sh.sh_size; offset +=3D insn->len) { + for (offset =3D 0; offset < sec_size(sec); offset +=3D insn->len) { if (!insns || idx =3D=3D INSN_CHUNK_MAX) { insns =3D calloc(sizeof(*insn), INSN_CHUNK_SIZE); if (!insns) { @@ -422,7 +422,7 @@ static int decode_instructions(struct objtool_file *fil= e) insn->prev_len =3D prev_len; =20 ret =3D arch_decode_instruction(file, sec, offset, - sec->sh.sh_size - offset, + sec_size(sec) - offset, insn); if (ret) return ret; @@ -444,12 +444,12 @@ static int decode_instructions(struct objtool_file *f= ile) // printf("%s: last chunk used: %d\n", sec->name, (int)idx); =20 sec_for_each_sym(sec, func) { - if (func->type !=3D STT_NOTYPE && func->type !=3D STT_FUNC) + if (!is_notype_symbol(func) && !is_function_symbol(func)) continue; =20 - if (func->offset =3D=3D sec->sh.sh_size) { + if (func->offset =3D=3D sec_size(sec)) { /* Heuristic: likely an "end" symbol */ - if (func->type =3D=3D STT_NOTYPE) + if (is_notype_symbol(func)) continue; WARN("%s(): STT_FUNC at end of section", func->name); @@ -467,7 +467,7 @@ static int decode_instructions(struct objtool_file *fil= e) =20 sym_for_each_insn(file, func, insn) { insn->sym =3D func; - if (func->type =3D=3D STT_FUNC && + if (is_function_symbol(func) && insn->type =3D=3D INSN_ENDBR && list_empty(&insn->call_node)) { if (insn->offset =3D=3D func->offset) { @@ -509,7 +509,7 @@ static int add_pv_ops(struct objtool_file *file, const = char *symname) break; =20 func =3D reloc->sym; - if (func->type =3D=3D STT_SECTION) + if (is_section_symbol(func)) func =3D find_symbol_by_offset(reloc->sym->sec, reloc_addend(reloc)); =20 @@ -569,9 +569,9 @@ static struct instruction *find_last_insn(struct objtoo= l_file *file, { struct instruction *insn =3D NULL; unsigned int offset; - unsigned int end =3D (sec->sh.sh_size > 10) ? sec->sh.sh_size - 10 : 0; + unsigned int end =3D (sec_size(sec) > 10) ? sec_size(sec) - 10 : 0; =20 - for (offset =3D sec->sh.sh_size - 1; offset >=3D end && !insn; offset--) + for (offset =3D sec_size(sec) - 1; offset >=3D end && !insn; offset--) insn =3D find_insn(file, sec, offset); =20 return insn; @@ -607,7 +607,7 @@ static int add_dead_ends(struct objtool_file *file) insn =3D find_insn(file, reloc->sym->sec, offset); if (insn) insn =3D prev_insn_same_sec(file, insn); - else if (offset =3D=3D reloc->sym->sec->sh.sh_size) { + else if (offset =3D=3D sec_size(reloc->sym->sec)) { insn =3D find_last_insn(file, reloc->sym->sec); if (!insn) { WARN("can't find unreachable insn at %s+0x%" PRIx64, @@ -647,7 +647,7 @@ static int add_dead_ends(struct objtool_file *file) insn =3D find_insn(file, reloc->sym->sec, offset); if (insn) insn =3D prev_insn_same_sec(file, insn); - else if (offset =3D=3D reloc->sym->sec->sh.sh_size) { + else if (offset =3D=3D sec_size(reloc->sym->sec)) { insn =3D find_last_insn(file, reloc->sym->sec); if (!insn) { WARN("can't find reachable insn at %s+0x%" PRIx64, @@ -868,7 +868,7 @@ static int create_ibt_endbr_seal_sections(struct objtoo= l_file *file) struct symbol *sym =3D insn->sym; *site =3D 0; =20 - if (opts.module && sym && sym->type =3D=3D STT_FUNC && + if (opts.module && sym && is_function_symbol(sym) && insn->offset =3D=3D sym->offset && (!strcmp(sym->name, "init_module") || !strcmp(sym->name, "cleanup_module"))) @@ -900,7 +900,7 @@ static int create_cfi_sections(struct objtool_file *fil= e) =20 idx =3D 0; for_each_sym(file->elf, sym) { - if (sym->type !=3D STT_FUNC) + if (!is_function_symbol(sym)) continue; =20 if (strncmp(sym->name, "__cfi_", 6)) @@ -916,7 +916,7 @@ static int create_cfi_sections(struct objtool_file *fil= e) =20 idx =3D 0; for_each_sym(file->elf, sym) { - if (sym->type !=3D STT_FUNC) + if (!is_function_symbol(sym)) continue; =20 if (strncmp(sym->name, "__cfi_", 6)) @@ -1534,7 +1534,7 @@ static bool jump_is_sibling_call(struct objtool_file = *file, return false; =20 /* Disallow sibling calls into STT_NOTYPE */ - if (ts->type =3D=3D STT_NOTYPE) + if (is_notype_symbol(ts)) return false; =20 /* Must not be self to be a sibling */ @@ -1566,7 +1566,7 @@ static int add_jump_destinations(struct objtool_file = *file) if (!reloc) { dest_sec =3D insn->sec; dest_off =3D arch_jump_destination(insn); - } else if (reloc->sym->type =3D=3D STT_SECTION) { + } else if (is_section_symbol(reloc->sym)) { dest_sec =3D reloc->sym->sec; dest_off =3D arch_dest_reloc_offset(reloc_addend(reloc)); } else if (reloc->sym->retpoline_thunk) { @@ -1712,12 +1712,12 @@ static int add_call_destinations(struct objtool_fil= e *file) return -1; } =20 - if (insn_func(insn) && insn_call_dest(insn)->type !=3D STT_FUNC) { + if (insn_func(insn) && !is_function_symbol(insn_call_dest(insn))) { WARN_INSN(insn, "unsupported call to non-function"); return -1; } =20 - } else if (reloc->sym->type =3D=3D STT_SECTION) { + } else if (is_section_symbol(reloc->sym)) { dest_off =3D arch_dest_reloc_offset(reloc_addend(reloc)); dest =3D find_call_destination(reloc->sym->sec, dest_off); if (!dest) { @@ -2199,7 +2199,7 @@ static int add_jump_table_alts(struct objtool_file *f= ile) return 0; =20 for_each_sym(file->elf, func) { - if (func->type !=3D STT_FUNC) + if (!is_function_symbol(func)) continue; =20 mark_func_jump_tables(file, func); @@ -2239,14 +2239,14 @@ static int read_unwind_hints(struct objtool_file *f= ile) return -1; } =20 - if (sec->sh.sh_size % sizeof(struct unwind_hint)) { + if (sec_size(sec) % sizeof(struct unwind_hint)) { WARN("struct unwind_hint size mismatch"); return -1; } =20 file->hints =3D true; =20 - for (i =3D 0; i < sec->sh.sh_size / sizeof(struct unwind_hint); i++) { + for (i =3D 0; i < sec_size(sec) / sizeof(struct unwind_hint); i++) { hint =3D (struct unwind_hint *)sec->data->d_buf + i; =20 reloc =3D find_reloc_by_dest(file->elf, sec, i * sizeof(*hint)); @@ -2291,7 +2291,7 @@ static int read_unwind_hints(struct objtool_file *fil= e) if (hint->type =3D=3D UNWIND_HINT_TYPE_REGS_PARTIAL) { struct symbol *sym =3D find_symbol_by_offset(insn->sec, insn->offset); =20 - if (sym && sym->bind =3D=3D STB_GLOBAL) { + if (sym && is_global_symbol(sym)) { if (opts.ibt && insn->type !=3D INSN_ENDBR && !insn->noendbr) { WARN_INSN(insn, "UNWIND_HINT_IRET_REGS without ENDBR"); } @@ -2469,7 +2469,7 @@ static int read_intra_function_calls(struct objtool_f= ile *file) for_each_reloc(rsec, reloc) { unsigned long dest_off; =20 - if (reloc->sym->type !=3D STT_SECTION) { + if (!is_section_symbol(reloc->sym)) { WARN("unexpected relocation symbol type in %s", rsec->name); return -1; @@ -2535,10 +2535,10 @@ static int classify_symbols(struct objtool_file *fi= le) struct symbol *func; =20 for_each_sym(file->elf, func) { - if (func->type =3D=3D STT_NOTYPE && strstarts(func->name, ".L")) + if (is_notype_symbol(func) && strstarts(func->name, ".L")) func->local_label =3D true; =20 - if (func->bind !=3D STB_GLOBAL) + if (!is_global_symbol(func)) continue; =20 if (!strncmp(func->name, STATIC_CALL_TRAMP_PREFIX_STR, @@ -4199,11 +4199,11 @@ static int add_prefix_symbols(struct objtool_file *= file) struct symbol *func; =20 for_each_sec(file->elf, sec) { - if (!(sec->sh.sh_flags & SHF_EXECINSTR)) + if (!is_text_section(sec)) continue; =20 sec_for_each_sym(sec, func) { - if (func->type !=3D STT_FUNC) + if (!is_function_symbol(func)) continue; =20 add_prefix_symbol(file, func); @@ -4246,7 +4246,7 @@ static int validate_section(struct objtool_file *file= , struct section *sec) int warnings =3D 0; =20 sec_for_each_sym(sec, func) { - if (func->type !=3D STT_FUNC) + if (!is_function_symbol(func)) continue; =20 init_insn_state(file, &state, sec); @@ -4290,7 +4290,7 @@ static int validate_functions(struct objtool_file *fi= le) int warnings =3D 0; =20 for_each_sec(file->elf, sec) { - if (!(sec->sh.sh_flags & SHF_EXECINSTR)) + if (!is_text_section(sec)) continue; =20 warnings +=3D validate_section(file, sec); @@ -4461,7 +4461,7 @@ static int validate_ibt(struct objtool_file *file) for_each_sec(file->elf, sec) { =20 /* Already done by validate_ibt_insn() */ - if (sec->sh.sh_flags & SHF_EXECINSTR) + if (is_text_section(sec)) continue; =20 if (!sec->rsec) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index b42ee4ef7015..5301fff87bea 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -170,7 +170,7 @@ struct symbol *find_symbol_by_offset(struct section *se= c, unsigned long offset) struct symbol *iter; =20 __sym_for_each(iter, tree, offset, offset) { - if (iter->offset =3D=3D offset && iter->type !=3D STT_SECTION) + if (iter->offset =3D=3D offset && !is_section_symbol(iter)) return iter; } =20 @@ -183,7 +183,7 @@ struct symbol *find_func_by_offset(struct section *sec,= unsigned long offset) struct symbol *iter; =20 __sym_for_each(iter, tree, offset, offset) { - if (iter->offset =3D=3D offset && iter->type =3D=3D STT_FUNC) + if (iter->offset =3D=3D offset && is_function_symbol(iter)) return iter; } =20 @@ -244,7 +244,7 @@ struct symbol *find_func_containing(struct section *sec= , unsigned long offset) struct symbol *iter; =20 __sym_for_each(iter, tree, offset, offset) { - if (iter->type =3D=3D STT_FUNC) + if (is_function_symbol(iter)) return iter; } =20 @@ -353,14 +353,14 @@ static int read_sections(struct elf *elf) return -1; } =20 - if (sec->sh.sh_size !=3D 0 && !is_dwarf_section(sec)) { + if (sec_size(sec) !=3D 0 && !is_dwarf_section(sec)) { sec->data =3D elf_getdata(s, NULL); if (!sec->data) { WARN_ELF("elf_getdata"); return -1; } if (sec->data->d_off !=3D 0 || - sec->data->d_size !=3D sec->sh.sh_size) { + sec->data->d_size !=3D sec_size(sec)) { WARN("unexpected data attributes for %s", sec->name); return -1; @@ -371,7 +371,7 @@ static int read_sections(struct elf *elf) elf_hash_add(section, &sec->hash, sec->idx); elf_hash_add(section_name, &sec->name_hash, str_hash(sec->name)); =20 - if (is_reloc_sec(sec)) + if (is_reloc_section(sec)) elf->num_relocs +=3D sec_num_entries(sec); } =20 @@ -401,7 +401,7 @@ static void elf_add_symbol(struct elf *elf, struct symb= ol *sym) sym->type =3D GELF_ST_TYPE(sym->sym.st_info); sym->bind =3D GELF_ST_BIND(sym->sym.st_info); =20 - if (sym->type =3D=3D STT_FILE) + if (is_file_symbol(sym)) elf->num_files++; =20 sym->offset =3D sym->sym.st_value; @@ -515,7 +515,7 @@ static int read_symbols(struct elf *elf) sec_for_each_sym(sec, sym) { char *pname; size_t pnamelen; - if (sym->type !=3D STT_FUNC) + if (!is_function_symbol(sym)) continue; =20 if (sym->pfunc =3D=3D NULL) @@ -890,7 +890,7 @@ struct reloc *elf_init_reloc_text_sym(struct elf *elf, = struct section *sec, struct symbol *sym =3D insn_sec->sym; int addend =3D insn_off; =20 - if (!(insn_sec->sh.sh_flags & SHF_EXECINSTR)) { + if (!is_text_section(insn_sec)) { WARN("bad call to %s() for data symbol %s", __func__, sym->name); return NULL; @@ -920,7 +920,7 @@ struct reloc *elf_init_reloc_data_sym(struct elf *elf, = struct section *sec, struct symbol *sym, s64 addend) { - if (sym->sec && (sec->sh.sh_flags & SHF_EXECINSTR)) { + if (is_text_section(sec)) { WARN("bad call to %s() for text symbol %s", __func__, sym->name); return NULL; @@ -943,7 +943,7 @@ static int read_relocs(struct elf *elf) return -1; =20 list_for_each_entry(rsec, &elf->sections, list) { - if (!is_reloc_sec(rsec)) + if (!is_reloc_section(rsec)) continue; =20 rsec->base =3D find_section_by_index(elf, rsec->sh.sh_info); @@ -1249,7 +1249,7 @@ int elf_write_insn(struct elf *elf, struct section *s= ec, */ static int elf_truncate_section(struct elf *elf, struct section *sec) { - u64 size =3D sec->sh.sh_size; + u64 size =3D sec_size(sec); bool truncated =3D false; Elf_Data *data =3D NULL; Elf_Scn *s; diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/ob= jtool/elf.h index 7524510b5565..0c2af699b1bf 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -8,6 +8,7 @@ =20 #include #include +#include #include #include #include @@ -174,11 +175,76 @@ static inline unsigned int elf_text_rela_type(struct = elf *elf) return elf_addr_size(elf) =3D=3D 4 ? R_TEXT32 : R_TEXT64; } =20 -static inline bool is_reloc_sec(struct section *sec) +static inline bool sym_has_section(struct symbol *sym) +{ + return sym->sec->idx; +} + +static inline bool is_null_symbol(struct symbol *sym) +{ + return !sym->idx; +} + +static inline bool is_section_symbol(struct symbol *sym) +{ + return sym->type =3D=3D STT_SECTION; +} + +static inline bool is_object_symbol(struct symbol *sym) +{ + return sym->type =3D=3D STT_OBJECT; +} + +static inline bool is_function_symbol(struct symbol *sym) +{ + return sym->type =3D=3D STT_FUNC; +} + +static inline bool is_file_symbol(struct symbol *sym) +{ + return sym->type =3D=3D STT_FILE; +} + +static inline bool is_notype_symbol(struct symbol *sym) +{ + return sym->type =3D=3D STT_NOTYPE; +} + +static inline bool is_prefix_symbol(struct symbol *sym) +{ + return is_function_symbol(sym) && strstarts(sym->name, "__pfx_"); +} + +static inline bool is_global_symbol(struct symbol *sym) +{ + return sym->bind =3D=3D STB_GLOBAL; +} + +static inline bool is_weak_symbol(struct symbol *sym) +{ + return sym->bind =3D=3D STB_WEAK; +} + +static inline bool is_local_symbol(struct symbol *sym) +{ + return sym->bind =3D=3D STB_LOCAL; +} + +static inline bool is_reloc_section(struct section *sec) { return sec->sh.sh_type =3D=3D SHT_RELA || sec->sh.sh_type =3D=3D SHT_REL; } =20 +static inline bool is_string_section(struct section *sec) +{ + return sec->sh.sh_flags & SHF_STRINGS; +} + +static inline bool is_text_section(struct section *sec) +{ + return sec->sh.sh_flags & SHF_EXECINSTR; +} + static inline bool sec_changed(struct section *sec) { return sec->_changed; @@ -219,6 +285,11 @@ static inline bool is_32bit_reloc(struct reloc *reloc) return reloc->sec->sh.sh_entsize < 16; } =20 +static inline unsigned long sec_size(struct section *sec) +{ + return sec->sh.sh_size; +} + #define __get_reloc_field(reloc, field) \ ({ \ is_32bit_reloc(reloc) ? \ diff --git a/tools/objtool/special.c b/tools/objtool/special.c index 91b1950f5bd8..312d01684e21 100644 --- a/tools/objtool/special.c +++ b/tools/objtool/special.c @@ -152,13 +152,13 @@ int special_get_alts(struct elf *elf, struct list_hea= d *alts) if (!sec) continue; =20 - if (sec->sh.sh_size % entry->size !=3D 0) { + if (sec_size(sec) % entry->size !=3D 0) { WARN("%s size not a multiple of %d", sec->name, entry->size); return -1; } =20 - nr_entries =3D sec->sh.sh_size / entry->size; + nr_entries =3D sec_size(sec) / entry->size; =20 for (idx =3D 0; idx < nr_entries; idx++) { alt =3D malloc(sizeof(*alt)); --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A200D1D1759; Tue, 3 Sep 2024 04:00:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336036; cv=none; b=eXAL6BHsQ5KgLDs0/Aw5OM6OxtfOIytYqiW+JqrqN2gqkfvCxV8K9iWG9QfiU62V5qaqXGytzGO1j60Mf/fLUfcckFN5dMYSzs3ee2VgG+2FiIlmTuelt7/vhz3xdCufqfUEBA8V13/9mmvy457bhVlZpv8QNNicHTeDpRDWZGg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336036; c=relaxed/simple; bh=S1TH3NgEYk8GKWSjwZk9iXKEQgbZtCkEzrr/z/94KPc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=HDQpLc8LWsoVYZOZxVvte+a3/7hxP2eac8sV/XWsSByCUCTFbBbJpFCwh/1jufzidjRDSmmAd9YyZ9sy7cjokPBx38pwWqP0qrX8KXJyUggMvzCgn8xZ/uf/3SMHWp2/6ir8hplzlbF9X+XJN5ClvP4UnCrh077uDsqdJ4xTmis= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=uum9/FgW; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="uum9/FgW" Received: by smtp.kernel.org (Postfix) with ESMTPSA id CEF1AC4CEC8; Tue, 3 Sep 2024 04:00:34 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336035; bh=S1TH3NgEYk8GKWSjwZk9iXKEQgbZtCkEzrr/z/94KPc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=uum9/FgWdoJnVN7TiIBuJmzsm4uI2exSJUrF+Sn+6vwuamDLqxWMGNnIe7JgfZHX6 kiszVrIzcR9GeEAPotXDZU4HlXfwqqhwPVzFZ3S69YySTnTNWQMsnBC4Dxx453esN3 tPRAf+gY0k4cC3arZqf+1JH68GQyUl5ed6DunTdlcvFFGp+yA3gaLrxg+d1TOgLGT7 CUBc320fzM7nwq/lyvYHZbcJ6oM72VJ3laxRkCt9Ddhv+HbLqWXbL9NN50Pgf+KDE5 OcLgjWKgUCVsSYAlNRkjqDYcIsAvo7T8dszGk8lfpH4mtfFh+4gq1PVriakeFmqk5J U2PHDm8GnUUjg== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 12/31] objtool: 'objname' refactoring Date: Mon, 2 Sep 2024 20:59:55 -0700 Message-ID: <3058a111d265e2cbcc6732e7d1a48ef4b506c8df.1725334260.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Rename the global 'objname' variable to 'Objname' to avoid local variable conflicts, and initialize it in elf_open_read() which is a more natural place for that. Signed-off-by: Josh Poimboeuf --- tools/objtool/builtin-check.c | 2 +- tools/objtool/check.c | 4 ++-- tools/objtool/elf.c | 3 +++ tools/objtool/include/objtool/objtool.h | 2 +- tools/objtool/include/objtool/warn.h | 8 +++++--- tools/objtool/objtool.c | 17 ++++++++--------- tools/objtool/orc_dump.c | 4 ++-- tools/objtool/weak.c | 2 +- 8 files changed, 23 insertions(+), 19 deletions(-) diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index 5e21cfb7661d..2f16f5ee83ae 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -204,8 +204,8 @@ static bool link_opts_valid(struct objtool_file *file) =20 int objtool_run(int argc, const char **argv) { - const char *objname; struct objtool_file *file; + const char *objname; int ret; =20 argc =3D cmd_parse_options(argc, argv, check_usage); diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 95f5de0c293d..92171ce458ec 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -4621,7 +4621,7 @@ static int disas_funcs(const char *funcs) "}' 1>&2"; =20 /* fake snprintf() to calculate the size */ - size =3D snprintf(NULL, 0, objdump_str, cross_compile, objname, funcs) + = 1; + size =3D snprintf(NULL, 0, objdump_str, cross_compile, Objname, funcs) + = 1; if (size <=3D 0) { WARN("objdump string size calculation failed"); return -1; @@ -4630,7 +4630,7 @@ static int disas_funcs(const char *funcs) cmd =3D malloc(size); =20 /* real snprintf() */ - snprintf(cmd, size, objdump_str, cross_compile, objname, funcs); + snprintf(cmd, size, objdump_str, cross_compile, Objname, funcs); ret =3D system(cmd); if (ret) { WARN("disassembly failed: %d", ret); diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 5301fff87bea..12dbcf425321 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -996,6 +996,9 @@ struct elf *elf_open_read(const char *name, int flags) struct elf *elf; Elf_Cmd cmd; =20 + if (!Objname) + Objname =3D strdup(name); + elf_version(EV_CURRENT); =20 elf =3D malloc(sizeof(*elf)); diff --git a/tools/objtool/include/objtool/objtool.h b/tools/objtool/includ= e/objtool/objtool.h index 94a33ee7b363..ae30497e014b 100644 --- a/tools/objtool/include/objtool/objtool.h +++ b/tools/objtool/include/objtool/objtool.h @@ -39,7 +39,7 @@ struct objtool_file { struct pv_state *pv_ops; }; =20 -struct objtool_file *objtool_open_read(const char *_objname); +struct objtool_file *objtool_open_read(const char *objname); =20 void objtool_pv_add(struct objtool_file *file, int idx, struct symbol *fun= c); =20 diff --git a/tools/objtool/include/objtool/warn.h b/tools/objtool/include/o= bjtool/warn.h index ac04d3fe4dd9..69995f84f91b 100644 --- a/tools/objtool/include/objtool/warn.h +++ b/tools/objtool/include/objtool/warn.h @@ -14,7 +14,7 @@ #include #include =20 -extern const char *objname; +extern char *Objname; =20 static inline char *offstr(struct section *sec, unsigned long offset) { @@ -41,10 +41,12 @@ static inline char *offstr(struct section *sec, unsigne= d long offset) return str; } =20 -#define WARN(format, ...) \ +#define WARN(...) WARN_FILENAME(Objname, ##__VA_ARGS__) + +#define WARN_FILENAME(filename, format, ...) \ fprintf(stderr, \ "%s: warning: objtool: " format "\n", \ - objname, ##__VA_ARGS__) + filename, ##__VA_ARGS__) =20 #define WARN_FUNC(format, sec, offset, ...) \ ({ \ diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c index f40febdd6e36..6d2102450b35 100644 --- a/tools/objtool/objtool.c +++ b/tools/objtool/objtool.c @@ -18,12 +18,12 @@ =20 bool help; =20 -const char *objname; +char *Objname; static struct objtool_file file; =20 -static bool objtool_create_backup(const char *_objname) +static bool objtool_create_backup(const char *objname) { - int len =3D strlen(_objname); + int len =3D strlen(objname); char *buf, *base, *name =3D malloc(len+6); int s, d, l, t; =20 @@ -32,7 +32,7 @@ static bool objtool_create_backup(const char *_objname) return false; } =20 - strcpy(name, _objname); + strcpy(name, objname); strcpy(name + len, ".orig"); =20 d =3D open(name, O_CREAT|O_WRONLY|O_TRUNC, 0644); @@ -41,7 +41,7 @@ static bool objtool_create_backup(const char *_objname) return false; } =20 - s =3D open(_objname, O_RDONLY); + s =3D open(objname, O_RDONLY); if (s < 0) { perror("failed to open orig file"); return false; @@ -79,16 +79,15 @@ static bool objtool_create_backup(const char *_objname) return true; } =20 -struct objtool_file *objtool_open_read(const char *_objname) +struct objtool_file *objtool_open_read(const char *objname) { - if (objname) { - if (strcmp(objname, _objname)) { + if (Objname) { + if (strcmp(Objname, objname)) { WARN("won't handle more than one file at a time"); return NULL; } return &file; } - objname =3D _objname; =20 file.elf =3D elf_open_read(objname, O_RDWR); if (!file.elf) diff --git a/tools/objtool/orc_dump.c b/tools/objtool/orc_dump.c index a62247efb64f..9c0b9d8a34fe 100644 --- a/tools/objtool/orc_dump.c +++ b/tools/objtool/orc_dump.c @@ -10,7 +10,7 @@ #include #include =20 -int orc_dump(const char *_objname) +int orc_dump(const char *objname) { int fd, nr_entries, i, *orc_ip =3D NULL, orc_size =3D 0; struct orc_entry *orc =3D NULL; @@ -27,7 +27,7 @@ int orc_dump(const char *_objname) struct elf dummy_elf =3D {}; =20 =20 - objname =3D _objname; + Objname =3D strdup(objname); =20 elf_version(EV_CURRENT); =20 diff --git a/tools/objtool/weak.c b/tools/objtool/weak.c index d83f607733b0..b568da3c33e6 100644 --- a/tools/objtool/weak.c +++ b/tools/objtool/weak.c @@ -15,7 +15,7 @@ return ENOSYS; \ }) =20 -int __weak orc_dump(const char *_objname) +int __weak orc_dump(const char *objname) { UNSUPPORTED("ORC"); } --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id DB4081D0DEB; Tue, 3 Sep 2024 04:00:35 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336036; cv=none; b=kDCKgBjnqT1E4QNNcMUk9nauDjWtfXGpSFmOzVjNo84H0YEZYh2R3yu02Zbe1DHvE5ODiZBDSUsLOLnuFDq6+s7l7w1A/jn+BDUw5QYQNMjHunYgL2VF00IUUsyAFq33+h5nAGPgb434P4VEHkA0SY7PVJR6epoy/KDLFozWdro= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336036; c=relaxed/simple; bh=BtVquJSftqUBmhf9tSLjp9ytg/driSytPQ0zkeW/6ls=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Xug4MsNTbXaVLEc2XHsDtkOWIdUejrHiXQ7izogPFXAO/mI76uWD+ymhwecNWOlJw75om+6otcNE+j3xY+9Xir80MjeqEcHEATU/Hrz7FFDpI/QnCmh53t+VdBCarNcE6JlGZtI/XyTVrEC+sj4ijcQqBeE5UMzqxqS9iFtYaaw= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=UrpCr16X; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="UrpCr16X" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 58240C4CECA; Tue, 3 Sep 2024 04:00:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336035; bh=BtVquJSftqUBmhf9tSLjp9ytg/driSytPQ0zkeW/6ls=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=UrpCr16Xj6P6aLlmOxmk6PseYF3o+rZY2Xel1RmNF1tdcZZ7WlGTaGUDlfay1OKKk tMF5zULr96XyhuZI2cazrsUjsJki4P/u2v/MugqDAEKVT9iReKyssYJ//wH+YDYD2+ MdFPfRM236AKilR79sg0tUoOi16a9wum7Pam7GUWO0EpUWdAkxdDLK20/7x+LSV71k R8U8pp6ZUbAfP2COTzgY2MZktsfss4eUoIp3HMesBNOr6A4P1wSWdXZ9kmBCY9HEhJ 0Zb5RRNycz4h2Ay/QR4IcyttCm4LaAiGsEIrSRkOeVDDWG0WXfT9mg26qvhISy0FLg Zc+zplU0gH0rw== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 13/31] objtool: Support references to all symbol types in special sections Date: Mon, 2 Sep 2024 20:59:56 -0700 Message-ID: <08657a8071475e802dd63e3392338a8f950b61bb.1725334260.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Make the code simpler and more flexible. Signed-off-by: Josh Poimboeuf --- tools/objtool/check.c | 74 +++++++++---------------------------------- 1 file changed, 15 insertions(+), 59 deletions(-) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 92171ce458ec..9212b5edffc8 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -595,15 +595,7 @@ static int add_dead_ends(struct objtool_file *file) goto reachable; =20 for_each_reloc(rsec, reloc) { - if (reloc->sym->type =3D=3D STT_SECTION) { - offset =3D reloc_addend(reloc); - } else if (reloc->sym->local_label) { - offset =3D reloc->sym->offset; - } else { - WARN("unexpected relocation symbol type in %s", rsec->name); - return -1; - } - + offset =3D reloc->sym->offset + reloc_addend(reloc); insn =3D find_insn(file, reloc->sym->sec, offset); if (insn) insn =3D prev_insn_same_sec(file, insn); @@ -635,15 +627,7 @@ static int add_dead_ends(struct objtool_file *file) return 0; =20 for_each_reloc(rsec, reloc) { - if (reloc->sym->type =3D=3D STT_SECTION) { - offset =3D reloc_addend(reloc); - } else if (reloc->sym->local_label) { - offset =3D reloc->sym->offset; - } else { - WARN("unexpected relocation symbol type in %s", rsec->name); - return -1; - } - + offset =3D reloc->sym->offset + reloc_addend(reloc); insn =3D find_insn(file, reloc->sym->sec, offset); if (insn) insn =3D prev_insn_same_sec(file, insn); @@ -1274,12 +1258,9 @@ static int add_ignore_alternatives(struct objtool_fi= le *file) return 0; =20 for_each_reloc(rsec, reloc) { - if (reloc->sym->type !=3D STT_SECTION) { - WARN("unexpected relocation symbol type in %s", rsec->name); - return -1; - } + unsigned long offset =3D reloc->sym->offset + reloc_addend(reloc); =20 - insn =3D find_insn(file, reloc->sym->sec, reloc_addend(reloc)); + insn =3D find_insn(file, reloc->sym->sec, offset); if (!insn) { WARN("bad .discard.ignore_alts entry"); return -1; @@ -2255,15 +2236,7 @@ static int read_unwind_hints(struct objtool_file *fi= le) return -1; } =20 - if (reloc->sym->type =3D=3D STT_SECTION) { - offset =3D reloc_addend(reloc); - } else if (reloc->sym->local_label) { - offset =3D reloc->sym->offset; - } else { - WARN("unexpected relocation symbol type in %s", sec->rsec->name); - return -1; - } - + offset =3D reloc->sym->offset + reloc_addend(reloc); insn =3D find_insn(file, reloc->sym->sec, offset); if (!insn) { WARN("can't find insn for unwind_hints[%d]", i); @@ -2356,12 +2329,9 @@ static int read_retpoline_hints(struct objtool_file = *file) return 0; =20 for_each_reloc(rsec, reloc) { - if (reloc->sym->type !=3D STT_SECTION) { - WARN("unexpected relocation symbol type in %s", rsec->name); - return -1; - } + unsigned long offset =3D reloc->sym->offset + reloc_addend(reloc); =20 - insn =3D find_insn(file, reloc->sym->sec, reloc_addend(reloc)); + insn =3D find_insn(file, reloc->sym->sec, offset); if (!insn) { WARN("bad .discard.retpoline_safe entry"); return -1; @@ -2392,12 +2362,9 @@ static int read_instr_hints(struct objtool_file *fil= e) return 0; =20 for_each_reloc(rsec, reloc) { - if (reloc->sym->type !=3D STT_SECTION) { - WARN("unexpected relocation symbol type in %s", rsec->name); - return -1; - } + unsigned long offset =3D reloc->sym->offset + reloc_addend(reloc); =20 - insn =3D find_insn(file, reloc->sym->sec, reloc_addend(reloc)); + insn =3D find_insn(file, reloc->sym->sec, offset); if (!insn) { WARN("bad .discard.instr_end entry"); return -1; @@ -2411,12 +2378,9 @@ static int read_instr_hints(struct objtool_file *fil= e) return 0; =20 for_each_reloc(rsec, reloc) { - if (reloc->sym->type !=3D STT_SECTION) { - WARN("unexpected relocation symbol type in %s", rsec->name); - return -1; - } + unsigned long offset =3D reloc->sym->offset + reloc_addend(reloc); =20 - insn =3D find_insn(file, reloc->sym->sec, reloc_addend(reloc)); + insn =3D find_insn(file, reloc->sym->sec, offset); if (!insn) { WARN("bad .discard.instr_begin entry"); return -1; @@ -2439,12 +2403,9 @@ static int read_validate_unret_hints(struct objtool_= file *file) return 0; =20 for_each_reloc(rsec, reloc) { - if (reloc->sym->type !=3D STT_SECTION) { - WARN("unexpected relocation symbol type in %s", rsec->name); - return -1; - } + unsigned long offset =3D reloc->sym->offset + reloc_addend(reloc); =20 - insn =3D find_insn(file, reloc->sym->sec, reloc_addend(reloc)); + insn =3D find_insn(file, reloc->sym->sec, offset); if (!insn) { WARN("bad .discard.instr_end entry"); return -1; @@ -2468,14 +2429,9 @@ static int read_intra_function_calls(struct objtool_= file *file) =20 for_each_reloc(rsec, reloc) { unsigned long dest_off; + unsigned long offset =3D reloc->sym->offset + reloc_addend(reloc); =20 - if (!is_section_symbol(reloc->sym)) { - WARN("unexpected relocation symbol type in %s", - rsec->name); - return -1; - } - - insn =3D find_insn(file, reloc->sym->sec, reloc_addend(reloc)); + insn =3D find_insn(file, reloc->sym->sec, offset); if (!insn) { WARN("bad .discard.intra_function_call entry"); return -1; --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 889661D1746; Tue, 3 Sep 2024 04:00:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336036; cv=none; b=cQt9+3skACJySizmB84P3OZQ1ag5IH+NQ1WV4tv6aB1fTtIgNgUmyQH96QBhrPx68CITj3wqC6mVXN9Y/8ZqpADBSMpp7LhQnVDMO9o6jUxx5jqWJFmHILOmnE762mP2UUq5CLwVEolEcmQI709xBy0yO8QOY0Lp3vVR9z+6fxU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336036; c=relaxed/simple; bh=vtgBTd6vd/L2FWYI0DggGWm8tym7W/zSfl9sqau4xmw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=jP0v3qxLNuk9o4CZrzXvTYdB/6kBanoXKUmOKzQmPwlz7vgUmZo5ydgLaIHERinrXfIhaUQUWNOiucLakpl1k3IZg6JZPu/FxrWGJp+szXh4TVNXZiJOo08RU1cSnbGDIpl2oVKyb+PF4cM0r6JGtLjIH4COELS8CSCZ1ONDnkE= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=N+VCAIIA; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="N+VCAIIA" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D9698C4CEDD; Tue, 3 Sep 2024 04:00:35 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336036; bh=vtgBTd6vd/L2FWYI0DggGWm8tym7W/zSfl9sqau4xmw=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=N+VCAIIAoMVWD+yTyCkDyZ3+nb7cVSghlmDVqbcYNurS5qGuguq+jwhtOHvCftrRY FyEGrGN47ecW1XXQbyDJZvJtX1sAbK9u0xmS6JncXbX8LYF1jVRkBFlEEfWsvTS3VE PADL1VkwjmpgXsAN7+G1onViFB8C29idwlRD869qfSEjA/iZQ1bnlqIjj+7r/FO3No M3dJQat/b21noJYdUnoaUBaGxzNOBy95fRQHN7J4tXZg8jBb9xFiNR5V3n0ztHToHK 03LVcBt4MMr9goITh3dZseyg4RMfIPSkM0UUCN5DY92NRKZQyty0jBy2tMVWyoHRiX vAr9qHJesMAfA== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 14/31] objtool: Refactor add_jump_destinations() Date: Mon, 2 Sep 2024 20:59:57 -0700 Message-ID: <408f39264cbe936b397b59c0a28dc34b92c15703.1725334260.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The logic is a bit weird - simplify it. Signed-off-by: Josh Poimboeuf --- tools/objtool/check.c | 239 ++++++++++++++++++++---------------------- 1 file changed, 114 insertions(+), 125 deletions(-) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 9212b5edffc8..6490bc939892 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1479,9 +1479,14 @@ static void add_return_call(struct objtool_file *fil= e, struct instruction *insn, } =20 static bool is_first_func_insn(struct objtool_file *file, - struct instruction *insn, struct symbol *sym) + struct instruction *insn) { - if (insn->offset =3D=3D sym->offset) + struct symbol *func =3D insn_func(insn); + + if (!func) + return false; + + if (insn->offset =3D=3D func->offset) return true; =20 /* Allow direct CALL/JMP past ENDBR */ @@ -1489,50 +1494,30 @@ static bool is_first_func_insn(struct objtool_file = *file, struct instruction *prev =3D prev_insn_same_sym(file, insn); =20 if (prev && prev->type =3D=3D INSN_ENDBR && - insn->offset =3D=3D sym->offset + prev->len) + insn->offset =3D=3D func->offset + prev->len) return true; } =20 return false; } =20 -/* - * A sibling call is a tail-call to another symbol -- to differentiate fro= m a - * recursive tail-call which is to the same symbol. - */ -static bool jump_is_sibling_call(struct objtool_file *file, - struct instruction *from, struct instruction *to) -{ - struct symbol *fs =3D from->sym; - struct symbol *ts =3D to->sym; - - /* Not a sibling call if from/to a symbol hole */ - if (!fs || !ts) - return false; - - /* Not a sibling call if not targeting the start of a symbol. */ - if (!is_first_func_insn(file, to, ts)) - return false; - - /* Disallow sibling calls into STT_NOTYPE */ - if (is_notype_symbol(ts)) - return false; - - /* Must not be self to be a sibling */ - return fs->pfunc !=3D ts->pfunc; -} - /* * Find the destination instructions for all jumps. */ static int add_jump_destinations(struct objtool_file *file) { - struct instruction *insn, *jump_dest; + struct instruction *insn; struct reloc *reloc; - struct section *dest_sec; - unsigned long dest_off; =20 for_each_insn(file, insn) { + struct instruction *dest_insn; + struct section *dest_sec =3D NULL; + struct symbol *dest_sym =3D NULL; + unsigned long dest_off; + + if (!is_static_jump(insn)) + continue; + if (insn->jump_dest) { /* * handle_group_alt() may have previously set @@ -1540,114 +1525,118 @@ static int add_jump_destinations(struct objtool_f= ile *file) */ continue; } - if (!is_static_jump(insn)) - continue; =20 reloc =3D insn_reloc(file, insn); if (!reloc) { dest_sec =3D insn->sec; dest_off =3D arch_jump_destination(insn); - } else if (is_section_symbol(reloc->sym)) { - dest_sec =3D reloc->sym->sec; - dest_off =3D arch_dest_reloc_offset(reloc_addend(reloc)); - } else if (reloc->sym->retpoline_thunk) { - add_retpoline_call(file, insn); - continue; - } else if (reloc->sym->return_thunk) { - add_return_call(file, insn, true); - continue; - } else if (insn_func(insn)) { - /* - * External sibling call or internal sibling call with - * STT_FUNC reloc. - */ - add_call_dest(file, insn, reloc->sym, true); - continue; - } else if (reloc->sym->sec->idx) { + } else if (sym_has_section(reloc->sym)) { dest_sec =3D reloc->sym->sec; dest_off =3D reloc->sym->sym.st_value + arch_dest_reloc_offset(reloc_addend(reloc)); } else { - /* non-func asm code jumping to another file */ + /* External symbol (UNDEF) */ + dest_sec =3D NULL; + dest_sym =3D reloc->sym; + } + + if (!dest_sym) { + dest_insn =3D find_insn(file, dest_sec, dest_off); + + if (!dest_insn) { + struct symbol *sym =3D find_symbol_by_offset(dest_sec, dest_off); + + /* + * This is a special case for retbleed_untrain_ret(). + * It jumps to __x86_return_thunk(), but objtool + * can't find the thunk's starting RET + * instruction, because the RET is also in the + * middle of another instruction. Objtool only + * knows about the outer instruction. + */ + if (sym && sym->embedded_insn) { + add_return_call(file, insn, false); + continue; + } + + WARN_INSN(insn, "can't find jump dest instruction at %s+0x%lx", + dest_sec->name, dest_off); + return -1; + } + + dest_sym =3D dest_insn->sym; + if (!dest_sym) + goto set_jump_dest; + } + + if (dest_sym->retpoline_thunk) { + add_retpoline_call(file, insn); continue; } =20 - jump_dest =3D find_insn(file, dest_sec, dest_off); - if (!jump_dest) { - struct symbol *sym =3D find_symbol_by_offset(dest_sec, dest_off); - - /* - * This is a special case for retbleed_untrain_ret(). - * It jumps to __x86_return_thunk(), but objtool - * can't find the thunk's starting RET - * instruction, because the RET is also in the - * middle of another instruction. Objtool only - * knows about the outer instruction. - */ - if (sym && sym->embedded_insn) { - add_return_call(file, insn, false); - continue; - } - - WARN_INSN(insn, "can't find jump dest instruction at %s+0x%lx", - dest_sec->name, dest_off); - return -1; - } - - /* - * An intra-TU jump in retpoline.o might not have a relocation - * for its jump dest, in which case the above - * add_{retpoline,return}_call() didn't happen. - */ - if (jump_dest->sym && jump_dest->offset =3D=3D jump_dest->sym->offset) { - if (jump_dest->sym->retpoline_thunk) { - add_retpoline_call(file, insn); - continue; - } - if (jump_dest->sym->return_thunk) { - add_return_call(file, insn, true); - continue; - } - } - - /* - * Cross-function jump. - */ - if (insn_func(insn) && insn_func(jump_dest) && - insn_func(insn) !=3D insn_func(jump_dest)) { - - /* - * For GCC 8+, create parent/child links for any cold - * subfunctions. This is _mostly_ redundant with a - * similar initialization in read_symbols(). - * - * If a function has aliases, we want the *first* such - * function in the symbol table to be the subfunction's - * parent. In that case we overwrite the - * initialization done in read_symbols(). - * - * However this code can't completely replace the - * read_symbols() code because this doesn't detect the - * case where the parent function's only reference to a - * subfunction is through a jump table. - */ - 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); - } - } - - if (jump_is_sibling_call(file, insn, jump_dest)) { - /* - * Internal sibling call without reloc or with - * STT_SECTION reloc. - */ - add_call_dest(file, insn, insn_func(jump_dest), true); + if (dest_sym->return_thunk) { + add_return_call(file, insn, true); continue; } =20 - insn->jump_dest =3D jump_dest; + if (!dest_sec) { + /* External symbol */ + if (insn_func(insn)) { + /* External sibling call */ + add_call_dest(file, insn, dest_sym, true); + continue; + } + + /* Non-func asm code jumping to external symbol */ + continue; + } + + if (!insn_func(insn) && insn_func(dest_insn)) { + /* + * Switching from non-func asm to func - force + * validate_branch() to stop. + */ + continue; + } + + if (!insn_func(insn) || !insn_func(dest_insn) || + insn_func(insn) =3D=3D insn_func(dest_insn)) + goto set_jump_dest; + + /* + * Internal cross-function jump. + */ + + /* + * For GCC 8+, create parent/child links for any cold + * subfunctions. This is _mostly_ redundant with a + * similar initialization in read_symbols(). + * + * If a function has aliases, we want the *first* such + * function in the symbol table to be the subfunction's + * parent. In that case we overwrite the + * initialization done in read_symbols(). + * + * However this code can't completely replace the + * read_symbols() code because this doesn't detect the + * case where the parent function's only reference to a + * subfunction is through a jump table. + */ + if (!strstr(insn_func(insn)->name, ".cold") && + strstr(insn_func(dest_insn)->name, ".cold")) { + insn_func(insn)->cfunc =3D insn_func(dest_insn); + insn_func(dest_insn)->pfunc =3D insn_func(insn); + goto set_jump_dest; + } + + if (is_first_func_insn(file, dest_insn)) { + /* Internal sibling call */ + add_call_dest(file, insn, insn_func(dest_insn), true); + continue; + } + +set_jump_dest: + insn->jump_dest =3D dest_insn; } =20 return 0; --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 425791D2F52; Tue, 3 Sep 2024 04:00:36 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336037; cv=none; b=M4BskPwOHQvEsFfi3+djGaqY2YVwKviWYcCoSdgUiGekx9/Foj9OpyLefezjtOvNeVy+JLJ6PBTFcY9LobvgUUllDo3DGyiBCgsCHWdI6nNGfB10Mh+3CVgrkew9drZdZXLjMrnTcXcipf6H3v4BhKOh9UGYM9nh5vopCT7bmXI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336037; c=relaxed/simple; bh=VgC2+j0s9bIMK+3nuQz/1Q1o5SD9/C5KSNwbSBE0sEg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=f67M0jmXkpKpCkw7Er2e/dkAKo2OHN7F3ZxcqEALj1MKXw/Ikv0j/UAhfgFBdwN+yvmQp+rRSKLxBMDQXHxRrTg31wf8TX6CfuB4ghfx5PeghjqGYDpAw133Ju3LR/GFyFTAkyD/KXBC+Ns/YQ1KSJ6boHhrHkbalyefdUj8wjg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=PXoDzT2z; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="PXoDzT2z" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 6E72BC4CEC9; Tue, 3 Sep 2024 04:00:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336036; bh=VgC2+j0s9bIMK+3nuQz/1Q1o5SD9/C5KSNwbSBE0sEg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=PXoDzT2zkdmushDDgZReQT6xPHxRasR8St4zk0vucHQ+XRZDd3DAaAJY2Ky6Ac69n 2XnXTb7nnVKipAqEYu7PhDKfe0brC5Ae2SmhuTSvtUacfF2IHhBuRsT8Dhn/3uaM64 lf5DzsVRvqJNumVIUmH90x26XDAcO6uZ+NF26hGJ77vaVhYxKAbsqnAafvNJzdpjQ8 cOzaww1pE1MEjxiPiiSKum7SZRz4eTgqSbKqyzS387/KocH9GoxZc6bnTPQEXM9BSz lzXh/MSv0vD6/JST6IH9NWm64dONtwjUGSsHisCHxyK1k3YBT69+ImdlqTT8/ob+pa w9yP6QNZqWFBw== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 15/31] objtool: Interval tree cleanups Date: Mon, 2 Sep 2024 20:59:58 -0700 Message-ID: <74b0bbc42dcbd778f14946ab600670f7d14c6c6f.1725334260.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Change some comments and variable names to improve readability of the interval tree code. Signed-off-by: Josh Poimboeuf --- tools/objtool/elf.c | 50 ++++++++++++++++++++++----------------------- 1 file changed, 24 insertions(+), 26 deletions(-) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 12dbcf425321..fc76692ced2c 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -103,7 +103,7 @@ INTERVAL_TREE_DEFINE(struct symbol, node, unsigned long= , __subtree_last, _iter; _iter =3D __sym_iter_next(_iter, (_start), (_end))) =20 struct symbol_hole { - unsigned long key; + unsigned long offset; const struct symbol *sym; }; =20 @@ -115,10 +115,10 @@ static int symbol_hole_by_offset(const void *key, con= st struct rb_node *node) const struct symbol *s =3D rb_entry(node, struct symbol, node); struct symbol_hole *sh =3D (void *)key; =20 - if (sh->key < s->offset) + if (sh->offset < s->offset) return -1; =20 - if (sh->key >=3D s->offset + s->len) { + if (sh->offset >=3D s->offset + s->len) { if (s->type !=3D STT_SECTION) sh->sym =3D s; return 1; @@ -167,11 +167,11 @@ static struct symbol *find_symbol_by_index(struct elf= *elf, unsigned int idx) struct symbol *find_symbol_by_offset(struct section *sec, unsigned long of= fset) { struct rb_root_cached *tree =3D (struct rb_root_cached *)&sec->symbol_tre= e; - struct symbol *iter; + struct symbol *sym; =20 - __sym_for_each(iter, tree, offset, offset) { - if (iter->offset =3D=3D offset && !is_section_symbol(iter)) - return iter; + __sym_for_each(sym, tree, offset, offset) { + if (sym->offset =3D=3D offset && !is_section_symbol(sym)) + return sym; } =20 return NULL; @@ -180,11 +180,11 @@ struct symbol *find_symbol_by_offset(struct section *= sec, unsigned long offset) struct symbol *find_func_by_offset(struct section *sec, unsigned long offs= et) { struct rb_root_cached *tree =3D (struct rb_root_cached *)&sec->symbol_tre= e; - struct symbol *iter; + struct symbol *sym; =20 - __sym_for_each(iter, tree, offset, offset) { - if (iter->offset =3D=3D offset && is_function_symbol(iter)) - return iter; + __sym_for_each(sym, tree, offset, offset) { + if (sym->offset =3D=3D offset && is_function_symbol(sym)) + return sym; } =20 return NULL; @@ -209,26 +209,24 @@ struct symbol *find_symbol_containing(const struct se= ction *sec, unsigned long o int find_symbol_hole_containing(const struct section *sec, unsigned long o= ffset) { struct symbol_hole hole =3D { - .key =3D offset, + .offset =3D offset, .sym =3D NULL, }; struct rb_node *n; struct symbol *s; =20 - /* - * Find the rightmost symbol for which @offset is after it. - */ + /* Find the last symbol before @offset */ n =3D rb_find(&hole, &sec->symbol_tree.rb_root, symbol_hole_by_offset); =20 - /* found a symbol that contains @offset */ + /* found a symbol containing @offset */ if (n) return 0; /* not a hole */ =20 - /* didn't find a symbol for which @offset is after it */ + /* no symbol before @offset */ if (!hole.sym) return 0; /* not a hole */ =20 - /* @offset >=3D sym->offset + sym->len, find symbol after it */ + /* find first symbol after @offset */ n =3D rb_next(&hole.sym->node); if (!n) return -1; /* until end of address space */ @@ -241,11 +239,11 @@ int find_symbol_hole_containing(const struct section = *sec, unsigned long offset) struct symbol *find_func_containing(struct section *sec, unsigned long off= set) { struct rb_root_cached *tree =3D (struct rb_root_cached *)&sec->symbol_tre= e; - struct symbol *iter; + struct symbol *sym; =20 - __sym_for_each(iter, tree, offset, offset) { - if (is_function_symbol(iter)) - return iter; + __sym_for_each(sym, tree, offset, offset) { + if (is_function_symbol(sym)) + return sym; } =20 return NULL; @@ -393,7 +391,7 @@ static void elf_add_symbol(struct elf *elf, struct symb= ol *sym) { struct list_head *entry; struct rb_node *pnode; - struct symbol *iter; + struct symbol *s; =20 INIT_LIST_HEAD(&sym->pv_target); sym->alias =3D sym; @@ -407,9 +405,9 @@ static void elf_add_symbol(struct elf *elf, struct symb= ol *sym) sym->offset =3D sym->sym.st_value; sym->len =3D sym->sym.st_size; =20 - __sym_for_each(iter, &sym->sec->symbol_tree, sym->offset, sym->offset) { - if (iter->offset =3D=3D sym->offset && iter->type =3D=3D sym->type) - iter->alias =3D sym; + __sym_for_each(s, &sym->sec->symbol_tree, sym->offset, sym->offset) { + if (s->offset =3D=3D sym->offset && s->type =3D=3D sym->type) + s->alias =3D sym; } =20 __sym_insert(sym, &sym->sec->symbol_tree); --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id E14EB1D04B8; Tue, 3 Sep 2024 04:00:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336038; cv=none; b=PF62CkMgRXOJZt5An+PzWYAGiS4GD0YsvpGTOm2rgmLxq3QcPh6Wc8o9jhz0JxfG4wBfS6c/W8qP5OQp8HSYpNwCsL0wQdrGrqVDKTKZajyr0FntA79YN0uevoisgFQTFb3WacTc7y+2I8IGtdiCv4DrzgPAIQQCu2h6PCDqHO8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336038; c=relaxed/simple; bh=lB8wZ30oA2Po8K7j/kcuRjyphLFRSY/xnULSUimRWRE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=nvims/RrxEugGyw5dd6V6QTmuWqO0q3C/Y/HYRJ5vRVbbffW+CoUYoju0Ewg2QT1VjLIqq4xUlwCceOfhzK1BkQLsKMqVLwLsg0SFwOrhlkipYo0jXy7XRyeF1pobq1IcWRVWer3TTgT+4hnCRc722nmwte2XLcXddk8UG94bjU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=RQdfHLi8; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="RQdfHLi8" Received: by smtp.kernel.org (Postfix) with ESMTPSA id EAF87C4CEC5; Tue, 3 Sep 2024 04:00:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336037; bh=lB8wZ30oA2Po8K7j/kcuRjyphLFRSY/xnULSUimRWRE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=RQdfHLi80JpLSICdux80JtelpMIAB7iNtakyXP3pXQuCayOp3EP/CLbm0QYdzSu4+ 78W6twAs6WRH2mEThvdW1O1l89zBXeeQdpHST6mFQ0/FuaM50eSwhAYbDk0ZYg5HQD AFbi2yQFH8jCkOjElAzSE8Zrb2nQGNKdxAs71SqlkgYxCXW9AXMBpZf8p32Cobh1wl d3Bi022B8Iuy+pqJl8mAf80ILL73MuIVH/dgcNIl35OCuqTQf5iCaE5M8dEJk1S3lj V7mWqbMUGR+IWQK1f33NLKmNm88wCXSUAPer28n6MewP/a5YCd7AAmc1gmBPfo2rwf 2lG5ShGQ4FEBg== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 16/31] objtool: Simplify fatal error handling Date: Mon, 2 Sep 2024 20:59:59 -0700 Message-ID: <50a3714d81376d61d5a8b8297c9016f8a0ede519.1725334260.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" For fatal errors, exit right away instead of passing the error back. Signed-off-by: Josh Poimboeuf --- tools/objtool/arch/loongarch/orc.c | 30 +- tools/objtool/arch/x86/decode.c | 40 +- tools/objtool/arch/x86/orc.c | 27 +- tools/objtool/builtin-check.c | 63 +- tools/objtool/check.c | 836 ++++++++---------------- tools/objtool/elf.c | 507 +++++--------- tools/objtool/include/objtool/elf.h | 8 +- tools/objtool/include/objtool/orc.h | 10 +- tools/objtool/include/objtool/special.h | 2 +- tools/objtool/include/objtool/warn.h | 42 +- tools/objtool/objtool.c | 59 +- tools/objtool/orc_dump.c | 96 +-- tools/objtool/orc_gen.c | 40 +- tools/objtool/special.c | 56 +- tools/objtool/weak.c | 2 +- 15 files changed, 625 insertions(+), 1193 deletions(-) diff --git a/tools/objtool/arch/loongarch/orc.c b/tools/objtool/arch/loonga= rch/orc.c index 873536d009d9..deb3b85e2e81 100644 --- a/tools/objtool/arch/loongarch/orc.c +++ b/tools/objtool/arch/loongarch/orc.c @@ -7,7 +7,7 @@ #include #include =20 -int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct in= struction *insn) +void init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct i= nstruction *insn) { struct cfi_reg *fp =3D &cfi->regs[CFI_FP]; struct cfi_reg *ra =3D &cfi->regs[CFI_RA]; @@ -21,16 +21,16 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_st= ate *cfi, struct instruct * STACK_FRAME_NON_STANDARD functions. */ orc->type =3D ORC_TYPE_UNDEFINED; - return 0; + return; } =20 switch (cfi->type) { case UNWIND_HINT_TYPE_UNDEFINED: orc->type =3D ORC_TYPE_UNDEFINED; - return 0; + return; case UNWIND_HINT_TYPE_END_OF_STACK: orc->type =3D ORC_TYPE_END_OF_STACK; - return 0; + return; case UNWIND_HINT_TYPE_CALL: orc->type =3D ORC_TYPE_CALL; break; @@ -41,8 +41,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_stat= e *cfi, struct instruct orc->type =3D ORC_TYPE_REGS_PARTIAL; break; default: - WARN_INSN(insn, "unknown unwind hint type %d", cfi->type); - return -1; + ERROR_INSN(insn, "unknown unwind hint type %d", cfi->type); } =20 orc->signal =3D cfi->signal; @@ -55,8 +54,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_stat= e *cfi, struct instruct orc->sp_reg =3D ORC_REG_FP; break; default: - WARN_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base); - return -1; + ERROR(insn, "unknown CFA base reg %d", cfi->cfa.base); } =20 switch (fp->base) { @@ -72,8 +70,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_stat= e *cfi, struct instruct orc->fp_reg =3D ORC_REG_FP; break; default: - WARN_INSN(insn, "unknown FP base reg %d", fp->base); - return -1; + ERROR_INSN(insn, "unknown FP base reg %d", fp->base); } =20 switch (ra->base) { @@ -89,16 +86,13 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_st= ate *cfi, struct instruct orc->ra_reg =3D ORC_REG_FP; break; default: - WARN_INSN(insn, "unknown RA base reg %d", ra->base); - return -1; + ERROR_INSN(insn, "unknown RA base reg %d", ra->base); } =20 orc->sp_offset =3D cfi->cfa.offset; - - return 0; } =20 -int write_orc_entry(struct elf *elf, struct section *orc_sec, +void write_orc_entry(struct elf *elf, struct section *orc_sec, struct section *ip_sec, unsigned int idx, struct section *insn_sec, unsigned long insn_off, struct orc_entry *o) @@ -110,11 +104,7 @@ int write_orc_entry(struct elf *elf, struct section *o= rc_sec, memcpy(orc, o, sizeof(*orc)); =20 /* populate reloc for ip */ - if (!elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx, - insn_sec, insn_off)) - return -1; - - return 0; + elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx, insn_sec, in= sn_off); } =20 static const char *reg_name(unsigned int reg) diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decod= e.c index 1b24b05eff09..6b34b058a821 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -36,8 +36,7 @@ static int is_x86_64(const struct elf *elf) case EM_386: return 0; default: - WARN("unexpected ELF machine type %d", elf->ehdr.e_machine); - return -1; + ERROR("unexpected ELF machine type %d", elf->ehdr.e_machine); } } =20 @@ -166,10 +165,8 @@ int arch_decode_instruction(struct objtool_file *file,= const struct section *sec =20 ret =3D insn_decode(&ins, sec->data->d_buf + offset, maxlen, x86_64 ? INSN_MODE_64 : INSN_MODE_32); - if (ret < 0) { - WARN("can't decode instruction at %s:0x%lx", sec->name, offset); - return -1; - } + if (ret < 0) + ERROR("can't decode instruction at %s:0x%lx", sec->name, offset); =20 insn->len =3D ins.length; insn->type =3D INSN_OTHER; @@ -441,10 +438,8 @@ int arch_decode_instruction(struct objtool_file *file,= const struct section *sec break; =20 case 0x8d: - if (mod_is_reg()) { - WARN("invalid LEA encoding at %s:0x%lx", sec->name, offset); - break; - } + if (mod_is_reg()) + ERROR("invalid LEA encoding at %s:0x%lx", sec->name, offset); =20 /* skip non 64bit ops */ if (!rex_w) @@ -553,8 +548,7 @@ int arch_decode_instruction(struct objtool_file *file, = const struct section *sec if (ins.prefixes.nbytes =3D=3D 1 && ins.prefixes.bytes[0] =3D=3D 0xf2) { /* ENQCMD cannot be used in the kernel. */ - WARN("ENQCMD instruction at %s:%lx", sec->name, - offset); + ERROR("ENQCMD instruction at %s:%lx", sec->name, offset); } =20 } else if (op2 =3D=3D 0xa0 || op2 =3D=3D 0xa8) { @@ -637,10 +631,8 @@ int arch_decode_instruction(struct objtool_file *file,= const struct section *sec func =3D disp->sym; if (disp->sym->type =3D=3D STT_SECTION) func =3D find_symbol_by_offset(disp->sym->sec, reloc_addend(disp)); - if (!func) { - WARN("no func for pv_ops[]"); - return -1; - } + if (!func) + ERROR("no func for pv_ops[]"); =20 objtool_pv_add(file, idx, func); } @@ -703,13 +695,13 @@ int arch_decode_instruction(struct objtool_file *file= , const struct section *sec =20 insn->type =3D INSN_CALL_DYNAMIC; if (has_notrack_prefix(&ins)) - WARN("notrack prefix found at %s:0x%lx", sec->name, offset); + ERROR("notrack prefix found at %s:0x%lx", sec->name, offset); =20 } else if (modrm_reg =3D=3D 4) { =20 insn->type =3D INSN_JUMP_DYNAMIC; if (has_notrack_prefix(&ins)) - WARN("notrack prefix found at %s:0x%lx", sec->name, offset); + ERROR("notrack prefix found at %s:0x%lx", sec->name, offset); =20 } else if (modrm_reg =3D=3D 5) { =20 @@ -764,10 +756,8 @@ const char *arch_nop_insn(int len) { BYTES_NOP5 }, }; =20 - if (len < 1 || len > 5) { - WARN("invalid NOP size: %d\n", len); - return NULL; - } + if (len < 1 || len > 5) + ERROR("invalid NOP size: %d\n", len); =20 return nops[len-1]; } @@ -784,10 +774,8 @@ const char *arch_ret_insn(int len) { BYTE_RET, 0xcc, BYTES_NOP3 }, }; =20 - if (len < 1 || len > 5) { - WARN("invalid RET size: %d\n", len); - return NULL; - } + if (len < 1 || len > 5) + ERROR("invalid RET size: %d\n", len); =20 return ret[len-1]; } diff --git a/tools/objtool/arch/x86/orc.c b/tools/objtool/arch/x86/orc.c index b6cd943e87f9..6e0aa5a56b39 100644 --- a/tools/objtool/arch/x86/orc.c +++ b/tools/objtool/arch/x86/orc.c @@ -7,7 +7,7 @@ #include #include =20 -int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct in= struction *insn) +void init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct i= nstruction *insn) { struct cfi_reg *bp =3D &cfi->regs[CFI_BP]; =20 @@ -20,16 +20,16 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_st= ate *cfi, struct instruct * STACK_FRAME_NON_STANDARD functions. */ orc->type =3D ORC_TYPE_UNDEFINED; - return 0; + return; } =20 switch (cfi->type) { case UNWIND_HINT_TYPE_UNDEFINED: orc->type =3D ORC_TYPE_UNDEFINED; - return 0; + return; case UNWIND_HINT_TYPE_END_OF_STACK: orc->type =3D ORC_TYPE_END_OF_STACK; - return 0; + return; case UNWIND_HINT_TYPE_CALL: orc->type =3D ORC_TYPE_CALL; break; @@ -40,8 +40,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_stat= e *cfi, struct instruct orc->type =3D ORC_TYPE_REGS_PARTIAL; break; default: - WARN_INSN(insn, "unknown unwind hint type %d", cfi->type); - return -1; + ERROR_INSN(insn, "unknown unwind hint type %d", cfi->type); } =20 orc->signal =3D cfi->signal; @@ -72,8 +71,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_stat= e *cfi, struct instruct orc->sp_reg =3D ORC_REG_DX; break; default: - WARN_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base); - return -1; + ERROR_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base); } =20 switch (bp->base) { @@ -87,17 +85,14 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_st= ate *cfi, struct instruct orc->bp_reg =3D ORC_REG_BP; break; default: - WARN_INSN(insn, "unknown BP base reg %d", bp->base); - return -1; + ERROR_INSN(insn, "unknown BP base reg %d", bp->base); } =20 orc->sp_offset =3D cfi->cfa.offset; orc->bp_offset =3D bp->offset; - - return 0; } =20 -int write_orc_entry(struct elf *elf, struct section *orc_sec, +void write_orc_entry(struct elf *elf, struct section *orc_sec, struct section *ip_sec, unsigned int idx, struct section *insn_sec, unsigned long insn_off, struct orc_entry *o) @@ -111,11 +106,7 @@ int write_orc_entry(struct elf *elf, struct section *o= rc_sec, orc->bp_offset =3D bswap_if_needed(elf, orc->bp_offset); =20 /* populate reloc for ip */ - if (!elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx, - insn_sec, insn_off)) - return -1; - - return 0; + elf_init_reloc_text_sym(elf, ip_sec, idx * sizeof(int), idx, insn_sec, in= sn_off); } =20 static const char *reg_name(unsigned int reg) diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index 2f16f5ee83ae..6894ef68d125 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -8,11 +8,7 @@ #include #include #include - -#define ERROR(format, ...) \ - fprintf(stderr, \ - "error: objtool: " format "\n", \ - ##__VA_ARGS__) +#include =20 struct opts opts; =20 @@ -129,7 +125,7 @@ int cmd_parse_options(int argc, const char **argv, cons= t char * const usage[]) return argc; } =20 -static bool opts_valid(void) +static void validate_opts(void) { if (opts.hack_jump_label || opts.hack_noinstr || @@ -143,63 +139,46 @@ static bool opts_valid(void) opts.stackval || opts.static_call || opts.uaccess) { - if (opts.dump_orc) { + if (opts.dump_orc) ERROR("--dump can't be combined with other options"); - return false; - } =20 - return true; + return; } =20 - if (opts.unret && !opts.rethunk) { + if (opts.unret && !opts.rethunk) ERROR("--unret requires --rethunk"); - return false; - } =20 if (opts.dump_orc) - return true; + return; =20 ERROR("At least one command required"); - return false; } =20 -static bool mnop_opts_valid(void) +static void validate_mnop_opts(void) { - if (opts.mnop && !opts.mcount) { + if (opts.mnop && !opts.mcount) ERROR("--mnop requires --mcount"); - return false; - } - - return true; } =20 -static bool link_opts_valid(struct objtool_file *file) +static void validate_link_opts(struct objtool_file *file) { if (opts.link) - return true; + return; =20 if (has_multiple_files(file->elf)) { - ERROR("Linked object detected, forcing --link"); + WARN("Linked object detected, forcing --link"); opts.link =3D true; - return true; + return; } =20 - if (opts.noinstr) { + if (opts.noinstr) ERROR("--noinstr requires --link"); - return false; - } =20 - if (opts.ibt) { + if (opts.ibt) ERROR("--ibt requires --link"); - return false; - } =20 - if (opts.unret) { + if (opts.unret) ERROR("--unret requires --link"); - return false; - } - - return true; } =20 int objtool_run(int argc, const char **argv) @@ -211,8 +190,7 @@ int objtool_run(int argc, const char **argv) argc =3D cmd_parse_options(argc, argv, check_usage); objname =3D argv[0]; =20 - if (!opts_valid()) - return 1; + validate_opts(); =20 if (opts.dump_orc) return orc_dump(objname); @@ -221,18 +199,15 @@ int objtool_run(int argc, const char **argv) if (!file) return 1; =20 - if (!mnop_opts_valid()) - return 1; - - if (!link_opts_valid(file)) - return 1; + validate_mnop_opts(); + validate_link_opts(file); =20 ret =3D check(file); if (ret) return ret; =20 if (file->elf->changed) - return elf_write(file->elf); + elf_write(file->elf); =20 return 0; } diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 6490bc939892..af945854dd72 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -292,11 +292,11 @@ static void init_insn_state(struct objtool_file *file= , struct insn_state *state, =20 static struct cfi_state *cfi_alloc(void) { - struct cfi_state *cfi =3D calloc(1, sizeof(struct cfi_state)); - if (!cfi) { - WARN("calloc failed"); - exit(1); - } + struct cfi_state *cfi; + + cfi =3D calloc(1, sizeof(struct cfi_state)); + ERROR_ON(!cfi, "calloc"); + nr_cfi++; return cfi; } @@ -346,15 +346,15 @@ static void cfi_hash_add(struct cfi_state *cfi) static void *cfi_hash_alloc(unsigned long size) { cfi_bits =3D max(10, ilog2(size)); + cfi_hash =3D mmap(NULL, sizeof(struct hlist_head) << cfi_bits, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, 0); - if (cfi_hash =3D=3D (void *)-1L) { - WARN("mmap fail cfi_hash"); - cfi_hash =3D NULL; - } else if (opts.stats) { + if (cfi_hash =3D=3D (void *)-1L) + ERROR("mmap fail cfi_hash"); + + if (opts.stats) printf("cfi_bits: %d\n", cfi_bits); - } =20 return cfi_hash; } @@ -366,7 +366,7 @@ static unsigned long nr_insns_visited; * Call the arch-specific instruction decoder for all the instructions and= add * them to the global instruction list. */ -static int decode_instructions(struct objtool_file *file) +static void decode_instructions(struct objtool_file *file) { struct section *sec; struct symbol *func; @@ -405,10 +405,8 @@ static int decode_instructions(struct objtool_file *fi= le) for (offset =3D 0; offset < sec_size(sec); offset +=3D insn->len) { if (!insns || idx =3D=3D INSN_CHUNK_MAX) { insns =3D calloc(sizeof(*insn), INSN_CHUNK_SIZE); - if (!insns) { - WARN("malloc failed"); - return -1; - } + ERROR_ON(!insns, "calloc"); + idx =3D 0; } else { idx++; @@ -424,8 +422,7 @@ static int decode_instructions(struct objtool_file *fil= e) ret =3D arch_decode_instruction(file, sec, offset, sec_size(sec) - offset, insn); - if (ret) - return ret; + ERROR_ON(ret, "arch_decode_instruction failed"); =20 prev_len =3D insn->len; =20 @@ -451,19 +448,14 @@ static int decode_instructions(struct objtool_file *f= ile) /* Heuristic: likely an "end" symbol */ if (is_notype_symbol(func)) continue; - WARN("%s(): STT_FUNC at end of section", - func->name); - return -1; + ERROR("%s(): STT_FUNC at end of section", func->name); } =20 if (func->embedded_insn || func->alias !=3D func) continue; =20 - if (!find_insn(file, sec, func->offset)) { - WARN("%s(): can't find starting instruction", - func->name); - return -1; - } + if (!find_insn(file, sec, func->offset)) + ERROR("%s(): can't find starting instruction", func->name); =20 sym_for_each_insn(file, func, insn) { insn->sym =3D func; @@ -483,14 +475,12 @@ static int decode_instructions(struct objtool_file *f= ile) =20 if (opts.stats) printf("nr_insns: %lu\n", nr_insns); - - return 0; } =20 /* * Read the pv_ops[] .data table to find the static initialized values. */ -static int add_pv_ops(struct objtool_file *file, const char *symname) +static void add_pv_ops(struct objtool_file *file, const char *symname) { struct symbol *sym, *func; unsigned long off, end; @@ -499,7 +489,7 @@ static int add_pv_ops(struct objtool_file *file, const = char *symname) =20 sym =3D find_symbol_by_name(file->elf, symname); if (!sym) - return 0; + return; =20 off =3D sym->offset; end =3D off + sym->len; @@ -509,10 +499,14 @@ static int add_pv_ops(struct objtool_file *file, cons= t char *symname) break; =20 func =3D reloc->sym; - if (is_section_symbol(func)) + if (is_section_symbol(func)) { func =3D find_symbol_by_offset(reloc->sym->sec, reloc_addend(reloc)); =20 + if (!func) + ERROR("can't find sym for %s", reloc->sym->name); + } + idx =3D (reloc_offset(reloc) - sym->offset) / sizeof(unsigned long); =20 objtool_pv_add(file, idx, func); @@ -522,13 +516,13 @@ static int add_pv_ops(struct objtool_file *file, cons= t char *symname) break; } =20 - return 0; + return; } =20 /* * Allocate and initialize file->pv_ops[]. */ -static int init_pv_ops(struct objtool_file *file) +static void init_pv_ops(struct objtool_file *file) { static const char *pv_ops_tables[] =3D { "pv_ops", @@ -542,26 +536,23 @@ static int init_pv_ops(struct objtool_file *file) int idx, nr; =20 if (!opts.noinstr) - return 0; + return; =20 file->pv_ops =3D NULL; =20 sym =3D find_symbol_by_name(file->elf, "pv_ops"); if (!sym) - return 0; + return; =20 nr =3D sym->len / sizeof(unsigned long); file->pv_ops =3D calloc(sizeof(struct pv_state), nr); - if (!file->pv_ops) - return -1; + ERROR_ON(!file->pv_ops, "calloc"); =20 for (idx =3D 0; idx < nr; idx++) INIT_LIST_HEAD(&file->pv_ops[idx].targets); =20 for (idx =3D 0; (pv_ops =3D pv_ops_tables[idx]); idx++) add_pv_ops(file, pv_ops); - - return 0; } =20 static struct instruction *find_last_insn(struct objtool_file *file, @@ -580,7 +571,7 @@ static struct instruction *find_last_insn(struct objtoo= l_file *file, /* * Mark "ud2" instructions and manually annotated dead ends. */ -static int add_dead_ends(struct objtool_file *file) +static void add_dead_ends(struct objtool_file *file) { struct section *rsec; struct reloc *reloc; @@ -601,15 +592,12 @@ static int add_dead_ends(struct objtool_file *file) insn =3D prev_insn_same_sec(file, insn); else if (offset =3D=3D sec_size(reloc->sym->sec)) { insn =3D find_last_insn(file, reloc->sym->sec); - if (!insn) { - WARN("can't find unreachable insn at %s+0x%" PRIx64, - reloc->sym->sec->name, offset); - return -1; - } + if (!insn) + ERROR("can't find unreachable insn at %s+0x%" PRIx64, + reloc->sym->sec->name, offset); } else { - WARN("can't find unreachable insn at %s+0x%" PRIx64, - reloc->sym->sec->name, offset); - return -1; + ERROR("can't find unreachable insn at %s+0x%" PRIx64, + reloc->sym->sec->name, offset); } =20 insn->dead_end =3D true; @@ -624,7 +612,7 @@ static int add_dead_ends(struct objtool_file *file) */ rsec =3D find_section_by_name(file->elf, ".rela.discard.reachable"); if (!rsec) - return 0; + return; =20 for_each_reloc(rsec, reloc) { offset =3D reloc->sym->offset + reloc_addend(reloc); @@ -633,24 +621,19 @@ static int add_dead_ends(struct objtool_file *file) insn =3D prev_insn_same_sec(file, insn); else if (offset =3D=3D sec_size(reloc->sym->sec)) { insn =3D find_last_insn(file, reloc->sym->sec); - if (!insn) { - WARN("can't find reachable insn at %s+0x%" PRIx64, - reloc->sym->sec->name, offset); - return -1; - } + if (!insn) + ERROR("can't find reachable insn at %s+0x%" PRIx64, + reloc->sym->sec->name, offset); } else { - WARN("can't find reachable insn at %s+0x%" PRIx64, - reloc->sym->sec->name, offset); - return -1; + ERROR("can't find reachable insn at %s+0x%" PRIx64, + reloc->sym->sec->name, offset); } =20 insn->dead_end =3D false; } - - return 0; } =20 -static int create_static_call_sections(struct objtool_file *file) +static void create_static_call_sections(struct objtool_file *file) { struct static_call_site *site; struct section *sec; @@ -663,11 +646,11 @@ static int create_static_call_sections(struct objtool= _file *file) if (sec) { INIT_LIST_HEAD(&file->static_call_list); WARN("file already has .static_call_sites section, skipping"); - return 0; + return; } =20 if (list_empty(&file->static_call_list)) - return 0; + return; =20 idx =3D 0; list_for_each_entry(insn, &file->static_call_list, call_node) @@ -675,8 +658,6 @@ static int create_static_call_sections(struct objtool_f= ile *file) =20 sec =3D elf_create_section_pair(file->elf, ".static_call_sites", sizeof(*site), idx, idx * 2); - if (!sec) - return -1; =20 /* Allow modules to modify the low bits of static_call_site::key */ sec->sh.sh_flags |=3D SHF_WRITE; @@ -685,33 +666,23 @@ static int create_static_call_sections(struct objtool= _file *file) list_for_each_entry(insn, &file->static_call_list, call_node) { =20 /* populate reloc for 'addr' */ - if (!elf_init_reloc_text_sym(file->elf, sec, - idx * sizeof(*site), idx * 2, - insn->sec, insn->offset)) - return -1; + elf_init_reloc_text_sym(file->elf, sec, idx * sizeof(*site), + idx * 2, insn->sec, insn->offset); =20 /* find key symbol */ key_name =3D strdup(insn_call_dest(insn)->name); - if (!key_name) { - perror("strdup"); - return -1; - } - if (strncmp(key_name, STATIC_CALL_TRAMP_PREFIX_STR, - STATIC_CALL_TRAMP_PREFIX_LEN)) { - WARN("static_call: trampoline name malformed: %s", key_name); - free(key_name); - return -1; - } + ERROR_ON(!key_name, "strdup"); + + if (strncmp(key_name, STATIC_CALL_TRAMP_PREFIX_STR, STATIC_CALL_TRAMP_PR= EFIX_LEN)) + ERROR("static_call: trampoline name malformed: %s", key_name); + tmp =3D key_name + STATIC_CALL_TRAMP_PREFIX_LEN - STATIC_CALL_KEY_PREFIX= _LEN; memcpy(tmp, STATIC_CALL_KEY_PREFIX_STR, STATIC_CALL_KEY_PREFIX_LEN); =20 key_sym =3D find_symbol_by_name(file->elf, tmp); if (!key_sym) { - if (!opts.module) { - WARN("static_call: can't find static_call_key symbol: %s", tmp); - free(key_name); - return -1; - } + if (!opts.module) + ERROR("static_call: can't find static_call_key symbol: %s", tmp); =20 /* * For modules(), the key might not be exported, which @@ -727,19 +698,15 @@ static int create_static_call_sections(struct objtool= _file *file) free(key_name); =20 /* populate reloc for 'key' */ - if (!elf_init_reloc_data_sym(file->elf, sec, - idx * sizeof(*site) + 4, - (idx * 2) + 1, key_sym, - is_sibling_call(insn) * STATIC_CALL_SITE_TAIL)) - return -1; + elf_init_reloc_data_sym(file->elf, sec, idx * sizeof(*site) + 4, + (idx * 2) + 1, key_sym, + is_sibling_call(insn) * STATIC_CALL_SITE_TAIL); =20 idx++; } - - return 0; } =20 -static int create_retpoline_sites_sections(struct objtool_file *file) +static void create_retpoline_sites_sections(struct objtool_file *file) { struct instruction *insn; struct section *sec; @@ -748,7 +715,7 @@ static int create_retpoline_sites_sections(struct objto= ol_file *file) sec =3D find_section_by_name(file->elf, ".retpoline_sites"); if (sec) { WARN("file already has .retpoline_sites, skipping"); - return 0; + return; } =20 idx =3D 0; @@ -756,28 +723,22 @@ static int create_retpoline_sites_sections(struct obj= tool_file *file) idx++; =20 if (!idx) - return 0; + return; =20 sec =3D elf_create_section_pair(file->elf, ".retpoline_sites", sizeof(int), idx, idx); - if (!sec) - return -1; =20 idx =3D 0; list_for_each_entry(insn, &file->retpoline_call_list, call_node) { =20 - if (!elf_init_reloc_text_sym(file->elf, sec, - idx * sizeof(int), idx, - insn->sec, insn->offset)) - return -1; + elf_init_reloc_text_sym(file->elf, sec, idx * sizeof(int), idx, + insn->sec, insn->offset); =20 idx++; } - - return 0; } =20 -static int create_return_sites_sections(struct objtool_file *file) +static void create_return_sites_sections(struct objtool_file *file) { struct instruction *insn; struct section *sec; @@ -786,7 +747,7 @@ static int create_return_sites_sections(struct objtool_= file *file) sec =3D find_section_by_name(file->elf, ".return_sites"); if (sec) { WARN("file already has .return_sites, skipping"); - return 0; + return; } =20 idx =3D 0; @@ -794,28 +755,22 @@ static int create_return_sites_sections(struct objtoo= l_file *file) idx++; =20 if (!idx) - return 0; + return; =20 sec =3D elf_create_section_pair(file->elf, ".return_sites", sizeof(int), idx, idx); - if (!sec) - return -1; =20 idx =3D 0; list_for_each_entry(insn, &file->return_thunk_list, call_node) { =20 - if (!elf_init_reloc_text_sym(file->elf, sec, - idx * sizeof(int), idx, - insn->sec, insn->offset)) - return -1; + elf_init_reloc_text_sym(file->elf, sec, idx * sizeof(int), idx, + insn->sec, insn->offset); =20 idx++; } - - return 0; } =20 -static int create_ibt_endbr_seal_sections(struct objtool_file *file) +static void create_ibt_endbr_seal_sections(struct objtool_file *file) { struct instruction *insn; struct section *sec; @@ -824,7 +779,7 @@ static int create_ibt_endbr_seal_sections(struct objtoo= l_file *file) sec =3D find_section_by_name(file->elf, ".ibt_endbr_seal"); if (sec) { WARN("file already has .ibt_endbr_seal, skipping"); - return 0; + return; } =20 idx =3D 0; @@ -838,12 +793,10 @@ static int create_ibt_endbr_seal_sections(struct objt= ool_file *file) } =20 if (!idx) - return 0; + return; =20 sec =3D elf_create_section_pair(file->elf, ".ibt_endbr_seal", sizeof(int), idx, idx); - if (!sec) - return -1; =20 idx =3D 0; list_for_each_entry(insn, &file->endbr_list, call_node) { @@ -856,20 +809,16 @@ static int create_ibt_endbr_seal_sections(struct objt= ool_file *file) insn->offset =3D=3D sym->offset && (!strcmp(sym->name, "init_module") || !strcmp(sym->name, "cleanup_module"))) - WARN("%s(): not an indirect call target", sym->name); + ERROR("%s(): not an indirect call target", sym->name); =20 - if (!elf_init_reloc_text_sym(file->elf, sec, - idx * sizeof(int), idx, - insn->sec, insn->offset)) - return -1; + elf_init_reloc_text_sym(file->elf, sec, idx * sizeof(int), idx, + insn->sec, insn->offset); =20 idx++; } - - return 0; } =20 -static int create_cfi_sections(struct objtool_file *file) +static void create_cfi_sections(struct objtool_file *file) { struct section *sec; struct symbol *sym; @@ -879,7 +828,7 @@ static int create_cfi_sections(struct objtool_file *fil= e) if (sec) { INIT_LIST_HEAD(&file->call_list); WARN("file already has .cfi_sites section, skipping"); - return 0; + return; } =20 idx =3D 0; @@ -895,8 +844,6 @@ static int create_cfi_sections(struct objtool_file *fil= e) =20 sec =3D elf_create_section_pair(file->elf, ".cfi_sites", sizeof(unsigned int), idx, idx); - if (!sec) - return -1; =20 idx =3D 0; for_each_sym(file->elf, sym) { @@ -906,18 +853,15 @@ static int create_cfi_sections(struct objtool_file *f= ile) if (strncmp(sym->name, "__cfi_", 6)) continue; =20 - if (!elf_init_reloc_text_sym(file->elf, sec, - idx * sizeof(unsigned int), idx, - sym->sec, sym->offset)) - return -1; + elf_init_reloc_text_sym(file->elf, sec, + idx * sizeof(unsigned int), idx, + sym->sec, sym->offset); =20 idx++; } - - return 0; } =20 -static int create_mcount_loc_sections(struct objtool_file *file) +static void create_mcount_loc_sections(struct objtool_file *file) { size_t addr_size =3D elf_addr_size(file->elf); struct instruction *insn; @@ -928,11 +872,11 @@ static int create_mcount_loc_sections(struct objtool_= file *file) if (sec) { INIT_LIST_HEAD(&file->mcount_loc_list); WARN("file already has __mcount_loc section, skipping"); - return 0; + return; } =20 if (list_empty(&file->mcount_loc_list)) - return 0; + return; =20 idx =3D 0; list_for_each_entry(insn, &file->mcount_loc_list, call_node) @@ -940,8 +884,6 @@ static int create_mcount_loc_sections(struct objtool_fi= le *file) =20 sec =3D elf_create_section_pair(file->elf, "__mcount_loc", addr_size, idx, idx); - if (!sec) - return -1; =20 sec->sh.sh_addralign =3D addr_size; =20 @@ -952,18 +894,14 @@ static int create_mcount_loc_sections(struct objtool_= file *file) =20 reloc =3D elf_init_reloc_text_sym(file->elf, sec, idx * addr_size, idx, insn->sec, insn->offset); - if (!reloc) - return -1; =20 set_reloc_type(file->elf, reloc, addr_size =3D=3D 8 ? R_ABS64 : R_ABS32); =20 idx++; } - - return 0; } =20 -static int create_direct_call_sections(struct objtool_file *file) +static void create_direct_call_sections(struct objtool_file *file) { struct instruction *insn; struct section *sec; @@ -973,11 +911,11 @@ static int create_direct_call_sections(struct objtool= _file *file) if (sec) { INIT_LIST_HEAD(&file->call_list); WARN("file already has .call_sites section, skipping"); - return 0; + return; } =20 if (list_empty(&file->call_list)) - return 0; + return; =20 idx =3D 0; list_for_each_entry(insn, &file->call_list, call_node) @@ -985,21 +923,16 @@ static int create_direct_call_sections(struct objtool= _file *file) =20 sec =3D elf_create_section_pair(file->elf, ".call_sites", sizeof(unsigned int), idx, idx); - if (!sec) - return -1; =20 idx =3D 0; list_for_each_entry(insn, &file->call_list, call_node) { =20 - if (!elf_init_reloc_text_sym(file->elf, sec, - idx * sizeof(unsigned int), idx, - insn->sec, insn->offset)) - return -1; + elf_init_reloc_text_sym(file->elf, sec, + idx * sizeof(unsigned int), idx, + insn->sec, insn->offset); =20 idx++; } - - return 0; } =20 /* @@ -1025,13 +958,12 @@ static void add_ignores(struct objtool_file *file) case STT_SECTION: func =3D find_func_by_offset(reloc->sym->sec, reloc_addend(reloc)); if (!func) - continue; + ERROR("bad STACK_FRAME_NON_STANDARD entry"); break; =20 default: - WARN("unexpected relocation symbol type in %s: %d", - rsec->name, reloc->sym->type); - continue; + ERROR("unexpected relocation symbol type in %s: %d", + rsec->name, reloc->sym->type); } =20 func_for_each_insn(file, func, insn) @@ -1247,7 +1179,7 @@ static void add_uaccess_safe(struct objtool_file *fil= e) * But it at least allows objtool to understand the control flow *around* = the * retpoline. */ -static int add_ignore_alternatives(struct objtool_file *file) +static void add_ignore_alternatives(struct objtool_file *file) { struct section *rsec; struct reloc *reloc; @@ -1255,21 +1187,17 @@ static int add_ignore_alternatives(struct objtool_f= ile *file) =20 rsec =3D find_section_by_name(file->elf, ".rela.discard.ignore_alts"); if (!rsec) - return 0; + return; =20 for_each_reloc(rsec, reloc) { unsigned long offset =3D reloc->sym->offset + reloc_addend(reloc); =20 insn =3D find_insn(file, reloc->sym->sec, offset); - if (!insn) { - WARN("bad .discard.ignore_alts entry"); - return -1; - } + if (!insn) + ERROR("bad .discard.ignore_alts entry"); =20 insn->ignore_alts =3D true; } - - return 0; } =20 /* @@ -1370,7 +1298,7 @@ static void annotate_call_site(struct objtool_file *f= ile, elf_write_insn(file->elf, insn->sec, insn->offset, insn->len, sibling ? arch_ret_insn(insn->len) - : arch_nop_insn(insn->len)); + : arch_nop_insn(insn->len)); =20 insn->type =3D sibling ? INSN_RETURN : INSN_NOP; =20 @@ -1389,7 +1317,7 @@ static void annotate_call_site(struct objtool_file *f= ile, =20 if (opts.mcount && sym->fentry) { if (sibling) - WARN_INSN(insn, "tail call to __fentry__ !?!?"); + ERROR_INSN(insn, "tail call to __fentry__ !?!?"); if (opts.mnop) { if (reloc) set_reloc_type(file->elf, reloc, R_NONE); @@ -1504,7 +1432,7 @@ static bool is_first_func_insn(struct objtool_file *f= ile, /* * Find the destination instructions for all jumps. */ -static int add_jump_destinations(struct objtool_file *file) +static void add_jump_destinations(struct objtool_file *file) { struct instruction *insn; struct reloc *reloc; @@ -1559,9 +1487,8 @@ static int add_jump_destinations(struct objtool_file = *file) continue; } =20 - WARN_INSN(insn, "can't find jump dest instruction at %s+0x%lx", - dest_sec->name, dest_off); - return -1; + ERROR_INSN(insn, "can't find jump dest instruction at %s+0x%lx", + dest_sec->name, dest_off); } =20 dest_sym =3D dest_insn->sym; @@ -1638,8 +1565,6 @@ static int add_jump_destinations(struct objtool_file = *file) set_jump_dest: insn->jump_dest =3D dest_insn; } - - return 0; } =20 static struct symbol *find_call_destination(struct section *sec, unsigned = long offset) @@ -1656,7 +1581,7 @@ static struct symbol *find_call_destination(struct se= ction *sec, unsigned long o /* * Find the destination instructions for all calls. */ -static int add_call_destinations(struct objtool_file *file) +static void add_call_destinations(struct objtool_file *file) { struct instruction *insn; unsigned long dest_off; @@ -1677,24 +1602,18 @@ static int add_call_destinations(struct objtool_fil= e *file) if (insn->ignore) continue; =20 - if (!insn_call_dest(insn)) { - WARN_INSN(insn, "unannotated intra-function call"); - return -1; - } + if (!insn_call_dest(insn)) + ERROR_INSN(insn, "unannotated intra-function call"); =20 - if (insn_func(insn) && !is_function_symbol(insn_call_dest(insn))) { - WARN_INSN(insn, "unsupported call to non-function"); - return -1; - } + if (insn_func(insn) && !is_function_symbol(insn_call_dest(insn))) + ERROR_INSN(insn, "unsupported call to non-function"); =20 } else if (is_section_symbol(reloc->sym)) { dest_off =3D arch_dest_reloc_offset(reloc_addend(reloc)); dest =3D find_call_destination(reloc->sym->sec, dest_off); - if (!dest) { - WARN_INSN(insn, "can't find call dest symbol at %s+0x%lx", - reloc->sym->sec->name, dest_off); - return -1; - } + if (!dest) + ERROR_INSN(insn, "can't find call dest symbol at %s+0x%lx", + reloc->sym->sec->name, dest_off); =20 add_call_dest(file, insn, dest, false); =20 @@ -1704,18 +1623,16 @@ static int add_call_destinations(struct objtool_fil= e *file) } else add_call_dest(file, insn, reloc->sym, false); } - - return 0; } =20 /* * The .alternatives section requires some extra special care over and abo= ve * other special sections because alternatives are patched in place. */ -static int handle_group_alt(struct objtool_file *file, - struct special_alt *special_alt, - struct instruction *orig_insn, - struct instruction **new_insn) +static void handle_group_alt(struct objtool_file *file, + struct special_alt *special_alt, + struct instruction *orig_insn, + struct instruction **new_insn) { struct instruction *last_new_insn =3D NULL, *insn, *nop =3D NULL; struct alt_group *orig_alt_group, *new_alt_group; @@ -1726,16 +1643,11 @@ static int handle_group_alt(struct objtool_file *fi= le, struct instruction *last_orig_insn =3D NULL; =20 orig_alt_group =3D malloc(sizeof(*orig_alt_group)); - if (!orig_alt_group) { - WARN("malloc failed"); - return -1; - } + ERROR_ON(!orig_alt_group, "malloc"); + orig_alt_group->cfi =3D calloc(special_alt->orig_len, sizeof(struct cfi_state *)); - if (!orig_alt_group->cfi) { - WARN("calloc failed"); - return -1; - } + ERROR_ON(!orig_alt_group->cfi, "calloc"); =20 insn =3D orig_insn; sec_for_each_insn_from(file, insn) { @@ -1752,20 +1664,16 @@ static int handle_group_alt(struct objtool_file *fi= le, } else { if (orig_alt_group->last_insn->offset + orig_alt_group->last_insn->len - orig_alt_group->first_insn->offset !=3D special_alt->orig_len) { - WARN_INSN(orig_insn, "weirdly overlapping alternative! %ld !=3D %d", - orig_alt_group->last_insn->offset + - orig_alt_group->last_insn->len - - orig_alt_group->first_insn->offset, - special_alt->orig_len); - return -1; + ERROR_INSN(orig_insn, "weirdly overlapping alternative! %ld !=3D %d", + orig_alt_group->last_insn->offset + + orig_alt_group->last_insn->len - + orig_alt_group->first_insn->offset, + special_alt->orig_len); } } =20 new_alt_group =3D malloc(sizeof(*new_alt_group)); - if (!new_alt_group) { - WARN("malloc failed"); - return -1; - } + ERROR_ON(!new_alt_group, "malloc"); =20 if (special_alt->new_len < special_alt->orig_len) { /* @@ -1775,12 +1683,8 @@ static int handle_group_alt(struct objtool_file *fil= e, * instruction affects the stack, the instruction after it (the * nop) will propagate the new state to the shared CFI array. */ - nop =3D malloc(sizeof(*nop)); - if (!nop) { - WARN("malloc failed"); - return -1; - } - memset(nop, 0, sizeof(*nop)); + nop =3D calloc(1, sizeof(*nop)); + ERROR_ON(!nop, "calloc"); =20 nop->sec =3D special_alt->new_sec; nop->offset =3D special_alt->new_off + special_alt->new_len; @@ -1819,11 +1723,9 @@ static int handle_group_alt(struct objtool_file *fil= e, */ alt_reloc =3D insn_reloc(file, insn); if (alt_reloc && arch_pc_relative_reloc(alt_reloc) && - !arch_support_alt_relocation(special_alt, insn, alt_reloc)) { + !arch_support_alt_relocation(special_alt, insn, alt_reloc)) =20 - WARN_INSN(insn, "unsupported relocation in alternatives section"); - return -1; - } + ERROR_INSN(insn, "unsupported relocation in alternatives section"); =20 if (!is_static_jump(insn)) continue; @@ -1834,18 +1736,14 @@ static int handle_group_alt(struct objtool_file *fi= le, dest_off =3D arch_jump_destination(insn); if (dest_off =3D=3D special_alt->new_off + special_alt->new_len) { insn->jump_dest =3D next_insn_same_sec(file, orig_alt_group->last_insn); - if (!insn->jump_dest) { - WARN_INSN(insn, "can't find alternative jump destination"); - return -1; - } + if (!insn->jump_dest) + ERROR_INSN(insn, "can't find alternative jump destination"); } } =20 - if (!last_new_insn) { - WARN_FUNC("can't find last new alternative instruction", - special_alt->new_sec, special_alt->new_off); - return -1; - } + if (!last_new_insn) + ERROR_FUNC(special_alt->new_sec, special_alt->new_off, + "can't find last new alternative instruction"); =20 end: new_alt_group->orig_group =3D orig_alt_group; @@ -1853,7 +1751,6 @@ static int handle_group_alt(struct objtool_file *file, new_alt_group->last_insn =3D last_new_insn; new_alt_group->nop =3D nop; new_alt_group->cfi =3D orig_alt_group->cfi; - return 0; } =20 /* @@ -1861,17 +1758,14 @@ static int handle_group_alt(struct objtool_file *fi= le, * If the original instruction is a jump, make the alt entry an effective = nop * by just skipping the original instruction. */ -static int handle_jump_alt(struct objtool_file *file, - struct special_alt *special_alt, - struct instruction *orig_insn, - struct instruction **new_insn) +static void handle_jump_alt(struct objtool_file *file, + struct special_alt *special_alt, + struct instruction *orig_insn, + struct instruction **new_insn) { if (orig_insn->type !=3D INSN_JUMP_UNCONDITIONAL && - orig_insn->type !=3D INSN_NOP) { - - WARN_INSN(orig_insn, "unsupported instruction at jump label"); - return -1; - } + orig_insn->type !=3D INSN_NOP) + ERROR_INSN(orig_insn, "unsupported instruction at jump label"); =20 if (opts.hack_jump_label && special_alt->key_addend & 2) { struct reloc *reloc =3D insn_reloc(file, orig_insn); @@ -1890,7 +1784,7 @@ static int handle_jump_alt(struct objtool_file *file, else file->jl_nop_long++; =20 - return 0; + return; } =20 if (orig_insn->len =3D=3D 2) @@ -1899,7 +1793,6 @@ static int handle_jump_alt(struct objtool_file *file, file->jl_long++; =20 *new_insn =3D next_insn_same_sec(file, orig_insn); - return 0; } =20 /* @@ -1908,65 +1801,43 @@ static int handle_jump_alt(struct objtool_file *fil= e, * instruction(s) has them added to its insn->alts list, which will be * traversed in validate_branch(). */ -static int add_special_section_alts(struct objtool_file *file) +static void add_special_section_alts(struct objtool_file *file) { struct list_head special_alts; struct instruction *orig_insn, *new_insn; struct special_alt *special_alt, *tmp; struct alternative *alt; - int ret; =20 - ret =3D special_get_alts(file->elf, &special_alts); - if (ret) - return ret; + special_get_alts(file->elf, &special_alts); =20 list_for_each_entry_safe(special_alt, tmp, &special_alts, list) { =20 orig_insn =3D find_insn(file, special_alt->orig_sec, special_alt->orig_off); - if (!orig_insn) { - WARN_FUNC("special: can't find orig instruction", - special_alt->orig_sec, special_alt->orig_off); - ret =3D -1; - goto out; - } + if (!orig_insn) + ERROR_FUNC(special_alt->orig_sec, special_alt->orig_off, + "special: can't find orig instruction"); =20 new_insn =3D NULL; if (!special_alt->group || special_alt->new_len) { new_insn =3D find_insn(file, special_alt->new_sec, special_alt->new_off); - if (!new_insn) { - WARN_FUNC("special: can't find new instruction", - special_alt->new_sec, - special_alt->new_off); - ret =3D -1; - goto out; - } + if (!new_insn) + ERROR_FUNC(special_alt->new_sec, special_alt->new_off, + "special: can't find new instruction"); } =20 if (special_alt->group) { - if (!special_alt->orig_len) { - WARN_INSN(orig_insn, "empty alternative entry"); - continue; - } + if (!special_alt->orig_len) + ERROR_INSN(orig_insn, "empty alternative entry"); =20 - ret =3D handle_group_alt(file, special_alt, orig_insn, - &new_insn); - if (ret) - goto out; + handle_group_alt(file, special_alt, orig_insn, &new_insn); } else if (special_alt->jump_or_nop) { - ret =3D handle_jump_alt(file, special_alt, orig_insn, - &new_insn); - if (ret) - goto out; + handle_jump_alt(file, special_alt, orig_insn, &new_insn); } =20 alt =3D malloc(sizeof(*alt)); - if (!alt) { - WARN("malloc failed"); - ret =3D -1; - goto out; - } + ERROR_ON(!alt, "malloc"); =20 alt->insn =3D new_insn; alt->skip_orig =3D special_alt->skip_orig; @@ -1983,13 +1854,10 @@ static int add_special_section_alts(struct objtool_= file *file) printf("short:\t%ld\t%ld\n", file->jl_nop_short, file->jl_short); printf("long:\t%ld\t%ld\n", file->jl_nop_long, file->jl_long); } - -out: - return ret; } =20 -static int add_jump_table(struct objtool_file *file, struct instruction *i= nsn, - struct reloc *next_table) +static void add_jump_table(struct objtool_file *file, struct instruction *= insn, + struct reloc *next_table) { struct symbol *pfunc =3D insn_func(insn)->pfunc; struct reloc *table =3D insn_jump_table(insn); @@ -2026,10 +1894,7 @@ static int add_jump_table(struct objtool_file *file,= struct instruction *insn, break; =20 alt =3D malloc(sizeof(*alt)); - if (!alt) { - WARN("malloc failed"); - return -1; - } + ERROR_ON(!alt, "malloc"); =20 alt->insn =3D dest_insn; alt->next =3D insn->alts; @@ -2037,12 +1902,8 @@ static int add_jump_table(struct objtool_file *file,= struct instruction *insn, prev_offset =3D reloc_offset(reloc); } =20 - if (!prev_offset) { - WARN_INSN(insn, "can't find switch jump table"); - return -1; - } - - return 0; + if (!prev_offset) + ERROR_INSN(insn, "can't find switch jump table"); } =20 /* @@ -2125,11 +1986,10 @@ static void mark_func_jump_tables(struct objtool_fi= le *file, } } =20 -static int add_func_jump_tables(struct objtool_file *file, +static void add_func_jump_tables(struct objtool_file *file, struct symbol *func) { struct instruction *insn, *insn_t1 =3D NULL, *insn_t2; - int ret =3D 0; =20 func_for_each_insn(file, func, insn) { if (!insn_jump_table(insn)) @@ -2142,17 +2002,13 @@ static int add_func_jump_tables(struct objtool_file= *file, =20 insn_t2 =3D insn; =20 - ret =3D add_jump_table(file, insn_t1, insn_jump_table(insn_t2)); - if (ret) - return ret; + add_jump_table(file, insn_t1, insn_jump_table(insn_t2)); =20 insn_t1 =3D insn_t2; } =20 if (insn_t1) - ret =3D add_jump_table(file, insn_t1, NULL); - - return ret; + add_jump_table(file, insn_t1, NULL); } =20 /* @@ -2160,25 +2016,20 @@ static int add_func_jump_tables(struct objtool_file= *file, * section which contains a list of addresses within the function to jump = to. * This finds these jump tables and adds them to the insn->alts lists. */ -static int add_jump_table_alts(struct objtool_file *file) +static void add_jump_table_alts(struct objtool_file *file) { struct symbol *func; - int ret; =20 if (!file->rodata) - return 0; + return; =20 for_each_sym(file->elf, func) { if (!is_function_symbol(func)) continue; =20 mark_func_jump_tables(file, func); - ret =3D add_func_jump_tables(file, func); - if (ret) - return ret; + add_func_jump_tables(file, func); } - - return 0; } =20 static void set_func_state(struct cfi_state *state) @@ -2190,7 +2041,7 @@ static void set_func_state(struct cfi_state *state) state->type =3D UNWIND_HINT_TYPE_CALL; } =20 -static int read_unwind_hints(struct objtool_file *file) +static void read_unwind_hints(struct objtool_file *file) { struct cfi_state cfi =3D init_cfi; struct section *sec; @@ -2202,17 +2053,13 @@ static int read_unwind_hints(struct objtool_file *f= ile) =20 sec =3D find_section_by_name(file->elf, ".discard.unwind_hints"); if (!sec) - return 0; + return; =20 - if (!sec->rsec) { - WARN("missing .rela.discard.unwind_hints section"); - return -1; - } + if (!sec->rsec) + ERROR("missing .rela.discard.unwind_hints section"); =20 - if (sec_size(sec) % sizeof(struct unwind_hint)) { - WARN("struct unwind_hint size mismatch"); - return -1; - } + if (sec_size(sec) % sizeof(struct unwind_hint)) + ERROR("struct unwind_hint size mismatch"); =20 file->hints =3D true; =20 @@ -2220,17 +2067,13 @@ static int read_unwind_hints(struct objtool_file *f= ile) hint =3D (struct unwind_hint *)sec->data->d_buf + i; =20 reloc =3D find_reloc_by_dest(file->elf, sec, i * sizeof(*hint)); - if (!reloc) { - WARN("can't find reloc for unwind_hints[%d]", i); - return -1; - } + if (!reloc) + ERROR("can't find reloc for unwind_hints[%d]", i); =20 offset =3D reloc->sym->offset + reloc_addend(reloc); insn =3D find_insn(file, reloc->sym->sec, offset); - if (!insn) { - WARN("can't find insn for unwind_hints[%d]", i); - return -1; - } + if (!insn) + ERROR("can't find insn for unwind_hints[%d]", i); =20 insn->hint =3D true; =20 @@ -2253,11 +2096,9 @@ static int read_unwind_hints(struct objtool_file *fi= le) if (hint->type =3D=3D UNWIND_HINT_TYPE_REGS_PARTIAL) { struct symbol *sym =3D find_symbol_by_offset(insn->sec, insn->offset); =20 - if (sym && is_global_symbol(sym)) { - if (opts.ibt && insn->type !=3D INSN_ENDBR && !insn->noendbr) { - WARN_INSN(insn, "UNWIND_HINT_IRET_REGS without ENDBR"); - } - } + if (opts.ibt && sym && is_global_symbol(sym) && + insn->type !=3D INSN_ENDBR && !insn->noendbr) + ERROR_INSN(insn, "UNWIND_HINT_IRET_REGS without ENDBR"); } =20 if (hint->type =3D=3D UNWIND_HINT_TYPE_FUNC) { @@ -2268,10 +2109,8 @@ static int read_unwind_hints(struct objtool_file *fi= le) if (insn->cfi) cfi =3D *(insn->cfi); =20 - if (arch_decode_hint_reg(hint->sp_reg, &cfi.cfa.base)) { - WARN_INSN(insn, "unsupported unwind_hint sp base reg %d", hint->sp_reg); - return -1; - } + if (arch_decode_hint_reg(hint->sp_reg, &cfi.cfa.base)) + ERROR_INSN(insn, "unsupported unwind_hint sp base reg %d", hint->sp_reg= ); =20 cfi.cfa.offset =3D bswap_if_needed(file->elf, hint->sp_offset); cfi.type =3D hint->type; @@ -2279,11 +2118,9 @@ static int read_unwind_hints(struct objtool_file *fi= le) =20 insn->cfi =3D cfi_hash_find_or_add(&cfi); } - - return 0; } =20 -static int read_noendbr_hints(struct objtool_file *file) +static void read_noendbr_hints(struct objtool_file *file) { struct instruction *insn; struct section *rsec; @@ -2291,23 +2128,19 @@ static int read_noendbr_hints(struct objtool_file *= file) =20 rsec =3D find_section_by_name(file->elf, ".rela.discard.noendbr"); if (!rsec) - return 0; + return; =20 for_each_reloc(rsec, reloc) { insn =3D find_insn(file, reloc->sym->sec, reloc->sym->offset + reloc_addend(reloc)); - if (!insn) { - WARN("bad .discard.noendbr entry"); - return -1; - } + if (!insn) + ERROR("bad .discard.noendbr entry"); =20 insn->noendbr =3D 1; } - - return 0; } =20 -static int read_retpoline_hints(struct objtool_file *file) +static void read_retpoline_hints(struct objtool_file *file) { struct section *rsec; struct instruction *insn; @@ -2315,32 +2148,26 @@ static int read_retpoline_hints(struct objtool_file= *file) =20 rsec =3D find_section_by_name(file->elf, ".rela.discard.retpoline_safe"); if (!rsec) - return 0; + return; =20 for_each_reloc(rsec, reloc) { unsigned long offset =3D reloc->sym->offset + reloc_addend(reloc); =20 insn =3D find_insn(file, reloc->sym->sec, offset); - if (!insn) { - WARN("bad .discard.retpoline_safe entry"); - return -1; - } + if (!insn) + ERROR("bad .discard.retpoline_safe entry"); =20 if (insn->type !=3D INSN_JUMP_DYNAMIC && insn->type !=3D INSN_CALL_DYNAMIC && insn->type !=3D INSN_RETURN && - insn->type !=3D INSN_NOP) { - WARN_INSN(insn, "retpoline_safe hint not an indirect jump/call/ret/nop"= ); - return -1; - } + insn->type !=3D INSN_NOP) + ERROR_INSN(insn, "retpoline_safe hint not an indirect jump/call/ret/nop= "); =20 insn->retpoline_safe =3D true; } - - return 0; } =20 -static int read_instr_hints(struct objtool_file *file) +static void read_instr_hints(struct objtool_file *file) { struct section *rsec; struct instruction *insn; @@ -2348,40 +2175,34 @@ static int read_instr_hints(struct objtool_file *fi= le) =20 rsec =3D find_section_by_name(file->elf, ".rela.discard.instr_end"); if (!rsec) - return 0; + return; =20 for_each_reloc(rsec, reloc) { unsigned long offset =3D reloc->sym->offset + reloc_addend(reloc); =20 insn =3D find_insn(file, reloc->sym->sec, offset); - if (!insn) { - WARN("bad .discard.instr_end entry"); - return -1; - } + if (!insn) + ERROR("bad .discard.instr_end entry"); =20 insn->instr--; } =20 rsec =3D find_section_by_name(file->elf, ".rela.discard.instr_begin"); if (!rsec) - return 0; + ERROR("missing instr_begin section"); =20 for_each_reloc(rsec, reloc) { unsigned long offset =3D reloc->sym->offset + reloc_addend(reloc); =20 insn =3D find_insn(file, reloc->sym->sec, offset); - if (!insn) { - WARN("bad .discard.instr_begin entry"); - return -1; - } + if (!insn) + ERROR("bad .discard.instr_begin entry"); =20 insn->instr++; } - - return 0; } =20 -static int read_validate_unret_hints(struct objtool_file *file) +static void read_validate_unret_hints(struct objtool_file *file) { struct section *rsec; struct instruction *insn; @@ -2389,24 +2210,21 @@ static int read_validate_unret_hints(struct objtool= _file *file) =20 rsec =3D find_section_by_name(file->elf, ".rela.discard.validate_unret"); if (!rsec) - return 0; + return; =20 for_each_reloc(rsec, reloc) { unsigned long offset =3D reloc->sym->offset + reloc_addend(reloc); =20 insn =3D find_insn(file, reloc->sym->sec, offset); - if (!insn) { - WARN("bad .discard.instr_end entry"); - return -1; - } + if (!insn) + ERROR("bad .discard.instr_end entry"); + insn->unret =3D 1; } - - return 0; } =20 =20 -static int read_intra_function_calls(struct objtool_file *file) +static void read_intra_function_calls(struct objtool_file *file) { struct instruction *insn; struct section *rsec; @@ -2414,22 +2232,18 @@ static int read_intra_function_calls(struct objtool= _file *file) =20 rsec =3D find_section_by_name(file->elf, ".rela.discard.intra_function_ca= lls"); if (!rsec) - return 0; + return; =20 for_each_reloc(rsec, reloc) { unsigned long dest_off; unsigned long offset =3D reloc->sym->offset + reloc_addend(reloc); =20 insn =3D find_insn(file, reloc->sym->sec, offset); - if (!insn) { - WARN("bad .discard.intra_function_call entry"); - return -1; - } + if (!insn) + ERROR("bad .discard.intra_function_call entry"); =20 - if (insn->type !=3D INSN_CALL) { - WARN_INSN(insn, "intra_function_call not a direct call"); - return -1; - } + if (insn->type !=3D INSN_CALL) + ERROR_INSN(insn, "intra_function_call not a direct call"); =20 /* * Treat intra-function CALLs as JMPs, but with a stack_op. @@ -2440,14 +2254,10 @@ static int read_intra_function_calls(struct objtool= _file *file) =20 dest_off =3D arch_jump_destination(insn); insn->jump_dest =3D find_insn(file, insn->sec, dest_off); - if (!insn->jump_dest) { - WARN_INSN(insn, "can't find call dest at %s+0x%lx", - insn->sec->name, dest_off); - return -1; - } + if (!insn->jump_dest) + ERROR_INSN(insn, "can't find call dest at %s+0x%lx", + insn->sec->name, dest_off); } - - return 0; } =20 /* @@ -2475,7 +2285,7 @@ static bool is_profiling_func(const char *name) return false; } =20 -static int classify_symbols(struct objtool_file *file) +static void classify_symbols(struct objtool_file *file) { struct symbol *func; =20 @@ -2505,8 +2315,6 @@ static int classify_symbols(struct objtool_file *file) if (is_profiling_func(func->name)) func->profiling_func =3D true; } - - return 0; } =20 static void mark_rodata(struct objtool_file *file) @@ -2535,96 +2343,62 @@ static void mark_rodata(struct objtool_file *file) file->rodata =3D found; } =20 -static int decode_sections(struct objtool_file *file) +static void decode_sections(struct objtool_file *file) { - int ret; - mark_rodata(file); =20 - ret =3D init_pv_ops(file); - if (ret) - return ret; + init_pv_ops(file); =20 /* * Must be before add_{jump_call}_destination. */ - ret =3D classify_symbols(file); - if (ret) - return ret; + classify_symbols(file); =20 - ret =3D decode_instructions(file); - if (ret) - return ret; + decode_instructions(file); =20 add_ignores(file); + add_uaccess_safe(file); =20 - ret =3D add_ignore_alternatives(file); - if (ret) - return ret; + add_ignore_alternatives(file); =20 /* * Must be before read_unwind_hints() since that needs insn->noendbr. */ - ret =3D read_noendbr_hints(file); - if (ret) - return ret; + read_noendbr_hints(file); =20 /* * Must be before add_jump_destinations(), which depends on 'func' * being set for alternatives, to enable proper sibling call detection. */ - if (opts.stackval || opts.orc || opts.uaccess || opts.noinstr) { - ret =3D add_special_section_alts(file); - if (ret) - return ret; - } + if (opts.stackval || opts.orc || opts.uaccess || opts.noinstr) + add_special_section_alts(file); =20 - ret =3D add_jump_destinations(file); - if (ret) - return ret; + add_jump_destinations(file); =20 /* * Must be before add_call_destination(); it changes INSN_CALL to * INSN_JUMP. */ - ret =3D read_intra_function_calls(file); - if (ret) - return ret; + read_intra_function_calls(file); =20 - ret =3D add_call_destinations(file); - if (ret) - return ret; + add_call_destinations(file); =20 /* * Must be after add_call_destinations() such that it can override * dead_end_function() marks. */ - ret =3D add_dead_ends(file); - if (ret) - return ret; + add_dead_ends(file); =20 - ret =3D add_jump_table_alts(file); - if (ret) - return ret; + add_jump_table_alts(file); =20 - ret =3D read_unwind_hints(file); - if (ret) - return ret; + read_unwind_hints(file); =20 - ret =3D read_retpoline_hints(file); - if (ret) - return ret; + read_retpoline_hints(file); =20 - ret =3D read_instr_hints(file); - if (ret) - return ret; + read_instr_hints(file); =20 - ret =3D read_validate_unret_hints(file); - if (ret) - return ret; - - return 0; + read_validate_unret_hints(file); } =20 static bool is_special_call(struct instruction *insn) @@ -3082,8 +2856,7 @@ static int update_cfi_state(struct instruction *insn, break; =20 default: - WARN_INSN(insn, "unknown stack-related instruction"); - return -1; + ERROR_INSN(insn, "unknown stack-related instruction"); } =20 break; @@ -3170,10 +2943,8 @@ static int update_cfi_state(struct instruction *insn, break; =20 case OP_DEST_MEM: - if (op->src.type !=3D OP_SRC_POP && op->src.type !=3D OP_SRC_POPF) { - WARN_INSN(insn, "unknown stack-related memory operation"); - return -1; - } + if (op->src.type !=3D OP_SRC_POP && op->src.type !=3D OP_SRC_POPF) + ERROR_INSN(insn, "unknown stack-related memory operation"); =20 /* pop mem */ cfi->stack_size -=3D 8; @@ -3183,8 +2954,7 @@ static int update_cfi_state(struct instruction *insn, break; =20 default: - WARN_INSN(insn, "unknown stack-related instruction"); - return -1; + ERROR_INSN(insn, "unknown stack-related instruction"); } =20 return 0; @@ -3207,25 +2977,20 @@ static int propagate_alt_cfi(struct objtool_file *f= ile, struct instruction *insn if (!insn->alt_group) return 0; =20 - if (!insn->cfi) { - WARN("CFI missing"); - return -1; - } + if (!insn->cfi) + ERROR("CFI missing"); =20 alt_cfi =3D insn->alt_group->cfi; group_off =3D insn->offset - insn->alt_group->first_insn->offset; =20 if (!alt_cfi[group_off]) { alt_cfi[group_off] =3D insn->cfi; - } else { - if (cficmp(alt_cfi[group_off], insn->cfi)) { - struct alt_group *orig_group =3D insn->alt_group->orig_group ?: insn->a= lt_group; - struct instruction *orig =3D orig_group->first_insn; - char *where =3D offstr(insn->sec, insn->offset); - WARN_INSN(orig, "stack layout conflict in alternatives: %s", where); - free(where); - return -1; - } + + } else if (cficmp(alt_cfi[group_off], insn->cfi)) { + struct alt_group *orig_group =3D insn->alt_group->orig_group ?: insn->al= t_group; + struct instruction *orig =3D orig_group->first_insn; + char *where =3D offstr(insn->sec, insn->offset); + ERROR_INSN(orig, "stack layout conflict in alternatives: %s", where); } =20 return 0; @@ -3274,16 +3039,15 @@ static bool insn_cfi_match(struct instruction *insn= , struct cfi_state *cfi2) struct cfi_state *cfi1 =3D insn->cfi; int i; =20 - if (!cfi1) { - WARN("CFI missing"); - return false; - } + if (!cfi1) + ERROR("CFI missing"); =20 if (memcmp(&cfi1->cfa, &cfi2->cfa, sizeof(cfi1->cfa))) { =20 WARN_INSN(insn, "stack state mismatch: cfa1=3D%d%+d cfa2=3D%d%+d", cfi1->cfa.base, cfi1->cfa.offset, cfi2->cfa.base, cfi2->cfa.offset); + return false; =20 } else if (memcmp(&cfi1->regs, &cfi2->regs, sizeof(cfi1->regs))) { for (i =3D 0; i < CFI_NUM_REGS; i++) { @@ -3294,13 +3058,14 @@ static bool insn_cfi_match(struct instruction *insn= , struct cfi_state *cfi2) WARN_INSN(insn, "stack state mismatch: reg1[%d]=3D%d%+d reg2[%d]=3D%d%+= d", i, cfi1->regs[i].base, cfi1->regs[i].offset, i, cfi2->regs[i].base, cfi2->regs[i].offset); - break; + return false; } =20 } else if (cfi1->type !=3D cfi2->type) { =20 WARN_INSN(insn, "stack state mismatch: type1=3D%d type2=3D%d", cfi1->type, cfi2->type); + return false; =20 } else if (cfi1->drap !=3D cfi2->drap || (cfi1->drap && cfi1->drap_reg !=3D cfi2->drap_reg) || @@ -3309,6 +3074,7 @@ static bool insn_cfi_match(struct instruction *insn, = struct cfi_state *cfi2) WARN_INSN(insn, "stack state mismatch: drap1=3D%d(%d,%d) drap2=3D%d(%d,%= d)", cfi1->drap, cfi1->drap_reg, cfi1->drap_offset, cfi2->drap, cfi2->drap_reg, cfi2->drap_offset); + return false; =20 } else return true; @@ -3361,10 +3127,8 @@ static bool pv_call_dest(struct objtool_file *file, = struct instruction *insn) file->pv_ops[idx].clean =3D true; =20 list_for_each_entry(target, &file->pv_ops[idx].targets, pv_target) { - if (!target->sec->noinstr) { - WARN("pv_ops[%d]: %s", idx, target->name); - file->pv_ops[idx].clean =3D false; - } + if (!target->sec->noinstr) + ERROR("pv_ops[%d]: %s", idx, target->name); } =20 return file->pv_ops[idx].clean; @@ -4090,14 +3854,14 @@ static bool ignore_unreachable_insn(struct objtool_= file *file, struct instructio return false; } =20 -static int add_prefix_symbol(struct objtool_file *file, struct symbol *fun= c) +static void add_prefix_symbol(struct objtool_file *file, struct symbol *fu= nc) { struct instruction *insn, *prev; struct cfi_state *cfi; =20 insn =3D find_insn(file, func->sec, func->offset); if (!insn) - return -1; + ERROR("%s(): can't find starting insn", func->name); =20 for (prev =3D prev_insn_same_sec(file, insn); prev; @@ -4105,40 +3869,39 @@ static int add_prefix_symbol(struct objtool_file *f= ile, struct symbol *func) u64 offset; =20 if (prev->type !=3D INSN_NOP) - return -1; + return; =20 offset =3D func->offset - prev->offset; =20 if (offset > opts.prefix) - return -1; + return; =20 if (offset < opts.prefix) continue; =20 elf_create_prefix_symbol(file->elf, func, opts.prefix); + break; } =20 if (!prev) - return -1; + return; =20 if (!insn->cfi) { /* * This can happen if stack validation isn't enabled or the * function is annotated with STACK_FRAME_NON_STANDARD. */ - return 0; + return; } =20 /* Propagate insn->cfi to the prefix code */ cfi =3D cfi_hash_find_or_add(insn->cfi); for (; prev !=3D insn; prev =3D next_insn_same_sec(file, prev)) prev->cfi =3D cfi; - - return 0; } =20 -static int add_prefix_symbols(struct objtool_file *file) +static void add_prefix_symbols(struct objtool_file *file) { struct section *sec; struct symbol *func; @@ -4154,8 +3917,6 @@ static int add_prefix_symbols(struct objtool_file *fi= le) add_prefix_symbol(file, func); } } - - return 0; } =20 static int validate_symbol(struct objtool_file *file, struct section *sec, @@ -4381,9 +4142,8 @@ static int validate_ibt_data_reloc(struct objtool_fil= e *file, if (dest->noendbr) return 0; =20 - WARN_FUNC("data relocation to !ENDBR: %s", - reloc->sec->base, reloc_offset(reloc), - offstr(dest->sec, dest->offset)); + WARN_FUNC(reloc->sec->base, reloc_offset(reloc), + "data relocation to !ENDBR: %s", offstr(dest->sec, dest->offset)); =20 return 1; } @@ -4536,7 +4296,7 @@ static int validate_reachable_instructions(struct obj= tool_file *file) } =20 /* 'funcs' is a space-separated list of function names */ -static int disas_funcs(const char *funcs) +static void disas_funcs(const char *funcs) { const char *objdump_str, *cross_compile; int size, ret; @@ -4567,22 +4327,16 @@ static int disas_funcs(const char *funcs) =20 /* fake snprintf() to calculate the size */ size =3D snprintf(NULL, 0, objdump_str, cross_compile, Objname, funcs) + = 1; - if (size <=3D 0) { - WARN("objdump string size calculation failed"); - return -1; - } + if (size <=3D 0) + ERROR("objdump string size calculation failed"); =20 cmd =3D malloc(size); =20 /* real snprintf() */ snprintf(cmd, size, objdump_str, cross_compile, Objname, funcs); ret =3D system(cmd); - if (ret) { - WARN("disassembly failed: %d", ret); - return -1; - } - - return 0; + if (ret) + ERROR("disassembly failed: %d", ret); } =20 static int disas_warned_funcs(struct objtool_file *file) @@ -4640,7 +4394,7 @@ static void free_insns(struct objtool_file *file) =20 int check(struct objtool_file *file) { - int ret, warnings =3D 0; + int ret =3D 0, warnings =3D 0; =20 arch_initial_func_cfi_state(&initial_func_cfi); init_cfi_state(&init_cfi); @@ -4649,17 +4403,12 @@ int check(struct objtool_file *file) init_cfi_state(&force_undefined_cfi); force_undefined_cfi.force_undefined =3D true; =20 - if (!cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3))) - goto out; + cfi_hash_alloc(1UL << (file->elf->symbol_bits - 3)); =20 cfi_hash_add(&init_cfi); cfi_hash_add(&func_cfi); =20 - ret =3D decode_sections(file); - if (ret < 0) - goto out; - - warnings +=3D ret; + decode_sections(file); =20 if (!nr_insns) goto out; @@ -4721,61 +4470,30 @@ int check(struct objtool_file *file) warnings +=3D ret; } =20 - if (opts.static_call) { - ret =3D create_static_call_sections(file); - if (ret < 0) - goto out; - warnings +=3D ret; - } + if (opts.static_call) + create_static_call_sections(file); =20 - if (opts.retpoline) { - ret =3D create_retpoline_sites_sections(file); - if (ret < 0) - goto out; - warnings +=3D ret; - } + if (opts.retpoline) + create_retpoline_sites_sections(file); =20 - if (opts.cfi) { - ret =3D create_cfi_sections(file); - if (ret < 0) - goto out; - warnings +=3D ret; - } + if (opts.cfi) + create_cfi_sections(file); =20 if (opts.rethunk) { - ret =3D create_return_sites_sections(file); - if (ret < 0) - goto out; - warnings +=3D ret; + create_return_sites_sections(file); =20 - if (opts.hack_skylake) { - ret =3D create_direct_call_sections(file); - if (ret < 0) - goto out; - warnings +=3D ret; - } + if (opts.hack_skylake) + create_direct_call_sections(file); } =20 - if (opts.mcount) { - ret =3D create_mcount_loc_sections(file); - if (ret < 0) - goto out; - warnings +=3D ret; - } + if (opts.mcount) + create_mcount_loc_sections(file); =20 - if (opts.prefix) { - ret =3D add_prefix_symbols(file); - if (ret < 0) - return ret; - warnings +=3D ret; - } + if (opts.prefix) + add_prefix_symbols(file); =20 - if (opts.ibt) { - ret =3D create_ibt_endbr_seal_sections(file); - if (ret < 0) - goto out; - warnings +=3D ret; - } + if (opts.ibt) + create_ibt_endbr_seal_sections(file); =20 if (opts.orc && nr_insns) { ret =3D orc_create(file); diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index fc76692ced2c..84cb6fc235c9 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -72,17 +72,17 @@ static inline void __elf_hash_del(struct elf_hash_node = *node, obj; \ obj =3D elf_list_entry(obj->member.next, typeof(*(obj)), member)) =20 -#define elf_alloc_hash(name, size) \ -({ \ - __elf_bits(name) =3D max(10, ilog2(size)); \ - __elf_table(name) =3D mmap(NULL, sizeof(struct elf_hash_node *) << __elf_= bits(name), \ - PROT_READ|PROT_WRITE, \ - MAP_PRIVATE|MAP_ANON, -1, 0); \ - if (__elf_table(name) =3D=3D (void *)-1L) { \ - WARN("mmap fail " #name); \ - __elf_table(name) =3D NULL; \ - } \ - __elf_table(name); \ +#define elf_alloc_hash(name, size) \ +({ \ + __elf_bits(name) =3D max(10, ilog2(size)); \ + __elf_table(name) =3D mmap(NULL, \ + sizeof(struct elf_hash_node *) << __elf_bits(name), \ + PROT_READ|PROT_WRITE, \ + MAP_PRIVATE|MAP_ANON, -1, 0); \ + if (__elf_table(name) =3D=3D (void *)-1L) \ + ERROR("mmap fail " #name); \ + \ + __elf_table(name); \ }) =20 static inline unsigned long __sym_start(struct symbol *s) @@ -301,68 +301,53 @@ static bool is_dwarf_section(struct section *sec) return !strncmp(sec->name, ".debug_", 7); } =20 -static int read_sections(struct elf *elf) +static void read_sections(struct elf *elf) { Elf_Scn *s =3D NULL; struct section *sec; size_t shstrndx, sections_nr; int i; =20 - if (elf_getshdrnum(elf->elf, §ions_nr)) { - WARN_ELF("elf_getshdrnum"); - return -1; - } + if (elf_getshdrnum(elf->elf, §ions_nr)) + ERROR_ELF("elf_getshdrnum"); =20 - if (elf_getshdrstrndx(elf->elf, &shstrndx)) { - WARN_ELF("elf_getshdrstrndx"); - return -1; - } + if (elf_getshdrstrndx(elf->elf, &shstrndx)) + ERROR_ELF("elf_getshdrstrndx"); =20 - if (!elf_alloc_hash(section, sections_nr) || - !elf_alloc_hash(section_name, sections_nr)) - return -1; + elf_alloc_hash(section, sections_nr); + elf_alloc_hash(section_name, sections_nr); =20 elf->section_data =3D calloc(sections_nr, sizeof(*sec)); - if (!elf->section_data) { - perror("calloc"); - return -1; - } + ERROR_ON(!elf->section_data, "calloc"); + for (i =3D 0; i < sections_nr; i++) { sec =3D &elf->section_data[i]; =20 INIT_LIST_HEAD(&sec->symbol_list); =20 s =3D elf_getscn(elf->elf, i); - if (!s) { - WARN_ELF("elf_getscn"); - return -1; - } + if (!s) + ERROR_ELF("elf_getscn"); =20 sec->idx =3D elf_ndxscn(s); =20 - if (!gelf_getshdr(s, &sec->sh)) { - WARN_ELF("gelf_getshdr"); - return -1; - } + if (!gelf_getshdr(s, &sec->sh)) + ERROR_ELF("gelf_getshdr"); + + sec->name =3D elf_strptr(elf->elf, shstrndx, sec->sh.sh_name); + if (!sec->name) + ERROR_ELF("elf_strptr"); =20 sec->name =3D elf_strptr(elf->elf, shstrndx, sec->sh.sh_name); - if (!sec->name) { - WARN_ELF("elf_strptr"); - return -1; - } =20 if (sec_size(sec) !=3D 0 && !is_dwarf_section(sec)) { sec->data =3D elf_getdata(s, NULL); - if (!sec->data) { - WARN_ELF("elf_getdata"); - return -1; - } + if (!sec->data) + ERROR_ELF("elf_getdata"); + if (sec->data->d_off !=3D 0 || - sec->data->d_size !=3D sec_size(sec)) { - WARN("unexpected data attributes for %s", - sec->name); - return -1; - } + sec->data->d_size !=3D sec_size(sec)) + ERROR("unexpected data attributes for %s", sec->name); } =20 list_add_tail(&sec->list, &elf->sections); @@ -379,12 +364,8 @@ static int read_sections(struct elf *elf) } =20 /* sanity check, one more call to elf_nextscn() should return NULL */ - if (elf_nextscn(elf->elf, s)) { - WARN("section entry mismatch"); - return -1; - } - - return 0; + if (elf_nextscn(elf->elf, s)) + ERROR("section entry mismatch"); } =20 static void elf_add_symbol(struct elf *elf, struct symbol *sym) @@ -428,7 +409,7 @@ static void elf_add_symbol(struct elf *elf, struct symb= ol *sym) __sym_remove(sym, &sym->sec->symbol_tree); } =20 -static int read_symbols(struct elf *elf) +static void read_symbols(struct elf *elf) { struct section *symtab, *symtab_shndx, *sec; struct symbol *sym, *pfunc; @@ -454,32 +435,24 @@ static int read_symbols(struct elf *elf) symbols_nr =3D 0; } =20 - if (!elf_alloc_hash(symbol, symbols_nr) || - !elf_alloc_hash(symbol_name, symbols_nr)) - return -1; + elf_alloc_hash(symbol, symbols_nr); + elf_alloc_hash(symbol_name, symbols_nr); =20 elf->symbol_data =3D calloc(symbols_nr, sizeof(*sym)); - if (!elf->symbol_data) { - perror("calloc"); - return -1; - } + ERROR_ON(!elf->symbol_data, "calloc"); + for (i =3D 0; i < symbols_nr; i++) { sym =3D &elf->symbol_data[i]; =20 sym->idx =3D i; =20 - if (!gelf_getsymshndx(symtab->data, shndx_data, i, &sym->sym, - &shndx)) { - WARN_ELF("gelf_getsymshndx"); - goto err; - } + if (!gelf_getsymshndx(symtab->data, shndx_data, i, &sym->sym, &shndx)) + ERROR_ELF("gelf_getsymshndx"); =20 sym->name =3D elf_strptr(elf->elf, symtab->sh.sh_link, sym->sym.st_name); - if (!sym->name) { - WARN_ELF("elf_strptr"); - goto err; - } + if (!sym->name) + ERROR_ELF("elf_strptr"); =20 if ((sym->sym.st_shndx > SHN_UNDEF && sym->sym.st_shndx < SHN_LORESERVE) || @@ -488,11 +461,9 @@ static int read_symbols(struct elf *elf) shndx =3D sym->sym.st_shndx; =20 sym->sec =3D find_section_by_index(elf, shndx); - if (!sym->sec) { - WARN("couldn't find section for symbol %s", - sym->name); - goto err; - } + if (!sym->sec) + ERROR("couldn't find section for symbol %s", sym->name); + if (GELF_ST_TYPE(sym->sym.st_info) =3D=3D STT_SECTION) { sym->name =3D sym->sec->name; sym->sec->sym =3D sym; @@ -528,20 +499,13 @@ static int read_symbols(struct elf *elf) =20 pnamelen =3D coldstr - sym->name; pname =3D strndup(sym->name, pnamelen); - if (!pname) { - WARN("%s(): failed to allocate memory", - sym->name); - return -1; - } + ERROR_ON(!pname, "strndup"); =20 pfunc =3D find_symbol_by_name(elf, pname); - free(pname); + if (!pfunc) + ERROR("%s(): can't find parent function", sym->name); =20 - if (!pfunc) { - WARN("%s(): can't find parent function", - sym->name); - return -1; - } + free(pname); =20 sym->pfunc =3D pfunc; pfunc->cfunc =3D sym; @@ -561,25 +525,17 @@ static int read_symbols(struct elf *elf) } } } - - return 0; - -err: - free(sym); - return -1; } =20 /* * @sym's idx has changed. Update the relocs which reference it. */ -static int elf_update_sym_relocs(struct elf *elf, struct symbol *sym) +static void elf_update_sym_relocs(struct elf *elf, struct symbol *sym) { struct reloc *reloc; =20 for (reloc =3D sym->relocs; reloc; reloc =3D reloc->sym_next_reloc) set_reloc_sym(elf, reloc, reloc->sym->idx); - - return 0; } =20 /* @@ -590,7 +546,7 @@ static int elf_update_sym_relocs(struct elf *elf, struc= t symbol *sym) * If no data block is found, allow adding a new data block provided the i= ndex * is only one past the end. */ -static int elf_update_symbol(struct elf *elf, struct section *symtab, +static void elf_update_symbol(struct elf *elf, struct section *symtab, struct section *symtab_shndx, struct symbol *sym) { Elf32_Word shndx =3D sym->sec ? sym->sec->idx : SHN_UNDEF; @@ -605,17 +561,13 @@ static int elf_update_symbol(struct elf *elf, struct = section *symtab, shndx =3D sym->sym.st_shndx; =20 s =3D elf_getscn(elf->elf, symtab->idx); - if (!s) { - WARN_ELF("elf_getscn"); - return -1; - } + if (!s) + ERROR_ELF("elf_getscn"); =20 if (symtab_shndx) { t =3D elf_getscn(elf->elf, symtab_shndx->idx); - if (!t) { - WARN_ELF("elf_getscn"); - return -1; - } + if (!t) + ERROR_ELF("elf_getscn"); } =20 for (;;) { @@ -634,11 +586,9 @@ static int elf_update_symbol(struct elf *elf, struct s= ection *symtab, int num =3D max(1U, sym->idx/3); void *buf; =20 - if (idx) { - /* we don't do holes in symbol tables */ - WARN("index out of range"); - return -1; - } + /* we don't do holes in symbol tables */ + if (idx) + ERROR("index out of range"); =20 /* if @idx =3D=3D 0, it's the next contiguous entry, create it */ symtab_data =3D elf_newdata(s); @@ -646,10 +596,7 @@ static int elf_update_symbol(struct elf *elf, struct s= ection *symtab, shndx_data =3D elf_newdata(t); =20 buf =3D calloc(num, entsize); - if (!buf) { - WARN("malloc"); - return -1; - } + ERROR_ON(!buf, "calloc"); =20 symtab_data->d_buf =3D buf; symtab_data->d_size =3D num * entsize; @@ -661,10 +608,7 @@ static int elf_update_symbol(struct elf *elf, struct s= ection *symtab, =20 if (t) { buf =3D calloc(num, sizeof(Elf32_Word)); - if (!buf) { - WARN("malloc"); - return -1; - } + ERROR_ON(!buf, "calloc"); =20 shndx_data->d_buf =3D buf; shndx_data->d_size =3D num * sizeof(Elf32_Word); @@ -679,10 +623,8 @@ static int elf_update_symbol(struct elf *elf, struct s= ection *symtab, } =20 /* empty blocks should not happen */ - if (!symtab_data->d_size) { - WARN("zero size data"); - return -1; - } + if (!symtab_data->d_size) + ERROR("zero size data"); =20 /* is this the right block? */ max_idx =3D symtab_data->d_size / entsize; @@ -694,10 +636,8 @@ static int elf_update_symbol(struct elf *elf, struct s= ection *symtab, } =20 /* something went side-ways */ - if (idx < 0) { - WARN("negative index"); - return -1; - } + if (idx < 0) + ERROR("negative index"); =20 /* setup extended section index magic and write the symbol */ if ((shndx >=3D SHN_UNDEF && shndx < SHN_LORESERVE) || is_special_shndx) { @@ -706,18 +646,12 @@ static int elf_update_symbol(struct elf *elf, struct = section *symtab, shndx =3D 0; } else { sym->sym.st_shndx =3D SHN_XINDEX; - if (!shndx_data) { - WARN("no .symtab_shndx"); - return -1; - } + if (!shndx_data) + ERROR("no .symtab_shndx"); } =20 - if (!gelf_update_symshndx(symtab_data, shndx_data, idx, &sym->sym, shndx)= ) { - WARN_ELF("gelf_update_symshndx"); - return -1; - } - - return 0; + if (!gelf_update_symshndx(symtab_data, shndx_data, idx, &sym->sym, shndx)) + ERROR_ELF("gelf_update_symshndx"); } =20 static struct symbol * @@ -728,12 +662,10 @@ __elf_create_symbol(struct elf *elf, struct symbol *s= ym) struct symbol *old; =20 symtab =3D find_section_by_name(elf, ".symtab"); - if (symtab) { - symtab_shndx =3D find_section_by_name(elf, ".symtab_shndx"); - } else { - WARN("no .symtab"); - return NULL; - } + if (!symtab) + ERROR("no symtab"); + + symtab_shndx =3D find_section_by_name(elf, ".symtab_shndx"); =20 new_idx =3D sec_num_entries(symtab); =20 @@ -752,13 +684,9 @@ __elf_create_symbol(struct elf *elf, struct symbol *sy= m) elf_hash_add(symbol, &old->hash, new_idx); old->idx =3D new_idx; =20 - if (elf_update_symbol(elf, symtab, symtab_shndx, old)) { - WARN("elf_update_symbol move"); - return NULL; - } + elf_update_symbol(elf, symtab, symtab_shndx, old); =20 - if (elf_update_sym_relocs(elf, old)) - return NULL; + elf_update_sym_relocs(elf, old); =20 new_idx =3D first_non_local; } @@ -770,10 +698,7 @@ __elf_create_symbol(struct elf *elf, struct symbol *sy= m) =20 non_local: sym->idx =3D new_idx; - if (elf_update_symbol(elf, symtab, symtab_shndx, sym)) { - WARN("elf_update_symbol"); - return NULL; - } + elf_update_symbol(elf, symtab, symtab_shndx, sym); =20 symtab->sh.sh_size +=3D symtab->sh.sh_entsize; mark_sec_changed(elf, symtab, true); @@ -789,12 +714,10 @@ __elf_create_symbol(struct elf *elf, struct symbol *s= ym) static struct symbol * elf_create_section_symbol(struct elf *elf, struct section *sec) { - struct symbol *sym =3D calloc(1, sizeof(*sym)); + struct symbol *sym; =20 - if (!sym) { - perror("malloc"); - return NULL; - } + sym =3D calloc(1, sizeof(*sym)); + ERROR_ON(!sym, "calloc"); =20 sym->name =3D sec->name; sym->sec =3D sec; @@ -806,8 +729,7 @@ elf_create_section_symbol(struct elf *elf, struct secti= on *sec) // st_size 0 =20 sym =3D __elf_create_symbol(elf, sym); - if (sym) - elf_add_symbol(elf, sym); + elf_add_symbol(elf, sym); =20 return sym; } @@ -821,10 +743,7 @@ elf_create_prefix_symbol(struct elf *elf, struct symbo= l *orig, long size) size_t namelen =3D strlen(orig->name) + sizeof("__pfx_"); char *name =3D malloc(namelen); =20 - if (!sym || !name) { - perror("malloc"); - return NULL; - } + ERROR_ON(!sym || !name, "malloc"); =20 snprintf(name, namelen, "__pfx_%s", orig->name); =20 @@ -837,8 +756,7 @@ elf_create_prefix_symbol(struct elf *elf, struct symbol= *orig, long size) sym->sym.st_size =3D size; =20 sym =3D __elf_create_symbol(elf, sym); - if (sym) - elf_add_symbol(elf, sym); + elf_add_symbol(elf, sym); =20 return sym; } @@ -850,19 +768,15 @@ static struct reloc *elf_init_reloc(struct elf *elf, = struct section *rsec, { struct reloc *reloc, empty =3D { 0 }; =20 - if (reloc_idx >=3D sec_num_entries(rsec)) { - WARN("%s: bad reloc_idx %u for %s with %d relocs", - __func__, reloc_idx, rsec->name, sec_num_entries(rsec)); - return NULL; - } + if (reloc_idx >=3D sec_num_entries(rsec)) + ERROR("bad reloc_idx %u for %s with %d relocs", + reloc_idx, rsec->name, sec_num_entries(rsec)); =20 reloc =3D &rsec->relocs[reloc_idx]; =20 - if (memcmp(reloc, &empty, sizeof(empty))) { - WARN("%s: %s: reloc %d already initialized!", - __func__, rsec->name, reloc_idx); - return NULL; - } + if (memcmp(reloc, &empty, sizeof(empty))) + ERROR("%s: reloc %d already initialized!", + rsec->name, reloc_idx); =20 reloc->sec =3D rsec; reloc->sym =3D sym; @@ -880,19 +794,16 @@ static struct reloc *elf_init_reloc(struct elf *elf, = struct section *rsec, } =20 struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec, - unsigned long offset, - unsigned int reloc_idx, - struct section *insn_sec, - unsigned long insn_off) + unsigned long offset, + unsigned int reloc_idx, + struct section *insn_sec, + unsigned long insn_off) { struct symbol *sym =3D insn_sec->sym; int addend =3D insn_off; =20 - if (!is_text_section(insn_sec)) { - WARN("bad call to %s() for data symbol %s", - __func__, sym->name); - return NULL; - } + if (!is_text_section(insn_sec)) + ERROR("bad call to %s() for data symbol %s", __func__, sym->name); =20 if (!sym) { /* @@ -902,8 +813,6 @@ struct reloc *elf_init_reloc_text_sym(struct elf *elf, = struct section *sec, * non-weak function after linking. */ sym =3D elf_create_section_symbol(elf, insn_sec); - if (!sym) - return NULL; =20 insn_sec->sym =3D sym; } @@ -918,17 +827,14 @@ struct reloc *elf_init_reloc_data_sym(struct elf *elf= , struct section *sec, struct symbol *sym, s64 addend) { - if (is_text_section(sec)) { - WARN("bad call to %s() for text symbol %s", - __func__, sym->name); - return NULL; - } + if (is_text_section(sec)) + ERROR("bad call to %s() for text symbol %s", __func__, sym->name); =20 return elf_init_reloc(elf, sec->rsec, reloc_idx, offset, sym, addend, elf_data_rela_type(elf)); } =20 -static int read_relocs(struct elf *elf) +static void read_relocs(struct elf *elf) { unsigned long nr_reloc, max_reloc =3D 0; struct section *rsec; @@ -937,39 +843,31 @@ static int read_relocs(struct elf *elf) struct symbol *sym; int i; =20 - if (!elf_alloc_hash(reloc, elf->num_relocs)) - return -1; + elf_alloc_hash(reloc, elf->num_relocs); =20 list_for_each_entry(rsec, &elf->sections, list) { if (!is_reloc_section(rsec)) continue; =20 rsec->base =3D find_section_by_index(elf, rsec->sh.sh_info); - if (!rsec->base) { - WARN("can't find base section for reloc section %s", - rsec->name); - return -1; - } + if (!rsec->base) + ERROR("can't find base section for reloc section %s", rsec->name); =20 rsec->base->rsec =3D rsec; =20 nr_reloc =3D 0; rsec->relocs =3D calloc(sec_num_entries(rsec), sizeof(*reloc)); - if (!rsec->relocs) { - perror("calloc"); - return -1; - } + ERROR_ON(!rsec->relocs, "calloc"); + for (i =3D 0; i < sec_num_entries(rsec); i++) { reloc =3D &rsec->relocs[i]; =20 reloc->sec =3D rsec; symndx =3D reloc_sym(reloc); reloc->sym =3D sym =3D find_symbol_by_index(elf, symndx); - if (!reloc->sym) { - WARN("can't find reloc entry symbol %d for %s", - symndx, rsec->name); - return -1; - } + if (!reloc->sym) + ERROR("can't find reloc entry symbol %d for %s", + symndx, rsec->name); =20 elf_hash_add(reloc, &reloc->hash, reloc_hash(reloc)); reloc->sym_next_reloc =3D sym->relocs; @@ -985,8 +883,6 @@ static int read_relocs(struct elf *elf) printf("num_relocs: %lu\n", elf->num_relocs); printf("reloc_bits: %d\n", elf->reloc_bits); } - - return 0; } =20 struct elf *elf_open_read(const char *name, int flags) @@ -999,21 +895,13 @@ struct elf *elf_open_read(const char *name, int flags) =20 elf_version(EV_CURRENT); =20 - elf =3D malloc(sizeof(*elf)); - if (!elf) { - perror("malloc"); - return NULL; - } - memset(elf, 0, sizeof(*elf)); + elf =3D calloc(1, sizeof(*elf)); + ERROR_ON(!elf, "calloc"); =20 INIT_LIST_HEAD(&elf->sections); =20 elf->fd =3D open(name, flags); - if (elf->fd =3D=3D -1) { - fprintf(stderr, "objtool: Can't open '%s': %s\n", - name, strerror(errno)); - goto err; - } + ERROR_ON(elf->fd =3D=3D -1, "can't open '%s': %s", name, strerror(errno)); =20 if ((flags & O_ACCMODE) =3D=3D O_RDONLY) cmd =3D ELF_C_READ_MMAP; @@ -1023,30 +911,19 @@ struct elf *elf_open_read(const char *name, int flag= s) cmd =3D ELF_C_WRITE; =20 elf->elf =3D elf_begin(elf->fd, cmd, NULL); - if (!elf->elf) { - WARN_ELF("elf_begin"); - goto err; - } + if (!elf->elf) + ERROR_ELF("elf_begin"); =20 - if (!gelf_getehdr(elf->elf, &elf->ehdr)) { - WARN_ELF("gelf_getehdr"); - goto err; - } + if (!gelf_getehdr(elf->elf, &elf->ehdr)) + ERROR_ELF("gelf_getehdr"); =20 - if (read_sections(elf)) - goto err; + read_sections(elf); =20 - if (read_symbols(elf)) - goto err; + read_symbols(elf); =20 - if (read_relocs(elf)) - goto err; + read_relocs(elf); =20 return elf; - -err: - elf_close(elf); - return NULL; } =20 static int elf_add_string(struct elf *elf, struct section *strtab, const c= har *str) @@ -1055,24 +932,19 @@ static int elf_add_string(struct elf *elf, struct se= ction *strtab, const char *s Elf_Scn *s; int len; =20 - if (!strtab) - strtab =3D find_section_by_name(elf, ".strtab"); if (!strtab) { - WARN("can't find .strtab section"); - return -1; + strtab =3D find_section_by_name(elf, ".strtab"); + if (!strtab) + ERROR("can't find .strtab section"); } =20 s =3D elf_getscn(elf->elf, strtab->idx); - if (!s) { - WARN_ELF("elf_getscn"); - return -1; - } + if (!s) + ERROR_ELF("elf_getscn"); =20 data =3D elf_newdata(s); - if (!data) { - WARN_ELF("elf_newdata"); - return -1; - } + if (!data) + ERROR_ELF("elf_newdata"); =20 data->d_buf =3D strdup(str); data->d_size =3D strlen(str) + 1; @@ -1094,50 +966,34 @@ struct section *elf_create_section(struct elf *elf, = const char *name, Elf_Scn *s; =20 sec =3D malloc(sizeof(*sec)); - if (!sec) { - perror("malloc"); - return NULL; - } + ERROR_ON(!sec, "malloc"); memset(sec, 0, sizeof(*sec)); =20 INIT_LIST_HEAD(&sec->symbol_list); =20 s =3D elf_newscn(elf->elf); - if (!s) { - WARN_ELF("elf_newscn"); - return NULL; - } + if (!s) + ERROR_ELF("elf_newscn"); =20 sec->name =3D strdup(name); - if (!sec->name) { - perror("strdup"); - return NULL; - } + ERROR_ON(!sec->name, "strdup"); =20 sec->idx =3D elf_ndxscn(s); =20 sec->data =3D elf_newdata(s); - if (!sec->data) { - WARN_ELF("elf_newdata"); - return NULL; - } + if (!sec->data) + ERROR_ELF("elf_newdata"); =20 sec->data->d_size =3D size; sec->data->d_align =3D 1; =20 if (size) { - sec->data->d_buf =3D malloc(size); - if (!sec->data->d_buf) { - perror("malloc"); - return NULL; - } - memset(sec->data->d_buf, 0, size); + sec->data->d_buf =3D calloc(1, size); + ERROR_ON(!sec->data->d_buf, "calloc"); } =20 - if (!gelf_getshdr(s, &sec->sh)) { - WARN_ELF("gelf_getshdr"); - return NULL; - } + if (!gelf_getshdr(s, &sec->sh)) + ERROR_ELF("gelf_getshdr"); =20 sec->sh.sh_size =3D size; sec->sh.sh_entsize =3D entsize; @@ -1147,15 +1003,12 @@ struct section *elf_create_section(struct elf *elf,= const char *name, =20 /* Add section name to .shstrtab (or .strtab for Clang) */ shstrtab =3D find_section_by_name(elf, ".shstrtab"); - if (!shstrtab) - shstrtab =3D find_section_by_name(elf, ".strtab"); if (!shstrtab) { - WARN("can't find .shstrtab or .strtab section"); - return NULL; + shstrtab =3D find_section_by_name(elf, ".strtab"); + if (!shstrtab) + ERROR("can't find .shstrtab or .strtab section"); } sec->sh.sh_name =3D elf_add_string(elf, shstrtab, sec->name); - if (sec->sh.sh_name =3D=3D -1) - return NULL; =20 list_add_tail(&sec->list, &elf->sections); elf_hash_add(section, &sec->hash, sec->idx); @@ -1174,17 +1027,13 @@ static struct section *elf_create_rela_section(stru= ct elf *elf, char *rsec_name; =20 rsec_name =3D malloc(strlen(sec->name) + strlen(".rela") + 1); - if (!rsec_name) { - perror("malloc"); - return NULL; - } + ERROR_ON(!rsec_name, "malloc"); + strcpy(rsec_name, ".rela"); strcat(rsec_name, sec->name); =20 rsec =3D elf_create_section(elf, rsec_name, elf_rela_size(elf), reloc_nr); free(rsec_name); - if (!rsec) - return NULL; =20 rsec->data->d_type =3D ELF_T_RELA; rsec->sh.sh_type =3D SHT_RELA; @@ -1194,10 +1043,7 @@ static struct section *elf_create_rela_section(struc= t elf *elf, rsec->sh.sh_flags =3D SHF_INFO_LINK; =20 rsec->relocs =3D calloc(sec_num_entries(rsec), sizeof(struct reloc)); - if (!rsec->relocs) { - perror("calloc"); - return NULL; - } + ERROR_ON(!rsec->relocs, "calloc"); =20 sec->rsec =3D rsec; rsec->base =3D sec; @@ -1212,31 +1058,22 @@ struct section *elf_create_section_pair(struct elf = *elf, const char *name, struct section *sec; =20 sec =3D elf_create_section(elf, name, entsize, nr); - if (!sec) - return NULL; - - if (!elf_create_rela_section(elf, sec, reloc_nr)) - return NULL; - + elf_create_rela_section(elf, sec, reloc_nr); return sec; } =20 -int elf_write_insn(struct elf *elf, struct section *sec, - unsigned long offset, unsigned int len, - const char *insn) +void elf_write_insn(struct elf *elf, struct section *sec, + unsigned long offset, unsigned int len, + const char *insn) { Elf_Data *data =3D sec->data; =20 - if (data->d_type !=3D ELF_T_BYTE || data->d_off) { - WARN("write to unexpected data for section: %s", sec->name); - return -1; - } + if (data->d_type !=3D ELF_T_BYTE || data->d_off) + ERROR("write to unexpected data for section: %s", sec->name); =20 memcpy(data->d_buf + offset, insn, len); =20 mark_sec_changed(elf, sec, true); - - return 0; } =20 /* @@ -1248,7 +1085,7 @@ int elf_write_insn(struct elf *elf, struct section *s= ec, * * Yes, libelf sucks and we need to manually truncate if we over-allocate = data. */ -static int elf_truncate_section(struct elf *elf, struct section *sec) +static void elf_truncate_section(struct elf *elf, struct section *sec) { u64 size =3D sec_size(sec); bool truncated =3D false; @@ -1256,33 +1093,25 @@ static int elf_truncate_section(struct elf *elf, st= ruct section *sec) Elf_Scn *s; =20 s =3D elf_getscn(elf->elf, sec->idx); - if (!s) { - WARN_ELF("elf_getscn"); - return -1; - } + if (!s) + ERROR_ELF("elf_getscn"); =20 for (;;) { /* get next data descriptor for the relevant section */ data =3D elf_getdata(s, data); =20 if (!data) { - if (size) { - WARN("end of section data but non-zero size left\n"); - return -1; - } - return 0; + if (size) + ERROR("end of section data but non-zero size left"); + return; } =20 - if (truncated) { - /* when we remove symbols */ - WARN("truncated; but more data\n"); - return -1; - } + /* when we remove symbols */ + if (truncated) + ERROR("truncated; but more data"); =20 - if (!data->d_size) { - WARN("zero size data"); - return -1; - } + if (!data->d_size) + ERROR("zero size data"); =20 if (data->d_size > size) { truncated =3D true; @@ -1293,13 +1122,13 @@ static int elf_truncate_section(struct elf *elf, st= ruct section *sec) } } =20 -int elf_write(struct elf *elf) +void elf_write(struct elf *elf) { struct section *sec; Elf_Scn *s; =20 if (opts.dryrun) - return 0; + return; =20 /* Update changed relocation sections and section headers: */ list_for_each_entry(sec, &elf->sections, list) { @@ -1308,16 +1137,12 @@ int elf_write(struct elf *elf) =20 if (sec_changed(sec)) { s =3D elf_getscn(elf->elf, sec->idx); - if (!s) { - WARN_ELF("elf_getscn"); - return -1; - } + if (!s) + ERROR_ELF("elf_getscn"); =20 /* Note this also flags the section dirty */ - if (!gelf_update_shdr(s, &sec->sh)) { - WARN_ELF("gelf_update_shdr"); - return -1; - } + if (!gelf_update_shdr(s, &sec->sh)) + ERROR_ELF("gelf_update_shdr"); =20 mark_sec_changed(elf, sec, false); } @@ -1327,14 +1152,10 @@ int elf_write(struct elf *elf) elf_flagelf(elf->elf, ELF_C_SET, ELF_F_DIRTY); =20 /* Write all changes to the file. */ - if (elf_update(elf->elf, ELF_C_WRITE) < 0) { - WARN_ELF("elf_update"); - return -1; - } + if (elf_update(elf->elf, ELF_C_WRITE) < 0) + ERROR_ELF("elf_update"); =20 elf->changed =3D false; - - return 0; } =20 void elf_close(struct elf *elf) diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/ob= jtool/elf.h index 0c2af699b1bf..8585b9802e1b 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -128,10 +128,10 @@ struct reloc *elf_init_reloc_data_sym(struct elf *elf= , struct section *sec, struct symbol *sym, s64 addend); =20 -int elf_write_insn(struct elf *elf, struct section *sec, - unsigned long offset, unsigned int len, - const char *insn); -int elf_write(struct elf *elf); +void elf_write_insn(struct elf *elf, struct section *sec, + unsigned long offset, unsigned int len, + const char *insn); +void elf_write(struct elf *elf); void elf_close(struct elf *elf); =20 struct section *find_section_by_name(const struct elf *elf, const char *na= me); diff --git a/tools/objtool/include/objtool/orc.h b/tools/objtool/include/ob= jtool/orc.h index 15a32def1071..32f313cd30a2 100644 --- a/tools/objtool/include/objtool/orc.h +++ b/tools/objtool/include/objtool/orc.h @@ -4,11 +4,11 @@ =20 #include =20 -int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct in= struction *insn); +void init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct i= nstruction *insn); void orc_print_dump(struct elf *dummy_elf, struct orc_entry *orc, int i); -int write_orc_entry(struct elf *elf, struct section *orc_sec, - struct section *ip_sec, unsigned int idx, - struct section *insn_sec, unsigned long insn_off, - struct orc_entry *o); +void write_orc_entry(struct elf *elf, struct section *orc_sec, + struct section *ip_sec, unsigned int idx, + struct section *insn_sec, unsigned long insn_off, + struct orc_entry *o); =20 #endif /* _OBJTOOL_ORC_H */ diff --git a/tools/objtool/include/objtool/special.h b/tools/objtool/includ= e/objtool/special.h index 86d4af9c5aa9..30898278d904 100644 --- a/tools/objtool/include/objtool/special.h +++ b/tools/objtool/include/objtool/special.h @@ -30,7 +30,7 @@ struct special_alt { unsigned int orig_len, new_len; /* group only */ }; =20 -int special_get_alts(struct elf *elf, struct list_head *alts); +void special_get_alts(struct elf *elf, struct list_head *alts); =20 void arch_handle_alternative(unsigned short feature, struct special_alt *a= lt); =20 diff --git a/tools/objtool/include/objtool/warn.h b/tools/objtool/include/o= bjtool/warn.h index 69995f84f91b..28a475c4eb03 100644 --- a/tools/objtool/include/objtool/warn.h +++ b/tools/objtool/include/objtool/warn.h @@ -48,7 +48,7 @@ static inline char *offstr(struct section *sec, unsigned = long offset) "%s: warning: objtool: " format "\n", \ filename, ##__VA_ARGS__) =20 -#define WARN_FUNC(format, sec, offset, ...) \ +#define WARN_FUNC(sec, offset, format, ...) \ ({ \ char *_str =3D offstr(sec, offset); \ WARN("%s: " format, _str, ##__VA_ARGS__); \ @@ -59,12 +59,21 @@ static inline char *offstr(struct section *sec, unsigne= d long offset) ({ \ struct instruction *_insn =3D (insn); \ if (!_insn->sym || !_insn->sym->warned) \ - WARN_FUNC(format, _insn->sec, _insn->offset, \ + WARN_FUNC(_insn->sec, _insn->offset, format, \ ##__VA_ARGS__); \ if (_insn->sym) \ _insn->sym->warned =3D 1; \ }) =20 +#define WARN_ONCE(format, ...) \ +({ \ + static bool warned; \ + if (!warned) { \ + warned =3D true; \ + WARN(format, ##__VA_ARGS__); \ + } \ +}) + #define BT_INSN(insn, format, ...) \ ({ \ if (opts.verbose || opts.backtrace) { \ @@ -78,4 +87,33 @@ static inline char *offstr(struct section *sec, unsigned= long offset) #define WARN_ELF(format, ...) \ WARN(format ": %s", ##__VA_ARGS__, elf_errmsg(-1)) =20 +#define ERROR(format, ...) \ +({ \ + fprintf(stderr, \ + "%s: error: objtool [%s:%d]: " format "\n", \ + Objname, __FILE__, __LINE__, ##__VA_ARGS__); \ + exit(1); \ +}) + +#define ERROR_ON(cond, format, ...) \ +({ \ + if (cond) \ + ERROR(format, ##__VA_ARGS__); \ +}) + +#define ERROR_ELF(format, ...) \ + ERROR(format ": %s", ##__VA_ARGS__, elf_errmsg(-1)) + +#define ERROR_FUNC(sec, offset, format, ...) \ +({ \ + char *_str =3D offstr(sec, offset); \ + ERROR("%s: " format, _str, ##__VA_ARGS__); \ +}) + +#define ERROR_INSN(insn, format, ...) \ +({ \ + struct instruction *_insn =3D (insn); \ + ERROR_FUNC(_insn->sec, _insn->offset, format, ##__VA_ARGS__); \ +}) + #endif /* _WARN_H */ diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c index 6d2102450b35..06f7e518b8a7 100644 --- a/tools/objtool/objtool.c +++ b/tools/objtool/objtool.c @@ -8,6 +8,8 @@ #include #include #include +#include + #include #include #include @@ -21,82 +23,59 @@ bool help; char *Objname; static struct objtool_file file; =20 -static bool objtool_create_backup(const char *objname) +static void objtool_create_backup(const char *objname) { int len =3D strlen(objname); char *buf, *base, *name =3D malloc(len+6); int s, d, l, t; =20 - if (!name) { - perror("failed backup name malloc"); - return false; - } + name =3D malloc(len+6); + ERROR_ON(!name, "malloc"); =20 strcpy(name, objname); strcpy(name + len, ".orig"); =20 d =3D open(name, O_CREAT|O_WRONLY|O_TRUNC, 0644); - if (d < 0) { - perror("failed to create backup file"); - return false; - } + ERROR_ON(d < 0, "can't create '%s': %s", name, strerror(errno)); =20 s =3D open(objname, O_RDONLY); - if (s < 0) { - perror("failed to open orig file"); - return false; - } + ERROR_ON(s < 0, "can't open '%s': %s", objname, strerror(errno)); =20 buf =3D malloc(4096); - if (!buf) { - perror("failed backup data malloc"); - return false; - } + ERROR_ON(!buf, "malloc"); =20 while ((l =3D read(s, buf, 4096)) > 0) { base =3D buf; do { t =3D write(d, base, l); - if (t < 0) { - perror("failed backup write"); - return false; - } + ERROR_ON(t < 0, "failed backup write"); + base +=3D t; l -=3D t; } while (l); } =20 - if (l < 0) { - perror("failed backup read"); - return false; - } + ERROR_ON(l < 0, "failed backup read"); =20 free(name); free(buf); close(d); close(s); - - return true; } =20 struct objtool_file *objtool_open_read(const char *objname) { if (Objname) { - if (strcmp(Objname, objname)) { - WARN("won't handle more than one file at a time"); - return NULL; - } + if (strcmp(Objname, objname)) + ERROR("won't handle more than one file at a time"); + return &file; } =20 file.elf =3D elf_open_read(objname, O_RDWR); - if (!file.elf) - return NULL; =20 - if (opts.backup && !objtool_create_backup(objname)) { - WARN("can't create backup file"); - return NULL; - } + if (opts.backup) + objtool_create_backup(objname); =20 hash_init(file.insn_hash); INIT_LIST_HEAD(&file.retpoline_call_list); @@ -116,10 +95,8 @@ void objtool_pv_add(struct objtool_file *f, int idx, st= ruct symbol *func) if (!opts.noinstr) return; =20 - if (!f->pv_ops) { - WARN("paravirt confusion"); - return; - } + if (!f->pv_ops) + ERROR("paravirt confusion"); =20 /* * These functions will be patched into native code, diff --git a/tools/objtool/orc_dump.c b/tools/objtool/orc_dump.c index 9c0b9d8a34fe..9fd176b7a35c 100644 --- a/tools/objtool/orc_dump.c +++ b/tools/objtool/orc_dump.c @@ -32,56 +32,38 @@ int orc_dump(const char *objname) elf_version(EV_CURRENT); =20 fd =3D open(objname, O_RDONLY); - if (fd =3D=3D -1) { - perror("open"); - return -1; - } + ERROR_ON(fd =3D=3D -1, "open"); =20 elf =3D elf_begin(fd, ELF_C_READ_MMAP, NULL); - if (!elf) { - WARN_ELF("elf_begin"); - return -1; - } + if (!elf) + ERROR_ELF("elf_begin"); + + if (!elf64_getehdr(elf)) + ERROR_ELF("elf64_getehdr"); =20 - if (!elf64_getehdr(elf)) { - WARN_ELF("elf64_getehdr"); - return -1; - } memcpy(&dummy_elf.ehdr, elf64_getehdr(elf), sizeof(dummy_elf.ehdr)); =20 - if (elf_getshdrnum(elf, &nr_sections)) { - WARN_ELF("elf_getshdrnum"); - return -1; - } + if (elf_getshdrnum(elf, &nr_sections)) + ERROR_ELF("elf_getshdrnum"); =20 - if (elf_getshdrstrndx(elf, &shstrtab_idx)) { - WARN_ELF("elf_getshdrstrndx"); - return -1; - } + if (elf_getshdrstrndx(elf, &shstrtab_idx)) + ERROR_ELF("elf_getshdrstrndx"); =20 for (i =3D 0; i < nr_sections; i++) { scn =3D elf_getscn(elf, i); - if (!scn) { - WARN_ELF("elf_getscn"); - return -1; - } + if (!scn) + ERROR_ELF("elf_getscn"); =20 - if (!gelf_getshdr(scn, &sh)) { - WARN_ELF("gelf_getshdr"); - return -1; - } + if (!gelf_getshdr(scn, &sh)) + ERROR_ELF("gelf_getshdr"); =20 name =3D elf_strptr(elf, shstrtab_idx, sh.sh_name); - if (!name) { - WARN_ELF("elf_strptr"); - return -1; - } + if (!name) + ERROR_ELF("elf_strptr"); =20 data =3D elf_getdata(scn, NULL); - if (!data) { - WARN_ELF("elf_getdata"); - return -1; - } + if (!data) + ERROR_ELF("elf_getdata"); =20 if (!strcmp(name, ".symtab")) { symtab =3D data; @@ -101,47 +83,33 @@ int orc_dump(const char *objname) if (!symtab || !strtab_idx || !orc || !orc_ip) return 0; =20 - if (orc_size % sizeof(*orc) !=3D 0) { - WARN("bad .orc_unwind section size"); - return -1; - } + if (orc_size % sizeof(*orc) !=3D 0) + ERROR("bad .orc_unwind section size"); =20 nr_entries =3D orc_size / sizeof(*orc); for (i =3D 0; i < nr_entries; i++) { if (rela_orc_ip) { - if (!gelf_getrela(rela_orc_ip, i, &rela)) { - WARN_ELF("gelf_getrela"); - return -1; - } + if (!gelf_getrela(rela_orc_ip, i, &rela)) + ERROR_ELF("gelf_getrela"); =20 - if (!gelf_getsym(symtab, GELF_R_SYM(rela.r_info), &sym)) { - WARN_ELF("gelf_getsym"); - return -1; - } + if (!gelf_getsym(symtab, GELF_R_SYM(rela.r_info), &sym)) + ERROR_ELF("gelf_getsym"); =20 if (GELF_ST_TYPE(sym.st_info) =3D=3D STT_SECTION) { scn =3D elf_getscn(elf, sym.st_shndx); - if (!scn) { - WARN_ELF("elf_getscn"); - return -1; - } + if (!scn) + ERROR_ELF("elf_getscn"); =20 - if (!gelf_getshdr(scn, &sh)) { - WARN_ELF("gelf_getshdr"); - return -1; - } + if (!gelf_getshdr(scn, &sh)) + ERROR_ELF("gelf_getshdr"); =20 name =3D elf_strptr(elf, shstrtab_idx, sh.sh_name); - if (!name) { - WARN_ELF("elf_strptr"); - return -1; - } + if (!name) + ERROR_ELF("elf_strptr"); } else { name =3D elf_strptr(elf, strtab_idx, sym.st_name); - if (!name) { - WARN_ELF("elf_strptr"); - return -1; - } + if (!name) + ERROR_ELF("elf_strptr"); } =20 printf("%s+%llx:", name, (unsigned long long)rela.r_addend); diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c index 6eff3d6a125c..56aca3845e20 100644 --- a/tools/objtool/orc_gen.c +++ b/tools/objtool/orc_gen.c @@ -21,22 +21,19 @@ struct orc_list_entry { unsigned long insn_off; }; =20 -static int orc_list_add(struct list_head *orc_list, struct orc_entry *orc, +static void orc_list_add(struct list_head *orc_list, struct orc_entry *orc, struct section *sec, unsigned long offset) { - struct orc_list_entry *entry =3D malloc(sizeof(*entry)); + struct orc_list_entry *entry; =20 - if (!entry) { - WARN("malloc failed"); - return -1; - } + entry =3D malloc(sizeof(*entry)); + ERROR_ON(!entry, "malloc"); =20 entry->orc =3D *orc; entry->insn_sec =3D sec; entry->insn_off =3D offset; =20 list_add_tail(&entry->list, orc_list); - return 0; } =20 static unsigned long alt_group_len(struct alt_group *alt_group) @@ -70,13 +67,13 @@ int orc_create(struct objtool_file *file) int i; =20 if (!alt_group) { - if (init_orc_entry(&orc, insn->cfi, insn)) - return -1; + init_orc_entry(&orc, insn->cfi, insn); + if (!memcmp(&prev_orc, &orc, sizeof(orc))) continue; - if (orc_list_add(&orc_list, &orc, sec, - insn->offset)) - return -1; + + orc_list_add(&orc_list, &orc, sec, insn->offset); + nr++; prev_orc =3D orc; empty =3D false; @@ -95,13 +92,10 @@ int orc_create(struct objtool_file *file) if (!cfi) continue; /* errors are reported on the original insn */ - if (init_orc_entry(&orc, cfi, insn)) - return -1; + init_orc_entry(&orc, cfi, insn); if (!memcmp(&prev_orc, &orc, sizeof(orc))) continue; - if (orc_list_add(&orc_list, &orc, insn->sec, - insn->offset + i)) - return -1; + orc_list_add(&orc_list, &orc, insn->sec, insn->offset + i); nr++; prev_orc =3D orc; empty =3D false; @@ -124,23 +118,17 @@ int orc_create(struct objtool_file *file) sec =3D find_section_by_name(file->elf, ".orc_unwind"); if (sec) { WARN("file already has .orc_unwind section, skipping"); - return -1; + return 0; } orc_sec =3D elf_create_section(file->elf, ".orc_unwind", sizeof(struct orc_entry), nr); - if (!orc_sec) - return -1; =20 sec =3D elf_create_section_pair(file->elf, ".orc_unwind_ip", sizeof(int),= nr, nr); - if (!sec) - return -1; =20 /* Write ORC entries to sections: */ list_for_each_entry(entry, &orc_list, list) { - if (write_orc_entry(file->elf, orc_sec, sec, idx++, - entry->insn_sec, entry->insn_off, - &entry->orc)) - return -1; + write_orc_entry(file->elf, orc_sec, sec, idx++, entry->insn_sec, + entry->insn_off, &entry->orc); } =20 return 0; diff --git a/tools/objtool/special.c b/tools/objtool/special.c index 312d01684e21..9838ad700f37 100644 --- a/tools/objtool/special.c +++ b/tools/objtool/special.c @@ -65,9 +65,9 @@ static void reloc_to_sec_off(struct reloc *reloc, struct = section **sec, *off =3D reloc->sym->offset + reloc_addend(reloc); } =20 -static int get_alt_entry(struct elf *elf, const struct special_entry *entr= y, - struct section *sec, int idx, - struct special_alt *alt) +static void get_alt_entry(struct elf *elf, const struct special_entry *ent= ry, + struct section *sec, int idx, + struct special_alt *alt) { struct reloc *orig_reloc, *new_reloc; unsigned long offset; @@ -95,20 +95,15 @@ static int get_alt_entry(struct elf *elf, const struct = special_entry *entry, } =20 orig_reloc =3D find_reloc_by_dest(elf, sec, offset + entry->orig); - if (!orig_reloc) { - WARN_FUNC("can't find orig reloc", sec, offset + entry->orig); - return -1; - } + if (!orig_reloc) + ERROR_FUNC(sec, offset + entry->orig, "can't find orig reloc"); =20 reloc_to_sec_off(orig_reloc, &alt->orig_sec, &alt->orig_off); =20 if (!entry->group || alt->new_len) { new_reloc =3D find_reloc_by_dest(elf, sec, offset + entry->new); - if (!new_reloc) { - WARN_FUNC("can't find new reloc", - sec, offset + entry->new); - return -1; - } + if (!new_reloc) + ERROR_FUNC(sec, offset + entry->new, "can't find new reloc"); =20 reloc_to_sec_off(new_reloc, &alt->new_sec, &alt->new_off); =20 @@ -121,15 +116,11 @@ static int get_alt_entry(struct elf *elf, const struc= t special_entry *entry, struct reloc *key_reloc; =20 key_reloc =3D find_reloc_by_dest(elf, sec, offset + entry->key); - if (!key_reloc) { - WARN_FUNC("can't find key reloc", - sec, offset + entry->key); - return -1; - } + if (!key_reloc) + ERROR_FUNC(sec, offset + entry->key, "can't find key reloc"); + alt->key_addend =3D reloc_addend(key_reloc); } - - return 0; } =20 /* @@ -137,13 +128,13 @@ static int get_alt_entry(struct elf *elf, const struc= t special_entry *entry, * describe all the alternate instructions which can be patched in or * redirected to at runtime. */ -int special_get_alts(struct elf *elf, struct list_head *alts) +void special_get_alts(struct elf *elf, struct list_head *alts) { const struct special_entry *entry; struct section *sec; unsigned int nr_entries; struct special_alt *alt; - int idx, ret; + int idx; =20 INIT_LIST_HEAD(alts); =20 @@ -152,31 +143,18 @@ int special_get_alts(struct elf *elf, struct list_hea= d *alts) if (!sec) continue; =20 - if (sec_size(sec) % entry->size !=3D 0) { - WARN("%s size not a multiple of %d", - sec->name, entry->size); - return -1; - } + if (sec_size(sec) % entry->size !=3D 0) + ERROR("%s size not a multiple of %d", sec->name, entry->size); =20 nr_entries =3D sec_size(sec) / entry->size; =20 for (idx =3D 0; idx < nr_entries; idx++) { - alt =3D malloc(sizeof(*alt)); - if (!alt) { - WARN("malloc failed"); - return -1; - } - memset(alt, 0, sizeof(*alt)); + alt =3D calloc(1, sizeof(*alt)); + ERROR_ON(!alt, "calloc"); =20 - ret =3D get_alt_entry(elf, entry, sec, idx, alt); - if (ret > 0) - continue; - if (ret < 0) - return ret; + get_alt_entry(elf, entry, sec, idx, alt); =20 list_add_tail(&alt->list, alts); } } - - return 0; } diff --git a/tools/objtool/weak.c b/tools/objtool/weak.c index b568da3c33e6..426fdf0b7548 100644 --- a/tools/objtool/weak.c +++ b/tools/objtool/weak.c @@ -12,7 +12,7 @@ #define UNSUPPORTED(name) \ ({ \ fprintf(stderr, "error: objtool: " name " not implemented\n"); \ - return ENOSYS; \ + exit(1); \ }) =20 int __weak orc_dump(const char *objname) --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 652F41D47B1; Tue, 3 Sep 2024 04:00:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336038; cv=none; b=WoIgPYCpTRA92XID017sHxidg6JpYA02r487hgXN0ysfVbfnyk3HXE6P0rrgC/WEJtxUTSeOIyr7DbVAhLd7Z9MKRPdx9DENe0UhnL3WYQXTDyUFyue5/UWki+n8MkFDoTBTSXYiTcPY4gD4saUQ/jeRs0DnwPyyp3bUjdgxSq8= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336038; c=relaxed/simple; bh=HWBwAIL74R3NuwZPju7TxulBJPG6tdUTrDLO12HHwQU=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=gUR6U5cJVycePR5QsFHtxgSM0l9PRehe8EIe8T0Sx52Z6EITjYc4oIf/cmQma73LbCWCvgKiZWqgw1kJPhkT0ZLreSvQvxYjGGGUHa51iJ1kkiWyOg4/wgCwm5mM906ptha7O3E+s06PAeHFJiBmaQNiPmtCa96anzHdiA69wns= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=to2guu/g; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="to2guu/g" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 84C12C4CEC8; Tue, 3 Sep 2024 04:00:37 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336037; bh=HWBwAIL74R3NuwZPju7TxulBJPG6tdUTrDLO12HHwQU=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=to2guu/gJpq9Qs3QDqyHk7IPs9o3HoWtZIU1STBfc0s6W4Tcrzi6uh8p0lcFurbW9 jMpK/PUVuTdJgoQspc9z0X4RvFtsT6Ena7QX1yDXEN+bsR5tsm3SBql4bfiOb6WeGA 8s8iqZANTfokzzCwwcfIUwuLUp+GcrWeEwMXo1CNLoeDZpytAnj5Sd+tVp0I4QnTSc jvubKcODeqCKEqXAZ6v3dlQrhkyB4cF6t5UTvjHLa8lvG0XvOH8S8XK0JrDBoY09zx exLjXmv/ecUeq/H3QjQ2m8WD4L6FtUrb38E35T90/RNnlNVpT77CTVbPmg1fWGvjKb MjWWQz3qUJRhw== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 17/31] objtool: Open up the elf API Date: Mon, 2 Sep 2024 21:00:00 -0700 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Expose more functionality in the ELF library. This will be needed for the upcoming "objtool klp" support. Signed-off-by: Josh Poimboeuf --- tools/objtool/elf.c | 338 +++++++++++++++++++--------- tools/objtool/include/objtool/elf.h | 30 ++- tools/objtool/orc_gen.c | 6 +- 3 files changed, 260 insertions(+), 114 deletions(-) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 84cb6fc235c9..0c95d7cdf0f5 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -18,10 +18,11 @@ #include #include #include - #include #include =20 +#define ALIGN_UP(x, align_to) (((x) + ((align_to)-1)) & ~((align_to)-1)) + static inline u32 str_hash(const char *str) { return jhash(str, strlen(str), 0); @@ -261,6 +262,18 @@ struct symbol *find_symbol_by_name(const struct elf *e= lf, const char *name) return NULL; } =20 +struct symbol *find_global_symbol_by_name(const struct elf *elf, const cha= r *name) +{ + struct symbol *sym; + + elf_hash_for_each_possible(symbol_name, sym, name_hash, str_hash(name)) { + if (!strcmp(sym->name, name) && !is_local_symbol(sym)) + return sym; + } + + return NULL; +} + struct reloc *find_reloc_by_dest_range(const struct elf *elf, struct secti= on *sec, unsigned long offset, unsigned int len) { @@ -549,7 +562,7 @@ static void elf_update_sym_relocs(struct elf *elf, stru= ct symbol *sym) static void elf_update_symbol(struct elf *elf, struct section *symtab, struct section *symtab_shndx, struct symbol *sym) { - Elf32_Word shndx =3D sym->sec ? sym->sec->idx : SHN_UNDEF; + Elf32_Word shndx; Elf_Data *symtab_data =3D NULL, *shndx_data =3D NULL; Elf64_Xword entsize =3D symtab->sh.sh_entsize; int max_idx, idx =3D sym->idx; @@ -557,8 +570,7 @@ static void elf_update_symbol(struct elf *elf, struct s= ection *symtab, bool is_special_shndx =3D sym->sym.st_shndx >=3D SHN_LORESERVE && sym->sym.st_shndx !=3D SHN_XINDEX; =20 - if (is_special_shndx) - shndx =3D sym->sym.st_shndx; + shndx =3D is_special_shndx ? sym->sym.st_shndx : sym->sec->idx; =20 s =3D elf_getscn(elf->elf, symtab->idx); if (!s) @@ -654,12 +666,29 @@ static void elf_update_symbol(struct elf *elf, struct= section *symtab, ERROR_ELF("gelf_update_symshndx"); } =20 -static struct symbol * -__elf_create_symbol(struct elf *elf, struct symbol *sym) +static struct symbol *__elf_create_symbol(struct elf *elf, const char *nam= e, + struct section *sec, unsigned int bind, + unsigned int type, unsigned long offset, + size_t size) { struct section *symtab, *symtab_shndx; Elf32_Word first_non_local, new_idx; - struct symbol *old; + struct symbol *old, *sym; + + sym =3D calloc(1, sizeof(*sym)); + ERROR_ON(!sym, "calloc"); + + if (name) { + sym->name =3D strdup(name); + if (type !=3D STT_SECTION) + sym->sym.st_name =3D elf_add_string(elf, NULL, sym->name); + } + + sym->sec =3D sec ? : find_section_by_index(elf, 0); + + sym->sym.st_info =3D GELF_ST_INFO(bind, type); + sym->sym.st_value =3D offset; + sym->sym.st_size =3D size; =20 symtab =3D find_section_by_name(elf, ".symtab"); if (!symtab) @@ -669,7 +698,7 @@ __elf_create_symbol(struct elf *elf, struct symbol *sym) =20 new_idx =3D sec_num_entries(symtab); =20 - if (GELF_ST_BIND(sym->sym.st_info) !=3D STB_LOCAL) + if (bind !=3D STB_LOCAL) goto non_local; =20 /* @@ -698,7 +727,8 @@ __elf_create_symbol(struct elf *elf, struct symbol *sym) =20 non_local: sym->idx =3D new_idx; - elf_update_symbol(elf, symtab, symtab_shndx, sym); + if (sym->idx) + elf_update_symbol(elf, symtab, symtab_shndx, sym); =20 symtab->sh.sh_size +=3D symtab->sh.sh_entsize; mark_sec_changed(elf, symtab, true); @@ -708,63 +738,49 @@ __elf_create_symbol(struct elf *elf, struct symbol *s= ym) mark_sec_changed(elf, symtab_shndx, true); } =20 + elf_add_symbol(elf, sym); + return sym; } =20 -static struct symbol * -elf_create_section_symbol(struct elf *elf, struct section *sec) +struct symbol *elf_create_symbol(struct elf *elf, const char *name, + struct section *sec, unsigned int bind, + unsigned int type, unsigned long offset, + size_t size) +{ + return __elf_create_symbol(elf, name, sec, bind, type, offset, size); +} + +struct symbol *elf_create_section_symbol(struct elf *elf, struct section *= sec) { struct symbol *sym; =20 - sym =3D calloc(1, sizeof(*sym)); - ERROR_ON(!sym, "calloc"); - - sym->name =3D sec->name; - sym->sec =3D sec; - - // st_name 0 - sym->sym.st_info =3D GELF_ST_INFO(STB_LOCAL, STT_SECTION); - // st_other 0 - // st_value 0 - // st_size 0 - - sym =3D __elf_create_symbol(elf, sym); - elf_add_symbol(elf, sym); + sym =3D elf_create_symbol(elf, sec->name, sec, STB_LOCAL, STT_SECTION, 0,= 0); + sec->sym =3D sym; =20 return sym; } =20 -static int elf_add_string(struct elf *elf, struct section *strtab, const c= har *str); - struct symbol * -elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, long size) +elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, size_t size) { - struct symbol *sym =3D calloc(1, sizeof(*sym)); size_t namelen =3D strlen(orig->name) + sizeof("__pfx_"); - char *name =3D malloc(namelen); - - ERROR_ON(!sym || !name, "malloc"); + char name[SYM_NAME_LEN]; + unsigned long offset; =20 snprintf(name, namelen, "__pfx_%s", orig->name); =20 - sym->name =3D name; - sym->sec =3D orig->sec; + offset =3D orig->sym.st_value - size; =20 - sym->sym.st_name =3D elf_add_string(elf, NULL, name); - sym->sym.st_info =3D orig->sym.st_info; - sym->sym.st_value =3D orig->sym.st_value - size; - sym->sym.st_size =3D size; - - sym =3D __elf_create_symbol(elf, sym); - elf_add_symbol(elf, sym); - - return sym; + return elf_create_symbol(elf, name, orig->sec, + GELF_ST_BIND(orig->sym.st_info), + GELF_ST_TYPE(orig->sym.st_info), + offset, size); } =20 -static struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec, - unsigned int reloc_idx, - unsigned long offset, struct symbol *sym, - s64 addend, unsigned int type) +struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec, + unsigned int reloc_idx, unsigned long offset, + struct symbol *sym, s64 addend, unsigned int type) { struct reloc *reloc, empty =3D { 0 }; =20 @@ -800,7 +816,7 @@ struct reloc *elf_init_reloc_text_sym(struct elf *elf, = struct section *sec, unsigned long insn_off) { struct symbol *sym =3D insn_sec->sym; - int addend =3D insn_off; + s64 addend =3D insn_off; =20 if (!is_text_section(insn_sec)) ERROR("bad call to %s() for data symbol %s", __func__, sym->name); @@ -813,8 +829,6 @@ struct reloc *elf_init_reloc_text_sym(struct elf *elf, = struct section *sec, * non-weak function after linking. */ sym =3D elf_create_section_symbol(elf, insn_sec); - - insn_sec->sym =3D sym; } =20 return elf_init_reloc(elf, sec->rsec, reloc_idx, offset, sym, addend, @@ -926,11 +940,9 @@ struct elf *elf_open_read(const char *name, int flags) return elf; } =20 -static int elf_add_string(struct elf *elf, struct section *strtab, const c= har *str) +unsigned long elf_add_string(struct elf *elf, struct section *strtab, cons= t char *str) { - Elf_Data *data; - Elf_Scn *s; - int len; + unsigned long offset; =20 if (!strtab) { strtab =3D find_section_by_name(elf, ".strtab"); @@ -938,56 +950,77 @@ static int elf_add_string(struct elf *elf, struct sec= tion *strtab, const char *s ERROR("can't find .strtab section"); } =20 - s =3D elf_getscn(elf->elf, strtab->idx); - if (!s) - ERROR_ELF("elf_getscn"); + offset =3D ALIGN_UP(strtab->sh.sh_size, strtab->sh.sh_addralign); =20 - data =3D elf_newdata(s); - if (!data) - ERROR_ELF("elf_newdata"); + elf_add_data(elf, strtab, str, strlen(str) + 1); =20 - data->d_buf =3D strdup(str); - data->d_size =3D strlen(str) + 1; - data->d_align =3D 1; - - len =3D strtab->sh.sh_size; - strtab->sh.sh_size +=3D data->d_size; - - mark_sec_changed(elf, strtab, true); - - return len; + return offset; } =20 -struct section *elf_create_section(struct elf *elf, const char *name, - size_t entsize, unsigned int nr) +void *elf_add_data(struct elf *elf, struct section *sec, const void *data,= size_t size) { - struct section *sec, *shstrtab; - size_t size =3D entsize * nr; + unsigned long offset; Elf_Scn *s; =20 - sec =3D malloc(sizeof(*sec)); - ERROR_ON(!sec, "malloc"); - memset(sec, 0, sizeof(*sec)); - - INIT_LIST_HEAD(&sec->symbol_list); - - s =3D elf_newscn(elf->elf); + s =3D elf_getscn(elf->elf, sec->idx); if (!s) - ERROR_ELF("elf_newscn"); - - sec->name =3D strdup(name); - ERROR_ON(!sec->name, "strdup"); - - sec->idx =3D elf_ndxscn(s); + ERROR_ELF("elf_getscn"); =20 sec->data =3D elf_newdata(s); if (!sec->data) ERROR_ELF("elf_newdata"); =20 + sec->data->d_buf =3D calloc(1, size); + ERROR_ON(!sec->data->d_buf, "calloc"); + + if (data) + memcpy(sec->data->d_buf, data, size); + sec->data->d_size =3D size; - sec->data->d_align =3D 1; + sec->data->d_align =3D sec->sh.sh_addralign; + + offset =3D ALIGN_UP(sec->sh.sh_size, sec->sh.sh_addralign); + sec->sh.sh_size =3D offset + size; + + mark_sec_changed(elf, sec, true); + + return sec->data->d_buf; +} + +struct section *elf_create_section(struct elf *elf, const char *name, + size_t size, size_t entsize, + unsigned int type, unsigned int align, + unsigned int flags) +{ + struct section *sec, *shstrtab; + Elf_Scn *s; + + if (name && find_section_by_name(elf, name)) + ERROR("section '%s' already exists", name); + + sec =3D calloc(1, sizeof(*sec)); + ERROR_ON(!sec, "calloc"); + + INIT_LIST_HEAD(&sec->symbol_list); + + /* don't actually create the section, just the data structures */ + if (type =3D=3D SHT_NULL) + goto add; + + s =3D elf_newscn(elf->elf); + if (!s) + ERROR_ELF("elf_newscn"); + + sec->idx =3D elf_ndxscn(s); =20 if (size) { + sec->data =3D elf_newdata(s); + if (!sec->data) + ERROR_ELF("elf_newdata"); + + sec->data->d_size =3D size; + sec->data->d_align =3D 1; + sec->data->d_buf =3D calloc(1, size); ERROR_ON(!sec->data->d_buf, "calloc"); } @@ -997,31 +1030,37 @@ struct section *elf_create_section(struct elf *elf, = const char *name, =20 sec->sh.sh_size =3D size; sec->sh.sh_entsize =3D entsize; - sec->sh.sh_type =3D SHT_PROGBITS; - sec->sh.sh_addralign =3D 1; - sec->sh.sh_flags =3D SHF_ALLOC; + sec->sh.sh_type =3D type; + sec->sh.sh_addralign =3D align; + sec->sh.sh_flags =3D flags; =20 - /* Add section name to .shstrtab (or .strtab for Clang) */ - shstrtab =3D find_section_by_name(elf, ".shstrtab"); - if (!shstrtab) { - shstrtab =3D find_section_by_name(elf, ".strtab"); - if (!shstrtab) - ERROR("can't find .shstrtab or .strtab section"); + if (name) { + sec->name =3D strdup(name); + ERROR_ON(!sec->name, "strdup"); + + /* Add section name to .shstrtab (or .strtab for Clang) */ + shstrtab =3D find_section_by_name(elf, ".shstrtab"); + if (!shstrtab) { + shstrtab =3D find_section_by_name(elf, ".strtab"); + if (!shstrtab) + ERROR("can't find .shstrtab or .strtab section"); + } + sec->sh.sh_name =3D elf_add_string(elf, shstrtab, sec->name); + + elf_hash_add(section_name, &sec->name_hash, str_hash(sec->name)); } - sec->sh.sh_name =3D elf_add_string(elf, shstrtab, sec->name); =20 +add: list_add_tail(&sec->list, &elf->sections); elf_hash_add(section, &sec->hash, sec->idx); - elf_hash_add(section_name, &sec->name_hash, str_hash(sec->name)); =20 mark_sec_changed(elf, sec, true); =20 return sec; } =20 -static struct section *elf_create_rela_section(struct elf *elf, - struct section *sec, - unsigned int reloc_nr) +struct section *elf_create_rela_section(struct elf *elf, struct section *s= ec, + unsigned int reloc_nr) { struct section *rsec; char *rsec_name; @@ -1032,33 +1071,110 @@ static struct section *elf_create_rela_section(str= uct elf *elf, strcpy(rsec_name, ".rela"); strcat(rsec_name, sec->name); =20 - rsec =3D elf_create_section(elf, rsec_name, elf_rela_size(elf), reloc_nr); - free(rsec_name); + rsec =3D elf_create_section(elf, rsec_name, reloc_nr * elf_rela_size(elf), + elf_rela_size(elf), SHT_RELA, elf_addr_size(elf), + SHF_INFO_LINK); =20 - rsec->data->d_type =3D ELF_T_RELA; - rsec->sh.sh_type =3D SHT_RELA; - rsec->sh.sh_addralign =3D elf_addr_size(elf); rsec->sh.sh_link =3D find_section_by_name(elf, ".symtab")->idx; rsec->sh.sh_info =3D sec->idx; - rsec->sh.sh_flags =3D SHF_INFO_LINK; =20 - rsec->relocs =3D calloc(sec_num_entries(rsec), sizeof(struct reloc)); - ERROR_ON(!rsec->relocs, "calloc"); + if (reloc_nr) { + rsec->data->d_type =3D ELF_T_RELA; + rsec->relocs =3D calloc(sec_num_entries(rsec), sizeof(struct reloc)); + ERROR_ON(!rsec->relocs, "calloc"); + } =20 sec->rsec =3D rsec; + free(rsec_name); + rsec->base =3D sec; =20 return rsec; } =20 +// TODO: preallocate sec->relocs so this doesn't happen often +// TODO: can avoid for bundled sections +static void elf_alloc_reloc(struct elf *elf, struct section *rsec) +{ + unsigned int nr_relocs =3D sec_num_entries(rsec); + struct reloc *old_relocs, *new_relocs; + struct symbol *sym; + + old_relocs =3D rsec->relocs; + new_relocs =3D calloc(1, (nr_relocs + 1) * sizeof(struct reloc)); + ERROR_ON(!new_relocs, "calloc"); + + if (!old_relocs) + goto done; + + // update syms and relocs which reference the reloc + for_each_sym(elf, sym) { + struct reloc **reloc; + + for (reloc =3D &sym->relocs; *reloc; ) { + struct reloc **next =3D &((*reloc)->sym_next_reloc); + if (*reloc >=3D old_relocs && *reloc < &old_relocs[nr_relocs]) { + *reloc =3D &new_relocs[*reloc - old_relocs]; + } + reloc =3D next; + } + } + + memcpy(new_relocs, old_relocs, (nr_relocs * sizeof(struct reloc))); + + for (int i =3D 0; i < nr_relocs; i++) { + struct reloc *old =3D &old_relocs[i]; + struct reloc *new =3D &new_relocs[i]; + u32 key =3D reloc_hash(old); + + elf_hash_del(reloc, &old->hash, key); + elf_hash_add(reloc, &new->hash, key); + } + + free(old_relocs); +done: + rsec->relocs =3D new_relocs; +} + +struct reloc *elf_create_reloc(struct elf *elf, struct section *sec, + unsigned long offset, + struct symbol *sym, s64 addend, + unsigned int type) +{ + struct section *rsec =3D sec->rsec; + + if (!rsec) + rsec =3D elf_create_rela_section(elf, sec, 0); + + if (find_reloc_by_dest(elf, sec, offset)) + ERROR_FUNC(sec, offset, "duplicate reloc"); + + if (!rsec->data) { + rsec->data =3D elf_newdata(elf_getscn(elf->elf, rsec->idx)); + rsec->data->d_align =3D 1; + rsec->data->d_type =3D ELF_T_RELA; + } + + elf_alloc_reloc(elf, rsec); + + rsec->sh.sh_size +=3D elf_rela_size(elf); + rsec->data->d_size =3D rsec->sh.sh_size; + rsec->data->d_buf =3D realloc(rsec->data->d_buf, rsec->sh.sh_size); + return elf_init_reloc(elf, rsec, sec_num_entries(rsec) - 1, offset, sym, + addend, type); +} + struct section *elf_create_section_pair(struct elf *elf, const char *name, size_t entsize, unsigned int nr, unsigned int reloc_nr) { struct section *sec; =20 - sec =3D elf_create_section(elf, name, entsize, nr); + sec =3D elf_create_section(elf, name, nr * entsize, entsize, + SHT_PROGBITS, 1, SHF_ALLOC); + elf_create_rela_section(elf, sec, reloc_nr); + return sec; } =20 diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/ob= jtool/elf.h index 8585b9802e1b..e91bbe7f07bf 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -15,6 +15,8 @@ #include #include =20 +#define SYM_NAME_LEN 512 + #ifdef LIBELF_USE_DEPRECATED # define elf_getshdrnum elf_getshnum # define elf_getshdrstrndx elf_getshstrndx @@ -109,12 +111,33 @@ struct elf { struct elf *elf_open_read(const char *name, int flags); =20 struct section *elf_create_section(struct elf *elf, const char *name, - size_t entsize, unsigned int nr); + size_t size, size_t entsize, + unsigned int type, unsigned int align, + unsigned int flags); struct section *elf_create_section_pair(struct elf *elf, const char *name, size_t entsize, unsigned int nr, unsigned int reloc_nr); =20 -struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *or= ig, long size); +struct section *elf_create_rela_section(struct elf *elf, struct section *s= ec, + unsigned int reloc_nr); + +struct symbol *elf_create_symbol(struct elf *elf, const char *name, + struct section *sec, unsigned int bind, + unsigned int type, unsigned long offset, + size_t size); +struct symbol *elf_create_section_symbol(struct elf *elf, struct section *= sec); +struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *or= ig, + size_t size); + +struct reloc *elf_create_reloc(struct elf *elf, struct section *sec, + unsigned long offset, struct symbol *sym, + s64 addend, unsigned int type); +void *elf_add_data(struct elf *elf, struct section *sec, const void *data, + size_t size); + +struct reloc *elf_init_reloc(struct elf *elf, struct section *rsec, + unsigned int reloc_idx, unsigned long offset, + struct symbol *sym, s64 addend, unsigned int type); =20 struct reloc *elf_init_reloc_text_sym(struct elf *elf, struct section *sec, unsigned long offset, @@ -128,6 +151,8 @@ struct reloc *elf_init_reloc_data_sym(struct elf *elf, = struct section *sec, struct symbol *sym, s64 addend); =20 +unsigned long elf_add_string(struct elf *elf, struct section *strtab, cons= t char *str); + void elf_write_insn(struct elf *elf, struct section *sec, unsigned long offset, unsigned int len, const char *insn); @@ -138,6 +163,7 @@ struct section *find_section_by_name(const struct elf *= elf, const char *name); struct symbol *find_func_by_offset(struct section *sec, unsigned long offs= et); struct symbol *find_symbol_by_offset(struct section *sec, unsigned long of= fset); struct symbol *find_symbol_by_name(const struct elf *elf, const char *name= ); +struct symbol *find_global_symbol_by_name(const struct elf *elf, const cha= r *name); struct symbol *find_symbol_containing(const struct section *sec, unsigned = long offset); int find_symbol_hole_containing(const struct section *sec, unsigned long o= ffset); struct reloc *find_reloc_by_dest(const struct elf *elf, struct section *se= c, unsigned long offset); diff --git a/tools/objtool/orc_gen.c b/tools/objtool/orc_gen.c index 56aca3845e20..3301128b5188 100644 --- a/tools/objtool/orc_gen.c +++ b/tools/objtool/orc_gen.c @@ -121,7 +121,11 @@ int orc_create(struct objtool_file *file) return 0; } orc_sec =3D elf_create_section(file->elf, ".orc_unwind", - sizeof(struct orc_entry), nr); + nr * sizeof(struct orc_entry), + sizeof(struct orc_entry), + SHT_PROGBITS, + 1, + SHF_ALLOC); =20 sec =3D elf_create_section_pair(file->elf, ".orc_unwind_ip", sizeof(int),= nr, nr); =20 --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 85CE71D47C4; Tue, 3 Sep 2024 04:00:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336038; cv=none; b=hVWZ2evQEiFn5jLDcUcn+4wszHez3Zkagtl8E2+e6T3B8kpROcMnQ8Xb85SGeq4N4vv0Hl7NRBPV+ji0O6pnfM0GBNkKQ3P54hMOAn9RhgjJVJDLOvwGw9LgBOvYnwTzn25CCLwxL8y+fSRFT+ST1NC6zuTW8Ou2PnBxnVb0a8g= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336038; c=relaxed/simple; bh=R7lpTxC5zGA9gCmdCP81GjnhFXtOMx9okauDMWA62HQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=K6lTU26kpn/ySnO+vy3yDXepwc85yurdSt8j6iHV1EspIM07+3LocO0q83k2N7oLZI8qf1smk0Go1SFMieMl/jFpu5AbrnhkpsG036doMIiz+OziL9ScaClfc3iN590mg4qRGU/WXGLsQOsn874eFBbkO08+juUtvyCEzAskWQ0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=s05wWCXK; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="s05wWCXK" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 0D2EDC4CED4; Tue, 3 Sep 2024 04:00:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336038; bh=R7lpTxC5zGA9gCmdCP81GjnhFXtOMx9okauDMWA62HQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=s05wWCXKjhfihSR7WWAMeTdm/B/Jn9c76wduABCrAd9bF13ETnEUwbdFk4VkO9cLc JOXU/FcFF60DfP18JGZDLloSnbpxWd3+BKy4FS3tkgOxZ0vLDCnHhXq4QUvKjhUVvy LtbD9Sh7g9c8rOiR7JnTAkQZzOJYWwjEsHeHypRP3kItYk5glP1Zp3s7jnVtFtVlwl 1xAs/UvZrfQ5fWDLfum//TJ/A52WOh9R4ACzEukUHV0O4n6bDGeDHBpYRTxNmak0hU fZ2m4D/IyMabxJqoixjz14dMQIoahGMVcEdrESKe906TRJkFF7VAPV49bh6lJtLgTo gQ63GLR4tbF0w== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 18/31] objtool: Disallow duplicate prefix symbols Date: Mon, 2 Sep 2024 21:00:01 -0700 Message-ID: <569ad57b4b74af51f806e624dea25b4c912533c8.1725334260.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Error out if a duplicate prefix symbol is attempted. Signed-off-by: Josh Poimboeuf --- tools/objtool/check.c | 5 ++++- tools/objtool/elf.c | 9 +++++++++ tools/objtool/include/objtool/elf.h | 3 +++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index af945854dd72..236dc7871f01 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -3866,6 +3866,7 @@ static void add_prefix_symbol(struct objtool_file *fi= le, struct symbol *func) for (prev =3D prev_insn_same_sec(file, insn); prev; prev =3D prev_insn_same_sec(file, prev)) { + struct symbol *sym_pfx; u64 offset; =20 if (prev->type !=3D INSN_NOP) @@ -3879,7 +3880,9 @@ static void add_prefix_symbol(struct objtool_file *fi= le, struct symbol *func) if (offset < opts.prefix) continue; =20 - elf_create_prefix_symbol(file->elf, func, opts.prefix); + sym_pfx =3D elf_create_prefix_symbol(file->elf, func, opts.prefix); + if (!sym_pfx) + ERROR("duplicate prefix symbol for %s\n", func->name); =20 break; } diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 0c95d7cdf0f5..748c170b931a 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -767,11 +767,20 @@ elf_create_prefix_symbol(struct elf *elf, struct symb= ol *orig, size_t size) size_t namelen =3D strlen(orig->name) + sizeof("__pfx_"); char name[SYM_NAME_LEN]; unsigned long offset; + struct symbol *sym; =20 snprintf(name, namelen, "__pfx_%s", orig->name); =20 + sym =3D orig; offset =3D orig->sym.st_value - size; =20 + sec_for_each_sym_continue_reverse(orig->sec, sym) { + if (sym->offset < offset) + break; + if (sym->offset =3D=3D offset && !strcmp(sym->name, name)) + return NULL; + } + return elf_create_symbol(elf, name, orig->sec, GELF_ST_BIND(orig->sym.st_info), GELF_ST_TYPE(orig->sym.st_info), diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/ob= jtool/elf.h index e91bbe7f07bf..5ac5e7cdddee 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -399,6 +399,9 @@ static inline void set_reloc_type(struct elf *elf, stru= ct reloc *reloc, unsigned #define sec_for_each_sym(sec, sym) \ list_for_each_entry(sym, &sec->symbol_list, list) =20 +#define sec_for_each_sym_continue_reverse(sec, sym) \ + list_for_each_entry_continue_reverse(sym, &sec->symbol_list, list) + #define for_each_sym(elf, sym) \ for (struct section *__sec, *__fake =3D (struct section *)1; \ __fake; __fake =3D NULL) \ --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 559451D54DB; Tue, 3 Sep 2024 04:00:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336039; cv=none; b=u0F7mtUVl2wyiRR0E1Y8c33rI9C6WSpmPN9Y79vLuLsR9QGN3/vFRdKIZfMJA3/Gp7URWWwKHDJN+yu5GHSWKJn1QDP5sgMDw0SEJcG2PRbge4PLyg6IAuPPhZS4/LtxpHqG6hVjHq+MjyKwCHpabroumTmJOCFN/EVZovo3T3I= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336039; c=relaxed/simple; bh=XEuuJCImEqHAJnZPhF5hOjypD7T7+zQrodOehIwpmB8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=FW3Ut3zNEaFM8Z1WYEB+OiRHc/oQeW4uBmc1w2YUA3Qmww4wLL2YZd7hM7zV/B7nstdX8CRnzvIl580kkTaGHuLRDN+KCv7uHvHypkVNP/TJiZkifhdUi6dpQUZUXtH1ryn3qqKXC0A0lOE/hef3aYX09B9DKiplNi7iGcw2wuI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=fVYa7cBD; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="fVYa7cBD" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 88EBAC4CECE; Tue, 3 Sep 2024 04:00:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336038; bh=XEuuJCImEqHAJnZPhF5hOjypD7T7+zQrodOehIwpmB8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=fVYa7cBD/1ZimqvEz8IK6nx5SuH7FXyZfy2um+a0+TXvWg8OcStxPA+rsUJ9bOZhy E2RjopDBowpMIXJfsO56r94AWSZ6fEg+hVwxN0R5OyESVpTKdTaVmzIjntkZwC/kmd 47quGtYfouqIERUS6xVFDsd72rBTyT/rXnjbPu54Nlm0cQlVwB65WCmIzzUgLlsrgL 8KHBcmLSwLfLsL/ognmwpBRf3ZXwopbFbOMT78TeQPHC9xtQ3f2JPep1MeCCPl924h trX/BqzLfxEcyhHEc7J/FW0IEowDJCMD/o+uFucYPBWNokx4is7YzrlmXot9azXmGI /xA4WhL1HcdOw== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 19/31] objtool: Add elf_create_file() Date: Mon, 2 Sep 2024 21:00:02 -0700 Message-ID: <327dc97a71aea6e9e5fa51960e0da62188da27f9.1725334260.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add interface to enable the creation of a new ELF file. Signed-off-by: Josh Poimboeuf --- tools/objtool/elf.c | 118 ++++++++++++++++++++++++++++ tools/objtool/include/objtool/elf.h | 3 +- 2 files changed, 120 insertions(+), 1 deletion(-) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 748c170b931a..7f89b0a99886 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -926,6 +927,9 @@ struct elf *elf_open_read(const char *name, int flags) elf->fd =3D open(name, flags); ERROR_ON(elf->fd =3D=3D -1, "can't open '%s': %s", name, strerror(errno)); =20 + elf->name =3D strdup(name); + ERROR_ON(!elf->name, "strdup"); + if ((flags & O_ACCMODE) =3D=3D O_RDONLY) cmd =3D ELF_C_READ_MMAP; else if ((flags & O_ACCMODE) =3D=3D O_RDWR) @@ -949,6 +953,108 @@ struct elf *elf_open_read(const char *name, int flags) return elf; } =20 +struct elf *elf_create_file(GElf_Ehdr *ehdr, const char *name) +{ + struct section *null, *symtab, *strtab, *shstrtab; + char *dir, *base, *tmp_name; + struct symbol *sym; + struct elf *elf; + + elf_version(EV_CURRENT); + + elf =3D calloc(1, sizeof(*elf)); + ERROR_ON(!elf, "calloc"); + + INIT_LIST_HEAD(&elf->sections); + + dir =3D strdup(name); + ERROR_ON(!dir, "strdup"); + dir =3D dirname(dir); + + base =3D strdup(name); + ERROR_ON(!base, "strdup"); + base =3D basename(base); + + tmp_name =3D malloc(256); + ERROR_ON(!tmp_name, "malloc"); + + snprintf(tmp_name, 256, "%s/%s.XXXXXX", dir, base); + + elf->fd =3D mkstemp(tmp_name); + if (elf->fd =3D=3D -1) { + fprintf(stderr, "objtool: Can't open '%s': %s\n", + elf->tmp_name, strerror(errno)); + exit(1); + } + + elf->tmp_name =3D tmp_name; + + elf->name =3D strdup(name); + ERROR_ON(!elf->name, "strdup"); + + elf->elf =3D elf_begin(elf->fd, ELF_C_WRITE, NULL); + if (!elf->elf) + ERROR_ELF("elf_begin"); + + if (!gelf_newehdr(elf->elf, ELFCLASS64)) + ERROR_ELF("gelf_newehdr"); + + memcpy(&elf->ehdr, ehdr, sizeof(elf->ehdr)); + + if (!gelf_update_ehdr(elf->elf, &elf->ehdr)) + ERROR_ELF("gelf_update_ehdr"); + + INIT_LIST_HEAD(&elf->symbols); + + elf_alloc_hash(section, 1000); + elf_alloc_hash(section_name, 1000); + + elf_alloc_hash(symbol, 10000); + elf_alloc_hash(symbol_name, 10000); + + elf_alloc_hash(reloc, 100000); + + /* + * NULL section: add it to the section list without actually adding it + * to elf as we use it for some things (such as?) + */ + null =3D elf_create_section(elf, NULL, 0, 0, SHT_NULL, 0, 0); + null->name =3D ""; + + shstrtab =3D elf_create_section(elf, NULL, 0, 0, SHT_STRTAB, 1, 0); + shstrtab->name =3D ".shstrtab"; + + strtab =3D elf_create_section(elf, NULL, 0, 0, SHT_STRTAB, 1, 0); + strtab->name =3D ".strtab"; + + null->sh.sh_name =3D elf_add_string(elf, shstrtab, null->name); + shstrtab->sh.sh_name =3D elf_add_string(elf, shstrtab, shstrtab->name); + strtab->sh.sh_name =3D elf_add_string(elf, shstrtab, strtab->name); + + elf_hash_add(section_name, &null->name_hash, str_hash(null->name)); + elf_hash_add(section_name, &strtab->name_hash, str_hash(strtab->name)); + elf_hash_add(section_name, &shstrtab->name_hash, str_hash(shstrtab->name)= ); + + elf_add_string(elf, strtab, ""); + + symtab =3D elf_create_section(elf, ".symtab", 0x18, 0x18, SHT_SYMTAB, 0x8= , 0); + symtab->sh.sh_link =3D strtab->idx; + symtab->sh.sh_info =3D 1; + + elf->ehdr.e_shstrndx =3D shstrtab->idx; + if (!gelf_update_ehdr(elf->elf, &elf->ehdr)) + ERROR_ELF("gelf_update_ehdr"); + + sym =3D calloc(1, sizeof(*sym)); + ERROR_ON(!sym, "calloc"); + + sym->name =3D ""; + sym->sec =3D null; + elf_add_symbol(elf, sym); + + return elf; +} + unsigned long elf_add_string(struct elf *elf, struct section *strtab, cons= t char *str) { unsigned long offset; @@ -1281,6 +1387,18 @@ void elf_write(struct elf *elf) ERROR_ELF("elf_update"); =20 elf->changed =3D false; + + if (elf->tmp_name) { + int ret; + + unlink(elf->name); + + ret =3D linkat(AT_FDCWD, elf->tmp_name, AT_FDCWD, elf->name, 0); + ERROR_ON(ret, "linkat"); + + close(elf->fd); + unlink(elf->tmp_name); + } } =20 void elf_close(struct elf *elf) diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/ob= jtool/elf.h index 5ac5e7cdddee..f759686d46d7 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -87,7 +87,7 @@ struct elf { GElf_Ehdr ehdr; int fd; bool changed; - const char *name; + const char *name, *tmp_name; unsigned int num_files; struct list_head sections; unsigned long num_relocs; @@ -109,6 +109,7 @@ struct elf { }; =20 struct elf *elf_open_read(const char *name, int flags); +struct elf *elf_create_file(GElf_Ehdr *ehdr, const char *name); =20 struct section *elf_create_section(struct elf *elf, const char *name, size_t size, size_t entsize, --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D224C1D54FD; Tue, 3 Sep 2024 04:00:39 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336039; cv=none; b=Bi7vFhtTR59glBiLDWcWrgb/u3ZTw6HdIwsdfaGF9HkBZc8o68HOh0ujrPpRRLQkMLD0L141WqHjjm3+rwBAeYVbeXOfw+dnGSDGgiyAuYxUvIxsRwoTwnfvsxw5RB637QkLoDjte/aet8y97XpxklbMoH79HJdBsYbfQIJrpCQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336039; c=relaxed/simple; bh=dzKVrdzTcHSO61YSnRdTuu8RumHoQqa7Gn5nYXj8C5Y=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=lavnL/31j3Qr8tsJ+LEZ3hYzs+zJn8jTvTPIQCrOw+sWOOM9EUTLX9FVBZCXnnoQfT4jSPIgIuTfMcpKoc9d7Rf8mZjUhasa6YzQX6strxm3E/lgjUIN4v5HCjIrVOm2Dth+yjdBItudeg1TjV6FwWkMWFSQdCtXJIqYmYdKA0U= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=nHONwC1X; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="nHONwC1X" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 1302DC4CECC; Tue, 3 Sep 2024 04:00:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336039; bh=dzKVrdzTcHSO61YSnRdTuu8RumHoQqa7Gn5nYXj8C5Y=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nHONwC1XuyQHnkdrm1PmBYct7yxb00XIXmHeADwkm2YnI5DjmdHmHLnBNutcNpg2O Hcoezj4bLXCDfIxY9agxSJwIr1hPU41+eFaXI1/NBfm6B3qDTgcF8ViSKSsYH+r8YI Si1d73vbKk4JxUJTUt5A5xfigeSI7mNw2GKnaCVRQqq8K1gcRsfC+51Jc8T3E2bprt 1tf0/uOAigiTaLg+Df57gPdK9C0DiD9S+1o7j8xxM3T0PhtDPzUjiDT6tk5uWzqaYU tROn0ijwlIkpe8D0n83uy4Wqe+qdCFkv0Abq29BanEL5ts5rMfblm9epBKFltu552d 0Msl55KJDfS6A== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 20/31] objtool: Add UD1 detection Date: Mon, 2 Sep 2024 21:00:03 -0700 Message-ID: <20e0e2662239a042a10196e8f240ce596b250ae8.1725334260.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" A UD1 isn't a BUG and shouldn't be treated like one. Signed-off-by: Josh Poimboeuf --- tools/objtool/arch/x86/decode.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decod= e.c index 6b34b058a821..72d55dcd3d7f 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -528,11 +528,19 @@ int arch_decode_instruction(struct objtool_file *file= , const struct section *sec /* sysenter, sysret */ insn->type =3D INSN_CONTEXT_SWITCH; =20 - } else if (op2 =3D=3D 0x0b || op2 =3D=3D 0xb9) { + } else if (op2 =3D=3D 0x0b) { =20 /* ud2 */ insn->type =3D INSN_BUG; =20 + } else if (op2 =3D=3D 0xb9) { + + /* + * ud1 - only used for the static call trampoline to + * stop speculation. Basically used like an int3. + */ + insn->type =3D INSN_TRAP; + } else if (op2 =3D=3D 0x0d || op2 =3D=3D 0x1f) { =20 /* nopl/nopw */ --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8331F1D61AE; Tue, 3 Sep 2024 04:00:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336040; cv=none; b=byUzh6dmoFUz5Pr3vKMKjfNjCr2sPEjojhO0QRZ8agM7D5Iy6TExyWbd4J6ArqDe9yt5mRt0j8AnaIHzyZRm4+JeAgowtsPPiqVj0KR2kBFIApHveVD7hT0b3BrBahKeoVF8/7oIDdJUmIwfq9AhLXIb2gYIbREcxcrugndzXUo= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336040; c=relaxed/simple; bh=67oHwTiAtqRuquV0JYsJeyGvcVHWHwzQnwQ9KJdp+kE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Liik7keeTtXYGNZyeKPCr+rlxrTZ223voELXymz4nj2sc5eu/w/kpCEdnuWcfRk+gKJhULMJ8f5SR+Yb+02fGYOnKSml1xa7tmHp/7le9+J/naBWzpzPJseeHjVM8Ykc5BsGs3qa5HSnLKa+ZKrhncAsVKEgx7gpumu3q24EbMU= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=R3zgjR+2; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="R3zgjR+2" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9034FC4CECA; Tue, 3 Sep 2024 04:00:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336039; bh=67oHwTiAtqRuquV0JYsJeyGvcVHWHwzQnwQ9KJdp+kE=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=R3zgjR+2Ti2BsDWbzA/ISFoOjQbmnSfmLVRUfUa7lSkG7jbTec1f8PV35TNTNWbcW +hD3eylt46m0LdYgBYr4AwRYEVuHz2qI+RRavUE5rUrDedM0RA7bkiWRjGmjv7Oq8y RHfNqSzNKYbw6m2NY/8emLNTBwnmxiJgq5ykm1J1bQSS4w8wOTWrYEABHAjlrQiXxC goXp87tJkWpDNrEsizZD0nhv2wxsaiYMz5H+2axjv9Bum3DDNTagH4in2TdOxlviwI pt4OzfjkqFzT6yg+OGdJ0dhu9tsG5Eap7CpOeMzxXatzg8hnnRutBj7N6PRrO8SaQP hOGHZatboFHZw== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 21/31] objtool: Fix x86 addend calcuation Date: Mon, 2 Sep 2024 21:00:04 -0700 Message-ID: <43433a745f6db5afb513d015a6181bc40be12b4f.1725334260.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" arch_dest_reloc_offset() hard-codes the addend adjustment to 4, which isn't always true. In fact it's dependent on the instruction itself. Signed-off-by: Josh Poimboeuf --- tools/objtool/arch/loongarch/decode.c | 4 ++-- tools/objtool/arch/powerpc/decode.c | 4 ++-- tools/objtool/arch/x86/decode.c | 15 +++++++++++++-- tools/objtool/check.c | 13 ++++--------- tools/objtool/include/objtool/arch.h | 2 +- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/tools/objtool/arch/loongarch/decode.c b/tools/objtool/arch/loo= ngarch/decode.c index ef09996c772e..b5d44d7bce4e 100644 --- a/tools/objtool/arch/loongarch/decode.c +++ b/tools/objtool/arch/loongarch/decode.c @@ -20,9 +20,9 @@ unsigned long arch_jump_destination(struct instruction *i= nsn) return insn->offset + (insn->immediate << 2); } =20 -unsigned long arch_dest_reloc_offset(int addend) +s64 arch_insn_adjusted_addend(struct instruction *insn, struct reloc *relo= c) { - return addend; + return reloc_addend(addend); } =20 bool arch_pc_relative_reloc(struct reloc *reloc) diff --git a/tools/objtool/arch/powerpc/decode.c b/tools/objtool/arch/power= pc/decode.c index 29e05ad1b8b6..11e59065f1dc 100644 --- a/tools/objtool/arch/powerpc/decode.c +++ b/tools/objtool/arch/powerpc/decode.c @@ -14,9 +14,9 @@ int arch_ftrace_match(const char *name) return !strcmp(name, "_mcount"); } =20 -unsigned long arch_dest_reloc_offset(int addend) +s64 arch_insn_adjusted_addend(struct instruction *insn, struct reloc *relo= c) { - return addend; + return reloc_addend(reloc); } =20 bool arch_callee_saved_reg(unsigned char reg) diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decod= e.c index 72d55dcd3d7f..afebd67d9b9d 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -67,9 +67,20 @@ bool arch_callee_saved_reg(unsigned char reg) } } =20 -unsigned long arch_dest_reloc_offset(int addend) +s64 arch_insn_adjusted_addend(struct instruction *insn, struct reloc *relo= c) { - return addend + 4; + s64 addend =3D reloc_addend(reloc); + + switch (reloc_type(reloc)) { + case R_X86_64_PC32: + case R_X86_64_PLT32: + addend +=3D insn->offset + insn->len - reloc_offset(reloc); + break; + default: + break; + } + + return addend; } =20 unsigned long arch_jump_destination(struct instruction *insn) diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 236dc7871f01..3c8d0903dfa7 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -1461,7 +1461,7 @@ static void add_jump_destinations(struct objtool_file= *file) } else if (sym_has_section(reloc->sym)) { dest_sec =3D reloc->sym->sec; dest_off =3D reloc->sym->sym.st_value + - arch_dest_reloc_offset(reloc_addend(reloc)); + arch_insn_adjusted_addend(insn, reloc); } else { /* External symbol (UNDEF) */ dest_sec =3D NULL; @@ -1609,7 +1609,7 @@ static void add_call_destinations(struct objtool_file= *file) ERROR_INSN(insn, "unsupported call to non-function"); =20 } else if (is_section_symbol(reloc->sym)) { - dest_off =3D arch_dest_reloc_offset(reloc_addend(reloc)); + dest_off =3D arch_insn_adjusted_addend(insn, reloc); dest =3D find_call_destination(reloc->sym->sec, dest_off); if (!dest) ERROR_INSN(insn, "can't find call dest symbol at %s+0x%lx", @@ -3119,7 +3119,7 @@ static bool pv_call_dest(struct objtool_file *file, s= truct instruction *insn) if (!reloc || strcmp(reloc->sym->name, "pv_ops")) return false; =20 - idx =3D (arch_dest_reloc_offset(reloc_addend(reloc)) / sizeof(void *)); + idx =3D (arch_insn_adjusted_addend(insn, reloc) / sizeof(void *)); =20 if (file->pv_ops[idx].clean) return true; @@ -4070,12 +4070,7 @@ static int validate_ibt_insn(struct objtool_file *fi= le, struct instruction *insn if (reloc->sym->static_call_tramp) continue; =20 - off =3D reloc->sym->offset; - if (reloc_type(reloc) =3D=3D R_X86_64_PC32 || - reloc_type(reloc) =3D=3D R_X86_64_PLT32) - off +=3D arch_dest_reloc_offset(reloc_addend(reloc)); - else - off +=3D reloc_addend(reloc); + off =3D reloc->sym->offset + arch_insn_adjusted_addend(insn, reloc); =20 dest =3D find_insn(file, reloc->sym->sec, off); if (!dest) diff --git a/tools/objtool/include/objtool/arch.h b/tools/objtool/include/o= bjtool/arch.h index f48f5109abb1..14911fdfdc8f 100644 --- a/tools/objtool/include/objtool/arch.h +++ b/tools/objtool/include/objtool/arch.h @@ -81,7 +81,7 @@ bool arch_callee_saved_reg(unsigned char reg); =20 unsigned long arch_jump_destination(struct instruction *insn); =20 -unsigned long arch_dest_reloc_offset(int addend); +s64 arch_insn_adjusted_addend(struct instruction *insn, struct reloc *relo= c); =20 const char *arch_nop_insn(int len); const char *arch_ret_insn(int len); --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 922CB1D61B4; Tue, 3 Sep 2024 04:00:40 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336040; cv=none; b=BdQoZ71+yIJBGSym/wr5nlSCfDu2r0/WT66cFL/Ln7akF8uvPwup1GjvTZ+O7GQggI0WWwn0b7/C26nD2rSjc0GWOutILe5pkpa9Xnp1+f3L+QRrlrkdAfKFcZjQ/ZfuDkHJ36HzYfPKeyDC2tTIVnjQm1CSwXO+24cek+OrpjQ= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336040; c=relaxed/simple; bh=K51ZKKek6YNwqc2KmzuJq5BxCeSmLBBJ3r1dJblKcf4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=umhWJP0CqX7W0jOMetjdd9j5hzbXepOc0Qjzd5vf3dL/i9rNU9OD2H/CJYGHjvixAi/p/2Srd3ExzTpZyLv4h4wp/Z6Jj59inae+6jqG/1Q6svJhAx/ADp6ZxjrWhRSU1i0ZY9aEGhRwGfmPp8H5CL4hJ6tWBl98VM7287tUzJI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=D580FoCP; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="D580FoCP" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 194F4C4CEC7; Tue, 3 Sep 2024 04:00:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336040; bh=K51ZKKek6YNwqc2KmzuJq5BxCeSmLBBJ3r1dJblKcf4=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=D580FoCP7B1SrYC6jLwS/tc6+JhsvVMSsPDF9QUluKX/ENwtHXVIERXvCuUEASrsk tOk496q0Q3YpG17t4wD1I8pHxAmIhL1LaPEUsN0SjDeDXwIhg9k+T8vjUI7fc96dZI XEo9+Ds4UeEBd1WJPDfgnXW9kpLdSb1cKmLR2mipGF3+/FthrA+bd+nqMibdrIEzyB YzoOEYiUjRIlCcwYHLXhXS/usqNHwvoLYqSo7DXFFhKVaPs75/CcnR8diEab2vKqxv QspsXpCQ+gbHqCudddoIe0xbKjTGQ4GlhIOgAuc/roiBMPcZgkCdCPe2YJRu7iNEtH dfSuQWpZ0cTrw== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 22/31] objtool: Make find_symbol_containing() less arbitrary Date: Mon, 2 Sep 2024 21:00:05 -0700 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" In the rare case of overlapping symbols, find_symbol_containing() just returns the first one it finds. Make it less arbitrary by returning the smallest symbol with size > 0. Eventually we should consider making such overlapping symbols illegal. Signed-off-by: Josh Poimboeuf --- tools/objtool/elf.c | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 7f89b0a99886..49528e7835aa 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -195,14 +195,29 @@ struct symbol *find_func_by_offset(struct section *se= c, unsigned long offset) struct symbol *find_symbol_containing(const struct section *sec, unsigned = long offset) { struct rb_root_cached *tree =3D (struct rb_root_cached *)&sec->symbol_tre= e; - struct symbol *iter; + struct symbol *sym =3D NULL, *tmp; =20 - __sym_for_each(iter, tree, offset, offset) { - if (iter->type !=3D STT_SECTION) - return iter; + __sym_for_each(tmp, tree, offset, offset) { + if (tmp->len) { + if (!sym) { + sym =3D tmp; + continue; + } + + if (sym->offset !=3D tmp->offset || sym->len !=3D tmp->len) { + /* + * In the rare case of overlapping symbols, + * pick the smaller one. + * + * TODO: outlaw overlapping symbols + */ + if (tmp->len < sym->len) + sym =3D tmp; + } + } } =20 - return NULL; + return sym; } =20 /* --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 245AB1D2F52; Tue, 3 Sep 2024 04:00:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336041; cv=none; b=Dr1ly6mn9+Li+1B1CLtOegIXGalah8drNECEibSeeAlJ0ve6eTPrdnt0lOqOu5KzcOOwG0OLIIUoJ6Fo31yXm4XT+fnnaHwDE5PWasg8s/wimS3FShqiwl15CcFFybXoEtz81/xR0U4KXC2P/CYAKnc6zo8f2YiFn5Jg+dwd9M4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336041; c=relaxed/simple; bh=mTzu1+CtgHG6mSPrVj5zmYy4j+KYldxKNu+MHa7dpDg=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=UfTgfP9ylrZE28Iq/2BVf5nu1+q3Y417LmDMDEuyGm0LXEhZCuXlu6acYHJn517R8OWguD8EofD9d6kkFQ0ewSK8T/wMKKZZ9MjQSGuLTkwbCXCgtJlhn1JpokV2IesEdgGgb9dx97xkdJ+3VjbMccExbcDQy47d71mtIXURpck= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=oyCqSnga; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="oyCqSnga" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 96F92C4CEC5; Tue, 3 Sep 2024 04:00:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336041; bh=mTzu1+CtgHG6mSPrVj5zmYy4j+KYldxKNu+MHa7dpDg=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=oyCqSngaSWpeL2IoAalav9kXFFqviQ8D/ljLAWZKt3Vei5UJ1OUimL/63RluqehtS NRWf2CvZq6GiXC1l094ffFuqtzb3+QlkQU4cSHjb3Wrt/7Yt5bqiCIRclCDSskurcp bjAIbLYRtXcRQVvQphcHvq+ad5y66uQBXeFPRgF9PKypZ4eUDPG6BY49ONItdZDgd0 P7FgTBAq/tZHKfCOZ9n7dcyYqHpb4bfplnqYes1rtfv1RZkke0JAnGJnWvOlv31bl5 33Mkz3Wtc42CeR9O8SRv4DmZ6hPv4DUFoaaIu2SQLMiMFiMNArk678z/azLZiD64Nx Lkk1XLAJ3MK3g== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 23/31] objtool: Handle __pa_symbol() relocations Date: Mon, 2 Sep 2024 21:00:06 -0700 Message-ID: <9b5ebea4361ec1a5471b6b2e86d6657b5685c72d.1725334260.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" A relocation created by __pa_symbol() has a large addend referring to a physical address. Convert it to back its virtual form before calculating the addend. Signed-off-by: Josh Poimboeuf --- tools/objtool/arch/x86/decode.c | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decod= e.c index afebd67d9b9d..5468fd15f380 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -67,6 +67,17 @@ bool arch_callee_saved_reg(unsigned char reg) } } =20 +/* undo the effects of __pa_symbol() if necessary */ +static unsigned long phys_to_virt(unsigned long pa) +{ + s64 va =3D pa; + + if (va > 0) + va &=3D ~(0x80000000); + + return va; +} + s64 arch_insn_adjusted_addend(struct instruction *insn, struct reloc *relo= c) { s64 addend =3D reloc_addend(reloc); @@ -80,7 +91,7 @@ s64 arch_insn_adjusted_addend(struct instruction *insn, s= truct reloc *reloc) break; } =20 - return addend; + return phys_to_virt(addend); } =20 unsigned long arch_jump_destination(struct instruction *insn) --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 96EC41D6C41; Tue, 3 Sep 2024 04:00:41 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336041; cv=none; b=D8+n/OPVJa0u+iBcBWhkRb2iOUKDSCh8c6DZgwHCNiWe7gV6rOHQ9dPwWY5qlcSZ6qnHsBnYOnro0lbY1IV2Q/M6wUmRjKDY3oxQ5FVOizTqosjoCS92W/uhmiA9bHuhRZcmi2RhPiVES0GIdwXQvEaiCaUvc78zkZ06Uig1qwg= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336041; c=relaxed/simple; bh=XXdyiXX1GCdB3j+QVtVXuuqcqiTXMHJpdUI+rw+aD2A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Sn2XxXdbx5xzpvwcl7XjaTUkJ++ITqAooEL2/1BPoMZWazFfEn3Mrs8d1OOAnslrQgy4YeS1be77zo/vRt7Uvt1hEg28l3lMsTTr8b73F9W3oVW+Rotl3p7dvTUIS3Jz2v5Bu6xcbnAJ3D3381B74Z0mrg4QZIOQIQGyBFjw/uQ= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=nOZ/0hSz; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="nOZ/0hSz" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 20D38C4CEC7; Tue, 3 Sep 2024 04:00:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336041; bh=XXdyiXX1GCdB3j+QVtVXuuqcqiTXMHJpdUI+rw+aD2A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=nOZ/0hSzrhoDJ1VxreT/niydB1BKi8c0ddJX2Q5wgb2YqQa3bl/5Oytkyz/uXv05r P5jFSjUUNAg2xJUmWvnU+gGet5QfcA2DuYhqp1XZpcP5tKXEaR6oWaPG4BjWfJdOFB qOU+V21nyr0Rk7W2gKCrJu0mv+Nl5XCt0uM5abFcMG7U3lHK9NFWzwzCesS3ej/Bnd ntoS5iTJsYfu9iLgRPJqmRU+Cr1cLdi/aQxFUwV0upWhy3umvurRrZb9EeT3faOUe4 5wNwdJAxL/0u3c6aSx7Oj6GD8GAUoMuCkkEtuBOanFvGT4gD+WVzh8RvcPu8L2rj0u dHhnyM2u15Ljw== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 24/31] objtool: Make STACK_FRAME_NON_STANDARD consistent Date: Mon, 2 Sep 2024 21:00:07 -0700 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" The C version of STACK_FRAME_NON_STANDARD differs from its asm counterpart: - it uses an 8-byte entry (vs 4-byte) - it creates a superfluous temporary variable Make it identical to the asm version. Signed-off-by: Josh Poimboeuf --- include/linux/objtool.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/include/linux/objtool.h b/include/linux/objtool.h index b3b8d3dab52d..5e66b6d26df5 100644 --- a/include/linux/objtool.h +++ b/include/linux/objtool.h @@ -30,9 +30,10 @@ * * For more information, see tools/objtool/Documentation/objtool.txt. */ -#define STACK_FRAME_NON_STANDARD(func) \ - static void __used __section(".discard.func_stack_frame_non_standard") \ - *__func_stack_frame_non_standard_##func =3D func +#define STACK_FRAME_NON_STANDARD(func) \ + asm(".pushsection .discard.func_stack_frame_non_standard, \"aw\"\n\t" \ + ".long " __stringify(func) " - .\n\t" \ + ".popsection") =20 /* * STACK_FRAME_NON_STANDARD_FP() is a frame-pointer-specific function igno= re --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 289961D6C66; Tue, 3 Sep 2024 04:00:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336042; cv=none; b=S90HQN0Q2FW3+WhXG9mwAvJgMQygRYNXc+7pNWtA3DlgSNt+a5EFKLwHozgYrBSNKBUqr7JFW8nDfGRplaoeDBRbcddv3MeEBeWKOb8xOvxXuVU/fE9EoJJ+t909/5ya9uTDeZM86cWnNLBn8RpIX12Y2GbWVG59/Mfcj1qpqFM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336042; c=relaxed/simple; bh=Sc4bf3ztjo9/6o7oLEQrV45T7l6aiZqsKA2dwcuesFo=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=dg/A0MoldAiNm0Ym0lv15nSZzUnG8P0F2cQG1GzoguM/fg2BHi3DSQrRro5kM4ktK13T4GrmKxi/2508ZWuG28kwbqWackXbRJpbrQPJu1A7mF3jKPv2jHqHyDX+For6v72TY76xPsoj75csCSd7oh0p9m/qEeOIqQCzKB7b9KA= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=MKosp2+X; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="MKosp2+X" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 9C7B4C4CEC5; Tue, 3 Sep 2024 04:00:41 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336042; bh=Sc4bf3ztjo9/6o7oLEQrV45T7l6aiZqsKA2dwcuesFo=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=MKosp2+XsmJIQk4/BTZehZ+u7F8+HtUtBg9voxcg8+cXBQWT08F1090LpLv8coNw+ yAm81iQ2dkvyd/rX+1DDCn181CLS5QrBAhl4Mdqd6v141BV5l24cqdpwb06nbLN/78 yMZBIcD7OEwMU8p89OmnQfnf2imdHHhsYqDeGcMb/M7+dzM2mWXTenvJL/tTj2oQB4 QcjO/2/Du6y8GBSZV/bD7iKvhf33ukexisjU1mn8OImVA/D7GfAn01r8yw3tRk53HV hYmqFdCj4U5F1SpC0IL4RgE3Mg1lQtxh3EK6veJndYxnKaFK0sMrcLAF8ZA8uNcXvF wNWmxe+teGp9g== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 25/31] objtool: Fix interval tree insertion for zero-length symbols Date: Mon, 2 Sep 2024 21:00:08 -0700 Message-ID: <5b44cec6fa1b80b7059e557e5b37a3a673e27e90.1725334260.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Zero-length symbols get inserted in the wrong spot. Fix that. Signed-off-by: Josh Poimboeuf --- tools/objtool/elf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 49528e7835aa..42a657268306 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -94,7 +94,7 @@ static inline unsigned long __sym_start(struct symbol *s) =20 static inline unsigned long __sym_last(struct symbol *s) { - return s->offset + s->len - 1; + return s->offset + (s->len ? s->len - 1 : 0); } =20 INTERVAL_TREE_DEFINE(struct symbol, node, unsigned long, __subtree_last, --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B2FA41D6DB1; Tue, 3 Sep 2024 04:00:42 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336042; cv=none; b=sHy7ZwbuonJOTljdD6AqPMOhzpj5rxAjmtcgCScd87cdtFxYA74S2uuWry0IipwVfxHRscUEi1XuzeqdUoTyEAz6faH5WWQSDc8OuhzvwFWq/j1tjFar3qHHFd8fQNvbdImYzSPjWhor3pqUhftK+QHOOXye2kFl7TwmWeerlB4= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336042; c=relaxed/simple; bh=aitFbO2kW3aH4lB1//9h+v3atK493HEbsCZmttf5L+M=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=eWKW+lhLcyz8h6eBLZQI3QjTgNAi/RjZ+1fBFL/bhW9LSLh6MIJ/WivQYl03YIwgypKouKw5Ghauv9klIK5vkpIWn3L0HUbtQMfczubvNjQd1ZJFUqwv427naelajIuc660m5aU55gHE2LmFn35dcjt1LorQKGJXl5hKPxRLWOg= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZTd0fV8b; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZTd0fV8b" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 2E489C4CEC8; Tue, 3 Sep 2024 04:00:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336042; bh=aitFbO2kW3aH4lB1//9h+v3atK493HEbsCZmttf5L+M=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=ZTd0fV8bpl8TJ1xemo40S/ioC5OMTo85cAwtGEFaE9Ehnpd+cxsc69EYUM6LrRS7n rpzNu9A43aQcut60QAnfdgpcpbWhWHWPGiF65ljGRb60toQU1Ms8FIpEf+PIGRnI0s psmEioof7Mhqrmm1CIrmUOpWko8ChtOQ+yV2BmOYNSO3JgSsEYzMdVXZevj2ygXFC7 0KaAh87ZOfwcUDjUpOEvpUk1mUjn3EIeiiVzgNGnMQC9jcuAtmD2pM4ENegHvjvipi VU+bMmpECTvjz2G+FDBMA4f43gj1WxqgKx/2zTS1cYNw17w/C+Ppyi2rO9+Ha4Vcia OTF+HM4NxAEPg== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 26/31] objtool: Make interval tree functions "static inline" Date: Mon, 2 Sep 2024 21:00:09 -0700 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Otherwise the compiler warns if a function isn't used. Signed-off-by: Josh Poimboeuf --- tools/objtool/elf.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 42a657268306..471df0336aa7 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -98,7 +98,7 @@ static inline unsigned long __sym_last(struct symbol *s) } =20 INTERVAL_TREE_DEFINE(struct symbol, node, unsigned long, __subtree_last, - __sym_start, __sym_last, static, __sym) + __sym_start, __sym_last, static inline, __sym) =20 #define __sym_for_each(_iter, _tree, _start, _end) \ for (_iter =3D __sym_iter_first((_tree), (_start), (_end)); \ --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 3F2231D6DD4; Tue, 3 Sep 2024 04:00:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336043; cv=none; b=fGN2/kUwTwugriaGHbZ1BjbmX40N52UoL0G05dGMGeU+H4CeTxZ4BO2GhyCcIloXmQoRQmO9ghwe81DsV02JgNTFL5zVKU9qcePyB/EfUfz+1Kl/hUZXlktDEefQxhFa8S8L+DFYCcb6yBKiNABqdLKx6qFXu3kew4DR9GCdBbM= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336043; c=relaxed/simple; bh=MTklontumUzZpdX06cPRFX4LLGHwOyI3SJ4gnMlG+5A=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=EqwzY9xM7rafhHguzCaXBP4toq0YjqJaiP9uEZLx/o3peBda8mLwJQt8IOsbJO8F81+PANKNq2T7xDkStt8DonOwe1dkns65Hgie/R8TDUYEJiesyAFB0a76Y6dsb9kEZqdwFigcbVb4MsWY9BrJ3QLr108WENgbXRpvCUZ7HFY= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=rAdGF1dJ; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="rAdGF1dJ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id B95CAC4CED0; Tue, 3 Sep 2024 04:00:42 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336043; bh=MTklontumUzZpdX06cPRFX4LLGHwOyI3SJ4gnMlG+5A=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rAdGF1dJMDPP8zNlF+p8n1XV4xPxBRGG/Bv+Jb2iJvdB2xHaW56BCDxCYbIi7wPkB Zpdso/ZPTLOygEdTCJ0rYCQLE3bsbIj1G/V+e9CKbRgmH6OTf6gArRvo2pIKeRsfst +sLQyLP3qW6Wfm7ueZsVuLtwCDYSz8ykT/ZZ0r2Mm7qQ9joroZ3bnmuTUg+b1cUCb1 pQmObfe8HyBxpZisGhJYtpgRWE+21KPuEZe9elZpOpfdCJ8dbHGDeoK8ui1lWd5Uly O78nrLS+ktGnjWK2S6oIZRSfBC9r8s3o0S+Ck5O9hdoruGb/wNStbZKK1j9Yh6ei6q VvXfGR1o+DDqw== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 27/31] objtool: Fix weak symbol detection Date: Mon, 2 Sep 2024 21:00:10 -0700 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" find_symbol_hole_containing() fails to find a symbol hole (aka stripped weak symbol) if its section has no symbols before the hole. This breaks weak symbol detection if -ffunction-sections is enabled. Fix it by allowing the interval tree to contain section symbols, which are always at offset zero for a given section. Fixes a bunch of (-ffunction-sections) warnings like: vmlinux.o: warning: objtool: .text.__x64_sys_io_setup+0x10: unreachable i= nstruction vmlinux.o: warning: objtool: .text.__x64_sys_io_setup+0x14: unreachable i= nstruction vmlinux.o: warning: objtool: .text.__x64_sys_io_setup+0x19: unreachable i= nstruction vmlinux.o: warning: objtool: .text.__x64_sys_io_setup+0x20: unreachable i= nstruction Fixes: 4adb23686795 ("objtool: Ignore extra-symbol code") Signed-off-by: Josh Poimboeuf --- tools/objtool/elf.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 471df0336aa7..3109277804cc 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -110,7 +110,7 @@ struct symbol_hole { }; =20 /* - * Find !section symbol where @offset is after it. + * Find the last symbol before @offset. */ static int symbol_hole_by_offset(const void *key, const struct rb_node *no= de) { @@ -121,8 +121,7 @@ static int symbol_hole_by_offset(const void *key, const= struct rb_node *node) return -1; =20 if (sh->offset >=3D s->offset + s->len) { - if (s->type !=3D STT_SECTION) - sh->sym =3D s; + sh->sym =3D s; return 1; } =20 @@ -416,7 +415,8 @@ static void elf_add_symbol(struct elf *elf, struct symb= ol *sym) sym->len =3D sym->sym.st_size; =20 __sym_for_each(s, &sym->sec->symbol_tree, sym->offset, sym->offset) { - if (s->offset =3D=3D sym->offset && s->type =3D=3D sym->type) + if (s->type =3D=3D sym->type && s->offset =3D=3D sym->offset && + s->len =3D=3D sym->len) s->alias =3D sym; } =20 @@ -433,9 +433,13 @@ static void elf_add_symbol(struct elf *elf, struct sym= bol *sym) /* * Don't store empty STT_NOTYPE symbols in the rbtree. They * can exist within a function, confusing the sorting. + * + * TODO: is this still true? */ - if (!sym->len) +#if 0 + if (sym->type =3D=3D STT_NOTYPE && !sym->len) __sym_remove(sym, &sym->sec->symbol_tree); +#endif } =20 static void read_symbols(struct elf *elf) --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 1FF9A1DAC7C; Tue, 3 Sep 2024 04:00:43 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336044; cv=none; b=YpMy1DwubzxoDZHbz5cwWF9bEr/GFH2tDYGJyMVBu+7TYFFcjoD4KkXAQuAXjdze3JlvpAFXXfbHVHaSmyFDwpf5lhhQnhj8cqdbJvGtqbespZNMQettiwjDxsT+UvRf5ZMp5rEHIY6ogDxsG5OL0xi426OGIsDfN/f2RriQWfc= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336044; c=relaxed/simple; bh=1honWldDE9HPro70aVWOosNOZlcXniv/IfkuI0B+mzc=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=rTO1svyu9SVsrrVt3tUKCRJ5DuHVPP7TeczEJEyiLXhHBWYY0g052Hx9I7/Hi9Oh/hViQBK+dOFICxt2xmd7HyA3g/paNKTUvgcedvW/evOrR5Tz61n1Buzndze07jDfxGSA9HP0KbL0gOrHE9fzW4JMe+Ge1NasjHA0yGSgU94= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=rxbI3mU7; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="rxbI3mU7" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 42DC5C4CEC5; Tue, 3 Sep 2024 04:00:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336043; bh=1honWldDE9HPro70aVWOosNOZlcXniv/IfkuI0B+mzc=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=rxbI3mU7AbF5OwNxmY4B3N+/RwJwaKl66aeqNKAoM96V1Wbxk71uumDDogn329ofu 2DNcwcbWk33Sxd1q/js1ZioDL5nWJu2cZjcqBCMR719gajJR6guVK4CMPqxlRS1y4P r/QlL00xn4X2jre6EtC9ceuN+0Q/ZY//hdR0ZEglggUdHJnoxYOdLoM1N8FwQkOf7X HtINPBWeWl9EXjf8DissOrONz6TU9OPxssjDs/z/vL7IiJKXhElQRfESdu40YbvUgB 1cByk6YraAUGryt1W/4LTesxeEeg/wWriD5b8uVp42lPkrv+JX+xdNxdcpFIWfyTWG 8Fdqz1h60aMjA== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 28/31] x86/alternative: Create symbols for special section entries Date: Mon, 2 Sep 2024 21:00:11 -0700 Message-ID: <7bc1bcb1cd875350948f43c77c9895173bd22012.1725334260.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Create a symbol for each special section entry. This helps objtool extract needed entries. Signed-off-by: Josh Poimboeuf --- arch/x86/include/asm/alternative.h | 50 ++++++++++++++++++++---------- arch/x86/include/asm/asm.h | 24 +++++++++----- arch/x86/include/asm/bug.h | 2 ++ arch/x86/include/asm/cpufeature.h | 2 ++ arch/x86/include/asm/jump_label.h | 2 ++ include/linux/objtool.h | 31 +++++++++++++++++- tools/objtool/check.c | 22 +++++++++++-- 7 files changed, 104 insertions(+), 29 deletions(-) diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alte= rnative.h index ba99ef75f56c..2617253bcb00 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -157,7 +157,9 @@ static inline int alternatives_text_reserved(void *star= t, void *end) #define ALT_CALL_INSTR "call BUG_func" =20 #define b_replacement(num) "664"#num -#define e_replacement(num) "665"#num + +#define __e_replacement(num) __PASTE(665, num) +#define e_replacement(num) __stringify(__e_replacement(num)) =20 #define alt_end_marker "663" #define alt_slen "662b-661b" @@ -203,15 +205,21 @@ static inline int alternatives_text_reserved(void *st= art, void *end) alt_end_marker ":\n" =20 #define ALTINSTR_ENTRY(ft_flags, num) \ + FAKE_SYMBOL(__alt_, 681f) \ " .long 661b - .\n" /* label */ \ " .long " b_replacement(num)"f - .\n" /* new instruction */ \ " .4byte " __stringify(ft_flags) "\n" /* feature + flags */ \ " .byte " alt_total_slen "\n" /* source len */ \ - " .byte " alt_rlen(num) "\n" /* replacement len */ + " .byte " alt_rlen(num) "\n" /* replacement len */ \ + "681:\n" =20 -#define ALTINSTR_REPLACEMENT(newinstr, num) /* replacement */ \ +#define ALTINSTR_REPLACEMENT(newinstr, num) \ "# ALT: replacement " #num "\n" \ - b_replacement(num)":\n\t" newinstr "\n" e_replacement(num) ":\n" + FAKE_SYMBOL(__alt_instr_, __PASTE(__e_replacement(num), f)) \ + b_replacement(num) ":\n" \ + "\t" newinstr "\n" \ + e_replacement(num) ":\n" + =20 /* alternative assembly primitive: */ #define ALTERNATIVE(oldinstr, newinstr, ft_flags) \ @@ -370,12 +378,20 @@ void nop_func(void); * enough information for the alternatives patching code to patch an * instruction. See apply_alternatives(). */ -.macro altinstr_entry orig alt ft_flags orig_len alt_len +.macro ALTINSTR_ENTRY orig alt ft_flags orig_len alt_len + FAKE_SYMBOL(__alt_, 681f) .long \orig - . .long \alt - . .4byte \ft_flags .byte \orig_len .byte \alt_len + 681: +.endm + +.macro ALTINSTR_REPLACEMENT newinstr + FAKE_SYMBOL(__alt_instr_, 681f) + \newinstr + 681: .endm =20 .macro ALT_CALL_INSTR @@ -396,12 +412,12 @@ void nop_func(void); 142: =20 .pushsection .altinstructions,"a" - altinstr_entry 140b,143f,\ft_flags,142b-140b,144f-143f + ALTINSTR_ENTRY 140b,143f,\ft_flags,142b-140b,144f-143f .popsection =20 .pushsection .altinstr_replacement,"ax" 143: - \newinstr + ALTINSTR_REPLACEMENT "\newinstr" 144: .popsection .endm @@ -435,15 +451,15 @@ void nop_func(void); 142: =20 .pushsection .altinstructions,"a" - altinstr_entry 140b,143f,\ft_flags1,142b-140b,144f-143f - altinstr_entry 140b,144f,\ft_flags2,142b-140b,145f-144f + ALTINSTR_ENTRY 140b,143f,\ft_flags1,142b-140b,144f-143f + ALTINSTR_ENTRY 140b,144f,\ft_flags2,142b-140b,145f-144f .popsection =20 .pushsection .altinstr_replacement,"ax" 143: - \newinstr1 + ALTINSTR_REPLACEMENT "\newinstr1" 144: - \newinstr2 + ALTINSTR_REPLACEMENT "\newinstr2" 145: .popsection .endm @@ -457,18 +473,18 @@ void nop_func(void); 142: =20 .pushsection .altinstructions,"a" - altinstr_entry 140b,143f,\ft_flags1,142b-140b,144f-143f - altinstr_entry 140b,144f,\ft_flags2,142b-140b,145f-144f - altinstr_entry 140b,145f,\ft_flags3,142b-140b,146f-145f + ALTINSTR_ENTRY 140b,143f,\ft_flags1,142b-140b,144f-143f + ALTINSTR_ENTRY 140b,144f,\ft_flags2,142b-140b,145f-144f + ALTINSTR_ENTRY 140b,145f,\ft_flags3,142b-140b,146f-145f .popsection =20 .pushsection .altinstr_replacement,"ax" 143: - \newinstr1 + ALTINSTR_REPLACEMENT "\newinstr1" 144: - \newinstr2 + ALTINSTR_REPLACEMENT "\newinstr2" 145: - \newinstr3 + ALTINSTR_REPLACEMENT "\newinstr3" 146: .popsection .endm diff --git a/arch/x86/include/asm/asm.h b/arch/x86/include/asm/asm.h index 2bec0c89a95c..c337240d342c 100644 --- a/arch/x86/include/asm/asm.h +++ b/arch/x86/include/asm/asm.h @@ -2,6 +2,8 @@ #ifndef _ASM_X86_ASM_H #define _ASM_X86_ASM_H =20 +#include + #ifdef __ASSEMBLY__ # define __ASM_FORM(x, ...) x,## __VA_ARGS__ # define __ASM_FORM_RAW(x, ...) x,## __VA_ARGS__ @@ -149,9 +151,11 @@ static __always_inline __pure void *rip_rel_ptr(void *= p) # define _ASM_EXTABLE_TYPE(from, to, type) \ .pushsection "__ex_table","a" ; \ .balign 4 ; \ + FAKE_SYMBOL(__ex_table_, 555f) ; \ .long (from) - . ; \ .long (to) - . ; \ .long type ; \ + 555: ; \ .popsection =20 # ifdef CONFIG_KPROBES @@ -196,19 +200,23 @@ static __always_inline __pure void *rip_rel_ptr(void = *p) # define _ASM_EXTABLE_TYPE(from, to, type) \ " .pushsection \"__ex_table\",\"a\"\n" \ " .balign 4\n" \ + FAKE_SYMBOL(__ex_table_, 555f) \ " .long (" #from ") - .\n" \ " .long (" #to ") - .\n" \ " .long " __stringify(type) " \n" \ + " 555:\n" \ " .popsection\n" =20 -# define _ASM_EXTABLE_TYPE_REG(from, to, type, reg) \ - " .pushsection \"__ex_table\",\"a\"\n" \ - " .balign 4\n" \ - " .long (" #from ") - .\n" \ - " .long (" #to ") - .\n" \ - DEFINE_EXTABLE_TYPE_REG \ - "extable_type_reg reg=3D" __stringify(reg) ", type=3D" __stringify(type) = " \n"\ - UNDEFINE_EXTABLE_TYPE_REG \ +# define _ASM_EXTABLE_TYPE_REG(from, to, type, reg) \ + " .pushsection \"__ex_table\",\"a\"\n" \ + " .balign 4\n" \ + FAKE_SYMBOL(__ex_table_, 555f) \ + " .long (" #from ") - .\n" \ + " .long (" #to ") - .\n" \ + DEFINE_EXTABLE_TYPE_REG \ + "extable_type_reg reg=3D" __stringify(reg) ", type=3D" __stringify(type) = " \n" \ + UNDEFINE_EXTABLE_TYPE_REG \ + " 555:\n" \ " .popsection\n" =20 /* For C file, we already have NOKPROBE_SYMBOL macro */ diff --git a/arch/x86/include/asm/bug.h b/arch/x86/include/asm/bug.h index a3ec87d198ac..86304d7d68f5 100644 --- a/arch/x86/include/asm/bug.h +++ b/arch/x86/include/asm/bug.h @@ -27,6 +27,7 @@ do { \ asm_inline volatile("1:\t" ins "\n" \ ".pushsection __bug_table,\"aw\"\n" \ + FAKE_SYMBOL(__bug_table_, . + %c3) \ "2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n" \ "\t" __BUG_REL(%c0) "\t# bug_entry::file\n" \ "\t.word %c1" "\t# bug_entry::line\n" \ @@ -45,6 +46,7 @@ do { \ do { \ asm_inline volatile("1:\t" ins "\n" \ ".pushsection __bug_table,\"aw\"\n" \ + FAKE_SYMBOL(__bug_table_, . + %c1) \ "2:\t" __BUG_REL(1b) "\t# bug_entry::bug_addr\n" \ "\t.word %c0" "\t# bug_entry::flags\n" \ "\t.org 2b+%c1\n" \ diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufe= ature.h index 0b9611da6c53..9decf644d55a 100644 --- a/arch/x86/include/asm/cpufeature.h +++ b/arch/x86/include/asm/cpufeature.h @@ -178,9 +178,11 @@ static __always_inline bool _static_cpu_has(u16 bit) asm goto(ALTERNATIVE_TERNARY("jmp 6f", %c[feature], "", "jmp %l[t_no]") ".pushsection .altinstr_aux,\"ax\"\n" "6:\n" + FAKE_SYMBOL(__alt_aux_, 681f) " testb %[bitnum], %a[cap_byte]\n" " jnz %l[t_yes]\n" " jmp %l[t_no]\n" + "681:\n" ".popsection\n" : : [feature] "i" (bit), [bitnum] "i" (1 << (bit & 7)), diff --git a/arch/x86/include/asm/jump_label.h b/arch/x86/include/asm/jump_= label.h index cbbef32517f0..731d7e69d244 100644 --- a/arch/x86/include/asm/jump_label.h +++ b/arch/x86/include/asm/jump_label.h @@ -15,9 +15,11 @@ #define JUMP_TABLE_ENTRY \ ".pushsection __jump_table, \"aw\" \n\t" \ _ASM_ALIGN "\n\t" \ + FAKE_SYMBOL(__jump_table_, 2f) \ ".long 1b - . \n\t" \ ".long %l[l_yes] - . \n\t" \ _ASM_PTR "%c0 + %c1 - .\n\t" \ + "2:\n\t" \ ".popsection \n\t" =20 #ifdef CONFIG_HAVE_JUMP_LABEL_HACK diff --git a/include/linux/objtool.h b/include/linux/objtool.h index 5e66b6d26df5..ae5030cac10d 100644 --- a/include/linux/objtool.h +++ b/include/linux/objtool.h @@ -10,9 +10,27 @@ =20 #ifndef __ASSEMBLY__ =20 -#define UNWIND_HINT(type, sp_reg, sp_offset, signal) \ +#define DEFINE_FAKE_SYMBOL \ + ".macro fake_symbol name, end\n\t" \ + "#ifdef __x86_64__\n" \ + ".type \\name\\@, @object\n" \ + ".size \\name\\@, \\end - .\n" \ + "\\name\\@:\n" \ + "#endif\n" \ + ".endm\n\t" + +#define UNDEFINE_FAKE_SYMBOL \ + ".purgem fake_symbol\n\t" + +#define FAKE_SYMBOL(name, end) \ + DEFINE_FAKE_SYMBOL \ + "fake_symbol " __stringify(name) ", \"" __stringify(end) "\"\n\t" \ + UNDEFINE_FAKE_SYMBOL + +#define UNWIND_HINT(type, sp_reg, sp_offset, signal) \ "987: \n\t" \ ".pushsection .discard.unwind_hints\n\t" \ + FAKE_SYMBOL(__unwind_hint_, 988f) \ /* struct unwind_hint */ \ ".long 987b - .\n\t" \ ".short " __stringify(sp_offset) "\n\t" \ @@ -20,6 +38,7 @@ ".byte " __stringify(type) "\n\t" \ ".byte " __stringify(signal) "\n\t" \ ".balign 4 \n\t" \ + "988:\n\t" \ ".popsection\n\t" =20 /* @@ -60,6 +79,14 @@ =20 #else /* __ASSEMBLY__ */ =20 +.macro fake_symbol name, end + .type \name\@, @object + .size \name\@, \end - . + \name\@: +.endm + +#define FAKE_SYMBOL(name, end) fake_symbol name, __stringify(end) + /* * This macro indicates that the following intra-function call is valid. * Any non-annotated intra-function call will cause objtool to issue a war= ning. @@ -94,6 +121,7 @@ .macro UNWIND_HINT type:req sp_reg=3D0 sp_offset=3D0 signal=3D0 .Lhere_\@: .pushsection .discard.unwind_hints + FAKE_SYMBOL(__unwind_hint_, .Lend_\@) /* struct unwind_hint */ .long .Lhere_\@ - . .short \sp_offset @@ -101,6 +129,7 @@ .byte \type .byte \signal .balign 4 + .Lend_\@: .popsection .endm =20 diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 3c8d0903dfa7..5dd78a7f75c3 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -633,6 +633,18 @@ static void add_dead_ends(struct objtool_file *file) } } =20 +static void create_fake_symbol(struct objtool_file *file, const char *name= _pfx, + struct section *sec, unsigned long offset, + size_t size) +{ + char name[256]; + static int ctr; + + snprintf(name, 256, "%s_%d", name_pfx, ctr++); + + elf_create_symbol(file->elf, name, sec, STB_LOCAL, STT_OBJECT, offset, si= ze); +} + static void create_static_call_sections(struct objtool_file *file) { struct static_call_site *site; @@ -664,10 +676,11 @@ static void create_static_call_sections(struct objtoo= l_file *file) =20 idx =3D 0; list_for_each_entry(insn, &file->static_call_list, call_node) { + unsigned long offset =3D idx * sizeof(*site); =20 /* populate reloc for 'addr' */ - elf_init_reloc_text_sym(file->elf, sec, idx * sizeof(*site), - idx * 2, insn->sec, insn->offset); + elf_init_reloc_text_sym(file->elf, sec, offset, idx * 2, + insn->sec, insn->offset); =20 /* find key symbol */ key_name =3D strdup(insn_call_dest(insn)->name); @@ -698,10 +711,13 @@ static void create_static_call_sections(struct objtoo= l_file *file) free(key_name); =20 /* populate reloc for 'key' */ - elf_init_reloc_data_sym(file->elf, sec, idx * sizeof(*site) + 4, + elf_init_reloc_data_sym(file->elf, sec, offset + 4, (idx * 2) + 1, key_sym, is_sibling_call(insn) * STATIC_CALL_SITE_TAIL); =20 + create_fake_symbol(file, "__static_call_site_", sec, + offset, sizeof(*site)); + idx++; } } --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8747520011E; Tue, 3 Sep 2024 04:00:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336044; cv=none; b=GQltXHwzvB3yxKdNly/WljCjvYERPeh68+rXahc0sY2CXy8v2TosSqWCBi3fq4bWM6L6Vu7POfmqhd2bCo7Vfa3K4ikbaXqKg8pjysvaJM+jGVtFhkvG3YC6uzOrmbuzKSWgIZ9ALbUTwmmHMwF8Thmux+SMCODrD6spCNw8rSI= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336044; c=relaxed/simple; bh=KhD/6JeYp0HzWzUQGCZwBMmcsHO1K5HE8VDDwOmizj8=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=j7boxCK70In8JpY/AtcISOw3pxkoqkVD64C/f/e6SgSNiPmVYIsbA+nCON2PwSF3i+4kRzRMa3vPrgC5/geXVMjeWdzqlU5aVoG3Srr3vJuXErGFaWoWXQOYFnKv45V3hZl2kKSVT37/+mbUiMqgKjLhqyCOxtBtUS1qe6JkaY0= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=iJNVwzJv; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="iJNVwzJv" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C06F2C4CECA; Tue, 3 Sep 2024 04:00:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336044; bh=KhD/6JeYp0HzWzUQGCZwBMmcsHO1K5HE8VDDwOmizj8=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=iJNVwzJvPzcxAR0nAQ2qiqUpjHFtFxBvFbS18VaJDuHX/Gl+36PQM9PBFWjxR+aOQ bvEe5zSrSZsLMtgntI3ufwCuEIG5FaBzrIYyTMu3BDKZwiMCAWPxuj3DIY3rPRnfED uZ4dhtzHCPBUYSOgTPrP6VuOw4DwHbKN7LU8L8LlbUkUOmQEvuCpjCWzPBFyI9EHDu 9GwV3fP7OHwXO/TgRgNgDnToYQz8vkEDt3fpC2uLlvXh0ZHHg5AFfm1Q4vlojz6MAE SDAxBEJ8HNOe00J1KjHW8HW+AP2105XmziciAXkase2eetCUxJV/sRcPN0pBIy0g86 FoxYWOwGvVGzA== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 29/31] objtool: Calculate function checksums Date: Mon, 2 Sep 2024 21:00:12 -0700 Message-ID: X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Calculate per-function checksums based on the functions' content and relocations. This will enable objtool to do binary diffs. Signed-off-by: Josh Poimboeuf --- scripts/Makefile.lib | 1 + tools/objtool/Makefile | 7 +- tools/objtool/builtin-check.c | 1 + tools/objtool/check.c | 137 +++++++++++++++++++++++- tools/objtool/elf.c | 31 ++++++ tools/objtool/include/objtool/builtin.h | 3 +- tools/objtool/include/objtool/check.h | 5 +- tools/objtool/include/objtool/elf.h | 11 +- tools/objtool/include/objtool/objtool.h | 2 + 9 files changed, 188 insertions(+), 10 deletions(-) diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 8411e3d53938..9f4708702ef7 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -265,6 +265,7 @@ ifdef CONFIG_OBJTOOL =20 objtool :=3D $(objtree)/tools/objtool/objtool =20 +objtool-args-$(CONFIG_LIVEPATCH) +=3D --sym-checksum objtool-args-$(CONFIG_HAVE_JUMP_LABEL_HACK) +=3D --hacks=3Djump_label objtool-args-$(CONFIG_HAVE_NOINSTR_HACK) +=3D --hacks=3Dnoinstr objtool-args-$(CONFIG_MITIGATION_CALL_DEPTH_TRACKING) +=3D --hacks=3Dskyla= ke diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index bf7f7f84ac62..6833804ca419 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile @@ -21,6 +21,9 @@ OBJTOOL_IN :=3D $(OBJTOOL)-in.o LIBELF_FLAGS :=3D $(shell $(HOSTPKG_CONFIG) libelf --cflags 2>/dev/null) LIBELF_LIBS :=3D $(shell $(HOSTPKG_CONFIG) libelf --libs 2>/dev/null || e= cho -lelf) =20 +LIBXXHASH_FLAGS :=3D $(shell $(HOSTPKG_CONFIG) libxxhash --cflags 2>/dev/n= ull) +LIBXXHASH_LIBS :=3D $(shell $(HOSTPKG_CONFIG) libxxhash --libs 2>/dev/nul= l || echo -lxxhash) + all: $(OBJTOOL) =20 INCLUDES :=3D -I$(srctree)/tools/include \ @@ -32,8 +35,8 @@ INCLUDES :=3D -I$(srctree)/tools/include \ # Note, EXTRA_WARNINGS here was determined for CC and not HOSTCC, it # is passed here to match a legacy behavior. WARNINGS :=3D $(EXTRA_WARNINGS) -Wno-switch-default -Wno-switch-enum -Wno-= packed -Wno-nested-externs -OBJTOOL_CFLAGS :=3D -Werror $(WARNINGS) $(KBUILD_HOSTCFLAGS) -g $(INCLUDES= ) $(LIBELF_FLAGS) -OBJTOOL_LDFLAGS :=3D $(LIBELF_LIBS) $(LIBSUBCMD) $(KBUILD_HOSTLDFLAGS) +OBJTOOL_CFLAGS :=3D -Werror $(WARNINGS) $(KBUILD_HOSTCFLAGS) -g $(INCLUDES= ) $(LIBELF_FLAGS) $(LIBXXHASH_FLAGS) +OBJTOOL_LDFLAGS :=3D $(LIBELF_LIBS) $(LIBXXHASH_LIBS) $(LIBSUBCMD) $(KBUIL= D_HOSTLDFLAGS) =20 # Allow old libelf to be used: elfshdr :=3D $(shell echo '$(pound)include ' | $(HOSTCC) $(OBJTO= OL_CFLAGS) -x c -E - | grep elf_getshdr) diff --git a/tools/objtool/builtin-check.c b/tools/objtool/builtin-check.c index 6894ef68d125..f3473c046c86 100644 --- a/tools/objtool/builtin-check.c +++ b/tools/objtool/builtin-check.c @@ -75,6 +75,7 @@ static const struct option check_options[] =3D { OPT_BOOLEAN('l', "sls", &opts.sls, "validate straight-line-speculation mi= tigations"), OPT_BOOLEAN('s', "stackval", &opts.stackval, "validate frame pointer rule= s"), OPT_BOOLEAN('t', "static-call", &opts.static_call, "annotate static calls= "), + OPT_BOOLEAN(0, "sym-checksum", &opts.sym_checksum, "generate per-functi= on checksums"), OPT_BOOLEAN('u', "uaccess", &opts.uaccess, "validate uaccess rules for SM= AP"), OPT_BOOLEAN(0 , "cfi", &opts.cfi, "annotate kernel control flow integrit= y (kCFI) function preambles"), OPT_CALLBACK_OPTARG(0, "dump", NULL, NULL, "orc", "dump metadata", parse_= dump), diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 5dd78a7f75c3..0e9e485cd3b6 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -8,6 +8,8 @@ #include #include =20 +#include + #include #include #include @@ -951,6 +953,48 @@ static void create_direct_call_sections(struct objtool= _file *file) } } =20 +static void create_sym_checksum_section(struct objtool_file *file) +{ + struct section *sec; + struct symbol *sym; + unsigned int idx =3D 0; + struct sym_checksum *sym_checksum; + size_t entsize =3D sizeof(struct sym_checksum); + + sec =3D find_section_by_name(file->elf, SYM_CHECKSUM_SEC); + if (sec) { + WARN("file already has " SYM_CHECKSUM_SEC " section, skipping"); + return; + } + + for_each_sym(file->elf, sym) + if (sym->checksum) + idx++; + + if (!idx) + return; + + sec =3D elf_create_section_pair(file->elf, ".discard.sym_checksum", entsi= ze, + idx, idx); + + idx =3D 0; + for_each_sym(file->elf, sym) { + if (!sym->checksum) + continue; + + elf_init_reloc(file->elf, sec->rsec, idx, idx * entsize, sym, + 0, R_TEXT64); + + sym_checksum =3D (struct sym_checksum *)sec->data->d_buf + idx; + sym_checksum->addr =3D 0; /* reloc */ + sym_checksum->checksum =3D sym->checksum; + + mark_sec_changed(file->elf, sec, true); + + idx++; + } +} + /* * Warnings shouldn't be reported for ignored functions. */ @@ -1709,6 +1753,7 @@ static void handle_group_alt(struct objtool_file *fil= e, nop->sym =3D orig_insn->sym; nop->alt_group =3D new_alt_group; nop->ignore =3D orig_insn->ignore_alts; + nop->fake =3D 1; } =20 if (!special_alt->new_len) { @@ -3291,6 +3336,58 @@ static struct instruction *next_insn_to_validate(str= uct objtool_file *file, return next_insn_same_sec(file, alt_group->orig_group->last_insn); } =20 +static void update_sym_checksum(struct symbol *func, struct instruction *i= nsn, + const void *data, size_t size) +{ + XXH3_64bits_update(func->checksum_state, data, size); +} + +static void update_insn_sym_checksum(struct objtool_file *file, struct sym= bol *func, + struct instruction *insn) +{ + struct reloc *reloc =3D insn_reloc(file, insn); + struct symbol *dest =3D insn_call_dest(insn); + + if (dest && !reloc) { + update_sym_checksum(func, insn, insn->sec->data->d_buf + insn->offset, 1= ); + update_sym_checksum(func, insn, dest->name, strlen(dest->name)); + } else if (!insn->fake) { + update_sym_checksum(func, insn, insn->sec->data->d_buf + insn->offset, i= nsn->len); + } + + if (reloc) { + struct symbol *sym =3D reloc->sym; + + if (sym->sec && is_string_section(sym->sec)) { + s64 addend; + char *str; + + addend =3D arch_insn_adjusted_addend(insn, reloc); + + str =3D sym->sec->data->d_buf + sym->offset + addend; + + update_sym_checksum(func, insn, str, strlen(str)); + + } else { + u64 offset =3D arch_insn_adjusted_addend(insn, reloc); + + if (is_section_symbol(sym)) { + sym =3D find_symbol_containing(reloc->sym->sec, offset); + if (!sym) + return; + + offset -=3D sym->offset; + } + + update_sym_checksum(func, insn, sym->demangled_name, + strlen(sym->demangled_name)); + + update_sym_checksum(func, insn, &offset, sizeof(offset)); + } + } +} + + /* * Follow the branch starting at the given instruction, and recursively fo= llow * any other branches (jumps). Meanwhile, track the frame pointer state at @@ -3306,11 +3403,15 @@ static int validate_branch(struct objtool_file *fil= e, struct symbol *func, u8 visited; int ret; =20 - sec =3D insn->sec; - while (1) { next_insn =3D next_insn_to_validate(file, insn); =20 + // moved this because alt can continue to orig thanks to next_insn_same_= sec + sec =3D insn->sec; + + if (opts.sym_checksum && func && sec) + update_insn_sym_checksum(file, func, insn); + 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) || @@ -3549,7 +3650,15 @@ static int validate_unwind_hint(struct objtool_file = *file, struct insn_state *state) { if (insn->hint && !insn->visited && !insn->ignore) { - int ret =3D validate_branch(file, insn_func(insn), insn, *state); + struct symbol *func =3D insn_func(insn); + int ret; + + if (func && !func->checksum_state) { + func->checksum_state =3D XXH3_createState(); + XXH3_64bits_reset(func->checksum_state); + } + + ret =3D validate_branch(file, func, insn, *state); if (ret) BT_INSN(insn, "<=3D=3D=3D (hint)"); return ret; @@ -3941,7 +4050,9 @@ static void add_prefix_symbols(struct objtool_file *f= ile) static int validate_symbol(struct objtool_file *file, struct section *sec, struct symbol *sym, struct insn_state *state) { + static XXH3_state_t *checksum_state; struct instruction *insn; + struct symbol *func; int ret; =20 if (!sym->len) { @@ -3958,9 +4069,24 @@ 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), insn, *state); + func =3D insn_func(insn); + + if (func && !func->checksum_state) { + if (!checksum_state) + checksum_state =3D XXH3_createState(); + XXH3_64bits_reset(checksum_state); + func->checksum_state =3D checksum_state; + } + + ret =3D validate_branch(file, func, insn, *state); if (ret) BT_INSN(insn, "<=3D=3D=3D (sym)"); + + if (func) { + func->checksum =3D XXH3_64bits_digest(func->checksum_state); + func->checksum_state =3D NULL; + } + return ret; } =20 @@ -4509,6 +4635,9 @@ int check(struct objtool_file *file) if (opts.ibt) create_ibt_endbr_seal_sections(file); =20 + if (opts.sym_checksum) + create_sym_checksum_section(file); + if (opts.orc && nr_insns) { ret =3D orc_create(file); if (ret < 0) diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 3109277804cc..022873bf7064 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -396,6 +397,34 @@ static void read_sections(struct elf *elf) ERROR("section entry mismatch"); } =20 +static const char *demangle_name(struct symbol *sym) +{ + char *str; + + if (!is_local_symbol(sym)) + return sym->name; + + if (!is_function_symbol(sym) && !is_object_symbol(sym)) + return sym->name; + + if (!strstarts(sym->name, "__UNIQUE_ID_") && !strchr(sym->name, '.')) + return sym->name; + + str =3D strdup(sym->name); + ERROR_ON(!str, "strdup"); + + for (int i =3D strlen(str) - 1; i >=3D 0; i--) { + char c =3D str[i]; + + if (!isdigit(c) && c !=3D '.') { + str[i + 1] =3D '\0'; + break; + } + }; + + return str; +} + static void elf_add_symbol(struct elf *elf, struct symbol *sym) { struct list_head *entry; @@ -440,6 +469,8 @@ static void elf_add_symbol(struct elf *elf, struct symb= ol *sym) if (sym->type =3D=3D STT_NOTYPE && !sym->len) __sym_remove(sym, &sym->sec->symbol_tree); #endif + + sym->demangled_name =3D demangle_name(sym); } =20 static void read_symbols(struct elf *elf) diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/includ= e/objtool/builtin.h index fcca6662c8b4..eab376169c1e 100644 --- a/tools/objtool/include/objtool/builtin.h +++ b/tools/objtool/include/objtool/builtin.h @@ -9,6 +9,7 @@ =20 struct opts { /* actions: */ + bool cfi; bool dump_orc; bool hack_jump_label; bool hack_noinstr; @@ -23,9 +24,9 @@ struct opts { bool sls; bool stackval; bool static_call; + bool sym_checksum; bool uaccess; int prefix; - bool cfi; =20 /* options: */ bool backtrace; diff --git a/tools/objtool/include/objtool/check.h b/tools/objtool/include/= objtool/check.h index daa46f1f0965..b546a31dc2a9 100644 --- a/tools/objtool/include/objtool/check.h +++ b/tools/objtool/include/objtool/check.h @@ -63,8 +63,9 @@ struct instruction { noendbr : 1, unret : 1, visited : 4, - no_reloc : 1; - /* 10 bit hole */ + no_reloc : 1, + fake : 1; + /* 9 bit hole */ =20 struct alt_group *alt_group; struct instruction *jump_dest; diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/ob= jtool/elf.h index f759686d46d7..1f14f33d279e 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -13,6 +13,7 @@ #include #include #include +#include #include =20 #define SYM_NAME_LEN 512 @@ -29,6 +30,11 @@ #define ELF_C_READ_MMAP ELF_C_READ #endif =20 +struct sym_checksum { + u64 addr; + u64 checksum; +}; + struct elf_hash_node { struct elf_hash_node *next; }; @@ -56,7 +62,7 @@ struct symbol { struct elf_hash_node name_hash; GElf_Sym sym; struct section *sec; - const char *name; + const char *name, *demangled_name; unsigned int idx, len; unsigned long offset; unsigned long __subtree_last; @@ -73,6 +79,9 @@ struct symbol { u8 local_label : 1; struct list_head pv_target; struct reloc *relocs; + + XXH3_state_t *checksum_state; + XXH64_hash_t checksum; }; =20 struct reloc { diff --git a/tools/objtool/include/objtool/objtool.h b/tools/objtool/includ= e/objtool/objtool.h index ae30497e014b..3280abcce55e 100644 --- a/tools/objtool/include/objtool/objtool.h +++ b/tools/objtool/include/objtool/objtool.h @@ -14,6 +14,8 @@ =20 #define __weak __attribute__((weak)) =20 +#define SYM_CHECKSUM_SEC ".discard.sym_checksum" + struct pv_state { bool clean; struct list_head targets; --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BF7F620012F; Tue, 3 Sep 2024 04:00:44 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336044; cv=none; b=oWLBiQ7O/PEsMZ6b/FY/yrHCz17hByVTAyWdIsPzGi/+5FNvlVk4uGJCRLbctz3NtW6vDG3m1fo6wPAjTOrfFRDLYok/8HUHmgxWr6A4F8XkTaqFpSdksqDblbixzDp8FzwQS4Z+hTChvHDDNDVnn6v8CmKzIOWej3MzBHvqWwY= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336044; c=relaxed/simple; bh=XZH6GbpQqqfXTAWtcBScwAB8pujkxzWJvje19GUL4Cs=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=Qcq0v7dNbOlbITO8gg0onepgy99BQON5uz0qseE7acUq/6At64X01oscp3wljDGt6PpvhMmPTJFaX22QoyvMDitpJCrUSERCRRaiOQf0szPjqJ5DEpn30vpKIoqaJu8Kt5TBZa2kYLbVQ34CRhELFR9+EJPGLgsEPrEePKK20gs= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=TvtovvBK; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="TvtovvBK" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 49633C4CEC7; Tue, 3 Sep 2024 04:00:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336044; bh=XZH6GbpQqqfXTAWtcBScwAB8pujkxzWJvje19GUL4Cs=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=TvtovvBKo9816mllYRKTLwt9zhZEKS3F8BbVy3qKPRSVuQ0ZwEb4P7A9Djb02tBcJ 6npZqjPZMns7hoO0I5+NhzldFT7JoKYN59QiuAI2GpdOkc3F0eckiadc6vdZYbte3Y PXn6Z+WcSaO9iBGEJJhQH9KvMSR9hhi77uLrhE7CzWPPPi1S0qMjD/Oi/elsGTsbnH pwj49zUsa8jrRulCJgP2NYOHOmCxrOxdt9KO3dtRzXZ5amn2anf1Ua14o1BVhRMOc7 I61Yydb6Bui4kV9/5bJ6hd7OVE9sXfrBrweys2jQ5MMNt3ZXHD97m0FDA4K2wLuqID ZIYBm62hPMNIw== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 30/31] livepatch: Enable -ffunction-sections -fdata-sections Date: Mon, 2 Sep 2024 21:00:13 -0700 Message-ID: <38c14842a3045e236bb5c446a86ca5536682a7b8.1725334260.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Doing a binary diff of two objects can be problematic: - For intra-section references, the compiler might use hard-coded offsets rather than relocations. - Data references can be ambiguous if the compiler uses section symbol references: - Symbol overlap and zero-length symbols create ambiguity as to which symbol is being referenced. - An access to the end of a symbol (e.g., array bounds) could be incorrectly interpreted as an access to the beginning of the next symbol. Remove those ambiguities by turning on -ffunction-sections and -fdata-sections for CONFIG_LIVEPATCH. They could alternatively be turned on only during the comparison builds, rather than also in the production kernel, but that might theoretically leave the possibility open for unexpected differences between the kernels. The compared kernels should be identical to the original kernel as much as possible. The performance impact should be small. Intra-TU references are quite rare in practice. And the resulting final code layout is similar. Distros are likely going to start using these options soon anyway for things like LTO and fgKASLR. A potential alternative approach would be to add a toolchain option to always use (symbol) relocations. Signed-off-by: Josh Poimboeuf --- Makefile | 9 +++++++++ include/asm-generic/vmlinux.lds.h | 2 +- scripts/Makefile.lib | 2 +- scripts/module.lds.S | 13 +++++++++---- 4 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Makefile b/Makefile index 3d10e3aadeda..2a15b560ecc0 100644 --- a/Makefile +++ b/Makefile @@ -931,10 +931,19 @@ ifdef CONFIG_DEBUG_SECTION_MISMATCH KBUILD_CFLAGS +=3D -fno-inline-functions-called-once endif =20 +ifdef CONFIG_LIVEPATCH +KBUILD_CFLAGS +=3D -ffunction-sections -fdata-sections # `rustc`'s `-Zfunction-sections` applies to data too (as of 1.59.0). +KBUILD_RUSTFLAGS +=3D -Zfunction-sections=3Dy +else ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION KBUILD_CFLAGS_KERNEL +=3D -ffunction-sections -fdata-sections +# `rustc`'s `-Zfunction-sections` applies to data too (as of 1.59.0). KBUILD_RUSTFLAGS_KERNEL +=3D -Zfunction-sections=3Dy +endif +endif + +ifdef CONFIG_LD_DEAD_CODE_DATA_ELIMINATION LDFLAGS_vmlinux +=3D --gc-sections endif =20 diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinu= x.lds.h index 5703526d6ebf..a7ac3ca596ad 100644 --- a/include/asm-generic/vmlinux.lds.h +++ b/include/asm-generic/vmlinux.lds.h @@ -98,7 +98,7 @@ * RODATA_MAIN is not used because existing code already defines .rodata.x * sections to be brought in with rodata. */ -#if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) || defined(CONFIG_LTO_CL= ANG) +#if defined(CONFIG_LD_DEAD_CODE_DATA_ELIMINATION) || defined(CONFIG_LTO_CL= ANG) || defined(CONFIG_LIVEPATCH) #define TEXT_MAIN .text .text.[0-9a-zA-Z_]* #define DATA_MAIN .data .data.[0-9a-zA-Z_]* .data..L* .data..compoundliter= al* .data.$__unnamed_* .data.$L* #define SDATA_MAIN .sdata .sdata.[0-9a-zA-Z_]* diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib index 9f4708702ef7..ca7497f74247 100644 --- a/scripts/Makefile.lib +++ b/scripts/Makefile.lib @@ -289,7 +289,7 @@ objtool-args =3D $(objtool-args-y) \ $(if $(delay-objtool), --link) \ $(if $(part-of-module), --module) =20 -delay-objtool :=3D $(or $(CONFIG_LTO_CLANG),$(CONFIG_X86_KERNEL_IBT)) +delay-objtool :=3D $(or $(CONFIG_LTO_CLANG),$(CONFIG_X86_KERNEL_IBT),$(CON= FIG_LIVEPATCH)) =20 cmd_objtool =3D $(if $(objtool-enabled), ; $(objtool) $(objtool-args) $@) cmd_gen_objtooldep =3D $(if $(objtool-enabled), { echo ; echo '$@: $$(wild= card $(objtool))' ; } >> $(dot-target).cmd) diff --git a/scripts/module.lds.S b/scripts/module.lds.S index 3f43edef813c..5cbae820bca0 100644 --- a/scripts/module.lds.S +++ b/scripts/module.lds.S @@ -36,12 +36,17 @@ SECTIONS { __kcfi_traps : { KEEP(*(.kcfi_traps)) } #endif =20 -#ifdef CONFIG_LTO_CLANG +#if defined(CONFIG_LTO_CLANG) || defined(CONFIG_LIVEPATCH) + /* - * With CONFIG_LTO_CLANG, LLD always enables -fdata-sections and - * -ffunction-sections, which increases the size of the final module. - * Merge the split sections in the final binary. + * Merge -ffunction-sections and -fdata-sections sections to decrease + * module size. */ + + .text : { + *(.text .text.[0-9a-zA-Z_]*) + } + .bss : { *(.bss .bss.[0-9a-zA-Z_]*) *(.bss..L*) --=20 2.45.2 From nobody Sat Feb 7 21:14:58 2026 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-1.web.codeaurora.org [10.30.226.201]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id A205B201278; Tue, 3 Sep 2024 04:00:45 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=10.30.226.201 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336045; cv=none; b=HN8aIN0caeyaejtFHKOMU6jdwd69nJztrj7VPo6tG7gARwD5lga4hM1I1AOAVrV/OnW4ADCr5SG/C8O3Ndxv5Bxo1FUORZGQOrxI7HV65H6Ynk2U8U8PCO7XejXOjsHv3Nw1b1zgUVJDAqg50eX8My6Sxi86WDqtbtbDpjw6BW0= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1725336045; c=relaxed/simple; bh=2387ZLqzG+E9PtfZZ8vkWz/hfacL1d+dPSLFhvagAjQ=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=RGFYoQmqkk6zgxyHflLzv2OMVaDcn/ANnEjl9060FA1eB75MEZuTpFMSIP8ren5MbHBGBj2VSb3FZklTv0q+qr5bHq6cjtSWQGFDBJqnfucx2o8sL0OAqt+rTIFxLztwNQNjVnJ1eQ4c5tpPgXUzEREQqYTng13XF7anSq60wsc= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=JfyylwoJ; arc=none smtp.client-ip=10.30.226.201 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="JfyylwoJ" Received: by smtp.kernel.org (Postfix) with ESMTPSA id C717BC4CEC8; Tue, 3 Sep 2024 04:00:44 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=kernel.org; s=k20201202; t=1725336045; bh=2387ZLqzG+E9PtfZZ8vkWz/hfacL1d+dPSLFhvagAjQ=; h=From:To:Cc:Subject:Date:In-Reply-To:References:From; b=JfyylwoJ8hbNBjArbRLMwtDAdGKVpnyeiZtCp7fSguMhYIpb7xqLClVa3MOdrgUIY hMU07h7bGzAYKkmv9/OTkWAa300Yh3b4WdcSr1uaFwkGACQjjR/JBN8STIITc0BqOz vLEJJ1kbo9CHRjKq7DNrnPJek7pS0YjSVpvocZ391AaRZuiCqYn/OrbY+5KtRsQ9EP BwEE7gvnIbjpd1Yn4HRLwj7ZYpsSLSK+Rqc2neId67H+8aGF60O3uxmEYssmK7E8pB yK9iM94zajKWKK0A02VESJOBegkuZNJ4KTWlABDcHGtafovmDN4k0e5j6cHvjRKPzl GjEEv7GshCiWg== From: Josh Poimboeuf To: live-patching@vger.kernel.org Cc: linux-kernel@vger.kernel.org, x86@kernel.org, Miroslav Benes , Petr Mladek , Joe Lawrence , Jiri Kosina , Peter Zijlstra , Marcos Paulo de Souza , Song Liu Subject: [RFC 31/31] objtool, livepatch: Livepatch module generation Date: Mon, 2 Sep 2024 21:00:14 -0700 Message-ID: <9ceb13e03c3af0b4823ec53a97f2a2d82c0328b3.1725334260.git.jpoimboe@kernel.org> X-Mailer: git-send-email 2.45.2 In-Reply-To: References: Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" Add a klp-build script which makes use of a new "objtool klp" subcommand to generate livepatch modules using a source patch as input. The concept is similar to kpatch-build which has been a successful out-of-tree project for over a decade. It takes a source .patch as an input, builds kernels before and after, does a binary diff, and copies any changed functions into a new object file which is then linked into a livepatch module. By making use of existing objtool functionalities, and taking from lessons learned over the last decade of maintaining kpatch-build, the overall design is much simpler. In fact, it's a complete redesign and has been written from scratch (no copied code). Advantages over kpatch-build: - Runs on vmlinux.o, so it's compatible with late-linked features like IBT and LTO - Much simpler design: ~3k fewer LOC - Makes use of existing objtool CFG functionality to create checksums to trivially detect changed functions - Offset __LINE__ changes are no longer a problem thanks to the adjust-patch-lines script - In-tree means less cruft, easier maintenance, and a larger pool of potential maintainers To use, run the following from the kernel source root: scripts/livepatch/klp-build /path/to/my.patch If it succeeds, the patch module (livepatch.ko) will be created in the current directory. TODO: - specify module name on cmdline - handle edge cases like correlation of static locals - support other arches (currently x86-64 only) - support clang - performance optimization - automated testing Signed-off-by: Josh Poimboeuf --- .gitignore | 3 + include/linux/livepatch.h | 25 +- include/linux/livepatch_ext.h | 83 ++ include/linux/livepatch_patch.h | 73 ++ kernel/livepatch/core.c | 4 +- scripts/livepatch/adjust-patch-lines | 181 ++++ scripts/livepatch/klp-build | 355 ++++++++ scripts/livepatch/module.c | 120 +++ scripts/module.lds.S | 9 +- tools/include/linux/livepatch_ext.h | 83 ++ tools/objtool/Build | 4 +- tools/objtool/Makefile | 33 +- tools/objtool/arch/x86/decode.c | 40 + tools/objtool/check.c | 29 +- tools/objtool/elf.c | 18 +- tools/objtool/include/objtool/arch.h | 1 + tools/objtool/include/objtool/builtin.h | 1 + tools/objtool/include/objtool/elf.h | 20 +- tools/objtool/include/objtool/klp.h | 25 + tools/objtool/include/objtool/objtool.h | 2 +- tools/objtool/klp-diff.c | 1112 +++++++++++++++++++++++ tools/objtool/klp-link.c | 122 +++ tools/objtool/klp.c | 57 ++ tools/objtool/objtool.c | 6 + tools/objtool/sync-check.sh | 1 + tools/objtool/weak.c | 7 + 26 files changed, 2361 insertions(+), 53 deletions(-) create mode 100644 include/linux/livepatch_ext.h create mode 100644 include/linux/livepatch_patch.h create mode 100755 scripts/livepatch/adjust-patch-lines create mode 100755 scripts/livepatch/klp-build create mode 100644 scripts/livepatch/module.c create mode 100644 tools/include/linux/livepatch_ext.h create mode 100644 tools/objtool/include/objtool/klp.h create mode 100644 tools/objtool/klp-diff.c create mode 100644 tools/objtool/klp-link.c create mode 100644 tools/objtool/klp.c diff --git a/.gitignore b/.gitignore index c59dc60ba62e..28bb70c9e808 100644 --- a/.gitignore +++ b/.gitignore @@ -171,3 +171,6 @@ sphinx_*/ =20 # Rust analyzer configuration /rust-project.json + +# Livepatch module build directory +/klp-tmp diff --git a/include/linux/livepatch.h b/include/linux/livepatch.h index 51a258c24ff5..d54e4dfe320e 100644 --- a/include/linux/livepatch.h +++ b/include/linux/livepatch.h @@ -13,6 +13,7 @@ #include #include #include +#include #include =20 #if IS_ENABLED(CONFIG_LIVEPATCH) @@ -77,30 +78,6 @@ struct klp_func { bool transition; }; =20 -struct klp_object; - -/** - * struct klp_callbacks - pre/post live-(un)patch callback structure - * @pre_patch: executed before code patching - * @post_patch: executed after code patching - * @pre_unpatch: executed before code unpatching - * @post_unpatch: executed after code unpatching - * @post_unpatch_enabled: flag indicating if post-unpatch callback - * should run - * - * All callbacks are optional. Only the pre-patch callback, if provided, - * will be unconditionally executed. If the parent klp_object fails to - * patch for any reason, including a non-zero error status returned from - * the pre-patch callback, no further callbacks will be executed. - */ -struct klp_callbacks { - int (*pre_patch)(struct klp_object *obj); - void (*post_patch)(struct klp_object *obj); - void (*pre_unpatch)(struct klp_object *obj); - void (*post_unpatch)(struct klp_object *obj); - bool post_unpatch_enabled; -}; - /** * struct klp_object - kernel object structure for live patching * @name: module name (or NULL for vmlinux) diff --git a/include/linux/livepatch_ext.h b/include/linux/livepatch_ext.h new file mode 100644 index 000000000000..4b71e72952d5 --- /dev/null +++ b/include/linux/livepatch_ext.h @@ -0,0 +1,83 @@ +/* SPDX License-Identifier: GPL-2.0-or-later */ +/* + * External livepatch interfaces for patch creation tooling + * + * Copyright (C) 2024 Josh Poimboeuf + */ + +#ifndef _LINUX_LIVEPATCH_EXT_H_ +#define _LINUX_LIVEPATCH_EXT_H_ + +#include + +#define KLP_RELOC_SEC_PREFIX ".klp.rela." +#define KLP_SYM_PREFIX ".klp.sym." + +#define KLP_CALLBACKS_SEC ".discard.klp_callbacks" + +#define __KLP_PRE_PATCH_PREFIX __klp_pre_patch_callback_ +#define __KLP_POST_PATCH_PREFIX __klp_post_patch_callback_ +#define __KLP_PRE_UNPATCH_PREFIX __klp_pre_unpatch_callback_ +#define __KLP_POST_UNPATCH_PREFIX __klp_post_unpatch_callback_ + +#define KLP_PRE_PATCH_PREFIX __stringify(__KLP_PRE_PATCH_PREFIX) +#define KLP_POST_PATCH_PREFIX __stringify(__KLP_POST_PATCH_PREFIX) +#define KLP_PRE_UNPATCH_PREFIX __stringify(__KLP_PRE_UNPATCH_PREFIX) +#define KLP_POST_UNPATCH_PREFIX __stringify(__KLP_POST_UNPATCH_PREFIX) + +struct klp_object; + +typedef int (*klp_pre_patch_t)(struct klp_object *obj); +typedef void (*klp_post_patch_t)(struct klp_object *obj); +typedef void (*klp_pre_unpatch_t)(struct klp_object *obj); +typedef void (*klp_post_unpatch_t)(struct klp_object *obj); + +/** + * struct klp_callbacks - pre/post live-(un)patch callback structure + * @pre_patch: executed before code patching + * @post_patch: executed after code patching + * @pre_unpatch: executed before code unpatching + * @post_unpatch: executed after code unpatching + * @post_unpatch_enabled: flag indicating if post-unpatch callback + * should run + * + * All callbacks are optional. Only the pre-patch callback, if provided, + * will be unconditionally executed. If the parent klp_object fails to + * patch for any reason, including a non-zero error status returned from + * the pre-patch callback, no further callbacks will be executed. + */ +struct klp_callbacks { + klp_pre_patch_t pre_patch; + klp_post_patch_t post_patch; + klp_pre_unpatch_t pre_unpatch; + klp_post_unpatch_t post_unpatch; + bool post_unpatch_enabled; +}; + +/* + * 'struct klp_{func,object}_ext' are compact "external" representations of + * 'struct klp_{func,object}'. They are used by objtool for livepatch + * generation. The structs are then read by the livepatch module and conv= erted + * to the real structs before calling klp_enable_patch(). + * + * TODO make these the official API for klp_enable_patch(). That should + * simplify livepatch's interface as well as its data structure lifetime + * management. + * + * TODO possibly use struct_group_tagged() to declare these within the ori= ginal + * structs. + */ +struct klp_func_ext { + const char *old_name; + void *new_func; + unsigned long sympos; +}; + +struct klp_object_ext { + const char *name; + struct klp_func_ext *funcs; + struct klp_callbacks callbacks; + unsigned int nr_funcs; +}; + +#endif /* _LINUX_LIVEPATCH_EXT_H_ */ diff --git a/include/linux/livepatch_patch.h b/include/linux/livepatch_patc= h.h new file mode 100644 index 000000000000..6f3b930cdc5a --- /dev/null +++ b/include/linux/livepatch_patch.h @@ -0,0 +1,73 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Helper macros for livepatch source patches + * + * Copyright (C) 2024 Josh Poimboeuf + */ +#ifndef _LINUX_LIVEPATCH_PATCH_H_ +#define _LINUX_LIVEPATCH_PATCH_H_ + +#include + +#ifdef MODULE +#define KLP_OBJNAME __KBUILD_MODNAME +#else +#define KLP_OBJNAME vmlinux +#endif + +#define KLP_PRE_PATCH_CALLBACK(func) \ + klp_pre_patch_t __used __section(KLP_CALLBACKS_SEC) \ + __PASTE(__KLP_PRE_PATCH_PREFIX, KLP_OBJNAME) =3D func + +#define KLP_POST_PATCH_CALLBACK(func) \ + klp_post_patch_t __used __section(KLP_CALLBACKS_SEC) \ + __PASTE(__KLP_POST_PATCH_PREFIX, KLP_OBJNAME) =3D func + +#define KLP_PRE_UNPATCH_CALLBACK(func) \ + klp_pre_unpatch_t __used __section(KLP_CALLBACKS_SEC) \ + __PASTE(__KLP_PRE_UNPATCH_PREFIX, KLP_OBJNAME) =3D func + +#define KLP_POST_UNPATCH_CALLBACK(func) \ + klp_post_unpatch_t __used __section(KLP_CALLBACKS_SEC) \ + __PASTE(__KLP_POST_UNPATCH_PREFIX, KLP_OBJNAME) =3D func + +#define KLP_SYSCALL_METADATA(sname) \ + static struct syscall_metadata __used \ + __section("__syscalls_metadata") \ + *__p_syscall_meta_##sname =3D NULL; \ + \ + static struct trace_event_call __used \ + __section("_ftrace_events") \ + *__event_enter_##sname =3D NULL + +#define KLP_SYSCALL_DEFINE1(name, ...) KLP_SYSCALL_DEFINEx(1, _##name, __V= A_ARGS__) +#define KLP_SYSCALL_DEFINE2(name, ...) KLP_SYSCALL_DEFINEx(2, _##name, __V= A_ARGS__) +#define KLP_SYSCALL_DEFINE3(name, ...) KLP_SYSCALL_DEFINEx(3, _##name, __V= A_ARGS__) +#define KLP_SYSCALL_DEFINE4(name, ...) KLP_SYSCALL_DEFINEx(4, _##name, __V= A_ARGS__) +#define KLP_SYSCALL_DEFINE5(name, ...) KLP_SYSCALL_DEFINEx(5, _##name, __V= A_ARGS__) +#define KLP_SYSCALL_DEFINE6(name, ...) KLP_SYSCALL_DEFINEx(6, _##name, __V= A_ARGS__) + +#define KLP_SYSCALL_DEFINEx(x, sname, ...) \ + KLP_SYSCALL_METADATA(sname); \ + __KLP_SYSCALL_DEFINEx(x, sname, __VA_ARGS__) + +#ifdef CONFIG_X86_64 + +// TODO move this to arch/x86/include/asm/syscall_wrapper.h and share code +#define __KLP_SYSCALL_DEFINEx(x, name, ...) \ + static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)); \ + static inline long __klp_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__));\ + __X64_SYS_STUBx(x, name, __VA_ARGS__) \ + __IA32_SYS_STUBx(x, name, __VA_ARGS__) \ + static long __se_sys##name(__MAP(x,__SC_LONG,__VA_ARGS__)) \ + { \ + long ret =3D __klp_do_sys##name(__MAP(x,__SC_CAST,__VA_ARGS__));\ + __MAP(x,__SC_TEST,__VA_ARGS__); \ + __PROTECT(x, ret,__MAP(x,__SC_ARGS,__VA_ARGS__)); \ + return ret; \ + } \ + static inline long __klp_do_sys##name(__MAP(x,__SC_DECL,__VA_ARGS__)) + +#endif + +#endif /* _LINUX_LIVEPATCH_PATCH_H_ */ diff --git a/kernel/livepatch/core.c b/kernel/livepatch/core.c index 76ffe29934d4..8ff917973254 100644 --- a/kernel/livepatch/core.c +++ b/kernel/livepatch/core.c @@ -226,7 +226,7 @@ static int klp_resolve_symbols(Elf_Shdr *sechdrs, const= char *strtab, =20 /* Format: .klp.sym.sym_objname.sym_name,sympos */ cnt =3D sscanf(strtab + sym->st_name, - ".klp.sym.%55[^.].%511[^,],%lu", + KLP_SYM_PREFIX "%55[^.].%511[^,],%lu", sym_objname, sym_name, &sympos); if (cnt !=3D 3) { pr_err("symbol %s has an incorrectly formatted name\n", @@ -305,7 +305,7 @@ static int klp_write_section_relocs(struct module *pmod= , Elf_Shdr *sechdrs, * See comment in klp_resolve_symbols() for an explanation * of the selected field width value. */ - cnt =3D sscanf(shstrtab + sec->sh_name, ".klp.rela.%55[^.]", + cnt =3D sscanf(shstrtab + sec->sh_name, KLP_RELOC_SEC_PREFIX "%55[^.]", sec_objname); if (cnt !=3D 1) { pr_err("section %s has an incorrectly formatted name\n", diff --git a/scripts/livepatch/adjust-patch-lines b/scripts/livepatch/adjus= t-patch-lines new file mode 100755 index 000000000000..b29592a57ed3 --- /dev/null +++ b/scripts/livepatch/adjust-patch-lines @@ -0,0 +1,181 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2024 Josh Poimboeuf +# +# Add #line statements to a patch so it doesn't affect __LINE__ usage + +SCRIPT=3D"$(basename "$0")" + +set -o errexit +set -o errtrace +set -o pipefail + +warn() { + str=3D"$1" + if [ -n "$str" ]; then + echo -e "$SCRIPT: error: $*" >&2 + else + echo -e "$SCRIPT: error" >&2 + + fi +} + +die() { + warn "$@" + if [ -n "$TMPFILE" ]; then + rm -f "$TMPFILE" + fi + exit 1 +} + +do_trap() { + die +} + +trap do_trap ERR + +__usage() { + echo "Usage: $SCRIPT [options] patch_file [output_file]" + echo "Add #line statements to a patch so it doesn't affect __LINE__ usage" + echo "for the rest of the file. This prevents false positive changes in = the binary." + echo + echo "Options:" + echo " -h, --help Show this help message and exit" + echo + echo "Arguments:" + echo " patch_file Source .patch file" + echo " output_file Optional output file. If not provided 'patch_fi= le' will be" + echo " edited in place." +} + +usage() { + __usage >&2 +} + +args=3D$(getopt -o "h" -l "help" -- "$@") +eval set -- "$args" + +while true; do + case "$1" in + -h | --help) + usage + exit 0 + ;; + --) + shift + break + ;; + *) + usage + exit 1 + ;; + esac +done + +if [ $# !=3D 1 ] && [ $# !=3D 2 ]; then + usage + die "unexpected # of args $#" +fi + +patch=3D"$1" + +if [ ! -e "$patch" ]; then + die "missing file: $patch" +fi + +if [ $# =3D 2 ]; then + output=3D"$2" +else + output=3D"$patch" +fi + +TMPFILE=3D"$(mktemp)" + +skip_file=3Dfalse +in_hunk=3Dfalse +needs_update=3Dfalse +while IFS=3D read -r line; do + if [[ "$line" =3D~ ^---\ ]]; then + filename=3D"${line#--- */}" + + if [[ ! "$filename" =3D~ \.[ch]$ ]]; then + skip_file=3Dtrue + echo "$line" >> "$TMPFILE" + continue + fi + + case "$filename" in + *vmlinux.lds.h) + skip_file=3Dtrue + echo "$line" >> "$TMPFILE" + continue + ;; + esac + + skip_file=3Dfalse + in_hunk=3Dfalse + needs_update=3Dfalse + echo "$line" >> "$TMPFILE" + continue + fi + + if $skip_file; then + echo "$line" >> "$TMPFILE" + continue + fi + + if [[ "$line" =3D~ ^@@ ]]; then + + in_hunk=3Dtrue + needs_update=3Dfalse + + cur=3D"${line#*-}" + cur=3D"${cur%%,*}" + ((cur--)) + + last=3D"${line#*,}" + last=3D"${last%% *}" + last=3D$((cur + last)) + + echo "$line" >> "$TMPFILE" + continue + fi + + if $in_hunk; then + if [[ "$line" =3D~ ^\+ ]]; then + needs_update=3Dtrue + echo "$line" >> "$TMPFILE" + continue + fi + + if [[ "$line" =3D~ ^- ]]; then + ((cur++)) + needs_update=3Dtrue + echo "$line" >> "$TMPFILE" + continue + fi + + if $needs_update; then + ((cur++)) + needs_update=3Dfalse + echo "+#line $cur" >> "$TMPFILE" + echo "$line" >> "$TMPFILE" + continue + fi + + ((cur++)) + echo "$line" >> "$TMPFILE" + + if [ $cur =3D $last ]; then + in_hunk=3Dfalse + fi + + continue + fi + + echo "$line" >> "$TMPFILE" + +done < "$patch" + +mv -f "$TMPFILE" "$output" diff --git a/scripts/livepatch/klp-build b/scripts/livepatch/klp-build new file mode 100755 index 000000000000..e16584a4b697 --- /dev/null +++ b/scripts/livepatch/klp-build @@ -0,0 +1,355 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 +# +# Copyright (C) 2024 Josh Poimboeuf + +set -o errexit +set -o errtrace +set -o pipefail + +SCRIPT=3D"$(basename "$0")" +SCRIPTDIR=3D"$(readlink -f "$(dirname "$(type -p "$0")")")" + +SRC=3D"$(pwd)" +BUILD_DIR=3D"$SRC" +TMP_DIR=3D"$BUILD_DIR/klp-tmp" +ORIG_DIR=3D"$TMP_DIR/orig" +PATCHED_DIR=3D"$TMP_DIR/patched" +OUTPUT_DIR=3D"$TMP_DIR/out" +TMP_TMP_DIR=3D"$TMP_DIR/tmp" + +shopt -o xtrace | grep -q 'on' && XTRACE=3D1 + +status() { + echo -e "- $SCRIPT: $*" +} + +warn() { + str=3D"$1" + if [[ -n "$str" ]]; then + echo "$SCRIPT: error: $*" >&2 + else + echo "$SCRIPT: error" >&2 + fi +} + +die() { + warn "$@" + revert_applied_patches "--recount" + [[ -z "$DEBUG" ]] && rm -rf "$TMP_DIR" + exit 1 +} + +__trap() { + die "line $1" +} + +trap '__trap ${LINENO}' ERR INT + +__usage() { + echo "Usage: $SCRIPT [options] patch_file(s)" + echo "Generate a livepatch module" + echo + echo "Options:" + echo " -h, --help Show this help message and exit" + echo + echo "Arguments:" + echo " patch_file(s) One or more .patch files" +} + +usage() { + __usage >&2 +} + +apply_patch() { + local patch=3D"$1" + local extra_args=3D"$2" + + [[ -f "$patch" ]] || die "$patch doesn't exist" + + ( cd "$SRC" && git apply --quiet --check $extra_args "$patch" ) || die "$= patch failed to apply" + ( cd "$SRC" && git apply --quiet $extra_args "$patch" ) || die "$= patch failed to apply" + APPLIED_PATCHES+=3D("$patch") +} + +revert_patch() { + local patch=3D"$1" + local extra_args=3D"$2" + + ( cd "$SRC" && git apply --reverse --quiet $extra_args "$patch" ) || die = "$patch failed to apply" + APPLIED_PATCHES=3D("${APPLIED_PATCHES[@]/$patch}") +} + +revert_applied_patches() { + local patches=3D("${APPLIED_PATCHES[@]}") + local extra_args=3D"$1" + + for (( i=3D${#patches[@]}-1 ; i>=3D0 ; i-- )) ; do + local patch=3D"${patches[$i]}" + + # "deleted" entry can still exist as an empty string + [[ "$patch" ]] || continue + + revert_patch "${patches[$i]}" "$extra_args" + done + + APPLIED_PATCHES=3D() +} + +apply_patches() { + for patch in "${PATCHES[@]}"; do + apply_patch "$patch" + done +} + +validate_patches() { + apply_patches + revert_applied_patches +} + +refresh_patch() { + local patch=3D"$1" + local tmp=3D"$TMP_TMP_DIR" + + rm -rf "$tmp" + mkdir -p "$tmp" + + while read -r file; do + local dest + dest=3D"$tmp/a/$(dirname "$file")" + mkdir -p "$dest" + cp -f "$SRC/$file" "$dest" + done < <(grep -E '^(--- |\+\+\+ )' "$patch" | sed -E 's/(--- a\/|\+\+\+ b= \/)//' | sort | uniq) + + apply_patch "$patch" --recount + + while read -r file; do + local dest + dest=3D"$tmp/b/$(dirname "$file")" + mkdir -p "$dest" + cp -f "$SRC/$file" "$dest" + done < <(grep -E '^(--- |\+\+\+ )' "$patch" | sed -E 's/(--- a\/|\+\+\+ b= \/)//' | sort | uniq) + + revert_patch "$patch" --recount + + ( + cd "$tmp" + git diff --no-index --no-prefix a b > "$patch" || true + ) +} + +# Copy the patches to a temporary directory, fix their lines so as not to +# affect the __LINE__ macro for otherwise unchanged functions, and update +# $PATCHES to point to fixed patches. +copy_and_fix_patches() { + + idx=3D0001 + for patch in "${PATCHES[@]}"; do + cp -f "$patch" "$TMP_DIR/$idx-$(basename "$patch")" + idx=3D$(printf "%04d" $((10#$idx + 1))) + done + + PATCHES=3D() + idx=3D0001 + while true; do + patch=3D"$(ls "$TMP_DIR"/"$idx"-*.patch 2> /dev/null || true)" + [[ -z "$patch" ]] && break + + refresh_patch "$patch" + "$SCRIPTDIR/adjust-patch-lines" "$patch" || die "adjust-patch-lines fail= ed" + refresh_patch "$patch" + apply_patch "$patch" + + idx=3D$(printf "%04d" $((10#$idx + 1))) + done + + revert_applied_patches + + idx=3D0001 + while true; do + patch=3D"$(ls "$TMP_DIR"/"$idx"-*.patch 2> /dev/null || true)" + [[ -z "$patch" ]] && break + + PATCHES+=3D("$patch") + + idx=3D$(printf "%04d" $((10#$idx + 1))) + done +} + +build_kernel() { + local options + + if [[ -n "$VERBOSE" ]]; then + options=3D"V=3D1" + else + options=3D"-s" + fi + + ( cd "$SRC" && make -j"$(nproc)" "$options" vmlinux modules ) || die "ker= nel build failed" +} + +copy_orig_objs() { + if [[ "$XTRACE" =3D 1 ]]; then + set +x + fi + + while read -r _file; do + local file=3D"${_file/.ko/.o}" + local rel_file=3D"${file#"$BUILD_DIR"/}" + local dest_dir=3D"$ORIG_DIR/$(dirname "$rel_file")" + + # ignore any livepatch modules in pwd + if [[ "$_file" =3D *.ko ]] && [[ "$(dirname "$file")" -ef "$BUILD_DIR" ]= ]; then + continue + fi + + [[ -f "$file" ]] || die "can't find $file" + + mkdir -p "$dest_dir" + cp -f "$file" "$dest_dir" || die "cp -f $file $dest_dir failed" + done < <(find "$BUILD_DIR" -type f \( -name vmlinux.o -o -name "*.ko" \)) + + if [[ -n "$XTRACE" ]]; then + set -x + fi +} + +diff_objects() { + local timestamp=3D"$1" + + while read -r _file; do + local file=3D"${_file/.ko/.o}" + local rel_file=3D"${file#"$BUILD_DIR"/}" + local orig=3D"$ORIG_DIR/$rel_file" + local patched=3D"$PATCHED_DIR/$rel_file" + local output=3D"$OUTPUT_DIR/$rel_file" + + [[ -f "$file" ]] || die "can't find $file" + + mkdir -p "$(dirname "$patched")" + cp -f "$file" "$patched" + + mkdir -p "$(dirname "$output")" + + # status "diff: $rel_file" + + "$SRC/tools/objtool/objtool" klp diff "$orig" "$patched" "$output" || di= e "objtool klp diff failed" + done < <(find "$BUILD_DIR" -type f \( -name vmlinux.o -o -name "*.ko" \) = -newer "$timestamp") + + local nr_objs=3D"$(find "$OUTPUT_DIR" -type f \( -name vmlinux.o -o -name= "*.ko" \) | wc -l)" + + if [[ "$nr_objs" =3D 0 ]]; then + die "no changes detected" + fi +} + +build_patch_module() { + local makefile=3D"$OUTPUT_DIR/Kbuild" + local verbose + local replace + + cp -f "$SRC/scripts/livepatch/module.c" "$OUTPUT_DIR" + + echo "obj-m :=3D $NAME.o" > "$makefile" + echo -n "$NAME-y :=3D module.o" >> "$makefile" + + while read -r file; do + cp -f "$file" "$file"_shipped + echo -n " ${file#"$OUTPUT_DIR"/}" >> "$makefile" + done < <(find "$OUTPUT_DIR" -type f -name "*.o" ) + echo >> "$makefile" + + if [[ -n "$VERBOSE" ]]; then + verbose=3D"V=3D1" + else + verbose=3D"-s" + fi + + [[ $REPLACE =3D=3D 1 ]] && replace=3D"KCFLAGS=3D-DKLP_REPLACE" + + make -C . M=3D"$OUTPUT_DIR" "$verbose" $replace || die "module build fail= ed" + + cp -f "$OUTPUT_DIR/$NAME.ko" "$OUTPUT_DIR/$NAME.ko.prelink" + + "$SRC/tools/objtool/objtool" klp link "$OUTPUT_DIR/$NAME.ko" || die "objt= ool klp link failed" + + cp -f "$OUTPUT_DIR/$NAME.ko" . +} + +args=3D$(getopt -o dhn:v -l "debug,help,name:,verbose,noreplace" -- "$@") +eval set -- "$args" + +NAME=3D"livepatch" +REPLACE=3D1 + +while true; do + case "$1" in + -d | --debug) + DEBUG=3D1 + ;; + -h | --help) + usage + exit 0 + ;; + -n | --name) + NAME=3D"$2" + shift + ;; + --noreplace) + REPLACE=3D0 + ;; + -v | --verbose) + VERBOSE=3D1 + ;; + --) + shift + break + ;; + *) + usage + exit 1 + ;; + esac + shift +done + +if [[ $# -eq 0 ]]; then + usage + exit 1 +fi + +# not yet smart enough to handle anything other than in-tree builds from p= wd +[[ "$PWD" -ef "$SCRIPTDIR/../.." ]] || die "please run from the kernel roo= t directory" + +[[ -x "$SCRIPTDIR/adjust-patch-lines" ]] || die "can't find adjust-patch-l= ines script" + +validate_patches + +rm -rf "$TMP_DIR" +mkdir -p "$TMP_DIR" +APPLIED_PATCHES=3D() +PATCHES=3D("$@") + +# this updates ${PATCHES} to point to the modified versions +copy_and_fix_patches + +status "building original kernel" +build_kernel +copy_orig_objs + +touch "$TMP_DIR/timestamp" + +status "building patched kernel" +apply_patches +export KBUILD_MODPOST_WARN=3D1 +build_kernel +revert_applied_patches + +status "diffing objects" +diff_objects "$TMP_DIR/timestamp" + +status "building patch module" +build_patch_module + +status "success" +[[ -z "$DEBUG" ]] && rm -rf "$TMP_DIR" diff --git a/scripts/livepatch/module.c b/scripts/livepatch/module.c new file mode 100644 index 000000000000..101cabf6b2f1 --- /dev/null +++ b/scripts/livepatch/module.c @@ -0,0 +1,120 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Base module code for a livepatch kernel module + * + * Copyright (C) 2024 Josh Poimboeuf + */ + +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt + +#include +#include +#include + +// TODO livepatch could recognize these sections directly +// TODO use function checksums instead of sympos + +extern char __start_klp_objects, __stop_klp_objects; + +/* + * Create weak versions of the linker-created symbols to prevent modpost f= rom + * warning about unresolved symbols. + */ +__weak char __start_klp_objects =3D 0; +__weak char __stop_klp_objects =3D 0; +struct klp_object_ext *__start_objs =3D (struct klp_object_ext *)&__start_= klp_objects; +struct klp_object_ext *__stop_objs =3D (struct klp_object_ext *)&__stop_k= lp_objects; + +static struct klp_patch *patch; + +static int __init livepatch_mod_init(void) +{ + struct klp_object *objs; + unsigned int nr_objs; + int ret; + + nr_objs =3D __stop_objs - __start_objs; + + if (!__start_klp_objects || !nr_objs) { + pr_err("nothing to patch!\n"); + ret =3D -EINVAL; + goto err; + } + + patch =3D kzalloc(sizeof(*patch), GFP_KERNEL); + if (!patch) { + ret =3D -ENOMEM; + goto err; + } + + objs =3D kzalloc(sizeof(struct klp_object) * (nr_objs + 1), GFP_KERNEL); + if (!objs) { + ret =3D -ENOMEM; + goto err_free_patch; + } + + for (int i =3D 0; i < nr_objs; i++) { + struct klp_object_ext *obj_ext =3D __start_objs + i; + struct klp_func_ext *funcs_ext =3D obj_ext->funcs; + unsigned int nr_funcs =3D obj_ext->nr_funcs; + struct klp_func *funcs =3D objs[i].funcs; + struct klp_object *obj =3D objs + i; + + funcs =3D kzalloc(sizeof(struct klp_func) * (obj_ext->nr_funcs + 1), GFP= _KERNEL); + if (!funcs) { + ret =3D -ENOMEM; + for (int j =3D 0; j < i; j++) + kfree(objs[i].funcs); + goto err_free_objs; + } + + for (int j =3D 0; j < nr_funcs; j++) { + funcs[j].old_name =3D funcs_ext[j].old_name; + funcs[j].new_func =3D funcs_ext[j].new_func; + funcs[j].old_sympos =3D funcs_ext[j].sympos; + } + + obj->name =3D obj_ext->name; + obj->funcs =3D funcs; + + memcpy(&obj->callbacks, &obj_ext->callbacks, sizeof(struct klp_callbacks= )); + } + + patch->mod =3D THIS_MODULE; + patch->objs =3D objs; + + /* TODO patch->states */ + +#ifdef KLP_REPLACE + patch->replace =3D true; +#else + patch->replace =3D false; +#endif + + return klp_enable_patch(patch); + +err_free_objs: + kfree(objs); +err_free_patch: + kfree(patch); +err: + return ret; +} + +static void __exit livepatch_mod_exit(void) +{ + unsigned int nr_objs; + + nr_objs =3D __stop_objs - __start_objs; + + for (int i =3D 0; i < nr_objs; i++) + kfree(patch->objs[i].funcs); + + kfree(patch->objs); + kfree(patch); +} + +module_init(livepatch_mod_init); +module_exit(livepatch_mod_exit); +MODULE_LICENSE("GPL"); +MODULE_INFO(livepatch, "Y"); diff --git a/scripts/module.lds.S b/scripts/module.lds.S index 5cbae820bca0..aec4b9f0ec95 100644 --- a/scripts/module.lds.S +++ b/scripts/module.lds.S @@ -32,8 +32,15 @@ SECTIONS { =20 __patchable_function_entries : { *(__patchable_function_entries) } =20 + __klp_objects 0: ALIGN(8) { + __start_klp_objects =3D .; + KEEP(*(__klp_objects)) + __stop_klp_objects =3D .; + } + __klp_funcs 0: ALIGN(8) { KEEP(*(__klp_funcs)) } + #ifdef CONFIG_ARCH_USES_CFI_TRAPS - __kcfi_traps : { KEEP(*(.kcfi_traps)) } + __kcfi_traps : { KEEP(*(.kcfi_traps)) } #endif =20 #if defined(CONFIG_LTO_CLANG) || defined(CONFIG_LIVEPATCH) diff --git a/tools/include/linux/livepatch_ext.h b/tools/include/linux/live= patch_ext.h new file mode 100644 index 000000000000..4b71e72952d5 --- /dev/null +++ b/tools/include/linux/livepatch_ext.h @@ -0,0 +1,83 @@ +/* SPDX License-Identifier: GPL-2.0-or-later */ +/* + * External livepatch interfaces for patch creation tooling + * + * Copyright (C) 2024 Josh Poimboeuf + */ + +#ifndef _LINUX_LIVEPATCH_EXT_H_ +#define _LINUX_LIVEPATCH_EXT_H_ + +#include + +#define KLP_RELOC_SEC_PREFIX ".klp.rela." +#define KLP_SYM_PREFIX ".klp.sym." + +#define KLP_CALLBACKS_SEC ".discard.klp_callbacks" + +#define __KLP_PRE_PATCH_PREFIX __klp_pre_patch_callback_ +#define __KLP_POST_PATCH_PREFIX __klp_post_patch_callback_ +#define __KLP_PRE_UNPATCH_PREFIX __klp_pre_unpatch_callback_ +#define __KLP_POST_UNPATCH_PREFIX __klp_post_unpatch_callback_ + +#define KLP_PRE_PATCH_PREFIX __stringify(__KLP_PRE_PATCH_PREFIX) +#define KLP_POST_PATCH_PREFIX __stringify(__KLP_POST_PATCH_PREFIX) +#define KLP_PRE_UNPATCH_PREFIX __stringify(__KLP_PRE_UNPATCH_PREFIX) +#define KLP_POST_UNPATCH_PREFIX __stringify(__KLP_POST_UNPATCH_PREFIX) + +struct klp_object; + +typedef int (*klp_pre_patch_t)(struct klp_object *obj); +typedef void (*klp_post_patch_t)(struct klp_object *obj); +typedef void (*klp_pre_unpatch_t)(struct klp_object *obj); +typedef void (*klp_post_unpatch_t)(struct klp_object *obj); + +/** + * struct klp_callbacks - pre/post live-(un)patch callback structure + * @pre_patch: executed before code patching + * @post_patch: executed after code patching + * @pre_unpatch: executed before code unpatching + * @post_unpatch: executed after code unpatching + * @post_unpatch_enabled: flag indicating if post-unpatch callback + * should run + * + * All callbacks are optional. Only the pre-patch callback, if provided, + * will be unconditionally executed. If the parent klp_object fails to + * patch for any reason, including a non-zero error status returned from + * the pre-patch callback, no further callbacks will be executed. + */ +struct klp_callbacks { + klp_pre_patch_t pre_patch; + klp_post_patch_t post_patch; + klp_pre_unpatch_t pre_unpatch; + klp_post_unpatch_t post_unpatch; + bool post_unpatch_enabled; +}; + +/* + * 'struct klp_{func,object}_ext' are compact "external" representations of + * 'struct klp_{func,object}'. They are used by objtool for livepatch + * generation. The structs are then read by the livepatch module and conv= erted + * to the real structs before calling klp_enable_patch(). + * + * TODO make these the official API for klp_enable_patch(). That should + * simplify livepatch's interface as well as its data structure lifetime + * management. + * + * TODO possibly use struct_group_tagged() to declare these within the ori= ginal + * structs. + */ +struct klp_func_ext { + const char *old_name; + void *new_func; + unsigned long sympos; +}; + +struct klp_object_ext { + const char *name; + struct klp_func_ext *funcs; + struct klp_callbacks callbacks; + unsigned int nr_funcs; +}; + +#endif /* _LINUX_LIVEPATCH_EXT_H_ */ diff --git a/tools/objtool/Build b/tools/objtool/Build index a3cdf8af6635..f917e70f0fd0 100644 --- a/tools/objtool/Build +++ b/tools/objtool/Build @@ -8,8 +8,8 @@ objtool-y +=3D builtin-check.o objtool-y +=3D elf.o objtool-y +=3D objtool.o =20 -objtool-$(BUILD_ORC) +=3D orc_gen.o -objtool-$(BUILD_ORC) +=3D orc_dump.o +objtool-$(BUILD_ORC) +=3D orc_gen.o orc_dump.o +objtool-$(BUILD_KLP) +=3D klp.o klp-diff.o klp-link.o =20 objtool-y +=3D libstring.o objtool-y +=3D libctype.o diff --git a/tools/objtool/Makefile b/tools/objtool/Makefile index 6833804ca419..cdae220abca0 100644 --- a/tools/objtool/Makefile +++ b/tools/objtool/Makefile @@ -2,6 +2,25 @@ include ../scripts/Makefile.include include ../scripts/Makefile.arch =20 +BUILD_ORC :=3D n +BUILD_KLP :=3D n + +ifeq ($(SRCARCH),x86) +BUILD_ORC :=3D y +BUILD_KLP :=3D y +endif + +ifeq ($(SRCARCH),loongarch) +BUILD_ORC :=3D y +endif + +export BUILD_ORC BUILD_KLP + +ifeq ($(BUILD_KLP),y) +LIBXXHASH_FLAGS :=3D $(shell $(HOSTPKG_CONFIG) libxxhash --cflags 2>/dev/n= ull) +LIBXXHASH_LIBS :=3D $(shell $(HOSTPKG_CONFIG) libxxhash --libs 2>/dev/nul= l || echo -lxxhash) +endif + ifeq ($(srctree),) srctree :=3D $(patsubst %/,%,$(dir $(CURDIR))) srctree :=3D $(patsubst %/,%,$(dir $(srctree))) @@ -21,9 +40,6 @@ OBJTOOL_IN :=3D $(OBJTOOL)-in.o LIBELF_FLAGS :=3D $(shell $(HOSTPKG_CONFIG) libelf --cflags 2>/dev/null) LIBELF_LIBS :=3D $(shell $(HOSTPKG_CONFIG) libelf --libs 2>/dev/null || e= cho -lelf) =20 -LIBXXHASH_FLAGS :=3D $(shell $(HOSTPKG_CONFIG) libxxhash --cflags 2>/dev/n= ull) -LIBXXHASH_LIBS :=3D $(shell $(HOSTPKG_CONFIG) libxxhash --libs 2>/dev/nul= l || echo -lxxhash) - all: $(OBJTOOL) =20 INCLUDES :=3D -I$(srctree)/tools/include \ @@ -54,17 +70,6 @@ else Q =3D @ endif =20 -BUILD_ORC :=3D n - -ifeq ($(SRCARCH),x86) - BUILD_ORC :=3D y -endif - -ifeq ($(SRCARCH),loongarch) - BUILD_ORC :=3D y -endif - -export BUILD_ORC export srctree OUTPUT CFLAGS SRCARCH AWK include $(srctree)/tools/build/Makefile.include =20 diff --git a/tools/objtool/arch/x86/decode.c b/tools/objtool/arch/x86/decod= e.c index 5468fd15f380..bb24e963f371 100644 --- a/tools/objtool/arch/x86/decode.c +++ b/tools/objtool/arch/x86/decode.c @@ -94,6 +94,46 @@ s64 arch_insn_adjusted_addend(struct instruction *insn, = struct reloc *reloc) return phys_to_virt(addend); } =20 +static void scan_for_insn(struct section *sec, unsigned long offset, + unsigned long *insn_off, unsigned int *insn_len) +{ + unsigned long o =3D 0; + struct insn insn; + + while (1) { + + insn_decode(&insn, sec->data->d_buf + o, sec_size(sec) - o, + INSN_MODE_64); + + if (o + insn.length > offset) { + *insn_off =3D o; + *insn_len =3D insn.length; + return; + } + + o +=3D insn.length; + } +} + +u64 arch_adjusted_addend(struct reloc *reloc) +{ + unsigned int type =3D reloc_type(reloc); + s64 addend =3D reloc_addend(reloc); + unsigned long insn_off; + unsigned int insn_len; + + if (type =3D=3D R_X86_64_PLT32) + return addend + 4; + + if (type !=3D R_X86_64_PC32 || !is_text_section(reloc->sec->base)) + return addend; + + scan_for_insn(reloc->sec->base, reloc_offset(reloc), + &insn_off, &insn_len); + + return addend + insn_off + insn_len - reloc_offset(reloc); +} + unsigned long arch_jump_destination(struct instruction *insn) { return insn->offset + insn->len + insn->immediate; diff --git a/tools/objtool/check.c b/tools/objtool/check.c index 0e9e485cd3b6..f55dec2932de 100644 --- a/tools/objtool/check.c +++ b/tools/objtool/check.c @@ -647,6 +647,20 @@ static void create_fake_symbol(struct objtool_file *fi= le, const char *name_pfx, elf_create_symbol(file->elf, name, sec, STB_LOCAL, STT_OBJECT, offset, si= ze); } =20 +static bool is_livepatch_module(struct objtool_file *file) +{ + struct section *sec; + + if (!opts.module) + return false; + + sec =3D find_section_by_name(file->elf, ".modinfo"); + if (!sec) + return false; + + return memmem(sec->data->d_buf, sec_size(sec), "livepatch=3DY", 12); +} + static void create_static_call_sections(struct objtool_file *file) { struct static_call_site *site; @@ -659,7 +673,14 @@ static void create_static_call_sections(struct objtool= _file *file) sec =3D find_section_by_name(file->elf, ".static_call_sites"); if (sec) { INIT_LIST_HEAD(&file->static_call_list); - WARN("file already has .static_call_sites section, skipping"); + + /* + * Livepatch modules may have already extracted the static call + * site entries. + */ + if (!file->klp) + WARN("file already has .static_call_sites section, skipping"); + return; } =20 @@ -696,7 +717,7 @@ static void create_static_call_sections(struct objtool_= file *file) =20 key_sym =3D find_symbol_by_name(file->elf, tmp); if (!key_sym) { - if (!opts.module) + if (!opts.module || file->klp) ERROR("static_call: can't find static_call_key symbol: %s", tmp); =20 /* @@ -2406,6 +2427,8 @@ static void mark_rodata(struct objtool_file *file) =20 static void decode_sections(struct objtool_file *file) { + file->klp =3D is_livepatch_module(file); + mark_rodata(file); =20 init_pv_ops(file); @@ -4006,7 +4029,7 @@ static void add_prefix_symbol(struct objtool_file *fi= le, struct symbol *func) continue; =20 sym_pfx =3D elf_create_prefix_symbol(file->elf, func, opts.prefix); - if (!sym_pfx) + if (!sym_pfx && !file->klp) ERROR("duplicate prefix symbol for %s\n", func->name); =20 break; diff --git a/tools/objtool/elf.c b/tools/objtool/elf.c index 022873bf7064..7960921996bd 100644 --- a/tools/objtool/elf.c +++ b/tools/objtool/elf.c @@ -21,6 +21,7 @@ #include #include #include +#include #include =20 #define ALIGN_UP(x, align_to) (((x) + ((align_to)-1)) & ~((align_to)-1)) @@ -456,6 +457,8 @@ static void elf_add_symbol(struct elf *elf, struct symb= ol *sym) else entry =3D &sym->sec->symbol_list; list_add(&sym->list, entry); + + list_add_tail(&sym->global_list, &elf->symbols); elf_hash_add(symbol, &sym->hash, sym->idx); elf_hash_add(symbol_name, &sym->name_hash, str_hash(sym->name)); =20 @@ -505,6 +508,8 @@ static void read_symbols(struct elf *elf) elf->symbol_data =3D calloc(symbols_nr, sizeof(*sym)); ERROR_ON(!elf->symbol_data, "calloc"); =20 + INIT_LIST_HEAD(&elf->symbols); + for (i =3D 0; i < symbols_nr; i++) { sym =3D &elf->symbol_data[i]; =20 @@ -720,7 +725,7 @@ static void elf_update_symbol(struct elf *elf, struct s= ection *symtab, static struct symbol *__elf_create_symbol(struct elf *elf, const char *nam= e, struct section *sec, unsigned int bind, unsigned int type, unsigned long offset, - size_t size) + size_t size, bool klp) { struct section *symtab, *symtab_shndx; Elf32_Word first_non_local, new_idx; @@ -735,6 +740,9 @@ static struct symbol *__elf_create_symbol(struct elf *e= lf, const char *name, sym->sym.st_name =3D elf_add_string(elf, NULL, sym->name); } =20 + if (klp) + sym->sym.st_shndx =3D SHN_LIVEPATCH; + sym->sec =3D sec ? : find_section_by_index(elf, 0); =20 sym->sym.st_info =3D GELF_ST_INFO(bind, type); @@ -799,7 +807,7 @@ struct symbol *elf_create_symbol(struct elf *elf, const= char *name, unsigned int type, unsigned long offset, size_t size) { - return __elf_create_symbol(elf, name, sec, bind, type, offset, size); + return __elf_create_symbol(elf, name, sec, bind, type, offset, size, fals= e); } =20 struct symbol *elf_create_section_symbol(struct elf *elf, struct section *= sec) @@ -812,6 +820,12 @@ struct symbol *elf_create_section_symbol(struct elf *e= lf, struct section *sec) return sym; } =20 +struct symbol *elf_create_klp_symbol(struct elf *elf, const char *name, + unsigned int bind, unsigned int type) +{ + return __elf_create_symbol(elf, name, NULL, bind, type, 0, 0, true); +} + struct symbol * elf_create_prefix_symbol(struct elf *elf, struct symbol *orig, size_t size) { diff --git a/tools/objtool/include/objtool/arch.h b/tools/objtool/include/o= bjtool/arch.h index 14911fdfdc8f..d9f019ef89a7 100644 --- a/tools/objtool/include/objtool/arch.h +++ b/tools/objtool/include/objtool/arch.h @@ -82,6 +82,7 @@ bool arch_callee_saved_reg(unsigned char reg); unsigned long arch_jump_destination(struct instruction *insn); =20 s64 arch_insn_adjusted_addend(struct instruction *insn, struct reloc *relo= c); +u64 arch_adjusted_addend(struct reloc *reloc); =20 const char *arch_nop_insn(int len); const char *arch_ret_insn(int len); diff --git a/tools/objtool/include/objtool/builtin.h b/tools/objtool/includ= e/objtool/builtin.h index eab376169c1e..26bbf04afb24 100644 --- a/tools/objtool/include/objtool/builtin.h +++ b/tools/objtool/include/objtool/builtin.h @@ -46,5 +46,6 @@ extern struct opts opts; extern int cmd_parse_options(int argc, const char **argv, const char * con= st usage[]); =20 extern int objtool_run(int argc, const char **argv); +extern int cmd_klp(int argc, const char **argv); =20 #endif /* _BUILTIN_H */ diff --git a/tools/objtool/include/objtool/elf.h b/tools/objtool/include/ob= jtool/elf.h index 1f14f33d279e..43839b3ac80f 100644 --- a/tools/objtool/include/objtool/elf.h +++ b/tools/objtool/include/objtool/elf.h @@ -16,6 +16,7 @@ #include #include =20 +#define SEC_NAME_LEN 512 #define SYM_NAME_LEN 512 =20 #ifdef LIBELF_USE_DEPRECATED @@ -53,10 +54,12 @@ struct section { int idx; bool _changed, text, rodata, noinstr, init, truncate; struct reloc *relocs; + struct section *twin; }; =20 struct symbol { struct list_head list; + struct list_head global_list; struct rb_node node; struct elf_hash_node hash; struct elf_hash_node name_hash; @@ -77,8 +80,11 @@ struct symbol { u8 warned : 1; u8 embedded_insn : 1; u8 local_label : 1; + u8 changed : 1; + u8 added : 1; struct list_head pv_target; struct reloc *relocs; + struct symbol *twin, *clone; =20 XXH3_state_t *checksum_state; XXH64_hash_t checksum; @@ -99,6 +105,7 @@ struct elf { const char *name, *tmp_name; unsigned int num_files; struct list_head sections; + struct list_head symbols; unsigned long num_relocs; =20 int symbol_bits; @@ -138,6 +145,8 @@ struct symbol *elf_create_symbol(struct elf *elf, const= char *name, struct symbol *elf_create_section_symbol(struct elf *elf, struct section *= sec); struct symbol *elf_create_prefix_symbol(struct elf *elf, struct symbol *or= ig, size_t size); +struct symbol *elf_create_klp_symbol(struct elf *elf, const char *name, + unsigned int bind, unsigned int type); =20 struct reloc *elf_create_reloc(struct elf *elf, struct section *sec, unsigned long offset, struct symbol *sym, @@ -412,11 +421,14 @@ static inline void set_reloc_type(struct elf *elf, st= ruct reloc *reloc, unsigned #define sec_for_each_sym_continue_reverse(sec, sym) \ list_for_each_entry_continue_reverse(sym, &sec->symbol_list, list) =20 +#define sec_prev_sym(sec, sym) \ + sym->list.prev =3D=3D &sec->symbol_list ? NULL : list_prev_entry(sym, lis= t) + #define for_each_sym(elf, sym) \ - for (struct section *__sec, *__fake =3D (struct section *)1; \ - __fake; __fake =3D NULL) \ - for_each_sec(elf, __sec) \ - sec_for_each_sym(__sec, sym) + list_for_each_entry(sym, &elf->symbols, global_list) + +#define for_each_sym_continue(elf, sym) \ + list_for_each_entry_continue(sym, &elf->symbols, global_list) =20 #define for_each_reloc(rsec, reloc) \ for (int __i =3D 0, __fake =3D 1; __fake; __fake =3D 0) \ diff --git a/tools/objtool/include/objtool/klp.h b/tools/objtool/include/ob= jtool/klp.h new file mode 100644 index 000000000000..0df1dd273e1e --- /dev/null +++ b/tools/objtool/include/objtool/klp.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ +/* + * Copyright (C) 2024 Josh Poimboeuf + */ +#ifndef _OBJTOOL_KLP_H +#define _OBJTOOL_KLP_H + +#define SHF_RELA_LIVEPATCH 0x00100000 +#define SHN_LIVEPATCH 0xff20 + +#define KLP_RELOCS_SEC ".klp.relocs" +#define KLP_OBJECTS_SEC "__klp_objects" +#define KLP_FUNCS_SEC "__klp_funcs" +#define KLP_STRINGS_SEC ".rodata.klp.str1.1" + +struct klp_reloc { + void *offset; + void *sym; + u32 type; +}; + +int cmd_klp_diff(int argc, const char **argv); +int cmd_klp_link(int argc, const char **argv); + +#endif /* _OBJTOOL_KLP_H */ diff --git a/tools/objtool/include/objtool/objtool.h b/tools/objtool/includ= e/objtool/objtool.h index 3280abcce55e..f562b08bfbff 100644 --- a/tools/objtool/include/objtool/objtool.h +++ b/tools/objtool/include/objtool/objtool.h @@ -30,7 +30,7 @@ struct objtool_file { struct list_head mcount_loc_list; struct list_head endbr_list; struct list_head call_list; - bool ignore_unreachables, hints, rodata; + bool ignore_unreachables, hints, rodata, klp; =20 unsigned int nr_endbr; unsigned int nr_endbr_int; diff --git a/tools/objtool/klp-diff.c b/tools/objtool/klp-diff.c new file mode 100644 index 000000000000..76296e38f9ff --- /dev/null +++ b/tools/objtool/klp-diff.c @@ -0,0 +1,1112 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2024 Josh Poimboeuf + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define ALIGN_DOWN(x, align_to) ((x) & ~((align_to)-1)) +#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER)) + +struct elfs { + struct elf *orig, *patched, *out; +}; + +struct export { + struct hlist_node hash; + char *mod, *sym; +}; + +static DEFINE_HASHTABLE(exports, 15); + +static inline u32 str_hash(const char *str) +{ + return jhash(str, strlen(str), 0); +} + +static void read_exports(void) +{ + const char *symvers =3D "Module.symvers"; + char line[1024]; + FILE *file; + + file =3D fopen(symvers, "r"); + ERROR_ON(!file, "can't open '%s', \"objtool diff\" should be run from the= kernel tree", symvers); + + while (fgets(line, 1024, file)) { + char *sym, *mod, *exp; + struct export *export; + + sym =3D strchr(line, '\t'); + ERROR_ON(!sym, "malformed Module.symvers"); + + *sym++ =3D '\0'; + + mod =3D strchr(sym, '\t'); + ERROR_ON(!mod, "malformed Module.symvers"); + + *mod++ =3D '\0'; + + exp =3D strchr(mod, '\t'); + ERROR_ON(!exp, "malformed Module.symvers"); + + *exp++ =3D '\0'; + + ERROR_ON(*sym =3D=3D '\0' || *mod =3D=3D '\0', "malformed Module.symvers= "); + + export =3D calloc(1, sizeof(*export)); + ERROR_ON(!export, "calloc"); + + export->mod =3D strdup(mod); + export->sym =3D strdup(sym); + hash_add(exports, &export->hash, str_hash(sym)); + } +} + +static int read_sym_checksums(struct elf *elf) +{ + struct section *sec; + + sec =3D find_section_by_name(elf, SYM_CHECKSUM_SEC); + if (!sec) + return 0; + + if (!sec->rsec) + ERROR("missing reloc section for " SYM_CHECKSUM_SEC); + + if (sec_size(sec) % sizeof(struct sym_checksum)) + ERROR("struct sym_checksum size mismatch"); + + for (int i =3D 0; i < sec_size(sec) / sizeof(struct sym_checksum); i++) { + struct sym_checksum *sym_checksum; + struct reloc *reloc; + struct symbol *sym; + + sym_checksum =3D (struct sym_checksum *)sec->data->d_buf + i; + + reloc =3D find_reloc_by_dest(elf, sec, i * sizeof(*sym_checksum)); + if (!reloc) + ERROR("can't find reloc for sym_checksum[%d]", i); + + sym =3D reloc->sym; + + if (is_section_symbol(sym)) + ERROR("not sure how to handle section %s", sym->name); + + if (is_function_symbol(sym)) + sym->checksum =3D sym_checksum->checksum; + } + + return 0; +} +static struct symbol *first_file_symbol(struct elf *elf) +{ + struct symbol *sym; + + for_each_sym(elf, sym) + if (is_file_symbol(sym)) + return sym; + + return NULL; +} + +static struct symbol *next_file_symbol(struct elf *elf, struct symbol *sym) +{ + for_each_sym_continue(elf, sym) + if (is_file_symbol(sym)) + return sym; + + return NULL; +} + +/* + * Certain static local variables should never be correlated. They will be + * used in place rather than referencing the originals. + */ +static bool is_uncorrelated_static_local(struct symbol *sym) +{ + static const char * const vars[] =3D { + "__key.", + "__warned.", + "__already_done.", + "__func__.", + "_rs.", + "CSWTCH.", + }; + + if (!is_object_symbol(sym) || !is_local_symbol(sym)) + return false; + + if (!strcmp(sym->sec->name, ".data.once")) + return true; + + for (int i =3D 0; i < ARRAY_SIZE(vars); i++) { + if (strstarts(sym->name, vars[i])) + return true; + } + + return false; +} + +static bool is_special_section(struct section *sec) +{ + static const char * const specials[] =3D { + ".altinstructions", + ".smp_locks", + "__bug_table", + "__ex_table", + "__jump_table", + "__mcount_loc", + /* + * .static_call_sites is generated by "objtool --static-call" + * which will run again later at livepatch module link time. + * So one might be forgiven for thinking it doesn't need to be + * extracted here. + * + * However, when run on modules, objtool blocks access to + * unexported static call keys. + * + * So extract it here to inherit the non-module preferential + * treatment. The later static call processing will be skipped + * when it sees this section already exists. + */ + ".static_call_sites", + }; + + static const char * const non_special_discards[] =3D { + ".discard.addressable", + SYM_CHECKSUM_SEC, + }; + + for (int i =3D 0; i < ARRAY_SIZE(specials); i++) + if (!strcmp(sec->name, specials[i])) + return true; + + /* Most .discard sections are special */ + for (int i =3D 0; i < ARRAY_SIZE(non_special_discards); i++) + if (!strcmp(sec->name, non_special_discards[i])) + return false; + return strstarts(sec->name, ".discard."); +} + +/* + * These sections are referenced by special sections but aren't considered + * special sections themselves. + */ +static bool is_special_section_aux(struct section *sec) +{ + static const char * const specials_aux[] =3D { + ".altinstr_replacement", + ".altinstr_aux", + }; + + for (int i =3D 0; i < ARRAY_SIZE(specials_aux); i++) + if (!strcmp(sec->name, specials_aux[i])) + return true; + + return false; +} + +/* + * These symbols should never be correlated, so their local patched versio= ns + * are used instead of linking to the originals. + */ +static bool dont_correlate(struct symbol *sym) +{ + return is_file_symbol(sym) || + is_null_symbol(sym) || + is_section_symbol(sym) || + is_prefix_symbol(sym) || + is_uncorrelated_static_local(sym) || + is_string_section(sym->sec) || + is_special_section(sym->sec) || + is_special_section_aux(sym->sec) || + strstarts(sym->name, "__UNIQUE_ID") || + strstarts(sym->name, "__initcall__"); +} + +/* + * For each symbol in the original kernel, find its corresponding "twin" i= n the + * patched kernel. + */ +static void correlate_symbols(struct elf *elf1, struct elf *elf2) +{ + struct symbol *file1_sym, *file2_sym; + struct symbol *sym1, *sym2; + + /* Correlate locals */ + for (file1_sym =3D first_file_symbol(elf1), + file2_sym =3D first_file_symbol(elf2); ; + file1_sym =3D next_file_symbol(elf1, file1_sym), + file2_sym =3D next_file_symbol(elf2, file2_sym)) { + + if (!file1_sym && file2_sym) + ERROR("FILE symbol mismatch: NULL !=3D %s", file2_sym->name); + + if (file1_sym && !file2_sym) + ERROR("FILE symbol mismatch: %s !=3D NULL", file1_sym->name); + + if (!file1_sym) + break; + + if (strcmp(file1_sym->name, file2_sym->name)) + ERROR("FILE symbol mismatch: %s !=3D %s",file1_sym->name, file2_sym->na= me); + + file1_sym->twin =3D file2_sym; + file2_sym->twin =3D file1_sym; + + sym1 =3D file1_sym; + + for_each_sym_continue(elf1, sym1) { + if (is_file_symbol(sym1) || !is_local_symbol(sym1)) + break; + + if (dont_correlate(sym1)) + continue; + + sym2 =3D file2_sym; + for_each_sym_continue(elf2, sym2) { + if (is_file_symbol(sym2) || !is_local_symbol(sym2)) + break; + + if (sym2->twin || dont_correlate(sym2)) + continue; + + if (strcmp(sym1->demangled_name, sym2->demangled_name)) + continue; + + sym1->twin =3D sym2; + sym2->twin =3D sym1; + break; + } + } + } + + /* Correlate globals */ + for_each_sym(elf1, sym1) { + if (sym1->bind =3D=3D STB_LOCAL) + continue; + + sym2 =3D find_global_symbol_by_name(elf2, sym1->name); + + if (sym2 && !sym2->twin && !strcmp(sym1->name, sym2->name)) { + sym1->twin =3D sym2; + sym2->twin =3D sym1; + } + } + + for_each_sym(elf1, sym1) { + if (sym1->twin || dont_correlate(sym1)) + continue; + WARN("no correlation: %s", sym1->name); + } +} + +/* "sympos" is used by livepatch to disambiguate duplicate symbol names */ +static unsigned long find_sympos(struct elf *elf, struct symbol *sym) +{ + unsigned long sympos =3D 0, nr_matches =3D 0; + bool has_dup =3D false; + struct symbol *s; + + if (sym->bind !=3D STB_LOCAL) + return 0; + + for_each_sym(elf, s) { + if (!strcmp(s->name, sym->name)) { + nr_matches++; + if (s =3D=3D sym) + sympos =3D nr_matches; + else + has_dup =3D true; + } + } + + if (!sympos) + ERROR("can't find sympos for %s", sym->name); + + return has_dup ? sympos : 0; +} + +static void clone_sym_relocs(struct elfs *e, struct symbol *sym_patched); + +static struct symbol *__clone_symbol(struct elf *elf, struct symbol *sym_p= atched, + bool data_too) +{ + struct section *sec =3D NULL; + unsigned long offset =3D 0; + struct symbol *sym; + + if (data_too && sym_has_section(sym_patched)) { + struct section *sec_patched =3D sym_patched->sec; + + sec =3D find_section_by_name(elf, sec_patched->name); + if (!sec) + sec =3D elf_create_section(elf, sec_patched->name, 0, + sec_patched->sh.sh_entsize, + sec_patched->sh.sh_type, + sec_patched->sh.sh_addralign, + sec_patched->sh.sh_flags); + + if (is_string_section(sym_patched->sec)) { + sym =3D elf_create_section_symbol(elf, sec); + goto sym_created; + } + + if (!is_section_symbol(sym_patched)) + offset =3D sec_size(sec); + + if (sym_patched->len || is_section_symbol(sym_patched)) { + void *data =3D NULL; + size_t size; + + // bss doesn't have data + if (sym_patched->sec->data->d_buf) + data =3D sym_patched->sec->data->d_buf + sym_patched->offset; + + if (is_section_symbol(sym_patched)) + size =3D sec_size(sym_patched->sec); + else + size =3D sym_patched->len; + + elf_add_data(elf, sec, data, size); + } + } + + sym =3D elf_create_symbol(elf, sym_patched->name, sec, sym_patched->bind, + sym_patched->type, offset, sym_patched->len); + +sym_created: + sym_patched->clone =3D sym; + sym->clone =3D sym_patched; + + return sym; +} + +/* + * Copy a symbol to the output object, optionally including its data and + * relocations. + */ +static struct symbol *clone_symbol(struct elfs *e, struct symbol *sym_patc= hed, + bool data_too) +{ + if (sym_patched->clone) + return sym_patched->clone; + + /* Clone prefix symbol */ + if (data_too && is_function_symbol(sym_patched) && sym_patched->offset) { + struct symbol *pfx_patched; + + pfx_patched =3D sec_prev_sym(sym_patched->sec, sym_patched); + + if (pfx_patched && is_prefix_symbol(pfx_patched)) + __clone_symbol(e->out, pfx_patched, true); + } + + __clone_symbol(e->out, sym_patched, data_too); + + if (data_too) + clone_sym_relocs(e, sym_patched); + + return sym_patched->clone; +} + +/* + * Copy all changed functions (and their dependencies) from the patched ob= ject + * to the output object. + */ +static void clone_changed_functions(struct elfs *e) +{ + struct symbol *sym_orig, *sym_patched; + + /* Find changed functions */ + for_each_sym(e->orig, sym_orig) { + if (!is_function_symbol(sym_orig) || is_prefix_symbol(sym_orig)) + continue; + + if (!sym_orig->twin) + continue; + + if (sym_orig->checksum !=3D sym_orig->twin->checksum) { + printf("%s: changed: %s\n", Objname, sym_orig->name); + sym_orig->twin->changed =3D 1; + } + } + + /* Find added functions */ + for_each_sym(e->patched, sym_patched) { + if (!is_function_symbol(sym_patched) || is_prefix_symbol(sym_patched)) + continue; + + if (!sym_patched->twin) { + sym_patched->added =3D 1; + printf("%s: added: %s\n", Objname, sym_patched->name); + } + } + + /* Clone changed and added functions */ + for_each_sym(e->patched, sym_patched) { + if (sym_patched->changed || sym_patched->added) + clone_symbol(e, sym_patched, true); + } +} + +/* + * Determine whether a relocation should reference the section rather than= the + * underlying symbol. + */ +static bool section_reference_needed(struct section *sec) +{ + /* + * String symbols are zero-length and uncorrelated. It's easier to + * deal with them as section symbols. + */ + if (is_string_section(sec)) + return true; + + /* + * .rodata has mostly anonymous data so there's no way to determine the + * length of a needed reference. just copy the whole section. + */ + if (!strcmp(sec->name, ".rodata")) + return true; + + /* UBSAN anonymous data */ + if (strstarts(sec->name, ".data..Lubsan")) + return true; + + return false; +} + +static bool is_reloc_allowed(struct reloc *reloc) +{ + return section_reference_needed(reloc->sym->sec) =3D=3D + is_section_symbol(reloc->sym); +} + +static struct export *find_export(struct elf *elf, struct symbol *sym) +{ + struct export *export; + + hash_for_each_possible(exports, export, hash, str_hash(sym->name)) { + if (!strcmp(export->sym, sym->name)) + return export; + } + + return NULL; +} + +static const char *__find_modname(struct elfs *e) +{ + struct section *sec; + char *name; + + sec =3D find_section_by_name(e->orig, ".modinfo"); + if (!sec) + ERROR("missing .modinfo section"); + + name =3D memmem(sec->data, sec_size(sec), "\0name=3D", 6); + if (name) + return name + 6; + + name =3D strdup(e->orig->name); + ERROR_ON(!name, "strdup"); + + for (char *c =3D name; *c; c++) { + if (*c =3D=3D '/') + name =3D c + 1; + else if (*c =3D=3D '-') + *c =3D '_'; + else if (*c =3D=3D '.') { + *c =3D '\0'; + break; + } + } + + return name; +} + +/* Get the object's module name as defined by the kernel (and klp_object) = */ +static const char *find_modname(struct elfs *e) +{ + static const char *modname; + + if (modname) + return modname; + + modname =3D __find_modname(e); + return modname; +} + +static bool klp_reloc_needed(struct elf *elf_patched, struct reloc *reloc_= patched) +{ + struct symbol *sym_patched =3D reloc_patched->sym; + struct export *export; + + /* no external symbol to reference */ + if (dont_correlate(sym_patched)) + return false; + + /* For cloned functions, a regular reloc will do. */ + if (sym_patched->changed || sym_patched->added) + return false; + + /* + * If exported by a module, it has to be a klp reloc. Thanks to the + * clusterfoot that is late module patching, the patch module is + * allowed to be loaded before any modules it depends on. + * + * If exported by vmlinux, a normal reloc will work. + */ + export =3D find_export(elf_patched, sym_patched); + if (export) + return strcmp(export->mod, "vmlinux"); + + if (!sym_patched->twin) { + /* + * Presumably the symbol and its reference were added by the + * patch. The symbol could be defined in this .o or in another + * .o in the patch module. + * + * This should be checked *after* the exports, for the case + * where the patch adds a reference to an exported symbol. + */ + return false; + } + + /* Unexported symbol which lives in the original vmlinux or module. */ + return true; +} + +static int convert_reloc_sym_to_secsym(struct elf *elf, struct reloc *relo= c) +{ + struct symbol *sym =3D reloc->sym; + struct section *sec =3D sym->sec; + + if (!sec->sym) + elf_create_section_symbol(elf, sec); + + reloc->sym =3D sec->sym; + set_reloc_sym(elf, reloc, sym->idx); + set_reloc_addend(elf, reloc, sym->offset + reloc_addend(reloc)); + return 0; +} + +static int convert_reloc_secsym_to_sym(struct elf *elf, struct reloc *relo= c) +{ + struct symbol *sym =3D reloc->sym; + struct section *sec =3D sym->sec; + + /* If the symbol has a dedicated section, it's easy to find */ + sym =3D find_symbol_by_offset(sec, 0); + if (sym && sym->len =3D=3D sec_size(sec)) + goto found_sym; + + /* No dedicated section; find the symbol manually */ + sym =3D find_symbol_containing(sec, arch_adjusted_addend(reloc)); + if (!sym) { + /* + * This can happen for special section references to weak code + * whose symbol has been stripped by the linker. + */ + return -1; + } + +found_sym: + reloc->sym =3D sym; + set_reloc_sym(elf, reloc, sym->idx); + set_reloc_addend(elf, reloc, reloc_addend(reloc) - sym->offset); + return 0; +} + +/* + * Convert a relocation symbol reference to the needed format: either a se= ction + * symbol or the underlying symbol itself. + */ +static int convert_reloc_sym(struct elf *elf, struct reloc *reloc) +{ + if (is_reloc_allowed(reloc)) + return 0; + + if (section_reference_needed(reloc->sym->sec)) + return convert_reloc_sym_to_secsym(elf, reloc); + else + return convert_reloc_secsym_to_sym(elf, reloc); +} + +/* + * Convert a regular relocation to a klp relocation (sort of). + */ +static void clone_reloc_klp(struct elfs *e, struct reloc *reloc_patched, + struct section *sec, unsigned long offset, + struct export *export) +{ + struct symbol *sym_patched =3D reloc_patched->sym; + s64 addend =3D reloc_addend(reloc_patched); + const char *sym_modname, *sym_orig_name; + static struct section *klp_relocs; + struct symbol *sym, *klp_sym; + unsigned long klp_reloc_off; + char sym_name[SYM_NAME_LEN]; + struct klp_reloc klp_reloc; + unsigned long sympos; + + if (!sym_patched->twin) + ERROR("unexpected klp reloc for new symbol %s", sym_patched->name); + + /* + * First, copy the original reloc and symbol as-is so objtool will be + * able to process the code correctly during module link time. This + * relocation will be disabled later by cmd_klp_link(). + */ + + sym =3D sym_patched->clone; + if (!sym) { + sym =3D elf_create_klp_symbol(e->out, sym_patched->name, + sym_patched->bind, + sym_patched->type); + sym_patched->clone =3D sym; + sym->clone =3D sym_patched; + } + + elf_create_reloc(e->out, sec, offset, sym, addend, reloc_type(reloc_patch= ed)); + + /* + * Second, create the klp symbol. + */ + + if (export) { + sym_modname =3D export->mod; + sym_orig_name =3D export->sym; + sympos =3D 0; + } else { + sym_modname =3D find_modname(e); + sym_orig_name =3D sym_patched->twin->name; + sympos =3D find_sympos(e->orig, sym_patched->twin); + } + + /* symbol format: .klp.sym.modname.sym_name,sympos */ + snprintf(sym_name, SYM_NAME_LEN, KLP_SYM_PREFIX "%s.%s,%ld", + sym_modname, sym_orig_name, sympos); + + klp_sym =3D find_symbol_by_name(e->out, sym_name); + if (!klp_sym) + klp_sym =3D elf_create_klp_symbol(e->out, sym_name, + sym_patched->bind, + sym_patched->type); + + /* + * Third, create the .klp_relocs entry, which will be converted to an + * actual klp rela by cmd_klp_link(). + * + * This intermediate step is necessary to prevent corruption by the + * linker, which doesn't know how to properly handle two rela sections + * applying to the same base section. + */ + + if (!klp_relocs) + klp_relocs =3D elf_create_section(e->out, KLP_RELOCS_SEC, 0, + 0, SHT_PROGBITS, 8, SHF_ALLOC); + + klp_reloc_off =3D sec_size(klp_relocs); + memset(&klp_reloc, 0, sizeof(klp_reloc)); + + klp_reloc.type =3D reloc_type(reloc_patched); + elf_add_data(e->out, klp_relocs, &klp_reloc, sizeof(klp_reloc)); + + /* klp_reloc.offset */ + if (!sec->sym) + elf_create_section_symbol(e->out, sec); + elf_create_reloc(e->out, klp_relocs, + klp_reloc_off + offsetof(struct klp_reloc, offset), + sec->sym, offset, R_ABS64); + + /* klp_reloc.sym */ + elf_create_reloc(e->out, klp_relocs, + klp_reloc_off + offsetof(struct klp_reloc, sym), + klp_sym, addend, R_ABS64); + +} + +/* Copy a reloc and its symbol to the output object */ +static void clone_reloc(struct elfs *e, struct reloc *reloc_patched, + struct section *sec, unsigned long offset) +{ + struct symbol *sym_patched =3D reloc_patched->sym; + struct export *export =3D find_export(e->out, sym_patched); + s64 addend =3D reloc_addend(reloc_patched); + struct symbol *sym; + + if (!is_reloc_allowed(reloc_patched)) + ERROR_FUNC(reloc_patched->sec->base, reloc_offset(reloc_patched), + "missing symbol for reference to %s+0x%lx", + sym_patched->name, addend); + + if (klp_reloc_needed(e->patched, reloc_patched)) { + clone_reloc_klp(e, reloc_patched, sec, offset, export); + return; + } + + sym =3D clone_symbol(e, sym_patched, !export); + + if (is_string_section(sym_patched->sec)) + addend =3D elf_add_string(e->out, sym->sec, + reloc_patched->sym->sec->data->d_buf + addend); + + elf_create_reloc(e->out, sec, offset, sym, addend, reloc_type(reloc_patch= ed)); +} + +/* Copy all relocs needed for a symbol's contents */ +static void clone_sym_relocs(struct elfs *e, struct symbol *sym_patched) +{ + struct section *rsec_patched =3D sym_patched->sec->rsec; + struct reloc *reloc_patched; + unsigned long start, end; + struct symbol *sym; + + sym =3D sym_patched->clone; + if (!sym) + ERROR("no clone for %s", sym_patched->name); + + if (!rsec_patched) + return; + + if (!is_section_symbol(sym_patched) && !sym_patched->len) + return; + + if (is_string_section(sym_patched->sec)) + return; + + if (is_section_symbol(sym_patched)) { + start =3D 0; + end =3D sec_size(sym_patched->sec); + } else { + start =3D sym_patched->offset; + end =3D start + sym_patched->len; + } + + for_each_reloc(rsec_patched, reloc_patched) { + unsigned long offset; + + if (reloc_offset(reloc_patched) < start || + reloc_offset(reloc_patched) >=3D end) + continue; + + convert_reloc_sym(e->patched, reloc_patched); + + offset =3D sym->offset + (reloc_offset(reloc_patched) - sym_patched->off= set); + + clone_reloc(e, reloc_patched, sym->sec, offset); + } +} + +/* Keep a special section entry if it references an included function */ +static bool should_keep_special_sym(struct elf *elf, struct symbol *sym) +{ + struct reloc *reloc; + + if (is_section_symbol(sym)) + return false; + + for_each_reloc(sym->sec->rsec, reloc) { + unsigned long reloc_off =3D reloc_offset(reloc); + + if (convert_reloc_sym(elf, reloc)) + continue; + + if (reloc_off >=3D sym->offset && reloc_off < sym->offset + sym->len && + is_function_symbol(reloc->sym) && + (reloc->sym->changed || reloc->sym->added)) + return true; + } + + return false; +} + +static unsigned int reloc_size(struct reloc *reloc) +{ + switch (reloc_type(reloc)) { + + case R_X86_64_PC32: + case R_X86_64_32: + return 4; + + case R_X86_64_64: + case R_X86_64_PC64: + return 8; + + default: + ERROR("unknown reloc type"); + } +} + +static void clone_special_section(struct elfs *e, struct section *sec_patc= hed) +{ + unsigned long off_patched, off_out; + struct reloc *reloc_patched; + struct symbol *sym_patched; + bool has_syms =3D false; + struct section *sec; + + /* + * Some special sections are composed of an array of structs, where + * each array entry has its own fake symbol denoting its location and + * size. Copy all entries (both data and relocs) referencing an + * included function. + */ + off_patched =3D 0; + sec_for_each_sym(sec_patched, sym_patched) { + if (!is_object_symbol(sym_patched)) + continue; + has_syms =3D true; + + if (off_patched !=3D sym_patched->offset) + ERROR_FUNC(sec_patched, off_patched, "special section symbol gap"); + + off_patched =3D sym_patched->offset + sym_patched->len; + + if (!should_keep_special_sym(e->patched, sym_patched)) + continue; + + clone_symbol(e, sym_patched, true); + } + + if (has_syms) + return; + + /* + * Some special sections are just a simple array of pointers. Copy all + * relocs referencing included functions. + */ + off_patched =3D 0; + off_out =3D 0; + sec =3D NULL; + for_each_reloc(sec_patched->rsec, reloc_patched) { + unsigned int rel_size =3D reloc_size(reloc_patched); + + if (off_patched !=3D reloc_offset(reloc_patched)) + ERROR("special section reloc gap - does it need fake symbols?"); + + off_patched +=3D rel_size; + + if (convert_reloc_sym(e->patched, reloc_patched)) + continue; + + if (!reloc_patched->sym->changed && !reloc_patched->sym->added) + continue; + + if (!sec) { + sec =3D find_section_by_name(e->out, sec_patched->name); + if (sec) + ERROR("why does %s already exist?", sec_patched->name); + + sec =3D elf_create_section(e->out, sec_patched->name, 0, + sec_patched->sh.sh_entsize, + sec_patched->sh.sh_type, + sec_patched->sh.sh_addralign, + sec_patched->sh.sh_flags); + } + + elf_add_data(e->out, sec, NULL, rel_size); + clone_reloc(e, reloc_patched, sec, off_out); + off_out +=3D rel_size; + } +} + +/* Extract only the needed bits from special sections */ +static void clone_special_sections(struct elfs *e) +{ + struct section *sec_patched; + + for_each_sec(e->patched, sec_patched) { + if (is_special_section(sec_patched)) + clone_special_section(e, sec_patched); + } +} + +/* + * Create __klp_objects and __klp_funcs sections which are intermediate + * sections provided as input to the patch module's init code (module.c) f= or + * building the 'struct klp_patch' needed for the livepatch API. + */ +static void create_klp_sections(struct elfs *e) +{ + size_t obj_size =3D sizeof(struct klp_object_ext); + size_t func_size =3D sizeof(struct klp_func_ext); + struct section *obj_sec, *funcs_sec, *str_sec; + struct symbol *funcs_sym, *str_sym, *sym; + const char *modname =3D find_modname(e); + char sym_name[SYM_NAME_LEN]; + unsigned int nr_funcs =3D 0; + void *obj_data; + s64 addend; + + obj_sec =3D elf_create_section_pair(e->out, KLP_OBJECTS_SEC, obj_size, 0= , 0); + + funcs_sec =3D elf_create_section_pair(e->out, KLP_FUNCS_SEC, func_size, 0= , 0); + funcs_sym =3D elf_create_section_symbol(e->out, funcs_sec); + + str_sec =3D elf_create_section(e->out, KLP_STRINGS_SEC, 0, 0, + SHT_PROGBITS, 1, + SHF_ALLOC | SHF_STRINGS | SHF_MERGE); + elf_add_string(e->out, str_sec, ""); + str_sym =3D elf_create_section_symbol(e->out, str_sec); + + /* allocate klp_object_ext */ + obj_data =3D elf_add_data(e->out, obj_sec, NULL, obj_size); + + /* klp_object_ext.name */ + if (strcmp(modname, "vmlinux")) { + addend =3D elf_add_string(e->out, str_sec, modname); + elf_create_reloc(e->out, obj_sec, + offsetof(struct klp_object_ext, name), + str_sym, addend, R_ABS64); + } + + /* klp_object_ext.funcs */ + elf_create_reloc(e->out, obj_sec, offsetof(struct klp_object_ext, funcs), + funcs_sym, 0, R_ABS64); + + for_each_sym(e->out, sym) { + unsigned long offset =3D nr_funcs * func_size; + unsigned long sympos; + void *func_data; + + if (!sym->clone || !sym->clone->changed || !is_function_symbol(sym)) + continue; + + /* allocate klp_func_ext */ + func_data =3D elf_add_data(e->out, funcs_sec, NULL, func_size); + + /* klp_func_ext.old_name */ + addend =3D elf_add_string(e->out, str_sec, sym->clone->twin->name); + elf_create_reloc(e->out, funcs_sec, + offset + offsetof(struct klp_func_ext, old_name), + str_sym, addend, R_ABS64); + + /* klp_func_ext.new_func */ + elf_create_reloc(e->out, funcs_sec, + offset + offsetof(struct klp_func_ext, new_func), + sym, 0, R_ABS64); + + /* klp_func_ext.sympos */ + BUILD_BUG_ON(sizeof(sympos) !=3D sizeof_field(struct klp_func_ext, sympo= s)); + sympos =3D find_sympos(e->orig, sym->clone->twin); + memcpy(func_data + offsetof(struct klp_func_ext, sympos), &sympos, + sizeof_field(struct klp_func_ext, sympos)); + + nr_funcs++; + } + + /* klp_object_ext.nr_funcs */ + BUILD_BUG_ON(sizeof(nr_funcs) !=3D sizeof_field(struct klp_object_ext, nr= _funcs)); + memcpy(obj_data + offsetof(struct klp_object_ext, nr_funcs), &nr_funcs, + sizeof_field(struct klp_object_ext, nr_funcs)); + + /* + * Find callback pointers created by KLP_PRE_PATCH_CALLBACK() and + * friends, and add them to the klp object. + */ + + snprintf(sym_name, SYM_NAME_LEN, KLP_PRE_PATCH_PREFIX "%s", modname); + sym =3D find_symbol_by_name(e->out, sym_name); + if (sym) { + struct reloc *reloc; + + reloc =3D find_reloc_by_dest(e->out, sym->sec, sym->offset); + + elf_create_reloc(e->out, obj_sec, + offsetof(struct klp_object_ext, callbacks) + + offsetof(struct klp_callbacks, pre_patch), + reloc->sym, reloc_addend(reloc), R_ABS64); + } + + snprintf(sym_name, SYM_NAME_LEN, KLP_POST_PATCH_PREFIX "%s", modname); + sym =3D find_symbol_by_name(e->out, sym_name); + if (sym) { + struct reloc *reloc; + + reloc =3D find_reloc_by_dest(e->out, sym->sec, sym->offset); + + elf_create_reloc(e->out, obj_sec, + offsetof(struct klp_object_ext, callbacks) + + offsetof(struct klp_callbacks, post_patch), + reloc->sym, reloc_addend(reloc), R_ABS64); + } + + snprintf(sym_name, SYM_NAME_LEN, KLP_PRE_UNPATCH_PREFIX "%s", modname); + sym =3D find_symbol_by_name(e->out, sym_name); + if (sym) { + struct reloc *reloc; + + reloc =3D find_reloc_by_dest(e->out, sym->sec, sym->offset); + + elf_create_reloc(e->out, obj_sec, + offsetof(struct klp_object_ext, callbacks) + + offsetof(struct klp_callbacks, pre_unpatch), + reloc->sym, reloc_addend(reloc), R_ABS64); + } + + snprintf(sym_name, SYM_NAME_LEN, KLP_POST_UNPATCH_PREFIX "%s", modname); + sym =3D find_symbol_by_name(e->out, sym_name); + if (sym) { + struct reloc *reloc; + + reloc =3D find_reloc_by_dest(e->out, sym->sec, sym->offset); + + elf_create_reloc(e->out, obj_sec, + offsetof(struct klp_object_ext, callbacks) + + offsetof(struct klp_callbacks, post_unpatch), + reloc->sym, reloc_addend(reloc), R_ABS64); + } +} + +int cmd_klp_diff(int argc, const char **argv) +{ + struct elf *elf_orig, *elf_patched, *elf_out; + struct elfs e; + + argc--; + argv++; + + if (argc !=3D 3) { + fprintf(stderr, "usage: objtool diff \n"); + return -1; + } + + elf_orig =3D elf_open_read(argv[0], O_RDONLY); + elf_patched =3D elf_open_read(argv[1], O_RDONLY); + + Objname =3D basename(Objname); + + read_exports(); + + read_sym_checksums(elf_orig); + read_sym_checksums(elf_patched); + + correlate_symbols(elf_orig, elf_patched); + + elf_out =3D elf_create_file(&elf_orig->ehdr, argv[2]); + + e.orig =3D elf_orig; + e.patched =3D elf_patched; + e.out =3D elf_out; + + clone_changed_functions(&e); + + clone_special_sections(&e); + + create_klp_sections(&e); + + elf_write(elf_out); + return 0; +} + diff --git a/tools/objtool/klp-link.c b/tools/objtool/klp-link.c new file mode 100644 index 000000000000..0b42a79c8215 --- /dev/null +++ b/tools/objtool/klp-link.c @@ -0,0 +1,122 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2024 Josh Poimboeuf + */ +#include +#include +#include +#include +#include +#include + +/* + * This runs on the livepatch module after all other linking has been done= . It + * converts the intermediate __klp_relocs section into proper klp relocs t= o be + * processed by livepatch. This needs to run last to avoid linker wreckag= e. + * Linkers don't tend to handle the "two rela sections for a single base + * section" case very well. + */ +int cmd_klp_link(int argc, const char **argv) +{ + struct section *symtab, *klp_relocs; + struct elf *elf; + + argc--; + argv++; + + if (argc !=3D 1) { + fprintf(stderr, "%d\n", argc); + fprintf(stderr, "usage: objtool link \n"); + return -1; + } + + elf =3D elf_open_read(argv[0], O_RDWR); + + klp_relocs =3D find_section_by_name(elf, KLP_RELOCS_SEC); + if (!klp_relocs) + return 0; + + symtab =3D find_section_by_name(elf, ".symtab"); + if (!symtab) + ERROR("missing .symtab"); + + for (int i =3D 0; i < sec_size(klp_relocs) / sizeof(struct klp_reloc); i+= +) { + struct klp_reloc *klp_reloc; + unsigned long klp_reloc_off; + struct section *sec, *tmp, *klp_rsec; + unsigned long offset; + struct reloc *reloc; + char sym_modname[64]; + char rsec_name[SEC_NAME_LEN]; + u64 addend; + struct symbol *sym, *klp_sym; + + klp_reloc_off =3D i * sizeof(*klp_reloc); + klp_reloc =3D klp_relocs->data->d_buf + klp_reloc_off; + + /* + * Read __klp_relocs entry: + */ + + /* klp_reloc.sec_offset */ + reloc =3D find_reloc_by_dest(elf, klp_relocs, + klp_reloc_off + offsetof(struct klp_reloc, offset)); + ERROR_ON(!reloc, "malformed " KLP_RELOCS_SEC " section"); + + sec =3D reloc->sym->sec; + offset =3D reloc_addend(reloc); + + /* klp_reloc.sym */ + reloc =3D find_reloc_by_dest(elf, klp_relocs, + klp_reloc_off + offsetof(struct klp_reloc, sym)); + ERROR_ON(!reloc, "malformed " KLP_RELOCS_SEC " section"); + + klp_sym =3D reloc->sym; + addend =3D reloc_addend(reloc); + + /* symbol format: .klp.sym.modname.sym_name,sympos */ + sscanf(klp_sym->name + strlen(KLP_SYM_PREFIX), "%55[^.]", sym_modname); + + /* + * Create klp reloc: + */ + + /* section format: .klp.rela.sec_objname.section_name */ + snprintf(rsec_name, SEC_NAME_LEN, KLP_RELOC_SEC_PREFIX "%s.%s", + sym_modname, sec->name); + klp_rsec =3D find_section_by_name(elf, rsec_name); + + if (!klp_rsec) { + klp_rsec =3D elf_create_section(elf, rsec_name, 0, + elf_rela_size(elf), + SHT_RELA, elf_addr_size(elf), + SHF_ALLOC | SHF_INFO_LINK | SHF_RELA_LIVEPATCH); + + klp_rsec->sh.sh_link =3D symtab->idx; + klp_rsec->sh.sh_info =3D sec->idx; + klp_rsec->base =3D sec; + } + + tmp =3D sec->rsec; + sec->rsec =3D klp_rsec; + elf_create_reloc(elf, sec, offset, klp_sym, addend, klp_reloc->type); + sec->rsec =3D tmp; + + klp_sym->sym.st_shndx =3D SHN_LIVEPATCH; + gelf_update_sym(symtab->data, klp_sym->idx, &klp_sym->sym); + + /* + * Disable original non-klp reloc by converting it to R_*_NONE: + */ + + reloc =3D find_reloc_by_dest(elf, sec, offset); + sym =3D reloc->sym; + sym->sym.st_shndx =3D SHN_LIVEPATCH; + set_reloc_type(elf, reloc, 0); + gelf_update_sym(symtab->data, sym->idx, &sym->sym); + } + + elf_write(elf); + + return 0; +} diff --git a/tools/objtool/klp.c b/tools/objtool/klp.c new file mode 100644 index 000000000000..fc871108060e --- /dev/null +++ b/tools/objtool/klp.c @@ -0,0 +1,57 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) 2024 Josh Poimboeuf + */ + +#include +#include +#include +#include +#include +#include + +struct subcmd { + const char *name; + const char *description; + int (*fn)(int, const char **); +}; + +static struct subcmd subcmds[] =3D { + { "diff", "Generate binary diff of two object files", cmd_klp_diff, }, + { "link", "Finalize klp symbols/relocations after module linking", cmd_k= lp_link, }, +}; + +static void cmd_klp_usage(void) +{ + fprintf(stderr, "usage: objtool klp []\n\n"); + fprintf(stderr, "Subcommands:\n"); + + for (int i =3D 0; i < ARRAY_SIZE(subcmds); i++) { + struct subcmd *cmd =3D &subcmds[i]; + + fprintf(stderr," %s\t%s\n", cmd->name, cmd->description); + } + + exit(1); +} + +int cmd_klp(int argc, const char **argv) +{ + argc--; + argv++; + + if (!argc) + cmd_klp_usage(); + + if (argc) { + for (int i =3D 0; i < ARRAY_SIZE(subcmds); i++) { + struct subcmd *cmd =3D &subcmds[i]; + + if (!strcmp(cmd->name, argv[0])) + return cmd->fn(argc, argv); + } + } + + cmd_klp_usage(); + return 0; +} diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c index 06f7e518b8a7..75ff32ab0368 100644 --- a/tools/objtool/objtool.c +++ b/tools/objtool/objtool.c @@ -122,5 +122,11 @@ int main(int argc, const char **argv) exec_cmd_init("objtool", UNUSED, UNUSED, UNUSED); pager_init(UNUSED); =20 + if (argc > 1 && !strcmp(argv[1], "klp")) { + argc--; + argv++; + return cmd_klp(argc, argv); + } + return objtool_run(argc, argv); } diff --git a/tools/objtool/sync-check.sh b/tools/objtool/sync-check.sh index 81d120d05442..873ce93f9993 100755 --- a/tools/objtool/sync-check.sh +++ b/tools/objtool/sync-check.sh @@ -16,6 +16,7 @@ arch/x86/include/asm/orc_types.h arch/x86/include/asm/emulate_prefix.h arch/x86/lib/x86-opcode-map.txt arch/x86/tools/gen-insn-attr-x86.awk +include/linux/livepatch_ext.h include/linux/static_call_types.h " =20 diff --git a/tools/objtool/weak.c b/tools/objtool/weak.c index 426fdf0b7548..7e1858885fd6 100644 --- a/tools/objtool/weak.c +++ b/tools/objtool/weak.c @@ -8,6 +8,8 @@ #include #include #include +#include +#include =20 #define UNSUPPORTED(name) \ ({ \ @@ -24,3 +26,8 @@ int __weak orc_create(struct objtool_file *file) { UNSUPPORTED("ORC"); } + +int __weak cmd_klp(int argc, const char **argv) +{ + UNSUPPORTED("klp"); +} --=20 2.45.2