mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Josh Poimboeuf <jpoimboe@kernel.org>
To: x86@kernel.org
Cc: linux-kernel@vger.kernel.org,
	Peter Zijlstra <peterz@infradead.org>,
	Gary Guo <gary@garyguo.net>,
	rust-for-linux@vger.kernel.org, Ard Biesheuvel <ardb@kernel.org>,
	Miguel Ojeda <ojeda@kernel.org>,
	Nathan Chancellor <nathan@kernel.org>,
	Nicolas Schier <nsc@kernel.org>,
	linux-kbuild@vger.kernel.org, Huacai Chen <chenhuacai@kernel.org>
Subject: [PATCH v2 24/27] kbuild: Generate the noreturn list and validate modules against it
Date: Tue,  8 Sep 2026 13:33:36 -0700	[thread overview]
Message-ID: <d6a8e30dc4b1808c766a7862081dd40197a2fbf1.1788899473.git.jpoimboe@kernel.org> (raw)
In-Reply-To: <cover.1788899473.git.jpoimboe@kernel.org>

Most of the remaining hard-coded noreturn functions are exported symbols
which live in vmlinux.o.  The objtool vmlinux.o pass can detect them
automatically, but modules can't.

Instead of hard-coding them in noreturns.h, dynamically generate the
list in a new scripts/noreturns.builtin file, which objtool on modules
can then read.  That allows most of the remaining hard-coded noreturn
entries to go away, including the Rust ones.  Note this means that
modules need to be linked after vmlinux.o has been built and analyzed by
objtool.

Objtool running on OOT modules will also need to read the generated
file.  Its location in scripts/ should ensure it gets installed with
kernel build files automatically.

Signed-off-by: Josh Poimboeuf <jpoimboe@kernel.org>
---
 Makefile                                |  8 +++++
 scripts/.gitignore                      |  1 +
 scripts/Makefile.modfinal               | 15 ++++++--
 scripts/Makefile.vmlinux_o              |  2 ++
 tools/objtool/Documentation/objtool.txt |  8 ++---
 tools/objtool/check.c                   | 46 -------------------------
 tools/objtool/noreturns.h               | 17 ++-------
 7 files changed, 29 insertions(+), 68 deletions(-)

diff --git a/Makefile b/Makefile
index 66654fa71655b..4e5de90c765e7 100644
--- a/Makefile
+++ b/Makefile
@@ -1750,6 +1750,13 @@ KBUILD_BUILTIN := y
 modules: vmlinux
 endif
 
+# Objtool for modules (run before module link) needs to come after objtool for
+# vmlinux.o so it can read the generated exported noreturns file.
+ifdef CONFIG_OBJTOOL_CONTROL_FLOW
+KBUILD_BUILTIN := y
+modules: vmlinux.o
+endif
+
 modules: modules_prepare
 
 # Target to prepare building external modules
@@ -1780,6 +1787,7 @@ MRPROPER_FILES += include/config include/generated          \
 		  debian snap tar-install PKGBUILD pacman \
 		  .config .config.old .version \
 		  Module.symvers \
+		  scripts/noreturns.builtin \
 		  certs/signing_key.pem \
 		  certs/x509.genkey \
 		  vmlinux-gdb.py \
diff --git a/scripts/.gitignore b/scripts/.gitignore
index 4215c2208f7e4..15d99dfd7c936 100644
--- a/scripts/.gitignore
+++ b/scripts/.gitignore
@@ -5,6 +5,7 @@
 /insert-sys-cert
 /kallsyms
 /module.lds
+/noreturns.builtin
 /recordmcount
 /rustdoc_test_builder
 /rustdoc_test_gen
