Merge tag 'core-bugs-2025-12-01' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip

Pull bug handling infrastructure updates from Ingo Molnar:
 "Core updates:

   - Improve WARN(), which has vararg printf like arguments, to work
     with the x86 #UD based WARN-optimizing infrastructure by hiding the
     format in the bug_table and replacing this first argument with the
     address of the bug-table entry, while making the actual function
     that's called a UD1 instruction (Peter Zijlstra)

   - Introduce the CONFIG_DEBUG_BUGVERBOSE_DETAILED Kconfig switch (Ingo
     Molnar, s390 support by Heiko Carstens)

  Fixes and cleanups:

   - bugs/s390: Remove private WARN_ON() implementation (Heiko Carstens)

   - <asm/bugs.h>: Make i386 use GENERIC_BUG_RELATIVE_POINTERS (Peter
     Zijlstra)"

* tag 'core-bugs-2025-12-01' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (31 commits)
  x86/bugs: Make i386 use GENERIC_BUG_RELATIVE_POINTERS
  x86/bug: Fix BUG_FORMAT vs KASLR
  x86_64/bug: Inline the UD1
  x86/bug: Implement WARN_ONCE()
  x86_64/bug: Implement __WARN_printf()
  x86/bug: Use BUG_FORMAT for DEBUG_BUGVERBOSE_DETAILED
  x86/bug: Add BUG_FORMAT basics
  bug: Allow architectures to provide __WARN_printf()
  bug: Implement WARN_ON() using __WARN_FLAGS()
  bug: Add report_bug_entry()
  bug: Add BUG_FORMAT_ARGS infrastructure
  bug: Clean up CONFIG_GENERIC_BUG_RELATIVE_POINTERS
  bug: Add BUG_FORMAT infrastructure
  x86: Rework __bug_table helpers
  bugs/s390: Remove private WARN_ON() implementation
  bugs/core: Reorganize fields in the first line of WARNING output, add ->comm[] output
  bugs/sh: Concatenate 'cond_str' with '__FILE__' in __WARN_FLAGS(), to extend WARN_ON/BUG_ON output
  bugs/parisc: Concatenate 'cond_str' with '__FILE__' in __WARN_FLAGS(), to extend WARN_ON/BUG_ON output
  bugs/riscv: Concatenate 'cond_str' with '__FILE__' in __BUG_FLAGS(), to extend WARN_ON/BUG_ON output
  bugs/riscv: Pass in 'cond_str' to __BUG_FLAGS()
  ...
This commit is contained in:
Linus Torvalds
2025-12-01 21:33:01 -08:00
17 changed files with 480 additions and 181 deletions

View File

@@ -206,6 +206,16 @@ config DEBUG_BUGVERBOSE
of the BUG call as well as the EIP and oops trace. This aids
debugging but costs about 70-100K of memory.
config DEBUG_BUGVERBOSE_DETAILED
bool "Verbose WARN_ON_ONCE() reporting (adds 100K)" if DEBUG_BUGVERBOSE
help
Say Y here to make WARN_ON_ONCE() output the condition string of the
warning, in addition to the file name and line number.
This helps debugging, but costs about 100K of memory.
Say N if unsure.
endmenu # "printk and dmesg options"
config DEBUG_KERNEL

View File

@@ -139,6 +139,29 @@ void bug_get_file_line(struct bug_entry *bug, const char **file,
#endif
}
static const char *bug_get_format(struct bug_entry *bug)
{
const char *format = NULL;
#ifdef HAVE_ARCH_BUG_FORMAT
#ifdef CONFIG_GENERIC_BUG_RELATIVE_POINTERS
/*
* Allow an architecture to:
* - relative encode NULL (difficult vs KASLR);
* - use a literal 0 (there are no valid objects inside
* the __bug_table itself to refer to after all);
* - use an empty string.
*/
if (bug->format_disp)
format = (const char *)&bug->format_disp + bug->format_disp;
if (format && format[0] == '\0')
format = NULL;
#else
format = bug->format;
#endif
#endif
return format;
}
struct bug_entry *find_bug(unsigned long bugaddr)
{
struct bug_entry *bug;
@@ -150,26 +173,51 @@ struct bug_entry *find_bug(unsigned long bugaddr)
return module_find_bug(bugaddr);
}
static enum bug_trap_type __report_bug(unsigned long bugaddr, struct pt_regs *regs)
static void __warn_printf(const char *fmt, struct pt_regs *regs)
{
struct bug_entry *bug;
const char *file;
unsigned line, warning, once, done;
if (!fmt)
return;
if (!is_valid_bugaddr(bugaddr))
return BUG_TRAP_TYPE_NONE;
#ifdef HAVE_ARCH_BUG_FORMAT_ARGS
if (regs) {
struct arch_va_list _args;
va_list *args = __warn_args(&_args, regs);
bug = find_bug(bugaddr);
if (!bug)
return BUG_TRAP_TYPE_NONE;
if (args) {
vprintk(fmt, *args);
return;
}
}
#endif
printk("%s", fmt);
}
static enum bug_trap_type __report_bug(struct bug_entry *bug, unsigned long bugaddr, struct pt_regs *regs)
{
bool warning, once, done, no_cut, has_args;
const char *file, *fmt;
unsigned line;
if (!bug) {
if (!is_valid_bugaddr(bugaddr))
return BUG_TRAP_TYPE_NONE;
bug = find_bug(bugaddr);
if (!bug)
return BUG_TRAP_TYPE_NONE;
}
disable_trace_on_warning();
bug_get_file_line(bug, &file, &line);
fmt = bug_get_format(bug);
warning = (bug->flags & BUGFLAG_WARNING) != 0;
once = (bug->flags & BUGFLAG_ONCE) != 0;
done = (bug->flags & BUGFLAG_DONE) != 0;
warning = bug->flags & BUGFLAG_WARNING;
once = bug->flags & BUGFLAG_ONCE;
done = bug->flags & BUGFLAG_DONE;
no_cut = bug->flags & BUGFLAG_NO_CUT_HERE;
has_args = bug->flags & BUGFLAG_ARGS;
if (warning && once) {
if (done)
@@ -187,8 +235,10 @@ static enum bug_trap_type __report_bug(unsigned long bugaddr, struct pt_regs *re
* "cut here" line now. WARN() issues its own "cut here" before the
* extra debugging message it writes before triggering the handler.
*/
if ((bug->flags & BUGFLAG_NO_CUT_HERE) == 0)
if (!no_cut) {
printk(KERN_DEFAULT CUT_HERE);
__warn_printf(fmt, has_args ? regs : NULL);
}
if (warning) {
/* this is a WARN_ON rather than BUG/BUG_ON */
@@ -206,13 +256,25 @@ static enum bug_trap_type __report_bug(unsigned long bugaddr, struct pt_regs *re
return BUG_TRAP_TYPE_BUG;
}
enum bug_trap_type report_bug_entry(struct bug_entry *bug, struct pt_regs *regs)
{
enum bug_trap_type ret;
bool rcu = false;
rcu = warn_rcu_enter();
ret = __report_bug(bug, 0, regs);
warn_rcu_exit(rcu);
return ret;
}
enum bug_trap_type report_bug(unsigned long bugaddr, struct pt_regs *regs)
{
enum bug_trap_type ret;
bool rcu = false;
rcu = warn_rcu_enter();
ret = __report_bug(bugaddr, regs);
ret = __report_bug(NULL, bugaddr, regs);
warn_rcu_exit(rcu);
return ret;