diff options
-rw-r--r-- | arch/parisc/Kconfig | 5 | ||||
-rw-r--r-- | arch/parisc/kernel/module.c | 4 | ||||
-rw-r--r-- | arch/parisc/kernel/traps.c | 85 | ||||
-rw-r--r-- | arch/parisc/kernel/vmlinux.lds.S | 2 | ||||
-rw-r--r-- | include/asm-parisc/bug.h | 73 |
5 files changed, 116 insertions, 53 deletions
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index 0f9ff618c6d7..848a67a024b2 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig | |||
@@ -37,6 +37,11 @@ config GENERIC_FIND_NEXT_BIT | |||
37 | bool | 37 | bool |
38 | default y | 38 | default y |
39 | 39 | ||
40 | config GENERIC_BUG | ||
41 | bool | ||
42 | default y | ||
43 | depends on BUG | ||
44 | |||
40 | config GENERIC_HWEIGHT | 45 | config GENERIC_HWEIGHT |
41 | bool | 46 | bool |
42 | default y | 47 | default y |
diff --git a/arch/parisc/kernel/module.c b/arch/parisc/kernel/module.c index 47ea4e4a2179..1808f857a73a 100644 --- a/arch/parisc/kernel/module.c +++ b/arch/parisc/kernel/module.c | |||
@@ -46,6 +46,7 @@ | |||
46 | #include <linux/fs.h> | 46 | #include <linux/fs.h> |
47 | #include <linux/string.h> | 47 | #include <linux/string.h> |
48 | #include <linux/kernel.h> | 48 | #include <linux/kernel.h> |
49 | #include <linux/bug.h> | ||
49 | 50 | ||
50 | #include <asm/unwind.h> | 51 | #include <asm/unwind.h> |
51 | 52 | ||
@@ -851,10 +852,11 @@ int module_finalize(const Elf_Ehdr *hdr, | |||
851 | nsyms = newptr - (Elf_Sym *)symhdr->sh_addr; | 852 | nsyms = newptr - (Elf_Sym *)symhdr->sh_addr; |
852 | DEBUGP("NEW num_symtab %lu\n", nsyms); | 853 | DEBUGP("NEW num_symtab %lu\n", nsyms); |
853 | symhdr->sh_size = nsyms * sizeof(Elf_Sym); | 854 | symhdr->sh_size = nsyms * sizeof(Elf_Sym); |
854 | return 0; | 855 | return module_bug_finalize(hdr, sechdrs, me); |
855 | } | 856 | } |
856 | 857 | ||
857 | void module_arch_cleanup(struct module *mod) | 858 | void module_arch_cleanup(struct module *mod) |
858 | { | 859 | { |
859 | deregister_unwind_table(mod); | 860 | deregister_unwind_table(mod); |
861 | module_bug_cleanup(mod); | ||
860 | } | 862 | } |
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index 949722540864..ea0eff91db4e 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c | |||
@@ -26,6 +26,7 @@ | |||
26 | #include <linux/interrupt.h> | 26 | #include <linux/interrupt.h> |
27 | #include <linux/console.h> | 27 | #include <linux/console.h> |
28 | #include <linux/kallsyms.h> | 28 | #include <linux/kallsyms.h> |
29 | #include <linux/bug.h> | ||
29 | 30 | ||
30 | #include <asm/assembly.h> | 31 | #include <asm/assembly.h> |
31 | #include <asm/system.h> | 32 | #include <asm/system.h> |
@@ -51,7 +52,7 @@ | |||
51 | DEFINE_SPINLOCK(pa_dbit_lock); | 52 | DEFINE_SPINLOCK(pa_dbit_lock); |
52 | #endif | 53 | #endif |
53 | 54 | ||
54 | int printbinary(char *buf, unsigned long x, int nbits) | 55 | static int printbinary(char *buf, unsigned long x, int nbits) |
55 | { | 56 | { |
56 | unsigned long mask = 1UL << (nbits - 1); | 57 | unsigned long mask = 1UL << (nbits - 1); |
57 | while (mask != 0) { | 58 | while (mask != 0) { |
@@ -207,6 +208,11 @@ HERE: | |||
207 | do_show_stack(&info); | 208 | do_show_stack(&info); |
208 | } | 209 | } |
209 | 210 | ||
211 | int is_valid_bugaddr(unsigned long iaoq) | ||
212 | { | ||
213 | return 1; | ||
214 | } | ||
215 | |||
210 | void die_if_kernel(char *str, struct pt_regs *regs, long err) | 216 | void die_if_kernel(char *str, struct pt_regs *regs, long err) |
211 | { | 217 | { |
212 | if (user_mode(regs)) { | 218 | if (user_mode(regs)) { |
@@ -225,7 +231,7 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err) | |||
225 | oops_in_progress = 1; | 231 | oops_in_progress = 1; |
226 | 232 | ||
227 | /* Amuse the user in a SPARC fashion */ | 233 | /* Amuse the user in a SPARC fashion */ |
228 | printk( | 234 | if (err) printk( |
229 | " _______________________________ \n" | 235 | " _______________________________ \n" |
230 | " < Your System ate a SPARC! Gah! >\n" | 236 | " < Your System ate a SPARC! Gah! >\n" |
231 | " ------------------------------- \n" | 237 | " ------------------------------- \n" |
@@ -245,8 +251,9 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err) | |||
245 | if (!console_drivers) | 251 | if (!console_drivers) |
246 | pdc_console_restart(); | 252 | pdc_console_restart(); |
247 | 253 | ||
248 | printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n", | 254 | if (err) |
249 | current->comm, current->pid, str, err); | 255 | printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n", |
256 | current->comm, current->pid, str, err); | ||
250 | show_regs(regs); | 257 | show_regs(regs); |
251 | 258 | ||
252 | if (in_interrupt()) | 259 | if (in_interrupt()) |
@@ -276,61 +283,45 @@ int syscall_ipi(int (*syscall) (struct pt_regs *), struct pt_regs *regs) | |||
276 | 283 | ||
277 | /* gdb uses break 4,8 */ | 284 | /* gdb uses break 4,8 */ |
278 | #define GDB_BREAK_INSN 0x10004 | 285 | #define GDB_BREAK_INSN 0x10004 |
279 | void handle_gdb_break(struct pt_regs *regs, int wot) | 286 | static void handle_gdb_break(struct pt_regs *regs, int wot) |
280 | { | 287 | { |
281 | struct siginfo si; | 288 | struct siginfo si; |
282 | 289 | ||
283 | si.si_code = wot; | ||
284 | si.si_addr = (void __user *) (regs->iaoq[0] & ~3); | ||
285 | si.si_signo = SIGTRAP; | 290 | si.si_signo = SIGTRAP; |
286 | si.si_errno = 0; | 291 | si.si_errno = 0; |
292 | si.si_code = wot; | ||
293 | si.si_addr = (void __user *) (regs->iaoq[0] & ~3); | ||
287 | force_sig_info(SIGTRAP, &si, current); | 294 | force_sig_info(SIGTRAP, &si, current); |
288 | } | 295 | } |
289 | 296 | ||
290 | void handle_break(unsigned iir, struct pt_regs *regs) | 297 | static void handle_break(struct pt_regs *regs) |
291 | { | 298 | { |
292 | struct siginfo si; | 299 | unsigned iir = regs->iir; |
293 | 300 | ||
294 | switch(iir) { | 301 | if (unlikely(iir == PARISC_BUG_BREAK_INSN && !user_mode(regs))) { |
295 | case 0x00: | 302 | /* check if a BUG() or WARN() trapped here. */ |
296 | #ifdef PRINT_USER_FAULTS | 303 | enum bug_trap_type tt; |
297 | printk(KERN_DEBUG "break 0,0: pid=%d command='%s'\n", | 304 | tt = report_bug(regs->iaoq[0] & ~3); |
298 | current->pid, current->comm); | 305 | if (tt == BUG_TRAP_TYPE_WARN) { |
299 | #endif | 306 | regs->iaoq[0] += 4; |
300 | die_if_kernel("Breakpoint", regs, 0); | 307 | regs->iaoq[1] += 4; |
301 | #ifdef PRINT_USER_FAULTS | 308 | return; /* return to next instruction when WARN_ON(). */ |
302 | show_regs(regs); | 309 | } |
303 | #endif | 310 | die_if_kernel("Unknown kernel breakpoint", regs, |
304 | si.si_code = TRAP_BRKPT; | 311 | (tt == BUG_TRAP_TYPE_NONE) ? 9 : 0); |
305 | si.si_addr = (void __user *) (regs->iaoq[0] & ~3); | 312 | } |
306 | si.si_signo = SIGTRAP; | ||
307 | force_sig_info(SIGTRAP, &si, current); | ||
308 | break; | ||
309 | |||
310 | case GDB_BREAK_INSN: | ||
311 | die_if_kernel("Breakpoint", regs, 0); | ||
312 | handle_gdb_break(regs, TRAP_BRKPT); | ||
313 | break; | ||
314 | 313 | ||
315 | default: | ||
316 | #ifdef PRINT_USER_FAULTS | 314 | #ifdef PRINT_USER_FAULTS |
317 | printk(KERN_DEBUG "break %#08x: pid=%d command='%s'\n", | 315 | if (unlikely(iir != GDB_BREAK_INSN)) { |
318 | iir, current->pid, current->comm); | 316 | printk(KERN_DEBUG "break %d,%d: pid=%d command='%s'\n", |
317 | (iir>>13) & ((1<<13)-1), iir & 31, | ||
318 | current->pid, current->comm); | ||
319 | show_regs(regs); | 319 | show_regs(regs); |
320 | #endif | ||
321 | si.si_signo = SIGTRAP; | ||
322 | si.si_code = TRAP_BRKPT; | ||
323 | si.si_addr = (void __user *) (regs->iaoq[0] & ~3); | ||
324 | force_sig_info(SIGTRAP, &si, current); | ||
325 | return; | ||
326 | } | 320 | } |
327 | } | 321 | #endif |
328 | |||
329 | 322 | ||
330 | int handle_toc(void) | 323 | /* send standard GDB signal */ |
331 | { | 324 | handle_gdb_break(regs, TRAP_BRKPT); |
332 | printk(KERN_CRIT "TOC call.\n"); | ||
333 | return 0; | ||
334 | } | 325 | } |
335 | 326 | ||
336 | static void default_trap(int code, struct pt_regs *regs) | 327 | static void default_trap(int code, struct pt_regs *regs) |
@@ -339,7 +330,7 @@ static void default_trap(int code, struct pt_regs *regs) | |||
339 | show_regs(regs); | 330 | show_regs(regs); |
340 | } | 331 | } |
341 | 332 | ||
342 | void (*cpu_lpmc) (int code, struct pt_regs *regs) = default_trap; | 333 | void (*cpu_lpmc) (int code, struct pt_regs *regs) __read_mostly = default_trap; |
343 | 334 | ||
344 | 335 | ||
345 | void transfer_pim_to_trap_frame(struct pt_regs *regs) | 336 | void transfer_pim_to_trap_frame(struct pt_regs *regs) |
@@ -576,7 +567,7 @@ void handle_interruption(int code, struct pt_regs *regs) | |||
576 | 567 | ||
577 | case 9: | 568 | case 9: |
578 | /* Break instruction trap */ | 569 | /* Break instruction trap */ |
579 | handle_break(regs->iir,regs); | 570 | handle_break(regs); |
580 | return; | 571 | return; |
581 | 572 | ||
582 | case 10: | 573 | case 10: |
diff --git a/arch/parisc/kernel/vmlinux.lds.S b/arch/parisc/kernel/vmlinux.lds.S index 7b943b45f7cd..7b149df9d422 100644 --- a/arch/parisc/kernel/vmlinux.lds.S +++ b/arch/parisc/kernel/vmlinux.lds.S | |||
@@ -68,6 +68,8 @@ SECTIONS | |||
68 | 68 | ||
69 | RODATA | 69 | RODATA |
70 | 70 | ||
71 | BUG_TABLE | ||
72 | |||
71 | /* writeable */ | 73 | /* writeable */ |
72 | . = ALIGN(ASM_PAGE_SIZE); /* Make sure this is page aligned so | 74 | . = ALIGN(ASM_PAGE_SIZE); /* Make sure this is page aligned so |
73 | that we can properly leave these | 75 | that we can properly leave these |
diff --git a/include/asm-parisc/bug.h b/include/asm-parisc/bug.h index 695588da41f8..8dd199f5d6d7 100644 --- a/include/asm-parisc/bug.h +++ b/include/asm-parisc/bug.h | |||
@@ -1,14 +1,77 @@ | |||
1 | #ifndef _PARISC_BUG_H | 1 | #ifndef _PARISC_BUG_H |
2 | #define _PARISC_BUG_H | 2 | #define _PARISC_BUG_H |
3 | 3 | ||
4 | /* | ||
5 | * Tell the user there is some problem. | ||
6 | * The offending file and line are encoded in the __bug_table section. | ||
7 | */ | ||
8 | |||
4 | #ifdef CONFIG_BUG | 9 | #ifdef CONFIG_BUG |
5 | #define HAVE_ARCH_BUG | 10 | #define HAVE_ARCH_BUG |
6 | #define BUG() do { \ | 11 | #define HAVE_ARCH_WARN_ON |
7 | printk("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ | 12 | |
8 | dump_stack(); \ | 13 | /* the break instruction is used as BUG() marker. */ |
9 | panic("BUG!"); \ | 14 | #define PARISC_BUG_BREAK_ASM "break 0x1f, 0x1fff" |
10 | } while (0) | 15 | #define PARISC_BUG_BREAK_INSN 0x03ffe01f /* PARISC_BUG_BREAK_ASM */ |
16 | |||
17 | #ifdef CONFIG_64BIT | ||
18 | #define ASM_ULONG_INSN ".dword" | ||
19 | #else | ||
20 | #define ASM_ULONG_INSN ".word" | ||
21 | #endif | ||
22 | |||
23 | #ifdef CONFIG_DEBUG_BUGVERBOSE | ||
24 | #define BUG() \ | ||
25 | do { \ | ||
26 | asm volatile("\n" \ | ||
27 | "1:\t" PARISC_BUG_BREAK_ASM "\n" \ | ||
28 | "\t.pushsection __bug_table,\"a\"\n" \ | ||
29 | "2:\t" ASM_ULONG_INSN " 1b, %c0\n" \ | ||
30 | "\t.short %c1, %c2\n" \ | ||
31 | "\t.org 2b+%c3\n" \ | ||
32 | "\t.popsection" \ | ||
33 | : : "i" (__FILE__), "i" (__LINE__), \ | ||
34 | "i" (0), "i" (sizeof(struct bug_entry)) ); \ | ||
35 | for(;;) ; \ | ||
36 | } while(0) | ||
37 | |||
38 | #else | ||
39 | #define BUG() \ | ||
40 | do { \ | ||
41 | asm volatile(PARISC_BUG_BREAK_ASM : : ); \ | ||
42 | for(;;) ; \ | ||
43 | } while(0) | ||
44 | #endif | ||
45 | |||
46 | #define __WARN() \ | ||
47 | do { \ | ||
48 | asm volatile("\n" \ | ||
49 | "1:\t" PARISC_BUG_BREAK_ASM "\n" \ | ||
50 | "\t.pushsection __bug_table,\"a\"\n" \ | ||
51 | "2:\t" ASM_ULONG_INSN " 1b, %c0\n" \ | ||
52 | "\t.short %c1, %c2\n" \ | ||
53 | "\t.org 2b+%c3\n" \ | ||
54 | "\t.popsection" \ | ||
55 | : : "i" (__FILE__), "i" (__LINE__), \ | ||
56 | "i" (BUGFLAG_WARNING), \ | ||
57 | "i" (sizeof(struct bug_entry)) ); \ | ||
58 | } while(0) | ||
59 | |||
60 | |||
61 | #define WARN_ON(x) ({ \ | ||
62 | typeof(x) __ret_warn_on = (x); \ | ||
63 | if (__builtin_constant_p(__ret_warn_on)) { \ | ||
64 | if (__ret_warn_on) \ | ||
65 | __WARN(); \ | ||
66 | } else { \ | ||
67 | if (unlikely(__ret_warn_on)) \ | ||
68 | __WARN(); \ | ||
69 | } \ | ||
70 | unlikely(__ret_warn_on); \ | ||
71 | }) | ||
72 | |||
11 | #endif | 73 | #endif |
12 | 74 | ||
13 | #include <asm-generic/bug.h> | 75 | #include <asm-generic/bug.h> |
14 | #endif | 76 | #endif |
77 | |||