diff --git a/scripts/Makefile.modfinal b/scripts/Makefile.modfinal
index 56b4227cc6863..23b07ad7eb9bd 100644
--- a/scripts/Makefile.modfinal
+++ b/scripts/Makefile.modfinal
@@ -32,6 +32,15 @@ ifneq ($(WARN_ON_UNUSED_TRACEPOINTS),)
 cmd_check_tracepoint = $(objtree)/scripts/tracepoint-update --module $<;
 endif
 
+ifdef CONFIG_OBJTOOL_CONTROL_FLOW
+noreturns-builtin := $(wildcard $(objtree)/scripts/noreturns.builtin)
+ifeq ($(noreturns-builtin),)
+$(warning scripts/noreturns.builtin is missing)
+else
+objtool-args += --noreturns-read=$(noreturns-builtin)
+endif
+endif
+
 $(modules:%.o=%.ko): private objtool-enabled = $(CONFIG_OBJTOOL_DEFERRED)
 
 mod-objtool = $(if $(objtool-enabled),$(objtool) $(objtool-args) -o $@.o $< ;)
@@ -59,8 +68,10 @@ define rule_ld_ko_o
 	+$(if $(CONFIG_DEBUG_INFO_BTF_MODULES),$(if $(newer-prereqs),$(call cmd,btf_ko)))
 endef
 
-# Re-generate module BTFs if either module's .ko or vmlinux changed
-%.ko: %.o %.mod.o .module-common.o $(objtree)/scripts/module.lds $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),$(objtree)/vmlinux) FORCE
+# Re-generate module BTFs if either module's .ko or vmlinux changed.
+# Re-run module objtool if the generated noreturn list changed.
+%.ko: %.o %.mod.o .module-common.o $(objtree)/scripts/module.lds $(noreturns-builtin) \
+      $(and $(CONFIG_DEBUG_INFO_BTF_MODULES),$(KBUILD_BUILTIN),$(objtree)/vmlinux) FORCE
 	$(call if_changed_rule,ld_ko_o)
 	+$(call cmd,check_tracepoint)
 
diff --git a/scripts/Makefile.vmlinux_o b/scripts/Makefile.vmlinux_o
index df1e3584883e6..9c60a4918a756 100644
--- a/scripts/Makefile.vmlinux_o
+++ b/scripts/Makefile.vmlinux_o
@@ -37,6 +37,8 @@ objtool-enabled := $(CONFIG_OBJTOOL_DEFERRED)
 
 vmlinux-objtool-args-y					+= $(objtool-args-y)
 
+vmlinux-objtool-args-$(CONFIG_OBJTOOL_CONTROL_FLOW)	+= --noreturns-write=scripts/noreturns.builtin
+
 vmlinux-objtool-args-$(CONFIG_NOINSTR_VALIDATION)	+= --noinstr \
 							   $(if $(or $(CONFIG_MITIGATION_UNRET_ENTRY),$(CONFIG_MITIGATION_SRSO)), --unret)
 
diff --git a/tools/objtool/Documentation/objtool.txt b/tools/objtool/Documentation/objtool.txt
index 9e97fc25b2d8a..c7ebfb9a8ca6b 100644
--- a/tools/objtool/Documentation/objtool.txt
+++ b/tools/objtool/Documentation/objtool.txt
@@ -334,8 +334,7 @@ the objtool maintainers.
 
    The call from foo() to bar() doesn't return, but bar() is incorrectly
    annotated.  A noreturn function must be marked __noreturn in both its
-   declaration and its definition, and must have a NORETURN() annotation
-   in tools/objtool/noreturns.h.
+   declaration and its definition.
 
 
 4. file.o: warning: objtool: func(): can't find starting instruction
@@ -393,9 +392,8 @@ the objtool maintainers.
    reasons for this:
 
    a) funcA()'s last instruction is a call to a "noreturn" function like
