summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/Kconfig5
-rw-r--r--arch/powerpc/kernel/module_32.c23
-rw-r--r--arch/powerpc/kernel/module_64.c23
-rw-r--r--arch/powerpc/kernel/traps.c54
-rw-r--r--arch/powerpc/kernel/vmlinux.lds.S6
-rw-r--r--arch/powerpc/xmon/xmon.c10
-rw-r--r--include/asm-powerpc/bug.h80
-rw-r--r--include/asm-powerpc/module.h2
8 files changed, 69 insertions, 134 deletions
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig
index a35212b7346e..f81d9f6f19f6 100644
--- a/arch/powerpc/Kconfig
+++ b/arch/powerpc/Kconfig
@@ -99,6 +99,11 @@ config AUDIT_ARCH
 	bool
 	default y
 
+config GENERIC_BUG
+	bool
+	default y
+	depends on BUG
+
 config DEFAULT_UIMAGE
 	bool
 	help
diff --git a/arch/powerpc/kernel/module_32.c b/arch/powerpc/kernel/module_32.c
index e2c3c6a85f33..8339fd609de0 100644
--- a/arch/powerpc/kernel/module_32.c
+++ b/arch/powerpc/kernel/module_32.c
@@ -23,6 +23,7 @@
 #include <linux/string.h>
 #include <linux/kernel.h>
 #include <linux/cache.h>
+#include <linux/bug.h>
 
 #include "setup.h"
 
@@ -290,23 +291,11 @@ int module_finalize(const Elf_Ehdr *hdr,
 		    struct module *me)
 {
 	const Elf_Shdr *sect;
+	int err;
 
-	me->arch.bug_table = NULL;
-	me->arch.num_bugs = 0;
-
-	/* Find the __bug_table section, if present */
-	sect = find_section(hdr, sechdrs, "__bug_table");
-	if (sect != NULL) {
-		me->arch.bug_table = (void *) sect->sh_addr;
-		me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry);
-	}
-
- 	/*
-	 * Strictly speaking this should have a spinlock to protect against
-	 * traversals, but since we only traverse on BUG()s, a spinlock
-	 * could potentially lead to deadlock and thus be counter-productive.
-	 */
-	list_add(&me->arch.bug_list, &module_bug_list);
+	err = module_bug_finalize(hdr, sechdrs, me);
+	if (err)		/* never true, currently */
+		return err;
 
 	/* Apply feature fixups */
 	sect = find_section(hdr, sechdrs, "__ftr_fixup");
