diff options
Diffstat (limited to 'arch/sparc/kernel/signal_32.c')
| -rw-r--r-- | arch/sparc/kernel/signal_32.c | 55 | 
1 files changed, 35 insertions, 20 deletions
diff --git a/arch/sparc/kernel/signal_32.c b/arch/sparc/kernel/signal_32.c index 9882df92ba0a..5e5c5fd03783 100644 --- a/arch/sparc/kernel/signal_32.c +++ b/arch/sparc/kernel/signal_32.c  | |||
| @@ -315,8 +315,8 @@ save_fpu_state(struct pt_regs *regs, __siginfo_fpu_t __user *fpu) | |||
| 315 | return err; | 315 | return err; | 
| 316 | } | 316 | } | 
| 317 | 317 | ||
| 318 | static void setup_frame(struct k_sigaction *ka, struct pt_regs *regs, | 318 | static int setup_frame(struct k_sigaction *ka, struct pt_regs *regs, | 
| 319 | int signo, sigset_t *oldset) | 319 | int signo, sigset_t *oldset) | 
| 320 | { | 320 | { | 
| 321 | struct signal_frame __user *sf; | 321 | struct signal_frame __user *sf; | 
| 322 | int sigframe_size, err; | 322 | int sigframe_size, err; | 
| @@ -384,16 +384,19 @@ static void setup_frame(struct k_sigaction *ka, struct pt_regs *regs, | |||
| 384 | /* Flush instruction space. */ | 384 | /* Flush instruction space. */ | 
| 385 | flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); | 385 | flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); | 
| 386 | } | 386 | } | 
| 387 | return; | 387 | return 0; | 
| 388 | 388 | ||
| 389 | sigill_and_return: | 389 | sigill_and_return: | 
| 390 | do_exit(SIGILL); | 390 | do_exit(SIGILL); | 
| 391 | return -EINVAL; | ||
| 392 | |||
| 391 | sigsegv: | 393 | sigsegv: | 
| 392 | force_sigsegv(signo, current); | 394 | force_sigsegv(signo, current); | 
| 395 | return -EFAULT; | ||
| 393 | } | 396 | } | 
| 394 | 397 | ||
| 395 | static void setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, | 398 | static int setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, | 
| 396 | int signo, sigset_t *oldset, siginfo_t *info) | 399 | int signo, sigset_t *oldset, siginfo_t *info) | 
| 397 | { | 400 | { | 
| 398 | struct rt_signal_frame __user *sf; | 401 | struct rt_signal_frame __user *sf; | 
| 399 | int sigframe_size; | 402 | int sigframe_size; | 
| @@ -466,22 +469,30 @@ static void setup_rt_frame(struct k_sigaction *ka, struct pt_regs *regs, | |||
| 466 | /* Flush instruction space. */ | 469 | /* Flush instruction space. */ | 
| 467 | flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); | 470 | flush_sig_insns(current->mm, (unsigned long) &(sf->insns[0])); | 
| 468 | } | 471 | } | 
| 469 | return; | 472 | return 0; | 
| 470 | 473 | ||
| 471 | sigill: | 474 | sigill: | 
| 472 | do_exit(SIGILL); | 475 | do_exit(SIGILL); | 
| 476 | return -EINVAL; | ||
| 477 | |||
| 473 | sigsegv: | 478 | sigsegv: | 
| 474 | force_sigsegv(signo, current); | 479 | force_sigsegv(signo, current); | 
| 480 | return -EFAULT; | ||
| 475 | } | 481 | } | 
| 476 | 482 | ||
| 477 | static inline void | 483 | static inline int | 
| 478 | handle_signal(unsigned long signr, struct k_sigaction *ka, | 484 | handle_signal(unsigned long signr, struct k_sigaction *ka, | 
| 479 | siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) | 485 | siginfo_t *info, sigset_t *oldset, struct pt_regs *regs) | 
| 480 | { | 486 | { | 
| 487 | int err; | ||
| 488 | |||
| 481 | if (ka->sa.sa_flags & SA_SIGINFO) | 489 | if (ka->sa.sa_flags & SA_SIGINFO) | 
| 482 | setup_rt_frame(ka, regs, signr, oldset, info); | 490 | err = setup_rt_frame(ka, regs, signr, oldset, info); | 
| 483 | else | 491 | else | 
| 484 | setup_frame(ka, regs, signr, oldset); | 492 | err = setup_frame(ka, regs, signr, oldset); | 
| 493 | |||
| 494 | if (err) | ||
| 495 | return err; | ||
| 485 | 496 | ||
| 486 | spin_lock_irq(¤t->sighand->siglock); | 497 | spin_lock_irq(¤t->sighand->siglock); | 
| 487 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 498 | sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); | 
| @@ -489,6 +500,10 @@ handle_signal(unsigned long signr, struct k_sigaction *ka, | |||
| 489 | sigaddset(¤t->blocked, signr); | 500 | sigaddset(¤t->blocked, signr); | 
| 490 | recalc_sigpending(); | 501 | recalc_sigpending(); | 
| 491 | spin_unlock_irq(¤t->sighand->siglock); | 502 | spin_unlock_irq(¤t->sighand->siglock); | 
| 503 | |||
| 504 | tracehook_signal_handler(signr, info, ka, regs, 0); | ||
| 505 | |||
| 506 | return 0; | ||
| 492 | } | 507 | } | 
| 493 | 508 | ||
| 494 | static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, | 509 | static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, | 
| @@ -546,17 +561,15 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) | |||
| 546 | if (signr > 0) { | 561 | if (signr > 0) { | 
| 547 | if (restart_syscall) | 562 | if (restart_syscall) | 
| 548 | syscall_restart(orig_i0, regs, &ka.sa); | 563 | syscall_restart(orig_i0, regs, &ka.sa); | 
| 549 | handle_signal(signr, &ka, &info, oldset, regs); | 564 | if (handle_signal(signr, &ka, &info, oldset, regs) == 0) { | 
| 550 | 565 | /* a signal was successfully delivered; the saved | |
| 551 | /* a signal was successfully delivered; the saved | 566 | * sigmask will have been stored in the signal frame, | 
| 552 | * sigmask will have been stored in the signal frame, | 567 | * and will be restored by sigreturn, so we can simply | 
| 553 | * and will be restored by sigreturn, so we can simply | 568 | * clear the TIF_RESTORE_SIGMASK flag. | 
| 554 | * clear the TIF_RESTORE_SIGMASK flag. | 569 | */ | 
| 555 | */ | 570 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 
| 556 | if (test_thread_flag(TIF_RESTORE_SIGMASK)) | 571 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 
| 557 | clear_thread_flag(TIF_RESTORE_SIGMASK); | 572 | } | 
| 558 | |||
| 559 | tracehook_signal_handler(signr, &info, &ka, regs, 0); | ||
| 560 | return; | 573 | return; | 
| 561 | } | 574 | } | 
| 562 | if (restart_syscall && | 575 | if (restart_syscall && | 
| @@ -567,12 +580,14 @@ static void do_signal(struct pt_regs *regs, unsigned long orig_i0) | |||
| 567 | regs->u_regs[UREG_I0] = orig_i0; | 580 | regs->u_regs[UREG_I0] = orig_i0; | 
| 568 | regs->pc -= 4; | 581 | regs->pc -= 4; | 
| 569 | regs->npc -= 4; | 582 | regs->npc -= 4; | 
| 583 | pt_regs_clear_syscall(regs); | ||
| 570 | } | 584 | } | 
| 571 | if (restart_syscall && | 585 | if (restart_syscall && | 
| 572 | regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { | 586 | regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { | 
| 573 | regs->u_regs[UREG_G1] = __NR_restart_syscall; | 587 | regs->u_regs[UREG_G1] = __NR_restart_syscall; | 
| 574 | regs->pc -= 4; | 588 | regs->pc -= 4; | 
| 575 | regs->npc -= 4; | 589 | regs->npc -= 4; | 
| 590 | pt_regs_clear_syscall(regs); | ||
| 576 | } | 591 | } | 
| 577 | 592 | ||
| 578 | /* if there's no signal to deliver, we just put the saved sigmask | 593 | /* if there's no signal to deliver, we just put the saved sigmask | 
