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 #include #include +#include #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 #include #include +#include #include #include #include @@ -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 #include #include +#include #include #include @@ -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 #include #include +#include #include #include @@ -35,7 +36,6 @@ #include #include #include -#include #include #include #include @@ -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.