diff options
| -rw-r--r-- | arch/tile/include/asm/processor.h | 7 | ||||
| -rw-r--r-- | arch/tile/include/asm/signal.h | 4 | ||||
| -rw-r--r-- | arch/tile/kernel/compat_signal.c | 4 | ||||
| -rw-r--r-- | arch/tile/kernel/signal.c | 128 | ||||
| -rw-r--r-- | arch/tile/kernel/single_step.c | 4 | ||||
| -rw-r--r-- | arch/tile/kernel/traps.c | 1 | ||||
| -rw-r--r-- | arch/tile/mm/fault.c | 24 | ||||
| -rw-r--r-- | kernel/sysctl.c | 2 |
8 files changed, 151 insertions, 23 deletions
diff --git a/arch/tile/include/asm/processor.h b/arch/tile/include/asm/processor.h index d6b43ddfcc04..34c1e01ffb5e 100644 --- a/arch/tile/include/asm/processor.h +++ b/arch/tile/include/asm/processor.h | |||
| @@ -257,10 +257,6 @@ static inline void cpu_relax(void) | |||
| 257 | barrier(); | 257 | barrier(); |
| 258 | } | 258 | } |
| 259 | 259 | ||
| 260 | struct siginfo; | ||
| 261 | extern void arch_coredump_signal(struct siginfo *, struct pt_regs *); | ||
| 262 | #define arch_coredump_signal arch_coredump_signal | ||
| 263 | |||
| 264 | /* Info on this processor (see fs/proc/cpuinfo.c) */ | 260 | /* Info on this processor (see fs/proc/cpuinfo.c) */ |
| 265 | struct seq_operations; | 261 | struct seq_operations; |
| 266 | extern const struct seq_operations cpuinfo_op; | 262 | extern const struct seq_operations cpuinfo_op; |
| @@ -271,9 +267,6 @@ extern char chip_model[64]; | |||
| 271 | /* Data on which physical memory controller corresponds to which NUMA node. */ | 267 | /* Data on which physical memory controller corresponds to which NUMA node. */ |
| 272 | extern int node_controller[]; | 268 | extern int node_controller[]; |
| 273 | 269 | ||
| 274 | /* Do we dump information to the console when a user application crashes? */ | ||
| 275 | extern int show_crashinfo; | ||
| 276 | |||
| 277 | #if CHIP_HAS_CBOX_HOME_MAP() | 270 | #if CHIP_HAS_CBOX_HOME_MAP() |
| 278 | /* Does the heap allocator return hash-for-home pages by default? */ | 271 | /* Does the heap allocator return hash-for-home pages by default? */ |
| 279 | extern int hash_default; | 272 | extern int hash_default; |
diff --git a/arch/tile/include/asm/signal.h b/arch/tile/include/asm/signal.h index 81d92a45cd4b..1e1e616783eb 100644 --- a/arch/tile/include/asm/signal.h +++ b/arch/tile/include/asm/signal.h | |||
| @@ -28,6 +28,10 @@ struct pt_regs; | |||
| 28 | int restore_sigcontext(struct pt_regs *, struct sigcontext __user *); | 28 | int restore_sigcontext(struct pt_regs *, struct sigcontext __user *); |
| 29 | int setup_sigcontext(struct sigcontext __user *, struct pt_regs *); | 29 | int setup_sigcontext(struct sigcontext __user *, struct pt_regs *); |
| 30 | void do_signal(struct pt_regs *regs); | 30 | void do_signal(struct pt_regs *regs); |
| 31 | void signal_fault(const char *type, struct pt_regs *, | ||
| 32 | void __user *frame, int sig); | ||
| 33 | void trace_unhandled_signal(const char *type, struct pt_regs *regs, | ||
| 34 | unsigned long address, int signo); | ||
| 31 | #endif | 35 | #endif |
| 32 | 36 | ||
| 33 | #endif /* _ASM_TILE_SIGNAL_H */ | 37 | #endif /* _ASM_TILE_SIGNAL_H */ |
diff --git a/arch/tile/kernel/compat_signal.c b/arch/tile/kernel/compat_signal.c index dbb0dfc7bece..a7869ad62776 100644 --- a/arch/tile/kernel/compat_signal.c +++ b/arch/tile/kernel/compat_signal.c | |||
| @@ -317,7 +317,7 @@ long compat_sys_rt_sigreturn(struct pt_regs *regs) | |||
| 317 | return 0; | 317 | return 0; |
| 318 | 318 | ||
| 319 | badframe: | 319 | badframe: |
| 320 | force_sig(SIGSEGV, current); | 320 | signal_fault("bad sigreturn frame", regs, frame, 0); |
| 321 | return 0; | 321 | return 0; |
| 322 | } | 322 | } |
| 323 | 323 | ||
| @@ -431,6 +431,6 @@ int compat_setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 431 | return 0; | 431 | return 0; |
| 432 | 432 | ||
| 433 | give_sigsegv: | 433 | give_sigsegv: |
| 434 | force_sigsegv(sig, current); | 434 | signal_fault("bad setup frame", regs, frame, sig); |
| 435 | return -EFAULT; | 435 | return -EFAULT; |
| 436 | } | 436 | } |
diff --git a/arch/tile/kernel/signal.c b/arch/tile/kernel/signal.c index 1260321155f1..bedaf4e9f3a7 100644 --- a/arch/tile/kernel/signal.c +++ b/arch/tile/kernel/signal.c | |||
| @@ -39,7 +39,6 @@ | |||
| 39 | 39 | ||
| 40 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) | 40 | #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP))) |
| 41 | 41 | ||
| 42 | |||
| 43 | SYSCALL_DEFINE3(sigaltstack, const stack_t __user *, uss, | 42 | SYSCALL_DEFINE3(sigaltstack, const stack_t __user *, uss, |
| 44 | stack_t __user *, uoss, struct pt_regs *, regs) | 43 | stack_t __user *, uoss, struct pt_regs *, regs) |
| 45 | { | 44 | { |
| @@ -78,6 +77,13 @@ int restore_sigcontext(struct pt_regs *regs, | |||
| 78 | return err; | 77 | return err; |
| 79 | } | 78 | } |
| 80 | 79 | ||
| 80 | void signal_fault(const char *type, struct pt_regs *regs, | ||
| 81 | void __user *frame, int sig) | ||
| 82 | { | ||
| 83 | trace_unhandled_signal(type, regs, (unsigned long)frame, SIGSEGV); | ||
| 84 | force_sigsegv(sig, current); | ||
| 85 | } | ||
| 86 | |||
| 81 | /* The assembly shim for this function arranges to ignore the return value. */ | 87 | /* The assembly shim for this function arranges to ignore the return value. */ |
| 82 | SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs) | 88 | SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs) |
| 83 | { | 89 | { |
| @@ -105,7 +111,7 @@ SYSCALL_DEFINE1(rt_sigreturn, struct pt_regs *, regs) | |||
| 105 | return 0; | 111 | return 0; |
| 106 | 112 | ||
| 107 | badframe: | 113 | badframe: |
| 108 | force_sig(SIGSEGV, current); | 114 | signal_fault("bad sigreturn frame", regs, frame, 0); |
| 109 | return 0; | 115 | return 0; |
| 110 | } | 116 | } |
| 111 | 117 | ||
| @@ -231,7 +237,7 @@ static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, | |||
| 231 | return 0; | 237 | return 0; |
| 232 | 238 | ||
| 233 | give_sigsegv: | 239 | give_sigsegv: |
| 234 | force_sigsegv(sig, current); | 240 | signal_fault("bad setup frame", regs, frame, sig); |
| 235 | return -EFAULT; | 241 | return -EFAULT; |
| 236 | } | 242 | } |
| 237 | 243 | ||
| @@ -245,7 +251,6 @@ static int handle_signal(unsigned long sig, siginfo_t *info, | |||
| 245 | { | 251 | { |
| 246 | int ret; | 252 | int ret; |
| 247 | 253 | ||
| 248 | |||
| 249 | /* Are we from a system call? */ | 254 | /* Are we from a system call? */ |
| 250 | if (regs->faultnum == INT_SWINT_1) { | 255 | if (regs->faultnum == INT_SWINT_1) { |
| 251 | /* If so, check system call restarting.. */ | 256 | /* If so, check system call restarting.. */ |
| @@ -363,3 +368,118 @@ done: | |||
| 363 | /* Avoid double syscall restart if there are nested signals. */ | 368 | /* Avoid double syscall restart if there are nested signals. */ |
| 364 | regs->faultnum = INT_SWINT_1_SIGRETURN; | 369 | regs->faultnum = INT_SWINT_1_SIGRETURN; |
| 365 | } | 370 | } |
| 371 | |||
| 372 | int show_unhandled_signals = 1; | ||
| 373 | |||
| 374 | static int __init crashinfo(char *str) | ||
| 375 | { | ||
| 376 | unsigned long val; | ||
| 377 | const char *word; | ||
| 378 | |||
| 379 | if (*str == '\0') | ||
| 380 | val = 2; | ||
| 381 | else if (*str != '=' || strict_strtoul(++str, 0, &val) != 0) | ||
| 382 | return 0; | ||
| 383 | show_unhandled_signals = val; | ||
| 384 | switch (show_unhandled_signals) { | ||
| 385 | case 0: | ||
| 386 | word = "No"; | ||
| 387 | break; | ||
| 388 | case 1: | ||
| 389 | word = "One-line"; | ||
| 390 | break; | ||
| 391 | default: | ||
| 392 | word = "Detailed"; | ||
| 393 | break; | ||
| 394 | } | ||
| 395 | pr_info("%s crash reports will be generated on the console\n", word); | ||
| 396 | return 1; | ||
| 397 | } | ||
| 398 | __setup("crashinfo", crashinfo); | ||
| 399 | |||
| 400 | static void dump_mem(void __user *address) | ||
| 401 | { | ||
| 402 | void __user *addr; | ||
| 403 | enum { region_size = 256, bytes_per_line = 16 }; | ||
| 404 | int i, j, k; | ||
| 405 | int found_readable_mem = 0; | ||
| 406 | |||
| 407 | pr_err("\n"); | ||
| 408 | if (!access_ok(VERIFY_READ, address, 1)) { | ||
| 409 | pr_err("Not dumping at address 0x%lx (kernel address)\n", | ||
| 410 | (unsigned long)address); | ||
| 411 | return; | ||
| 412 | } | ||
| 413 | |||
| 414 | addr = (void __user *) | ||
| 415 | (((unsigned long)address & -bytes_per_line) - region_size/2); | ||
| 416 | if (addr > address) | ||
| 417 | addr = NULL; | ||
| 418 | for (i = 0; i < region_size; | ||
| 419 | addr += bytes_per_line, i += bytes_per_line) { | ||
| 420 | unsigned char buf[bytes_per_line]; | ||
| 421 | char line[100]; | ||
| 422 | if (copy_from_user(buf, addr, bytes_per_line)) | ||
| 423 | continue; | ||
| 424 | if (!found_readable_mem) { | ||
| 425 | pr_err("Dumping memory around address 0x%lx:\n", | ||
| 426 | (unsigned long)address); | ||
| 427 | found_readable_mem = 1; | ||
| 428 | } | ||
| 429 | j = sprintf(line, REGFMT":", (unsigned long)addr); | ||
| 430 | for (k = 0; k < bytes_per_line; ++k) | ||
| 431 | j += sprintf(&line[j], " %02x", buf[k]); | ||
| 432 | pr_err("%s\n", line); | ||
| 433 | } | ||
| 434 | if (!found_readable_mem) | ||
| 435 | pr_err("No readable memory around address 0x%lx\n", | ||
| 436 | (unsigned long)address); | ||
| 437 | } | ||
| 438 | |||
| 439 | void trace_unhandled_signal(const char *type, struct pt_regs *regs, | ||
| 440 | unsigned long address, int sig) | ||
| 441 | { | ||
| 442 | struct task_struct *tsk = current; | ||
| 443 | |||
| 444 | if (show_unhandled_signals == 0) | ||
| 445 | return; | ||
| 446 | |||
| 447 | /* If the signal is handled, don't show it here. */ | ||
| 448 | if (!is_global_init(tsk)) { | ||
| 449 | void __user *handler = | ||
| 450 | tsk->sighand->action[sig-1].sa.sa_handler; | ||
| 451 | if (handler != SIG_IGN && handler != SIG_DFL) | ||
| 452 | return; | ||
| 453 | } | ||
| 454 | |||
| 455 | /* Rate-limit the one-line output, not the detailed output. */ | ||
| 456 | if (show_unhandled_signals <= 1 && !printk_ratelimit()) | ||
| 457 | return; | ||
| 458 | |||
| 459 | printk("%s%s[%d]: %s at %lx pc "REGFMT" signal %d", | ||
| 460 | task_pid_nr(tsk) > 1 ? KERN_INFO : KERN_EMERG, | ||
| 461 | tsk->comm, task_pid_nr(tsk), type, address, regs->pc, sig); | ||
| 462 | |||
| 463 | print_vma_addr(KERN_CONT " in ", regs->pc); | ||
| 464 | |||
| 465 | printk(KERN_CONT "\n"); | ||
| 466 | |||
| 467 | if (show_unhandled_signals > 1) { | ||
| 468 | switch (sig) { | ||
| 469 | case SIGILL: | ||
| 470 | case SIGFPE: | ||
| 471 | case SIGSEGV: | ||
| 472 | case SIGBUS: | ||
| 473 | pr_err("User crash: signal %d," | ||
| 474 | " trap %ld, address 0x%lx\n", | ||
| 475 | sig, regs->faultnum, address); | ||
| 476 | show_regs(regs); | ||
| 477 | dump_mem((void __user *)address); | ||
| 478 | break; | ||
| 479 | default: | ||
| 480 | pr_err("User crash: signal %d, trap %ld\n", | ||
| 481 | sig, regs->faultnum); | ||
| 482 | break; | ||
| 483 | } | ||
| 484 | } | ||
| 485 | } | ||
diff --git a/arch/tile/kernel/single_step.c b/arch/tile/kernel/single_step.c index 86df5a239b70..4032ca8e51b6 100644 --- a/arch/tile/kernel/single_step.c +++ b/arch/tile/kernel/single_step.c | |||
| @@ -186,6 +186,8 @@ static tile_bundle_bits rewrite_load_store_unaligned( | |||
| 186 | .si_code = SEGV_MAPERR, | 186 | .si_code = SEGV_MAPERR, |
| 187 | .si_addr = addr | 187 | .si_addr = addr |
| 188 | }; | 188 | }; |
| 189 | trace_unhandled_signal("segfault", regs, | ||
| 190 | (unsigned long)addr, SIGSEGV); | ||
| 189 | force_sig_info(info.si_signo, &info, current); | 191 | force_sig_info(info.si_signo, &info, current); |
| 190 | return (tile_bundle_bits) 0; | 192 | return (tile_bundle_bits) 0; |
| 191 | } | 193 | } |
| @@ -196,6 +198,8 @@ static tile_bundle_bits rewrite_load_store_unaligned( | |||
| 196 | .si_code = BUS_ADRALN, | 198 | .si_code = BUS_ADRALN, |
| 197 | .si_addr = addr | 199 | .si_addr = addr |
| 198 | }; | 200 | }; |
| 201 | trace_unhandled_signal("unaligned trap", regs, | ||
| 202 | (unsigned long)addr, SIGBUS); | ||
| 199 | force_sig_info(info.si_signo, &info, current); | 203 | force_sig_info(info.si_signo, &info, current); |
| 200 | return (tile_bundle_bits) 0; | 204 | return (tile_bundle_bits) 0; |
| 201 | } | 205 | } |
diff --git a/arch/tile/kernel/traps.c b/arch/tile/kernel/traps.c index 5474fc2e77e8..f9803dfa7357 100644 --- a/arch/tile/kernel/traps.c +++ b/arch/tile/kernel/traps.c | |||
| @@ -308,6 +308,7 @@ void __kprobes do_trap(struct pt_regs *regs, int fault_num, | |||
| 308 | info.si_addr = (void __user *)address; | 308 | info.si_addr = (void __user *)address; |
| 309 | if (signo == SIGILL) | 309 | if (signo == SIGILL) |
| 310 | info.si_trapno = fault_num; | 310 | info.si_trapno = fault_num; |
| 311 | trace_unhandled_signal("trap", regs, address, signo); | ||
| 311 | force_sig_info(signo, &info, current); | 312 | force_sig_info(signo, &info, current); |
| 312 | } | 313 | } |
| 313 | 314 | ||
diff --git a/arch/tile/mm/fault.c b/arch/tile/mm/fault.c index 24ca54a0703b..25b7b90fd620 100644 --- a/arch/tile/mm/fault.c +++ b/arch/tile/mm/fault.c | |||
| @@ -43,8 +43,11 @@ | |||
| 43 | 43 | ||
| 44 | #include <arch/interrupts.h> | 44 | #include <arch/interrupts.h> |
| 45 | 45 | ||
| 46 | static noinline void force_sig_info_fault(int si_signo, int si_code, | 46 | static noinline void force_sig_info_fault(const char *type, int si_signo, |
| 47 | unsigned long address, int fault_num, struct task_struct *tsk) | 47 | int si_code, unsigned long address, |
| 48 | int fault_num, | ||
| 49 | struct task_struct *tsk, | ||
| 50 | struct pt_regs *regs) | ||
| 48 | { | 51 | { |
| 49 | siginfo_t info; | 52 | siginfo_t info; |
| 50 | 53 | ||
| @@ -59,6 +62,7 @@ static noinline void force_sig_info_fault(int si_signo, int si_code, | |||
| 59 | info.si_code = si_code; | 62 | info.si_code = si_code; |
| 60 | info.si_addr = (void __user *)address; | 63 | info.si_addr = (void __user *)address; |
| 61 | info.si_trapno = fault_num; | 64 | info.si_trapno = fault_num; |
| 65 | trace_unhandled_signal(type, regs, address, si_signo); | ||
| 62 | force_sig_info(si_signo, &info, tsk); | 66 | force_sig_info(si_signo, &info, tsk); |
| 63 | } | 67 | } |
| 64 | 68 | ||
| @@ -71,11 +75,12 @@ SYSCALL_DEFINE2(cmpxchg_badaddr, unsigned long, address, | |||
| 71 | struct pt_regs *, regs) | 75 | struct pt_regs *, regs) |
| 72 | { | 76 | { |
| 73 | if (address >= PAGE_OFFSET) | 77 | if (address >= PAGE_OFFSET) |
| 74 | force_sig_info_fault(SIGSEGV, SEGV_MAPERR, address, | 78 | force_sig_info_fault("atomic segfault", SIGSEGV, SEGV_MAPERR, |
| 75 | INT_DTLB_MISS, current); | 79 | address, INT_DTLB_MISS, current, regs); |
| 76 | else | 80 | else |
| 77 | force_sig_info_fault(SIGBUS, BUS_ADRALN, address, | 81 | force_sig_info_fault("atomic alignment fault", SIGBUS, |
| 78 | INT_UNALIGN_DATA, current); | 82 | BUS_ADRALN, address, |
| 83 | INT_UNALIGN_DATA, current, regs); | ||
| 79 | 84 | ||
| 80 | /* | 85 | /* |
| 81 | * Adjust pc to point at the actual instruction, which is unusual | 86 | * Adjust pc to point at the actual instruction, which is unusual |
| @@ -471,8 +476,8 @@ bad_area_nosemaphore: | |||
| 471 | */ | 476 | */ |
| 472 | local_irq_enable(); | 477 | local_irq_enable(); |
| 473 | 478 | ||
| 474 | force_sig_info_fault(SIGSEGV, si_code, address, | 479 | force_sig_info_fault("segfault", SIGSEGV, si_code, address, |
| 475 | fault_num, tsk); | 480 | fault_num, tsk, regs); |
| 476 | return 0; | 481 | return 0; |
| 477 | } | 482 | } |
| 478 | 483 | ||
| @@ -547,7 +552,8 @@ do_sigbus: | |||
| 547 | if (is_kernel_mode) | 552 | if (is_kernel_mode) |
| 548 | goto no_context; | 553 | goto no_context; |
| 549 | 554 | ||
| 550 | force_sig_info_fault(SIGBUS, BUS_ADRERR, address, fault_num, tsk); | 555 | force_sig_info_fault("bus error", SIGBUS, BUS_ADRERR, address, |
| 556 | fault_num, tsk, regs); | ||
| 551 | return 0; | 557 | return 0; |
| 552 | } | 558 | } |
| 553 | 559 | ||
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index c0bb32414b17..aaec9342a33c 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
| @@ -1496,7 +1496,7 @@ static struct ctl_table fs_table[] = { | |||
| 1496 | 1496 | ||
| 1497 | static struct ctl_table debug_table[] = { | 1497 | static struct ctl_table debug_table[] = { |
| 1498 | #if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) || \ | 1498 | #if defined(CONFIG_X86) || defined(CONFIG_PPC) || defined(CONFIG_SPARC) || \ |
| 1499 | defined(CONFIG_S390) | 1499 | defined(CONFIG_S390) || defined(CONFIG_TILE) |
| 1500 | { | 1500 | { |
| 1501 | .procname = "exception-trace", | 1501 | .procname = "exception-trace", |
| 1502 | .data = &show_unhandled_signals, | 1502 | .data = &show_unhandled_signals, |
