Skip to contentSkip to conversation

Yet more objtool fixes

PATCH Applied Josh Poimboeuf 4 participants 29 messages Apr 1, 2025

Subsystems (5)
Kbuild RCU LoongArch objtool +1 more subsystems
lore
Share & tools
lore

Josh Poimboeuf

author maintainer
#0 lore raw

cover Yet more objtool fixes

David Laight (1):
objtool: Fix verbose disassembly if CROSS_COMPILE isn't set

Josh Poimboeuf (10):
objtool: Silence more KCOV warnings, part 2
objtool: Ignore end-of-section jumps for KCOV/GCOV
objtool: Append "()" to function name in "unexpected end of section"
warning
Revert "objtool: Increase per-function WARN_FUNC() rate limit"
objtool: Always fail on fatal errors
objtool: Change "warning:" to "error:" for fatal errors objtool/loongarch: Add unwind hints in prepare_frametrace() sched/smt: Always inline sched_smt_active()
context_tracking: Always inline ct_{nmi,irq}_{enter,exit}()
rcu-tasks: Always inline rcu_irq_work_resched()

 arch/loongarch/include/asm/stacktrace.h   |   3 +
 arch/loongarch/include/asm/unwind_hints.h |  10 +-
 include/linux/context_tracking_irq.h      |   8 +-
 include/linux/rcupdate.h                  |   2 +-
 include/linux/sched/smt.h                 |   2 +-
 scripts/Makefile.lib                      |   2 +-
 tools/objtool/arch/loongarch/decode.c     |  14 +-
 tools/objtool/arch/loongarch/orc.c        |   8 +-
 tools/objtool/arch/x86/decode.c           |  15 +-
 tools/objtool/arch/x86/orc.c              |   6 +-
 tools/objtool/builtin-check.c             |  30 ++--
 tools/objtool/check.c                     | 172 +++++++++++-----------
 tools/objtool/elf.c                       | 150 +++++++++----------
 tools/objtool/include/objtool/elf.h       |   2 +-
 tools/objtool/include/objtool/warn.h      |  63 ++++----
 tools/objtool/objtool.c                   |   4 +-
 tools/objtool/orc_dump.c                  |  30 ++--
 tools/objtool/special.c                   |  13 +-
 18 files changed, 273 insertions(+), 261 deletions(-)
Signature · 1 line
2.48.1
author maintainer
#1 lore raw

PATCH 1/11 objtool: Silence more KCOV warnings, part 2

Similar to GCOV, KCOV can leave behind dead code and undefined behavior. Warnings related to those should be ignored.

The previous commit:

6b023c784204 ("objtool: Silence more KCOV warnings")

... only did so for CONFIG_CGOV_KERNEL. Also do it for CONFIG_KCOV, but for real this time.

Fixes the following warning:

vmlinux.o: warning: objtool: synaptics_report_mt_data: unexpected end of section .text.synaptics_report_mt_data

---
 scripts/Makefile.lib | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
scripts/Makefile.lib +1 -1
index b93597420daf..4d543054f723 100644
@@ -275,7 +275,7 @@ objtool-args-$(CONFIG_MITIGATION_SLS)			+= --sls
 objtool-args-$(CONFIG_STACK_VALIDATION)			+= --stackval
 objtool-args-$(CONFIG_HAVE_STATIC_CALL_INLINE)		+= --static-call
 objtool-args-$(CONFIG_HAVE_UACCESS_VALIDATION)		+= --uaccess
-objtool-args-$(CONFIG_GCOV_KERNEL)			+= --no-unreachable
+objtool-args-$(or $(CONFIG_GCOV_KERNEL),$(CONFIG_KCOV))	+= --no-unreachable
 objtool-args-$(CONFIG_PREFIX_SYMBOLS)			+= --prefix=$(CONFIG_FUNCTION_PADDING_BYTES)
 objtool-args-$(CONFIG_OBJTOOL_WERROR)			+= --Werror
 
Signature · 1 line
2.48.1
merge bot Applied
#2 lore raw

[tip: objtool/urgent] objtool: Silence more KCOV warnings, part 2

The following commit has been merged into the objtool/urgent branch of tip:

The following commit has been merged into the objtool/urgent branch of tip:

Commit-ID:     55c78035a1a8dfb05f1472018ce2a651701adb7d
Gitweb:        https://git.kernel.org/tip/55c78035a1a8dfb05f1472018ce2a651701adb7d
Author:        Josh Poimboeuf <[email protected]>
AuthorDate:    Mon, 31 Mar 2025 21:26:36 -07:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Tue, 01 Apr 2025 09:07:12 +02:00

objtool: Silence more KCOV warnings, part 2

Similar to GCOV, KCOV can leave behind dead code and undefined behavior. Warnings related to those should be ignored.

The previous commit:

6b023c784204 ("objtool: Silence more KCOV warnings")

... only did so for CONFIG_CGOV_KERNEL. Also do it for CONFIG_KCOV, but for real this time.

Fixes the following warning:

vmlinux.o: warning: objtool: synaptics_report_mt_data: unexpected end of section .text.synaptics_report_mt_data

---
 scripts/Makefile.lib | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
scripts/Makefile.lib +1 -1
index b935974..4d54305 100644
@@ -275,7 +275,7 @@ objtool-args-$(CONFIG_MITIGATION_SLS)			+= --sls
 objtool-args-$(CONFIG_STACK_VALIDATION)			+= --stackval
 objtool-args-$(CONFIG_HAVE_STATIC_CALL_INLINE)		+= --static-call
 objtool-args-$(CONFIG_HAVE_UACCESS_VALIDATION)		+= --uaccess
-objtool-args-$(CONFIG_GCOV_KERNEL)			+= --no-unreachable
+objtool-args-$(or $(CONFIG_GCOV_KERNEL),$(CONFIG_KCOV))	+= --no-unreachable
 objtool-args-$(CONFIG_PREFIX_SYMBOLS)			+= --prefix=$(CONFIG_FUNCTION_PADDING_BYTES)
 objtool-args-$(CONFIG_OBJTOOL_WERROR)			+= --Werror
 
author maintainer
#3 lore raw

PATCH 2/11 objtool: Ignore end-of-section jumps for KCOV/GCOV

In reply to Josh Poimboeuf

When KCOV or GCOV is enabled, dead code can be left behind, in which case objtool silences unreachable and undefined behavior (fallthrough) warnings.

Fallthrough warnings, and their variant "end of section" warnings, were silenced with the following commit:

6b023c784204 ("objtool: Silence more KCOV warnings")

Another variant of a fallthrough warning is a jump to the end of a function. If that function happens to be at the end of a section, the jump destination doesn't actually exist.

Normally that would be a fatal objtool error, but for KCOV/GCOV it's just another undefined behavior fallthrough. Silence it like the others.

Fixes the following warning:

drivers/iommu/dma-iommu.o: warning: objtool: iommu_dma_sw_msi+0x92: can't find jump dest instruction at .text+0x54d5

Fixes 6b023c784204 ("objtool: Silence more KCOV warnings")
---
 tools/objtool/check.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)
