diff options
| -rw-r--r-- | arch/parisc/Kconfig | 1 | ||||
| -rw-r--r-- | arch/parisc/kernel/traps.c | 54 | ||||
| -rw-r--r-- | arch/parisc/mm/fault.c | 44 |
3 files changed, 56 insertions, 43 deletions
diff --git a/arch/parisc/Kconfig b/arch/parisc/Kconfig index bb2a8ec440e7..a8f4a70c0742 100644 --- a/arch/parisc/Kconfig +++ b/arch/parisc/Kconfig | |||
| @@ -22,6 +22,7 @@ config PARISC | |||
| 22 | select GENERIC_SMP_IDLE_THREAD | 22 | select GENERIC_SMP_IDLE_THREAD |
| 23 | select GENERIC_STRNCPY_FROM_USER | 23 | select GENERIC_STRNCPY_FROM_USER |
| 24 | select SYSCTL_ARCH_UNALIGN_ALLOW | 24 | select SYSCTL_ARCH_UNALIGN_ALLOW |
| 25 | select SYSCTL_EXCEPTION_TRACE | ||
| 25 | select HAVE_MOD_ARCH_SPECIFIC | 26 | select HAVE_MOD_ARCH_SPECIFIC |
| 26 | select VIRT_TO_BUS | 27 | select VIRT_TO_BUS |
| 27 | select MODULES_USE_ELF_RELA | 28 | select MODULES_USE_ELF_RELA |
diff --git a/arch/parisc/kernel/traps.c b/arch/parisc/kernel/traps.c index 1cd1d0c83b6d..47ee620d15d2 100644 --- a/arch/parisc/kernel/traps.c +++ b/arch/parisc/kernel/traps.c | |||
| @@ -25,6 +25,7 @@ | |||
| 25 | #include <linux/interrupt.h> | 25 | #include <linux/interrupt.h> |
| 26 | #include <linux/console.h> | 26 | #include <linux/console.h> |
| 27 | #include <linux/bug.h> | 27 | #include <linux/bug.h> |
| 28 | #include <linux/ratelimit.h> | ||
| 28 | 29 | ||
| 29 | #include <asm/assembly.h> | 30 | #include <asm/assembly.h> |
| 30 | #include <asm/uaccess.h> | 31 | #include <asm/uaccess.h> |
| @@ -42,9 +43,6 @@ | |||
| 42 | 43 | ||
| 43 | #include "../math-emu/math-emu.h" /* for handle_fpe() */ | 44 | #include "../math-emu/math-emu.h" /* for handle_fpe() */ |
| 44 | 45 | ||
| 45 | #define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */ | ||
| 46 | /* dumped to the console via printk) */ | ||
| 47 | |||
| 48 | #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) | 46 | #if defined(CONFIG_SMP) || defined(CONFIG_DEBUG_SPINLOCK) |
| 49 | DEFINE_SPINLOCK(pa_dbit_lock); | 47 | DEFINE_SPINLOCK(pa_dbit_lock); |
| 50 | #endif | 48 | #endif |
| @@ -160,6 +158,17 @@ void show_regs(struct pt_regs *regs) | |||
| 160 | } | 158 | } |
| 161 | } | 159 | } |
| 162 | 160 | ||
| 161 | static DEFINE_RATELIMIT_STATE(_hppa_rs, | ||
| 162 | DEFAULT_RATELIMIT_INTERVAL, DEFAULT_RATELIMIT_BURST); | ||
| 163 | |||
| 164 | #define parisc_printk_ratelimited(critical, regs, fmt, ...) { \ | ||
| 165 | if ((critical || show_unhandled_signals) && __ratelimit(&_hppa_rs)) { \ | ||
| 166 | printk(fmt, ##__VA_ARGS__); \ | ||
| 167 | show_regs(regs); \ | ||
| 168 | } \ | ||
| 169 | } | ||
| 170 | |||
| 171 | |||
| 163 | static void do_show_stack(struct unwind_frame_info *info) | 172 | static void do_show_stack(struct unwind_frame_info *info) |
| 164 | { | 173 | { |
| 165 | int i = 1; | 174 | int i = 1; |
| @@ -229,12 +238,10 @@ void die_if_kernel(char *str, struct pt_regs *regs, long err) | |||
| 229 | if (err == 0) | 238 | if (err == 0) |
| 230 | return; /* STFU */ | 239 | return; /* STFU */ |
| 231 | 240 | ||
| 232 | printk(KERN_CRIT "%s (pid %d): %s (code %ld) at " RFMT "\n", | 241 | parisc_printk_ratelimited(1, regs, |
| 242 | KERN_CRIT "%s (pid %d): %s (code %ld) at " RFMT "\n", | ||
| 233 | current->comm, task_pid_nr(current), str, err, regs->iaoq[0]); | 243 | current->comm, task_pid_nr(current), str, err, regs->iaoq[0]); |
| 234 | #ifdef PRINT_USER_FAULTS | 244 | |
| 235 | /* XXX for debugging only */ | ||
| 236 | show_regs(regs); | ||
| 237 | #endif | ||
| 238 | return; | 245 | return; |
| 239 | } | 246 | } |
| 240 | 247 | ||
| @@ -321,14 +328,11 @@ static void handle_break(struct pt_regs *regs) | |||
| 321 | (tt == BUG_TRAP_TYPE_NONE) ? 9 : 0); | 328 | (tt == BUG_TRAP_TYPE_NONE) ? 9 : 0); |
| 322 | } | 329 | } |
| 323 | 330 | ||
| 324 | #ifdef PRINT_USER_FAULTS | 331 | if (unlikely(iir != GDB_BREAK_INSN)) |
| 325 | if (unlikely(iir != GDB_BREAK_INSN)) { | 332 | parisc_printk_ratelimited(0, regs, |
| 326 | printk(KERN_DEBUG "break %d,%d: pid=%d command='%s'\n", | 333 | KERN_DEBUG "break %d,%d: pid=%d command='%s'\n", |
| 327 | iir & 31, (iir>>13) & ((1<<13)-1), | 334 | iir & 31, (iir>>13) & ((1<<13)-1), |
| 328 | task_pid_nr(current), current->comm); | 335 | task_pid_nr(current), current->comm); |
| 329 | show_regs(regs); | ||
| 330 | } | ||
| 331 | #endif | ||
| 332 | 336 | ||
| 333 | /* send standard GDB signal */ | 337 | /* send standard GDB signal */ |
| 334 | handle_gdb_break(regs, TRAP_BRKPT); | 338 | handle_gdb_break(regs, TRAP_BRKPT); |
| @@ -758,11 +762,9 @@ void notrace handle_interruption(int code, struct pt_regs *regs) | |||
| 758 | 762 | ||
| 759 | default: | 763 | default: |
| 760 | if (user_mode(regs)) { | 764 | if (user_mode(regs)) { |
| 761 | #ifdef PRINT_USER_FAULTS | 765 | parisc_printk_ratelimited(0, regs, KERN_DEBUG |
| 762 | printk(KERN_DEBUG "\nhandle_interruption() pid=%d command='%s'\n", | 766 | "handle_interruption() pid=%d command='%s'\n", |
| 763 | task_pid_nr(current), current->comm); | 767 | task_pid_nr(current), current->comm); |
| 764 | show_regs(regs); | ||
| 765 | #endif | ||
| 766 | /* SIGBUS, for lack of a better one. */ | 768 | /* SIGBUS, for lack of a better one. */ |
| 767 | si.si_signo = SIGBUS; | 769 | si.si_signo = SIGBUS; |
| 768 | si.si_code = BUS_OBJERR; | 770 | si.si_code = BUS_OBJERR; |
| @@ -779,16 +781,10 @@ void notrace handle_interruption(int code, struct pt_regs *regs) | |||
| 779 | 781 | ||
| 780 | if (user_mode(regs)) { | 782 | if (user_mode(regs)) { |
| 781 | if ((fault_space >> SPACEID_SHIFT) != (regs->sr[7] >> SPACEID_SHIFT)) { | 783 | if ((fault_space >> SPACEID_SHIFT) != (regs->sr[7] >> SPACEID_SHIFT)) { |
| 782 | #ifdef PRINT_USER_FAULTS | 784 | parisc_printk_ratelimited(0, regs, KERN_DEBUG |
| 783 | if (fault_space == 0) | 785 | "User fault %d on space 0x%08lx, pid=%d command='%s'\n", |
| 784 | printk(KERN_DEBUG "User Fault on Kernel Space "); | 786 | code, fault_space, |
| 785 | else | 787 | task_pid_nr(current), current->comm); |
| 786 | printk(KERN_DEBUG "User Fault (long pointer) (fault %d) ", | ||
| 787 | code); | ||
| 788 | printk(KERN_CONT "pid=%d command='%s'\n", | ||
| 789 | task_pid_nr(current), current->comm); | ||
| 790 | show_regs(regs); | ||
| 791 | #endif | ||
| 792 | si.si_signo = SIGSEGV; | 788 | si.si_signo = SIGSEGV; |
| 793 | si.si_errno = 0; | 789 | si.si_errno = 0; |
| 794 | si.si_code = SEGV_MAPERR; | 790 | si.si_code = SEGV_MAPERR; |
diff --git a/arch/parisc/mm/fault.c b/arch/parisc/mm/fault.c index 9d08c71a967e..d72197f0ddb8 100644 --- a/arch/parisc/mm/fault.c +++ b/arch/parisc/mm/fault.c | |||
| @@ -19,10 +19,6 @@ | |||
| 19 | #include <asm/uaccess.h> | 19 | #include <asm/uaccess.h> |
| 20 | #include <asm/traps.h> | 20 | #include <asm/traps.h> |
| 21 | 21 | ||
| 22 | #define PRINT_USER_FAULTS /* (turn this on if you want user faults to be */ | ||
| 23 | /* dumped to the console via printk) */ | ||
| 24 | |||
| 25 | |||
| 26 | /* Various important other fields */ | 22 | /* Various important other fields */ |
| 27 | #define bit22set(x) (x & 0x00000200) | 23 | #define bit22set(x) (x & 0x00000200) |
| 28 | #define bits23_25set(x) (x & 0x000001c0) | 24 | #define bits23_25set(x) (x & 0x000001c0) |
| @@ -34,6 +30,8 @@ | |||
| 34 | 30 | ||
| 35 | DEFINE_PER_CPU(struct exception_data, exception_data); | 31 | DEFINE_PER_CPU(struct exception_data, exception_data); |
| 36 | 32 | ||
| 33 | int show_unhandled_signals = 1; | ||
| 34 | |||
| 37 | /* | 35 | /* |
| 38 | * parisc_acctyp(unsigned int inst) -- | 36 | * parisc_acctyp(unsigned int inst) -- |
| 39 | * Given a PA-RISC memory access instruction, determine if the | 37 | * Given a PA-RISC memory access instruction, determine if the |
| @@ -173,6 +171,32 @@ int fixup_exception(struct pt_regs *regs) | |||
| 173 | return 0; | 171 | return 0; |
| 174 | } | 172 | } |
| 175 | 173 | ||
| 174 | /* | ||
| 175 | * Print out info about fatal segfaults, if the show_unhandled_signals | ||
| 176 | * sysctl is set: | ||
| 177 | */ | ||
| 178 | static inline void | ||
| 179 | show_signal_msg(struct pt_regs *regs, unsigned long code, | ||
| 180 | unsigned long address, struct task_struct *tsk, | ||
| 181 | struct vm_area_struct *vma) | ||
| 182 | { | ||
| 183 | if (!unhandled_signal(tsk, SIGSEGV)) | ||
| 184 | return; | ||
| 185 | |||
| 186 | if (!printk_ratelimit()) | ||
| 187 | return; | ||
| 188 | |||
| 189 | pr_warn("\n"); | ||
| 190 | pr_warn("do_page_fault() command='%s' type=%lu address=0x%08lx", | ||
| 191 | tsk->comm, code, address); | ||
| 192 | print_vma_addr(KERN_CONT " in ", regs->iaoq[0]); | ||
| 193 | if (vma) | ||
| 194 | pr_warn(" vm_start = 0x%08lx, vm_end = 0x%08lx\n", | ||
| 195 | vma->vm_start, vma->vm_end); | ||
| 196 | |||
| 197 | show_regs(regs); | ||
| 198 | } | ||
| 199 | |||
| 176 | void do_page_fault(struct pt_regs *regs, unsigned long code, | 200 | void do_page_fault(struct pt_regs *regs, unsigned long code, |
| 177 | unsigned long address) | 201 | unsigned long address) |
| 178 | { | 202 | { |
| @@ -270,16 +294,8 @@ bad_area: | |||
| 270 | if (user_mode(regs)) { | 294 | if (user_mode(regs)) { |
| 271 | struct siginfo si; | 295 | struct siginfo si; |
| 272 | 296 | ||
| 273 | #ifdef PRINT_USER_FAULTS | 297 | show_signal_msg(regs, code, address, tsk, vma); |
| 274 | printk(KERN_DEBUG "\n"); | 298 | |
| 275 | printk(KERN_DEBUG "do_page_fault() pid=%d command='%s' type=%lu address=0x%08lx\n", | ||
| 276 | task_pid_nr(tsk), tsk->comm, code, address); | ||
| 277 | if (vma) { | ||
| 278 | printk(KERN_DEBUG "vm_start = 0x%08lx, vm_end = 0x%08lx\n", | ||
| 279 | vma->vm_start, vma->vm_end); | ||
| 280 | } | ||
| 281 | show_regs(regs); | ||
| 282 | #endif | ||
| 283 | switch (code) { | 299 | switch (code) { |
| 284 | case 15: /* Data TLB miss fault/Data page fault */ | 300 | case 15: /* Data TLB miss fault/Data page fault */ |
| 285 | /* send SIGSEGV when outside of vma */ | 301 | /* send SIGSEGV when outside of vma */ |
