/* @(#)sig.c 1.3 */ #include "sys/param.h" #include "sys/config.h" #include "sys/mmu.h" #include "sys/types.h" #include "sys/sysmacros.h" #include "sys/systm.h" #include "sys/dir.h" #include "sys/signal.h" #include "sys/user.h" #include "sys/errno.h" #include "sys/proc.h" #include "sys/inode.h" #include "sys/file.h" #include "sys/reg.h" #include "sys/text.h" #include "sys/seg.h" #include "sys/var.h" #include "sys/psl.h" #include "sys/scat.h" /* * Priority for tracing */ #define IPCPRI PZERO /* * Tracing variables. * Used to pass trace command from * parent to child being traced. * This data base cannot be * shared and is locked * per user. */ struct ipctrace { int ip_data; int ip_lock; int ip_req; int *ip_addr; } ipc; /* * Send the specified signal to * all processes with 'pgrp' as * process group. * Called by tty.c for quits and * interrupts. */ signal(pgrp, sig) register pgrp; { register struct proc *p; if (pgrp == 0) return; for(p = &proc[1]; p < (struct proc *)v.ve_proc; p++) if (p->p_pgrp == pgrp) psignal(p, sig); } /* * Send the specified signal to * the specified process. */ psignal(p, sig) register struct proc *p; register sig; { sig--; if (sig < 0 || sig >= NSIG) return; if (((p->p_sigign >> sig) & 1) && sig != (SIGCLD - 1)) return; p->p_sig |= 1L<p_stat == SSLEEP && p->p_pri > PZERO) { if (p->p_pri > PUSER) p->p_pri = PUSER; setrun(p); } } /* * Returns true if the current * process has a signal to process. * This is asked at least once * each time a process enters the * system. * A signal does not do anything * directly to a process; it sets * a flag that asks the process to * do something to itself. */ issig() { register n; register struct proc *p, *q; p = u.u_procp; while(p->p_sig) { n = fsig(p); if (n == SIGCLD) { if (u.u_signal[SIGCLD-1]&01) { for (q = &proc[1]; q < (struct proc *)v.ve_proc; q++) if (p->p_pid == q->p_ppid && q->p_stat == SZOMB) freeproc(q, 0); } else if (u.u_signal[SIGCLD-1]) return(n); } else if (n == SIGPWR) { if (u.u_signal[SIGPWR-1] && (u.u_signal[SIGPWR-1]&1)==0) return(n); } else if ((u.u_signal[n-1]&1) == 0 || (p->p_flag&STRC)) return(n); p->p_sig &= ~(1L<<(n-1)); } return(0); } /* * Enter the tracing STOP state. * In this state, the parent is * informed and the process is able to * receive commands from the parent. */ stop() { register struct proc *pp, *cp; loop: cp = u.u_procp; if (cp->p_ppid != 1) for (pp = &proc[0]; pp < (struct proc *)v.ve_proc; pp++) if (pp->p_pid == cp->p_ppid) { wakeup((caddr_t)pp); cp->p_stat = SSTOP; swtch(); if ((cp->p_flag&STRC)==0 || procxmt()) return; goto loop; } exit(fsig(u.u_procp)); } /* * Perform the action specified by * the current signal. * The usual sequence is: * if (issig()) * psig(); */ psig() { register n, p; register struct proc *rp; #ifdef mc68881 /* MC68881 floating-point coprocessor */ extern short fp881; /* is there an MC68881? */ #endif mc68881 rp = u.u_procp; #ifdef FLOAT /* sky floating point board */ if (u.u_fpinuse && u.u_fpsaved==0) { savfp(); u.u_fpsaved = 1; } #endif #ifdef mc68881 /* MC68881 floating-point coprocessor */ if (fp881) fpsave(); #endif mc68881 if (rp->p_flag&STRC) stop(); n = fsig(rp); if (n==0) return; rp->p_sig &= ~(1L<<(n-1)); if ((p=u.u_signal[n-1]) != 0) { if (p & 1) return; u.u_error = 0; if (n != SIGILL && n != SIGTRAP) u.u_signal[n-1] = 0; sendsig((caddr_t)p, n); return; } switch(n) { case SIGQUIT: case SIGILL: case SIGTRAP: case SIGIOT: case SIGEMT: case SIGFPE: case SIGBUS: case SIGSEGV: case SIGSYS: if (core()) n += 0200; } exit(n); } /* * find the signal in bit-position * representation in p_sig. */ fsig(p) struct proc *p; { register short i; register long n; n = p->p_sig; i = NSIG - 1; do { if (n & 1L) return(NSIG - i); n >>= 1; } while (--i != -1); return(0); } /* * Create a core image on the file "core" * * It writes USIZE (v.v_usize) block of the * user.h area followed by the entire * data+stack segments. */ core() { register struct inode *ip; register struct user *up; register s; extern schar(); up = &u; if (up->u_uid != up->u_ruid) return(0); up->u_error = 0; up->u_dirp = "core"; ip = namei(schar, 1); if (ip == NULL) { if (up->u_error) return(0); ip = maknode(0666); if (ip==NULL) return(0); } if (!access(ip, IWRITE) && (ip->i_mode&IFMT) == IFREG) { itrunc(ip); up->u_offset = 0; up->u_base = (caddr_t)up; up->u_count = ctob(v.v_usize); up->u_segflg = 1; up->u_limit = (daddr_t)ctod(MAXMEM); up->u_fmode = FWRITE; /* make register pointer relative for adb */ up->u_ar0 = (int *)((int)up->u_ar0 - (int)up); up->u_usrtop = btoc(v.v_uend); writei(ip); up->u_ar0 = (int *)((int)up->u_ar0 + (int)up); s = up->u_procp->p_size - v.v_usize; (void) estabur((unsigned)0, (unsigned)s, (unsigned)0, 0, RO); up->u_base = (caddr_t)v.v_ustart; up->u_count = ctob(s); up->u_segflg = 0; writei(ip); } else up->u_error = EACCES; iput(ip); return(up->u_error==0); } /* * grow the stack to include the SP * true return if successful. */ #ifdef NONSCATLOAD grow(sp) unsigned sp; { register struct user *up; register struct proc *p; register si, i, a1; up = &u; if ((v.v_uend-sp) < ctob(up->u_ssize)) return(0); si = btoct(v.v_uend-sp) - up->u_ssize + SINCR; if (si <= 0) return(0); if (estabur(up->u_tsize, up->u_dsize, up->u_ssize+si, 0, RO)) return(0); p = up->u_procp; expand((int)(p->p_size+si)); a1 = p->p_addr + p->p_size; for(i=up->u_ssize; i; i--) { a1--; copyseg(a1-si, a1); } for(i=si; i; i--) clearseg(--a1); up->u_ssize += si; return(1); } #else grow(sp) unsigned sp; { register struct user *up; register struct proc *p; register si, i, a1; register struct scatter *s; register a2, n; short t; up = &u; if ((v.v_uend-sp) < ctob(up->u_ssize)) return(0); si = btoct(v.v_uend-sp) - up->u_ssize + SINCR; if (si <= 0) return(0); if (chksize(up->u_tsize, up->u_dsize, up->u_ssize+si)) return(0); p = up->u_procp; expand((int)(p->p_size+si)); /* * locate last click of old data size */ s = scatmap; a1 = p->p_scat; n = v.v_usize + up->u_dsize; for (i=1; iu_ssize; if (n == 0) printf("grow:ssize not expected to be zero\n"); for (i=1; ip_flag &= ~SCONTIG; up->u_ssize += si; (void) estabur(up->u_tsize, up->u_dsize, up->u_ssize, 0, RO); return(1); } #endif /* * sys-trace system call. */ ptrace() { register struct ipctrace *ipcp; register struct user *up; register struct proc *p; register struct a { int req; int pid; int *addr; int data; } *uap; up = &u; uap = (struct a *)up->u_ap; if (uap->req <= 0) { up->u_procp->p_flag |= STRC; return; } for (p=proc; p < (struct proc *)v.ve_proc; p++) if (p->p_stat==SSTOP && p->p_pid==uap->pid && p->p_ppid==up->u_procp->p_pid) goto found; up->u_error = ESRCH; return; found: ipcp = &ipc; while (ipcp->ip_lock) (void) sleep((caddr_t)ipcp, IPCPRI); ipcp->ip_lock = p->p_pid; ipcp->ip_data = uap->data; ipcp->ip_addr = uap->addr; ipcp->ip_req = uap->req; p->p_flag &= ~SWTED; setrun(p); while (ipcp->ip_req > 0) (void) sleep((caddr_t)ipcp, IPCPRI); up->u_rval1 = ipcp->ip_data; if (ipcp->ip_req < 0) up->u_error = EIO; ipcp->ip_lock = 0; wakeup((caddr_t)ipcp); } /* * Code that the child process * executes to implement the command * of the parent process in tracing. */ procxmt() { register struct ipctrace *ipcp; register struct user *up; register int i; register *p; register struct text *xp; up = &u; ipcp = &ipc; if (ipcp->ip_lock != up->u_procp->p_pid) return(0); i = ipcp->ip_req; ipcp->ip_req = 0; wakeup((caddr_t)ipcp); switch (i) { /* read user I */ case 1: ipcp->ip_data = fuiword((caddr_t)ipcp->ip_addr); break; /* read user D */ case 2: ipcp->ip_data = fuword((caddr_t)ipcp->ip_addr); break; /* read u */ case 3: i = (int)ipcp->ip_addr; if (i<0 || i >= ctob(v.v_usize)) goto error; ipcp->ip_data = *((int *)((char *)up + (i & ~1))); break; /* write user I */ /* Must set up to allow writing */ case 4: /* * If text, must assure exclusive use */ if (xp = up->u_procp->p_textp) { if (xp->x_count!=1 || xp->x_iptr->i_mode&ISVTX) goto error; xp->x_iptr->i_flag &= ~ITEXT; } (void) estabur(up->u_tsize, up->u_dsize, up->u_ssize, 0, RW); i = suiword((caddr_t)ipcp->ip_addr, 0); (void) suiword((caddr_t)ipcp->ip_addr, ipcp->ip_data); (void) estabur(up->u_tsize, up->u_dsize, up->u_ssize, 0, RO); if (i<0) goto error; if (xp) xp->x_flag |= XWRIT; break; /* write user D */ case 5: if (suword((caddr_t)ipcp->ip_addr, 0) < 0) goto error; (void) suword((caddr_t)ipcp->ip_addr, ipcp->ip_data); break; /* write u */ case 6: i = (int)ipcp->ip_addr; p = (int *)((char *)up + (i & ~1)); for (i=0; i<17; i++) if (p == &up->u_ar0[regloc[i]]) goto ok; if (p == &up->u_ar0[RPS]) { /* assure user space and priority 0 */ ipcp->ip_data &= ~0x2700; goto ok; } goto error; ok: *p = ipcp->ip_data; break; /* set signal and continue */ /* one version causes a trace-trap */ case 9: up->u_ar0[RPS] |= PS_T; case 7: if ((int)ipcp->ip_addr != 1) up->u_ar0[PC] = (int)ipcp->ip_addr; up->u_procp->p_sig = 0L; if (ipcp->ip_data) psignal(up->u_procp, ipcp->ip_data); return(1); /* force exit */ case 8: exit(fsig(up->u_procp)); /* read u registers */ case 10: if ((i = (int)ipcp->ip_addr) < 0 || i > 17) goto error; if (i == 17) ipcp->ip_data = up->u_ar0[regloc[17]] & 0xFFFF; else ipcp->ip_data = up->u_ar0[regloc[i]]; break; /* write u registers */ case 11: if ((i = (int)ipcp->ip_addr) < 0 || i > 17) goto error; if (i == 17) { ipcp->ip_data &= ~0x2700; /* user only */ up->u_ar0[regloc[17]] = (up->u_ar0[regloc[17]] & ~0xFFFF) | (ipcp->ip_data & 0xFFFF); } else up->u_ar0[regloc[i]] = ipcp->ip_data; break; default: error: ipcp->ip_req = -1; } return(0); }