tools/objtool/check.c +16 -6
index fff9d7a2947a..e6c4eefe295b 100644
@@ -1488,6 +1488,8 @@ static int add_jump_destinations(struct objtool_file *file)
 	int ret;
 
 	for_each_insn(file, insn) {
+		struct symbol *func = insn_func(insn);
+
 		if (insn->jump_dest) {
 			/*
 			 * handle_group_alt() may have previously set
@@ -1513,7 +1515,7 @@ static int add_jump_destinations(struct objtool_file *file)
 		} else if (reloc->sym->return_thunk) {
 			add_return_call(file, insn, true);
 			continue;
-		} else if (insn_func(insn)) {
+		} else if (func) {
 			/*
 			 * External sibling call or internal sibling call with
 			 * STT_FUNC reloc.
@@ -1548,6 +1550,15 @@ static int add_jump_destinations(struct objtool_file *file)
 				continue;
 			}
 
+			/*
+			 * GCOV/KCOV dead code can jump to the end of the
+			 * function/section.
+			 */
+			if (file->ignore_unreachables && func &&
+			    dest_sec == insn->sec &&
+			    dest_off == func->offset + func->len)
+				continue;
+
 			WARN_INSN(insn, "can't find jump dest instruction at %s+0x%lx",
 				  dest_sec->name, dest_off);
 			return -1;
@@ -1574,8 +1585,7 @@ static int add_jump_destinations(struct objtool_file *file)
 		/*
 		 * Cross-function jump.
 		 */
-		if (insn_func(insn) && insn_func(jump_dest) &&
-		    insn_func(insn) != insn_func(jump_dest)) {
+		if (func && insn_func(jump_dest) && func != insn_func(jump_dest)) {
 
 			/*
 			 * For GCC 8+, create parent/child links for any cold
@@ -1592,10 +1602,10 @@ static int add_jump_destinations(struct objtool_file *file)
 			 * case where the parent function's only reference to a
 			 * subfunction is through a jump table.
 			 */
-			if (!strstr(insn_func(insn)->name, ".cold") &&
+			if (!strstr(func->name, ".cold") &&
 			    strstr(insn_func(jump_dest)->name, ".cold")) {
-				insn_func(insn)->cfunc = insn_func(jump_dest);
-				insn_func(jump_dest)->pfunc = insn_func(insn);
+				func->cfunc = insn_func(jump_dest);
+				insn_func(jump_dest)->pfunc = func;
 			}
 		}
 
Signature · 1 line
2.48.1
merge bot Applied
#4 lore raw

[tip: objtool/urgent] objtool: Ignore end-of-section jumps for KCOV/GCOV

The following commit has been merged into the objtool/urgent branch of tip:

The following commit has been merged into the objtool/urgent branch of tip:

Commit-ID:     0d7597749f5a3ac67851d3836635d084df15fb66
Gitweb:        https://git.kernel.org/tip/0d7597749f5a3ac67851d3836635d084df15fb66
Author:        Josh Poimboeuf <[email protected]>
AuthorDate:    Mon, 31 Mar 2025 21:26:37 -07:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Tue, 01 Apr 2025 09:07:12 +02:00

objtool: Ignore end-of-section jumps for KCOV/GCOV

When KCOV or GCOV is enabled, dead code can be left behind, in which case objtool silences unreachable and undefined behavior (fallthrough) warnings.

Fallthrough warnings, and their variant "end of section" warnings, were silenced with the following commit:

6b023c784204 ("objtool: Silence more KCOV warnings")

Another variant of a fallthrough warning is a jump to the end of a function. If that function happens to be at the end of a section, the jump destination doesn't actually exist.

Normally that would be a fatal objtool error, but for KCOV/GCOV it's just another undefined behavior fallthrough. Silence it like the others.

Fixes the following warning:

drivers/iommu/dma-iommu.o: warning: objtool: iommu_dma_sw_msi+0x92: can't find jump dest instruction at .text+0x54d5

---
 tools/objtool/check.c | 22 ++++++++++++++++------
 1 file changed, 16 insertions(+), 6 deletions(-)
tools/objtool/check.c +16 -6
index fff9d7a..e6c4eef 100644
@@ -1488,6 +1488,8 @@ static int add_jump_destinations(struct objtool_file *file)
 	int ret;
 
 	for_each_insn(file, insn) {
+		struct symbol *func = insn_func(insn);
+
 		if (insn->jump_dest) {
 			/*
 			 * handle_group_alt() may have previously set
@@ -1513,7 +1515,7 @@ static int add_jump_destinations(struct objtool_file *file)
 		} else if (reloc->sym->return_thunk) {
 			add_return_call(file, insn, true);
 			continue;
-		} else if (insn_func(insn)) {
+		} else if (func) {
 			/*
 			 * External sibling call or internal sibling call with
 			 * STT_FUNC reloc.
@@ -1548,6 +1550,15 @@ static int add_jump_destinations(struct objtool_file *file)
 				continue;
 			}
 
+			/*
+			 * GCOV/KCOV dead code can jump to the end of the
+			 * function/section.
+			 */
+			if (file->ignore_unreachables && func &&
+			    dest_sec == insn->sec &&
+			    dest_off == func->offset + func->len)
+				continue;
+
 			WARN_INSN(insn, "can't find jump dest instruction at %s+0x%lx",
 				  dest_sec->name, dest_off);
 			return -1;
@@ -1574,8 +1585,7 @@ static int add_jump_destinations(struct objtool_file *file)
 		/*
 		 * Cross-function jump.
 		 */
-		if (insn_func(insn) && insn_func(jump_dest) &&
-		    insn_func(insn) != insn_func(jump_dest)) {
+		if (func && insn_func(jump_dest) && func != insn_func(jump_dest)) {
 
 			/*
 			 * For GCC 8+, create parent/child links for any cold
@@ -1592,10 +1602,10 @@ static int add_jump_destinations(struct objtool_file *file)
 			 * case where the parent function's only reference to a
 			 * subfunction is through a jump table.
 			 */
-			if (!strstr(insn_func(insn)->name, ".cold") &&
+			if (!strstr(func->name, ".cold") &&
 			    strstr(insn_func(jump_dest)->name, ".cold")) {
-				insn_func(insn)->cfunc = insn_func(jump_dest);
-				insn_func(jump_dest)->pfunc = insn_func(insn);
+				func->cfunc = insn_func(jump_dest);
+				insn_func(jump_dest)->pfunc = func;
 			}
 		}
 
author maintainer
#5 lore raw

PATCH 3/11 objtool: Append "()" to function name in "unexpected end of section" warning

In reply to Josh Poimboeuf

Append with "()" to clarify it's a function.

Before:

vmlinux.o: warning: objtool: cdns_mrvl_xspi_setup_clock: unexpected end of section .text.cdns_mrvl_xspi_setup_clock

After:

vmlinux.o: warning: objtool: cdns_mrvl_xspi_setup_clock(): unexpected end of section .text.cdns_mrvl_xspi_setup_clock

Fixes c5995abe1547 ("objtool: Improve error handling")
---
 tools/objtool/check.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/objtool/check.c +1 -1
index e6c4eefe295b..bd0c78bfe90c 100644
@@ -3761,7 +3761,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
 				return 0;
 
 			WARN("%s%sunexpected end of section %s",
-			     func ? func->name : "", func ? ": " : "",
+			     func ? func->name : "", func ? "(): " : "",
 			     sec->name);
 			return 1;
 		}
Signature · 1 line
2.48.1
merge bot Applied
#6 lore raw

[tip: objtool/urgent] objtool: Append "()" to function name in "unexpected end of section" warning

The following commit has been merged into the objtool/urgent branch of tip:

The following commit has been merged into the objtool/urgent branch of tip:

Commit-ID:     188d90f817e13b66e03e110eb6f82e8f5f0d654b
Gitweb:        https://git.kernel.org/tip/188d90f817e13b66e03e110eb6f82e8f5f0d654b
Author:        Josh Poimboeuf <[email protected]>
AuthorDate:    Mon, 31 Mar 2025 21:26:38 -07:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Tue, 01 Apr 2025 09:07:12 +02:00

objtool: Append "()" to function name in "unexpected end of section" warning

Append with "()" to clarify it's a function.

Before:

vmlinux.o: warning: objtool: cdns_mrvl_xspi_setup_clock: unexpected end of section .text.cdns_mrvl_xspi_setup_clock

After:

vmlinux.o: warning: objtool: cdns_mrvl_xspi_setup_clock(): unexpected end of section .text.cdns_mrvl_xspi_setup_clock

---
 tools/objtool/check.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
tools/objtool/check.c +1 -1
index e6c4eef..bd0c78b 100644
@@ -3761,7 +3761,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
 				return 0;
 
 			WARN("%s%sunexpected end of section %s",
-			     func ? func->name : "", func ? ": " : "",
+			     func ? func->name : "", func ? "(): " : "",
 			     sec->name);
 			return 1;
 		}
author maintainer
#7 lore raw

PATCH 4/11 Revert "objtool: Increase per-function WARN_FUNC() rate limit"

In reply to Josh Poimboeuf

This reverts commit 0a7fb6f07e3ad497d31ae9a2082d2cacab43d54a.

The "skipping duplicate warnings" warning is technically not an actual warning, which can cause confusion. This feature isn't all that useful anyway. It's exceedingly rare for a function to have more than one unrelated warning.

---
 tools/objtool/check.c                |  4 ++--
 tools/objtool/include/objtool/elf.h  |  2 +-
 tools/objtool/include/objtool/warn.h | 14 +++-----------
 3 files changed, 6 insertions(+), 14 deletions(-)
tools/objtool/check.c +2 -2
index bd0c78bfe90c..c8b3c8e7090c 100644
@@ -3545,7 +3545,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
 
 			WARN("%s() falls through to next function %s()",
 			     func->name, insn_func(insn)->name);
-			func->warnings++;
+			func->warned = 1;
 
 			return 1;
 		}
@@ -4576,7 +4576,7 @@ static void disas_warned_funcs(struct objtool_file *file)
 	char *funcs = NULL, *tmp;
 
 	for_each_sym(file, sym) {
-		if (sym->warnings) {
+		if (sym->warned) {
 			if (!funcs) {
 				funcs = malloc(strlen(sym->name) + 1);
 				if (!funcs) {
tools/objtool/include/objtool/elf.h +1 -1
index eba04392c6fd..c7c4e87ebe88 100644
@@ -65,11 +65,11 @@ struct symbol {
 	u8 return_thunk      : 1;
 	u8 fentry            : 1;
 	u8 profiling_func    : 1;
+	u8 warned	     : 1;
 	u8 embedded_insn     : 1;
 	u8 local_label       : 1;
 	u8 frame_pointer     : 1;
 	u8 ignore	     : 1;
-	u8 warnings	     : 2;
 	struct list_head pv_target;
 	struct reloc *relocs;
 };
tools/objtool/include/objtool/warn.h +3 -11
index b29ac144e4f5..e3ad9b2caf87 100644
@@ -57,22 +57,14 @@ static inline char *offstr(struct section *sec, unsigned long offset)
 	free(_str);					\
 })
 
-#define WARN_LIMIT 2
-
 #define WARN_INSN(insn, format, ...)					\
 ({									\
 	struct instruction *_insn = (insn);				\
-	BUILD_BUG_ON(WARN_LIMIT > 2);					\
-	if (!_insn->sym || _insn->sym->warnings < WARN_LIMIT) {		\
+	if (!_insn->sym || !_insn->sym->warned)				\
 		WARN_FUNC(format, _insn->sec, _insn->offset,		\
 			  ##__VA_ARGS__);				\
-		if (_insn->sym)						\
-			_insn->sym->warnings++;				\
-	} else if (_insn->sym && _insn->sym->warnings == WARN_LIMIT) {	\
-		WARN_FUNC("skipping duplicate warning(s)",		\
-			  _insn->sec, _insn->offset);			\
-		_insn->sym->warnings++;					\
-	}								\
+	if (_insn->sym)							\
+		_insn->sym->warned = 1;					\
 })
 
 #define BT_INSN(insn, format, ...)				\
Signature · 1 line
2.48.1
merge bot Applied
#8 lore raw

[tip: objtool/urgent] Revert "objtool: Increase per-function WARN_FUNC() rate limit"

The following commit has been merged into the objtool/urgent branch of tip:

The following commit has been merged into the objtool/urgent branch of tip:

Commit-ID:     c5610071a69d1c94c70e681874298b4fc6942098
Gitweb:        https://git.kernel.org/tip/c5610071a69d1c94c70e681874298b4fc6942098
Author:        Josh Poimboeuf <[email protected]>
AuthorDate:    Mon, 31 Mar 2025 21:26:39 -07:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Tue, 01 Apr 2025 09:07:13 +02:00

Revert "objtool: Increase per-function WARN_FUNC() rate limit"

This reverts commit 0a7fb6f07e3ad497d31ae9a2082d2cacab43d54a.

The "skipping duplicate warnings" warning is technically not an actual warning, which can cause confusion. This feature isn't all that useful anyway. It's exceedingly rare for a function to have more than one unrelated warning.

---
 tools/objtool/check.c                |  4 ++--
 tools/objtool/include/objtool/elf.h  |  2 +-
 tools/objtool/include/objtool/warn.h | 14 +++-----------
 3 files changed, 6 insertions(+), 14 deletions(-)
tools/objtool/check.c +2 -2
index bd0c78b..c8b3c8e 100644
@@ -3545,7 +3545,7 @@ static int validate_branch(struct objtool_file *file, struct symbol *func,
 
 			WARN("%s() falls through to next function %s()",
 			     func->name, insn_func(insn)->name);
-			func->warnings++;
+			func->warned = 1;
 
 			return 1;
 		}
@@ -4576,7 +4576,7 @@ static void disas_warned_funcs(struct objtool_file *file)
 	char *funcs = NULL, *tmp;
 
 	for_each_sym(file, sym) {
-		if (sym->warnings) {
+		if (sym->warned) {
 			if (!funcs) {
 				funcs = malloc(strlen(sym->name) + 1);
 				if (!funcs) {
tools/objtool/include/objtool/elf.h +1 -1
index eba0439..c7c4e87 100644
@@ -65,11 +65,11 @@ struct symbol {
 	u8 return_thunk      : 1;
 	u8 fentry            : 1;
 	u8 profiling_func    : 1;
+	u8 warned	     : 1;
 	u8 embedded_insn     : 1;
 	u8 local_label       : 1;
 	u8 frame_pointer     : 1;
 	u8 ignore	     : 1;
-	u8 warnings	     : 2;
 	struct list_head pv_target;
 	struct reloc *relocs;
 };
tools/objtool/include/objtool/warn.h +3 -11
index b29ac14..e3ad9b2 100644
@@ -57,22 +57,14 @@ static inline char *offstr(struct section *sec, unsigned long offset)
 	free(_str);					\
 })
 
-#define WARN_LIMIT 2
-
 #define WARN_INSN(insn, format, ...)					\
 ({									\
 	struct instruction *_insn = (insn);				\
-	BUILD_BUG_ON(WARN_LIMIT > 2);					\
-	if (!_insn->sym || _insn->sym->warnings < WARN_LIMIT) {		\
+	if (!_insn->sym || !_insn->sym->warned)				\
 		WARN_FUNC(format, _insn->sec, _insn->offset,		\
 			  ##__VA_ARGS__);				\
-		if (_insn->sym)						\
-			_insn->sym->warnings++;				\
-	} else if (_insn->sym && _insn->sym->warnings == WARN_LIMIT) {	\
-		WARN_FUNC("skipping duplicate warning(s)",		\
-			  _insn->sec, _insn->offset);			\
-		_insn->sym->warnings++;					\
-	}								\
+	if (_insn->sym)							\
+		_insn->sym->warned = 1;					\
 })
 
 #define BT_INSN(insn, format, ...)				\
author maintainer
#9 lore raw

PATCH 5/11 objtool: Always fail on fatal errors

In reply to Josh Poimboeuf

Objtool writes several object annotations which are used to enable critical kernel runtime functionalities like static calls and retpoline/rethunk patching.

In the rare case where it fails to read or write an object, the annotations don't get written, causing runtime code patching to fail and code to become corrupted.

Due to the catastrophic nature of such warnings, convert them to errors which fail the build regardless of CONFIG_OBJTOOL_WERROR.

---
 tools/objtool/check.c | 15 ++++-----------
 1 file changed, 4 insertions(+), 11 deletions(-)
tools/objtool/check.c +4 -11
index c8b3c8e7090c..cde669923b72 100644
@@ -4753,6 +4753,9 @@ int check(struct objtool_file *file)
 	if (!ret && !warnings)
 		return 0;
 
+	if (opts.werror && warnings)
+		ret = 1;
+
 	if (opts.verbose) {
 		if (opts.werror && warnings)
 			WARN("%d warning(s) upgraded to errors", warnings);
@@ -4760,15 +4763,5 @@ int check(struct objtool_file *file)
 		disas_warned_funcs(file);
 	}
 
-	/*
-	 * CONFIG_OBJTOOL_WERROR upgrades all warnings (and errors) to actual
-	 * errors.
-	 *
-	 * Note that even fatal errors don't yet actually return an error
-	 * without CONFIG_OBJTOOL_WERROR.  That will be fixed soon-ish.
-	 */
-	if (opts.werror)
-		return 1;
-
-	return 0;
+	return ret;
 }
Signature · 1 line
2.48.1
merge bot Applied
#10 lore raw

[tip: objtool/urgent] objtool: Always fail on fatal errors

The following commit has been merged into the objtool/urgent branch of tip:

The following commit has been merged into the objtool/urgent branch of tip:

Commit-ID:     0b10177114d1e434af850b377cf5e6620dd1d525
Gitweb:        https://git.kernel.org/tip/0b10177114d1e434af850b377cf5e6620dd1d525
Author:        Josh Poimboeuf <[email protected]>
AuthorDate:    Mon, 31 Mar 2025 21:26:40 -07:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Tue, 01 Apr 2025 09:07:13 +02:00

objtool: Always fail on fatal errors

Objtool writes several object annotations which are used to enable critical kernel runtime functionalities like static calls and retpoline/rethunk patching.

In the rare case where it fails to read or write an object, the annotations don't get written, causing runtime code patching to fail and code to become corrupted.

Due to the catastrophic nature of such warnings, convert them to errors which fail the build regardless of CONFIG_OBJTOOL_WERROR.

---
 tools/objtool/check.c | 15 ++++-----------
 1 file changed, 4 insertions(+), 11 deletions(-)
tools/objtool/check.c +4 -11
index c8b3c8e..cde6699 100644
@@ -4753,6 +4753,9 @@ out:
 	if (!ret && !warnings)
 		return 0;
 
+	if (opts.werror && warnings)
+		ret = 1;
+
 	if (opts.verbose) {
 		if (opts.werror && warnings)
 			WARN("%d warning(s) upgraded to errors", warnings);
@@ -4760,15 +4763,5 @@ out:
 		disas_warned_funcs(file);
 	}
 
-	/*
-	 * CONFIG_OBJTOOL_WERROR upgrades all warnings (and errors) to actual
-	 * errors.
-	 *
-	 * Note that even fatal errors don't yet actually return an error
-	 * without CONFIG_OBJTOOL_WERROR.  That will be fixed soon-ish.
-	 */
-	if (opts.werror)
-		return 1;
-
-	return 0;
+	return ret;
 }
author maintainer
#11 lore raw

PATCH 6/11 objtool: Change "warning:" to "error:" for fatal errors

In reply to Josh Poimboeuf

This is similar to GCC's behavior and makes it more obvious why the build failed.

---
 tools/objtool/arch/loongarch/decode.c |  14 ++-
 tools/objtool/arch/loongarch/orc.c    |   8 +-
 tools/objtool/arch/x86/decode.c       |  15 ++-
 tools/objtool/arch/x86/orc.c          |   6 +-
 tools/objtool/builtin-check.c         |  30 +++---
 tools/objtool/check.c                 | 127 +++++++++++-----------
 tools/objtool/elf.c                   | 150 ++++++++++++--------------
 tools/objtool/include/objtool/warn.h  |  51 ++++++---
 tools/objtool/objtool.c               |   4 +-
 tools/objtool/orc_dump.c              |  30 +++---
 tools/objtool/special.c               |  13 +--
 11 files changed, 226 insertions(+), 222 deletions(-)
tools/objtool/arch/loongarch/decode.c +9 -5
index 02e490555966..b6fdc68053cc 100644
@@ -63,7 +63,7 @@ static bool is_loongarch(const struct elf *elf)
 	if (elf->ehdr.e_machine == EM_LOONGARCH)
 		return true;
 
-	WARN("unexpected ELF machine type %d", elf->ehdr.e_machine);
+	ERROR("unexpected ELF machine type %d", elf->ehdr.e_machine);
 	return false;
 }
 
@@ -327,8 +327,10 @@ const char *arch_nop_insn(int len)
 {
 	static u32 nop;
 
-	if (len != LOONGARCH_INSN_SIZE)
-		WARN("invalid NOP size: %d\n", len);
+	if (len != LOONGARCH_INSN_SIZE) {
+		ERROR("invalid NOP size: %d\n", len);
+		return NULL;
+	}
 
 	nop = LOONGARCH_INSN_NOP;
 
@@ -339,8 +341,10 @@ const char *arch_ret_insn(int len)
 {
 	static u32 ret;
 
-	if (len != LOONGARCH_INSN_SIZE)
-		WARN("invalid RET size: %d\n", len);
+	if (len != LOONGARCH_INSN_SIZE) {
+		ERROR("invalid RET size: %d\n", len);
+		return NULL;
+	}
 
 	emit_jirl((union loongarch_instruction *)&ret, LOONGARCH_GPR_RA, LOONGARCH_GPR_ZERO, 0);
 
tools/objtool/arch/loongarch/orc.c +4 -4
index 873536d009d9..b58c5ff443c9 100644
@@ -41,7 +41,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 		orc->type = ORC_TYPE_REGS_PARTIAL;
 		break;
 	default:
-		WARN_INSN(insn, "unknown unwind hint type %d", cfi->type);
+		ERROR_INSN(insn, "unknown unwind hint type %d", cfi->type);
 		return -1;
 	}
 
@@ -55,7 +55,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 		orc->sp_reg = ORC_REG_FP;
 		break;
 	default:
-		WARN_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base);
+		ERROR_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base);
 		return -1;
 	}
 
@@ -72,7 +72,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 		orc->fp_reg = ORC_REG_FP;
 		break;
 	default:
-		WARN_INSN(insn, "unknown FP base reg %d", fp->base);
+		ERROR_INSN(insn, "unknown FP base reg %d", fp->base);
 		return -1;
 	}
 
@@ -89,7 +89,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 		orc->ra_reg = ORC_REG_FP;
 		break;
 	default:
-		WARN_INSN(insn, "unknown RA base reg %d", ra->base);
+		ERROR_INSN(insn, "unknown RA base reg %d", ra->base);
 		return -1;
 	}
 
tools/objtool/arch/x86/decode.c +7 -8
index 7567c893f45e..33d861c04ebd 100644
@@ -36,7 +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);
+		ERROR("unexpected ELF machine type %d", elf->ehdr.e_machine);
 		return -1;
 	}
 }
@@ -173,7 +173,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
 	ret = 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);
+		ERROR("can't decode instruction at %s:0x%lx", sec->name, offset);
 		return -1;
 	}
 
@@ -321,7 +321,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
 			break;
 
 		default:
-			/* WARN ? */
+			/* ERROR ? */
 			break;
 		}
 
