mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-12-27 10:01:39 -05:00
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:
@@ -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
|
||||
|
||||
90
lib/bug.c
90
lib/bug.c
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user