diff --git a/arch/sparc64/kernel/module.c b/arch/sparc64/kernel/module.c
--- a/arch/sparc64/kernel/module.c
+++ b/arch/sparc64/kernel/module.c
@@ -187,10 +187,15 @@ int apply_relocate_add(Elf64_Shdr *sechd
 	return 0;
 }
 
+static LIST_HEAD(module_bug_list);
+
 int module_finalize(const Elf_Ehdr *hdr,
 		    const Elf_Shdr *sechdrs,
 		    struct module *me)
 {
+	char *secstrings;
+	unsigned int i;
+
 	/* Cheetah's I-cache is fully coherent.  */
 	if (tlb_type == spitfire) {
 		unsigned long va;
@@ -201,9 +206,46 @@ int module_finalize(const Elf_Ehdr *hdr,
 		__asm__ __volatile__("flush %g6");
 	}
 
+	/* Find the __bug_table section, if present */
+	secstrings = (char *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+	for (i = 1; i < hdr->e_shnum; i++) {
+		if (strcmp(secstrings+sechdrs[i].sh_name, "__bug_table"))
+			continue;
+		me->arch.bug_table = (void *) sechdrs[i].sh_addr;
+		me->arch.num_bugs =
+			(sechdrs[i].sh_size / sizeof(struct bug_entry));
+		break;
+	}
+
+	/*
+	 * 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);
+
 	return 0;
 }
 
 void module_arch_cleanup(struct module *mod)
 {
+	list_del(&mod->arch.bug_list);
+}
+
+struct bug_entry *module_find_bug(unsigned long pc)
+{
+	struct mod_arch_specific *mod;
+
+	list_for_each_entry(mod, &module_bug_list, bug_list) {
+		struct bug_entry *bug = mod->bug_table;
+		unsigned int i;
+
+		for (i = 0; i < mod->num_bugs; ++i, ++bug) {
+			unsigned long entry_addr = bug->bug_addr;
+
+			if (entry_addr == pc)
+				return bug;
+		}
+	}
+	return NULL;
 }
diff --git a/arch/sparc64/kernel/sparc64_ksyms.c b/arch/sparc64/kernel/sparc64_ksyms.c
--- a/arch/sparc64/kernel/sparc64_ksyms.c
+++ b/arch/sparc64/kernel/sparc64_ksyms.c
@@ -388,10 +388,6 @@ EXPORT_SYMBOL(sun_do_break);
 EXPORT_SYMBOL(serial_console);
 EXPORT_SYMBOL(stop_a_enabled);
 
-#ifdef CONFIG_DEBUG_BUGVERBOSE
-EXPORT_SYMBOL(do_BUG);
-#endif
-
 /* for ns8703 */
 EXPORT_SYMBOL(ns87303_lock);
 
diff --git a/arch/sparc64/kernel/traps.c b/arch/sparc64/kernel/traps.c
--- a/arch/sparc64/kernel/traps.c
+++ b/arch/sparc64/kernel/traps.c
@@ -86,9 +86,64 @@ static void dump_tl1_traplog(struct tl1_
 	}
 }
 
-void do_call_debug(struct pt_regs *regs) 
-{ 
-	notify_die(DIE_CALL, "debug call", regs, 0, 255, SIGINT); 
+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 pc)
+{
+	struct bug_entry *bug;
+
+	for (bug = __start___bug_table; bug < __stop___bug_table; ++bug) {
+		unsigned long entry_addr = bug->bug_addr;
+		if (entry_addr == pc)
+			return bug;
+	}
+	return module_find_bug(pc);
+}
+
+void kernel_bug_trap(struct pt_regs *regs)
+{
+	struct bug_entry *bug;
+	unsigned long addr;
+
+	if (!(regs->tstate & TSTATE_PRIV)) {
+		siginfo_t info;
+
+		if (test_thread_flag(TIF_32BIT)) {
+			regs->tpc &= 0xffffffff;
+			regs->tnpc &= 0xffffffff;
+		}
+		info.si_signo = SIGILL;
+		info.si_errno = 0;
+		info.si_code = ILL_ILLTRP;
+		info.si_addr = (void __user *)regs->tpc;
+		info.si_trapno = 5;
+		force_sig_info(SIGILL, &info, current);
+		return;
+	}
+	addr = regs->tpc;
+	bug = find_bug(addr);
+	if (likely(bug)) {
+		const char *func = (const char *) (long) bug->function;
+		const char *file = (const char *) (long) bug->file;
+		int line = bug->line & ~BUG_WARNING_TRAP;
+
+		if (bug->line & BUG_WARNING_TRAP) {
+			/* this is a WARN_ON rather than BUG/BUG_ON */
+			printk(KERN_ERR "Badness in %s at %s:%d\n",
+			       func, file, line);
+			dump_stack();
+		} else {
+			printk(KERN_CRIT "kernel BUG in %s at %s:%d!\n",
+			       func, file, line);
+			die_if_kernel("kernel BUG", regs);
+		}
+	}
+	regs->tpc = regs->tnpc;
+	regs->tnpc += 4;
 }
 
 void bad_trap(struct pt_regs *regs, long lvl)
@@ -136,14 +191,6 @@ void bad_trap_tl1(struct pt_regs *regs, 
 	die_if_kernel (buffer, regs);
 }
 
-#ifdef CONFIG_DEBUG_BUGVERBOSE
-void do_BUG(const char *file, int line)
-{
-	bust_spinlocks(1);
-	printk("kernel BUG at %s:%d!\n", file, line);
-}
-#endif
-
 void spitfire_insn_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar)
 {
 	siginfo_t info;
diff --git a/arch/sparc64/kernel/ttable.S b/arch/sparc64/kernel/ttable.S
--- a/arch/sparc64/kernel/ttable.S
+++ b/arch/sparc64/kernel/ttable.S
@@ -125,7 +125,9 @@ tl0_sunos:	SUNOS_SYSCALL_TRAP
 tl0_bkpt:	BREAKPOINT_TRAP
 tl0_divz:	TRAP(do_div0)
 tl0_flushw:	FLUSH_WINDOW_TRAP
-tl0_resv104:	BTRAP(0x104) BTRAP(0x105) BTRAP(0x106) BTRAP(0x107)
+tl0_resv104:	BTRAP(0x104)
+tl0_kbug:	TRAP(kernel_bug_trap)
+tl0_resv106:	BTRAP(0x106) BTRAP(0x107)
 		.globl tl0_solaris
 tl0_solaris:	SOLARIS_SYSCALL_TRAP
 tl0_netbsd:	NETBSD_SYSCALL_TRAP
diff --git a/arch/sparc64/kernel/us2e_cpufreq.c b/arch/sparc64/kernel/us2e_cpufreq.c
--- a/arch/sparc64/kernel/us2e_cpufreq.c
+++ b/arch/sparc64/kernel/us2e_cpufreq.c
@@ -223,6 +223,7 @@ static unsigned long estar_to_divisor(un
 		ret = 8;
 		break;
 	default:
+		ret = 0;
 		BUG();
 	};
 
diff --git a/arch/sparc64/kernel/us3_cpufreq.c b/arch/sparc64/kernel/us3_cpufreq.c
--- a/arch/sparc64/kernel/us3_cpufreq.c
+++ b/arch/sparc64/kernel/us3_cpufreq.c
@@ -70,6 +70,7 @@ static unsigned long get_current_freq(un
 		ret = clock_tick / 32;
 		break;
 	default:
+		ret = 0;
 		BUG();
 	};
 
@@ -124,6 +125,7 @@ static void us3_set_cpu_divider_index(un
 		break;
 
 	default:
+		new_bits = 0;
 		BUG();
 	};
 
diff --git a/include/asm-sparc64/bug.h b/include/asm-sparc64/bug.h
--- a/include/asm-sparc64/bug.h
+++ b/include/asm-sparc64/bug.h
@@ -1,22 +1,85 @@
 #ifndef _SPARC64_BUG_H
 #define _SPARC64_BUG_H
 
+#include <linux/config.h>
+
+/* All kernel image and module addresses are in the lower
+ * 32-bits of the address space, so we can save a lot of
+ * space in the bug table by using 32-bit words to store
+ * the pointers.
+ */
+struct bug_entry {
+	unsigned int	bug_addr;
+	int		line;
+	unsigned int	file;
+	unsigned int	function;
+};
+
+extern struct bug_entry *find_bug(unsigned long);
+
+/*
+ * 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
-#include <linux/compiler.h>
 
-#ifdef CONFIG_DEBUG_BUGVERBOSE
-extern void do_BUG(const char *file, int line);
-#define BUG() do {					\
-	do_BUG(__FILE__, __LINE__);			\
-	__builtin_trap();				\
+/* We used to use the __builtin_trap() facility of the compiler,
+ * and while that generates the most straightforward sequence of
+ * code, it wastes a lot of instructions loading the various string
+ * pointers and such.
+ *
+ * But frankly, this 2 instruction sequence is not so bad and is
+ * equal to the optimal case most of the time.  We could get optimal
+ * code generation if GCC provided a way to specify a condition code
+ * setting as an input, in fact such a feature would be very useful
+ * in many other situations as well.
+ */
+
+#define BUG() do {							\
+	__asm__ __volatile__(						\
+		"\n1:\tta\t%%xcc, 0x5\t! BUG()\n\t"		 	\
+		".section\t__bug_table,\"a\"\n\t"			\
+		".word\t1b,%0,%1,%2\n\t"				\
+		".previous"						\
+		: /* no outputs */					\
+		: "i" (__LINE__), "i" (__FILE__), "i" (__FUNCTION__));	\
+} while (0)
+
+#define BUG_ON(x) do {						\
+	__asm__ __volatile__(					\
+		"cmp\t%0, 0\n"					\
+		"1:\ttne\t%%xcc, 0x5\t! BUG_ON()\n\t"		\
+		".section\t__bug_table,\"a\"\n\t"		\
+		".word\t1b,%1,%2,%3\n\t"			\
+		".previous"					\
+		: /* no outputs */				\
+		: "r" ((long)(x)), "i" (__LINE__),		\
+		  "i" (__FILE__), "i" (__FUNCTION__)		\
+		: "cc");					\
+} while (0)
+
+#define WARN_ON(x) do {						\
+	__asm__ __volatile__(					\
+		"cmp\t%0, 0\n"					\
+		"1:\ttne\t%%xcc, 0x5\t! WARN_ON()\n\t"		\
+		".section\t__bug_table,\"a\"\n\t"		\
+		".word\t1b,%1,%2,%3\n\t"			\
+		".previous"					\
+		: /* no outputs */				\
+		: "r" ((long)(x)),				\
+		  "i" (__LINE__ + BUG_WARNING_TRAP),		\
+		  "i" (__FILE__), "i" (__FUNCTION__)		\
+		: "cc");					\
 } while (0)
