diff options
-rw-r--r-- | arch/powerpc/Kconfig | 5 | ||||
-rw-r--r-- | arch/powerpc/kernel/module_32.c | 23 | ||||
-rw-r--r-- | arch/powerpc/kernel/module_64.c | 23 | ||||
-rw-r--r-- | arch/powerpc/kernel/traps.c | 54 | ||||
-rw-r--r-- | arch/powerpc/kernel/vmlinux.lds.S | 6 | ||||
-rw-r--r-- | arch/powerpc/xmon/xmon.c | 10 | ||||
-rw-r--r-- | include/asm-powerpc/bug.h | 80 | ||||
-rw-r--r-- | include/asm-powerpc/module.h | 2 |
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 | |||
99 | bool | 99 | bool |
100 | default y | 100 | default y |
101 | 101 | ||
102 | config GENERIC_BUG | ||
103 | bool | ||
104 | default y | ||
105 | depends on BUG | ||
106 | |||
102 | config DEFAULT_UIMAGE | 107 | config DEFAULT_UIMAGE |
103 | bool | 108 | bool |
104 | help | 109 | 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 @@ | |||
23 | #include <linux/string.h> | 23 | #include <linux/string.h> |
24 | #include <linux/kernel.h> | 24 | #include <linux/kernel.h> |
25 | #include <linux/cache.h> | 25 | #include <linux/cache.h> |
26 | #include <linux/bug.h> | ||
26 | 27 | ||
27 | #include "setup.h" | 28 | #include "setup.h" |
28 | 29 | ||
@@ -290,23 +291,11 @@ int module_finalize(const Elf_Ehdr *hdr, | |||
290 | struct module *me) | 291 | struct module *me) |
291 | { | 292 | { |
292 | const Elf_Shdr *sect; | 293 | const Elf_Shdr *sect; |
294 | int err; | ||
293 | 295 | ||
294 | me->arch.bug_table = NULL; | 296 | err = module_bug_finalize(hdr, sechdrs, me); |
295 | me->arch.num_bugs = 0; | 297 | if (err) /* never true, currently */ |
296 | 298 | return err; | |
297 | /* Find the __bug_table section, if present */ | ||
298 | sect = find_section(hdr, sechdrs, "__bug_table"); | ||
299 | if (sect != NULL) { | ||
300 | me->arch.bug_table = (void *) sect->sh_addr; | ||
301 | me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry); | ||
302 | } | ||
303 | |||
304 | /* | ||
305 | * Strictly speaking this should have a spinlock to protect against | ||
306 | * traversals, but since we only traverse on BUG()s, a spinlock | ||
307 | * could potentially lead to deadlock and thus be counter-productive. | ||
308 | */ | ||
309 | list_add(&me->arch.bug_list, &module_bug_list); | ||
310 | 299 | ||
311 | /* Apply feature fixups */ | 300 | /* Apply feature fixups */ |
312 | sect = find_section(hdr, sechdrs, "__ftr_fixup"); | 301 | sect = find_section(hdr, sechdrs, "__ftr_fixup"); |
@@ -320,7 +309,7 @@ int module_finalize(const Elf_Ehdr *hdr, | |||
320 | 309 | ||
321 | void module_arch_cleanup(struct module *mod) | 310 | void module_arch_cleanup(struct module *mod) |
322 | { | 311 | { |
323 | list_del(&mod->arch.bug_list); | 312 | module_bug_cleanup(mod); |
324 | } | 313 | } |
325 | 314 | ||
326 | struct bug_entry *module_find_bug(unsigned long bugaddr) | 315 | 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 @@ | |||
20 | #include <linux/moduleloader.h> | 20 | #include <linux/moduleloader.h> |
21 | #include <linux/err.h> | 21 | #include <linux/err.h> |
22 | #include <linux/vmalloc.h> | 22 | #include <linux/vmalloc.h> |
23 | #include <linux/bug.h> | ||
23 | #include <asm/module.h> | 24 | #include <asm/module.h> |
24 | #include <asm/uaccess.h> | 25 | #include <asm/uaccess.h> |
25 | #include <asm/firmware.h> | 26 | #include <asm/firmware.h> |
@@ -439,23 +440,11 @@ int module_finalize(const Elf_Ehdr *hdr, | |||
439 | const Elf_Shdr *sechdrs, struct module *me) | 440 | const Elf_Shdr *sechdrs, struct module *me) |
440 | { | 441 | { |
441 | const Elf_Shdr *sect; | 442 | const Elf_Shdr *sect; |
443 | int err; | ||
442 | 444 | ||
443 | me->arch.bug_table = NULL; | 445 | err = module_bug_finalize(hdr, sechdrs, me); |
444 | me->arch.num_bugs = 0; | 446 | if (err) |
445 | 447 | return err; | |
446 | /* Find the __bug_table section, if present */ | ||
447 | sect = find_section(hdr, sechdrs, "__bug_table"); | ||
448 | if (sect != NULL) { | ||
449 | me->arch.bug_table = (void *) sect->sh_addr; | ||
450 | me->arch.num_bugs = sect->sh_size / sizeof(struct bug_entry); | ||
451 | } | ||
452 | |||
453 | /* | ||
454 | * Strictly speaking this should have a spinlock to protect against | ||
455 | * traversals, but since we only traverse on BUG()s, a spinlock | ||
456 | * could potentially lead to deadlock and thus be counter-productive. | ||
457 | */ | ||
458 | list_add(&me->arch.bug_list, &module_bug_list); | ||
459 | 448 | ||
460 | /* Apply feature fixups */ | 449 | /* Apply feature fixups */ |
461 | sect = find_section(hdr, sechdrs, "__ftr_fixup"); | 450 | sect = find_section(hdr, sechdrs, "__ftr_fixup"); |
@@ -475,7 +464,7 @@ int module_finalize(const Elf_Ehdr *hdr, | |||
475 | 464 | ||
476 | void module_arch_cleanup(struct module *mod) | 465 | void module_arch_cleanup(struct module *mod) |
477 | { | 466 | { |
478 | list_del(&mod->arch.bug_list); | 467 | module_bug_cleanup(mod); |
479 | } | 468 | } |
480 | 469 | ||
481 | struct bug_entry *module_find_bug(unsigned long bugaddr) | 470 | 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 @@ | |||
32 | #include <linux/kprobes.h> | 32 | #include <linux/kprobes.h> |
33 | #include <linux/kexec.h> | 33 | #include <linux/kexec.h> |
34 | #include <linux/backlight.h> | 34 | #include <linux/backlight.h> |
35 | #include <linux/bug.h> | ||
35 | 36 | ||
36 | #include <asm/kdebug.h> | 37 | #include <asm/kdebug.h> |
37 | #include <asm/pgtable.h> | 38 | #include <asm/pgtable.h> |
@@ -727,54 +728,9 @@ static int emulate_instruction(struct pt_regs *regs) | |||
727 | return -EINVAL; | 728 | return -EINVAL; |
728 | } | 729 | } |
729 | 730 | ||
730 | /* | 731 | int is_valid_bugaddr(unsigned long addr) |
731 | * Look through the list of trap instructions that are used for BUG(), | ||
732 | * BUG_ON() and WARN_ON() and see if we hit one. At this point we know | ||
733 | * that the exception was caused by a trap instruction of some kind. | ||
734 | * Returns 1 if we should continue (i.e. it was a WARN_ON) or 0 | ||
735 | * otherwise. | ||
736 | */ | ||
737 | extern struct bug_entry __start___bug_table[], __stop___bug_table[]; | ||
738 | |||
739 | #ifndef CONFIG_MODULES | ||
740 | #define module_find_bug(x) NULL | ||
741 | #endif | ||
742 | |||
743 | struct bug_entry *find_bug(unsigned long bugaddr) | ||
744 | { | 732 | { |
745 | struct bug_entry *bug; | 733 | return is_kernel_addr(addr); |
746 | |||
747 | for (bug = __start___bug_table; bug < __stop___bug_table; ++bug) | ||
748 | if (bugaddr == bug->bug_addr) | ||
749 | return bug; | ||
750 | return module_find_bug(bugaddr); | ||
751 | } | ||
752 | |||
753 | static int check_bug_trap(struct pt_regs *regs) | ||
754 | { | ||
755 | struct bug_entry *bug; | ||
756 | unsigned long addr; | ||
757 | |||
758 | if (regs->msr & MSR_PR) | ||
759 | return 0; /* not in kernel */ | ||
760 | addr = regs->nip; /* address of trap instruction */ | ||
761 | if (addr < PAGE_OFFSET) | ||
762 | return 0; | ||
763 | bug = find_bug(regs->nip); | ||
764 | if (bug == NULL) | ||
765 | return 0; | ||
766 | if (bug->line & BUG_WARNING_TRAP) { | ||
767 | /* this is a WARN_ON rather than BUG/BUG_ON */ | ||
768 | printk(KERN_ERR "Badness in %s at %s:%ld\n", | ||
769 | bug->function, bug->file, | ||
770 | bug->line & ~BUG_WARNING_TRAP); | ||
771 | dump_stack(); | ||
772 | return 1; | ||
773 | } | ||
774 | printk(KERN_CRIT "kernel BUG in %s at %s:%ld!\n", | ||
775 | bug->function, bug->file, bug->line); | ||
776 | |||
777 | return 0; | ||
778 | } | 734 | } |
779 | 735 | ||
780 | void __kprobes program_check_exception(struct pt_regs *regs) | 736 | void __kprobes program_check_exception(struct pt_regs *regs) |
@@ -810,7 +766,9 @@ void __kprobes program_check_exception(struct pt_regs *regs) | |||
810 | return; | 766 | return; |
811 | if (debugger_bpt(regs)) | 767 | if (debugger_bpt(regs)) |
812 | return; | 768 | return; |
813 | if (check_bug_trap(regs)) { | 769 | |
770 | if (!(regs->msr & MSR_PR) && /* not user-mode */ | ||
771 | report_bug(regs->nip) == BUG_TRAP_TYPE_WARN) { | ||
814 | regs->nip += 4; | 772 | regs->nip += 4; |
815 | return; | 773 | return; |
816 | } | 774 | } |
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 | |||
62 | __stop___ex_table = .; | 62 | __stop___ex_table = .; |
63 | } | 63 | } |
64 | 64 | ||
65 | __bug_table : { | 65 | BUG_TABLE |
66 | __start___bug_table = .; | ||
67 | *(__bug_table) | ||
68 | __stop___bug_table = .; | ||
69 | } | ||
70 | 66 | ||
71 | /* | 67 | /* |
72 | * Init sections discarded at runtime | 68 | * 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 @@ | |||
22 | #include <linux/sysrq.h> | 22 | #include <linux/sysrq.h> |
23 | #include <linux/interrupt.h> | 23 | #include <linux/interrupt.h> |
24 | #include <linux/irq.h> | 24 | #include <linux/irq.h> |
25 | #include <linux/bug.h> | ||
25 | 26 | ||
26 | #include <asm/ptrace.h> | 27 | #include <asm/ptrace.h> |
27 | #include <asm/string.h> | 28 | #include <asm/string.h> |
@@ -35,7 +36,6 @@ | |||
35 | #include <asm/cputable.h> | 36 | #include <asm/cputable.h> |
36 | #include <asm/rtas.h> | 37 | #include <asm/rtas.h> |
37 | #include <asm/sstep.h> | 38 | #include <asm/sstep.h> |
38 | #include <asm/bug.h> | ||
39 | #include <asm/irq_regs.h> | 39 | #include <asm/irq_regs.h> |
40 | #include <asm/spu.h> | 40 | #include <asm/spu.h> |
41 | #include <asm/spu_priv1.h> | 41 | #include <asm/spu_priv1.h> |
@@ -1346,7 +1346,7 @@ static void backtrace(struct pt_regs *excp) | |||
1346 | 1346 | ||
1347 | static void print_bug_trap(struct pt_regs *regs) | 1347 | static void print_bug_trap(struct pt_regs *regs) |
1348 | { | 1348 | { |
1349 | struct bug_entry *bug; | 1349 | const struct bug_entry *bug; |
1350 | unsigned long addr; | 1350 | unsigned long addr; |
1351 | 1351 | ||
1352 | if (regs->msr & MSR_PR) | 1352 | if (regs->msr & MSR_PR) |
@@ -1357,11 +1357,11 @@ static void print_bug_trap(struct pt_regs *regs) | |||
1357 | bug = find_bug(regs->nip); | 1357 | bug = find_bug(regs->nip); |
1358 | if (bug == NULL) | 1358 | if (bug == NULL) |
1359 | return; | 1359 | return; |
1360 | if (bug->line & BUG_WARNING_TRAP) | 1360 | if (is_warning_bug(bug)) |
1361 | return; | 1361 | return; |
1362 | 1362 | ||
1363 | printf("kernel BUG in %s at %s:%d!\n", | 1363 | printf("kernel BUG at %s:%u!\n", |
1364 | bug->function, bug->file, (unsigned int)bug->line); | 1364 | bug->file, bug->line); |
1365 | } | 1365 | } |
1366 | 1366 | ||
1367 | void excprint(struct pt_regs *fp) | 1367 | 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 @@ | |||
13 | 13 | ||
14 | #ifndef __ASSEMBLY__ | 14 | #ifndef __ASSEMBLY__ |
15 | 15 | ||
16 | struct bug_entry { | ||
17 | unsigned long bug_addr; | ||
18 | long line; | ||
19 | const char *file; | ||
20 | const char *function; | ||
21 | }; | ||
22 | |||
23 | struct bug_entry *find_bug(unsigned long bugaddr); | ||
24 | |||
25 | /* | ||
26 | * If this bit is set in the line number it means that the trap | ||
27 | * is for WARN_ON rather than BUG or BUG_ON. | ||
28 | */ | ||
29 | #define BUG_WARNING_TRAP 0x1000000 | ||
30 | |||
31 | #ifdef CONFIG_BUG | 16 | #ifdef CONFIG_BUG |
32 | 17 | ||
18 | /* _EMIT_BUG_ENTRY expects args %0,%1,%2,%3 to be FILE, LINE, flags and | ||
19 | sizeof(struct bug_entry), respectively */ | ||
20 | #ifdef CONFIG_DEBUG_BUGVERBOSE | ||
21 | #define _EMIT_BUG_ENTRY \ | ||
22 | ".section __bug_table,\"a\"\n" \ | ||
23 | "2:\t" PPC_LONG "1b, %0\n" \ | ||
24 | "\t.short %1, %2\n" \ | ||
25 | ".org 2b+%3\n" \ | ||
26 | ".previous\n" | ||
27 | #else | ||
28 | #define _EMIT_BUG_ENTRY \ | ||
29 | ".section __bug_table,\"a\"\n" \ | ||
30 | "2:\t" PPC_LONG "1b\n" \ | ||
31 | "\t.short %2\n" \ | ||
32 | ".org 2b+%3\n" \ | ||
33 | ".previous\n" | ||
34 | #endif | ||
35 | |||
33 | /* | 36 | /* |
34 | * BUG_ON() and WARN_ON() do their best to cooperate with compile-time | 37 | * BUG_ON() and WARN_ON() do their best to cooperate with compile-time |
35 | * optimisations. However depending on the complexity of the condition | 38 | * optimisations. However depending on the complexity of the condition |
36 | * some compiler versions may not produce optimal results. | 39 | * some compiler versions may not produce optimal results. |
37 | */ | 40 | */ |
38 | 41 | ||
39 | #define BUG() do { \ | 42 | #define BUG() do { \ |
40 | __asm__ __volatile__( \ | 43 | __asm__ __volatile__( \ |
41 | "1: twi 31,0,0\n" \ | 44 | "1: twi 31,0,0\n" \ |
42 | ".section __bug_table,\"a\"\n" \ | 45 | _EMIT_BUG_ENTRY \ |
43 | "\t"PPC_LONG" 1b,%0,%1,%2\n" \ | 46 | : : "i" (__FILE__), "i" (__LINE__), \ |
44 | ".previous" \ | 47 | "i" (0), "i" (sizeof(struct bug_entry))); \ |
45 | : : "i" (__LINE__), "i" (__FILE__), "i" (__FUNCTION__)); \ | 48 | for(;;) ; \ |
46 | } while (0) | 49 | } while (0) |
47 | 50 | ||
48 | #define BUG_ON(x) do { \ | 51 | #define BUG_ON(x) do { \ |
@@ -51,23 +54,21 @@ struct bug_entry *find_bug(unsigned long bugaddr); | |||
51 | BUG(); \ | 54 | BUG(); \ |
52 | } else { \ | 55 | } else { \ |
53 | __asm__ __volatile__( \ | 56 | __asm__ __volatile__( \ |
54 | "1: "PPC_TLNEI" %0,0\n" \ | 57 | "1: "PPC_TLNEI" %4,0\n" \ |
55 | ".section __bug_table,\"a\"\n" \ | 58 | _EMIT_BUG_ENTRY \ |
56 | "\t"PPC_LONG" 1b,%1,%2,%3\n" \ | 59 | : : "i" (__FILE__), "i" (__LINE__), "i" (0), \ |
57 | ".previous" \ | 60 | "i" (sizeof(struct bug_entry)), \ |
58 | : : "r" ((long)(x)), "i" (__LINE__), \ | 61 | "r" ((long)(x))); \ |
59 | "i" (__FILE__), "i" (__FUNCTION__)); \ | ||
60 | } \ | 62 | } \ |
61 | } while (0) | 63 | } while (0) |
62 | 64 | ||
63 | #define __WARN() do { \ | 65 | #define __WARN() do { \ |
64 | __asm__ __volatile__( \ | 66 | __asm__ __volatile__( \ |
65 | "1: twi 31,0,0\n" \ | 67 | "1: twi 31,0,0\n" \ |
66 | ".section __bug_table,\"a\"\n" \ | 68 | _EMIT_BUG_ENTRY \ |
67 | "\t"PPC_LONG" 1b,%0,%1,%2\n" \ | 69 | : : "i" (__FILE__), "i" (__LINE__), \ |
68 | ".previous" \ | 70 | "i" (BUGFLAG_WARNING), \ |
69 | : : "i" (__LINE__ + BUG_WARNING_TRAP), \ | 71 | "i" (sizeof(struct bug_entry))); \ |
70 | "i" (__FILE__), "i" (__FUNCTION__)); \ | ||
71 | } while (0) | 72 | } while (0) |
72 | 73 | ||
73 | #define WARN_ON(x) ({ \ | 74 | #define WARN_ON(x) ({ \ |
@@ -77,13 +78,12 @@ struct bug_entry *find_bug(unsigned long bugaddr); | |||
77 | __WARN(); \ | 78 | __WARN(); \ |
78 | } else { \ | 79 | } else { \ |
79 | __asm__ __volatile__( \ | 80 | __asm__ __volatile__( \ |
80 | "1: "PPC_TLNEI" %0,0\n" \ | 81 | "1: "PPC_TLNEI" %4,0\n" \ |
81 | ".section __bug_table,\"a\"\n" \ | 82 | _EMIT_BUG_ENTRY \ |
82 | "\t"PPC_LONG" 1b,%1,%2,%3\n" \ | 83 | : : "i" (__FILE__), "i" (__LINE__), \ |
83 | ".previous" \ | 84 | "i" (BUGFLAG_WARNING), \ |
84 | : : "r" (__ret_warn_on), \ | 85 | "i" (sizeof(struct bug_entry)), \ |
85 | "i" (__LINE__ + BUG_WARNING_TRAP), \ | 86 | "r" (__ret_warn_on)); \ |
86 | "i" (__FILE__), "i" (__FUNCTION__)); \ | ||
87 | } \ | 87 | } \ |
88 | unlikely(__ret_warn_on); \ | 88 | unlikely(__ret_warn_on); \ |
89 | }) | 89 | }) |
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 { | |||
46 | unsigned int num_bugs; | 46 | unsigned int num_bugs; |
47 | }; | 47 | }; |
48 | 48 | ||
49 | extern struct bug_entry *module_find_bug(unsigned long bugaddr); | ||
50 | |||
51 | /* | 49 | /* |
52 | * Select ELF headers. | 50 | * Select ELF headers. |
53 | * Make empty section for module_frob_arch_sections to expand. | 51 | * Make empty section for module_frob_arch_sections to expand. |