return flags and generation number in stat structure
[unix-history] / usr / src / sys / kern / sys_process.c
/*
* Copyright (c) 1982, 1986, 1989 Regents of the University of California.
* All rights reserved. The Berkeley software License Agreement
* specifies the terms and conditions for redistribution.
*
* @(#)sys_process.c 7.6 (Berkeley) %G%
*/
#define IPCREG
#include "param.h"
#include "user.h"
#include "proc.h"
#include "vnode.h"
#include "text.h"
#include "seg.h"
#include "buf.h"
#include "ptrace.h"
#include "machine/reg.h"
#include "machine/psl.h"
#include "machine/pte.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 {
int ip_lock;
int ip_req;
int *ip_addr;
int ip_data;
} ipc;
/*
* sys-trace system call.
*/
ptrace()
{
register struct proc *p;
register struct a {
int req;
int pid;
int *addr;
int data;
} *uap;
uap = (struct a *)u.u_ap;
if (uap->req <= 0) {
u.u_procp->p_flag |= STRC;
return;
}
p = pfind(uap->pid);
if (p == 0 || p->p_stat != SSTOP || p->p_ppid != u.u_procp->p_pid ||
!(p->p_flag & STRC)) {
u.u_error = ESRCH;
return;
}
while (ipc.ip_lock)
sleep((caddr_t)&ipc, IPCPRI);
ipc.ip_lock = p->p_pid;
ipc.ip_data = uap->data;
ipc.ip_addr = uap->addr;
ipc.ip_req = uap->req;
p->p_flag &= ~SWTED;
while (ipc.ip_req > 0) {
if (p->p_stat==SSTOP)
setrun(p);
sleep((caddr_t)&ipc, IPCPRI);
}
u.u_r.r_val1 = ipc.ip_data;
if (ipc.ip_req < 0)
u.u_error = EIO;
ipc.ip_lock = 0;
wakeup((caddr_t)&ipc);
}
#define PHYSOFF(p, o) \
((physadr)(p)+((o)/sizeof(((physadr)0)->r[0])))
/*
* Code that the child process
* executes to implement the command
* of the parent process in tracing.
*/
procxmt()
{
register int i;
register *p;
register struct text *xp;
struct vattr vattr;
struct vnode *vp;
if (ipc.ip_lock != u.u_procp->p_pid)
return (0);
u.u_procp->p_slptime = 0;
i = ipc.ip_req;
ipc.ip_req = 0;
switch (i) {
case PT_READ_I: /* read the child's text space */
if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
goto error;
ipc.ip_data = fuiword((caddr_t)ipc.ip_addr);
break;
case PT_READ_D: /* read the child's data space */
if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
goto error;
ipc.ip_data = fuword((caddr_t)ipc.ip_addr);
break;
case PT_READ_U: /* read the child's u. */
i = (int)ipc.ip_addr;
if (i<0 || i >= ctob(UPAGES))
goto error;
ipc.ip_data = *(int *)PHYSOFF(&u, i);
break;
case PT_WRITE_I: /* write the child's text space */
/*
* If text, must assure exclusive use
*/
if (xp = u.u_procp->p_textp) {
vp = xp->x_vptr;
VOP_GETATTR(vp, &vattr, u.u_cred);
if (xp->x_count!=1 || (vattr.va_mode & VSVTX))
goto error;
xp->x_flag |= XTRC;
}
i = -1;
if ((i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data)) < 0) {
if (chgprot((caddr_t)ipc.ip_addr, RW) &&
chgprot((caddr_t)ipc.ip_addr+(sizeof(int)-1), RW))
i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data);
(void) chgprot((caddr_t)ipc.ip_addr, RO);
(void) chgprot((caddr_t)ipc.ip_addr+(sizeof(int)-1), RO);
}
if (i < 0)
goto error;
#if defined(tahoe)
/* make sure the old value is not in cache */
ckeyrelease(u.u_procp->p_ckey);
u.u_procp->p_ckey = getcodekey();
#endif
if (xp) {
xp->x_flag |= XWRIT;
#if defined(tahoe)
xp->x_ckey = u.u_procp->p_ckey;
#endif
}
break;
case PT_WRITE_D: /* write the child's data space */
if (suword((caddr_t)ipc.ip_addr, 0) < 0)
goto error;
(void) suword((caddr_t)ipc.ip_addr, ipc.ip_data);
break;
case PT_WRITE_U: /* write the child's u. */
i = (int)ipc.ip_addr;
p = (int *)PHYSOFF(&u, i);
for (i=0; i<NIPCREG; i++)
if (p == &u.u_ar0[ipcreg[i]])
goto ok;
if (p == &u.u_ar0[PS]) {
ipc.ip_data |= PSL_USERSET;
ipc.ip_data &= ~PSL_USERCLR;
#ifdef PSL_CM_CLR
if (ipc.ip_data & PSL_CM)
ipc.ip_data &= ~PSL_CM_CLR;
#endif
goto ok;
}
goto error;
ok:
*p = ipc.ip_data;
break;
case PT_STEP: /* single step the child */
case PT_CONTINUE: /* continue the child */
if ((int)ipc.ip_addr != 1)
u.u_ar0[PC] = (int)ipc.ip_addr;
if ((unsigned)ipc.ip_data > NSIG)
goto error;
u.u_procp->p_cursig = ipc.ip_data; /* see issig */
if (i == PT_STEP)
u.u_ar0[PS] |= PSL_T;
wakeup((caddr_t)&ipc);
return (1);
case PT_KILL: /* kill the child process */
wakeup((caddr_t)&ipc);
exit(u.u_procp->p_cursig);
default:
error:
ipc.ip_req = -1;
}
wakeup((caddr_t)&ipc);
return (0);
}