diff options
Diffstat (limited to 'arch/mips/kernel/traps.c')
| -rw-r--r-- | arch/mips/kernel/traps.c | 50 |
1 files changed, 35 insertions, 15 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c index 852780868fb4..03ec0019032b 100644 --- a/arch/mips/kernel/traps.c +++ b/arch/mips/kernel/traps.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/ptrace.h> | 25 | #include <linux/ptrace.h> |
| 26 | #include <linux/kgdb.h> | 26 | #include <linux/kgdb.h> |
| 27 | #include <linux/kdebug.h> | 27 | #include <linux/kdebug.h> |
| 28 | #include <linux/kprobes.h> | ||
| 28 | #include <linux/notifier.h> | 29 | #include <linux/notifier.h> |
| 29 | #include <linux/kdb.h> | 30 | #include <linux/kdb.h> |
| 30 | 31 | ||
| @@ -334,7 +335,7 @@ void show_regs(struct pt_regs *regs) | |||
| 334 | __show_regs((struct pt_regs *)regs); | 335 | __show_regs((struct pt_regs *)regs); |
| 335 | } | 336 | } |
| 336 | 337 | ||
| 337 | void show_registers(const struct pt_regs *regs) | 338 | void show_registers(struct pt_regs *regs) |
| 338 | { | 339 | { |
| 339 | const int field = 2 * sizeof(unsigned long); | 340 | const int field = 2 * sizeof(unsigned long); |
| 340 | 341 | ||
| @@ -356,9 +357,14 @@ void show_registers(const struct pt_regs *regs) | |||
| 356 | printk("\n"); | 357 | printk("\n"); |
| 357 | } | 358 | } |
| 358 | 359 | ||
| 360 | static int regs_to_trapnr(struct pt_regs *regs) | ||
| 361 | { | ||
| 362 | return (regs->cp0_cause >> 2) & 0x1f; | ||
| 363 | } | ||
| 364 | |||
| 359 | static DEFINE_SPINLOCK(die_lock); | 365 | static DEFINE_SPINLOCK(die_lock); |
| 360 | 366 | ||
| 361 | void __noreturn die(const char * str, struct pt_regs * regs) | 367 | void __noreturn die(const char *str, struct pt_regs *regs) |
| 362 | { | 368 | { |
| 363 | static int die_counter; | 369 | static int die_counter; |
| 364 | int sig = SIGSEGV; | 370 | int sig = SIGSEGV; |
| @@ -366,7 +372,7 @@ void __noreturn die(const char * str, struct pt_regs * regs) | |||
| 366 | unsigned long dvpret = dvpe(); | 372 | unsigned long dvpret = dvpe(); |
| 367 | #endif /* CONFIG_MIPS_MT_SMTC */ | 373 | #endif /* CONFIG_MIPS_MT_SMTC */ |
| 368 | 374 | ||
| 369 | notify_die(DIE_OOPS, str, (struct pt_regs *)regs, SIGSEGV, 0, 0); | 375 | notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV); |
| 370 | 376 | ||
| 371 | console_verbose(); | 377 | console_verbose(); |
| 372 | spin_lock_irq(&die_lock); | 378 | spin_lock_irq(&die_lock); |
| @@ -375,7 +381,7 @@ void __noreturn die(const char * str, struct pt_regs * regs) | |||
| 375 | mips_mt_regdump(dvpret); | 381 | mips_mt_regdump(dvpret); |
| 376 | #endif /* CONFIG_MIPS_MT_SMTC */ | 382 | #endif /* CONFIG_MIPS_MT_SMTC */ |
| 377 | 383 | ||
| 378 | if (notify_die(DIE_OOPS, str, regs, 0, current->thread.trap_no, SIGSEGV) == NOTIFY_STOP) | 384 | if (notify_die(DIE_OOPS, str, regs, 0, regs_to_trapnr(regs), SIGSEGV) == NOTIFY_STOP) |
| 379 | sig = 0; | 385 | sig = 0; |
| 380 | 386 | ||
| 381 | printk("%s[#%d]:\n", str, ++die_counter); | 387 | printk("%s[#%d]:\n", str, ++die_counter); |
| @@ -449,7 +455,7 @@ asmlinkage void do_be(struct pt_regs *regs) | |||
| 449 | printk(KERN_ALERT "%s bus error, epc == %0*lx, ra == %0*lx\n", | 455 | printk(KERN_ALERT "%s bus error, epc == %0*lx, ra == %0*lx\n", |
| 450 | data ? "Data" : "Instruction", | 456 | data ? "Data" : "Instruction", |
| 451 | field, regs->cp0_epc, field, regs->regs[31]); | 457 | field, regs->cp0_epc, field, regs->regs[31]); |
| 452 | if (notify_die(DIE_OOPS, "bus error", regs, SIGBUS, 0, 0) | 458 | if (notify_die(DIE_OOPS, "bus error", regs, 0, regs_to_trapnr(regs), SIGBUS) |
| 453 | == NOTIFY_STOP) | 459 | == NOTIFY_STOP) |
| 454 | return; | 460 | return; |
| 455 | 461 | ||
| @@ -650,7 +656,7 @@ asmlinkage void do_fpe(struct pt_regs *regs, unsigned long fcr31) | |||
| 650 | { | 656 | { |
| 651 | siginfo_t info; | 657 | siginfo_t info; |
| 652 | 658 | ||
| 653 | if (notify_die(DIE_FP, "FP exception", regs, SIGFPE, 0, 0) | 659 | if (notify_die(DIE_FP, "FP exception", regs, 0, regs_to_trapnr(regs), SIGFPE) |
| 654 | == NOTIFY_STOP) | 660 | == NOTIFY_STOP) |
| 655 | return; | 661 | return; |
| 656 | die_if_kernel("FP exception in kernel code", regs); | 662 | die_if_kernel("FP exception in kernel code", regs); |
| @@ -713,11 +719,11 @@ static void do_trap_or_bp(struct pt_regs *regs, unsigned int code, | |||
| 713 | char b[40]; | 719 | char b[40]; |
| 714 | 720 | ||
| 715 | #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP | 721 | #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP |
| 716 | if (kgdb_ll_trap(DIE_TRAP, str, regs, code, 0, 0) == NOTIFY_STOP) | 722 | if (kgdb_ll_trap(DIE_TRAP, str, regs, code, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP) |
| 717 | return; | 723 | return; |
| 718 | #endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */ | 724 | #endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */ |
| 719 | 725 | ||
| 720 | if (notify_die(DIE_TRAP, str, regs, code, 0, 0) == NOTIFY_STOP) | 726 | if (notify_die(DIE_TRAP, str, regs, code, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP) |
| 721 | return; | 727 | return; |
| 722 | 728 | ||
| 723 | /* | 729 | /* |
| @@ -783,6 +789,25 @@ asmlinkage void do_bp(struct pt_regs *regs) | |||
| 783 | if (bcode >= (1 << 10)) | 789 | if (bcode >= (1 << 10)) |
| 784 | bcode >>= 10; | 790 | bcode >>= 10; |
| 785 | 791 | ||
| 792 | /* | ||
| 793 | * notify the kprobe handlers, if instruction is likely to | ||
| 794 | * pertain to them. | ||
| 795 | */ | ||
| 796 | switch (bcode) { | ||
| 797 | case BRK_KPROBE_BP: | ||
| 798 | if (notify_die(DIE_BREAK, "debug", regs, bcode, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP) | ||
| 799 | return; | ||
| 800 | else | ||
| 801 | break; | ||
| 802 | case BRK_KPROBE_SSTEPBP: | ||
| 803 | if (notify_die(DIE_SSTEPBP, "single_step", regs, bcode, regs_to_trapnr(regs), SIGTRAP) == NOTIFY_STOP) | ||
| 804 | return; | ||
| 805 | else | ||
| 806 | break; | ||
| 807 | default: | ||
| 808 | break; | ||
| 809 | } | ||
| 810 | |||
| 786 | do_trap_or_bp(regs, bcode, "Break"); | 811 | do_trap_or_bp(regs, bcode, "Break"); |
| 787 | return; | 812 | return; |
| 788 | 813 | ||
| @@ -815,7 +840,7 @@ asmlinkage void do_ri(struct pt_regs *regs) | |||
| 815 | unsigned int opcode = 0; | 840 | unsigned int opcode = 0; |
| 816 | int status = -1; | 841 | int status = -1; |
| 817 | 842 | ||
| 818 | if (notify_die(DIE_RI, "RI Fault", regs, SIGSEGV, 0, 0) | 843 | if (notify_die(DIE_RI, "RI Fault", regs, 0, regs_to_trapnr(regs), SIGILL) |
| 819 | == NOTIFY_STOP) | 844 | == NOTIFY_STOP) |
| 820 | return; | 845 | return; |
| 821 | 846 | ||
| @@ -907,11 +932,6 @@ static int default_cu2_call(struct notifier_block *nfb, unsigned long action, | |||
| 907 | return NOTIFY_OK; | 932 | return NOTIFY_OK; |
| 908 | } | 933 | } |
| 909 | 934 | ||
| 910 | static struct notifier_block default_cu2_notifier = { | ||
| 911 | .notifier_call = default_cu2_call, | ||
| 912 | .priority = 0x80000000, /* Run last */ | ||
| 913 | }; | ||
| 914 | |||
| 915 | asmlinkage void do_cpu(struct pt_regs *regs) | 935 | asmlinkage void do_cpu(struct pt_regs *regs) |
| 916 | { | 936 | { |
| 917 | unsigned int __user *epc; | 937 | unsigned int __user *epc; |
| @@ -1734,5 +1754,5 @@ void __init trap_init(void) | |||
| 1734 | 1754 | ||
| 1735 | sort_extable(__start___dbe_table, __stop___dbe_table); | 1755 | sort_extable(__start___dbe_table, __stop___dbe_table); |
| 1736 | 1756 | ||
| 1737 | register_cu2_notifier(&default_cu2_notifier); | 1757 | cu2_notifier(default_cu2_call, 0x80000000); /* Run last */ |
| 1738 | } | 1758 | } |