@@ -320,7 +309,7 @@ int module_finalize(const Elf_Ehdr *hdr,
 
 void module_arch_cleanup(struct module *mod)
 {
-	list_del(&mod->arch.bug_list);
+	module_bug_cleanup(mod);
 }
 
 struct bug_entry *module_find_bug(unsigned long bugaddr)
diff --git a/arch/powerpc/kernel/module_64.c b/arch/powerpc/kernel/module_64.c
index 8dd1f0aae5d6..75c7c4f19280 100644
--- a/arch/powerpc/kernel/module_64.c
+++ b/arch/powerpc/kernel/module_64.c
@@ -20,6 +20,7 @@
 #include <linux/moduleloader.h>
 #include <linux/err.h>
 #include <linux/vmalloc.h>
+#include <linux/bug.h>
 #include <asm/module.h>
 #include <asm/uaccess.h>
 #include <asm/firmware.h>
@@ -439,23 +440,11 @@ int module_finalize(const Elf_Ehdr *hdr,
 		const Elf_Shdr *sechdrs, struct module *me)
 {
 	const Elf_Shdr *sect;
+	int err;
 
-	me->arch.bug_table = NULL;
-	me->arch.num_bugs = 0;
-
-	/* Find the __bug_table section, if present */
-	sect = find_section(hdr, sechdrs, "__bug_table");
-	if (sect != NULL) {
-		me->arch.bug_table = (void *) sect->sh_addr;
-		me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry);
-	}
-
-	/*
-	 * Strictly speaking this should have a spinlock to protect against
-	 * traversals, but since we only traverse on BUG()s, a spinlock
-	 * could potentially lead to deadlock and thus be counter-productive.
-	 */
-	list_add(&me->arch.bug_list, &module_bug_list);
+	err = module_bug_finalize(hdr, sechdrs, me);
+	if (err)
+		return err;
 
 	/* Apply feature fixups */
 	sect = find_section(hdr, sechdrs, "__ftr_fixup");
@@ -475,7 +464,7 @@ int module_finalize(const Elf_Ehdr *hdr,
 
 void module_arch_cleanup(struct module *mod)
 {
-	list_del(&mod->arch.bug_list);
+	module_bug_cleanup(mod);
 }
 
 struct bug_entry *module_find_bug(unsigned long bugaddr)
diff --git a/arch/powerpc/kernel/traps.c b/arch/powerpc/kernel/traps.c
index fde820e52d03..535f50665647 100644
--- a/arch/powerpc/kernel/traps.c
+++ b/arch/powerpc/kernel/traps.c
@@ -32,6 +32,7 @@
 #include <linux/kprobes.h>
 #include <linux/kexec.h>
 #include <linux/backlight.h>
+#include <linux/bug.h>
 
 #include <asm/kdebug.h>
 #include <asm/pgtable.h>
@@ -727,54 +728,9 @@ static int emulate_instruction(struct pt_regs *regs)
 	return -EINVAL;
 }
 
-/*
- * Look through the list of trap instructions that are used for BUG(),
- * BUG_ON() and WARN_ON() and see if we hit one.  At this point we know
- * that the exception was caused by a trap instruction of some kind.
- * Returns 1 if we should continue (i.e. it was a WARN_ON) or 0
- * otherwise.
- */
-extern struct bug_entry __start___bug_table[], __stop___bug_table[];
-
-#ifndef CONFIG_MODULES
-#define module_find_bug(x)	NULL
-#endif
-
-struct bug_entry *find_bug(unsigned long bugaddr)
+int is_valid_bugaddr(unsigned long addr)
 {
-	struct bug_entry *bug;
-
-	for (bug = __start___bug_table; bug < __stop___bug_table; ++bug)
-		if (bugaddr == bug->bug_addr)
-			return bug;
-	return module_find_bug(bugaddr);
-}
-
-static int check_bug_trap(struct pt_regs *regs)
-{
-	struct bug_entry *bug;
-	unsigned long addr;
-
-	if (regs->msr & MSR_PR)
-		return 0;	/* not in kernel */
-	addr = regs->nip;	/* address of trap instruction */
-	if (addr < PAGE_OFFSET)
-		return 0;
-	bug = find_bug(regs->nip);
-	if (bug == NULL)
-		return 0;
-	if (bug->line & BUG_WARNING_TRAP) {
-		/* this is a WARN_ON rather than BUG/BUG_ON */
-		printk(KERN_ERR "Badness in %s at %s:%ld\n",
-		       bug->function, bug->file,
-		       bug->line & ~BUG_WARNING_TRAP);
-		dump_stack();
-		return 1;
-	}
-	printk(KERN_CRIT "kernel BUG in %s at %s:%ld!\n",
-	       bug->function, bug->file, bug->line);
-
-	return 0;
+	return is_kernel_addr(addr);
 }
 
 void __kprobes program_check_exception(struct pt_regs *regs)
@@ -810,7 +766,9 @@ void __kprobes program_check_exception(struct pt_regs *regs)
 			return;
 		if (debugger_bpt(regs))
 			return;
-		if (check_bug_trap(regs)) {
+
+		if (!(regs->msr & MSR_PR) &&  /* not user-mode */
+		    report_bug(regs->nip) == BUG_TRAP_TYPE_WARN) {
 			regs->nip += 4;
 			return;
 		}
diff --git a/arch/powerpc/kernel/vmlinux.lds.S b/arch/powerpc/kernel/vmlinux.lds.S
index 04b98671a060..04b8e71bf5b0 100644
--- a/arch/powerpc/kernel/vmlinux.lds.S
+++ b/arch/powerpc/kernel/vmlinux.lds.S
@@ -62,11 +62,7 @@ SECTIONS
 		__stop___ex_table = .;
 	}
 
-	__bug_table : {
-		__start___bug_table = .;
-		*(__bug_table)
-		__stop___bug_table = .;
-	}
+	BUG_TABLE
 
 /*
  * Init sections discarded at runtime
diff --git a/arch/powerpc/xmon/xmon.c b/arch/powerpc/xmon/xmon.c
index a34ed49e0356..77540a2f7704 100644
--- a/arch/powerpc/xmon/xmon.c
+++ b/arch/powerpc/xmon/xmon.c
@@ -22,6 +22,7 @@
 #include <linux/sysrq.h>
 #include <linux/interrupt.h>
 #include <linux/irq.h>
+#include <linux/bug.h>
 
 #include <asm/ptrace.h>
 #include <asm/string.h>
@@ -35,7 +36,6 @@
 #include <asm/cputable.h>
 #include <asm/rtas.h>
 #include <asm/sstep.h>
-#include <asm/bug.h>
 #include <asm/irq_regs.h>
 #include <asm/spu.h>
 #include <asm/spu_priv1.h>
@@ -1346,7 +1346,7 @@ static void backtrace(struct pt_regs *excp)
 
 static void print_bug_trap(struct pt_regs *regs)
 {
-	struct bug_entry *bug;
+	const struct bug_entry *bug;
 	unsigned long addr;
 
 	if (regs->msr & MSR_PR)
@@ -1357,11 +1357,11 @@ static void print_bug_trap(struct pt_regs *regs)
 	bug = find_bug(regs->nip);
 	if (bug == NULL)
 		return;
-	if (bug->line & BUG_WARNING_TRAP)
+	if (is_warning_bug(bug))
 		return;
 
-	printf("kernel BUG in %s at %s:%d!\n",
-	       bug->function, bug->file, (unsigned int)bug->line);
+	printf("kernel BUG at %s:%u!\n",
+	       bug->file, bug->line);
 }
 
 void excprint(struct pt_regs *fp)
diff --git a/include/asm-powerpc/bug.h b/include/asm-powerpc/bug.h
index 978b2c7e84ea..709568879f73 100644
--- a/include/asm-powerpc/bug.h
+++ b/include/asm-powerpc/bug.h
@@ -13,36 +13,39 @@
 
 #ifndef __ASSEMBLY__
 
-struct bug_entry {
-	unsigned long	bug_addr;
-	long		line;
-	const char	*file;
-	const char	*function;
-};
-
-struct bug_entry *find_bug(unsigned long bugaddr);
-
-/*
- * If this bit is set in the line number it means that the trap
- * is for WARN_ON rather than BUG or BUG_ON.
- */
-#define BUG_WARNING_TRAP	0x1000000
-
 #ifdef CONFIG_BUG
 
+/* _EMIT_BUG_ENTRY expects args %0,%1,%2,%3 to be FILE, LINE, flags and
+   sizeof(struct bug_entry), respectively */
+#ifdef CONFIG_DEBUG_BUGVERBOSE
+#define _EMIT_BUG_ENTRY				\
+	".section __bug_table,\"a\"\n"		\
+	"2:\t" PPC_LONG "1b, %0\n"		\
+	"\t.short %1, %2\n"			\
+	".org 2b+%3\n"				\
+	".previous\n"
+#else
+#define _EMIT_BUG_ENTRY				\
+	".section __bug_table,\"a\"\n"		\
+	"2:\t" PPC_LONG "1b\n"			\
+	"\t.short %2\n"				\
+	".org 2b+%3\n"				\
+	".previous\n"
+#endif
+
 /*
  * BUG_ON() and WARN_ON() do their best to cooperate with compile-time
  * optimisations. However depending on the complexity of the condition
  * some compiler versions may not produce optimal results.
  */
 
-#define BUG() do {							 \
-	__asm__ __volatile__(						 \
-		"1:	twi 31,0,0\n"					 \
-		".section __bug_table,\"a\"\n"				 \
-		"\t"PPC_LONG"	1b,%0,%1,%2\n"				 \
-		".previous"						 \
-		: : "i" (__LINE__), "i" (__FILE__), "i" (__FUNCTION__)); \
+#define BUG() do {						\
+	__asm__ __volatile__(					\
+		"1:	twi 31,0,0\n"				\
+		_EMIT_BUG_ENTRY					\
+		: : "i" (__FILE__), "i" (__LINE__),		\
+		    "i" (0), "i"  (sizeof(struct bug_entry)));	\
+	for(;;) ;						\
 } while (0)
 
 #define BUG_ON(x) do {						\
