📄 signal.c
字号:
err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int)); /* Store registers */ err |= __put_user(regs->pc, &((*gr)[SVR4_PC])); err |= __put_user(regs->npc, &((*gr)[SVR4_NPC])); err |= __put_user(regs->psr, &((*gr)[SVR4_PSR])); err |= __put_user(regs->y, &((*gr)[SVR4_Y])); /* Copy g[1..7] and o[0..7] registers */ err |= __copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs[UREG_G1], sizeof(long) * 7); err |= __copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs[UREG_I0], sizeof(long) * 8); /* Setup sigaltstack */ err |= __put_user(current->sas_ss_sp, &uc->stack.sp); err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags); err |= __put_user(current->sas_ss_size, &uc->stack.size); /* Save the currently window file: */ /* 1. Link sfp->uc->gwins to our windows */ err |= __put_user(gw, &mc->gwin); /* 2. Number of windows to restore at setcontext(): */ err |= __put_user(tp->w_saved, &gw->count); /* 3. Save each valid window * Currently, it makes a copy of the windows from the kernel copy. * David's code for SunOS, makes the copy but keeps the pointer to * the kernel. My version makes the pointer point to a userland * copy of those. Mhm, I wonder if I shouldn't just ignore those * on setcontext and use those that are on the kernel, the signal * handler should not be modyfing those, mhm. * * These windows are just used in case synchronize_user_stack failed * to flush the user windows. */ for (window = 0; window < tp->w_saved; window++) { err |= __put_user((int *) &(gw->win[window]), &gw->winptr[window]); err |= __copy_to_user(&gw->win[window], &tp->reg_window[window], sizeof(svr4_rwindow_t)); err |= __put_user(0, gw->winptr[window]); } /* 4. We just pay attention to the gw->count field on setcontext */ tp->w_saved = 0; /* So process is allowed to execute. */ /* Setup the signal information. Solaris expects a bunch of * information to be passed to the signal handler, we don't provide * that much currently, should use siginfo. */ err |= __put_user(signr, &si->siginfo.signo); err |= __put_user(SVR4_SINOINFO, &si->siginfo.code); if (err) goto sigsegv; regs->u_regs[UREG_FP] = (unsigned long) sfp; regs->pc = (unsigned long) sa->sa_handler; regs->npc = (regs->pc + 4); /* Arguments passed to signal handler */ if (regs->u_regs[14]){ struct reg_window __user *rw = (struct reg_window __user *) regs->u_regs[14]; err |= __put_user(signr, &rw->ins[0]); err |= __put_user(si, &rw->ins[1]); err |= __put_user(uc, &rw->ins[2]); err |= __put_user(sfp, &rw->ins[6]); /* frame pointer */ if (err) goto sigsegv; regs->u_regs[UREG_I0] = signr; regs->u_regs[UREG_I1] = (unsigned long) si; regs->u_regs[UREG_I2] = (unsigned long) uc; } return;sigill_and_return: do_exit(SIGILL);sigsegv: do_exit(SIGSEGV);}asmlinkage int svr4_getcontext(svr4_ucontext_t __user *uc, struct pt_regs *regs){ svr4_gregset_t __user *gr; svr4_mcontext_t __user *mc; svr4_sigset_t setv; int err = 0; synchronize_user_stack(); if (current_thread_info()->w_saved) goto sigsegv_and_return; err = clear_user(uc, sizeof(*uc)); if (err) return -EFAULT; /* Setup convenience variables */ mc = &uc->mcontext; gr = &mc->greg; setv.sigbits[0] = current->blocked.sig[0]; setv.sigbits[1] = current->blocked.sig[1]; if (_NSIG_WORDS >= 4) { setv.sigbits[2] = current->blocked.sig[2]; setv.sigbits[3] = current->blocked.sig[3]; err |= __copy_to_user(&uc->sigmask, &setv, sizeof(svr4_sigset_t)); } else err |= __copy_to_user(&uc->sigmask, &setv, 2 * sizeof(unsigned int)); /* Store registers */ err |= __put_user(regs->pc, &uc->mcontext.greg[SVR4_PC]); err |= __put_user(regs->npc, &uc->mcontext.greg[SVR4_NPC]); err |= __put_user(regs->psr, &uc->mcontext.greg[SVR4_PSR]); err |= __put_user(regs->y, &uc->mcontext.greg[SVR4_Y]); /* Copy g[1..7] and o[0..7] registers */ err |= __copy_to_user(&(*gr)[SVR4_G1], ®s->u_regs[UREG_G1], sizeof(uint) * 7); err |= __copy_to_user(&(*gr)[SVR4_O0], ®s->u_regs[UREG_I0], sizeof(uint) * 8); /* Setup sigaltstack */ err |= __put_user(current->sas_ss_sp, &uc->stack.sp); err |= __put_user(sas_ss_flags(regs->u_regs[UREG_FP]), &uc->stack.flags); err |= __put_user(current->sas_ss_size, &uc->stack.size); /* The register file is not saved * we have already stuffed all of it with sync_user_stack */ return (err ? -EFAULT : 0);sigsegv_and_return: do_exit(SIGSEGV);}/* Set the context for a svr4 application, this is Solaris way to sigreturn */asmlinkage int svr4_setcontext(svr4_ucontext_t __user *c, struct pt_regs *regs){ svr4_gregset_t __user *gr; unsigned long pc, npc, psr; mm_segment_t old_fs; sigset_t set; svr4_sigset_t setv; int err; stack_t st; /* Fixme: restore windows, or is this already taken care of in * svr4_setup_frame when sync_user_windows is done? */ flush_user_windows(); if (current_thread_info()->w_saved) goto sigsegv_and_return; if (((unsigned long) c) & 3) goto sigsegv_and_return; if (!__access_ok((unsigned long)c, sizeof(*c))) goto sigsegv_and_return; /* Check for valid PC and nPC */ gr = &c->mcontext.greg; err = __get_user(pc, &((*gr)[SVR4_PC])); err |= __get_user(npc, &((*gr)[SVR4_NPC])); if ((pc | npc) & 3) goto sigsegv_and_return; /* Retrieve information from passed ucontext */ /* note that nPC is ored a 1, this is used to inform entry.S */ /* that we don't want it to mess with our PC and nPC */ /* This is pretty much atomic, no amount locking would prevent * the races which exist anyways. */ err |= __copy_from_user(&setv, &c->sigmask, sizeof(svr4_sigset_t)); err |= __get_user(st.ss_sp, &c->stack.sp); err |= __get_user(st.ss_flags, &c->stack.flags); err |= __get_user(st.ss_size, &c->stack.size); if (err) goto sigsegv_and_return; /* It is more difficult to avoid calling this function than to call it and ignore errors. */ old_fs = get_fs(); set_fs(KERNEL_DS); do_sigaltstack((const stack_t __user *) &st, NULL, regs->u_regs[UREG_I6]); set_fs(old_fs); set.sig[0] = setv.sigbits[0]; set.sig[1] = setv.sigbits[1]; if (_NSIG_WORDS >= 4) { set.sig[2] = setv.sigbits[2]; set.sig[3] = setv.sigbits[3]; } sigdelsetmask(&set, ~_BLOCKABLE); spin_lock_irq(¤t->sighand->siglock); current->blocked = set; recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); regs->pc = pc; regs->npc = npc | 1; err |= __get_user(regs->y, &((*gr)[SVR4_Y])); err |= __get_user(psr, &((*gr)[SVR4_PSR])); regs->psr &= ~(PSR_ICC); regs->psr |= (psr & PSR_ICC); /* Restore g[1..7] and o[0..7] registers */ err |= __copy_from_user(®s->u_regs[UREG_G1], &(*gr)[SVR4_G1], sizeof(long) * 7); err |= __copy_from_user(®s->u_regs[UREG_I0], &(*gr)[SVR4_O0], sizeof(long) * 8); return (err ? -EFAULT : 0);sigsegv_and_return: do_exit(SIGSEGV);}static inline voidhandle_signal(unsigned long signr, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs, int svr4_signal){ if (svr4_signal) setup_svr4_frame(&ka->sa, regs->pc, regs->npc, regs, signr, oldset); else { if (ka->sa.sa_flags & SA_SIGINFO) new_setup_rt_frame(ka, regs, signr, oldset, info); else if (current->thread.new_signal) new_setup_frame(ka, regs, signr, oldset); else setup_frame(&ka->sa, regs, signr, oldset, info); } if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; if (!(ka->sa.sa_flags & SA_NOMASK)) { spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); sigaddset(¤t->blocked, signr); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); }}static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, struct sigaction *sa){ switch(regs->u_regs[UREG_I0]) { case ERESTART_RESTARTBLOCK: case ERESTARTNOHAND: no_system_call_restart: regs->u_regs[UREG_I0] = EINTR; regs->psr |= PSR_C; break; case ERESTARTSYS: if (!(sa->sa_flags & SA_RESTART)) goto no_system_call_restart; /* fallthrough */ case ERESTARTNOINTR: regs->u_regs[UREG_I0] = orig_i0; regs->pc -= 4; regs->npc -= 4; }}/* Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. */asmlinkage int do_signal(sigset_t *oldset, struct pt_regs * regs, unsigned long orig_i0, int restart_syscall){ siginfo_t info; struct sparc_deliver_cookie cookie; int signr; /* * XXX Disable svr4 signal handling until solaris emulation works. * It is buggy - Anton */#define SVR4_SIGNAL_BROKEN 1#ifdef SVR4_SIGNAL_BROKEN int svr4_signal = 0;#else int svr4_signal = current->personality == PER_SVR4;#endif cookie.restart_syscall = restart_syscall; cookie.orig_i0 = orig_i0; if (!oldset) oldset = ¤t->blocked; signr = get_signal_to_deliver(&info, regs, &cookie); if (signr > 0) { struct k_sigaction *ka; ka = ¤t->sighand->action[signr-1]; if (cookie.restart_syscall) syscall_restart(cookie.orig_i0, regs, &ka->sa); handle_signal(signr, ka, &info, oldset, regs, svr4_signal); return 1; } if (cookie.restart_syscall && (regs->u_regs[UREG_I0] == ERESTARTNOHAND || regs->u_regs[UREG_I0] == ERESTARTSYS || regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { /* replay the system call when we are done */ regs->u_regs[UREG_I0] = cookie.orig_i0; regs->pc -= 4; regs->npc -= 4; } if (cookie.restart_syscall && regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { regs->u_regs[UREG_G1] = __NR_restart_syscall; regs->pc -= 4; regs->npc -= 4; } return 0;}asmlinkage intdo_sys_sigstack(struct sigstack __user *ssptr, struct sigstack __user *ossptr, unsigned long sp){ int ret = -EFAULT; /* First see if old state is wanted. */ if (ossptr) { if (put_user(current->sas_ss_sp + current->sas_ss_size, &ossptr->the_stack) || __put_user(on_sig_stack(sp), &ossptr->cur_status)) goto out; } /* Now see if we want to update the new state. */ if (ssptr) { char *ss_sp; if (get_user(ss_sp, &ssptr->the_stack)) goto out; /* If the current stack was set with sigaltstack, don't swap stacks while we are on it. */ ret = -EPERM; if (current->sas_ss_sp && on_sig_stack(sp)) goto out; /* Since we don't know the extent of the stack, and we don't track onstack-ness, but rather calculate it, we must presume a size. Ho hum this interface is lossy. */ current->sas_ss_sp = (unsigned long)ss_sp - SIGSTKSZ; current->sas_ss_size = SIGSTKSZ; } ret = 0;out: return ret;}void ptrace_signal_deliver(struct pt_regs *regs, void *cookie){ struct sparc_deliver_cookie *cp = cookie; if (cp->restart_syscall && (regs->u_regs[UREG_I0] == ERESTARTNOHAND || regs->u_regs[UREG_I0] == ERESTARTSYS || regs->u_regs[UREG_I0] == ERESTARTNOINTR)) { /* replay the system call when we are done */ regs->u_regs[UREG_I0] = cp->orig_i0; regs->pc -= 4; regs->npc -= 4; cp->restart_syscall = 0; } if (cp->restart_syscall && regs->u_regs[UREG_I0] == ERESTART_RESTARTBLOCK) { regs->u_regs[UREG_G1] = __NR_restart_syscall; regs->pc -= 4; regs->npc -= 4; cp->restart_syscall = 0; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -