add USL's copyright notice
[unix-history] / usr / src / sys / kern / sys_process.c
CommitLineData
5dc2581e 1/*-
7a6e4544
KB
2 * Copyright (c) 1982, 1986, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
adb35f79
KB
4 * (c) UNIX System Laboratories, Inc.
5 * All or some portions of this file are derived from material licensed
6 * to the University of California by American Telephone and Telegraph
7 * Co. or Unix System Laboratories, Inc. and are reproduced herein with
8 * the permission of UNIX System Laboratories, Inc.
5dc2581e
KB
9 *
10 * %sccs.include.proprietary.c%
da7c5cc6 11 *
adb35f79 12 * @(#)sys_process.c 8.5 (Berkeley) %G%
da7c5cc6 13 */
961945a8 14
ff32eb64 15#define IPCREG
38a01dbe
KB
16#include <sys/param.h>
17#include <sys/proc.h>
18#include <sys/vnode.h>
19#include <sys/buf.h>
20#include <sys/ptrace.h>
9ce4de2d 21
38a01dbe
KB
22#include <machine/reg.h>
23#include <machine/psl.h>
24#include <vm/vm.h>
25#include <vm/vm_page.h>
de5931fb 26
38a01dbe 27#include <sys/user.h>
d301d150 28
4147b3f6
BJ
29/*
30 * Priority for tracing
31 */
32#define IPCPRI PZERO
33
34/*
35 * Tracing variables.
36 * Used to pass trace command from
37 * parent to child being traced.
38 * This data base cannot be
39 * shared and is locked
40 * per user.
41 */
42struct {
43 int ip_lock;
44 int ip_req;
80527497 45 caddr_t ip_addr;
4147b3f6
BJ
46 int ip_data;
47} ipc;
48
49/*
3f75397a 50 * Process debugging system call.
4147b3f6 51 */
afc12c69
CT
52struct ptrace_args {
53 int req;
80527497
KM
54 pid_t pid;
55 caddr_t addr;
afc12c69
CT
56 int data;
57};
8c7d0e2a
KM
58ptrace(curp, uap, retval)
59 struct proc *curp;
afc12c69 60 register struct ptrace_args *uap;
8c7d0e2a
KM
61 int *retval;
62{
63 register struct proc *p;
ee8c7b71 64 int error;
4147b3f6 65
48c729cb 66 if (uap->req <= 0) {
cf5ef508 67 curp->p_flag |= P_TRACED;
48c729cb
MH
68 return (0);
69 }
ee8c7b71 70 p = pfind(uap->pid);
48c729cb
MH
71 if (p == 0)
72 return (ESRCH);
ee8c7b71
KM
73 if (uap->req == PT_ATTACH) {
74 /*
45f54c1f
KB
75 * Must be root if the process has used set user or group
76 * privileges or does not belong to the real user. Must
77 * not be already traced. Can't attach to ourselves.
ee8c7b71 78 */
cf5ef508 79 if ((p->p_flag & P_SUGID ||
ee8c7b71
KM
80 p->p_cred->p_ruid != curp->p_cred->p_ruid) &&
81 (error = suser(p->p_ucred, &p->p_acflag)) != 0)
82 return (error);
cf5ef508 83 if (p->p_flag & P_TRACED)
ee8c7b71 84 return (EALREADY); /* ??? */
45f54c1f
KB
85 if (p->p_pid == curp->p_pid)
86 return (EINVAL);
ee8c7b71
KM
87 /*
88 * It would be nice if the tracing relationship was separate
89 * from the parent relationship but that would require
90 * another set of links in the proc struct or for "wait"
91 * to scan the entire proc table. To make life easier,
92 * we just re-parent the process we're trying to trace.
93 * The old parent is remembered so we can put things back
94 * on a "detach".
95 */
cf5ef508 96 p->p_flag |= P_TRACED;
ee8c7b71
KM
97 p->p_oppid = p->p_pptr->p_pid;
98 proc_reparent(p, curp);
99 psignal(p, SIGSTOP);
100 return (0);
101 }
cf5ef508 102 if (p->p_stat != SSTOP || p->p_pptr != curp || !(p->p_flag & P_TRACED))
d9c2f47f 103 return (ESRCH);
4147b3f6
BJ
104 while (ipc.ip_lock)
105 sleep((caddr_t)&ipc, IPCPRI);
106 ipc.ip_lock = p->p_pid;
107 ipc.ip_data = uap->data;
108 ipc.ip_addr = uap->addr;
109 ipc.ip_req = uap->req;
cf5ef508 110 p->p_flag &= ~P_WAITED;
4147b3f6
BJ
111 while (ipc.ip_req > 0) {
112 if (p->p_stat==SSTOP)
cb84e0ab 113 setrunnable(p);
4147b3f6
BJ
114 sleep((caddr_t)&ipc, IPCPRI);
115 }
8c7d0e2a 116 *retval = ipc.ip_data;
4147b3f6
BJ
117 ipc.ip_lock = 0;
118 wakeup((caddr_t)&ipc);
8c7d0e2a 119 if (ipc.ip_req < 0)
d9c2f47f
MK
120 return (EIO);
121 return (0);
4147b3f6
BJ
122}
123
e128a701 124#define PHYSOFF(p, o) ((caddr_t)(p) + (o))
b4d15838
KM
125#if defined(hp300) || defined(luna68k)
126#define PHYSALIGNED(a) (((int)(a) & (sizeof(short) - 1)) == 0)
127#else
128#define PHYSALIGNED(a) (((int)(a) & (sizeof(int) - 1)) == 0)
129#endif
e128a701 130
6ce8aff2
WN
131#if defined(i386)
132#undef PC
133#undef SP
134#undef PS
135#undef R0
136#undef R1
137
138#define PC tEIP
139#define SP tESP
140#define PS tEFLAGS
141#define R0 tEDX
142#define R1 tECX
143#endif
883d0f83 144
4147b3f6 145/*
3f75397a
KM
146 * Transmit a tracing request from the parent to the child process
147 * being debugged. This code runs in the context of the child process
148 * to fulfill the command requested by the parent.
4147b3f6 149 */
cf5ef508 150trace_req(p)
82655668 151 register struct proc *p;
4147b3f6 152{
214b997f 153 register int i, *poff, *regs;
e128a701 154 extern char kstack[];
4147b3f6 155
82655668 156 if (ipc.ip_lock != p->p_pid)
4147b3f6 157 return (0);
82655668 158 p->p_slptime = 0;
214b997f
MH
159 regs = p->p_md.md_regs;
160 p->p_addr->u_kproc.kp_proc.p_md.md_regs = regs; /* u.u_ar0 */
4147b3f6
BJ
161 i = ipc.ip_req;
162 ipc.ip_req = 0;
163 switch (i) {
164
01b0e233 165 case PT_READ_I: /* read the child's text space */
4147b3f6
BJ
166 if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
167 goto error;
168 ipc.ip_data = fuiword((caddr_t)ipc.ip_addr);
169 break;
170
01b0e233 171 case PT_READ_D: /* read the child's data space */
4147b3f6
BJ
172 if (!useracc((caddr_t)ipc.ip_addr, 4, B_READ))
173 goto error;
174 ipc.ip_data = fuword((caddr_t)ipc.ip_addr);
175 break;
176
01b0e233 177 case PT_READ_U: /* read the child's u. */
4147b3f6 178 i = (int)ipc.ip_addr;
b4d15838 179 if ((u_int) i > ctob(UPAGES)-sizeof(int) || !PHYSALIGNED(i))
4147b3f6 180 goto error;
eadb8ef2 181 ipc.ip_data = *(int *)PHYSOFF(p->p_addr, i);
4147b3f6
BJ
182 break;
183
01b0e233 184 case PT_WRITE_I: /* write the child's text space */
883d0f83 185 if ((i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data)) < 0) {
9db58063
KM
186 vm_offset_t sa, ea;
187 int rv;
188
189 sa = trunc_page((vm_offset_t)ipc.ip_addr);
d6cefe4b 190 ea = round_page((vm_offset_t)ipc.ip_addr+sizeof(int));
d7db4999 191 rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea,
9db58063
KM
192 VM_PROT_DEFAULT, FALSE);
193 if (rv == KERN_SUCCESS) {
883d0f83 194 i = suiword((caddr_t)ipc.ip_addr, ipc.ip_data);
d7db4999
MK
195 (void) vm_map_protect(&p->p_vmspace->vm_map,
196 sa, ea, VM_PROT_READ|VM_PROT_EXECUTE,
197 FALSE);
9db58063 198 }
883d0f83 199 }
4147b3f6
BJ
200 if (i < 0)
201 goto error;
4147b3f6
BJ
202 break;
203
01b0e233 204 case PT_WRITE_D: /* write the child's data space */
4147b3f6
BJ
205 if (suword((caddr_t)ipc.ip_addr, 0) < 0)
206 goto error;
207 (void) suword((caddr_t)ipc.ip_addr, ipc.ip_data);
208 break;
209
01b0e233 210 case PT_WRITE_U: /* write the child's u. */
4147b3f6 211 i = (int)ipc.ip_addr;
d89b7f8b 212#ifdef mips
b4d15838 213 poff = (int *)PHYSOFF(p->p_addr, i);
d89b7f8b 214#else
e128a701 215 poff = (int *)PHYSOFF(kstack, i);
d89b7f8b 216#endif
883d0f83 217 for (i=0; i<NIPCREG; i++)
214b997f 218 if (poff == &regs[ipcreg[i]])
4147b3f6 219 goto ok;
2a81c17c 220#if defined(hp300) || defined(luna68k)
214b997f
MH
221 /*
222 * In the new frame layout, PS/PC are skewed by 2 bytes.
223 */
224 regs = (int *)((short *)regs + 1);
225 if (poff == &regs[PC])
226 goto ok;
227#endif
228 if (poff == &regs[PS]) {
883d0f83 229 ipc.ip_data |= PSL_USERSET;
dc57440c 230 ipc.ip_data &= ~PSL_USERCLR;
bf47fbca
MK
231#ifdef PSL_CM_CLR
232 if (ipc.ip_data & PSL_CM)
233 ipc.ip_data &= ~PSL_CM_CLR;
234#endif
4147b3f6
BJ
235 goto ok;
236 }
7c02c1d3 237#if defined(hp300) || defined(luna68k)
dc57440c 238#ifdef FPCOPROC
e128a701
MK
239 if (poff >= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_regs &&
240 poff <= (int *)&((struct user *)kstack)->u_pcb.pcb_fpregs.fpf_fpiar)
dc57440c
KM
241 goto ok;
242#endif
243#endif
4147b3f6
BJ
244 goto error;
245
246 ok:
82655668 247 *poff = ipc.ip_data;
4147b3f6
BJ
248 break;
249
01b0e233
MK
250 case PT_STEP: /* single step the child */
251 case PT_CONTINUE: /* continue the child */
92ee7b5c 252#ifndef mips
214b997f 253 regs = (int *)((short *)regs + 1);
92ee7b5c 254#endif
ee8c7b71
KM
255 if ((unsigned)ipc.ip_data >= NSIG)
256 goto error;
4147b3f6 257 if ((int)ipc.ip_addr != 1)
214b997f 258 regs[PC] = (int)ipc.ip_addr;
cf5ef508 259 p->p_xstat = ipc.ip_data; /* see issignal */
92ee7b5c
KM
260#ifdef mips
261 if (i == PT_STEP && cpu_singlestep(p))
262 goto error;
263#else
d89b7f8b
MT
264#ifdef PSL_T
265 /* need something more machine independent here... */
01b0e233 266 if (i == PT_STEP)
214b997f 267 regs[PS] |= PSL_T;
92ee7b5c 268#endif
d89b7f8b 269#endif
4147b3f6
BJ
270 wakeup((caddr_t)&ipc);
271 return (1);
272
01b0e233 273 case PT_KILL: /* kill the child process */
4147b3f6 274 wakeup((caddr_t)&ipc);
817f339a 275 exit1(p, (int)p->p_xstat);
4147b3f6 276
ee8c7b71 277 case PT_DETACH: /* stop tracing the child */
214b997f 278 regs = (int *)((short *)regs + 1);
ee8c7b71
KM
279 if ((unsigned)ipc.ip_data >= NSIG)
280 goto error;
281 if ((int)ipc.ip_addr != 1)
214b997f 282 regs[PC] = (int)ipc.ip_addr;
cf5ef508
KB
283 p->p_xstat = ipc.ip_data; /* see issignal */
284 p->p_flag &= ~P_TRACED;
ee8c7b71
KM
285 if (p->p_oppid != p->p_pptr->p_pid) {
286 register struct proc *pp = pfind(p->p_oppid);
287
288 if (pp)
289 proc_reparent(p, pp);
290 }
291 p->p_oppid = 0;
292 wakeup((caddr_t)&ipc);
293 return (1);
294
4147b3f6
BJ
295 default:
296 error:
297 ipc.ip_req = -1;
298 }
299 wakeup((caddr_t)&ipc);
300 return (0);
301}