int sigaction( int sig, const struct sigaction *act, struct sigaction *oact ) { struct sigaction tmp, *my_act = &tmp; if( act ) { *my_act = *act; } else { my_act = NULL; } if ( MappingFileDescriptors() && act ) { /* called by User code */ switch (sig) { case SIGUSR2: case SIGTSTP: case SIGCONT: /* don't let user code mess with these signals */ errno = EINVAL; return -1; default: /* block checkpointing inside users signal handler */ sigaddset( &(my_act->sa_mask), SIGTSTP ); sigaddset( &(my_act->sa_mask), SIGUSR2 ); } } return SIGACTION( sig, my_act, oact); }
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; }
int wmain(int argc, wchar_t *argv[]) { STARTW(argc, argv, "vmem_create_win"); if (argc < 2 || argc > 3) UT_FATAL("usage: %s directory", ut_toUTF8(argv[0])); Vmp = vmem_createW(argv[1], VMEM_MIN_POOL); if (Vmp == NULL) UT_OUT("!vmem_create"); else { struct sigaction v; sigemptyset(&v.sa_mask); v.sa_flags = 0; v.sa_handler = signal_handler; if (SIGACTION(SIGSEGV, &v, NULL) != 0) UT_FATAL("!sigaction"); /* try to dereference the opaque handle */ char x = *(char *)Vmp; UT_OUT("x = %c", x); } UT_FATAL("no signal received"); }
void linux_sendsig(const ksiginfo_t *ksi, const sigset_t *mask) { if (SIGACTION(curproc, ksi->ksi_signo).sa_flags & SA_SIGINFO) linux_rt_sendsig(ksi, mask); else linux_old_sendsig(ksi, mask); }
/* * 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; }
void * cpu_sendsig_getframe(struct lwp *l, int signo, bool *onstack) { struct trapframe * const tf = l->l_md.md_utf; struct proc * const p = l->l_proc; /* Do we need to jump onto the signal stack? */ *onstack = (l->l_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && (SIGACTION(p, signo).sa_flags & SA_ONSTACK) != 0; if (*onstack) return (char *)stack_align((intptr_t)l->l_sigstk.ss_sp + l->l_sigstk.ss_size); return (void *)(intptr_t)stack_align(tf->tf_sp); }
void * getframe(struct proc *p, int sig, int *onstack) { struct sigctx *ctx = &p->p_sigctx; struct trapframe *tf = process_frame(l); /* Do we need to jump onto the signal stack? */ *onstack = (ctx->ps_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0; if (*onstack) return (char *)ctx->ps_sigstk.ss_sp + ctx->ps_sigstk.ss_size; return (void *)tf->tf_usr_sp; }
/* * Get the base address of the signal frame either on the lwp's stack * or on the signal stack and set *onstack accordingly. Caller then * just subtracts the size of appropriate struct sigframe_foo. */ static void * getframe(struct lwp *l, int sig, int *onstack) { struct proc *p = l->l_proc; struct sigaltstack *sigstk= &l->l_sigstk; /* Do we need to jump onto the signal stack? */ *onstack = (sigstk->ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0; if (*onstack) return ((char *)sigstk->ss_sp + sigstk->ss_size); else return ((void *)l->l_md.md_regs->tf_r15); }
/* * 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. */ void linux_sendsig(const ksiginfo_t *ksi, const sigset_t *mask) { struct lwp *l = curlwp; struct proc *p = l->l_proc; struct trapframe *tf = l->l_md.md_tf; const int sig = ksi->ksi_signo; sig_t catcher = SIGACTION(p, sig).sa_handler; #ifdef notyet struct linux_emuldata *edp; /* Setup the signal frame (and part of the trapframe) */ /*OLD: if (p->p_sigacts->ps_siginfo & sigmask(sig))*/ /* XXX XAX this is broken now. need someplace to store what XXX XAX kind of signal handler a signal has.*/ #if 0 edp = (struct linux_emuldata *)p->p_emuldata; #else edp = 0; #endif if (edp && sigismember(&edp->ps_siginfo, sig)) setup_linux_rt_sigframe(tf, ksi, mask); else #endif /* notyet */ setup_linux_sigframe(tf, ksi, mask); /* Signal handler for trampoline code */ tf->tf_regs[FRAME_T12] = (u_int64_t)catcher; tf->tf_regs[FRAME_A0] = native_to_linux_signo[sig]; /* * Linux has a custom restorer option. To support it we would * need to store an array of restorers and a sigcode block * which knew to use it. Doesn't seem worth the trouble. * -erh */ #ifdef DEBUG if (sigdebug & SDB_FOLLOW) printf("sendsig(%d): pc %lx, catcher %lx\n", l->l_proc->p_pid, tf->tf_regs[FRAME_PC], tf->tf_regs[FRAME_A3]); if ((sigdebug & SDB_KSTACK) && l->l_proc->p_pid == sigpid) printf("sendsig(%d): sig %d returns\n", l->l_proc->p_pid, sig); #endif }
int main(int argc, char *argv[]) { PMEMlogpool *plp; START(argc, argv, "log_walker"); if (argc != 2) UT_FATAL("usage: %s file-name", argv[0]); const char *path = argv[1]; int fd = OPEN(path, O_RDWR); /* pre-allocate 2MB of persistent memory */ errno = posix_fallocate(fd, (off_t)0, (size_t)(2 * 1024 * 1024)); if (errno != 0) UT_FATAL("!posix_fallocate"); CLOSE(fd); if ((plp = pmemlog_create(path, 0, S_IWUSR | S_IRUSR)) == NULL) UT_FATAL("!pmemlog_create: %s", path); /* append some data */ do_append(plp); /* arrange to catch SEGV */ struct sigaction v; sigemptyset(&v.sa_mask); v.sa_flags = 0; v.sa_handler = signal_handler; SIGACTION(SIGSEGV, &v, NULL); if (!sigsetjmp(Jmp, 1)) { do_walk(plp); } pmemlog_close(plp); DONE(NULL); }
/* * do_check -- check the mapping */ static void do_check(int fd, void *addr, size_t mlen) { /* arrange to catch SEGV */ struct sigaction v; sigemptyset(&v.sa_mask); v.sa_flags = 0; v.sa_handler = signal_handler; SIGACTION(SIGSEGV, &v, NULL); char pat[CHECK_BYTES]; char buf[CHECK_BYTES]; /* write some pattern to the file */ memset(pat, 0x5A, CHECK_BYTES); WRITE(fd, pat, CHECK_BYTES); if (memcmp(pat, addr, CHECK_BYTES)) UT_OUT("first %d bytes do not match", CHECK_BYTES); /* fill up mapped region with new pattern */ memset(pat, 0xA5, CHECK_BYTES); memcpy(addr, pat, CHECK_BYTES); UT_ASSERTeq(pmem_msync(addr, CHECK_BYTES), 0); UT_ASSERTeq(pmem_unmap(addr, mlen), 0); if (!ut_sigsetjmp(Jmp)) { /* same memcpy from above should now fail */ memcpy(addr, pat, CHECK_BYTES); } else { UT_OUT("unmap successful"); } LSEEK(fd, (os_off_t)0, SEEK_SET); if (READ(fd, buf, CHECK_BYTES) == CHECK_BYTES) { if (memcmp(pat, buf, CHECK_BYTES)) UT_OUT("first %d bytes do not match", CHECK_BYTES); } }
/* * check_access -- check access to mapped memory */ static void check_access(char *addr, size_t len, int prot) { volatile int i; /* arrange to catch SEGV */ struct sigaction v; sigemptyset(&v.sa_mask); v.sa_flags = 0; v.sa_handler = signal_handler; SIGACTION(SIGSEGV, &v, NULL); char pat[PAGE_SIZE]; char buf[PAGE_SIZE]; for (i = 0; i < len / PAGE_SIZE; i++) { /* check read access */ if (!ut_sigsetjmp(Jmp)) { memcpy(buf, addr + PAGE_SIZE * i, PAGE_SIZE); if ((prot & PROT_READ) == 0) UT_FATAL("memory can be read"); } else { if (prot & PROT_READ) UT_FATAL("memory cannot be read"); } } /* fill up mapped region with new pattern */ memset(pat, 0xA5, PAGE_SIZE); for (i = 0; i < len / PAGE_SIZE; i++) { if (!ut_sigsetjmp(Jmp)) { memcpy(addr + PAGE_SIZE * i, pat, PAGE_SIZE); if ((prot & PROT_WRITE) == 0) UT_FATAL("memory can be written"); } else { if (prot & PROT_WRITE) UT_FATAL("memory cannot be written"); } } }
static void setup_sync_signal_handlers() { /* * Setup synchronous handlers. Note that we get the current state of * each signal and then just change the handler field. Reputed to * be better for some implementations. */ #ifdef HAVE_OS_WIN32 #define SIGACTION(_sig) signal(_sig, sync_signal_handler) #else #define SIGACTION(_sig) \ { \ struct sigaction action; \ (void)sigaction((_sig), (struct sigaction *)0, &action); \ if (action.sa_handler == SIG_DFL) \ action.sa_handler = (__sighandler_t) sync_signal_handler; \ (void)sigaction((_sig), &action, (struct sigaction *)0); \ }; #endif /* * initialize the PER-PROCESS sync signal policy table, * if it hasnt already been done. */ pthread_once(&_dce_exclib_syncsig_setdefault, _set_dceexc_syncsignals_default); #if defined(SIGIOT) if (_dce_exclib_syncsig_catch[SIGIOT]) SIGACTION(SIGIOT); #endif #if defined(SIGEMT) if (_dce_exclib_syncsig_catch[SIGEMT]) SIGACTION(SIGEMT); #endif #if defined(SIGILL) if (_dce_exclib_syncsig_catch[SIGILL]) SIGACTION(SIGILL); #endif #if defined(SIGTRAP) if (_dce_exclib_syncsig_catch[SIGTRAP]) SIGACTION(SIGTRAP); #endif #if defined(SIGFPE) if (_dce_exclib_syncsig_catch[SIGFPE]) SIGACTION(SIGFPE); #endif #if defined(SIGBUS) if (_dce_exclib_syncsig_catch[SIGBUS]) SIGACTION(SIGBUS); #endif #if defined(SIGSEGV) if (_dce_exclib_syncsig_catch[SIGSEGV]) SIGACTION(SIGSEGV); #endif #if defined(SIGSYS) if (_dce_exclib_syncsig_catch[SIGSYS]) SIGACTION(SIGSYS); #endif #if defined(SIGPIPE) if (_dce_exclib_syncsig_catch[SIGPIPE]) SIGACTION(SIGPIPE); #endif #undef SIGACTION }
/* * Send an interrupt to process. */ void sendsig(const struct ksiginfo *ksi, const sigset_t *mask) { /* XXX we don't deliver siginfo yet */ int sig = ksi->ksi_signo; u_long code = ksi->ksi_trap; struct lwp *l = curlwp; struct proc *p = l->l_proc; struct sigacts *ps = p->p_sigacts; struct sigframe *fp, kf; caddr_t sp; struct trapframe *tf; int onstack, fsize; sig_t catcher = SIGACTION(p, sig).sa_handler; tf = (struct trapframe *)l->l_md.md_regs; /* Do we need to jump onto the signal stack? */ onstack = (p->p_sigctx.ps_sigstk.ss_flags & (SS_DISABLE | SS_ONSTACK)) == 0 && (SIGACTION(p, sig).sa_flags & SA_ONSTACK) != 0; /* * Allocate space for the signal handler context. * The PA-RISC calling convention mandates that * the stack pointer must always be 64-byte aligned, * and points to the first *unused* byte. */ fsize = sizeof(struct sigframe); sp = (onstack ? (caddr_t)p->p_sigctx.ps_sigstk.ss_sp : (caddr_t)tf->tf_sp); sp = (caddr_t)(((u_int)(sp + fsize + 63)) & ~63); fp = (struct sigframe *) (sp - fsize); #ifdef DEBUG if ((sigdebug & SDB_FOLLOW) && (!sigpid || p->p_pid == sigpid)) printf("sendsig: %s[%d] sig %d catcher %p\n", p->p_comm, p->p_pid, sig, catcher); #endif /* * Save necessary hardware state. Currently this includes: * - original exception frame * - FP coprocessor state */ kf.sf_state.ss_flags = SS_USERREGS; memcpy(&kf.sf_state.ss_frame, tf, sizeof(*tf)); /* XXX FP state */ /* Build the signal context to be used by sigreturn. */ kf.sf_sc.sc_sp = tf->tf_sp; kf.sf_sc.sc_fp = tf->tf_sp; /* XXX fredette - is this right? */ kf.sf_sc.sc_ap = (int)&fp->sf_state; kf.sf_sc.sc_pcsqh = tf->tf_iisq_head; kf.sf_sc.sc_pcoqh = tf->tf_iioq_head; kf.sf_sc.sc_pcsqt = tf->tf_iisq_tail; kf.sf_sc.sc_pcoqt = tf->tf_iioq_tail; kf.sf_sc.sc_ps = tf->tf_ipsw; /* 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; /* Fill the calling convention part of the signal frame. */ kf.sf_psp = 0; kf.sf_clup = 0; /* XXX fredette - is this right? */ kf.sf_sl = 0; /* XXX fredette - is this right? */ kf.sf_edp = 0; /* XXX fredette - is this right? */ /* Copy out the signal frame. */ if (copyout(&kf, fp, fsize)) { #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, &fp->sf_sc, fp, kf.sf_sc.sc_sp, kf.sf_sc.sc_ap); #endif /* Set up the registers to return to sigcode. */ switch (ps->sa_sigdesc[sig].sd_vers) { #if 1 /* COMPAT_16 */ case 0: /* legacy on-stack sigtramp */ tf->tf_iioq_head = (int)p->p_sigctx.ps_sigcode | HPPA_PC_PRIV_USER; tf->tf_iioq_tail = tf->tf_iioq_head + 4; break; #endif case 1: tf->tf_iioq_head = (int)ps->sa_sigdesc[sig].sd_tramp | HPPA_PC_PRIV_USER; tf->tf_iioq_tail = tf->tf_iioq_head + 4; break; default: /* Don't know what trampoline version; kill it. */ sigexit(l, SIGILL); } tf->tf_sp = (int)sp; tf->tf_r3 = (int)&fp->sf_sc; tf->tf_arg0 = sig; tf->tf_arg1 = code; tf->tf_arg2 = (int)&fp->sf_sc; tf->tf_arg3 = (int)catcher; /* 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 }
/* * 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 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 trapframe *tf = l->l_md.md_regs; int sig = ksi->ksi_info._signo; sig_t catcher = SIGACTION(p, sig).sa_handler; struct sigframe_sigcontext *fp, frame; int onstack, error; fp = getframe(l, sig, &onstack); --fp; /* Save register context. */ frame.sf_sc.sc_ssr = tf->tf_ssr; frame.sf_sc.sc_spc = tf->tf_spc; frame.sf_sc.sc_pr = tf->tf_pr; frame.sf_sc.sc_r15 = tf->tf_r15; frame.sf_sc.sc_r14 = tf->tf_r14; frame.sf_sc.sc_r13 = tf->tf_r13; frame.sf_sc.sc_r12 = tf->tf_r12; frame.sf_sc.sc_r11 = tf->tf_r11; frame.sf_sc.sc_r10 = tf->tf_r10; frame.sf_sc.sc_r9 = tf->tf_r9; frame.sf_sc.sc_r8 = tf->tf_r8; frame.sf_sc.sc_r7 = tf->tf_r7; frame.sf_sc.sc_r6 = tf->tf_r6; frame.sf_sc.sc_r5 = tf->tf_r5; frame.sf_sc.sc_r4 = tf->tf_r4; frame.sf_sc.sc_r3 = tf->tf_r3; frame.sf_sc.sc_r2 = tf->tf_r2; frame.sf_sc.sc_r1 = tf->tf_r1; frame.sf_sc.sc_r0 = tf->tf_r0; frame.sf_sc.sc_expevt = tf->tf_expevt; /* Save signal stack. */ frame.sf_sc.sc_onstack = l->l_sigstk.ss_flags & SS_ONSTACK; /* Save signal mask. */ frame.sf_sc.sc_mask = *mask; 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. We invoke the handler * directly, only returning via the trampoline. */ switch (ps->sa_sigdesc[sig].sd_vers) { case 0: /* legacy on-stack sigtramp */ tf->tf_pr = (int)p->p_sigctx.ps_sigcode; break; case 1: tf->tf_pr = (int)ps->sa_sigdesc[sig].sd_tramp; break; default: /* Don't know what trampoline version; kill it. */ printf("sendsig_sigcontext: bad version %d\n", ps->sa_sigdesc[sig].sd_vers); sigexit(l, SIGILL); } tf->tf_r4 = sig; tf->tf_r5 = ksi->ksi_code; tf->tf_r6 = (int)&fp->sf_sc; tf->tf_spc = (int)catcher; tf->tf_r15 = (int)fp; /* Remember if we're now on the signal stack. */ if (onstack) l->l_sigstk.ss_flags |= SS_ONSTACK; }
int main(int argc, char *argv[]) { START(argc, argv, "blk_recovery"); if (argc != 5) FATAL("usage: %s bsize file first_lba lba", argv[0]); Bsize = strtoul(argv[1], NULL, 0); const char *path = argv[2]; PMEMblkpool *handle; if ((handle = pmemblk_create(path, Bsize, 0, S_IWUSR | S_IRUSR)) == NULL) FATAL("!%s: pmemblk_create", path); OUT("%s block size %zu usable blocks %zu", argv[1], Bsize, pmemblk_nblock(handle)); /* write the first lba */ off_t lba = strtoul(argv[3], NULL, 0); unsigned char buf[Bsize]; construct(buf); if (pmemblk_write(handle, buf, lba) < 0) FATAL("!write lba %zu", lba); OUT("write lba %zu: %s", lba, ident(buf)); /* reach into the layout and write-protect the map */ struct btt_info *infop = (void *)handle + roundup(sizeof (struct pmemblk), BLK_FORMAT_DATA_ALIGN); void *mapaddr = (void *)infop + le32toh(infop->mapoff); void *flogaddr = (void *)infop + le32toh(infop->flogoff); OUT("write-protecting map, length %zu", (size_t)(flogaddr - mapaddr)); MPROTECT(mapaddr, (size_t)(flogaddr - mapaddr), PROT_READ); /* arrange to catch SEGV */ struct sigaction v; sigemptyset(&v.sa_mask); v.sa_flags = 0; v.sa_handler = signal_handler; SIGACTION(SIGSEGV, &v, NULL); /* map each file argument with the given map type */ lba = strtoul(argv[4], NULL, 0); construct(buf); if (!sigsetjmp(Jmp, 1)) { if (pmemblk_write(handle, buf, lba) < 0) FATAL("!write lba %zu", lba); else FATAL("write lba %zu: %s", lba, ident(buf)); } pmemblk_close(handle); int result = pmemblk_check(path); if (result < 0) OUT("!%s: pmemblk_check", path); else if (result == 0) OUT("%s: pmemblk_check: not consistent", path); else OUT("%s: consistent", path); DONE(NULL); }
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; }
/* * 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 }
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; }
/** * Eventually calls exit(), passing @p code, therefore does not return. * * @param code one of the RERR_* codes from errcode.h. **/ NORETURN void _exit_cleanup(int code, const char *file, int line) { static int switch_step = 0; static int exit_code = 0, exit_line = 0; static const char *exit_file = NULL; static int first_code = 0; SIGACTION(SIGUSR1, SIG_IGN); SIGACTION(SIGUSR2, SIG_IGN); if (!exit_code) { /* Preserve first error exit info when recursing. */ exit_code = code; exit_file = file; exit_line = line < 0 ? -line : line; } /* If this is the exit at the end of the run, the server side * should not attempt to output a message (see log_exit()). */ if (am_server && code == 0) am_server = 2; /* Some of our actions might cause a recursive call back here, so we * keep track of where we are in the cleanup and never repeat a step. */ switch (switch_step) { #include "case_N.h" /* case 0: */ switch_step++; first_code = code; if (output_needs_newline) { fputc('\n', stdout); output_needs_newline = 0; } if (DEBUG_GTE(EXIT, 2)) { rprintf(FINFO, "[%s] _exit_cleanup(code=%d, file=%s, line=%d): entered\n", who_am_i(), code, file, line); } /* FALLTHROUGH */ #include "case_N.h" switch_step++; if (cleanup_child_pid != -1) { int status; int pid = wait_process(cleanup_child_pid, &status, WNOHANG); if (pid == cleanup_child_pid) { status = WEXITSTATUS(status); if (status > exit_code) exit_code = status; } } /* FALLTHROUGH */ #include "case_N.h" switch_step++; if (cleanup_got_literal && (cleanup_fname || cleanup_fd_w != -1)) { if (cleanup_fd_r != -1) { close(cleanup_fd_r); cleanup_fd_r = -1; } if (cleanup_fd_w != -1) { flush_write_file(cleanup_fd_w); close(cleanup_fd_w); cleanup_fd_w = -1; } if (cleanup_fname && cleanup_new_fname && keep_partial && handle_partial_dir(cleanup_new_fname, PDIR_CREATE)) { int tweak_modtime = 0; const char *fname = cleanup_fname; cleanup_fname = NULL; if (!partial_dir) { /* We don't want to leave a partial file with a modern time or it * could be skipped via --update. Setting the time to something * really old also helps it to stand out as unfinished in an ls. */ tweak_modtime = 1; cleanup_file->modtime = 0; } finish_transfer(cleanup_new_fname, fname, NULL, NULL, cleanup_file, tweak_modtime, !partial_dir); } } /* FALLTHROUGH */ #include "case_N.h" switch_step++; if (flush_ok_after_signal) { flush_ok_after_signal = False; if (code == RERR_SIGNAL) io_flush(FULL_FLUSH); } if (!exit_code && !code) io_flush(FULL_FLUSH); /* FALLTHROUGH */ #include "case_N.h" switch_step++; if (cleanup_fname) do_unlink(cleanup_fname); if (exit_code) kill_all(SIGUSR1); if (cleanup_pid && cleanup_pid == getpid()) { char *pidf = lp_pid_file(); if (pidf && *pidf) unlink(lp_pid_file()); } if (exit_code == 0) { if (code) exit_code = code; if (io_error & IOERR_DEL_LIMIT) exit_code = RERR_DEL_LIMIT; if (io_error & IOERR_VANISHED) exit_code = RERR_VANISHED; if (io_error & IOERR_GENERAL || got_xfer_error) exit_code = RERR_PARTIAL; } /* If line < 0, this exit is after a MSG_ERROR_EXIT event, so * we don't want to output a duplicate error. */ if ((exit_code && line > 0) || am_daemon || (logfile_name && (am_server || !INFO_GTE(STATS, 1)))) log_exit(exit_code, exit_file, exit_line); /* FALLTHROUGH */ #include "case_N.h" switch_step++; if (DEBUG_GTE(EXIT, 1)) { rprintf(FINFO, "[%s] _exit_cleanup(code=%d, file=%s, line=%d): " "about to call exit(%d)\n", who_am_i(), first_code, exit_file, exit_line, exit_code); } /* FALLTHROUGH */ #include "case_N.h" switch_step++; if (exit_code && exit_code != RERR_SOCKETIO && exit_code != RERR_STREAMIO && exit_code != RERR_SIGNAL1 && exit_code != RERR_TIMEOUT && !shutting_down && (protocol_version >= 31 || am_receiver)) { if (line > 0) { if (DEBUG_GTE(EXIT, 3)) { rprintf(FINFO, "[%s] sending MSG_ERROR_EXIT with exit_code %d\n", who_am_i(), exit_code); } send_msg_int(MSG_ERROR_EXIT, exit_code); } noop_io_until_death(); } /* FALLTHROUGH */ #include "case_N.h" switch_step++; if (am_server && exit_code) msleep(100); close_all(); /* FALLTHROUGH */ default: break; } exit(exit_code); }
/* * check_mapping -- check access to memory mapped file */ static void check_mapping(int fd, char *addr, size_t len, int prot, int flags, off_t offset) { volatile int i; /* arrange to catch SEGV */ struct sigaction v; sigemptyset(&v.sa_mask); v.sa_flags = 0; v.sa_handler = signal_handler; SIGACTION(SIGSEGV, &v, NULL); char pat[PAGE_SIZE] = { 0 }; char buf[PAGE_SIZE]; if ((flags & CHECK_RO) == 0 && fd != -1) { /* write some pattern to the file */ memset(pat, 0x5A, PAGE_SIZE); for (i = 0; i < len / PAGE_SIZE; i++) { LSEEK(fd, offset + PAGE_SIZE * i, SEEK_SET); WRITE(fd, pat, PAGE_SIZE); LSEEK(fd, offset + PAGE_SIZE * i, SEEK_SET); if (READ(fd, buf, PAGE_SIZE) == PAGE_SIZE) { if (memcmp(pat, buf, PAGE_SIZE)) UT_FATAL("first %d bytes do not match", PAGE_SIZE); } } } check_access(addr, len, prot); munmap(addr, len); /* same memcpy from above should now fail */ for (i = 0; i < len / PAGE_SIZE; i++) { if (!ut_sigsetjmp(Jmp)) { memcpy(addr + PAGE_SIZE * i, pat, PAGE_SIZE); UT_FATAL("unmap failed"); } } if (fd != -1) { /* expected pattern */ if ((flags & (CHECK_PRIV | CHECK_RO)) != 0 || (prot & PROT_WRITE) == 0) memset(pat, 0x5A, PAGE_SIZE); else memset(pat, 0xA5, PAGE_SIZE); for (i = 0; i < len / PAGE_SIZE; i++) { LSEEK(fd, offset + PAGE_SIZE * i, SEEK_SET); if (READ(fd, buf, PAGE_SIZE) == PAGE_SIZE) { if (memcmp(pat, buf, PAGE_SIZE)) UT_FATAL("first %d bytes do not match", PAGE_SIZE); } } } }
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 }
/* * Send an interrupt to process. * */ void sendsig( struct proc * p, user_addr_t catcher, int sig, int mask, __unused uint32_t code ) { union { struct ts32 { arm_thread_state_t ss; } ts32; #if defined(__arm64__) struct ts64 { arm_thread_state64_t ss; } ts64; #endif } ts; union { struct user_sigframe32 uf32; #if defined(__arm64__) struct user_sigframe64 uf64; #endif } user_frame; user_siginfo_t sinfo; user_addr_t sp = 0, trampact; struct sigacts *ps = p->p_sigacts; int oonstack, infostyle; thread_t th_act; struct uthread *ut; user_size_t stack_size = 0; user_addr_t p_uctx, token_uctx; kern_return_t kr; th_act = current_thread(); ut = get_bsdthread_info(th_act); bzero(&ts, sizeof(ts)); bzero(&user_frame, sizeof(user_frame)); if (p->p_sigacts->ps_siginfo & sigmask(sig)) infostyle = UC_FLAVOR; else infostyle = UC_TRAD; trampact = ps->ps_trampact[sig]; oonstack = ps->ps_sigstk.ss_flags & SA_ONSTACK; /* * Get sundry thread state. */ if (proc_is64bit_data(p)) { #ifdef __arm64__ if (sendsig_get_state64(th_act, &ts.ts64.ss, &user_frame.uf64.mctx) != 0) { goto bad2; } #else panic("Shouldn't have 64-bit thread states on a 32-bit kernel."); #endif } else { if (sendsig_get_state32(th_act, &ts.ts32.ss, &user_frame.uf32.mctx) != 0) { goto bad2; } } /* * Figure out where our new stack lives. */ if ((ps->ps_flags & SAS_ALTSTACK) && !oonstack && (ps->ps_sigonstack & sigmask(sig))) { sp = ps->ps_sigstk.ss_sp; sp += ps->ps_sigstk.ss_size; stack_size = ps->ps_sigstk.ss_size; ps->ps_sigstk.ss_flags |= SA_ONSTACK; } else { /* * Get stack pointer, and allocate enough space * for signal handler data. */ if (proc_is64bit_data(p)) { #if defined(__arm64__) sp = CAST_USER_ADDR_T(ts.ts64.ss.sp); sp = (sp - sizeof(user_frame.uf64) - C_64_REDZONE_LEN) & ~0xf; /* Make sure to align to 16 bytes and respect red zone */ #else panic("Shouldn't have 64-bit thread states on a 32-bit kernel."); #endif } else { sp = CAST_USER_ADDR_T(ts.ts32.ss.sp); sp -= sizeof(user_frame.uf32); #if defined(__arm__) && (__BIGGEST_ALIGNMENT__ > 4) sp &= ~0xf; /* Make sure to align to 16 bytes for armv7k */ #endif } } proc_unlock(p); /* * Fill in ucontext (points to mcontext, i.e. thread states). */ if (proc_is64bit_data(p)) { #if defined(__arm64__) sendsig_fill_uctx64(&user_frame.uf64.uctx, oonstack, mask, sp, (user64_size_t)stack_size, (user64_addr_t)&((struct user_sigframe64*)sp)->mctx); #else panic("Shouldn't have 64-bit thread states on a 32-bit kernel."); #endif } else { sendsig_fill_uctx32(&user_frame.uf32.uctx, oonstack, mask, sp, (user32_size_t)stack_size, (user32_addr_t)&((struct user_sigframe32*)sp)->mctx); } /* * Setup siginfo. */ bzero((caddr_t) & sinfo, sizeof(sinfo)); sinfo.si_signo = sig; if (proc_is64bit_data(p)) { #if defined(__arm64__) sinfo.si_addr = ts.ts64.ss.pc; sinfo.pad[0] = ts.ts64.ss.sp; #else panic("Shouldn't have 64-bit thread states on a 32-bit kernel."); #endif } else { sinfo.si_addr = ts.ts32.ss.pc; sinfo.pad[0] = ts.ts32.ss.sp; } switch (sig) { case SIGILL: #ifdef BER_XXX if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_ILL_INS_BIT))) sinfo.si_code = ILL_ILLOPC; else if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_PRV_INS_BIT))) sinfo.si_code = ILL_PRVOPC; else if (mctx.ss.srr1 & (1 << (31 - SRR1_PRG_TRAP_BIT))) sinfo.si_code = ILL_ILLTRP; else sinfo.si_code = ILL_NOOP; #else sinfo.si_code = ILL_ILLTRP; #endif break; case SIGFPE: break; case SIGBUS: if (proc_is64bit_data(p)) { #if defined(__arm64__) sinfo.si_addr = user_frame.uf64.mctx.es.far; #else panic("Shouldn't have 64-bit thread states on a 32-bit kernel."); #endif } else { sinfo.si_addr = user_frame.uf32.mctx.es.far; } sinfo.si_code = BUS_ADRALN; break; case SIGSEGV: if (proc_is64bit_data(p)) { #if defined(__arm64__) sinfo.si_addr = user_frame.uf64.mctx.es.far; #else panic("Shouldn't have 64-bit thread states on a 32-bit kernel."); #endif } else { sinfo.si_addr = user_frame.uf32.mctx.es.far; } #ifdef BER_XXX /* First check in srr1 and then in dsisr */ if (mctx.ss.srr1 & (1 << (31 - DSISR_PROT_BIT))) sinfo.si_code = SEGV_ACCERR; else if (mctx.es.dsisr & (1 << (31 - DSISR_PROT_BIT))) sinfo.si_code = SEGV_ACCERR; else sinfo.si_code = SEGV_MAPERR; #else sinfo.si_code = SEGV_ACCERR; #endif break; default: { int status_and_exitcode; /* * All other signals need to fill out a minimum set of * information for the siginfo structure passed into * the signal handler, if SA_SIGINFO was specified. * * p->si_status actually contains both the status and * the exit code; we save it off in its own variable * for later breakdown. */ proc_lock(p); sinfo.si_pid = p->si_pid; p->si_pid = 0; status_and_exitcode = p->si_status; p->si_status = 0; sinfo.si_uid = p->si_uid; p->si_uid = 0; sinfo.si_code = p->si_code; p->si_code = 0; proc_unlock(p); if (sinfo.si_code == CLD_EXITED) { if (WIFEXITED(status_and_exitcode)) sinfo.si_code = CLD_EXITED; else if (WIFSIGNALED(status_and_exitcode)) { if (WCOREDUMP(status_and_exitcode)) { sinfo.si_code = CLD_DUMPED; status_and_exitcode = W_EXITCODE(status_and_exitcode,status_and_exitcode); } else { sinfo.si_code = CLD_KILLED; status_and_exitcode = W_EXITCODE(status_and_exitcode,status_and_exitcode); } } } /* * The recorded status contains the exit code and the * signal information, but the information to be passed * in the siginfo to the handler is supposed to only * contain the status, so we have to shift it out. */ sinfo.si_status = (WEXITSTATUS(status_and_exitcode) & 0x00FFFFFF) | (((uint32_t)(p->p_xhighbits) << 24) & 0xFF000000); p->p_xhighbits = 0; break; } } #if CONFIG_DTRACE sendsig_do_dtrace(ut, &sinfo, sig, catcher); #endif /* CONFIG_DTRACE */ /* * Copy signal-handling frame out to user space, set thread state. */ if (proc_is64bit_data(p)) { #if defined(__arm64__) user64_addr_t token; /* * mctx filled in when we get state. uctx filled in by * sendsig_fill_uctx64(). We fill in the sinfo now. */ siginfo_user_to_user64(&sinfo, &user_frame.uf64.sinfo); p_uctx = (user_addr_t)&((struct user_sigframe64*)sp)->uctx; /* * Generate the validation token for sigreturn */ token_uctx = p_uctx; kr = machine_thread_siguctx_pointer_convert_to_user(th_act, &token_uctx); assert(kr == KERN_SUCCESS); token = (user64_addr_t)token_uctx ^ (user64_addr_t)ps->ps_sigreturn_token; if (copyout(&user_frame.uf64, sp, sizeof(user_frame.uf64)) != 0) { goto bad; } if (sendsig_set_thread_state64(&ts.ts64.ss, catcher, infostyle, sig, (user64_addr_t)&((struct user_sigframe64*)sp)->sinfo, (user64_addr_t)p_uctx, token, trampact, sp, th_act) != KERN_SUCCESS) goto bad; #else panic("Shouldn't have 64-bit thread states on a 32-bit kernel."); #endif } else { user32_addr_t token; /* * mctx filled in when we get state. uctx filled in by * sendsig_fill_uctx32(). We fill in the sinfo, *pointer* * to uctx and token now. */ siginfo_user_to_user32(&sinfo, &user_frame.uf32.sinfo); p_uctx = (user_addr_t)&((struct user_sigframe32*)sp)->uctx; /* * Generate the validation token for sigreturn */ token_uctx = (user_addr_t)p_uctx; kr = machine_thread_siguctx_pointer_convert_to_user(th_act, &token_uctx); assert(kr == KERN_SUCCESS); token = (user32_addr_t)token_uctx ^ (user32_addr_t)ps->ps_sigreturn_token; user_frame.uf32.puctx = (user32_addr_t)p_uctx; user_frame.uf32.token = token; if (copyout(&user_frame.uf32, sp, sizeof(user_frame.uf32)) != 0) { goto bad; } if (sendsig_set_thread_state32(&ts.ts32.ss, CAST_DOWN_EXPLICIT(user32_addr_t, catcher), infostyle, sig, (user32_addr_t)&((struct user_sigframe32*)sp)->sinfo, CAST_DOWN_EXPLICIT(user32_addr_t, trampact), CAST_DOWN_EXPLICIT(user32_addr_t, sp), th_act) != KERN_SUCCESS) goto bad; } proc_lock(p); return; bad: proc_lock(p); bad2: SIGACTION(p, SIGILL) = SIG_DFL; sig = sigmask(SIGILL); p->p_sigignore &= ~sig; p->p_sigcatch &= ~sig; ut->uu_sigmask &= ~sig; /* sendsig is called with signal lock held */ proc_unlock(p); psignal_locked(p, SIGILL); proc_lock(p); }
int main(int argc, char *argv[]) { START(argc, argv, "vmem_delete"); VMEM *vmp; void *ptr; if (argc < 2) FATAL("usage: %s op:h|f|m|c|r|a|s|d", argv[0]); /* allocate memory for function vmem_create_in_region() */ void *mem_pool = MMAP_ANON_ALIGNED(VMEM_MIN_POOL, 4 << 20); vmp = vmem_create_in_region(mem_pool, VMEM_MIN_POOL); if (vmp == NULL) FATAL("!vmem_create_in_region"); ptr = vmem_malloc(vmp, sizeof (long long int)); if (ptr == NULL) ERR("!vmem_malloc"); vmem_delete(vmp); /* arrange to catch SEGV */ struct sigaction v; sigemptyset(&v.sa_mask); v.sa_flags = 0; v.sa_handler = signal_handler; SIGACTION(SIGSEGV, &v, NULL); SIGACTION(SIGABRT, &v, NULL); SIGACTION(SIGILL, &v, NULL); /* go through all arguments one by one */ for (int arg = 1; arg < argc; arg++) { /* Scan the character of each argument. */ if (strchr("hfmcrasd", argv[arg][0]) == NULL || argv[arg][1] != '\0') FATAL("op must be one of: h, f, m, c, r, a, s, d"); switch (argv[arg][0]) { case 'h': OUT("Testing vmem_check..."); if (!sigsetjmp(Jmp, 1)) { OUT("\tvmem_check returned %i", vmem_check(vmp)); } break; case 'f': OUT("Testing vmem_free..."); if (!sigsetjmp(Jmp, 1)) { vmem_free(vmp, ptr); OUT("\tvmem_free succeeded"); } break; case 'm': OUT("Testing vmem_malloc..."); if (!sigsetjmp(Jmp, 1)) { ptr = vmem_malloc(vmp, sizeof (long long int)); if (ptr != NULL) OUT("\tvmem_malloc succeeded"); else OUT("\tvmem_malloc returned NULL"); } break; case 'c': OUT("Testing vmem_calloc..."); if (!sigsetjmp(Jmp, 1)) { ptr = vmem_calloc(vmp, 10, sizeof (int)); if (ptr != NULL) OUT("\tvmem_calloc succeeded"); else OUT("\tvmem_calloc returned NULL"); } break; case 'r': OUT("Testing vmem_realloc..."); if (!sigsetjmp(Jmp, 1)) { ptr = vmem_realloc(vmp, ptr, 128); if (ptr != NULL) OUT("\tvmem_realloc succeeded"); else OUT("\tvmem_realloc returned NULL"); } break; case 'a': OUT("Testing vmem_aligned_alloc..."); if (!sigsetjmp(Jmp, 1)) { ptr = vmem_aligned_alloc(vmp, 128, 128); if (ptr != NULL) OUT("\tvmem_aligned_alloc succeeded"); else OUT("\tvmem_aligned_alloc" " returned NULL"); } break; case 's': OUT("Testing vmem_strdup..."); if (!sigsetjmp(Jmp, 1)) { ptr = vmem_strdup(vmp, "Test string"); if (ptr != NULL) OUT("\tvmem_strdup succeeded"); else OUT("\tvmem_strdup returned NULL"); } break; case 'd': OUT("Testing vmem_delete..."); if (!sigsetjmp(Jmp, 1)) { vmem_delete(vmp); if (errno != 0) OUT("\tvmem_delete failed: %s", vmem_errormsg()); else OUT("\tvmem_delete succeeded"); } break; } } DONE(NULL); }
/* * 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 }
/*ARGSUSED*/ void trap(struct frame *fp, int type, unsigned code, unsigned v) { extern char fubail[], subail[]; struct lwp *l; struct proc *p; struct pcb *pcb; void *onfault; ksiginfo_t ksi; int s; int rv; u_quad_t sticks = 0 /* XXX initialiser works around compiler bug */; static int panicking __diagused; curcpu()->ci_data.cpu_ntrap++; l = curlwp; p = l->l_proc; pcb = lwp_getpcb(l); KSI_INIT_TRAP(&ksi); ksi.ksi_trap = type & ~T_USER; if (USERMODE(fp->f_sr)) { type |= T_USER; sticks = p->p_sticks; l->l_md.md_regs = fp->f_regs; LWP_CACHE_CREDS(l, p); } switch (type) { default: dopanic: /* * Let the kernel debugger see the trap frame that * caused us to panic. This is a convenience so * one can see registers at the point of failure. */ s = splhigh(); panicking = 1; printf("trap type %d, code = 0x%x, v = 0x%x\n", type, code, v); printf("%s program counter = 0x%x\n", (type & T_USER) ? "user" : "kernel", fp->f_pc); #ifdef KGDB /* If connected, step or cont returns 1 */ if (kgdb_trap(type, (db_regs_t *)fp)) goto kgdb_cont; #endif #ifdef DDB (void)kdb_trap(type, (db_regs_t *)fp); #endif #ifdef KGDB kgdb_cont: #endif splx(s); if (panicstr) { printf("trap during panic!\n"); #ifdef DEBUG /* XXX should be a machine-dependent hook */ printf("(press a key)\n"); (void)cngetc(); #endif } regdump((struct trapframe *)fp, 128); type &= ~T_USER; if ((u_int)type < trap_types) panic(trap_type[type]); panic("trap"); case T_BUSERR: /* kernel bus error */ onfault = pcb->pcb_onfault; if (onfault == NULL) goto dopanic; rv = EFAULT; /* FALLTHROUGH */ copyfault: /* * If we have arranged to catch this fault in any of the * copy to/from user space routines, set PC to return to * indicated location and set flag informing buserror code * that it may need to clean up stack frame. */ fp->f_stackadj = exframesize[fp->f_format]; fp->f_format = fp->f_vector = 0; fp->f_pc = (int)onfault; fp->f_regs[D0] = rv; return; case T_BUSERR|T_USER: /* bus error */ case T_ADDRERR|T_USER: /* address error */ ksi.ksi_addr = (void *)v; ksi.ksi_signo = SIGBUS; ksi.ksi_code = (type == (T_BUSERR|T_USER)) ? BUS_OBJERR : BUS_ADRERR; break; case T_COPERR: /* kernel coprocessor violation */ case T_FMTERR|T_USER: /* do all RTE errors come in as T_USER? */ case T_FMTERR: /* ...just in case... */ /* * The user has most likely trashed the RTE or FP state info * in the stack frame of a signal handler. */ printf("pid %d: kernel %s exception\n", p->p_pid, type==T_COPERR ? "coprocessor" : "format"); type |= T_USER; mutex_enter(p->p_lock); SIGACTION(p, SIGILL).sa_handler = SIG_DFL; sigdelset(&p->p_sigctx.ps_sigignore, SIGILL); sigdelset(&p->p_sigctx.ps_sigcatch, SIGILL); sigdelset(&l->l_sigmask, SIGILL); mutex_exit(p->p_lock); ksi.ksi_signo = SIGILL; ksi.ksi_addr = (void *)(int)fp->f_format; /* XXX was ILL_RESAD_FAULT */ ksi.ksi_code = (type == T_COPERR) ? ILL_COPROC : ILL_ILLOPC; break; case T_COPERR|T_USER: /* user coprocessor violation */ /* What is a proper response here? */ ksi.ksi_signo = SIGFPE; ksi.ksi_code = FPE_FLTINV; break; case T_FPERR|T_USER: /* 68881 exceptions */ /* * We pass along the 68881 status register which locore stashed * in code for us. */ ksi.ksi_signo = SIGFPE; ksi.ksi_code = fpsr2siginfocode(code); break; #ifdef M68040 case T_FPEMULI|T_USER: /* unimplemented FP instruction */ case T_FPEMULD|T_USER: /* unimplemented FP data type */ /* XXX need to FSAVE */ printf("pid %d(%s): unimplemented FP %s at %x (EA %x)\n", p->p_pid, p->p_comm, fp->f_format == 2 ? "instruction" : "data type", fp->f_pc, fp->f_fmt2.f_iaddr); /* XXX need to FRESTORE */ ksi.ksi_signo = SIGFPE; ksi.ksi_code = FPE_FLTINV; break; #endif case T_ILLINST|T_USER: /* illegal instruction fault */ case T_PRIVINST|T_USER: /* privileged instruction fault */ ksi.ksi_addr = (void *)(int)fp->f_format; /* XXX was ILL_PRIVIN_FAULT */ ksi.ksi_signo = SIGILL; ksi.ksi_code = (type == (T_PRIVINST|T_USER)) ? ILL_PRVOPC : ILL_ILLOPC; break; case T_ZERODIV|T_USER: /* Divide by zero */ ksi.ksi_addr = (void *)(int)fp->f_format; /* XXX was FPE_INTDIV_TRAP */ ksi.ksi_signo = SIGFPE; ksi.ksi_code = FPE_FLTDIV; break; case T_CHKINST|T_USER: /* CHK instruction trap */ ksi.ksi_addr = (void *)(int)fp->f_format; /* XXX was FPE_SUBRNG_TRAP */ ksi.ksi_signo = SIGFPE; break; case T_TRAPVINST|T_USER: /* TRAPV instruction trap */ ksi.ksi_addr = (void *)(int)fp->f_format; /* XXX was FPE_INTOVF_TRAP */ ksi.ksi_signo = SIGFPE; break; /* * XXX: Trace traps are a nightmare. * * HP-UX uses trap #1 for breakpoints, * NetBSD/m68k uses trap #2, * SUN 3.x uses trap #15, * DDB and KGDB uses trap #15 (for kernel breakpoints; * handled elsewhere). * * NetBSD and HP-UX traps both get mapped by locore.s into T_TRACE. * SUN 3.x traps get passed through as T_TRAP15 and are not really * supported yet. * * XXX: We should never get kernel-mode T_TRAP15 * XXX: because locore.s now gives them special treatment. */ case T_TRAP15: /* kernel breakpoint */ #ifdef DEBUG printf("unexpected kernel trace trap, type = %d\n", type); printf("program counter = 0x%x\n", fp->f_pc); #endif fp->f_sr &= ~PSL_T; return; case T_TRACE|T_USER: /* user trace trap */ #ifdef COMPAT_SUNOS /* * SunOS uses Trap #2 for a "CPU cache flush". * Just flush the on-chip caches and return. */ if (p->p_emul == &emul_sunos) { ICIA(); DCIU(); return; } #endif /* FALLTHROUGH */ case T_TRACE: /* tracing a trap instruction */ case T_TRAP15|T_USER: /* SUN user trace trap */ fp->f_sr &= ~PSL_T; ksi.ksi_signo = SIGTRAP; break; case T_ASTFLT: /* system async trap, cannot happen */ goto dopanic; case T_ASTFLT|T_USER: /* user async trap */ astpending = 0; /* * We check for software interrupts first. This is because * they are at a higher level than ASTs, and on a VAX would * interrupt the AST. We assume that if we are processing * an AST that we must be at IPL0 so we don't bother to * check. Note that we ensure that we are at least at SIR * IPL while processing the SIR. */ spl1(); /* fall into... */ case T_SSIR: /* software interrupt */ case T_SSIR|T_USER: /* * If this was not an AST trap, we are all done. */ if (type != (T_ASTFLT|T_USER)) { curcpu()->ci_data.cpu_ntrap--; return; } spl0(); if (l->l_pflag & LP_OWEUPC) { l->l_pflag &= ~LP_OWEUPC; ADDUPROF(l); } if (curcpu()->ci_want_resched) preempt(); goto out; case T_MMUFLT: /* kernel mode page fault */ /* * If we were doing profiling ticks or other user mode * stuff from interrupt code, Just Say No. */ onfault = pcb->pcb_onfault; if (onfault == fubail || onfault == subail) { rv = EFAULT; goto copyfault; } /* fall into ... */ case T_MMUFLT|T_USER: /* page fault */ { vaddr_t va; struct vmspace *vm = p->p_vmspace; struct vm_map *map; vm_prot_t ftype; extern struct vm_map *kernel_map; onfault = pcb->pcb_onfault; #ifdef DEBUG if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) printf("trap: T_MMUFLT pid=%d, code=%x, v=%x, pc=%x, sr=%x\n", p->p_pid, code, v, fp->f_pc, fp->f_sr); #endif /* * It is only a kernel address space fault iff: * 1. (type & T_USER) == 0 and * 2. pcb_onfault not set or * 3. pcb_onfault set but supervisor space data fault * The last can occur during an exec() copyin where the * argument space is lazy-allocated. */ if ((type & T_USER) == 0 && (onfault == NULL || KDFAULT(code))) map = kernel_map; else { map = vm ? &vm->vm_map : kernel_map; } if (WRFAULT(code)) ftype = VM_PROT_WRITE; else ftype = VM_PROT_READ; va = trunc_page((vaddr_t)v); if (map == kernel_map && va == 0) { printf("trap: bad kernel %s access at 0x%x\n", (ftype & VM_PROT_WRITE) ? "read/write" : "read", v); goto dopanic; } #ifdef DIAGNOSTIC if (interrupt_depth && !panicking) { printf("trap: calling uvm_fault() from interrupt!\n"); goto dopanic; } #endif pcb->pcb_onfault = NULL; rv = uvm_fault(map, va, ftype); pcb->pcb_onfault = onfault; #ifdef DEBUG if (rv && MDB_ISPID(p->p_pid)) printf("uvm_fault(%p, 0x%lx, 0x%x) -> 0x%x\n", map, va, ftype, rv); #endif /* * If this was a stack access we keep track of the maximum * accessed stack size. Also, if vm_fault gets a protection * failure it is due to accessing the stack region outside * the current limit and we need to reflect that as an access * error. */ if (rv == 0) { if (map != kernel_map && (void *)va >= vm->vm_maxsaddr) uvm_grow(p, va); if (type == T_MMUFLT) { if (ucas_ras_check(&fp->F_t)) { return; } #ifdef M68040 if (cputype == CPU_68040) (void) writeback(fp, 1); #endif return; } goto out; } if (rv == EACCES) { ksi.ksi_code = SEGV_ACCERR; rv = EFAULT; } else ksi.ksi_code = SEGV_MAPERR; if (type == T_MMUFLT) { if (onfault) goto copyfault; printf("uvm_fault(%p, 0x%lx, 0x%x) -> 0x%x\n", map, va, ftype, rv); printf(" type %x, code [mmu,,ssw]: %x\n", type, code); goto dopanic; } ksi.ksi_addr = (void *)v; switch (rv) { case ENOMEM: printf("UVM: pid %d (%s), uid %d killed: out of swap\n", p->p_pid, p->p_comm, l->l_cred ? kauth_cred_geteuid(l->l_cred) : -1); ksi.ksi_signo = SIGKILL; break; case EINVAL: ksi.ksi_signo = SIGBUS; ksi.ksi_code = BUS_ADRERR; break; case EACCES: ksi.ksi_signo = SIGSEGV; ksi.ksi_code = SEGV_ACCERR; break; default: ksi.ksi_signo = SIGSEGV; ksi.ksi_code = SEGV_MAPERR; break; } break; } } trapsignal(l, &ksi); if ((type & T_USER) == 0) return; out: userret(l, fp, sticks, v, 1); }
/* * General purpose routine for passing commands to gdb. All gdb commands * come through here, where they are passed to gdb_command_funnel(). */ void gdb_interface(struct gnu_request *req) { if (!(pc->flags & GDB_INIT)) error(FATAL, "gdb_interface: gdb not initialized?\n"); if (output_closed()) restart(0); if (!req->fp) { req->fp = ((pc->flags & RUNTIME) || (pc->flags2 & ALLOW_FP)) ? fp : CRASHDEBUG(1) ? fp : pc->nullfp; } pc->cur_req = req; pc->cur_gdb_cmd = req->command; if (req->flags & GNU_RETURN_ON_ERROR) { error_hook = gdb_error_hook; if (setjmp(pc->gdb_interface_env)) { pc->last_gdb_cmd = pc->cur_gdb_cmd; pc->cur_gdb_cmd = 0; pc->cur_req = NULL; req->flags |= GNU_COMMAND_FAILED; pc->flags &= ~IN_GDB; return; } } else error_hook = NULL; if (CRASHDEBUG(2)) dump_gnu_request(req, IN_GDB); if (!(pc->flags & DROP_CORE)) SIGACTION(SIGSEGV, restart, &pc->sigaction, NULL); else SIGACTION(SIGSEGV, SIG_DFL, &pc->sigaction, NULL); if (interruptible()) { SIGACTION(SIGINT, pc->gdb_sigaction.sa_handler, &pc->gdb_sigaction, NULL); } else { SIGACTION(SIGINT, SIG_IGN, &pc->sigaction, NULL); SIGACTION(SIGPIPE, SIG_IGN, &pc->sigaction, NULL); } pc->flags |= IN_GDB; gdb_command_funnel(req); pc->flags &= ~IN_GDB; SIGACTION(SIGINT, restart, &pc->sigaction, NULL); SIGACTION(SIGSEGV, SIG_DFL, &pc->sigaction, NULL); if (CRASHDEBUG(2)) dump_gnu_request(req, !IN_GDB); error_hook = NULL; pc->last_gdb_cmd = pc->cur_gdb_cmd; pc->cur_gdb_cmd = 0; pc->cur_req = NULL; }
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 }
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; }
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; }