return flags and generation number in stat structure
[unix-history] / usr / src / sys / kern / sys_process.c
index 69b816a..90a993f 100644 (file)
-/*     sys_process.c   5.1     82/07/15        */
-
-#include "../h/param.h"
-#include "../h/systm.h"
-#include "../h/dir.h"
-#include "../h/user.h"
-#include "../h/proc.h"
-#include "../h/inode.h"
-#include "../h/reg.h"
-#include "../h/text.h"
-#include "../h/seg.h"
-#include "../h/mtpr.h"
-#include "../h/pte.h"
-#include "../h/psl.h"
-#include "../h/vm.h"
-#include "../h/buf.h"
-#include "../h/vlimit.h"
-#include "../h/acct.h"
+/*
+ * 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);
+}