-      panic().  In this case the noreturn function needs to be added to
-      objtool's hard-coded global_noreturns array.  Feel free to bug the
-      objtool maintainer, or you can submit a patch.
+      panic(), and objtool doesn't know that function never returns.  See
+      warning 3 above.
 
    b) funcA() uses the unreachable() annotation in a section of code
       that is actually reachable.
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index b572b9ce6ada9..52630519bdbf2 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -176,49 +176,6 @@ static bool is_sibling_call(struct instruction *insn)
 	return (is_static_jump(insn) && insn_call_dest(insn));
 }
 
-/*
- * Checks if a function is a Rust "noreturn" one.
- */
-static bool is_rust_noreturn(const struct symbol *func)
-{
-	/*
-	 * If it does not start with "_R", then it is not a Rust symbol.
-	 */
-	if (strncmp(func->name, "_R", 2))
-		return false;
-
-	/*
-	 * These are just heuristics -- we do not control the precise symbol
-	 * name, due to the crate disambiguators (which depend on the compiler)
-	 * as well as changes to the source code itself between versions (since
-	 * these come from the Rust standard library).
-	 */
-	return str_ends_with(func->name, "_4core3num20from_str_radix_panic")				||
-	       str_ends_with(func->name, "_4core3num22from_ascii_radix_panic")				||
-	       str_ends_with(func->name, "_4core3num28from_ascii_bytes_radix_panic")			||
-	       str_ends_with(func->name, "_4core3str16slice_error_fail")				||
-	       str_ends_with(func->name, "_4core5sliceSp15copy_from_slice17len_mismatch_fail")		||
-	       str_ends_with(func->name, "_4core6option13expect_failed")				||
-	       str_ends_with(func->name, "_4core6option13unwrap_failed")				||
-	       str_ends_with(func->name, "_4core6result13unwrap_failed")				||
-	       str_ends_with(func->name, "_4core9panicking5panic")					||
-	       str_ends_with(func->name, "_4core9panicking9panic_fmt")					||
-	       str_ends_with(func->name, "_4core9panicking14panic_explicit")				||
-	       str_ends_with(func->name, "_4core9panicking14panic_nounwind")				||
-	       str_ends_with(func->name, "_4core9panicking18panic_bounds_check")			||
-	       str_ends_with(func->name, "_4core9panicking18panic_nounwind_fmt")			||
-	       str_ends_with(func->name, "_4core9panicking19assert_failed_inner")			||
-	       str_ends_with(func->name, "_4core9panicking30panic_null_pointer_dereference")		||
-	       str_ends_with(func->name, "_4core9panicking32panic_null_reference_constructed")		||
-	       str_ends_with(func->name, "_4core9panicking36panic_misaligned_pointer_dereference")	||
-	       str_ends_with(func->name, "_7___rustc17rust_begin_unwind")				||
-	       strstr(func->name, "_4core9panicking13assert_failed")					||
-	       strstr(func->name, "_4core9panicking11panic_const24panic_const_")			||
-	       (strstr(func->name, "_4core5slice5index") &&
-		strstr(func->name, "slice_") &&
-		str_ends_with(func->name, "_fail"));
-}
-
 static bool is_listed_noreturn(struct symbol *func)
 {
 #define NORETURN(func) __stringify(func),
@@ -230,9 +187,6 @@ static bool is_listed_noreturn(struct symbol *func)
 	if (is_local_sym(func))
 		return false;
 
-	if (is_rust_noreturn(func))
-		return true;
-
 	for (int i = 0; i < ARRAY_SIZE(global_noreturns); i++)
 		if (!strcmp(func->name, global_noreturns[i]))
 			return true;
diff --git a/tools/objtool/noreturns.h b/tools/objtool/noreturns.h
index 2dce56030b980..4e8007a8c2584 100644
--- a/tools/objtool/noreturns.h
+++ b/tools/objtool/noreturns.h
@@ -1,22 +1,9 @@
 /* SPDX-License-Identifier: GPL-2.0 */
 
 /*
- * This is a (sorted!) list of all known __noreturn functions in the kernel.
- * It's needed for objtool to properly reverse-engineer the control flow graph.
- *
- * Yes, this is unfortunate.  A better solution is in the works.
+ * This is a list of noreturn functions which are exported *by modules*.
+ * No other noreturns need to be listed here.
  */
-NORETURN(__fortify_panic)
 NORETURN(__kunit_abort)
-NORETURN(__module_put_and_kthread_exit)
-NORETURN(__stack_chk_fail)
-NORETURN(__ubsan_handle_builtin_unreachable)
-NORETURN(abort)
-NORETURN(acpi_processor_ffh_play_dead)
-NORETURN(do_exit)
-NORETURN(kthread_complete_and_exit)
 NORETURN(kunit_try_catch_throw)
 NORETURN(mpt_halt_firmware)
-NORETURN(panic)
-NORETURN(vpanic)
-NORETURN(rust_helper_BUG)
-- 
2.55.0


  parent reply	other threads:[~2026-09-08 20:34 UTC|newest]

Thread overview: 29+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-08 20:33 [PATCH v2 00/27] objtool: dynamically detect noreturns Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 01/27] objtool: Remove obsolete noreturns.h entries Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 02/27] kbuild: Add CONFIG_OBJTOOL_DEFERRED Josh Poimboeuf
2026-09-10 19:22   ` Julian Braha
2026-09-08 20:33 ` [PATCH v2 03/27] kbuild: Add CONFIG_OBJTOOL_CONTROL_FLOW Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 04/27] objtool: Fix dead end detection for sibling calls Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 05/27] objtool: Refactor the noreturn/dead-end detection Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 06/27] objtool: Ignore traps after noreturn calls in STT_CODE Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 07/27] objtool: Make .discard.stack_frame_non_standard non-allocatable Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 08/27] efi/libstub: Drop .discard.addressable from the stub objects Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 09/27] efi/loongarch: Mark loongarch efi_boot_kernel() non-standard for objtool Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 10/27] objtool: Add ANNOTATE_IGNORE_NORETURN() Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 11/27] LoongArch: Annotate reboot and kexec paths as returnable Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 12/27] kbuild: Defer running objtool to link time for all CFG features Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 13/27] rust: Annotate the intrinsic stubs as returnable Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 14/27] panic: Mark abort() __noreturn Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 15/27] x86/xen: Ignore noreturn status of weak mem_map_via_hcall() Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 16/27] objtool: Detect noreturns in weak functions Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 17/27] x86/entry: Make rewind_stack_and_make_dead() a real function Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 18/27] x86/xen: Make xen_cpu_bringup_again() " Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 19/27] x86/xen: Make xen_start_kernel() noreturn Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 20/27] x86/boot: Rework how pi startup symbols get exposed to vmlinux Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 21/27] objtool: Fix noreturn detection for non-sibling jumps to SYM_CODE Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 22/27] objtool: Add options to write/read exported noreturns to/from a file Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 23/27] kbuild: Do the per-module objtool pass right before linking Josh Poimboeuf
2026-09-08 20:33 ` Josh Poimboeuf [this message]
2026-09-08 20:33 ` [PATCH v2 25/27] objtool: Add ANNOTATE_EXPORTED_NORETURN() Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 26/27] objtool: Annotate all module-exported noreturns and remove noreturns.h Josh Poimboeuf
2026-09-08 20:33 ` [PATCH v2 27/27] objtool: Warn about missing/stale ANNOTATE_EXPORTED_NORETURN() usage Josh Poimboeuf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d6a8e30dc4b1808c766a7862081dd40197a2fbf1.1788899473.git.jpoimboe@kernel.org \
    --to=jpoimboe@kernel.org \
    --cc=ardb@kernel.org \
    --cc=chenhuacai@kernel.org \
    --cc=gary@garyguo.net \
    --cc=linux-kbuild@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=nathan@kernel.org \
    --cc=nsc@kernel.org \
    --cc=ojeda@kernel.org \
    --cc=peterz@infradead.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=x86@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®