static void sendsig_siginfo(const ksiginfo_t *ksi, const sigset_t *mask) { struct lwp *l = curlwp; struct proc *p = l->l_proc; struct sigacts *ps = p->p_sigacts; struct trapframe *tf = l->l_md.md_regs; int sig = ksi->ksi_signo, error; sig_t catcher = SIGACTION(p, sig).sa_handler; struct sigframe_siginfo *fp, frame; int onstack; switch (ps->sa_sigdesc[sig].sd_vers) { case 0: /* FALLTHROUGH */ /* handled by sendsig_sigcontext */ case 1: /* FALLTHROUGH */ /* handled by sendsig_sigcontext */ default: /* unknown version */ printf("sendsig_siginfo: bad version %d\n", ps->sa_sigdesc[sig].sd_vers); sigexit(l, SIGILL); /* NOTREACHED */ case 2: break; } fp = getframe(l, sig, &onstack); --fp; frame.sf_si._info = ksi->ksi_info; frame.sf_uc.uc_link = l->l_ctxlink; frame.sf_uc.uc_sigmask = *mask; frame.sf_uc.uc_flags = _UC_SIGMASK; frame.sf_uc.uc_flags |= (l->l_sigstk.ss_flags & SS_ONSTACK) ? _UC_SETSTACK : _UC_CLRSTACK; memset(&frame.sf_uc.uc_stack, 0, sizeof(frame.sf_uc.uc_stack)); sendsig_reset(l, sig); mutex_exit(p->p_lock); cpu_getmcontext(l, &frame.sf_uc.uc_mcontext, &frame.sf_uc.uc_flags); error = copyout(&frame, fp, sizeof(frame)); mutex_enter(p->p_lock); if (error != 0) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ sigexit(l, SIGILL); /* NOTREACHED */ } tf->tf_r4 = sig; /* "signum" argument for handler */ tf->tf_r5 = (int)&fp->sf_si; /* "sip" argument for handler */ tf->tf_r6 = (int)&fp->sf_uc; /* "ucp" argument for handler */ tf->tf_spc = (int)catcher; tf->tf_r15 = (int)fp; tf->tf_pr = (int)ps->sa_sigdesc[sig].sd_tramp; /* Remember if we're now on the signal stack. */ if (onstack) l->l_sigstk.ss_flags |= SS_ONSTACK; }
/* * void cpu_upcall(struct lwp *l, int type, int nevents, int ninterrupted, * void *sas, void *ap, void *sp, sa_upcall_t upcall): * * Send an upcall to userland. */ void cpu_upcall(struct lwp *l, int type, int nevents, int ninterrupted, void *sas, void *ap, void *sp, sa_upcall_t upcall) { struct trapframe *tf; struct saframe *sf, frame; tf = l->l_md.md_regs; /* Build the stack frame. */ #if 0 /* First 4 args in regs (see below). */ frame.sa_type = type; frame.sa_sas = sas; frame.sa_events = nevents; frame.sa_interrupted = ninterrupted; #endif frame.sa_arg = ap; sf = (struct saframe *)sp - 1; if (copyout(&frame, sf, sizeof(frame)) != 0) { /* Copying onto the stack didn't work. Die. */ sigexit(l, SIGILL); /* NOTREACHED */ } tf->tf_r4 = type; tf->tf_r5 = (int) sas; tf->tf_r6 = nevents; tf->tf_r7 = ninterrupted; tf->tf_spc = (int) upcall; tf->tf_pr = 0; /* no return */ tf->tf_r15 = (int) sf; }
/* * cpu_upcall: * * Send an an upcall to userland. */ void cpu_upcall(struct lwp *l, int type, int nevents, int ninterrupted, void *sas, void *ap, void *sp, sa_upcall_t upcall) { struct trapframe *tf; struct saframe *sf, frame; tf = process_frame(l); /* Finally, copy out the rest of the frame. */ #if 0 /* First 4 args in regs (see below). */ frame.sa_type = type; frame.sa_sas = sas; frame.sa_events = nevents; frame.sa_interrupted = ninterrupted; #endif frame.sa_arg = ap; sf = (struct saframe *)sp - 1; if (copyout(&frame, sf, sizeof(frame)) != 0) { /* Copying onto the stack didn't work. Die. */ sigexit(l, SIGILL); /* NOTREACHED */ } tf->tf_r0 = type; tf->tf_r1 = (int) sas; tf->tf_r2 = nevents; tf->tf_r3 = ninterrupted; tf->tf_pc = (int) upcall; tf->tf_usr_sp = (int) sf; tf->tf_usr_lr = 0; /* no return */ }
static vaddr_t setupstack_siginfo3(const ksiginfo_t *ksi, const sigset_t *mask, int vers, struct lwp *l, struct trapframe *tf, vaddr_t sp, int onstack, vaddr_t handler) { struct trampoline3 tramp; ucontext_t uc; /* * Arguments given to the signal handler. */ tramp.narg = 3; tramp.sig = ksi->ksi_signo; sp -= sizeof(uc); tramp.ucp = sp; sp -= sizeof(siginfo_t); tramp.sip = sp; sp -= sizeof(tramp); /* Save register context. */ uc.uc_flags = _UC_SIGMASK; uc.uc_sigmask = *mask; uc.uc_link = NULL; memset(&uc.uc_stack, 0, sizeof(uc.uc_stack)); cpu_getmcontext(l, &uc.uc_mcontext, &uc.uc_flags); tf->fp = handler; /* Copy the context to the stack. */ if (copyout(&uc, (char *)tramp.ucp, sizeof(uc)) != 0 || copyout(&ksi->ksi_info, (char *)tramp.sip, sizeof(ksi->ksi_info)) != 0 || copyout(&tramp, (char *)sp, sizeof(tramp)) != 0) sigexit(l, SIGILL); return sp; };
/* * Send a signal to process. */ void sendsig_siginfo(const ksiginfo_t *ksi, const sigset_t *mask) { struct lwp * const l = curlwp; struct proc * const p = l->l_proc; struct sigacts * const sa = p->p_sigacts; struct trapframe * const tf = l->l_md.md_utf; const int signo = ksi->ksi_signo; const sig_t catcher = SIGACTION(p, signo).sa_handler; bool onstack; struct COMPATNAME2(sigframe_siginfo) *sf = cpu_sendsig_getframe(l, signo, &onstack); struct COMPATNAME2(sigframe_siginfo) ksf; sf--; // allocate sigframe COPY_SIGINFO(&ksf, ksi); ksf.sf_uc.uc_flags = _UC_SIGMASK | (l->l_sigstk.ss_flags & SS_ONSTACK ? _UC_SETSTACK : _UC_CLRSTACK); ksf.sf_uc.uc_sigmask = *mask; UCLINK_SET(&ksf.sf_uc, l->l_ctxlink); memset(&ksf.sf_uc.uc_stack, 0, sizeof(ksf.sf_uc.uc_stack)); sendsig_reset(l, signo); mutex_exit(p->p_lock); COMPATNAME2(cpu_getmcontext)(l, &ksf.sf_uc.uc_mcontext, &ksf.sf_uc.uc_flags); int error = copyout(&ksf, sf, sizeof(ksf)); mutex_enter(p->p_lock); if (error != 0) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ sigexit(l, SIGILL); /* NOTREACHED */ } /* * Set up the registers to directly invoke the signal * handler. The return address will be set up to point * to the signal trampoline to bounce us back. */ tf->tf_a0 = signo; tf->tf_a1 = (intptr_t)&sf->sf_si; tf->tf_a2 = (intptr_t)&sf->sf_uc; tf->tf_pc = (intptr_t)catcher; tf->tf_sp = (intptr_t)sf; tf->tf_ra = (intptr_t)sa->sa_sigdesc[signo].sd_tramp; /* Remember that we're now on the signal stack. */ if (onstack) l->l_sigstk.ss_flags |= SS_ONSTACK; }
caddr_t stackgap_init(struct proc *p) { struct process *pr = p->p_p; if (pr->ps_stackgap == 0) { if (uvm_map(&pr->ps_vmspace->vm_map, &pr->ps_stackgap, round_page(STACKGAPLEN), NULL, 0, 0, UVM_MAPFLAG(PROT_READ | PROT_WRITE, PROT_READ | PROT_WRITE, MAP_INHERIT_COPY, MADV_RANDOM, UVM_FLAG_COPYONW))) sigexit(p, SIGILL); } return (caddr_t)pr->ps_stackgap; }
void sendsig(const ksiginfo_t *ksi, const sigset_t *mask) { struct lwp *l = curlwp; struct proc *p = l->l_proc; struct trapframe *tf = l->l_addr->u_pcb.framep; struct sigaltstack *ss = &p->p_sigctx.ps_sigstk; const struct sigact_sigdesc *sd = &p->p_sigacts->sa_sigdesc[ksi->ksi_signo]; vaddr_t sp; int onstack; sig_setupstack_t setup; /* Figure what stack we are running on. */ onstack = (ss->ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && (sd->sd_sigact.sa_flags & SA_ONSTACK) != 0; sp = onstack ? ((vaddr_t)ss->ss_sp + ss->ss_size) : tf->sp; if (sd->sd_vers > 3 || (setup = sig_setupstacks[sd->sd_vers]) == NULL) goto nosupport; sp = (*setup)(ksi, mask, sd->sd_vers, l, tf, sp, onstack, (vaddr_t)sd->sd_sigact.sa_handler); if (sp == 0) goto nosupport; if (sd->sd_vers == 0) tf->pc = (register_t)p->p_sigctx.ps_sigcode; else tf->pc = (register_t)sd->sd_tramp; tf->psl = PSL_U | PSL_PREVU; tf->sp = sp; tf->ap = sp; if (onstack) ss->ss_flags |= SS_ONSTACK; return; nosupport: /* Don't know what trampoline version; kill it. */ printf("sendsig(sig %d): bad version %d\n", ksi->ksi_signo, sd->sd_vers); sigexit(l, SIGILL); }
void vm86_return(struct proc *p, int retval) { union sigval sv; /* * We can't set the virtual flags in our real trap frame, * since it's used to jump to the signal handler. Instead we * let sendsig() pull in the vm86_eflags bits. */ if (p->p_sigmask & sigmask(SIGURG)) { #ifdef DIAGNOSTIC printf("pid %d killed on VM86 protocol screwup (SIGURG blocked)\n", p->p_pid); #endif sigexit(p, SIGILL); /* NOTREACHED */ } sv.sival_int = 0; trapsignal(p, SIGURG, retval, 0, sv); }
static void netbsd32_sendsig_siginfo(const ksiginfo_t *ksi, const sigset_t *mask) { struct lwp *l = curlwp; struct proc *p = l->l_proc; struct sigacts *ps = p->p_sigacts; int onstack; int sig = ksi->ksi_signo; ucontext32_t uc; struct sparc32_sigframe_siginfo *fp; siginfo32_t si32; netbsd32_intptr_t catcher; struct trapframe64 *tf = l->l_md.md_tf; struct rwindow32 *oldsp, *newsp; register32_t sp; int ucsz, error; /* Need to attempt to zero extend this 32-bit pointer */ oldsp = (struct rwindow32*)(u_long)(u_int)tf->tf_out[6]; /* Do we need to jump onto the signal stack? */ onstack = (l->l_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0; /* Allocate space for the signal handler context. */ if (onstack) fp = (struct sparc32_sigframe_siginfo *) ((char *)l->l_sigstk.ss_sp + l->l_sigstk.ss_size); else fp = (struct sparc32_sigframe_siginfo *)oldsp; fp = (struct sparc32_sigframe_siginfo*)((u_long)(fp - 1) & ~7); /* * Build the signal context to be used by sigreturn. */ memset(&uc, 0, sizeof uc); uc.uc_flags = _UC_SIGMASK | ((l->l_sigstk.ss_flags & SS_ONSTACK) ? _UC_SETSTACK : _UC_CLRSTACK); uc.uc_sigmask = *mask; uc.uc_link = (uint32_t)(uintptr_t)l->l_ctxlink; sendsig_reset(l, sig); /* * Now copy the stack contents out to user space. * We need to make sure that when we start the signal handler, * its %i6 (%fp), which is loaded from the newly allocated stack area, * joins seamlessly with the frame it was in when the signal occurred, * so that the debugger and _longjmp code can back up through it. * Since we're calling the handler directly, allocate a full size * C stack frame. */ mutex_exit(p->p_lock); cpu_getmcontext32(l, &uc.uc_mcontext, &uc.uc_flags); netbsd32_si_to_si32(&si32, (const siginfo_t *)&ksi->ksi_info); ucsz = (int)(intptr_t)&uc.__uc_pad - (int)(intptr_t)&uc; newsp = (struct rwindow32*)((intptr_t)fp - sizeof(struct frame32)); sp = NETBSD32PTR32I(oldsp); error = (copyout(&si32, &fp->sf_si, sizeof si32) || copyout(&uc, &fp->sf_uc, ucsz) || copyout(&sp, &newsp->rw_in[6], sizeof(sp))); mutex_enter(p->p_lock); if (error) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ sigexit(l, SIGILL); /* NOTREACHED */ } switch (ps->sa_sigdesc[sig].sd_vers) { default: /* Unsupported trampoline version; kill the process. */ sigexit(l, SIGILL); case 2: /* * Arrange to continue execution at the user's handler. * It needs a new stack pointer, a return address and * three arguments: (signo, siginfo *, ucontext *). */ catcher = (intptr_t)SIGACTION(p, sig).sa_handler; tf->tf_pc = catcher; tf->tf_npc = catcher + 4; tf->tf_out[0] = sig; tf->tf_out[1] = (intptr_t)&fp->sf_si; tf->tf_out[2] = (intptr_t)&fp->sf_uc; tf->tf_out[6] = (intptr_t)newsp; tf->tf_out[7] = (intptr_t)ps->sa_sigdesc[sig].sd_tramp - 8; break; } /* Remember that we're now on the signal stack. */ if (onstack) l->l_sigstk.ss_flags |= SS_ONSTACK; }
int cpu_setmcontext32(struct lwp *l, const mcontext32_t *mcp, unsigned int flags) { struct trapframe *tf = l->l_md.md_tf; const __greg32_t *gr = mcp->__gregs; struct proc *p = l->l_proc; int error; /* First ensure consistent stack state (see sendsig). */ write_user_windows(); if (rwindow_save(l)) { mutex_enter(p->p_lock); sigexit(l, SIGILL); } /* Restore register context, if any. */ if ((flags & _UC_CPU) != 0) { error = cpu_mcontext32_validate(l, mcp); if (error) return error; /* Restore general register context. */ /* take only tstate CCR (and ASI) fields */ tf->tf_tstate = (tf->tf_tstate & ~TSTATE_CCR) | PSRCC_TO_TSTATE(gr[_REG32_PSR]); tf->tf_pc = (uint64_t)gr[_REG32_PC]; tf->tf_npc = (uint64_t)gr[_REG32_nPC]; tf->tf_y = (uint64_t)gr[_REG32_Y]; tf->tf_global[1] = (uint64_t)gr[_REG32_G1]; tf->tf_global[2] = (uint64_t)gr[_REG32_G2]; tf->tf_global[3] = (uint64_t)gr[_REG32_G3]; tf->tf_global[4] = (uint64_t)gr[_REG32_G4]; tf->tf_global[5] = (uint64_t)gr[_REG32_G5]; tf->tf_global[6] = (uint64_t)gr[_REG32_G6]; /* done in lwp_setprivate */ /* tf->tf_global[7] = (uint64_t)gr[_REG32_G7]; */ tf->tf_out[0] = (uint64_t)gr[_REG32_O0]; tf->tf_out[1] = (uint64_t)gr[_REG32_O1]; tf->tf_out[2] = (uint64_t)gr[_REG32_O2]; tf->tf_out[3] = (uint64_t)gr[_REG32_O3]; tf->tf_out[4] = (uint64_t)gr[_REG32_O4]; tf->tf_out[5] = (uint64_t)gr[_REG32_O5]; tf->tf_out[6] = (uint64_t)gr[_REG32_O6]; tf->tf_out[7] = (uint64_t)gr[_REG32_O7]; /* %asi restored above; %fprs not yet supported. */ if (flags & _UC_TLSBASE) lwp_setprivate(l, (void *)(uintptr_t)gr[_REG32_G7]); /* XXX mcp->__gwins */ } /* Restore floating point register context, if any. */ if ((flags & _UC_FPU) != 0) { #ifdef notyet struct fpstate64 *fsp; const __fpregset_t *fpr = &mcp->__fpregs; /* * If we're the current FPU owner, simply reload it from * the supplied context. Otherwise, store it into the * process' FPU save area (which is used to restore from * by lazy FPU context switching); allocate it if necessary. */ if ((fsp = l->l_md.md_fpstate) == NULL) { fsp = pool_cache_get(fpstate_cache, PR_WAITOK); l->l_md.md_fpstate = fsp; } else { /* Drop the live context on the floor. */ fpusave_lwp(l, false); } /* Note: sizeof fpr->__fpu_fr <= sizeof fsp->fs_regs. */ memcpy(fsp->fs_regs, &fpr->__fpu_fr, sizeof (fpr->__fpu_fr)); fsp->fs_fsr = mcp->__fpregs.__fpu_fsr; fsp->fs_qsize = 0; #if 0 /* Need more info! */ mcp->__fpregs.__fpu_q = NULL; /* `Need more info.' */ mcp->__fpregs.__fpu_qcnt = 0 /*fs.fs_qsize*/; /* See above */ #endif #endif } #ifdef _UC_SETSTACK mutex_enter(p->p_lock); if (flags & _UC_SETSTACK) l->l_sigstk.ss_flags |= SS_ONSTACK; if (flags & _UC_CLRSTACK) l->l_sigstk.ss_flags &= ~SS_ONSTACK; mutex_exit(p->p_lock); #endif return (0); }
static void netbsd32_sendsig_sigcontext(const ksiginfo_t *ksi, const sigset_t *mask) { int sig = ksi->ksi_signo; struct lwp *l = curlwp; struct proc *p = l->l_proc; struct sparc32_sigframe *fp; struct trapframe64 *tf; int addr, onstack, error; struct rwindow32 *oldsp, *newsp; register32_t sp; sig_t catcher = SIGACTION(p, sig).sa_handler; struct sparc32_sigframe sf; extern char netbsd32_sigcode[], netbsd32_esigcode[]; #define szsigcode (netbsd32_esigcode - netbsd32_sigcode) tf = l->l_md.md_tf; /* Need to attempt to zero extend this 32-bit pointer */ oldsp = (struct rwindow32 *)(u_long)(u_int)tf->tf_out[6]; /* Do we need to jump onto the signal stack? */ onstack = (l->l_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0; if (onstack) { fp = (struct sparc32_sigframe *)((char *)l->l_sigstk.ss_sp + l->l_sigstk.ss_size); l->l_sigstk.ss_flags |= SS_ONSTACK; } else fp = (struct sparc32_sigframe *)oldsp; fp = (struct sparc32_sigframe *)((u_long)(fp - 1) & ~7); #ifdef DEBUG sigpid = p->p_pid; if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) { printf("sendsig: %s[%d] sig %d newusp %p scp %p oldsp %p\n", p->p_comm, p->p_pid, sig, fp, &fp->sf_sc, oldsp); if (sigdebug & SDB_DDB) Debugger(); } #endif /* * Now set up the signal frame. We build it in kernel space * and then copy it out. We probably ought to just build it * directly in user space.... */ sf.sf_signo = sig; sf.sf_code = (u_int)ksi->ksi_trap; #if defined(COMPAT_SUNOS) || defined(MODULAR) sf.sf_scp = (u_long)&fp->sf_sc; #endif sf.sf_addr = 0; /* XXX */ /* * Build the signal context to be used by sigreturn. */ sf.sf_sc.sc_onstack = onstack; sf.sf_sc.sc_mask = *mask; sf.sf_sc.sc_sp = (u_long)oldsp; sf.sf_sc.sc_pc = tf->tf_pc; sf.sf_sc.sc_npc = tf->tf_npc; sf.sf_sc.sc_psr = TSTATECCR_TO_PSR(tf->tf_tstate); /* XXX */ sf.sf_sc.sc_g1 = tf->tf_global[1]; sf.sf_sc.sc_o0 = tf->tf_out[0]; /* * Put the stack in a consistent state before we whack away * at it. Note that write_user_windows may just dump the * registers into the pcb; we need them in the process's memory. * We also need to make sure that when we start the signal handler, * its %i6 (%fp), which is loaded from the newly allocated stack area, * joins seamlessly with the frame it was in when the signal occurred, * so that the debugger and _longjmp code can back up through it. */ sendsig_reset(l, sig); mutex_exit(p->p_lock); newsp = (struct rwindow32 *)((long)fp - sizeof(struct rwindow32)); write_user_windows(); #ifdef DEBUG if ((sigdebug & SDB_KSTACK)) printf("sendsig: saving sf to %p, setting stack pointer %p to %p\n", fp, &(((struct rwindow32 *)newsp)->rw_in[6]), oldsp); #endif sp = NETBSD32PTR32I(oldsp); error = (rwindow_save(l) || copyout(&sf, fp, sizeof sf) || copyout(&sp, &(((struct rwindow32 *)newsp)->rw_in[6]), sizeof(sp))); mutex_enter(p->p_lock); if (error) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ #ifdef DEBUG mutex_exit(p->p_lock); if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig: window save or copyout error\n"); printf("sendsig: stack was trashed trying to send sig %d, sending SIGILL\n", sig); if (sigdebug & SDB_DDB) Debugger(); mutex_enter(p->p_lock); #endif sigexit(l, SIGILL); /* NOTREACHED */ } #ifdef DEBUG if (sigdebug & SDB_FOLLOW) { printf("sendsig: %s[%d] sig %d scp %p\n", p->p_comm, p->p_pid, sig, &fp->sf_sc); } #endif /* * Arrange to continue execution at the code copied out in exec(). * It needs the function to call in %g1, and a new stack pointer. */ addr = p->p_psstrp - szsigcode; tf->tf_global[1] = (long)catcher; tf->tf_pc = addr; tf->tf_npc = addr + 4; tf->tf_out[6] = (uint64_t)(u_int)(u_long)newsp; /* Remember that we're now on the signal stack. */ if (onstack) l->l_sigstk.ss_flags |= SS_ONSTACK; #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) { mutex_exit(p->p_lock); printf("sendsig: about to return to catcher %p thru %p\n", catcher, addr); if (sigdebug & SDB_DDB) Debugger(); mutex_enter(p->p_lock); } #endif }
int linux_sys_rt_sigreturn(struct lwp *l, const void *v, register_t *retval) { struct linux_ucontext *luctx; struct trapframe *tf = l->l_md.md_regs; struct linux_sigcontext *lsigctx; struct linux_rt_sigframe frame, *fp; ucontext_t uctx; mcontext_t *mctx; int error; fp = (struct linux_rt_sigframe *)(tf->tf_regs[_R_SP]); if ((error = copyin(fp, &frame, sizeof(frame))) != 0) { mutex_enter(l->l_proc->p_lock); sigexit(l, SIGILL); return error; } luctx = &frame.lrs_uc; lsigctx = &luctx->luc_mcontext; bzero(&uctx, sizeof(uctx)); mctx = (mcontext_t *)&uctx.uc_mcontext; /* * Set the flags. Linux always have CPU, stack and signal state, * FPU is optional. uc_flags is not used to tell what we have. */ uctx.uc_flags = (_UC_SIGMASK|_UC_CPU|_UC_STACK); uctx.uc_link = NULL; /* * Signal set. */ linux_to_native_sigset(&uctx.uc_sigmask, &luctx->luc_sigmask); /* * CPU state. */ memcpy(mctx->__gregs, lsigctx->lsc_regs, sizeof(lsigctx->lsc_regs)); /* * And the stack. */ uctx.uc_stack.ss_flags = 0; if (luctx->luc_stack.ss_flags & LINUX_SS_ONSTACK) uctx.uc_stack.ss_flags |= SS_ONSTACK; if (luctx->luc_stack.ss_flags & LINUX_SS_DISABLE) uctx.uc_stack.ss_flags |= SS_DISABLE; uctx.uc_stack.ss_sp = luctx->luc_stack.ss_sp; uctx.uc_stack.ss_size = luctx->luc_stack.ss_size; /* * And let setucontext deal with that. */ mutex_enter(l->l_proc->p_lock); error = setucontext(l, &uctx); mutex_exit(l->l_proc->p_lock); if (error) return error; return (EJUSTRETURN); }
void sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) { struct thread *td; struct proc *p; struct trapframe *tf; struct sigframe *fp, frame; struct sigacts *psp; int code, onstack, sig; td = curthread; p = td->td_proc; PROC_LOCK_ASSERT(p, MA_OWNED); sig = ksi->ksi_signo; code = ksi->ksi_code; psp = p->p_sigacts; mtx_assert(&psp->ps_mtx, MA_OWNED); tf = td->td_frame; onstack = sigonstack(tf->tf_sp); CTR4(KTR_SIG, "sendsig: td=%p (%s) catcher=%p sig=%d", td, p->p_comm, catcher, sig); /* Allocate and validate space for the signal handler context. */ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !onstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { fp = (struct sigframe *)(td->td_sigstk.ss_sp + td->td_sigstk.ss_size); #if defined(COMPAT_43) td->td_sigstk.ss_flags |= SS_ONSTACK; #endif } else { fp = (struct sigframe *)td->td_frame->tf_sp; } /* Make room, keeping the stack aligned */ fp--; fp = (struct sigframe *)STACKALIGN(fp); /* Fill in the frame to copy out */ get_mcontext(td, &frame.sf_uc.uc_mcontext, 0); get_fpcontext(td, &frame.sf_uc.uc_mcontext); frame.sf_si = ksi->ksi_info; frame.sf_uc.uc_sigmask = *mask; frame.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) ? ((onstack) ? SS_ONSTACK : 0) : SS_DISABLE; frame.sf_uc.uc_stack = td->td_sigstk; mtx_unlock(&psp->ps_mtx); PROC_UNLOCK(td->td_proc); /* Copy the sigframe out to the user's stack. */ if (copyout(&frame, fp, sizeof(*fp)) != 0) { /* Process has trashed its stack. Kill it. */ CTR2(KTR_SIG, "sendsig: sigexit td=%p fp=%p", td, fp); PROC_LOCK(p); sigexit(td, SIGILL); } tf->tf_x[0]= sig; tf->tf_x[1] = (register_t)&fp->sf_si; tf->tf_x[2] = (register_t)&fp->sf_uc; tf->tf_elr = (register_t)catcher; tf->tf_sp = (register_t)fp; tf->tf_lr = (register_t)(PS_STRINGS - *(p->p_sysent->sv_szsigcode)); CTR3(KTR_SIG, "sendsig: return td=%p pc=%#x sp=%#x", td, tf->tf_elr, tf->tf_sp); PROC_LOCK(p); mtx_lock(&psp->ps_mtx); }
int netbsd32_cpu_setmcontext( struct lwp *l, /* XXX const netbsd32_*/mcontext_t *mcp, unsigned int flags) { #ifdef NOT_YET /* XXX */ greg32_t *gr = mcp->__gregs; struct trapframe64 *tf = l->l_md.md_tf; /* First ensure consistent stack state (see sendsig). */ write_user_windows(); if (rwindow_save(p)) { mutex_enter(l->l_proc->p_lock); sigexit(p, SIGILL); } if ((flags & _UC_CPU) != 0) { /* * Only the icc bits in the psr are used, so it need not be * verified. pc and npc must be multiples of 4. This is all * that is required; if it holds, just do it. */ if (((gr[_REG_PC] | gr[_REG_nPC]) & 3) != 0 || gr[_REG_PC] == 0 || gr[_REG_nPC] == 0) return (EINVAL); /* Restore general register context. */ /* take only tstate CCR (and ASI) fields */ tf->tf_tstate = (tf->tf_tstate & ~TSTATE_CCR) | PSRCC_TO_TSTATE(gr[_REG_PSR]); tf->tf_pc = (uint64_t)gr[_REG_PC]; tf->tf_npc = (uint64_t)gr[_REG_nPC]; tf->tf_y = (uint64_t)gr[_REG_Y]; tf->tf_global[1] = (uint64_t)gr[_REG_G1]; tf->tf_global[2] = (uint64_t)gr[_REG_G2]; tf->tf_global[3] = (uint64_t)gr[_REG_G3]; tf->tf_global[4] = (uint64_t)gr[_REG_G4]; tf->tf_global[5] = (uint64_t)gr[_REG_G5]; tf->tf_global[6] = (uint64_t)gr[_REG_G6]; tf->tf_global[7] = (uint64_t)gr[_REG_G7]; tf->tf_out[0] = (uint64_t)gr[_REG_O0]; tf->tf_out[1] = (uint64_t)gr[_REG_O1]; tf->tf_out[2] = (uint64_t)gr[_REG_O2]; tf->tf_out[3] = (uint64_t)gr[_REG_O3]; tf->tf_out[4] = (uint64_t)gr[_REG_O4]; tf->tf_out[5] = (uint64_t)gr[_REG_O5]; tf->tf_out[6] = (uint64_t)gr[_REG_O6]; tf->tf_out[7] = (uint64_t)gr[_REG_O7]; /* %asi restored above; %fprs not yet supported. */ /* XXX mcp->__gwins */ } /* Restore FP register context, if any. */ if ((flags & _UC_FPU) != 0 && mcp->__fpregs.__fpu_en != 0) { struct fpstate *fsp; const netbsd32_fpregset_t *fpr = &mcp->__fpregs; int reload = 0; /* * If we're the current FPU owner, simply reload it from * the supplied context. Otherwise, store it into the * process' FPU save area (which is used to restore from * by lazy FPU context switching); allocate it if necessary. */ /* * XXX Should we really activate the supplied FPU context * XXX immediately or just fault it in later? */ if ((fsp = l->l_md.md_fpstate) == NULL) { fsp = pool_cache_get(fpstate_cache, PR_WAITOK); l->l_md.md_fpstate = fsp; } else { /* Drop the live context on the floor. */ fpusave_lwp(l, false); reload = 1; } /* Note: sizeof fpr->__fpu_fr <= sizeof fsp->fs_regs. */ memcpy(fsp->fs_regs, fpr->__fpu_fr, sizeof (fpr->__fpu_fr)); fsp->fs_fsr = fpr->__fpu_fsr; /* don't care about fcc1-3 */ fsp->fs_qsize = 0; #if 0 /* Need more info! */ mcp->__fpregs.__fpu_q = NULL; /* `Need more info.' */ mcp->__fpregs.__fpu_qcnt = 0 /*fs.fs_qsize*/; /* See above */ #endif /* Reload context again, if necessary. */ if (reload) loadfpstate(fsp); } /* XXX mcp->__xrs */ /* XXX mcp->__asrs */ #endif return (0); }
/* * The CheriABI version of sendsig(9) largely borrows from the MIPS version, * and it is important to keep them in sync. It differs primarily in that it * must also be aware of user stack-handling ABIs, so is also sensitive to our * (fluctuating) design choices in how $stc and $sp interact. The current * design uses ($stc + $sp) for stack-relative references, so early on we have * to calculate a 'relocated' version of $sp that we can then use for * MIPS-style access. * * This code, as with the CHERI-aware MIPS code, makes a privilege * determination in order to decide whether to trust the stack exposed by the * user code for the purposes of signal handling. We must use the alternative * stack if there is any indication that using the user thread's stack state * might violate the userspace compartmentalisation model. */ static void cheriabi_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) { struct proc *p; struct thread *td; struct trapframe *regs; struct sigacts *psp; struct sigframe_c sf, *sfp; uintptr_t stackbase; vm_offset_t sp; int cheri_is_sandboxed; int sig; int oonstack; td = curthread; p = td->td_proc; PROC_LOCK_ASSERT(p, MA_OWNED); sig = ksi->ksi_signo; psp = p->p_sigacts; mtx_assert(&psp->ps_mtx, MA_OWNED); regs = td->td_frame; /* * In CheriABI, $sp is $stc relative, so calculate a relocation base * that must be combined with regs->sp from this point onwards. * Unfortunately, we won't retain bounds and permissions information * (as is the case elsewhere in CheriABI). While 'stackbase' * suggests that $stc's offset isn't included, in practice it will be, * although we may reasonably assume that it will be zero. * * If it turns out we will be delivering to the alternative signal * stack, we'll recalculate stackbase later. */ CHERI_CLC(CHERI_CR_CTEMP0, CHERI_CR_KDC, &td->td_pcb->pcb_regs.stc, 0); CHERI_CTOPTR(stackbase, CHERI_CR_CTEMP0, CHERI_CR_KDC); oonstack = sigonstack(stackbase + regs->sp); /* * CHERI affects signal delivery in the following ways: * * (1) Additional capability-coprocessor state is exposed via * extensions to the context frame placed on the stack. * * (2) If the user $pcc doesn't include CHERI_PERM_SYSCALL, then we * consider user state to be 'sandboxed' and therefore to require * special delivery handling which includes a domain-switch to the * thread's context-switch domain. (This is done by * cheri_sendsig()). * * (3) If an alternative signal stack is not defined, and we are in a * 'sandboxed' state, then we have two choices: (a) if the signal * is of type SA_SANDBOX_UNWIND, we will automatically unwind the * trusted stack by one frame; (b) otherwise, we will terminate * the process unconditionally. */ cheri_is_sandboxed = cheri_signal_sandboxed(td); /* * We provide the ability to drop into the debugger in two different * circumstances: (1) if the code running is sandboxed; and (2) if the * fault is a CHERI protection fault. Handle both here for the * non-unwind case. Do this before we rewrite any general-purpose or * capability register state for the thread. */ #if DDB if (cheri_is_sandboxed && security_cheri_debugger_on_sandbox_signal) kdb_enter(KDB_WHY_CHERI, "Signal delivery to CHERI sandbox"); else if (sig == SIGPROT && security_cheri_debugger_on_sigprot) kdb_enter(KDB_WHY_CHERI, "SIGPROT delivered outside sandbox"); #endif /* * If a thread is running sandboxed, we can't rely on $sp which may * not point at a valid stack in the ambient context, or even be * maliciously manipulated. We must therefore always use the * alternative stack. We are also therefore unable to tell whether we * are on the alternative stack, so must clear 'oonstack' here. * * XXXRW: This requires significant further thinking; however, the net * upshot is that it is not a good idea to do an object-capability * invoke() from a signal handler, as with so many other things in * life. */ if (cheri_is_sandboxed != 0) oonstack = 0; /* save user context */ bzero(&sf, sizeof(sf)); sf.sf_uc.uc_sigmask = *mask; #if 0 /* * XXX-BD: stack_t type differs and we can't just fake a capabilty. * We don't restore the value so what purpose does it serve? */ sf.sf_uc.uc_stack = td->td_sigstk; #endif sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; sf.sf_uc.uc_mcontext.mc_pc = regs->pc; sf.sf_uc.uc_mcontext.mullo = regs->mullo; sf.sf_uc.uc_mcontext.mulhi = regs->mulhi; cheri_capability_copy(&sf.sf_uc.uc_mcontext.mc_tls, &td->td_md.md_tls_cap); sf.sf_uc.uc_mcontext.mc_regs[0] = UCONTEXT_MAGIC; /* magic number */ bcopy((void *)®s->ast, (void *)&sf.sf_uc.uc_mcontext.mc_regs[1], sizeof(sf.sf_uc.uc_mcontext.mc_regs) - sizeof(register_t)); sf.sf_uc.uc_mcontext.mc_fpused = td->td_md.md_flags & MDTD_FPUSED; #if defined(CPU_HAVEFPU) if (sf.sf_uc.uc_mcontext.mc_fpused) { /* if FPU has current state, save it first */ if (td == PCPU_GET(fpcurthread)) MipsSaveCurFPState(td); bcopy((void *)&td->td_frame->f0, (void *)sf.sf_uc.uc_mcontext.mc_fpregs, sizeof(sf.sf_uc.uc_mcontext.mc_fpregs)); } #endif /* XXXRW: sf.sf_uc.uc_mcontext.sr seems never to be set? */ sf.sf_uc.uc_mcontext.cause = regs->cause; cheri_trapframe_to_cheriframe(&td->td_pcb->pcb_regs, &sf.sf_uc.uc_mcontext.mc_cheriframe); /* * Allocate and validate space for the signal handler context. For * CheriABI purposes, 'sp' from this point forward is relocated * relative to any pertinent stack capability. For an alternative * signal context, we need to recalculate stackbase for later use in * calculating a new $sp for the signal-handling context. * * XXXRW: It seems like it would be nice to both the regular and * alternative stack calculations in the same place. However, we need * oonstack sooner. We should clean this up later. */ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { stackbase = (vm_offset_t)td->td_sigstk.ss_sp; sp = (vm_offset_t)(stackbase + td->td_sigstk.ss_size); } else { /* * Signals delivered when a CHERI sandbox is present must be * delivered on the alternative stack rather than a local one. * If an alternative stack isn't present, then terminate or * risk leaking capabilities (and control) to the sandbox (or * just crashing the sandbox). */ if (cheri_is_sandboxed) { mtx_unlock(&psp->ps_mtx); printf("pid %d, tid %d: signal in sandbox without " "alternative stack defined\n", td->td_proc->p_pid, td->td_tid); sigexit(td, SIGILL); /* NOTREACHED */ } sp = (vm_offset_t)(stackbase + regs->sp); } sp -= sizeof(struct sigframe_c); /* For CHERI, keep the stack pointer capability aligned. */ sp &= ~(CHERICAP_SIZE - 1); sfp = (void *)sp; /* Build the argument list for the signal handler. */ regs->a0 = sig; if (SIGISMEMBER(psp->ps_siginfo, sig)) { /* * Signal handler installed with SA_SIGINFO. * * XXXRW: We would ideally synthesise these from the * user-originated stack capability, rather than $kdc, to be * on the safe side. */ cheri_capability_set(®s->c3, CHERI_CAP_USER_DATA_PERMS, (void *)(intptr_t)&sfp->sf_si, sizeof(sfp->sf_si), 0); cheri_capability_set(®s->c4, CHERI_CAP_USER_DATA_PERMS, (void *)(intptr_t)&sfp->sf_uc, sizeof(sfp->sf_uc), 0); /* sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; */ /* fill siginfo structure */ sf.sf_si.si_signo = sig; sf.sf_si.si_code = ksi->ksi_code; /* * Write out badvaddr, but don't create a valid capability * since that might allow privilege amplification. * * XXX-BD: This probably isn't the right method. * XXX-BD: Do we want to set base or offset? * * XXXRW: I think there's some argument that anything * receiving this signal is fairly privileged. But we could * generate a $ddc-relative (or $pcc-relative) capability, if * possible. (Using versions if $ddc and $pcc for the * signal-handling context rather than that which caused the * signal). I'd be tempted to deliver badvaddr as the offset * of that capability. If badvaddr is not in range, then we * should just deliver an untagged NULL-derived version * (perhaps)? */ *((uintptr_t *)&sf.sf_si.si_addr) = (uintptr_t)(void *)regs->badvaddr; } /* * XXX: No support for undocumented arguments to old style handlers. */ mtx_unlock(&psp->ps_mtx); PROC_UNLOCK(p); /* * Copy the sigframe out to the user's stack. */ if (copyoutcap(&sf, (void *)sfp, sizeof(sf)) != 0) { /* * Something is wrong with the stack pointer. * ...Kill the process. */ PROC_LOCK(p); printf("pid %d, tid %d: could not copy out sigframe\n", td->td_proc->p_pid, td->td_tid); sigexit(td, SIGILL); /* NOTREACHED */ } /* * Re-acquire process locks necessary to access suitable pcb fields. * However, arguably, these operations should be atomic with the * initial inspection of 'psp'. */ PROC_LOCK(p); mtx_lock(&psp->ps_mtx); /* * Install CHERI signal-delivery register state for handler to run * in. As we don't install this in the CHERI frame on the user stack, * it will be (generally) be removed automatically on sigreturn(). */ /* XXX-BD: this isn't quite right */ cheri_sendsig(td); /* * Note that $sp must be installed relative to $stc, so re-subtract * the stack base here. */ regs->pc = (register_t)(intptr_t)catcher; regs->sp = (register_t)((intptr_t)sfp - stackbase); cheri_capability_copy(®s->c12, &psp->ps_sigcap[_SIG_IDX(sig)]); cheri_capability_copy(®s->c17, &td->td_pcb->pcb_cherisignal.csig_sigcode); }
void ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) { struct ia32_sigframe sf, *sfp; struct siginfo32 siginfo; struct proc *p; struct thread *td; struct sigacts *psp; char *sp; struct trapframe *regs; char *xfpusave; size_t xfpusave_len; int oonstack; int sig; siginfo_to_siginfo32(&ksi->ksi_info, &siginfo); td = curthread; p = td->td_proc; PROC_LOCK_ASSERT(p, MA_OWNED); sig = siginfo.si_signo; psp = p->p_sigacts; #ifdef COMPAT_FREEBSD4 if (SIGISMEMBER(psp->ps_freebsd4, sig)) { freebsd4_ia32_sendsig(catcher, ksi, mask); return; } #endif #ifdef COMPAT_43 if (SIGISMEMBER(psp->ps_osigset, sig)) { ia32_osendsig(catcher, ksi, mask); return; } #endif mtx_assert(&psp->ps_mtx, MA_OWNED); regs = td->td_frame; oonstack = sigonstack(regs->tf_rsp); if (cpu_max_ext_state_size > sizeof(struct savefpu) && use_xsave) { xfpusave_len = cpu_max_ext_state_size - sizeof(struct savefpu); xfpusave = __builtin_alloca(xfpusave_len); } else { xfpusave_len = 0; xfpusave = NULL; } /* Save user context. */ bzero(&sf, sizeof(sf)); sf.sf_uc.uc_sigmask = *mask; sf.sf_uc.uc_stack.ss_sp = (uintptr_t)td->td_sigstk.ss_sp; sf.sf_uc.uc_stack.ss_size = td->td_sigstk.ss_size; sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; sf.sf_uc.uc_mcontext.mc_edi = regs->tf_rdi; sf.sf_uc.uc_mcontext.mc_esi = regs->tf_rsi; sf.sf_uc.uc_mcontext.mc_ebp = regs->tf_rbp; sf.sf_uc.uc_mcontext.mc_isp = regs->tf_rsp; /* XXX */ sf.sf_uc.uc_mcontext.mc_ebx = regs->tf_rbx; sf.sf_uc.uc_mcontext.mc_edx = regs->tf_rdx; sf.sf_uc.uc_mcontext.mc_ecx = regs->tf_rcx; sf.sf_uc.uc_mcontext.mc_eax = regs->tf_rax; sf.sf_uc.uc_mcontext.mc_trapno = regs->tf_trapno; sf.sf_uc.uc_mcontext.mc_err = regs->tf_err; sf.sf_uc.uc_mcontext.mc_eip = regs->tf_rip; sf.sf_uc.uc_mcontext.mc_cs = regs->tf_cs; sf.sf_uc.uc_mcontext.mc_eflags = regs->tf_rflags; sf.sf_uc.uc_mcontext.mc_esp = regs->tf_rsp; sf.sf_uc.uc_mcontext.mc_ss = regs->tf_ss; sf.sf_uc.uc_mcontext.mc_ds = regs->tf_ds; sf.sf_uc.uc_mcontext.mc_es = regs->tf_es; sf.sf_uc.uc_mcontext.mc_fs = regs->tf_fs; sf.sf_uc.uc_mcontext.mc_gs = regs->tf_gs; sf.sf_uc.uc_mcontext.mc_len = sizeof(sf.sf_uc.uc_mcontext); /* magic */ ia32_get_fpcontext(td, &sf.sf_uc.uc_mcontext, xfpusave, xfpusave_len); fpstate_drop(td); sf.sf_uc.uc_mcontext.mc_fsbase = td->td_pcb->pcb_fsbase; sf.sf_uc.uc_mcontext.mc_gsbase = td->td_pcb->pcb_gsbase; bzero(sf.sf_uc.__spare__, sizeof(sf.sf_uc.__spare__)); /* Allocate space for the signal handler context. */ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) sp = td->td_sigstk.ss_sp + td->td_sigstk.ss_size; else sp = (char *)regs->tf_rsp; if (xfpusave != NULL) { sp -= xfpusave_len; sp = (char *)((unsigned long)sp & ~0x3Ful); sf.sf_uc.uc_mcontext.mc_xfpustate = (register_t)sp; } sp -= sizeof(sf); /* Align to 16 bytes. */ sfp = (struct ia32_sigframe *)((uintptr_t)sp & ~0xF); PROC_UNLOCK(p); /* Translate the signal if appropriate. */ if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize) sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; /* Build the argument list for the signal handler. */ sf.sf_signum = sig; sf.sf_ucontext = (register_t)&sfp->sf_uc; bzero(&sf.sf_si, sizeof(sf.sf_si)); if (SIGISMEMBER(psp->ps_siginfo, sig)) { /* Signal handler installed with SA_SIGINFO. */ sf.sf_siginfo = (u_int32_t)(uintptr_t)&sfp->sf_si; sf.sf_ah = (u_int32_t)(uintptr_t)catcher; /* Fill in POSIX parts */ sf.sf_si = siginfo; sf.sf_si.si_signo = sig; } else { /* Old FreeBSD-style arguments. */ sf.sf_siginfo = siginfo.si_code; sf.sf_addr = (u_int32_t)siginfo.si_addr; sf.sf_ah = (u_int32_t)(uintptr_t)catcher; } mtx_unlock(&psp->ps_mtx); /* * Copy the sigframe out to the user's stack. */ if (copyout(&sf, sfp, sizeof(*sfp)) != 0 || (xfpusave != NULL && copyout(xfpusave, PTRIN(sf.sf_uc.uc_mcontext.mc_xfpustate), xfpusave_len) != 0)) { #ifdef DEBUG printf("process %ld has trashed its stack\n", (long)p->p_pid); #endif PROC_LOCK(p); sigexit(td, SIGILL); } regs->tf_rsp = (uintptr_t)sfp; regs->tf_rip = p->p_sysent->sv_sigcode_base; regs->tf_rflags &= ~(PSL_T | PSL_D); regs->tf_cs = _ucode32sel; regs->tf_ss = _udatasel; regs->tf_ds = _udatasel; regs->tf_es = _udatasel; set_pcb_flags(td->td_pcb, PCB_FULL_IRET); /* XXXKIB leave user %fs and %gs untouched */ PROC_LOCK(p); mtx_lock(&psp->ps_mtx); }
static void freebsd4_ia32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) { struct ia32_sigframe4 sf, *sfp; struct siginfo32 siginfo; struct proc *p; struct thread *td; struct sigacts *psp; struct trapframe *regs; int oonstack; int sig; td = curthread; p = td->td_proc; siginfo_to_siginfo32(&ksi->ksi_info, &siginfo); PROC_LOCK_ASSERT(p, MA_OWNED); sig = siginfo.si_signo; psp = p->p_sigacts; mtx_assert(&psp->ps_mtx, MA_OWNED); regs = td->td_frame; oonstack = sigonstack(regs->tf_rsp); /* Save user context. */ bzero(&sf, sizeof(sf)); sf.sf_uc.uc_sigmask = *mask; sf.sf_uc.uc_stack.ss_sp = (uintptr_t)td->td_sigstk.ss_sp; sf.sf_uc.uc_stack.ss_size = td->td_sigstk.ss_size; sf.sf_uc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) ? ((oonstack) ? SS_ONSTACK : 0) : SS_DISABLE; sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; sf.sf_uc.uc_mcontext.mc_edi = regs->tf_rdi; sf.sf_uc.uc_mcontext.mc_esi = regs->tf_rsi; sf.sf_uc.uc_mcontext.mc_ebp = regs->tf_rbp; sf.sf_uc.uc_mcontext.mc_isp = regs->tf_rsp; /* XXX */ sf.sf_uc.uc_mcontext.mc_ebx = regs->tf_rbx; sf.sf_uc.uc_mcontext.mc_edx = regs->tf_rdx; sf.sf_uc.uc_mcontext.mc_ecx = regs->tf_rcx; sf.sf_uc.uc_mcontext.mc_eax = regs->tf_rax; sf.sf_uc.uc_mcontext.mc_trapno = regs->tf_trapno; sf.sf_uc.uc_mcontext.mc_err = regs->tf_err; sf.sf_uc.uc_mcontext.mc_eip = regs->tf_rip; sf.sf_uc.uc_mcontext.mc_cs = regs->tf_cs; sf.sf_uc.uc_mcontext.mc_eflags = regs->tf_rflags; sf.sf_uc.uc_mcontext.mc_esp = regs->tf_rsp; sf.sf_uc.uc_mcontext.mc_ss = regs->tf_ss; sf.sf_uc.uc_mcontext.mc_ds = regs->tf_ds; sf.sf_uc.uc_mcontext.mc_es = regs->tf_es; sf.sf_uc.uc_mcontext.mc_fs = regs->tf_fs; sf.sf_uc.uc_mcontext.mc_gs = regs->tf_gs; bzero(sf.sf_uc.uc_mcontext.mc_fpregs, sizeof(sf.sf_uc.uc_mcontext.mc_fpregs)); bzero(sf.sf_uc.uc_mcontext.__spare__, sizeof(sf.sf_uc.uc_mcontext.__spare__)); bzero(sf.sf_uc.__spare__, sizeof(sf.sf_uc.__spare__)); /* Allocate space for the signal handler context. */ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { sfp = (struct ia32_sigframe4 *)(td->td_sigstk.ss_sp + td->td_sigstk.ss_size - sizeof(sf)); } else sfp = (struct ia32_sigframe4 *)regs->tf_rsp - 1; PROC_UNLOCK(p); /* Translate the signal if appropriate. */ if (p->p_sysent->sv_sigtbl && sig <= p->p_sysent->sv_sigsize) sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; /* Build the argument list for the signal handler. */ sf.sf_signum = sig; sf.sf_ucontext = (register_t)&sfp->sf_uc; bzero(&sf.sf_si, sizeof(sf.sf_si)); if (SIGISMEMBER(psp->ps_siginfo, sig)) { /* Signal handler installed with SA_SIGINFO. */ sf.sf_siginfo = (u_int32_t)(uintptr_t)&sfp->sf_si; sf.sf_ah = (u_int32_t)(uintptr_t)catcher; /* Fill in POSIX parts */ sf.sf_si = siginfo; sf.sf_si.si_signo = sig; } else { /* Old FreeBSD-style arguments. */ sf.sf_siginfo = siginfo.si_code; sf.sf_addr = (u_int32_t)siginfo.si_addr; sf.sf_ah = (u_int32_t)(uintptr_t)catcher; } mtx_unlock(&psp->ps_mtx); /* * Copy the sigframe out to the user's stack. */ if (copyout(&sf, sfp, sizeof(*sfp)) != 0) { #ifdef DEBUG printf("process %ld has trashed its stack\n", (long)p->p_pid); #endif PROC_LOCK(p); sigexit(td, SIGILL); } regs->tf_rsp = (uintptr_t)sfp; regs->tf_rip = p->p_sysent->sv_sigcode_base + sz_ia32_sigcode - sz_freebsd4_ia32_sigcode; regs->tf_rflags &= ~(PSL_T | PSL_D); regs->tf_cs = _ucode32sel; regs->tf_ss = _udatasel; regs->tf_ds = _udatasel; regs->tf_es = _udatasel; set_pcb_flags(td->td_pcb, PCB_FULL_IRET); /* leave user %fs and %gs untouched */ PROC_LOCK(p); mtx_lock(&psp->ps_mtx); }
/* * Send an interrupt to process. * * Stack is set up to allow sigcode stored * in u. to call routine, followed by kcall * to sigreturn routine below. After sigreturn * resets the signal mask, the stack, and the * frame pointer, it returns to the user * specified pc, psl. */ static void linux_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) { struct thread *td = curthread; struct proc *p = td->td_proc; struct sigacts *psp; struct trapframe *regs; struct l_sigframe *fp, frame; l_sigset_t lmask; int oonstack, i; int sig, code; sig = ksi->ksi_signo; code = ksi->ksi_code; PROC_LOCK_ASSERT(p, MA_OWNED); psp = p->p_sigacts; mtx_assert(&psp->ps_mtx, MA_OWNED); if (SIGISMEMBER(psp->ps_siginfo, sig)) { /* Signal handler installed with SA_SIGINFO. */ linux_rt_sendsig(catcher, ksi, mask); return; } regs = td->td_frame; oonstack = sigonstack(regs->tf_rsp); #ifdef DEBUG if (ldebug(sendsig)) printf(ARGS(sendsig, "%p, %d, %p, %u"), catcher, sig, (void*)mask, code); #endif /* * Allocate space for the signal handler context. */ if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { fp = (struct l_sigframe *)(td->td_sigstk.ss_sp + td->td_sigstk.ss_size - sizeof(struct l_sigframe)); } else fp = (struct l_sigframe *)regs->tf_rsp - 1; mtx_unlock(&psp->ps_mtx); PROC_UNLOCK(p); /* * Build the argument list for the signal handler. */ if (p->p_sysent->sv_sigtbl) if (sig <= p->p_sysent->sv_sigsize) sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; bzero(&frame, sizeof(frame)); frame.sf_handler = PTROUT(catcher); frame.sf_sig = sig; bsd_to_linux_sigset(mask, &lmask); /* * Build the signal context to be used by sigreturn. */ frame.sf_sc.sc_mask = lmask.__bits[0]; frame.sf_sc.sc_gs = regs->tf_gs; frame.sf_sc.sc_fs = regs->tf_fs; frame.sf_sc.sc_es = regs->tf_es; frame.sf_sc.sc_ds = regs->tf_ds; frame.sf_sc.sc_edi = regs->tf_rdi; frame.sf_sc.sc_esi = regs->tf_rsi; frame.sf_sc.sc_ebp = regs->tf_rbp; frame.sf_sc.sc_ebx = regs->tf_rbx; frame.sf_sc.sc_edx = regs->tf_rdx; frame.sf_sc.sc_ecx = regs->tf_rcx; frame.sf_sc.sc_eax = regs->tf_rax; frame.sf_sc.sc_eip = regs->tf_rip; frame.sf_sc.sc_cs = regs->tf_cs; frame.sf_sc.sc_eflags = regs->tf_rflags; frame.sf_sc.sc_esp_at_signal = regs->tf_rsp; frame.sf_sc.sc_ss = regs->tf_ss; frame.sf_sc.sc_err = regs->tf_err; frame.sf_sc.sc_cr2 = (u_int32_t)(uintptr_t)ksi->ksi_addr; frame.sf_sc.sc_trapno = bsd_to_linux_trapcode(code); for (i = 0; i < (LINUX_NSIG_WORDS-1); i++) frame.sf_extramask[i] = lmask.__bits[i+1]; if (copyout(&frame, fp, sizeof(frame)) != 0) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ PROC_LOCK(p); sigexit(td, SIGILL); } /* * Build context to run handler in. */ regs->tf_rsp = PTROUT(fp); regs->tf_rip = p->p_sysent->sv_sigcode_base; regs->tf_rflags &= ~(PSL_T | PSL_D); regs->tf_cs = _ucode32sel; regs->tf_ss = _udatasel; regs->tf_ds = _udatasel; regs->tf_es = _udatasel; regs->tf_fs = _ufssel; regs->tf_gs = _ugssel; regs->tf_flags = TF_HASSEGS; set_pcb_flags(td->td_pcb, PCB_FULL_IRET); PROC_LOCK(p); mtx_lock(&psp->ps_mtx); }
/* * Send a signal to process. */ void sendsig_sigcontext(const ksiginfo_t *ksi, const sigset_t *returnmask) { int sig = ksi->ksi_signo; struct lwp * const l = curlwp; struct proc * const p = l->l_proc; struct sigacts * const ps = p->p_sigacts; struct pcb * const pcb = lwp_getpcb(l); int onstack, error; struct sigcontext *scp = getframe(l, sig, &onstack); struct sigcontext ksc; struct trapframe * const tf = l->l_md.md_utf; sig_t catcher = SIGACTION(p, sig).sa_handler; #if !defined(__mips_o32) if (p->p_md.md_abi != _MIPS_BSD_API_O32) sigexit(l, SIGILL); #endif scp--; #ifdef DEBUG if ((sigdebug & SDB_FOLLOW) || ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid)) printf("sendsig(%d): sig %d ssp %p scp %p\n", p->p_pid, sig, &onstack, scp); #endif /* Build stack frame for signal trampoline. */ ksc.sc_pc = tf->tf_regs[_R_PC]; ksc.mullo = tf->tf_regs[_R_MULLO]; ksc.mulhi = tf->tf_regs[_R_MULHI]; /* Save register context. */ ksc.sc_regs[_R_ZERO] = 0xACEDBADE; /* magic number */ #if defined(__mips_o32) memcpy(&ksc.sc_regs[1], &tf->tf_regs[1], sizeof(ksc.sc_regs) - sizeof(ksc.sc_regs[0])); #else for (size_t i = 1; i < 32; i++) ksc.sc_regs[i] = tf->tf_regs[i]; #endif /* Save the FP state, if necessary, then copy it. */ ksc.sc_fpused = fpu_used_p(); #if !defined(NOFPU) if (ksc.sc_fpused) { /* if FPU has current state, save it first */ fpu_save(); } #endif *(struct fpreg *)ksc.sc_fpregs = *(struct fpreg *)&pcb->pcb_fpregs; /* Save signal stack. */ ksc.sc_onstack = l->l_sigstk.ss_flags & SS_ONSTACK; /* Save signal mask. */ ksc.sc_mask = *returnmask; #if defined(COMPAT_13) || defined(COMPAT_ULTRIX) /* * XXX We always have to save an old style signal mask because * XXX we might be delivering a signal to a process which will * XXX escape from the signal in a non-standard way and invoke * XXX sigreturn() directly. */ native_sigset_to_sigset13(returnmask, &ksc.__sc_mask13); #endif sendsig_reset(l, sig); mutex_exit(p->p_lock); error = copyout(&ksc, (void *)scp, sizeof(ksc)); mutex_enter(p->p_lock); if (error != 0) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ #ifdef DEBUG if ((sigdebug & SDB_FOLLOW) || ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid)) printf("sendsig(%d): copyout failed on sig %d\n", p->p_pid, sig); #endif sigexit(l, SIGILL); /* NOTREACHED */ } /* * Set up the registers to directly invoke the signal * handler. The return address will be set up to point * to the signal trampoline to bounce us back. */ tf->tf_regs[_R_A0] = sig; tf->tf_regs[_R_A1] = ksi->ksi_trap; tf->tf_regs[_R_A2] = (intptr_t)scp; tf->tf_regs[_R_A3] = (intptr_t)catcher; /* XXX ??? */ tf->tf_regs[_R_PC] = (intptr_t)catcher; tf->tf_regs[_R_T9] = (intptr_t)catcher; tf->tf_regs[_R_SP] = (intptr_t)scp; switch (ps->sa_sigdesc[sig].sd_vers) { case 0: /* legacy on-stack sigtramp */ tf->tf_regs[_R_RA] = (intptr_t)p->p_sigctx.ps_sigcode; break; #ifdef COMPAT_16 case 1: tf->tf_regs[_R_RA] = (intptr_t)ps->sa_sigdesc[sig].sd_tramp; break; #endif default: /* Don't know what trampoline version; kill it. */ sigexit(l, SIGILL); } /* Remember that we're now on the signal stack. */ if (onstack) l->l_sigstk.ss_flags |= SS_ONSTACK; #ifdef DEBUG if ((sigdebug & SDB_FOLLOW) || ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid)) printf("sendsig(%d): sig %d returns\n", p->p_pid, sig); #endif }
static void linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) { struct thread *td = curthread; struct proc *p = td->td_proc; struct sigacts *psp; struct trapframe *regs; struct l_rt_sigframe *fp, frame; int oonstack; int sig; int code; sig = ksi->ksi_signo; code = ksi->ksi_code; PROC_LOCK_ASSERT(p, MA_OWNED); psp = p->p_sigacts; mtx_assert(&psp->ps_mtx, MA_OWNED); regs = td->td_frame; oonstack = sigonstack(regs->tf_rsp); #ifdef DEBUG if (ldebug(rt_sendsig)) printf(ARGS(rt_sendsig, "%p, %d, %p, %u"), catcher, sig, (void*)mask, code); #endif /* * Allocate space for the signal handler context. */ if ((td->td_pflags & TDP_ALTSTACK) && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { fp = (struct l_rt_sigframe *)(td->td_sigstk.ss_sp + td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe)); } else fp = (struct l_rt_sigframe *)regs->tf_rsp - 1; mtx_unlock(&psp->ps_mtx); /* * Build the argument list for the signal handler. */ if (p->p_sysent->sv_sigtbl) if (sig <= p->p_sysent->sv_sigsize) sig = p->p_sysent->sv_sigtbl[_SIG_IDX(sig)]; bzero(&frame, sizeof(frame)); frame.sf_handler = PTROUT(catcher); frame.sf_sig = sig; frame.sf_siginfo = PTROUT(&fp->sf_si); frame.sf_ucontext = PTROUT(&fp->sf_sc); /* Fill in POSIX parts */ ksiginfo_to_lsiginfo(ksi, &frame.sf_si, sig); /* * Build the signal context to be used by sigreturn. */ frame.sf_sc.uc_flags = 0; /* XXX ??? */ frame.sf_sc.uc_link = 0; /* XXX ??? */ frame.sf_sc.uc_stack.ss_sp = PTROUT(td->td_sigstk.ss_sp); frame.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size; frame.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE; PROC_UNLOCK(p); bsd_to_linux_sigset(mask, &frame.sf_sc.uc_sigmask); frame.sf_sc.uc_mcontext.sc_mask = frame.sf_sc.uc_sigmask.__bits[0]; frame.sf_sc.uc_mcontext.sc_edi = regs->tf_rdi; frame.sf_sc.uc_mcontext.sc_esi = regs->tf_rsi; frame.sf_sc.uc_mcontext.sc_ebp = regs->tf_rbp; frame.sf_sc.uc_mcontext.sc_ebx = regs->tf_rbx; frame.sf_sc.uc_mcontext.sc_edx = regs->tf_rdx; frame.sf_sc.uc_mcontext.sc_ecx = regs->tf_rcx; frame.sf_sc.uc_mcontext.sc_eax = regs->tf_rax; frame.sf_sc.uc_mcontext.sc_eip = regs->tf_rip; frame.sf_sc.uc_mcontext.sc_cs = regs->tf_cs; frame.sf_sc.uc_mcontext.sc_gs = regs->tf_gs; frame.sf_sc.uc_mcontext.sc_fs = regs->tf_fs; frame.sf_sc.uc_mcontext.sc_es = regs->tf_es; frame.sf_sc.uc_mcontext.sc_ds = regs->tf_ds; frame.sf_sc.uc_mcontext.sc_eflags = regs->tf_rflags; frame.sf_sc.uc_mcontext.sc_esp_at_signal = regs->tf_rsp; frame.sf_sc.uc_mcontext.sc_ss = regs->tf_ss; frame.sf_sc.uc_mcontext.sc_err = regs->tf_err; frame.sf_sc.uc_mcontext.sc_cr2 = (u_int32_t)(uintptr_t)ksi->ksi_addr; frame.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code); #ifdef DEBUG if (ldebug(rt_sendsig)) printf(LMSG("rt_sendsig flags: 0x%x, sp: %p, ss: 0x%lx, mask: 0x%x"), frame.sf_sc.uc_stack.ss_flags, td->td_sigstk.ss_sp, td->td_sigstk.ss_size, frame.sf_sc.uc_mcontext.sc_mask); #endif if (copyout(&frame, fp, sizeof(frame)) != 0) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ #ifdef DEBUG if (ldebug(rt_sendsig)) printf(LMSG("rt_sendsig: bad stack %p, oonstack=%x"), fp, oonstack); #endif PROC_LOCK(p); sigexit(td, SIGILL); } /* * Build context to run handler in. */ regs->tf_rsp = PTROUT(fp); regs->tf_rip = p->p_sysent->sv_sigcode_base + linux_sznonrtsigcode; regs->tf_rflags &= ~(PSL_T | PSL_D); regs->tf_cs = _ucode32sel; regs->tf_ss = _udatasel; regs->tf_ds = _udatasel; regs->tf_es = _udatasel; regs->tf_fs = _ufssel; regs->tf_gs = _ugssel; regs->tf_flags = TF_HASSEGS; set_pcb_flags(td->td_pcb, PCB_FULL_IRET); PROC_LOCK(p); mtx_lock(&psp->ps_mtx); }
/* * Send an interrupt to process. */ void sendsig_sigcontext(const ksiginfo_t *ksi, const sigset_t *mask) { struct lwp *l = curlwp; struct proc *p = l->l_proc; struct sigacts *ps = p->p_sigacts; struct frame *frame = (struct frame *)l->l_md.md_regs; int onstack; int sig = ksi->ksi_signo; u_long code = KSI_TRAPCODE(ksi); struct sigframe_sigcontext *fp = getframe(l, sig, &onstack), kf; sig_t catcher = SIGACTION(p, sig).sa_handler; short ft = frame->f_format; fp--; #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig(%d): sig %d ssp %p usp %p scp %p ft %d\n", p->p_pid, sig, &onstack, fp, &fp->sf_sc, ft); #endif /* Build stack frame for signal trampoline. */ switch (ps->sa_sigdesc[sig].sd_vers) { case 0: /* legacy on-stack sigtramp */ kf.sf_ra = (int)p->p_sigctx.ps_sigcode; break; case 1: kf.sf_ra = (int)ps->sa_sigdesc[sig].sd_tramp; break; default: /* Don't know what trampoline version; kill it. */ sigexit(l, SIGILL); } kf.sf_signum = sig; kf.sf_code = code; kf.sf_scp = &fp->sf_sc; /* * Save necessary hardware state. Currently this includes: * - general registers * - original exception frame (if not a "normal" frame) * - FP coprocessor state */ kf.sf_state.ss_flags = SS_USERREGS; memcpy(kf.sf_state.ss_frame.f_regs, frame->f_regs, sizeof(frame->f_regs)); if (ft >= FMT4) { #ifdef DEBUG if (ft > 15 || exframesize[ft] < 0) panic("sendsig: bogus frame type"); #endif kf.sf_state.ss_flags |= SS_RTEFRAME; kf.sf_state.ss_frame.f_format = frame->f_format; kf.sf_state.ss_frame.f_vector = frame->f_vector; memcpy(&kf.sf_state.ss_frame.F_u, &frame->F_u, (size_t) exframesize[ft]); /* * Leave an indicator that we need to clean up the kernel * stack. We do this by setting the "pad word" above the * hardware stack frame to the amount the stack must be * adjusted by. * * N.B. we increment rather than just set f_stackadj in * case we are called from syscall when processing a * sigreturn. In that case, f_stackadj may be non-zero. */ frame->f_stackadj += exframesize[ft]; frame->f_format = frame->f_vector = 0; #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sendsig(%d): copy out %d of frame %d\n", p->p_pid, exframesize[ft], ft); #endif } if (fputype) { kf.sf_state.ss_flags |= SS_FPSTATE; m68881_save(&kf.sf_state.ss_fpstate); } #ifdef DEBUG if ((sigdebug & SDB_FPSTATE) && *(char *)&kf.sf_state.ss_fpstate) printf("sendsig(%d): copy out FP state (%x) to %p\n", p->p_pid, *(u_int *)&kf.sf_state.ss_fpstate, &kf.sf_state.ss_fpstate); #endif /* Build the signal context to be used by sigreturn. */ kf.sf_sc.sc_sp = frame->f_regs[SP]; kf.sf_sc.sc_fp = frame->f_regs[A6]; kf.sf_sc.sc_ap = (int)&fp->sf_state; kf.sf_sc.sc_pc = frame->f_pc; kf.sf_sc.sc_ps = frame->f_sr; /* Save signal stack. */ kf.sf_sc.sc_onstack = p->p_sigctx.ps_sigstk.ss_flags & SS_ONSTACK; /* Save signal mask. */ kf.sf_sc.sc_mask = *mask; #ifdef COMPAT_13 /* * XXX We always have to save an old style signal mask because * XXX we might be delivering a signal to a process which will * XXX escape from the signal in a non-standard way and invoke * XXX sigreturn() directly. */ native_sigset_to_sigset13(mask, &kf.sf_sc.__sc_mask13); #endif if (copyout(&kf, fp, sizeof(kf)) != 0) { #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig(%d): copyout failed on sig %d\n", p->p_pid, sig); #endif /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ sigexit(l, SIGILL); /* NOTREACHED */ } #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sendsig(%d): sig %d scp %p fp %p sc_sp %x sc_ap %x\n", p->p_pid, sig, kf.sf_scp, fp, kf.sf_sc.sc_sp, kf.sf_sc.sc_ap); #endif buildcontext(l, catcher, fp); /* Remember that we're now on the signal stack. */ if (onstack) p->p_sigctx.ps_sigstk.ss_flags |= SS_ONSTACK; #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig(%d): sig %d returns\n", p->p_pid, sig); #endif }
void sendsig_sigcontext(const ksiginfo_t *ksi, const sigset_t *mask) { struct lwp *l = curlwp; struct proc *p = l->l_proc; struct sigacts *ps = p->p_sigacts; int onstack, sig = ksi->ksi_signo; struct sigframe_sigcontext *fp, frame; struct trapframe *tf; sig_t catcher = SIGACTION(p, sig).sa_handler; tf = l->l_md.md_tf; fp = getframe(l, sig, &onstack), frame; fp--; #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig_sigcontext(%d): sig %d ssp %p usp %p\n", p->p_pid, sig, &onstack, fp); #endif /* Build stack frame for signal trampoline. */ frame.sf_sc.sc_pc = tf->tf_regs[FRAME_PC]; frame.sf_sc.sc_ps = tf->tf_regs[FRAME_PS]; /* Save register context. */ frametoreg(tf, (struct reg *)frame.sf_sc.sc_regs); frame.sf_sc.sc_regs[R_ZERO] = 0xACEDBADE; /* magic number */ frame.sf_sc.sc_regs[R_SP] = alpha_pal_rdusp(); /* save the floating-point state, if necessary, then copy it. */ if (l->l_addr->u_pcb.pcb_fpcpu != NULL) fpusave_proc(l, 1); frame.sf_sc.sc_ownedfp = l->l_md.md_flags & MDP_FPUSED; memcpy((struct fpreg *)frame.sf_sc.sc_fpregs, &l->l_addr->u_pcb.pcb_fp, sizeof(struct fpreg)); frame.sf_sc.sc_fp_control = alpha_read_fp_c(l); memset(frame.sf_sc.sc_reserved, 0, sizeof frame.sf_sc.sc_reserved); memset(frame.sf_sc.sc_xxx, 0, sizeof frame.sf_sc.sc_xxx); /* XXX */ /* Save signal stack. */ frame.sf_sc.sc_onstack = p->p_sigctx.ps_sigstk.ss_flags & SS_ONSTACK; /* Save signal mask. */ frame.sf_sc.sc_mask = *mask; #ifdef COMPAT_13 /* * XXX We always have to save an old style signal mask because * XXX we might be delivering a signal to a process which will * XXX escape from the signal in a non-standard way and invoke * XXX sigreturn() directly. */ { /* Note: it's a long in the stack frame. */ sigset13_t mask13; native_sigset_to_sigset13(mask, &mask13); frame.sf_sc.__sc_mask13 = mask13; } #endif #ifdef COMPAT_OSF1 /* * XXX Create an OSF/1-style sigcontext and associated goo. */ #endif if (copyout(&frame, (caddr_t)fp, sizeof(frame)) != 0) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig_sigcontext(%d): copyout failed on sig %d\n", p->p_pid, sig); #endif sigexit(l, SIGILL); /* NOTREACHED */ } #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sendsig_sigcontext(%d): sig %d usp %p code %x\n", p->p_pid, sig, fp, ksi->ksi_code); #endif /* * Set up the registers to directly invoke the signal handler. The * signal trampoline is then used to return from the signal. Note * the trampoline version numbers are coordinated with machine- * dependent code in libc. */ switch (ps->sa_sigdesc[sig].sd_vers) { case 0: /* legacy on-stack sigtramp */ buildcontext(l,(void *)catcher, (void *)p->p_sigctx.ps_sigcode, (void *)fp); break; case 1: buildcontext(l,(void *)catcher, (void *)ps->sa_sigdesc[sig].sd_tramp, (void *)fp); break; default: /* Don't know what trampoline version; kill it. */ sigexit(l, SIGILL); } /* sigcontext specific trap frame */ tf->tf_regs[FRAME_A0] = sig; /* tf->tf_regs[FRAME_A1] = ksi->ksi_code; */ tf->tf_regs[FRAME_A1] = KSI_TRAPCODE(ksi); tf->tf_regs[FRAME_A2] = (u_int64_t)&fp->sf_sc; /* Remember that we're now on the signal stack. */ if (onstack) p->p_sigctx.ps_sigstk.ss_flags |= SS_ONSTACK; #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sendsig(%d): pc %lx, catcher %lx\n", p->p_pid, tf->tf_regs[FRAME_PC], tf->tf_regs[FRAME_A3]); if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig(%d): sig %d returns\n", p->p_pid, sig); #endif }
/* ARGSUSED */ int compat_16_netbsd32___sigreturn14(struct lwp *l, const struct compat_16_netbsd32___sigreturn14_args *uap, register_t *retval) { /* { syscallarg(struct sigcontext *) sigcntxp; } */ struct netbsd32_sigcontext sc, *scp; struct trapframe64 *tf; struct proc *p = l->l_proc; /* First ensure consistent stack state (see sendsig). */ write_user_windows(); if (rwindow_save(l)) { #ifdef DEBUG printf("netbsd32_sigreturn14: rwindow_save(%p) failed, sending SIGILL\n", p); Debugger(); #endif mutex_enter(p->p_lock); sigexit(l, SIGILL); } #ifdef DEBUG if (sigdebug & SDB_FOLLOW) { printf("netbsd32_sigreturn14: %s[%d], sigcntxp %p\n", p->p_comm, p->p_pid, SCARG(uap, sigcntxp)); if (sigdebug & SDB_DDB) Debugger(); } #endif scp = (struct netbsd32_sigcontext *)(u_long)SCARG(uap, sigcntxp); if ((vaddr_t)scp & 3 || (copyin((void *)scp, &sc, sizeof sc) != 0)) { #ifdef DEBUG printf("netbsd32_sigreturn14: copyin failed: scp=%p\n", scp); Debugger(); #endif return (EINVAL); } scp = ≻ tf = l->l_md.md_tf; /* * Only the icc bits in the psr are used, so it need not be * verified. pc and npc must be multiples of 4. This is all * that is required; if it holds, just do it. */ if (((sc.sc_pc | sc.sc_npc) & 3) != 0 || (sc.sc_pc == 0) || (sc.sc_npc == 0)) #ifdef DEBUG { printf("netbsd32_sigreturn14: pc %p or npc %p invalid\n", sc.sc_pc, sc.sc_npc); Debugger(); return (EINVAL); } #else return (EINVAL); #endif /* take only psr ICC field */ tf->tf_tstate = (int64_t)(tf->tf_tstate & ~TSTATE_CCR) | PSRCC_TO_TSTATE(sc.sc_psr); tf->tf_pc = (int64_t)sc.sc_pc; tf->tf_npc = (int64_t)sc.sc_npc; tf->tf_global[1] = (int64_t)sc.sc_g1; tf->tf_out[0] = (int64_t)sc.sc_o0; tf->tf_out[6] = (int64_t)sc.sc_sp; #ifdef DEBUG if (sigdebug & SDB_FOLLOW) { printf("netbsd32_sigreturn14: return trapframe pc=%p sp=%p tstate=%llx\n", (vaddr_t)tf->tf_pc, (vaddr_t)tf->tf_out[6], tf->tf_tstate); if (sigdebug & SDB_DDB) Debugger(); } #endif /* Restore signal stack. */ mutex_enter(p->p_lock); if (sc.sc_onstack & SS_ONSTACK) l->l_sigstk.ss_flags |= SS_ONSTACK; else l->l_sigstk.ss_flags &= ~SS_ONSTACK; /* Restore signal mask. */ (void) sigprocmask1(l, SIG_SETMASK, &sc.sc_mask, 0); mutex_exit(p->p_lock); return (EJUSTRETURN); }
void setup_linux_sigframe(struct trapframe *tf, const ksiginfo_t *ksi, const sigset_t *mask) { struct lwp *l = curlwp; struct proc *p = l->l_proc; struct linux_sigframe *sfp, sigframe; int onstack, error; int fsize, rndfsize; int sig = ksi->ksi_signo; extern char linux_sigcode[], linux_esigcode[]; /* Do we need to jump onto the signal stack? */ onstack = (l->l_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0; /* Allocate space for the signal handler context. */ fsize = sizeof(struct linux_sigframe); rndfsize = ((fsize + 15) / 16) * 16; if (onstack) sfp = (struct linux_sigframe *) ((char *)l->l_sigstk.ss_sp + l->l_sigstk.ss_size); else sfp = (struct linux_sigframe *)(alpha_pal_rdusp()); sfp = (struct linux_sigframe *)((char *)sfp - rndfsize); #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && (p->p_pid == sigpid)) printf("linux_sendsig(%d): sig %d ssp %p usp %p\n", p->p_pid, sig, &onstack, sfp); #endif /* DEBUG */ /* * Build the signal context to be used by sigreturn. */ memset(&sigframe.sf_sc, 0, sizeof(struct linux_sigcontext)); sigframe.sf_sc.sc_onstack = onstack; native_to_linux_old_sigset(&sigframe.sf_sc.sc_mask, mask); sigframe.sf_sc.sc_pc = tf->tf_regs[FRAME_PC]; sigframe.sf_sc.sc_ps = ALPHA_PSL_USERMODE; frametoreg(tf, (struct reg *)sigframe.sf_sc.sc_regs); sigframe.sf_sc.sc_regs[R_SP] = alpha_pal_rdusp(); if (l == fpcurlwp) { struct pcb *pcb = lwp_getpcb(l); alpha_pal_wrfen(1); savefpstate(&pcb->pcb_fp); alpha_pal_wrfen(0); sigframe.sf_sc.sc_fpcr = pcb->pcb_fp.fpr_cr; fpcurlwp = NULL; } /* XXX ownedfp ? etc...? */ sigframe.sf_sc.sc_traparg_a0 = tf->tf_regs[FRAME_A0]; sigframe.sf_sc.sc_traparg_a1 = tf->tf_regs[FRAME_A1]; sigframe.sf_sc.sc_traparg_a2 = tf->tf_regs[FRAME_A2]; sendsig_reset(l, sig); mutex_exit(p->p_lock); error = copyout((void *)&sigframe, (void *)sfp, fsize); mutex_enter(p->p_lock); if (error != 0) { #ifdef DEBUG if ((sigdebug & SDB_KSTACK) && p->p_pid == sigpid) printf("sendsig(%d): copyout failed on sig %d\n", p->p_pid, sig); #endif /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ sigexit(l, SIGILL); /* NOTREACHED */ } /* Pass pointers to sigcontext in the regs */ tf->tf_regs[FRAME_A1] = 0; tf->tf_regs[FRAME_A2] = (unsigned long)&sfp->sf_sc; /* Address of trampoline code. End up at this PC after mi_switch */ tf->tf_regs[FRAME_PC] = (u_int64_t)(p->p_psstrp - (linux_esigcode - linux_sigcode)); /* Adjust the stack */ alpha_pal_wrusp((unsigned long)sfp); /* Remember that we're now on the signal stack. */ if (onstack) l->l_sigstk.ss_flags |= SS_ONSTACK; }
void netbsd32_cpu_getmcontext( struct lwp *l, /* netbsd32_mcontext_t XXX */mcontext_t *mcp, unsigned int *flags) { #if 0 /* XXX */ greg32_t *gr = mcp->__gregs; const struct trapframe64 *tf = l->l_md.md_tf; /* First ensure consistent stack state (see sendsig). */ /* XXX? */ write_user_windows(); if (rwindow_save(l)) { mutex_enter(l->l_proc->p_lock); sigexit(l, SIGILL); } /* For now: Erase any random indicators for optional state. */ (void)memset(mcp, 0, sizeof (*mcp)); /* Save general register context. */ gr[_REG_PSR] = TSTATECCR_TO_PSR(tf->tf_tstate); gr[_REG_PC] = tf->tf_pc; gr[_REG_nPC] = tf->tf_npc; gr[_REG_Y] = tf->tf_y; gr[_REG_G1] = tf->tf_global[1]; gr[_REG_G2] = tf->tf_global[2]; gr[_REG_G3] = tf->tf_global[3]; gr[_REG_G4] = tf->tf_global[4]; gr[_REG_G5] = tf->tf_global[5]; gr[_REG_G6] = tf->tf_global[6]; gr[_REG_G7] = tf->tf_global[7]; gr[_REG_O0] = tf->tf_out[0]; gr[_REG_O1] = tf->tf_out[1]; gr[_REG_O2] = tf->tf_out[2]; gr[_REG_O3] = tf->tf_out[3]; gr[_REG_O4] = tf->tf_out[4]; gr[_REG_O5] = tf->tf_out[5]; gr[_REG_O6] = tf->tf_out[6]; gr[_REG_O7] = tf->tf_out[7]; *flags |= (_UC_CPU|_UC_TLSBASE); mcp->__gwins = 0; /* Save FP register context, if any. */ if (l->l_md.md_fpstate != NULL) { struct fpstate *fsp; netbsd32_fpregset_t *fpr = &mcp->__fpregs; /* * If our FP context is currently held in the FPU, take a * private snapshot - lazy FPU context switching can deal * with it later when it becomes necessary. * Otherwise, get it from the process's save area. */ fpusave_lwp(l, true); fsp = l->l_md.md_fpstate; memcpy(&fpr->__fpu_fr, fsp->fs_regs, sizeof (fpr->__fpu_fr)); mcp->__fpregs.__fpu_q = NULL; /* `Need more info.' */ mcp->__fpregs.__fpu_fsr = fs.fs_fsr; mcp->__fpregs.__fpu_qcnt = 0 /*fs.fs_qsize*/; /* See above */ mcp->__fpregs.__fpu_q_entrysize = sizeof (struct netbsd32_fq); mcp->__fpregs.__fpu_en = 1; *flags |= _UC_FPU; } else { mcp->__fpregs.__fpu_en = 0; } mcp->__xrs.__xrs_id = 0; /* Solaris extension? */ #endif }
void linux_sendsig(const ksiginfo_t *ksi, const sigset_t *mask) { const int sig = ksi->ksi_signo; struct lwp *l = curlwp; struct proc *p = l->l_proc; struct sigacts *ps = p->p_sigacts; struct linux_rt_sigframe *fp; struct frame *f; int i, onstack, error; struct linux_rt_sigframe sf; #ifdef DEBUG_LINUX printf("linux_sendsig()\n"); #endif /* DEBUG_LINUX */ f = (struct frame *)l->l_md.md_regs; /* * Do we need to jump onto the signal stack? */ onstack = (l->l_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0; /* * Allocate space for the signal handler context. */ if (onstack) panic("linux_sendsig: onstack notyet"); else fp = (struct linux_rt_sigframe *)(u_int32_t)f->f_regs[_R_SP]; /* * Build stack frame for signal trampoline. */ memset(&sf, 0, sizeof sf); #if LINUX_SYS_rt_sigreturn > 127 #error LINUX_SYS_rt_sigreturn does not fit in a 16-bit opcode. #endif /* * This is the signal trampoline used by Linux, we don't use it, * but we set it up in case an application expects it to be there. * * mov r8, LINUX_SYS_rt_sigreturn * scall */ sf.lrs_code = (0x3008d733 | LINUX_SYS_rt_sigreturn << 20); /* * The user context. */ native_to_linux_sigset(&sf.lrs_uc.luc_sigmask, mask); sf.lrs_uc.luc_flags = 0; sf.lrs_uc.luc_link = NULL; /* This is used regardless of SA_ONSTACK in Linux AVR32. */ sf.lrs_uc.luc_stack.ss_sp = l->l_sigstk.ss_sp; sf.lrs_uc.luc_stack.ss_size = l->l_sigstk.ss_size; sf.lrs_uc.luc_stack.ss_flags = 0; if (l->l_sigstk.ss_flags & SS_ONSTACK) sf.lrs_uc.luc_stack.ss_flags |= LINUX_SS_ONSTACK; if (l->l_sigstk.ss_flags & SS_DISABLE) sf.lrs_uc.luc_stack.ss_flags |= LINUX_SS_DISABLE; memcpy(sf.lrs_uc.luc_mcontext.lsc_regs, f->f_regs, sizeof(sf.lrs_uc.luc_mcontext.lsc_regs)); sendsig_reset(l, sig); /* * Install the sigframe onto the stack. */ fp -= sizeof(struct linux_rt_sigframe); mutex_exit(p->p_lock); error = copyout(&sf, fp, sizeof(sf)); mutex_enter(p->p_lock); if (error != 0) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ #ifdef DEBUG_LINUX printf("linux_sendsig: stack trashed\n"); #endif /* DEBUG_LINUX */ sigexit(l, SIGILL); /* NOTREACHED */ } #ifdef DEBUG_LINUX printf("sigcontext is at %p\n", &fp->lrs_sc); #endif /* DEBUG_LINUX */ /* Set up the registers to return to sigcode. */ f->f_regs[_R_SP] = (register_t)fp; f->f_regs[_R_R12] = native_to_linux_signo[sig]; f->f_regs[_R_R11] = 0; f->f_regs[_R_R10] = (register_t)&fp->lrs_uc; f->f_regs[_R_PC] = (register_t)SIGACTION(p, sig).sa_handler; #define RESTORER(p, sig) \ (p->p_sigacts->sa_sigdesc[(sig)].sd_tramp) if (ps->sa_sigdesc[sig].sd_vers != 0) f->f_regs[_R_LR] = (register_t)RESTORER(p, sig); else panic("linux_sendsig: SA_RESTORER"); /* Remember that we're now on the signal stack. */ if (onstack) l->l_sigstk.ss_flags |= SS_ONSTACK; return; }
/* * Send an interrupt to process. * * Stack is set up to allow sigcode stored * at top to call routine, followed by kcall * to sigreturn routine below. After sigreturn * resets the signal mask, the stack, and the * frame pointer, it returns to the user * specified pc, psl. */ static void freebsd32_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) { struct proc *p; struct thread *td; struct fpreg32 fpregs; struct reg32 regs; struct sigacts *psp; struct sigframe32 sf, *sfp; int sig; int oonstack; unsigned i; td = curthread; p = td->td_proc; PROC_LOCK_ASSERT(p, MA_OWNED); sig = ksi->ksi_signo; psp = p->p_sigacts; mtx_assert(&psp->ps_mtx, MA_OWNED); fill_regs32(td, ®s); oonstack = sigonstack(td->td_frame->sp); /* save user context */ bzero(&sf, sizeof sf); sf.sf_uc.uc_sigmask = *mask; sf.sf_uc.uc_stack.ss_sp = (int32_t)(intptr_t)td->td_sigstk.ss_sp; sf.sf_uc.uc_stack.ss_size = td->td_sigstk.ss_size; sf.sf_uc.uc_stack.ss_flags = td->td_sigstk.ss_flags; sf.sf_uc.uc_mcontext.mc_onstack = (oonstack) ? 1 : 0; sf.sf_uc.uc_mcontext.mc_pc = regs.r_regs[PC]; sf.sf_uc.uc_mcontext.mullo = regs.r_regs[MULLO]; sf.sf_uc.uc_mcontext.mulhi = regs.r_regs[MULHI]; sf.sf_uc.uc_mcontext.mc_tls = (int32_t)(intptr_t)td->td_md.md_tls; sf.sf_uc.uc_mcontext.mc_regs[0] = UCONTEXT_MAGIC; /* magic number */ for (i = 1; i < 32; i++) sf.sf_uc.uc_mcontext.mc_regs[i] = regs.r_regs[i]; sf.sf_uc.uc_mcontext.mc_fpused = td->td_md.md_flags & MDTD_FPUSED; if (sf.sf_uc.uc_mcontext.mc_fpused) { /* if FPU has current state, save it first */ if (td == PCPU_GET(fpcurthread)) MipsSaveCurFPState(td); fill_fpregs32(td, &fpregs); for (i = 0; i < 33; i++) sf.sf_uc.uc_mcontext.mc_fpregs[i] = fpregs.r_regs[i]; } /* Allocate and validate space for the signal handler context. */ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { sfp = (struct sigframe32 *)(((uintptr_t)td->td_sigstk.ss_sp + td->td_sigstk.ss_size - sizeof(struct sigframe32)) & ~(sizeof(__int64_t) - 1)); } else sfp = (struct sigframe32 *)((vm_offset_t)(td->td_frame->sp - sizeof(struct sigframe32)) & ~(sizeof(__int64_t) - 1)); /* Build the argument list for the signal handler. */ td->td_frame->a0 = sig; td->td_frame->a2 = (register_t)(intptr_t)&sfp->sf_uc; if (SIGISMEMBER(psp->ps_siginfo, sig)) { /* Signal handler installed with SA_SIGINFO. */ td->td_frame->a1 = (register_t)(intptr_t)&sfp->sf_si; /* sf.sf_ahu.sf_action = (__siginfohandler_t *)catcher; */ /* fill siginfo structure */ sf.sf_si.si_signo = sig; sf.sf_si.si_code = ksi->ksi_code; sf.sf_si.si_addr = td->td_frame->badvaddr; } else { /* Old FreeBSD-style arguments. */ td->td_frame->a1 = ksi->ksi_code; td->td_frame->a3 = td->td_frame->badvaddr; /* sf.sf_ahu.sf_handler = catcher; */ } mtx_unlock(&psp->ps_mtx); PROC_UNLOCK(p); /* * Copy the sigframe out to the user's stack. */ if (copyout(&sf, sfp, sizeof(struct sigframe32)) != 0) { /* * Something is wrong with the stack pointer. * ...Kill the process. */ PROC_LOCK(p); sigexit(td, SIGILL); } td->td_frame->pc = (register_t)(intptr_t)catcher; td->td_frame->t9 = (register_t)(intptr_t)catcher; td->td_frame->sp = (register_t)(intptr_t)sfp; /* * Signal trampoline code is at base of user stack. */ td->td_frame->ra = (register_t)(intptr_t)p->p_psstrings - *(p->p_sysent->sv_szsigcode); PROC_LOCK(p); mtx_lock(&psp->ps_mtx); }
void linux_sendsig(sig_t catcher, int sig, int mask, u_long code, int type, union sigval val) { struct proc *p = curproc; struct trapframe *tf; struct linux_sigframe *fp, frame; struct sigacts *psp = p->p_sigacts; int oonstack; tf = p->p_md.md_regs; oonstack = p->p_sigstk.ss_flags & SS_ONSTACK; /* * Allocate space for the signal handler context. */ if ((p->p_sigstk.ss_flags & SS_DISABLE) == 0 && !oonstack && (psp->ps_sigonstack & sigmask(sig))) { fp = (struct linux_sigframe *)((char *)p->p_sigstk.ss_sp + p->p_sigstk.ss_size - sizeof(struct linux_sigframe)); p->p_sigstk.ss_flags |= SS_ONSTACK; } else { fp = (struct linux_sigframe *)tf->tf_esp - 1; } frame.sf_handler = catcher; frame.sf_sig = bsd_to_linux_sig[sig]; /* * Build the signal context to be used by sigreturn. */ frame.sf_sc.sc_mask = mask; #ifdef VM86 if (tf->tf_eflags & PSL_VM) { frame.sf_sc.sc_gs = tf->tf_vm86_gs; frame.sf_sc.sc_fs = tf->tf_vm86_fs; frame.sf_sc.sc_es = tf->tf_vm86_es; frame.sf_sc.sc_ds = tf->tf_vm86_ds; frame.sf_sc.sc_eflags = get_vflags(p); } else #endif { frame.sf_sc.sc_fs = tf->tf_fs; frame.sf_sc.sc_gs = tf->tf_gs; frame.sf_sc.sc_es = tf->tf_es; frame.sf_sc.sc_ds = tf->tf_ds; frame.sf_sc.sc_eflags = tf->tf_eflags; } frame.sf_sc.sc_edi = tf->tf_edi; frame.sf_sc.sc_esi = tf->tf_esi; frame.sf_sc.sc_ebp = tf->tf_ebp; frame.sf_sc.sc_ebx = tf->tf_ebx; frame.sf_sc.sc_edx = tf->tf_edx; frame.sf_sc.sc_ecx = tf->tf_ecx; frame.sf_sc.sc_eax = tf->tf_eax; frame.sf_sc.sc_eip = tf->tf_eip; frame.sf_sc.sc_cs = tf->tf_cs; frame.sf_sc.sc_esp_at_signal = tf->tf_esp; frame.sf_sc.sc_ss = tf->tf_ss; frame.sf_sc.sc_err = tf->tf_err; frame.sf_sc.sc_trapno = tf->tf_trapno; if (copyout(&frame, fp, sizeof(frame)) != 0) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ sigexit(p, SIGILL); /* NOTREACHED */ } /* * Build context to run handler in. */ tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL); tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL); tf->tf_eip = p->p_sigcode; tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL); tf->tf_eflags &= ~(PSL_T|PSL_D|PSL_VM|PSL_AC); tf->tf_esp = (int)fp; tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL); }
static void linux_old_sendsig(const ksiginfo_t *ksi, const sigset_t *mask) { struct lwp *l = curlwp; struct proc *p = l->l_proc; struct trapframe *tf; struct linux_sigframe *fp, frame; int onstack, error; int sig = ksi->ksi_signo; sig_t catcher = SIGACTION(p, sig).sa_handler; struct sigaltstack *sas = &l->l_sigstk; tf = l->l_md.md_regs; /* Do we need to jump onto the signal stack? */ onstack = (sas->ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0; /* Allocate space for the signal handler context. */ if (onstack) fp = (struct linux_sigframe *) ((char *)sas->ss_sp + sas->ss_size); else fp = (struct linux_sigframe *)tf->tf_esp; fp--; DPRINTF(("old: onstack = %d, fp = %p sig = %d eip = 0x%x cr2 = 0x%x\n", onstack, fp, sig, tf->tf_eip, ((struct pcb *)lwp_getpcb(l))->pcb_cr2)); /* Build stack frame for signal trampoline. */ frame.sf_handler = catcher; frame.sf_sig = native_to_linux_signo[sig]; linux_save_sigcontext(l, tf, mask, &frame.sf_sc); sendsig_reset(l, sig); mutex_exit(p->p_lock); error = copyout(&frame, fp, sizeof(frame)); mutex_enter(p->p_lock); if (error != 0) { /* * Process has trashed its stack; give it an illegal * instruction to halt it in its tracks. */ sigexit(l, SIGILL); /* NOTREACHED */ } /* * Build context to run handler in. */ tf->tf_fs = GSEL(GUDATA_SEL, SEL_UPL); tf->tf_es = GSEL(GUDATA_SEL, SEL_UPL); tf->tf_ds = GSEL(GUDATA_SEL, SEL_UPL); tf->tf_eip = (int)p->p_sigctx.ps_sigcode; tf->tf_cs = GSEL(GUCODEBIG_SEL, SEL_UPL); tf->tf_eflags &= ~PSL_CLEARSIG; tf->tf_esp = (int)fp; tf->tf_ss = GSEL(GUDATA_SEL, SEL_UPL); /* Remember that we're now on the signal stack. */ if (onstack) sas->ss_flags |= SS_ONSTACK; }
/* * copied from amd64/amd64/machdep.c * * Send an interrupt to process. */ static void linux_rt_sendsig(sig_t catcher, ksiginfo_t *ksi, sigset_t *mask) { struct l_rt_sigframe sf, *sfp; struct proc *p; struct thread *td; struct sigacts *psp; caddr_t sp; struct trapframe *regs; int sig, code; int oonstack; td = curthread; p = td->td_proc; PROC_LOCK_ASSERT(p, MA_OWNED); sig = ksi->ksi_signo; psp = p->p_sigacts; code = ksi->ksi_code; mtx_assert(&psp->ps_mtx, MA_OWNED); regs = td->td_frame; oonstack = sigonstack(regs->tf_rsp); LINUX_CTR4(rt_sendsig, "%p, %d, %p, %u", catcher, sig, mask, code); /* Allocate space for the signal handler context. */ if ((td->td_pflags & TDP_ALTSTACK) != 0 && !oonstack && SIGISMEMBER(psp->ps_sigonstack, sig)) { sp = (caddr_t)td->td_sigstk.ss_sp + td->td_sigstk.ss_size - sizeof(struct l_rt_sigframe); } else sp = (caddr_t)regs->tf_rsp - sizeof(struct l_rt_sigframe) - 128; /* Align to 16 bytes. */ sfp = (struct l_rt_sigframe *)((unsigned long)sp & ~0xFul); mtx_unlock(&psp->ps_mtx); /* Translate the signal. */ sig = bsd_to_linux_signal(sig); /* Save user context. */ bzero(&sf, sizeof(sf)); bsd_to_linux_sigset(mask, &sf.sf_sc.uc_sigmask); bsd_to_linux_sigset(mask, &sf.sf_sc.uc_mcontext.sc_mask); sf.sf_sc.uc_stack.ss_sp = PTROUT(td->td_sigstk.ss_sp); sf.sf_sc.uc_stack.ss_size = td->td_sigstk.ss_size; sf.sf_sc.uc_stack.ss_flags = (td->td_pflags & TDP_ALTSTACK) ? ((oonstack) ? LINUX_SS_ONSTACK : 0) : LINUX_SS_DISABLE; PROC_UNLOCK(p); sf.sf_sc.uc_mcontext.sc_rdi = regs->tf_rdi; sf.sf_sc.uc_mcontext.sc_rsi = regs->tf_rsi; sf.sf_sc.uc_mcontext.sc_rdx = regs->tf_rdx; sf.sf_sc.uc_mcontext.sc_rbp = regs->tf_rbp; sf.sf_sc.uc_mcontext.sc_rbx = regs->tf_rbx; sf.sf_sc.uc_mcontext.sc_rcx = regs->tf_rcx; sf.sf_sc.uc_mcontext.sc_rax = regs->tf_rax; sf.sf_sc.uc_mcontext.sc_rip = regs->tf_rip; sf.sf_sc.uc_mcontext.sc_rsp = regs->tf_rsp; sf.sf_sc.uc_mcontext.sc_r8 = regs->tf_r8; sf.sf_sc.uc_mcontext.sc_r9 = regs->tf_r9; sf.sf_sc.uc_mcontext.sc_r10 = regs->tf_r10; sf.sf_sc.uc_mcontext.sc_r11 = regs->tf_r11; sf.sf_sc.uc_mcontext.sc_r12 = regs->tf_r12; sf.sf_sc.uc_mcontext.sc_r13 = regs->tf_r13; sf.sf_sc.uc_mcontext.sc_r14 = regs->tf_r14; sf.sf_sc.uc_mcontext.sc_r15 = regs->tf_r15; sf.sf_sc.uc_mcontext.sc_cs = regs->tf_cs; sf.sf_sc.uc_mcontext.sc_rflags = regs->tf_rflags; sf.sf_sc.uc_mcontext.sc_err = regs->tf_err; sf.sf_sc.uc_mcontext.sc_trapno = bsd_to_linux_trapcode(code); sf.sf_sc.uc_mcontext.sc_cr2 = (register_t)ksi->ksi_addr; /* Build the argument list for the signal handler. */ regs->tf_rdi = sig; /* arg 1 in %rdi */ regs->tf_rax = 0; regs->tf_rsi = (register_t)&sfp->sf_si; /* arg 2 in %rsi */ regs->tf_rdx = (register_t)&sfp->sf_sc; /* arg 3 in %rdx */ sf.sf_handler = catcher; /* Fill in POSIX parts */ ksiginfo_to_lsiginfo(ksi, &sf.sf_si, sig); /* * Copy the sigframe out to the user's stack. */ if (copyout(&sf, sfp, sizeof(*sfp)) != 0) { #ifdef DEBUG printf("process %ld has trashed its stack\n", (long)p->p_pid); #endif PROC_LOCK(p); sigexit(td, SIGILL); } regs->tf_rsp = (long)sfp; regs->tf_rip = linux_rt_sigcode; regs->tf_rflags &= ~(PSL_T | PSL_D); regs->tf_cs = _ucodesel; set_pcb_flags(td->td_pcb, PCB_FULL_IRET); PROC_LOCK(p); mtx_lock(&psp->ps_mtx); }