xref: /original-bsd/sys/kern/sys_process.c (revision 049d63db)
1 /*
2  * Copyright (c) 1982, 1986, 1989 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.16 (Berkeley) 03/17/91
7  */
8 
9 #define IPCREG
10 #include "param.h"
11 #include "user.h"
12 #include "proc.h"
13 #include "vnode.h"
14 #include "seg.h"
15 #include "buf.h"
16 #include "ptrace.h"
17 
18 #include "machine/reg.h"
19 #include "machine/psl.h"
20 #include "vm/vm_page.h"
21 #include "vm/vm_prot.h"
22 
23 /*
24  * Priority for tracing
25  */
26 #define	IPCPRI	PZERO
27 
28 /*
29  * Tracing variables.
30  * Used to pass trace command from
31  * parent to child being traced.
32  * This data base cannot be
33  * shared and is locked
34  * per user.
35  */
36 struct {
37 	int	ip_lock;
38 	int	ip_req;
39 	int	*ip_addr;
40 	int	ip_data;
41 } ipc;
42 
43 /*
44  * sys-trace system call.
45  */
46 ptrace(curp, uap, retval)
47 	struct proc *curp;
48 	register struct args {
49 		int	req;
50 		int	pid;
51 		int	*addr;
52 		int	data;
53 	} *uap;
54 	int *retval;
55 {
56 	register struct proc *p;
57 
58 	if (uap->req <= 0) {
59 		curp->p_flag |= STRC;
60 		return (0);
61 	}
62 	p = pfind(uap->pid);
63 	if (p == 0 || p->p_stat != SSTOP || p->p_pptr != curp ||
64 	    !(p->p_flag & STRC))
65 		return (ESRCH);
66 	while (ipc.ip_lock)
67 		sleep((caddr_t)&ipc, IPCPRI);
68 	ipc.ip_lock = p->p_pid;
69 	ipc.ip_data = uap->data;
70 	ipc.ip_addr = uap->addr;
71 	ipc.ip_req = uap->req;
72 	p->p_flag &= ~SWTED;
73 	while (ipc.ip_req > 0) {
74 		if (p->p_stat==SSTOP)
75 			setrun(p);
76 		sleep((caddr_t)&ipc, IPCPRI);
77 	}
78 	*retval = ipc.ip_data;
79 	ipc.ip_lock = 0;
80 	wakeup((caddr_t)&ipc);
81 	if (ipc.ip_req < 0)
82 		return (EIO);
83 	return (0);
84 }
85 
86 #define	PHYSOFF(p, o) \
87 	((physadr)(p)+((o)/sizeof(((physadr)0)->r[0])))
88 #if defined(i386)
89 #undef        PC
90 #undef        SP
91 #undef        PS
92 #undef        R0
93 #undef        R1
94 
95 #define       PC      tEIP
96 #define       SP      tESP
97 #define       PS      tEFLAGS
98 #define       R0      tEDX
99 #define       R1      tECX
100 #endif
101 
102 /*
103  * Code that the child process
104  * executes to implement the command
105  * of the parent process in tracing.
106  */
107 procxmt(p)
108 	register struct proc *p;
109 {
110 	register int i, *poff;
111 
112 	if (ipc.ip_lock != p->p_pid)
113 		return (0);
114 	p->p_slptime = 0;
115 	i = ipc.ip_req;
116 	ipc.ip_req = 0;
117 	switch (i) {
118 
119 	case PT_READ_I:			/* read the child's text space */
120 		if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
121 			goto error;
122 		ipc.ip_data = fuiword((caddr_t)ipc.ip_addr);
123 		break;
124 
125 	case PT_READ_D:			/* read the child's data space */
126 		if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
127 			goto error;
128 		ipc.ip_data = fuword((caddr_t)ipc.ip_addr);
129 		break;
130 
131 	case PT_READ_U:			/* read the child's u. */
132 #ifdef HPUXCOMPAT
133 		if (u.u_pcb.pcb_flags & PCB_HPUXTRACE)
134 			i = hpuxtobsduoff(ipc.ip_addr);
135 		else
136 #endif
137 		i = (int)ipc.ip_addr;
138 		if (i<0 || i > ctob(UPAGES)-sizeof(int))
139 			goto error;
140 		ipc.ip_data = *(int *)PHYSOFF(&u, i);
141 		break;
142 
143 	case PT_WRITE_I:		/* write the child's text space */
144 		if ((i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data)) < 0) {
145 			vm_offset_t sa, ea;
146 			int rv;
147 
148 			sa = trunc_page((vm_offset_t)ipc.ip_addr);
149 			ea = round_page((vm_offset_t)ipc.ip_addr+sizeof(int)-1);
150 			rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea,
151 					VM_PROT_DEFAULT, FALSE);
152 			if (rv == KERN_SUCCESS) {
153 				i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data);
154 				(void) vm_map_protect(&p->p_vmspace->vm_map,
155 					sa, ea, VM_PROT_READ|VM_PROT_EXECUTE,
156 					FALSE);
157 			}
158 		}
159 		if (i < 0)
160 			goto error;
161 		break;
162 
163 	case PT_WRITE_D:		/* write the child's data space */
164 		if (suword((caddr_t)ipc.ip_addr, 0) < 0)
165 			goto error;
166 		(void) suword((caddr_t)ipc.ip_addr, ipc.ip_data);
167 		break;
168 
169 	case PT_WRITE_U:		/* write the child's u. */
170 #ifdef HPUXCOMPAT
171 		if (u.u_pcb.pcb_flags & PCB_HPUXTRACE)
172 			i = hpuxtobsduoff(ipc.ip_addr);
173 		else
174 #endif
175 		i = (int)ipc.ip_addr;
176 		poff = (int *)PHYSOFF(&u, i);
177 		for (i=0; i<NIPCREG; i++)
178 			if (poff == &p->p_regs[ipcreg[i]])
179 				goto ok;
180 		if (poff == &p->p_regs[PS]) {
181 			ipc.ip_data |= PSL_USERSET;
182 			ipc.ip_data &= ~PSL_USERCLR;
183 #ifdef PSL_CM_CLR
184 			if (ipc.ip_data & PSL_CM)
185 				ipc.ip_data &= ~PSL_CM_CLR;
186 #endif
187 			goto ok;
188 		}
189 #if defined(hp300)
190 #ifdef FPCOPROC
191 		if (poff >= (int *)u.u_pcb.pcb_fpregs.fpf_regs &&
192 		    poff <= (int *)&u.u_pcb.pcb_fpregs.fpf_fpiar)
193 			goto ok;
194 #endif
195 #endif
196 		goto error;
197 
198 	ok:
199 		*poff = ipc.ip_data;
200 		break;
201 
202 	case PT_STEP:			/* single step the child */
203 	case PT_CONTINUE:		/* continue the child */
204 		if ((int)ipc.ip_addr != 1)
205 			p->p_regs[PC] = (int)ipc.ip_addr;
206 		if ((unsigned)ipc.ip_data > NSIG)
207 			goto error;
208 		p->p_xstat = ipc.ip_data;	/* see issig */
209 		if (i == PT_STEP)
210 			p->p_regs[PS] |= PSL_T;
211 		wakeup((caddr_t)&ipc);
212 		return (1);
213 
214 	case PT_KILL:			/* kill the child process */
215 		wakeup((caddr_t)&ipc);
216 		exit(p, (int)p->p_xstat);
217 
218 	default:
219 	error:
220 		ipc.ip_req = -1;
221 	}
222 	wakeup((caddr_t)&ipc);
223 	return (0);
224 }
225