diff options
author | Jeremy Fitzhardinge <jeremy@goop.org> | 2006-12-08 06:30:41 -0500 |
---|---|---|
committer | Paul Mackerras <paulus@samba.org> | 2006-12-11 00:35:07 -0500 |
commit | 73c9ceab40b1269d6195e556773167c078ac8311 (patch) | |
tree | d1de1c286b58a8b1e8dcd0e690ac6e8724e990f5 | |
parent | 973c1fabc70deb10f12a0eaab2f50c2263784257 (diff) |
[POWERPC] Generic BUG for powerpc
This makes powerpc use the generic BUG machinery. The biggest reports the
function name, since it is redundant with kallsyms, and not needed in general.
There is an overall reduction of code, since module_32/64 duplicated several
functions.
Unfortunately there's no way to tell gcc that BUG won't return, so the BUG
macro includes a goto loop. This will generate a real jmp instruction, which
is never used.
[akpm@osdl.org: build fix]
[paulus@samba.org: remove infinite loop in BUG_ON]
Signed-off-by: Jeremy Fitzhardinge <jeremy@goop.org>
Cc: Andi Kleen <ak@muc.de>
Cc: Hugh Dickens <hugh@veritas.com>
Cc: Michael Ellerman <michael@ellerman.id.au>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Paul Mackerras <paulus@samba.org>
-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. |