@@ -561,8 +561,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
 			if (ins.prefixes.nbytes == 1 &&
 			    ins.prefixes.bytes[0] == 0xf2) {
 				/* ENQCMD cannot be used in the kernel. */
-				WARN("ENQCMD instruction at %s:%lx", sec->name,
-				     offset);
+				WARN("ENQCMD instruction at %s:%lx", sec->name, offset);
 			}
 
 		} else if (op2 == 0xa0 || op2 == 0xa8) {
@@ -646,7 +645,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
 			if (disp->sym->type == STT_SECTION)
 				func = find_symbol_by_offset(disp->sym->sec, reloc_addend(disp));
 			if (!func) {
-				WARN("no func for pv_ops[]");
+				ERROR("no func for pv_ops[]");
 				return -1;
 			}
 
@@ -776,7 +775,7 @@ const char *arch_nop_insn(int len)
 	};
 
 	if (len < 1 || len > 5) {
-		WARN("invalid NOP size: %d\n", len);
+		ERROR("invalid NOP size: %d\n", len);
 		return NULL;
 	}
 
@@ -796,7 +795,7 @@ const char *arch_ret_insn(int len)
 	};
 
 	if (len < 1 || len > 5) {
-		WARN("invalid RET size: %d\n", len);
+		ERROR("invalid RET size: %d\n", len);
 		return NULL;
 	}
 
tools/objtool/arch/x86/orc.c +3 -3
index b6cd943e87f9..7176b9ec5b05 100644
@@ -40,7 +40,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 		orc->type = ORC_TYPE_REGS_PARTIAL;
 		break;
 	default:
-		WARN_INSN(insn, "unknown unwind hint type %d", cfi->type);
+		ERROR_INSN(insn, "unknown unwind hint type %d", cfi->type);
 		return -1;
 	}
 
@@ -72,7 +72,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 		orc->sp_reg = ORC_REG_DX;
 		break;
 	default:
-		WARN_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base);
+		ERROR_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base);
 		return -1;
 	}
 
@@ -87,7 +87,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 		orc->bp_reg = ORC_REG_BP;
 		break;
 	default:
-		WARN_INSN(insn, "unknown BP base reg %d", bp->base);
+		ERROR_INSN(insn, "unknown BP base reg %d", bp->base);
 		return -1;
 	}
 
