xref: /original-bsd/sys/kern/sys_process.c (revision d0e3910b)
1 /*
2  * Copyright (c) 1982, 1986 Regents of the University of California.
3  * All rights reserved.  The Berkeley software License Agreement
4  * specifies the terms and conditions for redistribution.
5  *
6  *	@(#)sys_process.c	7.4 (Berkeley) 12/10/87
7  */
8 
9 #define IPCREG
10 #include "../machine/reg.h"
11 #include "../machine/psl.h"
12 #include "../machine/pte.h"
13 
14 #include "param.h"
15 #include "systm.h"
16 #include "dir.h"
17 #include "user.h"
18 #include "proc.h"
19 #include "inode.h"
20 #include "text.h"
21 #include "seg.h"
22 #include "vm.h"
23 #include "buf.h"
24 #include "acct.h"
25 #include "ptrace.h"
26 
27 /*
28  * Priority for tracing
29  */
30 #define	IPCPRI	PZERO
31 
32 /*
33  * Tracing variables.
34  * Used to pass trace command from
35  * parent to child being traced.
36  * This data base cannot be
37  * shared and is locked
38  * per user.
39  */
40 struct {
41 	int	ip_lock;
42 	int	ip_req;
43 	int	*ip_addr;
44 	int	ip_data;
45 } ipc;
46 
47 /*
48  * sys-trace system call.
49  */
50 ptrace()
51 {
52 	register struct proc *p;
53 	register struct a {
54 		int	req;
55 		int	pid;
56 		int	*addr;
57 		int	data;
58 	} *uap;
59 
60 	uap = (struct a *)u.u_ap;
61 	if (uap->req <= 0) {
62 		u.u_procp->p_flag |= STRC;
63 		return;
64 	}
65 	p = pfind(uap->pid);
66 	if (p == 0 || p->p_stat != SSTOP || p->p_ppid != u.u_procp->p_pid ||
67 	    !(p->p_flag & STRC)) {
68 		u.u_error = ESRCH;
69 		return;
70 	}
71 	while (ipc.ip_lock)
72 		sleep((caddr_t)&ipc, IPCPRI);
73 	ipc.ip_lock = p->p_pid;
74 	ipc.ip_data = uap->data;
75 	ipc.ip_addr = uap->addr;
76 	ipc.ip_req = uap->req;
77 	p->p_flag &= ~SWTED;
78 	while (ipc.ip_req > 0) {
79 		if (p->p_stat==SSTOP)
80 			setrun(p);
81 		sleep((caddr_t)&ipc, IPCPRI);
82 	}
83 	u.u_r.r_val1 = ipc.ip_data;
84 	if (ipc.ip_req < 0)
85 		u.u_error = EIO;
86 	ipc.ip_lock = 0;
87 	wakeup((caddr_t)&ipc);
88 }
89 
90 #define	PHYSOFF(p, o) \
91 	((physadr)(p)+((o)/sizeof(((physadr)0)->r[0])))
92 
93 /*
94  * Code that the child process
95  * executes to implement the command
96  * of the parent process in tracing.
97  */
98 procxmt()
99 {
100 	register int i;
101 	register *p;
102 	register struct text *xp;
103 
104 	if (ipc.ip_lock != u.u_procp->p_pid)
105 		return (0);
106 	u.u_procp->p_slptime = 0;
107 	i = ipc.ip_req;
108 	ipc.ip_req = 0;
109 	switch (i) {
110 
111 	case PT_READ_I:			/* read the child's text space */
112 		if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
113 			goto error;
114 		ipc.ip_data = fuiword((caddr_t)ipc.ip_addr);
115 		break;
116 
117 	case PT_READ_D:			/* read the child's data space */
118 		if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
119 			goto error;
120 		ipc.ip_data = fuword((caddr_t)ipc.ip_addr);
121 		break;
122 
123 	case PT_READ_U:			/* read the child's u. */
124 		i = (int)ipc.ip_addr;
125 		if (i<0 || i >= ctob(UPAGES))
126 			goto error;
127 		ipc.ip_data = *(int *)PHYSOFF(&u, i);
128 		break;
129 
130 	case PT_WRITE_I:		/* write the child's text space */
131 		/*
132 		 * If text, must assure exclusive use
133 		 */
134 		if (xp = u.u_procp->p_textp) {
135 			if (xp->x_count!=1 || xp->x_iptr->i_mode&ISVTX)
136 				goto error;
137 			xp->x_flag |= XTRC;
138 		}
139 		i = -1;
140 		if ((i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data)) < 0) {
141 			if (chgprot((caddr_t)ipc.ip_addr, RW) &&
142 			    chgprot((caddr_t)ipc.ip_addr+(sizeof(int)-1), RW))
143 				i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data);
144 			(void) chgprot((caddr_t)ipc.ip_addr, RO);
145 			(void) chgprot((caddr_t)ipc.ip_addr+(sizeof(int)-1), RO);
146 		}
147 		if (i < 0)
148 			goto error;
149 #if defined(tahoe)
150 		/* make sure the old value is not in cache */
151 		ckeyrelease(u.u_procp->p_ckey);
152 		u.u_procp->p_ckey = getcodekey();
153 #endif
154 		if (xp) {
155 			xp->x_flag |= XWRIT;
156 #if defined(tahoe)
157 			xp->x_ckey = u.u_procp->p_ckey;
158 #endif
159 		}
160 		break;
161 
162 	case PT_WRITE_D:		/* write the child's data space */
163 		if (suword((caddr_t)ipc.ip_addr, 0) < 0)
164 			goto error;
165 		(void) suword((caddr_t)ipc.ip_addr, ipc.ip_data);
166 		break;
167 
168 	case PT_WRITE_U:		/* write the child's u. */
169 		i = (int)ipc.ip_addr;
170 		p = (int *)PHYSOFF(&u, i);
171 		for (i=0; i<NIPCREG; i++)
172 			if (p == &u.u_ar0[ipcreg[i]])
173 				goto ok;
174 		if (p == &u.u_ar0[PS]) {
175 			ipc.ip_data |= PSL_USERSET;
176 			ipc.ip_data &=  ~PSL_USERCLR;
177 #ifdef PSL_CM_CLR
178 			if (ipc.ip_data & PSL_CM)
179 				ipc.ip_data &= ~PSL_CM_CLR;
180 #endif
181 			goto ok;
182 		}
183 		goto error;
184 
185 	ok:
186 		*p = ipc.ip_data;
187 		break;
188 
189 	case PT_STEP:			/* single step the child */
190 	case PT_CONTINUE:		/* continue the child */
191 		if ((int)ipc.ip_addr != 1)
192 			u.u_ar0[PC] = (int)ipc.ip_addr;
193 		if ((unsigned)ipc.ip_data > NSIG)
194 			goto error;
195 		u.u_procp->p_cursig = ipc.ip_data;	/* see issig */
196 		if (i == PT_STEP)
197 			u.u_ar0[PS] |= PSL_T;
198 		wakeup((caddr_t)&ipc);
199 		return (1);
200 
201 	case PT_KILL:			/* kill the child process */
202 		wakeup((caddr_t)&ipc);
203 		exit(u.u_procp->p_cursig);
204 
205 	default:
206 	error:
207 		ipc.ip_req = -1;
208 	}
209 	wakeup((caddr_t)&ipc);
210 	return (0);
211 }
212