xref: /original-bsd/sys/kern/sys_process.c (revision d364528e)
1 /*-
2  * Copyright (c) 1982, 1986, 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.proprietary.c%
6  *
7  *	@(#)sys_process.c	7.31 (Berkeley) 07/15/92
8  */
9 
10 #define IPCREG
11 #include "param.h"
12 #include "proc.h"
13 #include "vnode.h"
14 #include "buf.h"
15 #include "ptrace.h"
16 
17 #include "machine/reg.h"
18 #include "machine/psl.h"
19 #include "vm/vm.h"
20 #include "vm/vm_page.h"
21 
22 #include "user.h"
23 
24 /*
25  * Priority for tracing
26  */
27 #define	IPCPRI	PZERO
28 
29 /*
30  * Tracing variables.
31  * Used to pass trace command from
32  * parent to child being traced.
33  * This data base cannot be
34  * shared and is locked
35  * per user.
36  */
37 struct {
38 	int	ip_lock;
39 	int	ip_req;
40 	int	*ip_addr;
41 	int	ip_data;
42 } ipc;
43 
44 /*
45  * Process debugging system call.
46  */
47 struct ptrace_args {
48 	int	req;
49 	int	pid;
50 	int	*addr;
51 	int	data;
52 };
53 ptrace(curp, uap, retval)
54 	struct proc *curp;
55 	register struct ptrace_args *uap;
56 	int *retval;
57 {
58 	register struct proc *p;
59 	int error;
60 
61 	p = pfind(uap->pid);
62 	if (uap->req == PT_ATTACH) {
63 		/*
64 		 * Must be root if the process has used set user or
65 		 * group privileges or does not belong to the real
66 		 * user. Must not be already traced.
67 		 */
68 		if ((p->p_flag & SUGID ||
69 		    p->p_cred->p_ruid != curp->p_cred->p_ruid) &&
70 		    (error = suser(p->p_ucred, &p->p_acflag)) != 0)
71 			return (error);
72 		if (p->p_flag & STRC)
73 			return (EALREADY);	/* ??? */
74 		/*
75 		 * It would be nice if the tracing relationship was separate
76 		 * from the parent relationship but that would require
77 		 * another set of links in the proc struct or for "wait"
78 		 * to scan the entire proc table.  To make life easier,
79 		 * we just re-parent the process we're trying to trace.
80 		 * The old parent is remembered so we can put things back
81 		 * on a "detach".
82 		 */
83 		p->p_flag |= STRC;
84 		p->p_oppid = p->p_pptr->p_pid;
85 		proc_reparent(p, curp);
86 		psignal(p, SIGSTOP);
87 		return (0);
88 	}
89 	if (uap->req <= 0) {
90 		curp->p_flag |= STRC;
91 		return (0);
92 	}
93 	if (p == 0 || p->p_stat != SSTOP || p->p_pptr != curp ||
94 	    !(p->p_flag & STRC))
95 		return (ESRCH);
96 	while (ipc.ip_lock)
97 		sleep((caddr_t)&ipc, IPCPRI);
98 	ipc.ip_lock = p->p_pid;
99 	ipc.ip_data = uap->data;
100 	ipc.ip_addr = uap->addr;
101 	ipc.ip_req = uap->req;
102 	p->p_flag &= ~SWTED;
103 	while (ipc.ip_req > 0) {
104 		if (p->p_stat==SSTOP)
105 			setrun(p);
106 		sleep((caddr_t)&ipc, IPCPRI);
107 	}
108 	*retval = ipc.ip_data;
109 	ipc.ip_lock = 0;
110 	wakeup((caddr_t)&ipc);
111 	if (ipc.ip_req < 0)
112 		return (EIO);
113 	return (0);
114 }
115 
116 #define	PHYSOFF(p, o) ((caddr_t)(p) + (o))
117 
118 #if defined(i386)
119 #undef        PC
120 #undef        SP
121 #undef        PS
122 #undef        R0
123 #undef        R1
124 
125 #define       PC      tEIP
126 #define       SP      tESP
127 #define       PS      tEFLAGS
128 #define       R0      tEDX
129 #define       R1      tECX
130 #endif
131 
132 /*
133  * Transmit a tracing request from the parent to the child process
134  * being debugged. This code runs in the context of the child process
135  * to fulfill the command requested by the parent.
136  */
137 procxmt(p)
138 	register struct proc *p;
139 {
140 	register int i, *poff;
141 	extern char kstack[];
142 
143 	if (ipc.ip_lock != p->p_pid)
144 		return (0);
145 	p->p_slptime = 0;
146 	p->p_addr->u_kproc.kp_proc.p_md.md_regs = p->p_md.md_regs; /* u.u_ar0 */
147 	i = ipc.ip_req;
148 	ipc.ip_req = 0;
149 	switch (i) {
150 
151 	case PT_READ_I:			/* read the child's text space */
152 		if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
153 			goto error;
154 		ipc.ip_data = fuiword((caddr_t)ipc.ip_addr);
155 		break;
156 
157 	case PT_READ_D:			/* read the child's data space */
158 		if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
159 			goto error;
160 		ipc.ip_data = fuword((caddr_t)ipc.ip_addr);
161 		break;
162 
163 	case PT_READ_U:			/* read the child's u. */
164 #ifdef HPUXCOMPAT
165 		if (p->p_addr->u_pcb.pcb_flags & PCB_HPUXTRACE)
166 			i = hpuxtobsduoff(ipc.ip_addr);
167 		else
168 #endif
169 		i = (int)ipc.ip_addr;
170 		if ((u_int) i > ctob(UPAGES)-sizeof(int) || (i & 1) != 0)
171 			goto error;
172 		ipc.ip_data = *(int *)PHYSOFF(p->p_addr, i);
173 		break;
174 
175 	case PT_WRITE_I:		/* write the child's text space */
176 		if ((i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data)) < 0) {
177 			vm_offset_t sa, ea;
178 			int rv;
179 
180 			sa = trunc_page((vm_offset_t)ipc.ip_addr);
181 			ea = round_page((vm_offset_t)ipc.ip_addr+sizeof(int));
182 			rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea,
183 					VM_PROT_DEFAULT, FALSE);
184 			if (rv == KERN_SUCCESS) {
185 				i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data);
186 				(void) vm_map_protect(&p->p_vmspace->vm_map,
187 					sa, ea, VM_PROT_READ|VM_PROT_EXECUTE,
188 					FALSE);
189 			}
190 		}
191 		if (i < 0)
192 			goto error;
193 		break;
194 
195 	case PT_WRITE_D:		/* write the child's data space */
196 		if (suword((caddr_t)ipc.ip_addr, 0) < 0)
197 			goto error;
198 		(void) suword((caddr_t)ipc.ip_addr, ipc.ip_data);
199 		break;
200 
201 	case PT_WRITE_U:		/* write the child's u. */
202 #ifdef HPUXCOMPAT
203 		if (p->p_addr->u_pcb.pcb_flags & PCB_HPUXTRACE)
204 			i = hpuxtobsduoff(ipc.ip_addr);
205 		else
206 #endif
207 		i = (int)ipc.ip_addr;
208 #ifdef mips
209 		poff = (int *)PHYSOFF(curproc->p_addr, i);
210 #else
211 		poff = (int *)PHYSOFF(kstack, i);
212 #endif
213 		for (i=0; i<NIPCREG; i++)
214 			if (poff == &p->p_md.md_regs[ipcreg[i]])
215 				goto ok;
216 		if (poff == &p->p_md.md_regs[PS]) {
217 			ipc.ip_data |= PSL_USERSET;
218 			ipc.ip_data &= ~PSL_USERCLR;
219 #ifdef PSL_CM_CLR
220 			if (ipc.ip_data & PSL_CM)
221 				ipc.ip_data &= ~PSL_CM_CLR;
222 #endif
223 			goto ok;
224 		}
225 #if defined(hp300) || defined(luna68k)
226 #ifdef FPCOPROC
227 		if (poff >= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_regs &&
228 		    poff <= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_fpiar)
229 			goto ok;
230 #endif
231 #endif
232 		goto error;
233 
234 	ok:
235 		*poff = ipc.ip_data;
236 		break;
237 
238 	case PT_STEP:			/* single step the child */
239 	case PT_CONTINUE:		/* continue the child */
240 		if ((unsigned)ipc.ip_data >= NSIG)
241 			goto error;
242 		if ((int)ipc.ip_addr != 1)
243 			p->p_md.md_regs[PC] = (int)ipc.ip_addr;
244 		p->p_xstat = ipc.ip_data;	/* see issig */
245 #ifdef PSL_T
246 		/* need something more machine independent here... */
247 		if (i == PT_STEP)
248 			p->p_md.md_regs[PS] |= PSL_T;
249 #endif
250 		wakeup((caddr_t)&ipc);
251 		return (1);
252 
253 	case PT_KILL:			/* kill the child process */
254 		wakeup((caddr_t)&ipc);
255 		exit(p, (int)p->p_xstat);
256 
257 	case PT_DETACH:			/* stop tracing the child */
258 		if ((unsigned)ipc.ip_data >= NSIG)
259 			goto error;
260 		if ((int)ipc.ip_addr != 1)
261 			p->p_md.md_regs[PC] = (int)ipc.ip_addr;
262 		p->p_xstat = ipc.ip_data;	/* see issig */
263 		p->p_flag &= ~STRC;
264 		if (p->p_oppid != p->p_pptr->p_pid) {
265                         register struct proc *pp = pfind(p->p_oppid);
266 
267                         if (pp)
268                                 proc_reparent(p, pp);
269 		}
270 		p->p_oppid = 0;
271 		wakeup((caddr_t)&ipc);
272 		return (1);
273 
274 	default:
275 	error:
276 		ipc.ip_req = -1;
277 	}
278 	wakeup((caddr_t)&ipc);
279 	return (0);
280 }
281