diff options
Diffstat (limited to 'arch/parisc')
-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 */ |