tools/objtool/builtin-check.c +15 -15
index e364ab6345d3..80239843e9f0 100644
@@ -139,22 +139,22 @@ int cmd_parse_options(int argc, const char **argv, const char * const usage[])
 static bool opts_valid(void)
 {
 	if (opts.mnop && !opts.mcount) {
-		WARN("--mnop requires --mcount");
+		ERROR("--mnop requires --mcount");
 		return false;
 	}
 
 	if (opts.noinstr && !opts.link) {
-		WARN("--noinstr requires --link");
+		ERROR("--noinstr requires --link");
 		return false;
 	}
 
 	if (opts.ibt && !opts.link) {
-		WARN("--ibt requires --link");
+		ERROR("--ibt requires --link");
 		return false;
 	}
 
 	if (opts.unret && !opts.link) {
-		WARN("--unret requires --link");
+		ERROR("--unret requires --link");
 		return false;
 	}
 
@@ -171,7 +171,7 @@ static bool opts_valid(void)
 	    opts.static_call		||
 	    opts.uaccess) {
 		if (opts.dump_orc) {
-			WARN("--dump can't be combined with other actions");
+			ERROR("--dump can't be combined with other actions");
 			return false;
 		}
 
@@ -181,7 +181,7 @@ static bool opts_valid(void)
 	if (opts.dump_orc)
 		return true;
 
-	WARN("At least one action required");
+	ERROR("At least one action required");
 	return false;
 }
 
@@ -194,30 +194,30 @@ static int copy_file(const char *src, const char *dst)
 
 	src_fd = open(src, O_RDONLY);
 	if (src_fd == -1) {
-		WARN("can't open %s for reading: %s", src, strerror(errno));
+		ERROR("can't open %s for reading: %s", src, strerror(errno));
 		return 1;
 	}
 
 	dst_fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0400);
 	if (dst_fd == -1) {
-		WARN("can't open %s for writing: %s", dst, strerror(errno));
+		ERROR("can't open %s for writing: %s", dst, strerror(errno));
 		return 1;
 	}
 
 	if (fstat(src_fd, &stat) == -1) {
-		WARN_GLIBC("fstat");
+		ERROR_GLIBC("fstat");
 		return 1;
 	}
 
 	if (fchmod(dst_fd, stat.st_mode) == -1) {
-		WARN_GLIBC("fchmod");
+		ERROR_GLIBC("fchmod");
 		return 1;
 	}
 
 	for (to_copy = stat.st_size; to_copy > 0; to_copy -= copied) {
 		copied = sendfile(dst_fd, src_fd, &offset, to_copy);
 		if (copied == -1) {
-			WARN_GLIBC("sendfile");
+			ERROR_GLIBC("sendfile");
 			return 1;
 		}
 	}
@@ -231,14 +231,14 @@ static void save_argv(int argc, const char **argv)
 {
 	orig_argv = calloc(argc, sizeof(char *));
 	if (!orig_argv) {
-		WARN_GLIBC("calloc");
+		ERROR_GLIBC("calloc");
 		exit(1);
 	}
 
 	for (int i = 0; i < argc; i++) {
 		orig_argv[i] = strdup(argv[i]);
 		if (!orig_argv[i]) {
-			WARN_GLIBC("strdup(%s)", argv[i]);
+			ERROR_GLIBC("strdup(%s)", argv[i]);
 			exit(1);
 		}
 	};
@@ -257,7 +257,7 @@ void print_args(void)
 	 */
 	backup = malloc(strlen(objname) + strlen(ORIG_SUFFIX) + 1);
 	if (!backup) {
-		WARN_GLIBC("malloc");
+		ERROR_GLIBC("malloc");
 		goto print;
 	}
 
@@ -319,7 +319,7 @@ int objtool_run(int argc, const char **argv)
 		return 1;
 
 	if (!opts.link && has_multiple_files(file->elf)) {
-		WARN("Linked object requires --link");
+		ERROR("Linked object requires --link");
 		return 1;
 	}
 
tools/objtool/check.c +60 -67

401 lines not on this page · raw message

tools/objtool/elf.c +71 -79

497 lines not on this page · raw message

tools/objtool/include/objtool/warn.h +35 -16

71 lines not on this page · raw message

tools/objtool/objtool.c +2 -2
index e4b49c534e4d..5c8b974ad0f9 100644
@@ -23,7 +23,7 @@ static struct objtool_file file;
 struct objtool_file *objtool_open_read(const char *filename)
 {
 	if (file.elf) {
-		WARN("won't handle more than one file at a time");
+		ERROR("won't handle more than one file at a time");
 		return NULL;
 	}
 
@@ -50,7 +50,7 @@ int objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func)
 		return 0;
 
 	if (!f->pv_ops) {
-		WARN("paravirt confusion");
+		ERROR("paravirt confusion");
 		return -1;
 	}
 
tools/objtool/orc_dump.c +15 -15
index 05ef0e297837..1dd9fc18fe62 100644
@@ -36,47 +36,47 @@ int orc_dump(const char *filename)
 
 	elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
 	if (!elf) {
-		WARN_ELF("elf_begin");
+		ERROR_ELF("elf_begin");
 		return -1;
 	}
 
 	if (!elf64_getehdr(elf)) {
-		WARN_ELF("elf64_getehdr");
+		ERROR_ELF("elf64_getehdr");
 		return -1;
 	}
 	memcpy(&dummy_elf.ehdr, elf64_getehdr(elf), sizeof(dummy_elf.ehdr));
 
 	if (elf_getshdrnum(elf, &nr_sections)) {
-		WARN_ELF("elf_getshdrnum");
+		ERROR_ELF("elf_getshdrnum");
 		return -1;
 	}
 
 	if (elf_getshdrstrndx(elf, &shstrtab_idx)) {
-		WARN_ELF("elf_getshdrstrndx");
+		ERROR_ELF("elf_getshdrstrndx");
 		return -1;
 	}
 
 	for (i = 0; i < nr_sections; i++) {
 		scn = elf_getscn(elf, i);
 		if (!scn) {
-			WARN_ELF("elf_getscn");
+			ERROR_ELF("elf_getscn");
 			return -1;
 		}
 
 		if (!gelf_getshdr(scn, &sh)) {
-			WARN_ELF("gelf_getshdr");
+			ERROR_ELF("gelf_getshdr");
 			return -1;
 		}
 
 		name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
 		if (!name) {
-			WARN_ELF("elf_strptr");
+			ERROR_ELF("elf_strptr");
 			return -1;
 		}
 
 		data = elf_getdata(scn, NULL);
 		if (!data) {
-			WARN_ELF("elf_getdata");
+			ERROR_ELF("elf_getdata");
 			return -1;
 		}
 
@@ -99,7 +99,7 @@ int orc_dump(const char *filename)
 		return 0;
 
 	if (orc_size % sizeof(*orc) != 0) {
-		WARN("bad .orc_unwind section size");
+		ERROR("bad .orc_unwind section size");
 		return -1;
 	}
 
@@ -107,36 +107,36 @@ int orc_dump(const char *filename)
 	for (i = 0; i < nr_entries; i++) {
 		if (rela_orc_ip) {
 			if (!gelf_getrela(rela_orc_ip, i, &rela)) {
-				WARN_ELF("gelf_getrela");
+				ERROR_ELF("gelf_getrela");
 				return -1;
 			}
 
 			if (!gelf_getsym(symtab, GELF_R_SYM(rela.r_info), &sym)) {
-				WARN_ELF("gelf_getsym");
+				ERROR_ELF("gelf_getsym");
 				return -1;
 			}
 
 			if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) {
 				scn = elf_getscn(elf, sym.st_shndx);
 				if (!scn) {
-					WARN_ELF("elf_getscn");
+					ERROR_ELF("elf_getscn");
 					return -1;
 				}
 
 				if (!gelf_getshdr(scn, &sh)) {
-					WARN_ELF("gelf_getshdr");
+					ERROR_ELF("gelf_getshdr");
 					return -1;
 				}
 
 				name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
 				if (!name) {
-					WARN_ELF("elf_strptr");
+					ERROR_ELF("elf_strptr");
 					return -1;
 				}
 			} else {
 				name = elf_strptr(elf, strtab_idx, sym.st_name);
 				if (!name) {
-					WARN_ELF("elf_strptr");
+					ERROR_ELF("elf_strptr");
 					return -1;
 				}
 			}
tools/objtool/special.c +5 -8
index 6cd7b1be5331..c80fed8a840e 100644
@@ -86,7 +86,7 @@ static int get_alt_entry(struct elf *elf, const struct special_entry *entry,
 
 	orig_reloc = find_reloc_by_dest(elf, sec, offset + entry->orig);
 	if (!orig_reloc) {
-		WARN_FUNC("can't find orig reloc", sec, offset + entry->orig);
+		ERROR_FUNC(sec, offset + entry->orig, "can't find orig reloc");
 		return -1;
 	}
 
@@ -97,8 +97,7 @@ static int get_alt_entry(struct elf *elf, const struct special_entry *entry,
 	if (!entry->group || alt->new_len) {
 		new_reloc = find_reloc_by_dest(elf, sec, offset + entry->new);
 		if (!new_reloc) {
-			WARN_FUNC("can't find new reloc",
-				  sec, offset + entry->new);
+			ERROR_FUNC(sec, offset + entry->new, "can't find new reloc");
 			return -1;
 		}
 
@@ -114,8 +113,7 @@ static int get_alt_entry(struct elf *elf, const struct special_entry *entry,
 
 		key_reloc = find_reloc_by_dest(elf, sec, offset + entry->key);
 		if (!key_reloc) {
-			WARN_FUNC("can't find key reloc",
-				  sec, offset + entry->key);
+			ERROR_FUNC(sec, offset + entry->key, "can't find key reloc");
 			return -1;
 		}
 		alt->key_addend = reloc_addend(key_reloc);
@@ -145,8 +143,7 @@ int special_get_alts(struct elf *elf, struct list_head *alts)
 			continue;
 
 		if (sec->sh.sh_size % entry->size != 0) {
-			WARN("%s size not a multiple of %d",
-			     sec->name, entry->size);
+			ERROR("%s size not a multiple of %d", sec->name, entry->size);
 			return -1;
 		}
 
@@ -155,7 +152,7 @@ int special_get_alts(struct elf *elf, struct list_head *alts)
 		for (idx = 0; idx < nr_entries; idx++) {
 			alt = malloc(sizeof(*alt));
 			if (!alt) {
-				WARN("malloc failed");
+				ERROR_GLIBC("malloc failed");
 				return -1;
 			}
 			memset(alt, 0, sizeof(*alt));
Signature · 1 line
2.48.1
merge bot Applied
#12 lore raw

[tip: objtool/urgent] objtool: Change "warning:" to "error: " for fatal errors

The following commit has been merged into the objtool/urgent branch of tip:

The following commit has been merged into the objtool/urgent branch of tip:

Commit-ID:     3e7be635937d19b91bab70695328214a3d789d51
Gitweb:        https://git.kernel.org/tip/3e7be635937d19b91bab70695328214a3d789d51
Author:        Josh Poimboeuf <[email protected]>
AuthorDate:    Mon, 31 Mar 2025 21:26:41 -07:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Tue, 01 Apr 2025 09:07:13 +02:00

objtool: Change "warning:" to "error: " for fatal errors

This is similar to GCC's behavior and makes it more obvious why the build failed.

---
 tools/objtool/arch/loongarch/decode.c |  14 +-
 tools/objtool/arch/loongarch/orc.c    |   8 +-
 tools/objtool/arch/x86/decode.c       |  15 +--
 tools/objtool/arch/x86/orc.c          |   6 +-
 tools/objtool/builtin-check.c         |  30 ++---
 tools/objtool/check.c                 | 127 +++++++++------------
 tools/objtool/elf.c                   | 150 +++++++++++--------------
 tools/objtool/include/objtool/warn.h  |  51 ++++++---
 tools/objtool/objtool.c               |   4 +-
 tools/objtool/orc_dump.c              |  30 ++---
 tools/objtool/special.c               |  13 +--
 11 files changed, 226 insertions(+), 222 deletions(-)
tools/objtool/arch/loongarch/decode.c +9 -5
index 02e4905..b6fdc68 100644
@@ -63,7 +63,7 @@ static bool is_loongarch(const struct elf *elf)
 	if (elf->ehdr.e_machine == EM_LOONGARCH)
 		return true;
 
-	WARN("unexpected ELF machine type %d", elf->ehdr.e_machine);
+	ERROR("unexpected ELF machine type %d", elf->ehdr.e_machine);
 	return false;
 }
 
@@ -327,8 +327,10 @@ const char *arch_nop_insn(int len)
 {
 	static u32 nop;
 
-	if (len != LOONGARCH_INSN_SIZE)
-		WARN("invalid NOP size: %d\n", len);
+	if (len != LOONGARCH_INSN_SIZE) {
+		ERROR("invalid NOP size: %d\n", len);
+		return NULL;
+	}
 
 	nop = LOONGARCH_INSN_NOP;
 
@@ -339,8 +341,10 @@ const char *arch_ret_insn(int len)
 {
 	static u32 ret;
 
-	if (len != LOONGARCH_INSN_SIZE)
-		WARN("invalid RET size: %d\n", len);
+	if (len != LOONGARCH_INSN_SIZE) {
+		ERROR("invalid RET size: %d\n", len);
+		return NULL;
+	}
 
 	emit_jirl((union loongarch_instruction *)&ret, LOONGARCH_GPR_RA, LOONGARCH_GPR_ZERO, 0);
 
tools/objtool/arch/loongarch/orc.c +4 -4
index 873536d..b58c5ff 100644
@@ -41,7 +41,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 		orc->type = ORC_TYPE_REGS_PARTIAL;
 		break;
 	default:
-		WARN_INSN(insn, "unknown unwind hint type %d", cfi->type);
+		ERROR_INSN(insn, "unknown unwind hint type %d", cfi->type);
 		return -1;
 	}
 
@@ -55,7 +55,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 		orc->sp_reg = ORC_REG_FP;
 		break;
 	default:
-		WARN_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base);
+		ERROR_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base);
 		return -1;
 	}
 
@@ -72,7 +72,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 		orc->fp_reg = ORC_REG_FP;
 		break;
 	default:
-		WARN_INSN(insn, "unknown FP base reg %d", fp->base);
+		ERROR_INSN(insn, "unknown FP base reg %d", fp->base);
 		return -1;
 	}
 
@@ -89,7 +89,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 		orc->ra_reg = ORC_REG_FP;
 		break;
 	default:
-		WARN_INSN(insn, "unknown RA base reg %d", ra->base);
+		ERROR_INSN(insn, "unknown RA base reg %d", ra->base);
 		return -1;
 	}
 
tools/objtool/arch/x86/decode.c +7 -8
index 7567c89..33d861c 100644
@@ -36,7 +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);
+		ERROR("unexpected ELF machine type %d", elf->ehdr.e_machine);
 		return -1;
 	}
 }