@@ -51,23 +54,21 @@ struct bug_entry *find_bug(unsigned long bugaddr);
 			BUG();					\
 	} else {						\
 		__asm__ __volatile__(				\
-		"1:	"PPC_TLNEI"	%0,0\n"			\
-		".section __bug_table,\"a\"\n"			\
-		"\t"PPC_LONG"	1b,%1,%2,%3\n"			\
-		".previous"					\
-		: : "r" ((long)(x)), "i" (__LINE__),		\
-		    "i" (__FILE__), "i" (__FUNCTION__));	\
+		"1:	"PPC_TLNEI"	%4,0\n"			\
+		_EMIT_BUG_ENTRY					\
+		: : "i" (__FILE__), "i" (__LINE__), "i" (0),	\
+		  "i" (sizeof(struct bug_entry)),		\
+		  "r" ((long)(x)));				\
 	}							\
 } while (0)
 
 #define __WARN() do {						\
 	__asm__ __volatile__(					\
 		"1:	twi 31,0,0\n"				\
-		".section __bug_table,\"a\"\n"			\
-		"\t"PPC_LONG"	1b,%0,%1,%2\n"			\
-		".previous"					\
-		: : "i" (__LINE__ + BUG_WARNING_TRAP),		\
-		    "i" (__FILE__), "i" (__FUNCTION__));	\
+		_EMIT_BUG_ENTRY					\
+		: : "i" (__FILE__), "i" (__LINE__),		\
+		  "i" (BUGFLAG_WARNING),			\
+		  "i" (sizeof(struct bug_entry)));		\
 } while (0)
 
 #define WARN_ON(x) ({						\
