Files
android_kernel_xiaomi_sm8450/arch/sh/include/asm/bug.h
Josh Poimboeuf 325cdacd03 debug: Fix WARN_ON_ONCE() for modules
Mike Galbraith reported a situation where a WARN_ON_ONCE() call in DRM
code turned into an oops.  As it turns out, WARN_ON_ONCE() seems to be
completely broken when called from a module.

The bug was introduced with the following commit:

  19d436268d ("debug: Add _ONCE() logic to report_bug()")

That commit changed WARN_ON_ONCE() to move its 'once' logic into the bug
trap handler.  It requires a writable bug table so that the BUGFLAG_DONE
bit can be written to the flags to indicate the first warning has
occurred.

The bug table was made writable for vmlinux, which relies on
vmlinux.lds.S and vmlinux.lds.h for laying out the sections.  However,
it wasn't made writable for modules, which rely on the ELF section
header flags.

Reported-by: Mike Galbraith <efault@gmx.de>
Tested-by: Masami Hiramatsu <mhiramat@kernel.org>
Signed-off-by: Josh Poimboeuf <jpoimboe@redhat.com>
Acked-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Cc: Linus Torvalds <torvalds@linux-foundation.org>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Thomas Gleixner <tglx@linutronix.de>
Fixes: 19d436268d ("debug: Add _ONCE() logic to report_bug()")
Link: http://lkml.kernel.org/r/a53b04235a65478dd9afc51f5b329fdc65c84364.1500095401.git.jpoimboe@redhat.com
Signed-off-by: Ingo Molnar <mingo@kernel.org>
2017-07-20 12:31:04 +02:00

120 lines
2.7 KiB
C

#ifndef __ASM_SH_BUG_H
#define __ASM_SH_BUG_H
#include <linux/linkage.h>
#define TRAPA_BUG_OPCODE 0xc33e /* trapa #0x3e */
#define BUGFLAG_UNWINDER (1 << 1)
#ifdef CONFIG_GENERIC_BUG
#define HAVE_ARCH_BUG
#define HAVE_ARCH_WARN_ON
/**
* _EMIT_BUG_ENTRY
* %1 - __FILE__
* %2 - __LINE__
* %3 - trap type
* %4 - sizeof(struct bug_entry)
*
* The trapa opcode itself sits in %0.
* The %O notation is used to avoid # generation.
*
* The offending file and line are encoded in the __bug_table section.
*/
#ifdef CONFIG_DEBUG_BUGVERBOSE
#define _EMIT_BUG_ENTRY \
"\t.pushsection __bug_table,\"aw\"\n" \
"2:\t.long 1b, %O1\n" \
"\t.short %O2, %O3\n" \
"\t.org 2b+%O4\n" \
"\t.popsection\n"
#else
#define _EMIT_BUG_ENTRY \
"\t.pushsection __bug_table,\"aw\"\n" \
"2:\t.long 1b\n" \
"\t.short %O3\n" \
"\t.org 2b+%O4\n" \
"\t.popsection\n"
#endif
#define BUG() \
do { \
__asm__ __volatile__ ( \
"1:\t.short %O0\n" \
_EMIT_BUG_ENTRY \
: \
: "n" (TRAPA_BUG_OPCODE), \
"i" (__FILE__), \
"i" (__LINE__), "i" (0), \
"i" (sizeof(struct bug_entry))); \
} while (0)
#define __WARN_FLAGS(flags) \
do { \
__asm__ __volatile__ ( \
"1:\t.short %O0\n" \
_EMIT_BUG_ENTRY \
: \
: "n" (TRAPA_BUG_OPCODE), \
"i" (__FILE__), \
"i" (__LINE__), \
"i" (BUGFLAG_WARNING|(flags)), \
"i" (sizeof(struct bug_entry))); \
} while (0)
#define WARN_ON(x) ({ \
int __ret_warn_on = !!(x); \
if (__builtin_constant_p(__ret_warn_on)) { \
if (__ret_warn_on) \
__WARN(); \
} else { \
if (unlikely(__ret_warn_on)) \
__WARN(); \
} \
unlikely(__ret_warn_on); \
})
#define UNWINDER_BUG() \
do { \
__asm__ __volatile__ ( \
"1:\t.short %O0\n" \
_EMIT_BUG_ENTRY \
: \
: "n" (TRAPA_BUG_OPCODE), \
"i" (__FILE__), \
"i" (__LINE__), \
"i" (BUGFLAG_UNWINDER), \
"i" (sizeof(struct bug_entry))); \
} while (0)
#define UNWINDER_BUG_ON(x) ({ \
int __ret_unwinder_on = !!(x); \
if (__builtin_constant_p(__ret_unwinder_on)) { \
if (__ret_unwinder_on) \
UNWINDER_BUG(); \
} else { \
if (unlikely(__ret_unwinder_on)) \
UNWINDER_BUG(); \
} \
unlikely(__ret_unwinder_on); \
})
#else
#define UNWINDER_BUG BUG
#define UNWINDER_BUG_ON BUG_ON
#endif /* CONFIG_GENERIC_BUG */
#include <asm-generic/bug.h>
struct pt_regs;
/* arch/sh/kernel/traps.c */
extern void die(const char *str, struct pt_regs *regs, long err) __attribute__ ((noreturn));
extern void die_if_kernel(const char *str, struct pt_regs *regs, long err);
extern void die_if_no_fixup(const char *str, struct pt_regs *regs, long err);
#endif /* __ASM_SH_BUG_H */