@@ -173,7 +173,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
 	ret = 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);
+		ERROR("can't decode instruction at %s:0x%lx", sec->name, offset);
 		return -1;
 	}
 
@@ -321,7 +321,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
 			break;
 
 		default:
-			/* WARN ? */
+			/* ERROR ? */
 			break;
 		}
 
@@ -561,8 +561,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
 			if (ins.prefixes.nbytes == 1 &&
 			    ins.prefixes.bytes[0] == 0xf2) {
 				/* ENQCMD cannot be used in the kernel. */
-				WARN("ENQCMD instruction at %s:%lx", sec->name,
-				     offset);
+				WARN("ENQCMD instruction at %s:%lx", sec->name, offset);
 			}
 
 		} else if (op2 == 0xa0 || op2 == 0xa8) {
@@ -646,7 +645,7 @@ int arch_decode_instruction(struct objtool_file *file, const struct section *sec
 			if (disp->sym->type == STT_SECTION)
 				func = find_symbol_by_offset(disp->sym->sec, reloc_addend(disp));
 			if (!func) {
-				WARN("no func for pv_ops[]");
+				ERROR("no func for pv_ops[]");
 				return -1;
 			}
 
@@ -776,7 +775,7 @@ const char *arch_nop_insn(int len)
 	};
 
 	if (len < 1 || len > 5) {
-		WARN("invalid NOP size: %d\n", len);
+		ERROR("invalid NOP size: %d\n", len);
 		return NULL;
 	}
 
@@ -796,7 +795,7 @@ const char *arch_ret_insn(int len)
 	};
 
 	if (len < 1 || len > 5) {
-		WARN("invalid RET size: %d\n", len);
+		ERROR("invalid RET size: %d\n", len);
 		return NULL;
 	}
 
tools/objtool/arch/x86/orc.c +3 -3
index b6cd943..7176b9e 100644
@@ -40,7 +40,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 		orc->type = ORC_TYPE_REGS_PARTIAL;
 		break;
 	default:
-		WARN_INSN(insn, "unknown unwind hint type %d", cfi->type);
+		ERROR_INSN(insn, "unknown unwind hint type %d", cfi->type);
 		return -1;
 	}
 
@@ -72,7 +72,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 		orc->sp_reg = ORC_REG_DX;
 		break;
 	default:
-		WARN_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base);
+		ERROR_INSN(insn, "unknown CFA base reg %d", cfi->cfa.base);
 		return -1;
 	}
 
@@ -87,7 +87,7 @@ int init_orc_entry(struct orc_entry *orc, struct cfi_state *cfi, struct instruct
 		orc->bp_reg = ORC_REG_BP;
 		break;
 	default:
-		WARN_INSN(insn, "unknown BP base reg %d", bp->base);
+		ERROR_INSN(insn, "unknown BP base reg %d", bp->base);
 		return -1;
 	}
 
tools/objtool/builtin-check.c +15 -15
index e364ab6..8023984 100644
@@ -139,22 +139,22 @@ int cmd_parse_options(int argc, const char **argv, const char * const usage[])
 static bool opts_valid(void)
 {
 	if (opts.mnop && !opts.mcount) {
-		WARN("--mnop requires --mcount");
+		ERROR("--mnop requires --mcount");
 		return false;
 	}
 
 	if (opts.noinstr && !opts.link) {
-		WARN("--noinstr requires --link");
+		ERROR("--noinstr requires --link");
 		return false;
 	}
 
 	if (opts.ibt && !opts.link) {
-		WARN("--ibt requires --link");
+		ERROR("--ibt requires --link");
 		return false;
 	}
 
 	if (opts.unret && !opts.link) {
-		WARN("--unret requires --link");
+		ERROR("--unret requires --link");
 		return false;
 	}
 
@@ -171,7 +171,7 @@ static bool opts_valid(void)
 	    opts.static_call		||
 	    opts.uaccess) {
 		if (opts.dump_orc) {
-			WARN("--dump can't be combined with other actions");
+			ERROR("--dump can't be combined with other actions");
 			return false;
 		}
 
@@ -181,7 +181,7 @@ static bool opts_valid(void)
 	if (opts.dump_orc)
 		return true;
 
-	WARN("At least one action required");
+	ERROR("At least one action required");
 	return false;
 }
 
@@ -194,30 +194,30 @@ static int copy_file(const char *src, const char *dst)
 
 	src_fd = open(src, O_RDONLY);
 	if (src_fd == -1) {
-		WARN("can't open %s for reading: %s", src, strerror(errno));
+		ERROR("can't open %s for reading: %s", src, strerror(errno));
 		return 1;
 	}
 
 	dst_fd = open(dst, O_WRONLY | O_CREAT | O_TRUNC, 0400);
 	if (dst_fd == -1) {
-		WARN("can't open %s for writing: %s", dst, strerror(errno));
+		ERROR("can't open %s for writing: %s", dst, strerror(errno));
 		return 1;
 	}
 
 	if (fstat(src_fd, &stat) == -1) {
-		WARN_GLIBC("fstat");
+		ERROR_GLIBC("fstat");
 		return 1;
 	}
 
 	if (fchmod(dst_fd, stat.st_mode) == -1) {
-		WARN_GLIBC("fchmod");
+		ERROR_GLIBC("fchmod");
 		return 1;
 	}
 
 	for (to_copy = stat.st_size; to_copy > 0; to_copy -= copied) {
 		copied = sendfile(dst_fd, src_fd, &offset, to_copy);
 		if (copied == -1) {
-			WARN_GLIBC("sendfile");
+			ERROR_GLIBC("sendfile");
 			return 1;
 		}
 	}
