xref: /csrg-svn/old/adb/common_source/pcs.c (revision 36578)
1 #ifndef lint
2 static char sccsid[] = "@(#)pcs.c	5.3 (Berkeley) 01/17/89";
3 #endif
4 
5 /*
6  * adb - subprocess control
7  */
8 
9 #include "defs.h"
10 #include "bkpt.h"
11 #include <machine/reg.h>	/* for getpc() *//* XXX */
12 #include <sys/file.h>
13 #include <sys/ptrace.h>
14 #include <sys/wait.h>
15 
16 extern char NOBKPT[];
17 extern char SZBKPT[];
18 extern char EXBKPT[];
19 extern char NOPCS[];
20 extern char BADMOD[];
21 extern char NOFORK[];
22 extern char ENDPCS[];
23 extern char BADWAIT[];
24 
25 struct bkpt *bkpthead;		/* head of breakpoint list */
26 
27 static long runcount;		/* number of times to loop past breakpoints */
28 
29 /* bpstate remembers whether we have installed the breakpoints */
30 static enum { BPOUT, BPIN } bpstate;
31 
32 char	*malloc();
33 
34 /* run modes */
35 #define	CONTINUOUS	0
36 #define	SINGLESTEP	1
37 
38 /* sub process control */
39 
40 subpcs(modif)
41 	int modif;
42 {
43 	register int check;
44 	register struct bkpt *bp;
45 	int execsig, runmode;
46 	char *comptr;
47 
48 	switch (modif) {
49 
50 	case 'd':
51 		/* delete breakpoint */
52 		if ((bp = scanbkpt(dot)) == NULL)
53 			error(NOBKPT);
54 		bp->state = BKPT_FREE;
55 		return;
56 
57 	case 'D':
58 		/* delete all breapoints */
59 		for (bp = bkpthead; bp != NULL; bp = bp->next)
60 			bp->state = BKPT_FREE;
61 		return;
62 
63 	case 'b':
64 	case 'B':
65 		/* set breakpoint */
66 		if ((bp = scanbkpt(dot)) != NULL)
67 			bp->state = BKPT_FREE;
68 		else {
69 			for (bp = bkpthead; bp != NULL; bp = bp->next)
70 				if (bp->state == BKPT_FREE)
71 					break;
72 			if (bp == NULL) {
73 				bp = (struct bkpt *)malloc(sizeof *bp);
74 				if (bp == NULL)
75 					error(EXBKPT);
76 				bp->next = bkpthead;
77 				bkpthead = bp;
78 			}
79 		}
80 		bp->loc = dot;
81 		bp->initcnt = bp->count = ecount;
82 		bp->state = BKPT_SET;
83 		check = MAX_BKPTCOM - 1;
84 		comptr = bp->comm;
85 		(void) rdc();
86 		unreadc();
87 		do {
88 			*comptr++ = readchar();
89 		} while (check-- && lastc != '\n');
90 		*comptr = 0;
91 		unreadc();
92 		if (check == 0)
93 			error(SZBKPT);
94 		return;
95 
96 	case 'k':
97 	case 'K':
98 		/* kill process */
99 		if (pid == 0)
100 			error(NOPCS);
101 		adbprintf("%d: killed", pid);
102 		endpcs();
103 		return;
104 
105 	case 'r':
106 	case 'R':
107 		/* run program */
108 		endpcs();
109 		setup();
110 		runcount = ecount;
111 		runmode = CONTINUOUS;
112 		execsig = 0;
113 		if (gavedot) {
114 			if (scanbkpt(dot) == NULL)
115 				runcount++;
116 		} else {
117 			if (scanbkpt(entrypc()) == NULL)
118 				runcount++;
119 		}
120 		break;
121 
122 	case 's':
123 	case 'S':
124 		/* single step, with optional signal */
125 		runcount = ecount;
126 		if (pid) {
127 			runmode = SINGLESTEP;
128 			execsig = oexpr() ? expv : signo;
129 		} else {
130 			setup();
131 			runmode = SINGLESTEP;
132 			execsig = 0;
133 			runcount--;
134 		}
135 		break;
136 
137 	case 'c':
138 	case 'C':
139 	case 0:
140 		/* continue with optional signal */
141 		runcount = ecount;
142 		if (pid == 0)
143 			error(NOPCS);
144 		runmode = CONTINUOUS;
145 		execsig = oexpr() ? expv : signo;
146 		break;
147 
148 	default:
149 		error(BADMOD);
150 		/* NOTREACHED */
151 	}
152 
153 	if (runcount > 0 && runpcs(runmode, execsig))
154 		adbprintf("breakpoint%16t");
155 	else
156 		adbprintf("stopped at%16t");
157 	delbp();
158 	printpc();
159 }
160 
161 /*
162  * Print all breakpoints.
163  */
164 printbkpts()
165 {
166 	register struct bkpt *b;
167 
168 	adbprintf("breakpoints\ncount%8tbkpt%24tcommand\n");
169 	for (b = bkpthead; b != NULL; b = b->next) {
170 		if (b->state != BKPT_FREE) {
171 			adbprintf("%-8.8D", b->count);
172 			psymoff("%R", b->loc, SP_INSTR, maxoff, "%24t");
173 			prints(b->comm);
174 		}
175 	}
176 }
177 
178 /*
179  * Remove (restore to original instruction(s)) all breakpoints.
180  */
181 delbp()
182 {
183 	register struct bkpt *b;
184 
185 	if (bpstate != BPOUT) {
186 		for (b = bkpthead; b != NULL; b = b->next)
187 			if (b->state != BKPT_FREE && clr_bpt(b))
188 				bperr(b, "clear");
189 		bpstate = BPOUT;
190 	}
191 }
192 
193 /*
194  * Insert all breakpoints.
195  */
196 setbp()
197 {
198 	register struct bkpt *b;
199 
200 	if (bpstate != BPIN) {
201 		for (b = bkpthead; b != NULL; b = b->next)
202 			if (b->state != BKPT_FREE && set_bpt(b))
203 				bperr(b, "set");
204 		bpstate = BPIN;
205 	}
206 }
207 
208 static
209 bperr(b, how)
210 	struct bkpt *b;
211 	char *how;
212 {
213 
214 	adbprintf("cannot %s breakpoint: ", how);
215 	psymoff("%R", b->loc, SP_INSTR, maxoff, "\n");
216 }
217 
218 /*
219  * ... return true iff stopped due to breakpoint
220  */
221 int
222 runpcs(runmode, execsig)
223 	int runmode, execsig;
224 {
225 	register struct bkpt *bkpt;
226 	int rc;
227 
228 	/* always set pc, so that expr>pc works too */
229 	setpc(gavedot ? dot : getpc());
230 	adbprintf("%s: running\n", symfile.name);
231 	while (--runcount >= 0) {
232 		/* BEGIN XXX (machine dependent?, delete ptrace, etc) */
233 		if (runmode == SINGLESTEP)
234 			delbp();	/* hardware handles single-stepping */
235 		else {	/* continuing from a breakpoint is hard */
236 			if ((bkpt = scanbkpt(getpc())) != NULL) {
237 				execbkpt(bkpt, execsig);
238 				execsig = 0;
239 			}
240 			setbp();
241 		}
242 		(void) ptrace(runmode == CONTINUOUS ? PT_CONTINUE : PT_STEP,
243 			pid, (int *)getpc(), execsig);
244 		/* END XXX */
245 		bpwait();
246 		checkerr();
247 		execsig = 0;
248 		delbp();
249 		readregs();
250 
251 		if (signo != 0 || (bkpt = scanbkpt(getpc())) == NULL) {
252 			execsig = signo;
253 			rc = 0;
254 			continue;
255 		}
256 		/* stopped by BPT instruction */
257 #ifdef DEBUG
258 		adbprintf("\n BPT code: comm=%s%8tstate=%d",
259 		    bkpt->comm, bkpt->state);
260 #endif
261 		dot = bkpt->loc;
262 		switch (bkpt->state) {
263 			char *p;
264 
265 		case BKPT_SET:
266 			bkpt->state = BKPT_TRIPPED;
267 			if (*bkpt->comm == '\n')
268 				break;
269 			p = lp;
270 			command(bkpt->comm, ':');
271 			lp = p;
272 			if (gavedot && edot == 0) /* maybe dot==0 ??? */
273 				break;
274 			if (--bkpt->count == 0)
275 				break;
276 			/* FALLTHROUGH */
277 
278 		case BKPT_TRIPPED:
279 			execbkpt(bkpt, execsig);
280 			execsig = 0;
281 			runcount++;
282 			continue;
283 
284 		default:
285 			panic("runpcs");
286 			/* NOTREACHED */
287 		}
288 		bkpt->count = bkpt->initcnt;
289 		rc = 1;
290 	}
291 	return (rc);
292 }
293 
294 endpcs()
295 {
296 	register struct bkpt *bp;
297 
298 	if (pid) {
299 		(void) ptrace(PT_KILL, pid, (int *)0, 0);	/* XXX */
300 		pid = 0;
301 		for (bp = bkpthead; bp != NULL; bp = bp->next)
302 			if (bp->state != BKPT_FREE)
303 				bp->state = BKPT_SET;
304 	}
305 	bpstate = BPOUT;
306 }
307 
308 #ifdef VFORK
309 nullsig()
310 {
311 
312 }
313 #endif
314 
315 setup()
316 {
317 
318 	(void) close(symfile.fd);
319 	symfile.fd = -1;
320 #ifndef VFORK
321 #define vfork fork
322 #endif
323 	if ((pid = vfork()) == 0) {
324 		(void) ptrace(PT_TRACE_ME, 0, (int *)0, 0);	/* XXX */
325 #ifdef VFORK
326 		(void) signal(SIGTRAP, nullsig);
327 #endif
328 		(void) signal(SIGINT, sigint);
329 		(void) signal(SIGQUIT, sigquit);
330 		doexec();
331 		exit(0);
332 	} else if (pid == -1)
333 		error(NOFORK);
334 	else {
335 		bpwait();
336 		readregs();
337 		symfile.fd = open(symfile.name, wtflag);
338 		if (errflag) {
339 			adbprintf("%s: cannot execute\n", symfile.name);
340 			endpcs();
341 			error((char *)0);
342 		}
343 	}
344 	bpstate = BPOUT;
345 }
346 
347 execbkpt(bp, execsig)
348 	struct bkpt *bp;
349 	int execsig;
350 {
351 
352 #ifdef DEBUG
353 	adbprintf("exbkpt: %d\n", bp->count);
354 #endif
355 	delbp();
356 	(void) ptrace(PT_STEP, pid, (int *)bp->loc, execsig);	/* XXX */
357 	bp->state = BKPT_SET;
358 	bpwait();
359 	checkerr();
360 	readregs();
361 }
362 
363 static char separators[] = "<> \t\n";
364 
365 doexec()
366 {
367 	register char *p, **ap;
368 	register int c;
369 	char *argl[LINELEN / 2 + 1];
370 	char args[LINELEN];
371 	extern char **environ;
372 	char *index();
373 
374 	ap = argl;
375 	p = args;
376 	*ap++ = symfile.name;
377 	do {
378 		switch (c = rdc()) {
379 
380 		case '\n':
381 			break;
382 
383 		case '<':
384 			setfile(0, O_RDONLY, 0, p, "open");
385 			break;
386 
387 		case '>':
388 			setfile(1, O_CREAT|O_WRONLY, 0666, p, "create");
389 			break;
390 
391 		default:
392 			*ap = p;
393 			while (index(separators, c) == NULL) {
394 				*p++ = c;
395 				c = readchar();
396 			}
397 			*p++ = '\0';
398 			ap++;
399 		}
400 	} while (c != '\n');
401 	unreadc();
402 	*ap++ = 0;
403 	execve(symfile.name, argl, environ);
404 	perror(symfile.name);
405 }
406 
407 static int
408 setfile(fd, flags, mode, namebuf, err)
409 	int fd, flags, mode;
410 	char *namebuf, *err;
411 {
412 	register char *p = namebuf;
413 	register int c = rdc();
414 
415 	while (index(separators, c) == NULL) {
416 		*p++ = c;
417 		c = readchar();
418 	}
419 	*p = 0;
420 	(void) close(fd);
421 	if (open(namebuf, flags, mode) < 0) {
422 		adbprintf("%s: cannot %s\n", namebuf, err);
423 		_exit(0);
424 		/* NOTREACHED */
425 	}
426 }
427 
428 struct bkpt *
429 scanbkpt(a)
430 	register addr_t a;
431 {
432 	register struct bkpt *bp;
433 
434 	for (bp = bkpthead; bp != NULL; bp = bp->next)
435 		if (bp->state != BKPT_FREE && bp->loc == a)
436 			break;
437 	return (bp);
438 }
439 
440 bpwait()
441 {
442 	register int w;
443 	union wait status;
444 
445 	(void) signal(SIGINT, SIG_IGN);
446 	while ((w = wait(&status)) != pid && w != -1)
447 		 /* void */ ;
448 	(void) signal(SIGINT, intcatch);
449 	if (w == -1) {
450 		pid = 0;
451 		errflag = BADWAIT;
452 	} else if (!WIFSTOPPED(status)) {
453 		sigcode = 0;
454 		if ((signo = status.w_termsig) != 0)
455 			sigprint();
456 		if (status.w_coredump) {
457 			prints(" - core dumped");
458 			(void) close(corefile.fd);
459 			setcore();
460 		}
461 		pid = 0;
462 		bpstate = BPOUT;
463 		errflag = ENDPCS;
464 	} else {
465 		signo = status.w_stopsig;
466 		sigcode = ptrace(PT_READ_U, pid,
467 				 &((struct user *)0)->u_code, 0); /* XXX */
468 		if (signo != SIGTRAP)
469 			sigprint();
470 		else
471 			signo = 0;
472 		flushbuf();
473 	}
474 }
475