aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2006-01-06 03:11:44 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-01-06 11:33:33 -0500
commit8efc0ab50edbac5c65191b8a58dfdab3741b7901 (patch)
tree3598a874f715e89d475a9bc8a435a1096f19c58d /arch
parent7ee1dd3fee22f15728f545d266403fc977e1eb99 (diff)
[PATCH] frv: fix signal handling
The attached patch makes FRV signal handling work properly: (1) After do_notify_resume() has been called, the work flags must be checked again (there may be another signal to deliver or the process might require rescheduling for instance). (2) After the signal frame is set up on the userspace stack, ptrace() should be given an opportunity to single-step into the signal handler. (3) The error state from setting up a signal frame should be passed back up the call chain. (4) The segfault handler shouldn't be preemptively reset in the arch if we fail to deliver a SEGV signal: force_sig() will take care of that. Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/frv/kernel/entry.S2
-rw-r--r--arch/frv/kernel/signal.c73
2 files changed, 46 insertions, 29 deletions
diff --git a/arch/frv/kernel/entry.S b/arch/frv/kernel/entry.S
index ad10ea595459..5f6548388b74 100644
--- a/arch/frv/kernel/entry.S
+++ b/arch/frv/kernel/entry.S
@@ -1076,7 +1076,7 @@ __entry_work_notifysig:
1076 LEDS 0x6410 1076 LEDS 0x6410
1077 ori.p gr4,#0,gr8 1077 ori.p gr4,#0,gr8
1078 call do_notify_resume 1078 call do_notify_resume
1079 bra __entry_return_direct 1079 bra __entry_resume_userspace
1080 1080
1081 # perform syscall entry tracing 1081 # perform syscall entry tracing
1082__syscall_trace_entry: 1082__syscall_trace_entry:
diff --git a/arch/frv/kernel/signal.c b/arch/frv/kernel/signal.c
index d4ccc0728dfe..89a1cf5c076a 100644
--- a/arch/frv/kernel/signal.c
+++ b/arch/frv/kernel/signal.c
@@ -297,7 +297,8 @@ static inline void __user *get_sigframe(struct k_sigaction *ka,
297/* 297/*
298 * 298 *
299 */ 299 */
300static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs * regs) 300static int setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
301 struct pt_regs *regs)
301{ 302{
302 struct sigframe __user *frame; 303 struct sigframe __user *frame;
303 int rsig; 304 int rsig;
@@ -362,26 +363,30 @@ static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct p
362 363
363 set_fs(USER_DS); 364 set_fs(USER_DS);
364 365
366 /* the tracer may want to single-step inside the handler */
367 if (test_thread_flag(TIF_SINGLESTEP))
368 ptrace_notify(SIGTRAP);
369
365#if DEBUG_SIG 370#if DEBUG_SIG
366 printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", 371 printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
367 sig, current->comm, current->pid, frame, regs->pc, frame->pretcode); 372 sig, current->comm, current->pid, frame, regs->pc,
373 frame->pretcode);
368#endif 374#endif
369 375
370 return; 376 return 1;
371 377
372give_sigsegv: 378give_sigsegv:
373 if (sig == SIGSEGV)
374 ka->sa.sa_handler = SIG_DFL;
375
376 force_sig(SIGSEGV, current); 379 force_sig(SIGSEGV, current);
380 return 0;
381
377} /* end setup_frame() */ 382} /* end setup_frame() */
378 383
379/*****************************************************************************/ 384/*****************************************************************************/
380/* 385/*
381 * 386 *
382 */ 387 */
383static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, 388static int setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
384 sigset_t *set, struct pt_regs * regs) 389 sigset_t *set, struct pt_regs * regs)
385{ 390{
386 struct rt_sigframe __user *frame; 391 struct rt_sigframe __user *frame;
387 int rsig; 392 int rsig;
@@ -457,17 +462,21 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
457 462
458 set_fs(USER_DS); 463 set_fs(USER_DS);
459 464
465 /* the tracer may want to single-step inside the handler */
466 if (test_thread_flag(TIF_SINGLESTEP))
467 ptrace_notify(SIGTRAP);
468
460#if DEBUG_SIG 469#if DEBUG_SIG
461 printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n", 470 printk("SIG deliver %d (%s:%d): sp=%p pc=%lx ra=%p\n",
462 sig, current->comm, current->pid, frame, regs->pc, frame->pretcode); 471 sig, current->comm, current->pid, frame, regs->pc,
472 frame->pretcode);
463#endif 473#endif
464 474
465 return; 475 return 1;
466 476
467give_sigsegv: 477give_sigsegv:
468 if (sig == SIGSEGV)
469 ka->sa.sa_handler = SIG_DFL;
470 force_sig(SIGSEGV, current); 478 force_sig(SIGSEGV, current);
479 return 0;
471 480
472} /* end setup_rt_frame() */ 481} /* end setup_rt_frame() */
473 482
@@ -475,10 +484,12 @@ give_sigsegv:
475/* 484/*
476 * OK, we're invoking a handler 485 * OK, we're invoking a handler
477 */ 486 */
478static void handle_signal(unsigned long sig, siginfo_t *info, 487static int handle_signal(unsigned long sig, siginfo_t *info,
479 struct k_sigaction *ka, sigset_t *oldset, 488 struct k_sigaction *ka, sigset_t *oldset,
480 struct pt_regs *regs) 489 struct pt_regs *regs)
481{ 490{
491 int ret;
492
482 /* Are we from a system call? */ 493 /* Are we from a system call? */
483 if (in_syscall(regs)) { 494 if (in_syscall(regs)) {
484 /* If so, check system call restarting.. */ 495 /* If so, check system call restarting.. */
@@ -493,6 +504,7 @@ static void handle_signal(unsigned long sig, siginfo_t *info,
493 regs->gr8 = -EINTR; 504 regs->gr8 = -EINTR;
494 break; 505 break;
495 } 506 }
507
496 /* fallthrough */ 508 /* fallthrough */
497 case -ERESTARTNOINTR: 509 case -ERESTARTNOINTR:
498 regs->gr8 = regs->orig_gr8; 510 regs->gr8 = regs->orig_gr8;
@@ -502,16 +514,22 @@ static void handle_signal(unsigned long sig, siginfo_t *info,
502 514
503 /* Set up the stack frame */ 515 /* Set up the stack frame */
504 if (ka->sa.sa_flags & SA_SIGINFO) 516 if (ka->sa.sa_flags & SA_SIGINFO)
505 setup_rt_frame(sig, ka, info, oldset, regs); 517 ret = setup_rt_frame(sig, ka, info, oldset, regs);
506 else 518 else
507 setup_frame(sig, ka, oldset, regs); 519 ret = setup_frame(sig, ka, oldset, regs);
520
521 if (ret) {
522 spin_lock_irq(&current->sighand->siglock);
523 sigorsets(&current->blocked, &current->blocked,
524 &ka->sa.sa_mask);
525 if (!(ka->sa.sa_flags & SA_NODEFER))
526 sigaddset(&current->blocked, sig);
527 recalc_sigpending();
528 spin_unlock_irq(&current->sighand->siglock);
529 }
530
531 return ret;
508 532
509 spin_lock_irq(&current->sighand->siglock);
510 sigorsets(&current->blocked, &current->blocked, &ka->sa.sa_mask);
511 if (!(ka->sa.sa_flags & SA_NODEFER))
512 sigaddset(&current->blocked, sig);
513 recalc_sigpending();
514 spin_unlock_irq(&current->sighand->siglock);
515} /* end handle_signal() */ 533} /* end handle_signal() */
516 534
517/*****************************************************************************/ 535/*****************************************************************************/
@@ -542,12 +560,10 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
542 oldset = &current->blocked; 560 oldset = &current->blocked;
543 561
544 signr = get_signal_to_deliver(&info, &ka, regs, NULL); 562 signr = get_signal_to_deliver(&info, &ka, regs, NULL);
545 if (signr > 0) { 563 if (signr > 0)
546 handle_signal(signr, &info, &ka, oldset, regs); 564 return handle_signal(signr, &info, &ka, oldset, regs);
547 return 1;
548 }
549 565
550 no_signal: 566no_signal:
551 /* Did we come from a system call? */ 567 /* Did we come from a system call? */
552 if (regs->syscallno >= 0) { 568 if (regs->syscallno >= 0) {
553 /* Restart the system call - no handlers present */ 569 /* Restart the system call - no handlers present */
@@ -565,6 +581,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
565 } 581 }
566 582
567 return 0; 583 return 0;
584
568} /* end do_signal() */ 585} /* end do_signal() */
569 586
570/*****************************************************************************/ 587/*****************************************************************************/