@@ -231,14 +231,14 @@ static void save_argv(int argc, const char **argv)
 {
 	orig_argv = calloc(argc, sizeof(char *));
 	if (!orig_argv) {
-		WARN_GLIBC("calloc");
+		ERROR_GLIBC("calloc");
 		exit(1);
 	}
 
 	for (int i = 0; i < argc; i++) {
 		orig_argv[i] = strdup(argv[i]);
 		if (!orig_argv[i]) {
-			WARN_GLIBC("strdup(%s)", argv[i]);
+			ERROR_GLIBC("strdup(%s)", argv[i]);
 			exit(1);
 		}
 	};
@@ -257,7 +257,7 @@ void print_args(void)
 	 */
 	backup = malloc(strlen(objname) + strlen(ORIG_SUFFIX) + 1);
 	if (!backup) {
-		WARN_GLIBC("malloc");
+		ERROR_GLIBC("malloc");
 		goto print;
 	}
 
@@ -319,7 +319,7 @@ int objtool_run(int argc, const char **argv)
 		return 1;
 
 	if (!opts.link && has_multiple_files(file->elf)) {
-		WARN("Linked object requires --link");
+		ERROR("Linked object requires --link");
 		return 1;
 	}
 
tools/objtool/check.c +60 -67

401 lines not on this page · raw message

tools/objtool/elf.c +71 -79

497 lines not on this page · raw message

tools/objtool/include/objtool/warn.h +35 -16

71 lines not on this page · raw message

tools/objtool/objtool.c +2 -2
index e4b49c5..5c8b974 100644
@@ -23,7 +23,7 @@ static struct objtool_file file;
 struct objtool_file *objtool_open_read(const char *filename)
 {
 	if (file.elf) {
-		WARN("won't handle more than one file at a time");
+		ERROR("won't handle more than one file at a time");
 		return NULL;
 	}
 
@@ -50,7 +50,7 @@ int objtool_pv_add(struct objtool_file *f, int idx, struct symbol *func)
 		return 0;
 
 	if (!f->pv_ops) {
-		WARN("paravirt confusion");
+		ERROR("paravirt confusion");
 		return -1;
 	}
 
tools/objtool/orc_dump.c +15 -15
index 05ef0e2..1dd9fc1 100644
@@ -36,47 +36,47 @@ int orc_dump(const char *filename)
 
 	elf = elf_begin(fd, ELF_C_READ_MMAP, NULL);
 	if (!elf) {
-		WARN_ELF("elf_begin");
+		ERROR_ELF("elf_begin");
 		return -1;
 	}
 
 	if (!elf64_getehdr(elf)) {
-		WARN_ELF("elf64_getehdr");
+		ERROR_ELF("elf64_getehdr");
 		return -1;
 	}
 	memcpy(&dummy_elf.ehdr, elf64_getehdr(elf), sizeof(dummy_elf.ehdr));
 
 	if (elf_getshdrnum(elf, &nr_sections)) {
-		WARN_ELF("elf_getshdrnum");
+		ERROR_ELF("elf_getshdrnum");
 		return -1;
 	}
 
 	if (elf_getshdrstrndx(elf, &shstrtab_idx)) {
-		WARN_ELF("elf_getshdrstrndx");
+		ERROR_ELF("elf_getshdrstrndx");
 		return -1;
 	}
 
 	for (i = 0; i < nr_sections; i++) {
 		scn = elf_getscn(elf, i);
 		if (!scn) {
-			WARN_ELF("elf_getscn");
+			ERROR_ELF("elf_getscn");
 			return -1;
 		}
 
 		if (!gelf_getshdr(scn, &sh)) {
-			WARN_ELF("gelf_getshdr");
+			ERROR_ELF("gelf_getshdr");
 			return -1;
 		}
 
 		name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
 		if (!name) {
-			WARN_ELF("elf_strptr");
+			ERROR_ELF("elf_strptr");
 			return -1;
 		}
 
 		data = elf_getdata(scn, NULL);
 		if (!data) {
-			WARN_ELF("elf_getdata");
+			ERROR_ELF("elf_getdata");
 			return -1;
 		}
 
@@ -99,7 +99,7 @@ int orc_dump(const char *filename)
 		return 0;
 
 	if (orc_size % sizeof(*orc) != 0) {
-		WARN("bad .orc_unwind section size");
+		ERROR("bad .orc_unwind section size");
 		return -1;
 	}
 
@@ -107,36 +107,36 @@ int orc_dump(const char *filename)
 	for (i = 0; i < nr_entries; i++) {
 		if (rela_orc_ip) {
 			if (!gelf_getrela(rela_orc_ip, i, &rela)) {
-				WARN_ELF("gelf_getrela");
+				ERROR_ELF("gelf_getrela");
 				return -1;
 			}
 
 			if (!gelf_getsym(symtab, GELF_R_SYM(rela.r_info), &sym)) {
-				WARN_ELF("gelf_getsym");
+				ERROR_ELF("gelf_getsym");
 				return -1;
 			}
 
 			if (GELF_ST_TYPE(sym.st_info) == STT_SECTION) {
 				scn = elf_getscn(elf, sym.st_shndx);
 				if (!scn) {
-					WARN_ELF("elf_getscn");
+					ERROR_ELF("elf_getscn");
 					return -1;
 				}
 
 				if (!gelf_getshdr(scn, &sh)) {
-					WARN_ELF("gelf_getshdr");
+					ERROR_ELF("gelf_getshdr");
 					return -1;
 				}
 
 				name = elf_strptr(elf, shstrtab_idx, sh.sh_name);
 				if (!name) {
-					WARN_ELF("elf_strptr");
+					ERROR_ELF("elf_strptr");
 					return -1;
 				}
 			} else {
 				name = elf_strptr(elf, strtab_idx, sym.st_name);
 				if (!name) {
-					WARN_ELF("elf_strptr");
+					ERROR_ELF("elf_strptr");
 					return -1;
 				}
 			}
tools/objtool/special.c +5 -8
index 6cd7b1b..c80fed8 100644
@@ -86,7 +86,7 @@ static int get_alt_entry(struct elf *elf, const struct special_entry *entry,
 
 	orig_reloc = find_reloc_by_dest(elf, sec, offset + entry->orig);
 	if (!orig_reloc) {
-		WARN_FUNC("can't find orig reloc", sec, offset + entry->orig);
+		ERROR_FUNC(sec, offset + entry->orig, "can't find orig reloc");
 		return -1;
 	}
 
@@ -97,8 +97,7 @@ static int get_alt_entry(struct elf *elf, const struct special_entry *entry,
 	if (!entry->group || alt->new_len) {
 		new_reloc = find_reloc_by_dest(elf, sec, offset + entry->new);
 		if (!new_reloc) {
-			WARN_FUNC("can't find new reloc",
-				  sec, offset + entry->new);
+			ERROR_FUNC(sec, offset + entry->new, "can't find new reloc");
 			return -1;
 		}
 
@@ -114,8 +113,7 @@ static int get_alt_entry(struct elf *elf, const struct special_entry *entry,
 
 		key_reloc = find_reloc_by_dest(elf, sec, offset + entry->key);
 		if (!key_reloc) {
-			WARN_FUNC("can't find key reloc",
-				  sec, offset + entry->key);
+			ERROR_FUNC(sec, offset + entry->key, "can't find key reloc");
 			return -1;
 		}
 		alt->key_addend = reloc_addend(key_reloc);
@@ -145,8 +143,7 @@ int special_get_alts(struct elf *elf, struct list_head *alts)
 			continue;
 
 		if (sec->sh.sh_size % entry->size != 0) {
-			WARN("%s size not a multiple of %d",
-			     sec->name, entry->size);
+			ERROR("%s size not a multiple of %d", sec->name, entry->size);
 			return -1;
 		}
 
@@ -155,7 +152,7 @@ int special_get_alts(struct elf *elf, struct list_head *alts)
 		for (idx = 0; idx < nr_entries; idx++) {
 			alt = malloc(sizeof(*alt));
 			if (!alt) {
-				WARN("malloc failed");
+				ERROR_GLIBC("malloc failed");
 				return -1;
 			}
 			memset(alt, 0, sizeof(*alt));
author maintainer
#13 lore raw

PATCH 7/11 objtool: Fix verbose disassembly if CROSS_COMPILE isn't set

In reply to Josh Poimboeuf

From: David Laight <[email protected]>

In verbose mode, when printing the disassembly of affected functions, if CROSS_COMPILE isn't set, the objdump command string gets prefixed with "(null)".

Somehow this worked before. Maybe some versions of glibc return an empty string instead of NULL. Fix it regardless.

[ jpoimboe: Rewrite commit log. ]

Fixes ca653464dd097 ("objtool: Add verbose option for disassembling affected functions")
---
 tools/objtool/check.c | 2 ++
 1 file changed, 2 insertions(+)
tools/objtool/check.c +2 -0
index ff83be1aab1d..4a1f6c3169b3 100644
@@ -4523,6 +4523,8 @@ static void disas_funcs(const char *funcs)
 	char *cmd;
 
 	cross_compile = getenv("CROSS_COMPILE");
+	if (!cross_compile)
+		cross_compile = "";
 
 	objdump_str = "%sobjdump -wdr %s | gawk -M -v _funcs='%s' '"
 			"BEGIN { split(_funcs, funcs); }"
Signature · 1 line
2.48.1
merge bot Applied
#14 lore raw

[tip: objtool/urgent] objtool: Fix verbose disassembly if CROSS_COMPILE isn't set

The following commit has been merged into the objtool/urgent branch of tip:

The following commit has been merged into the objtool/urgent branch of tip:

Commit-ID:     e77956e4e5c11218e60a1fe8cdbccd02476f2e56
Gitweb:        https://git.kernel.org/tip/e77956e4e5c11218e60a1fe8cdbccd02476f2e56
Author:        David Laight <[email protected]>
AuthorDate:    Mon, 31 Mar 2025 21:26:42 -07:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Tue, 01 Apr 2025 09:07:13 +02:00

objtool: Fix verbose disassembly if CROSS_COMPILE isn't set

In verbose mode, when printing the disassembly of affected functions, if CROSS_COMPILE isn't set, the objdump command string gets prefixed with "(null)".

Somehow this worked before. Maybe some versions of glibc return an empty string instead of NULL. Fix it regardless.

[ jpoimboe: Rewrite commit log. ]

---
 tools/objtool/check.c | 2 ++
 1 file changed, 2 insertions(+)
tools/objtool/check.c +2 -0
index ff83be1..4a1f6c3 100644
@@ -4523,6 +4523,8 @@ static void disas_funcs(const char *funcs)
 	char *cmd;
 
 	cross_compile = getenv("CROSS_COMPILE");
+	if (!cross_compile)
+		cross_compile = "";
 
 	objdump_str = "%sobjdump -wdr %s | gawk -M -v _funcs='%s' '"
 			"BEGIN { split(_funcs, funcs); }"
author maintainer
#15 lore raw

PATCH 8/11 objtool/loongarch: Add unwind hints in prepare_frametrace()

In reply to Josh Poimboeuf

If 'regs' points to a local stack variable, prepare_frametrace() stores all registers to the stack. This confuses objtool as it expects them to be restored from the stack later.

The stores don't affect stack tracing, so use unwind hints to hide them from objtool.

Fixes the following warnings:

arch/loongarch/kernel/traps.o: warning: objtool: show_stack+0xe0: stack state mismatch: reg1[22]=-1+0 reg2[22]=-2-160 arch/loongarch/kernel/traps.o: warning: objtool: show_stack+0xe0: stack state mismatch: reg1[23]=-1+0 reg2[23]=-2-152

Cc Tiezhu Yang <[email protected]>
Fixes cb8a2ef0848c ("LoongArch: Add ORC stack unwinder support")
---
 arch/loongarch/include/asm/stacktrace.h   |  3 +++
 arch/loongarch/include/asm/unwind_hints.h | 10 +++++++++-
 2 files changed, 12 insertions(+), 1 deletion(-)
arch/loongarch/include/asm/stacktrace.h +3 -0
index f23adb15f418..fc8b64773794 100644
@@ -8,6 +8,7 @@
 #include <asm/asm.h>
 #include <asm/ptrace.h>
 #include <asm/loongarch.h>
+#include <asm/unwind_hints.h>
 #include <linux/stringify.h>
 
 enum stack_type {
@@ -43,6 +44,7 @@ int get_stack_info(unsigned long stack, struct task_struct *task, struct stack_i
 static __always_inline void prepare_frametrace(struct pt_regs *regs)
 {
 	__asm__ __volatile__(
+		UNWIND_HINT_SAVE
 		/* Save $ra */
 		STORE_ONE_REG(1)
 		/* Use $ra to save PC */
@@ -80,6 +82,7 @@ static __always_inline void prepare_frametrace(struct pt_regs *regs)
 		STORE_ONE_REG(29)
 		STORE_ONE_REG(30)
 		STORE_ONE_REG(31)
+		UNWIND_HINT_RESTORE
 		: "=m" (regs->csr_era)
 		: "r" (regs->regs)
 		: "memory");
arch/loongarch/include/asm/unwind_hints.h +9 -1
index a01086ad9dde..2c68bc72736c 100644
@@ -23,6 +23,14 @@
 	UNWIND_HINT sp_reg=ORC_REG_SP type=UNWIND_HINT_TYPE_CALL
 .endm
 
-#endif /* __ASSEMBLY__ */
+#else /* !__ASSEMBLY__ */
+
+#define UNWIND_HINT_SAVE \
+	UNWIND_HINT(UNWIND_HINT_TYPE_SAVE, 0, 0, 0)
+
+#define UNWIND_HINT_RESTORE \
+	UNWIND_HINT(UNWIND_HINT_TYPE_RESTORE, 0, 0, 0)
+
+#endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_LOONGARCH_UNWIND_HINTS_H */
Signature · 1 line
2.48.1
#16 lore raw

Re: [PATCH 08/11] objtool/loongarch: Add unwind hints in prepare_frametrace()

Quoted 9 lines · Josh Poimboeuf

If 'regs' points to a local stack variable, prepare_frametrace() stores all registers to the stack. This confuses objtool as it expects them to be restored from the stack later.

The stores don't affect stack tracing, so use unwind hints to hide them from objtool.

Fixes the following warnings:

Quoted 8 lines

arch/loongarch/kernel/traps.o: warning: objtool: show_stack+0xe0: stack state mismatch: reg1[22]=-1+0 reg2[22]=-2-160 arch/loongarch/kernel/traps.o: warning: objtool: show_stack+0xe0: stack state mismatch: reg1[23]=-1+0 reg2[23]=-2-152

Cc Tiezhu Yang <[email protected]>
Fixes cb8a2ef0848c ("LoongArch: Add ORC stack unwinder support")

Note, I skipped this fix from tip:objtool/urgent for the time being, because Tiezhu Yang indicated that he'd be reviewing and testing this patch.

Thanks,

Ingo

Tested-by
#17 lore raw

Re: [PATCH 08/11] objtool/loongarch: Add unwind hints in prepare_frametrace()

Quoted 21 lines · Ingo Molnar
Quoted 9 lines · Josh Poimboeuf

If 'regs' points to a local stack variable, prepare_frametrace() stores all registers to the stack. This confuses objtool as it expects them to be restored from the stack later.

The stores don't affect stack tracing, so use unwind hints to hide them from objtool.

Fixes the following warnings:

Quoted 8 lines

arch/loongarch/kernel/traps.o: warning: objtool: show_stack+0xe0: stack state mismatch: reg1[22]=-1+0 reg2[22]=-2-160 arch/loongarch/kernel/traps.o: warning: objtool: show_stack+0xe0: stack state mismatch: reg1[23]=-1+0 reg2[23]=-2-152

Cc Tiezhu Yang <[email protected]>
Fixes cb8a2ef0848c ("LoongArch: Add ORC stack unwinder support")
Quoted 3 lines

Note, I skipped this fix from tip:objtool/urgent for the time being, because Tiezhu Yang indicated that he'd be reviewing and testing this patch.

#18 lore raw

Re: [PATCH 08/11] objtool/loongarch: Add unwind hints in prepare_frametrace()

Quoted 22 lines · Tiezhu Yang
Quoted 21 lines · Ingo Molnar
Quoted 17 lines · Josh Poimboeuf

If 'regs' points to a local stack variable, prepare_frametrace() stores all registers to the stack. This confuses objtool as it expects them to be restored from the stack later.

The stores don't affect stack tracing, so use unwind hints to hide them from objtool.

Fixes the following warnings:

arch/loongarch/kernel/traps.o: warning: objtool: show_stack+0xe0: stack state mismatch: reg1[22]=-1+0 reg2[22]=-2-160 arch/loongarch/kernel/traps.o: warning: objtool: show_stack+0xe0: stack state mismatch: reg1[23]=-1+0 reg2[23]=-2-152

Cc Tiezhu Yang <[email protected]>
Fixes cb8a2ef0848c ("LoongArch: Add ORC stack unwinder support")
Quoted 5 lines
Quoted 3 lines

Note, I skipped this fix from tip:objtool/urgent for the time being, because Tiezhu Yang indicated that he'd be reviewing and testing this patch.

Thank you! Is it fine with you if I send this fix with tonight's objtool/urgent pull request to Linus?

Thanks,

Ingo

#19 lore raw

Re: [PATCH 08/11] objtool/loongarch: Add unwind hints in prepare_frametrace()

Quoted 25 lines · Ingo Molnar
Quoted 22 lines · Tiezhu Yang
Quoted 21 lines · Ingo Molnar
Quoted 17 lines · Josh Poimboeuf

If 'regs' points to a local stack variable, prepare_frametrace() stores all registers to the stack. This confuses objtool as it expects them to be restored from the stack later.

The stores don't affect stack tracing, so use unwind hints to hide them from objtool.

Fixes the following warnings:

arch/loongarch/kernel/traps.o: warning: objtool: show_stack+0xe0: stack state mismatch: reg1[22]=-1+0 reg2[22]=-2-160 arch/loongarch/kernel/traps.o: warning: objtool: show_stack+0xe0: stack state mismatch: reg1[23]=-1+0 reg2[23]=-2-152

Cc Tiezhu Yang <[email protected]>
Fixes cb8a2ef0848c ("LoongArch: Add ORC stack unwinder support")
Quoted 8 lines
Quoted 5 lines
Quoted 3 lines

Note, I skipped this fix from tip:objtool/urgent for the time being, because Tiezhu Yang indicated that he'd be reviewing and testing this patch.

Thank you! Is it fine with you if I send this fix with tonight's objtool/urgent pull request to Linus?

Yes, no problem, thank you for doing this.

merge bot Applied
#20 lore raw

[tip: objtool/urgent] objtool/loongarch: Add unwind hints in prepare_frametrace()

In reply to Josh Poimboeuf
The following commit has been merged into the objtool/urgent branch of tip:

The following commit has been merged into the objtool/urgent branch of tip:

Commit-ID:     7c977393b8277ed319e92e4b598b26598c9d30c0
Gitweb:        https://git.kernel.org/tip/7c977393b8277ed319e92e4b598b26598c9d30c0
Author:        Josh Poimboeuf <[email protected]>
AuthorDate:    Mon, 31 Mar 2025 21:26:43 -07:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Tue, 01 Apr 2025 10:10:10 +02:00

objtool/loongarch: Add unwind hints in prepare_frametrace()

If 'regs' points to a local stack variable, prepare_frametrace() stores all registers to the stack. This confuses objtool as it expects them to be restored from the stack later.

The stores don't affect stack tracing, so use unwind hints to hide them from objtool.

Fixes the following warnings:

arch/loongarch/kernel/traps.o: warning: objtool: show_stack+0xe0: stack state mismatch: reg1[22]=-1+0 reg2[22]=-2-160 arch/loongarch/kernel/traps.o: warning: objtool: show_stack+0xe0: stack state mismatch: reg1[23]=-1+0 reg2[23]=-2-152

---
 arch/loongarch/include/asm/stacktrace.h   |  3 +++
 arch/loongarch/include/asm/unwind_hints.h | 10 +++++++++-
 2 files changed, 12 insertions(+), 1 deletion(-)
arch/loongarch/include/asm/stacktrace.h +3 -0
index f23adb1..fc8b647 100644
@@ -8,6 +8,7 @@
 #include <asm/asm.h>
 #include <asm/ptrace.h>
 #include <asm/loongarch.h>
+#include <asm/unwind_hints.h>
 #include <linux/stringify.h>
 
 enum stack_type {
@@ -43,6 +44,7 @@ int get_stack_info(unsigned long stack, struct task_struct *task, struct stack_i
 static __always_inline void prepare_frametrace(struct pt_regs *regs)
 {
 	__asm__ __volatile__(
+		UNWIND_HINT_SAVE
 		/* Save $ra */
 		STORE_ONE_REG(1)
 		/* Use $ra to save PC */
@@ -80,6 +82,7 @@ static __always_inline void prepare_frametrace(struct pt_regs *regs)
 		STORE_ONE_REG(29)
 		STORE_ONE_REG(30)
 		STORE_ONE_REG(31)
+		UNWIND_HINT_RESTORE
 		: "=m" (regs->csr_era)
 		: "r" (regs->regs)
 		: "memory");
arch/loongarch/include/asm/unwind_hints.h +9 -1
index a01086a..2c68bc7 100644
@@ -23,6 +23,14 @@
 	UNWIND_HINT sp_reg=ORC_REG_SP type=UNWIND_HINT_TYPE_CALL
 .endm
 
-#endif /* __ASSEMBLY__ */
+#else /* !__ASSEMBLY__ */
+
+#define UNWIND_HINT_SAVE \
+	UNWIND_HINT(UNWIND_HINT_TYPE_SAVE, 0, 0, 0)
+
+#define UNWIND_HINT_RESTORE \
+	UNWIND_HINT(UNWIND_HINT_TYPE_RESTORE, 0, 0, 0)
+
+#endif /* !__ASSEMBLY__ */
 
 #endif /* _ASM_LOONGARCH_UNWIND_HINTS_H */
author maintainer
#21 lore raw

PATCH 9/11 sched/smt: Always inline sched_smt_active()

In reply to Josh Poimboeuf

sched_smt_active() can be called from noinstr code, so it should always be inlined. The CONFIG_SCHED_SMT version already has __always_inline. Do the same for its !CONFIG_SCHED_SMT counterpart.

Fixes the following warning:

vmlinux.o: error: objtool: intel_idle_ibrs+0x13: call to sched_smt_active() leaves .noinstr.text section

Fixes 321a874a7ef8 ("sched/smt: Expose sched_smt_present static key")
---
 include/linux/sched/smt.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/sched/smt.h +1 -1
index fb1e295e7e63..166b19af956f 100644
@@ -12,7 +12,7 @@ static __always_inline bool sched_smt_active(void)
 	return static_branch_likely(&sched_smt_present);
 }
 #else
-static inline bool sched_smt_active(void) { return false; }
+static __always_inline bool sched_smt_active(void) { return false; }
 #endif
 
 void arch_smt_update(void);
Signature · 1 line
2.48.1
merge bot Applied
#22 lore raw

[tip: objtool/urgent] sched/smt: Always inline sched_smt_active()

The following commit has been merged into the objtool/urgent branch of tip:

The following commit has been merged into the objtool/urgent branch of tip:

Commit-ID:     09f37f2d7b21ff35b8b533f9ab8cfad2fe8f72f6
Gitweb:        https://git.kernel.org/tip/09f37f2d7b21ff35b8b533f9ab8cfad2fe8f72f6
Author:        Josh Poimboeuf <[email protected]>
AuthorDate:    Mon, 31 Mar 2025 21:26:44 -07:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Tue, 01 Apr 2025 09:07:13 +02:00

sched/smt: Always inline sched_smt_active()

sched_smt_active() can be called from noinstr code, so it should always be inlined. The CONFIG_SCHED_SMT version already has __always_inline. Do the same for its !CONFIG_SCHED_SMT counterpart.

Fixes the following warning:

vmlinux.o: error: objtool: intel_idle_ibrs+0x13: call to sched_smt_active() leaves .noinstr.text section

---
 include/linux/sched/smt.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/sched/smt.h +1 -1
index fb1e295..166b19a 100644
@@ -12,7 +12,7 @@ static __always_inline bool sched_smt_active(void)
 	return static_branch_likely(&sched_smt_present);
 }
 #else
-static inline bool sched_smt_active(void) { return false; }
+static __always_inline bool sched_smt_active(void) { return false; }
 #endif
 
 void arch_smt_update(void);
author maintainer
#23 lore raw

PATCH 10/11 context_tracking: Always inline ct_{nmi,irq}_{enter,exit}()

In reply to Josh Poimboeuf

Thanks to CONFIG_DEBUG_SECTION_MISMATCH, empty functions can be generated out of line. These can be called from noinstr code, so make sure they're always inlined.

Fixes the following warnings:

vmlinux.o: warning: objtool: irqentry_nmi_enter+0xa2: call to ct_nmi_enter() leaves .noinstr.text section vmlinux.o: warning: objtool: irqentry_nmi_exit+0x16: call to ct_nmi_exit() leaves .noinstr.text section vmlinux.o: warning: objtool: irqentry_exit+0x78: call to ct_irq_exit() leaves .noinstr.text section

Fixes 6f0e6c1598b1 ("context_tracking: Take IRQ eqs entrypoints over RCU")
---
 include/linux/context_tracking_irq.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
include/linux/context_tracking_irq.h +4 -4
index c50b5670c4a5..197916ee91a4 100644
@@ -10,12 +10,12 @@ void ct_irq_exit_irqson(void);
 void ct_nmi_enter(void);
 void ct_nmi_exit(void);
 #else
-static inline void ct_irq_enter(void) { }
-static inline void ct_irq_exit(void) { }
+static __always_inline void ct_irq_enter(void) { }
+static __always_inline void ct_irq_exit(void) { }
 static inline void ct_irq_enter_irqson(void) { }
 static inline void ct_irq_exit_irqson(void) { }
-static inline void ct_nmi_enter(void) { }
-static inline void ct_nmi_exit(void) { }
+static __always_inline void ct_nmi_enter(void) { }
+static __always_inline void ct_nmi_exit(void) { }
 #endif
 
 #endif
Signature · 1 line
2.48.1
merge bot Applied
#24 lore raw

[tip: objtool/urgent] context_tracking: Always inline ct_{nmi,irq}_{enter,exit}()

The following commit has been merged into the objtool/urgent branch of tip:

The following commit has been merged into the objtool/urgent branch of tip:

Commit-ID:     cf7d9bc6ba10e41084361158375677070bbbcdb7
Gitweb:        https://git.kernel.org/tip/cf7d9bc6ba10e41084361158375677070bbbcdb7
Author:        Josh Poimboeuf <[email protected]>
AuthorDate:    Mon, 31 Mar 2025 21:26:45 -07:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Tue, 01 Apr 2025 09:07:14 +02:00

context_tracking: Always inline ct_{nmi,irq}_{enter,exit}()

Thanks to CONFIG_DEBUG_SECTION_MISMATCH, empty functions can be generated out of line. These can be called from noinstr code, so make sure they're always inlined.

Fixes the following warnings:

vmlinux.o: warning: objtool: irqentry_nmi_enter+0xa2: call to ct_nmi_enter() leaves .noinstr.text section vmlinux.o: warning: objtool: irqentry_nmi_exit+0x16: call to ct_nmi_exit() leaves .noinstr.text section vmlinux.o: warning: objtool: irqentry_exit+0x78: call to ct_irq_exit() leaves .noinstr.text section

---
 include/linux/context_tracking_irq.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
include/linux/context_tracking_irq.h +4 -4
index c50b567..197916e 100644
@@ -10,12 +10,12 @@ void ct_irq_exit_irqson(void);
 void ct_nmi_enter(void);
 void ct_nmi_exit(void);
 #else
-static inline void ct_irq_enter(void) { }
-static inline void ct_irq_exit(void) { }
+static __always_inline void ct_irq_enter(void) { }
+static __always_inline void ct_irq_exit(void) { }
 static inline void ct_irq_enter_irqson(void) { }
 static inline void ct_irq_exit_irqson(void) { }
-static inline void ct_nmi_enter(void) { }
-static inline void ct_nmi_exit(void) { }
+static __always_inline void ct_nmi_enter(void) { }
+static __always_inline void ct_nmi_exit(void) { }
 #endif
 
 #endif
merge bot Applied
#25 lore raw

[tip: objtool/urgent] context_tracking: Always inline ct_{nmi,irq}_{enter,exit}()

In reply to Josh Poimboeuf
The following commit has been merged into the objtool/urgent branch of tip:

The following commit has been merged into the objtool/urgent branch of tip:

Commit-ID:     9ac50f7311dc8b39e355582f14c1e82da47a8196
Gitweb:        https://git.kernel.org/tip/9ac50f7311dc8b39e355582f14c1e82da47a8196
Author:        Josh Poimboeuf <[email protected]>
AuthorDate:    Mon, 31 Mar 2025 21:26:45 -07:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Tue, 01 Apr 2025 09:12:05 +02:00

context_tracking: Always inline ct_{nmi,irq}_{enter,exit}()

Thanks to CONFIG_DEBUG_SECTION_MISMATCH, empty functions can be generated out of line. These can be called from noinstr code, so make sure they're always inlined.

Fixes the following warnings:

vmlinux.o: warning: objtool: irqentry_nmi_enter+0xa2: call to ct_nmi_enter() leaves .noinstr.text section vmlinux.o: warning: objtool: irqentry_nmi_exit+0x16: call to ct_nmi_exit() leaves .noinstr.text section vmlinux.o: warning: objtool: irqentry_exit+0x78: call to ct_irq_exit() leaves .noinstr.text section

---
 include/linux/context_tracking_irq.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)
include/linux/context_tracking_irq.h +4 -4
index c50b567..197916e 100644
@@ -10,12 +10,12 @@ void ct_irq_exit_irqson(void);
 void ct_nmi_enter(void);
 void ct_nmi_exit(void);
 #else
-static inline void ct_irq_enter(void) { }
-static inline void ct_irq_exit(void) { }
+static __always_inline void ct_irq_enter(void) { }
+static __always_inline void ct_irq_exit(void) { }
 static inline void ct_irq_enter_irqson(void) { }
 static inline void ct_irq_exit_irqson(void) { }
-static inline void ct_nmi_enter(void) { }
-static inline void ct_nmi_exit(void) { }
+static __always_inline void ct_nmi_enter(void) { }
+static __always_inline void ct_nmi_exit(void) { }
 #endif
 
 #endif
author maintainer
#26 lore raw

PATCH 11/11 rcu-tasks: Always inline rcu_irq_work_resched()

In reply to Josh Poimboeuf

Thanks to CONFIG_DEBUG_SECTION_MISMATCH, empty functions can be generated out of line. rcu_irq_work_resched() can be called from noinstr code, so make sure it's always inlined.

Fixes 564506495ca9 ("rcu/context-tracking: Move deferred nocb resched to context tracking")
---
 include/linux/rcupdate.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/rcupdate.h +1 -1
index f8159f8a7d73..120536f4c6eb 100644
@@ -132,7 +132,7 @@ static inline void rcu_sysrq_end(void) { }
 #if defined(CONFIG_NO_HZ_FULL) && (!defined(CONFIG_GENERIC_ENTRY) || !defined(CONFIG_KVM_XFER_TO_GUEST_WORK))
 void rcu_irq_work_resched(void);
 #else
-static inline void rcu_irq_work_resched(void) { }
+static __always_inline void rcu_irq_work_resched(void) { }
 #endif
 
 #ifdef CONFIG_RCU_NOCB_CPU
Signature · 1 line
2.48.1
merge bot Applied
#27 lore raw

[tip: objtool/urgent] rcu-tasks: Always inline rcu_irq_work_resched()

The following commit has been merged into the objtool/urgent branch of tip:

The following commit has been merged into the objtool/urgent branch of tip:

Commit-ID:     f117dc45092f45e4620de4b928ce02591077ab66
Gitweb:        https://git.kernel.org/tip/f117dc45092f45e4620de4b928ce02591077ab66
Author:        Josh Poimboeuf <[email protected]>
AuthorDate:    Mon, 31 Mar 2025 21:26:46 -07:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Tue, 01 Apr 2025 09:07:14 +02:00

rcu-tasks: Always inline rcu_irq_work_resched()

Thanks to CONFIG_DEBUG_SECTION_MISMATCH, empty functions can be generated out of line. rcu_irq_work_resched() can be called from noinstr code, so make sure it's always inlined.

---
 include/linux/rcupdate.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/rcupdate.h +1 -1
index f8159f8..120536f 100644
@@ -132,7 +132,7 @@ static inline void rcu_sysrq_end(void) { }
 #if defined(CONFIG_NO_HZ_FULL) && (!defined(CONFIG_GENERIC_ENTRY) || !defined(CONFIG_KVM_XFER_TO_GUEST_WORK))
 void rcu_irq_work_resched(void);
 #else
-static inline void rcu_irq_work_resched(void) { }
+static __always_inline void rcu_irq_work_resched(void) { }
 #endif
 
 #ifdef CONFIG_RCU_NOCB_CPU
merge bot Applied
#28 lore raw

[tip: objtool/urgent] rcu-tasks: Always inline rcu_irq_work_resched()

In reply to Josh Poimboeuf
The following commit has been merged into the objtool/urgent branch of tip:

The following commit has been merged into the objtool/urgent branch of tip:

Commit-ID:     6309a5c43b0dc629851f25b2e5ef8beff61d08e5
Gitweb:        https://git.kernel.org/tip/6309a5c43b0dc629851f25b2e5ef8beff61d08e5
Author:        Josh Poimboeuf <[email protected]>
AuthorDate:    Mon, 31 Mar 2025 21:26:46 -07:00
Committer:     Ingo Molnar <[email protected]>
CommitterDate: Tue, 01 Apr 2025 09:12:17 +02:00

rcu-tasks: Always inline rcu_irq_work_resched()

Thanks to CONFIG_DEBUG_SECTION_MISMATCH, empty functions can be generated out of line. rcu_irq_work_resched() can be called from noinstr code, so make sure it's always inlined.

Fixes 564506495ca9 ("rcu/context-tracking: Move deferred nocb resched to context tracking")
Cc Frederic Weisbecker <[email protected]>
Cc Paul E. McKenney <[email protected]>
Cc Linus Torvalds <[email protected]>
---
 include/linux/rcupdate.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
include/linux/rcupdate.h +1 -1
index f8159f8..120536f 100644
@@ -132,7 +132,7 @@ static inline void rcu_sysrq_end(void) { }
 #if defined(CONFIG_NO_HZ_FULL) && (!defined(CONFIG_GENERIC_ENTRY) || !defined(CONFIG_KVM_XFER_TO_GUEST_WORK))
 void rcu_irq_work_resched(void);
 #else
-static inline void rcu_irq_work_resched(void) { }
+static __always_inline void rcu_irq_work_resched(void) { }
 #endif
 
 #ifdef CONFIG_RCU_NOCB_CPU