|
@@ -272,12 +272,9 @@ give_sigsegv:
|
|
|
*/
|
|
|
|
|
|
static inline void __user *
|
|
|
-get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size)
|
|
|
+get_sigframe(struct ksignal *ksig, unsigned long sp, size_t frame_size)
|
|
|
{
|
|
|
- if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! sas_ss_flags(sp))
|
|
|
- sp = current->sas_ss_sp + current->sas_ss_size;
|
|
|
-
|
|
|
- return (void __user *)((sp - frame_size) & -32ul);
|
|
|
+ return (void __user *)((sigsp(sp, ksig) - frame_size) & -32ul);
|
|
|
}
|
|
|
|
|
|
static long
|
|
@@ -338,14 +335,13 @@ setup_sigcontext(struct sigcontext __user *sc, struct pt_regs *regs,
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
-setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
|
|
|
- struct pt_regs *regs)
|
|
|
+setup_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
|
|
|
{
|
|
|
unsigned long oldsp, r26, err = 0;
|
|
|
struct sigframe __user *frame;
|
|
|
|
|
|
oldsp = rdusp();
|
|
|
- frame = get_sigframe(ka, oldsp, sizeof(*frame));
|
|
|
+ frame = get_sigframe(ksig, oldsp, sizeof(*frame));
|
|
|
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
|
|
return -EFAULT;
|
|
|
|
|
@@ -355,9 +351,8 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
|
|
|
|
|
|
/* Set up to return from userspace. If provided, use a stub
|
|
|
already in userspace. */
|
|
|
- if (ka->ka_restorer) {
|
|
|
- r26 = (unsigned long) ka->ka_restorer;
|
|
|
- } else {
|
|
|
+ r26 = (unsigned long) ksig->ka.ka_restorer;
|
|
|
+ if (!r26) {
|
|
|
err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0);
|
|
|
err |= __put_user(INSN_LDI_R0+__NR_sigreturn, frame->retcode+1);
|
|
|
err |= __put_user(INSN_CALLSYS, frame->retcode+2);
|
|
@@ -371,8 +366,8 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
|
|
|
|
|
|
/* "Return" to the handler */
|
|
|
regs->r26 = r26;
|
|
|
- regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler;
|
|
|
- regs->r16 = sig; /* a0: signal number */
|
|
|
+ regs->r27 = regs->pc = (unsigned long) ksig->ka.sa.sa_handler;
|
|
|
+ regs->r16 = ksig->sig; /* a0: signal number */
|
|
|
regs->r17 = 0; /* a1: exception code */
|
|
|
regs->r18 = (unsigned long) &frame->sc; /* a2: sigcontext pointer */
|
|
|
wrusp((unsigned long) frame);
|
|
@@ -385,18 +380,17 @@ setup_frame(int sig, struct k_sigaction *ka, sigset_t *set,
|
|
|
}
|
|
|
|
|
|
static int
|
|
|
-setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|
|
- sigset_t *set, struct pt_regs *regs)
|
|
|
+setup_rt_frame(struct ksignal *ksig, sigset_t *set, struct pt_regs *regs)
|
|
|
{
|
|
|
unsigned long oldsp, r26, err = 0;
|
|
|
struct rt_sigframe __user *frame;
|
|
|
|
|
|
oldsp = rdusp();
|
|
|
- frame = get_sigframe(ka, oldsp, sizeof(*frame));
|
|
|
+ frame = get_sigframe(ksig, oldsp, sizeof(*frame));
|
|
|
if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame)))
|
|
|
return -EFAULT;
|
|
|
|
|
|
- err |= copy_siginfo_to_user(&frame->info, info);
|
|
|
+ err |= copy_siginfo_to_user(&frame->info, &ksig->info);
|
|
|
|
|
|
/* Create the ucontext. */
|
|
|
err |= __put_user(0, &frame->uc.uc_flags);
|
|
@@ -411,9 +405,8 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|
|
|
|
|
/* Set up to return from userspace. If provided, use a stub
|
|
|
already in userspace. */
|
|
|
- if (ka->ka_restorer) {
|
|
|
- r26 = (unsigned long) ka->ka_restorer;
|
|
|
- } else {
|
|
|
+ r26 = (unsigned long) ksig->ka.ka_restorer;
|
|
|
+ if (!r26) {
|
|
|
err |= __put_user(INSN_MOV_R30_R16, frame->retcode+0);
|
|
|
err |= __put_user(INSN_LDI_R0+__NR_rt_sigreturn,
|
|
|
frame->retcode+1);
|
|
@@ -427,8 +420,8 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|
|
|
|
|
/* "Return" to the handler */
|
|
|
regs->r26 = r26;
|
|
|
- regs->r27 = regs->pc = (unsigned long) ka->sa.sa_handler;
|
|
|
- regs->r16 = sig; /* a0: signal number */
|
|
|
+ regs->r27 = regs->pc = (unsigned long) ksig->ka.sa.sa_handler;
|
|
|
+ regs->r16 = ksig->sig; /* a0: signal number */
|
|
|
regs->r17 = (unsigned long) &frame->info; /* a1: siginfo pointer */
|
|
|
regs->r18 = (unsigned long) &frame->uc; /* a2: ucontext pointer */
|
|
|
wrusp((unsigned long) frame);
|
|
@@ -446,22 +439,17 @@ setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|
|
* OK, we're invoking a handler.
|
|
|
*/
|
|
|
static inline void
|
|
|
-handle_signal(int sig, struct k_sigaction *ka, siginfo_t *info,
|
|
|
- struct pt_regs * regs)
|
|
|
+handle_signal(struct ksignal *ksig, struct pt_regs *regs)
|
|
|
{
|
|
|
sigset_t *oldset = sigmask_to_save();
|
|
|
int ret;
|
|
|
|
|
|
- if (ka->sa.sa_flags & SA_SIGINFO)
|
|
|
- ret = setup_rt_frame(sig, ka, info, oldset, regs);
|
|
|
+ if (ksig->ka.sa.sa_flags & SA_SIGINFO)
|
|
|
+ ret = setup_rt_frame(ksig, oldset, regs);
|
|
|
else
|
|
|
- ret = setup_frame(sig, ka, oldset, regs);
|
|
|
+ ret = setup_frame(ksig, oldset, regs);
|
|
|
|
|
|
- if (ret) {
|
|
|
- force_sigsegv(sig, current);
|
|
|
- return;
|
|
|
- }
|
|
|
- signal_delivered(sig, info, ka, regs, 0);
|
|
|
+ signal_setup_done(ret, ksig, 0);
|
|
|
}
|
|
|
|
|
|
static inline void
|
|
@@ -504,47 +492,38 @@ syscall_restart(unsigned long r0, unsigned long r19,
|
|
|
static void
|
|
|
do_signal(struct pt_regs *regs, unsigned long r0, unsigned long r19)
|
|
|
{
|
|
|
- siginfo_t info;
|
|
|
- int signr;
|
|
|
unsigned long single_stepping = ptrace_cancel_bpt(current);
|
|
|
- struct k_sigaction ka;
|
|
|
+ struct ksignal ksig;
|
|
|
|
|
|
/* This lets the debugger run, ... */
|
|
|
- signr = get_signal_to_deliver(&info, &ka, regs, NULL);
|
|
|
-
|
|
|
- /* ... so re-check the single stepping. */
|
|
|
- single_stepping |= ptrace_cancel_bpt(current);
|
|
|
-
|
|
|
- if (signr > 0) {
|
|
|
+ if (get_signal(&ksig)) {
|
|
|
+ /* ... so re-check the single stepping. */
|
|
|
+ single_stepping |= ptrace_cancel_bpt(current);
|
|
|
/* Whee! Actually deliver the signal. */
|
|
|
if (r0)
|
|
|
- syscall_restart(r0, r19, regs, &ka);
|
|
|
- handle_signal(signr, &ka, &info, regs);
|
|
|
- if (single_stepping)
|
|
|
- ptrace_set_bpt(current); /* re-set bpt */
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (r0) {
|
|
|
- switch (regs->r0) {
|
|
|
- case ERESTARTNOHAND:
|
|
|
- case ERESTARTSYS:
|
|
|
- case ERESTARTNOINTR:
|
|
|
- /* Reset v0 and a3 and replay syscall. */
|
|
|
- regs->r0 = r0;
|
|
|
- regs->r19 = r19;
|
|
|
- regs->pc -= 4;
|
|
|
- break;
|
|
|
- case ERESTART_RESTARTBLOCK:
|
|
|
- /* Force v0 to the restart syscall and reply. */
|
|
|
- regs->r0 = __NR_restart_syscall;
|
|
|
- regs->pc -= 4;
|
|
|
- break;
|
|
|
+ syscall_restart(r0, r19, regs, &ksig.ka);
|
|
|
+ handle_signal(&ksig, regs);
|
|
|
+ } else {
|
|
|
+ single_stepping |= ptrace_cancel_bpt(current);
|
|
|
+ if (r0) {
|
|
|
+ switch (regs->r0) {
|
|
|
+ case ERESTARTNOHAND:
|
|
|
+ case ERESTARTSYS:
|
|
|
+ case ERESTARTNOINTR:
|
|
|
+ /* Reset v0 and a3 and replay syscall. */
|
|
|
+ regs->r0 = r0;
|
|
|
+ regs->r19 = r19;
|
|
|
+ regs->pc -= 4;
|
|
|
+ break;
|
|
|
+ case ERESTART_RESTARTBLOCK:
|
|
|
+ /* Set v0 to the restart_syscall and replay */
|
|
|
+ regs->r0 = __NR_restart_syscall;
|
|
|
+ regs->pc -= 4;
|
|
|
+ break;
|
|
|
+ }
|
|
|
}
|
|
|
+ restore_saved_sigmask();
|
|
|
}
|
|
|
-
|
|
|
- /* If there's no signal to deliver, we just restore the saved mask. */
|
|
|
- restore_saved_sigmask();
|
|
|
if (single_stepping)
|
|
|
ptrace_set_bpt(current); /* re-set breakpoint */
|
|
|
}
|