-#else
-#define BUG()		__builtin_trap()
-#endif
 
 #define HAVE_ARCH_BUG
-#endif
+#define HAVE_ARCH_BUG_ON
+#define HAVE_ARCH_WARN_ON
+
+#endif /* !(CONFIG_BUG) */
 
 #include <asm-generic/bug.h>
 
-#endif
+#endif /* !(_SPARC64_BUG_H) */
diff --git a/include/asm-sparc64/module.h b/include/asm-sparc64/module.h
--- a/include/asm-sparc64/module.h
+++ b/include/asm-sparc64/module.h
@@ -1,7 +1,19 @@
 #ifndef _ASM_SPARC64_MODULE_H
 #define _ASM_SPARC64_MODULE_H
-struct mod_arch_specific { };
+
+#include <linux/list.h>
+#include <asm/bug.h>
+
+struct mod_arch_specific {
+	struct list_head	bug_list;
+	struct bug_entry	*bug_table;
+	unsigned int		num_bugs;
+};
+
+extern struct bug_entry *module_find_bug(unsigned long);
+
 #define Elf_Shdr Elf64_Shdr
 #define Elf_Sym Elf64_Sym
 #define Elf_Ehdr Elf64_Ehdr
+
 #endif /* _ASM_SPARC64_MODULE_H */
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -109,7 +109,7 @@ config DEBUG_HIGHMEM
 config DEBUG_BUGVERBOSE
 	bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EMBEDDED
 	depends on BUG
-	depends on ARM || ARM26 || M32R || M68K || SPARC32 || SPARC64 || (X86 && !X86_64) || FRV
+	depends on ARM || ARM26 || M32R || M68K || SPARC32 || (X86 && !X86_64) || FRV
 	default !EMBEDDED
 	help
 	  Say Y here to make BUG() panics output the file name and line number