@@ -77,13 +78,12 @@ struct bug_entry *find_bug(unsigned long bugaddr);
 			__WARN();				\
 	} else {						\
 		__asm__ __volatile__(				\
-		"1:	"PPC_TLNEI"	%0,0\n"			\
-		".section __bug_table,\"a\"\n"			\
-		"\t"PPC_LONG"	1b,%1,%2,%3\n"			\
-		".previous"					\
-		: : "r" (__ret_warn_on),			\
-		    "i" (__LINE__ + BUG_WARNING_TRAP),		\
-		    "i" (__FILE__), "i" (__FUNCTION__));	\
+		"1:	"PPC_TLNEI"	%4,0\n"			\
+		_EMIT_BUG_ENTRY					\
+		: : "i" (__FILE__), "i" (__LINE__),		\
+		  "i" (BUGFLAG_WARNING),			\
+		  "i" (sizeof(struct bug_entry)),		\
+		  "r" (__ret_warn_on));				\
 	}							\
 	unlikely(__ret_warn_on);				\
 })
diff --git a/include/asm-powerpc/module.h b/include/asm-powerpc/module.h
index 584fabfb4f08..e5f14b13ccf0 100644
--- a/include/asm-powerpc/module.h
+++ b/include/asm-powerpc/module.h
@@ -46,8 +46,6 @@ struct mod_arch_specific {
 	unsigned int num_bugs;
 };
 
-extern struct bug_entry *module_find_bug(unsigned long bugaddr);
-
 /*
  * Select ELF headers.
  * Make empty section for module_frob_arch_sections to expand.