xref: /csrg-svn/old/adb/common_source/pcs.c (revision 47822)
1*47822Sbostic /*-
2*47822Sbostic  * Copyright (c) 1991 The Regents of the University of California.
3*47822Sbostic  * All rights reserved.
4*47822Sbostic  *
5*47822Sbostic  * %sccs.include.proprietary.c%
6*47822Sbostic  */
7*47822Sbostic 
836559Sbostic #ifndef lint
9*47822Sbostic static char sccsid[] = "@(#)pcs.c	5.6 (Berkeley) 04/04/91";
10*47822Sbostic #endif /* not lint */
1136559Sbostic 
1236559Sbostic /*
1336559Sbostic  * adb - subprocess control
1436559Sbostic  */
1536559Sbostic 
1636559Sbostic #include "defs.h"
1736559Sbostic #include "bkpt.h"
1836559Sbostic #include <machine/reg.h>	/* for getpc() *//* XXX */
1936559Sbostic #include <sys/file.h>
2036559Sbostic #include <sys/ptrace.h>
2136559Sbostic #include <sys/wait.h>
2236559Sbostic 
2336559Sbostic extern char NOBKPT[];
2436559Sbostic extern char SZBKPT[];
2536559Sbostic extern char EXBKPT[];
2636559Sbostic extern char NOPCS[];
2736559Sbostic extern char BADMOD[];
2836559Sbostic extern char NOFORK[];
2936559Sbostic extern char ENDPCS[];
3036559Sbostic extern char BADWAIT[];
3136559Sbostic 
3236559Sbostic struct bkpt *bkpthead;		/* head of breakpoint list */
3336559Sbostic 
3436559Sbostic static long runcount;		/* number of times to loop past breakpoints */
3536559Sbostic 
3636559Sbostic /* bpstate remembers whether we have installed the breakpoints */
3736559Sbostic static enum { BPOUT, BPIN } bpstate;
3836559Sbostic 
3936559Sbostic char	*malloc();
4036559Sbostic 
4136559Sbostic /* run modes */
4236559Sbostic #define	CONTINUOUS	0
4336559Sbostic #define	SINGLESTEP	1
4436559Sbostic 
4536559Sbostic /* sub process control */
4636559Sbostic 
subpcs(modif)4736559Sbostic subpcs(modif)
4836559Sbostic 	int modif;
4936559Sbostic {
5036559Sbostic 	register int check;
5136559Sbostic 	register struct bkpt *bp;
5236578Storek 	int execsig, runmode;
5336559Sbostic 	char *comptr;
5436559Sbostic 
5536559Sbostic 	switch (modif) {
5636559Sbostic 
5736559Sbostic 	case 'd':
5836559Sbostic 		/* delete breakpoint */
5936559Sbostic 		if ((bp = scanbkpt(dot)) == NULL)
6036559Sbostic 			error(NOBKPT);
6136559Sbostic 		bp->state = BKPT_FREE;
6236559Sbostic 		return;
6336559Sbostic 
6436559Sbostic 	case 'D':
6536559Sbostic 		/* delete all breapoints */
6636559Sbostic 		for (bp = bkpthead; bp != NULL; bp = bp->next)
6736559Sbostic 			bp->state = BKPT_FREE;
6836559Sbostic 		return;
6936559Sbostic 
7036559Sbostic 	case 'b':
7136559Sbostic 	case 'B':
7236559Sbostic 		/* set breakpoint */
7337336Storek 		if ((bp = scanbkpt(dot)) == NULL) {
7437336Storek 			/* find a free one, or make one */
7536559Sbostic 			for (bp = bkpthead; bp != NULL; bp = bp->next)
7636559Sbostic 				if (bp->state == BKPT_FREE)
7736559Sbostic 					break;
7836559Sbostic 			if (bp == NULL) {
7936559Sbostic 				bp = (struct bkpt *)malloc(sizeof *bp);
8036559Sbostic 				if (bp == NULL)
8136559Sbostic 					error(EXBKPT);
8236559Sbostic 				bp->next = bkpthead;
8336559Sbostic 				bkpthead = bp;
8436559Sbostic 			}
8536559Sbostic 		}
8636559Sbostic 		bp->loc = dot;
8736559Sbostic 		bp->initcnt = bp->count = ecount;
8836559Sbostic 		bp->state = BKPT_SET;
8936559Sbostic 		check = MAX_BKPTCOM - 1;
9036559Sbostic 		comptr = bp->comm;
9136559Sbostic 		(void) rdc();
9236559Sbostic 		unreadc();
9336559Sbostic 		do {
9436559Sbostic 			*comptr++ = readchar();
9536559Sbostic 		} while (check-- && lastc != '\n');
9636559Sbostic 		*comptr = 0;
9736559Sbostic 		unreadc();
9836559Sbostic 		if (check == 0)
9936559Sbostic 			error(SZBKPT);
10036559Sbostic 		return;
10136559Sbostic 
10236559Sbostic 	case 'k':
10336559Sbostic 	case 'K':
10436559Sbostic 		/* kill process */
10536559Sbostic 		if (pid == 0)
10636559Sbostic 			error(NOPCS);
10736559Sbostic 		adbprintf("%d: killed", pid);
10836559Sbostic 		endpcs();
10936559Sbostic 		return;
11036559Sbostic 
11136559Sbostic 	case 'r':
11236559Sbostic 	case 'R':
11336559Sbostic 		/* run program */
11436559Sbostic 		endpcs();
11536559Sbostic 		setup();
11636559Sbostic 		runcount = ecount;
11736578Storek 		runmode = CONTINUOUS;
11836559Sbostic 		execsig = 0;
11937336Storek 		/* if starting at a breakpoint, run over it */
12037336Storek 		if (scanbkpt(gavedot ? dot : entrypc()) != NULL)
12137336Storek 			runcount++;
12236559Sbostic 		break;
12336559Sbostic 
12436559Sbostic 	case 's':
12536559Sbostic 	case 'S':
12636559Sbostic 		/* single step, with optional signal */
12736559Sbostic 		runcount = ecount;
12836559Sbostic 		if (pid) {
12936559Sbostic 			runmode = SINGLESTEP;
13036559Sbostic 			execsig = oexpr() ? expv : signo;
13136559Sbostic 		} else {
13236559Sbostic 			setup();
13336578Storek 			runmode = SINGLESTEP;
13436559Sbostic 			execsig = 0;
13536578Storek 			runcount--;
13636559Sbostic 		}
13736559Sbostic 		break;
13836559Sbostic 
13936559Sbostic 	case 'c':
14036559Sbostic 	case 'C':
14136559Sbostic 	case 0:
14236559Sbostic 		/* continue with optional signal */
14336559Sbostic 		runcount = ecount;
14436559Sbostic 		if (pid == 0)
14536559Sbostic 			error(NOPCS);
14636559Sbostic 		runmode = CONTINUOUS;
14736559Sbostic 		execsig = oexpr() ? expv : signo;
14836559Sbostic 		break;
14936559Sbostic 
15036559Sbostic 	default:
15136559Sbostic 		error(BADMOD);
15236578Storek 		/* NOTREACHED */
15336559Sbostic 	}
15436559Sbostic 
15536578Storek 	if (runcount > 0 && runpcs(runmode, execsig))
15636559Sbostic 		adbprintf("breakpoint%16t");
15736559Sbostic 	else
15836559Sbostic 		adbprintf("stopped at%16t");
15936559Sbostic 	delbp();
16036559Sbostic 	printpc();
16136559Sbostic }
16236559Sbostic 
16336559Sbostic /*
16436559Sbostic  * Print all breakpoints.
16536559Sbostic  */
printbkpts()16636559Sbostic printbkpts()
16736559Sbostic {
16836559Sbostic 	register struct bkpt *b;
16936559Sbostic 
17036559Sbostic 	adbprintf("breakpoints\ncount%8tbkpt%24tcommand\n");
17136559Sbostic 	for (b = bkpthead; b != NULL; b = b->next) {
17236559Sbostic 		if (b->state != BKPT_FREE) {
17336559Sbostic 			adbprintf("%-8.8D", b->count);
17436559Sbostic 			psymoff("%R", b->loc, SP_INSTR, maxoff, "%24t");
17536559Sbostic 			prints(b->comm);
17636559Sbostic 		}
17736559Sbostic 	}
17836559Sbostic }
17936559Sbostic 
18036559Sbostic /*
18136559Sbostic  * Remove (restore to original instruction(s)) all breakpoints.
18236559Sbostic  */
delbp()18336559Sbostic delbp()
18436559Sbostic {
18536559Sbostic 	register struct bkpt *b;
18636559Sbostic 
18736559Sbostic 	if (bpstate != BPOUT) {
18836559Sbostic 		for (b = bkpthead; b != NULL; b = b->next)
18936559Sbostic 			if (b->state != BKPT_FREE && clr_bpt(b))
19036559Sbostic 				bperr(b, "clear");
19136559Sbostic 		bpstate = BPOUT;
19236559Sbostic 	}
19336559Sbostic }
19436559Sbostic 
19536559Sbostic /*
19636559Sbostic  * Insert all breakpoints.
19736559Sbostic  */
setbp()19836559Sbostic setbp()
19936559Sbostic {
20036559Sbostic 	register struct bkpt *b;
20136559Sbostic 
20236559Sbostic 	if (bpstate != BPIN) {
20336559Sbostic 		for (b = bkpthead; b != NULL; b = b->next)
20436559Sbostic 			if (b->state != BKPT_FREE && set_bpt(b))
20536559Sbostic 				bperr(b, "set");
20636559Sbostic 		bpstate = BPIN;
20736559Sbostic 	}
20836559Sbostic }
20936559Sbostic 
21036559Sbostic static
21136559Sbostic bperr(b, how)
21236559Sbostic 	struct bkpt *b;
21336559Sbostic 	char *how;
21436559Sbostic {
21536559Sbostic 
21636559Sbostic 	adbprintf("cannot %s breakpoint: ", how);
21736559Sbostic 	psymoff("%R", b->loc, SP_INSTR, maxoff, "\n");
21836559Sbostic }
21936559Sbostic 
22036559Sbostic /*
22136679Storek  * Run subprocess for a while.
22236679Storek  * Return true iff stopped due to breakpoint.
22336559Sbostic  */
22436559Sbostic int
runpcs(runmode,execsig)22536578Storek runpcs(runmode, execsig)
22636578Storek 	int runmode, execsig;
22736559Sbostic {
22836559Sbostic 	register struct bkpt *bkpt;
22936559Sbostic 	int rc;
23036559Sbostic 
23136559Sbostic 	/* always set pc, so that expr>pc works too */
23236578Storek 	setpc(gavedot ? dot : getpc());
23336559Sbostic 	adbprintf("%s: running\n", symfile.name);
23436559Sbostic 	while (--runcount >= 0) {
23536559Sbostic 		/* BEGIN XXX (machine dependent?, delete ptrace, etc) */
23636559Sbostic 		if (runmode == SINGLESTEP)
23736559Sbostic 			delbp();	/* hardware handles single-stepping */
23836559Sbostic 		else {	/* continuing from a breakpoint is hard */
23936578Storek 			if ((bkpt = scanbkpt(getpc())) != NULL) {
24036559Sbostic 				execbkpt(bkpt, execsig);
24136559Sbostic 				execsig = 0;
24236559Sbostic 			}
24336559Sbostic 			setbp();
24436559Sbostic 		}
24536559Sbostic 		(void) ptrace(runmode == CONTINUOUS ? PT_CONTINUE : PT_STEP,
24636578Storek 			pid, (int *)getpc(), execsig);
24736559Sbostic 		/* END XXX */
24836679Storek 
24936679Storek 		/* paranoia, SP_DATA usually sufficient, but this is easy */
25036679Storek 		cacheinval(SP_INSTR | SP_DATA);
25136679Storek 
25236559Sbostic 		bpwait();
25336559Sbostic 		checkerr();
25436559Sbostic 		execsig = 0;
25536559Sbostic 		delbp();
25636559Sbostic 		readregs();
25736559Sbostic 
25836559Sbostic 		if (signo != 0 || (bkpt = scanbkpt(getpc())) == NULL) {
25936559Sbostic 			execsig = signo;
26036559Sbostic 			rc = 0;
26136559Sbostic 			continue;
26236559Sbostic 		}
26336559Sbostic 		/* stopped by BPT instruction */
26436559Sbostic #ifdef DEBUG
26536559Sbostic 		adbprintf("\n BPT code: comm=%s%8tstate=%d",
26636559Sbostic 		    bkpt->comm, bkpt->state);
26736559Sbostic #endif
26836559Sbostic 		dot = bkpt->loc;
26936559Sbostic 		switch (bkpt->state) {
27036559Sbostic 			char *p;
27136559Sbostic 
27236559Sbostic 		case BKPT_SET:
27336559Sbostic 			bkpt->state = BKPT_TRIPPED;
27436559Sbostic 			if (*bkpt->comm == '\n')
27536559Sbostic 				break;
27636559Sbostic 			p = lp;
27736559Sbostic 			command(bkpt->comm, ':');
27836559Sbostic 			lp = p;
27936559Sbostic 			if (gavedot && edot == 0) /* maybe dot==0 ??? */
28036559Sbostic 				break;
28136559Sbostic 			if (--bkpt->count == 0)
28236559Sbostic 				break;
28336559Sbostic 			/* FALLTHROUGH */
28436559Sbostic 
28536559Sbostic 		case BKPT_TRIPPED:
28636559Sbostic 			execbkpt(bkpt, execsig);
28736559Sbostic 			execsig = 0;
28836559Sbostic 			runcount++;
28936559Sbostic 			continue;
29036559Sbostic 
29136559Sbostic 		default:
29236559Sbostic 			panic("runpcs");
29336559Sbostic 			/* NOTREACHED */
29436559Sbostic 		}
29536559Sbostic 		bkpt->count = bkpt->initcnt;
29636559Sbostic 		rc = 1;
29736559Sbostic 	}
29836559Sbostic 	return (rc);
29936559Sbostic }
30036559Sbostic 
endpcs()30136559Sbostic endpcs()
30236559Sbostic {
30336559Sbostic 	register struct bkpt *bp;
30436559Sbostic 
30536559Sbostic 	if (pid) {
30636559Sbostic 		(void) ptrace(PT_KILL, pid, (int *)0, 0);	/* XXX */
30736559Sbostic 		pid = 0;
30836559Sbostic 		for (bp = bkpthead; bp != NULL; bp = bp->next)
30936559Sbostic 			if (bp->state != BKPT_FREE)
31036559Sbostic 				bp->state = BKPT_SET;
31136559Sbostic 	}
31236559Sbostic 	bpstate = BPOUT;
31336559Sbostic }
31436559Sbostic 
31536559Sbostic #ifdef VFORK
nullsig()31636559Sbostic nullsig()
31736559Sbostic {
31836559Sbostic 
31936559Sbostic }
32036559Sbostic #endif
32136559Sbostic 
setup()32236559Sbostic setup()
32336559Sbostic {
32436559Sbostic 
32536679Storek 	cacheinval(SP_INSTR | SP_DATA);	/* paranoia */
32636559Sbostic 	(void) close(symfile.fd);
32736559Sbostic 	symfile.fd = -1;
32836559Sbostic #ifndef VFORK
32936559Sbostic #define vfork fork
33036559Sbostic #endif
33136559Sbostic 	if ((pid = vfork()) == 0) {
33236559Sbostic 		(void) ptrace(PT_TRACE_ME, 0, (int *)0, 0);	/* XXX */
33336559Sbostic #ifdef VFORK
33436559Sbostic 		(void) signal(SIGTRAP, nullsig);
33536559Sbostic #endif
33636559Sbostic 		(void) signal(SIGINT, sigint);
33736559Sbostic 		(void) signal(SIGQUIT, sigquit);
33836559Sbostic 		doexec();
33936559Sbostic 		exit(0);
34036679Storek 	} else if (pid == -1) {
34136679Storek 		pid = 0;
34236559Sbostic 		error(NOFORK);
34336679Storek 	} else {
34436559Sbostic 		bpwait();
34536559Sbostic 		readregs();
34636559Sbostic 		symfile.fd = open(symfile.name, wtflag);
34736559Sbostic 		if (errflag) {
34836559Sbostic 			adbprintf("%s: cannot execute\n", symfile.name);
34936559Sbostic 			endpcs();
35036559Sbostic 			error((char *)0);
35136559Sbostic 		}
35236559Sbostic 	}
35336559Sbostic 	bpstate = BPOUT;
35436559Sbostic }
35536559Sbostic 
35637336Storek /*
35737336Storek  * Single step over a location containing a breakpoint.
35837336Storek  */
35936559Sbostic execbkpt(bp, execsig)
36036559Sbostic 	struct bkpt *bp;
36136559Sbostic 	int execsig;
36236559Sbostic {
36336559Sbostic 
36436559Sbostic #ifdef DEBUG
36536559Sbostic 	adbprintf("exbkpt: %d\n", bp->count);
36636559Sbostic #endif
36736559Sbostic 	delbp();
36836559Sbostic 	(void) ptrace(PT_STEP, pid, (int *)bp->loc, execsig);	/* XXX */
36936559Sbostic 	bp->state = BKPT_SET;
37036559Sbostic 	bpwait();
37136559Sbostic 	checkerr();
37236559Sbostic 	readregs();
37336559Sbostic }
37436559Sbostic 
37536559Sbostic static char separators[] = "<> \t\n";
37636559Sbostic 
doexec()37736559Sbostic doexec()
37836559Sbostic {
37936559Sbostic 	register char *p, **ap;
38036559Sbostic 	register int c;
38136559Sbostic 	char *argl[LINELEN / 2 + 1];
38236559Sbostic 	char args[LINELEN];
38336559Sbostic 	extern char **environ;
38436559Sbostic 	char *index();
38536559Sbostic 
38636559Sbostic 	ap = argl;
38736559Sbostic 	p = args;
38836559Sbostic 	*ap++ = symfile.name;
38936559Sbostic 	do {
39036559Sbostic 		switch (c = rdc()) {
39136559Sbostic 
39236559Sbostic 		case '\n':
39336559Sbostic 			break;
39436559Sbostic 
39536559Sbostic 		case '<':
39636559Sbostic 			setfile(0, O_RDONLY, 0, p, "open");
39736559Sbostic 			break;
39836559Sbostic 
39936559Sbostic 		case '>':
40036559Sbostic 			setfile(1, O_CREAT|O_WRONLY, 0666, p, "create");
40136559Sbostic 			break;
40236559Sbostic 
40336559Sbostic 		default:
40436559Sbostic 			*ap = p;
40536559Sbostic 			while (index(separators, c) == NULL) {
40636559Sbostic 				*p++ = c;
40736559Sbostic 				c = readchar();
40836559Sbostic 			}
40936559Sbostic 			*p++ = '\0';
41036559Sbostic 			ap++;
41136559Sbostic 		}
41236559Sbostic 	} while (c != '\n');
41336559Sbostic 	unreadc();
41436559Sbostic 	*ap++ = 0;
41536578Storek 	execve(symfile.name, argl, environ);
41636559Sbostic 	perror(symfile.name);
41736559Sbostic }
41836559Sbostic 
41936559Sbostic static int
setfile(fd,flags,mode,namebuf,err)42036559Sbostic setfile(fd, flags, mode, namebuf, err)
42136559Sbostic 	int fd, flags, mode;
42236559Sbostic 	char *namebuf, *err;
42336559Sbostic {
42436559Sbostic 	register char *p = namebuf;
42536559Sbostic 	register int c = rdc();
42636559Sbostic 
42736559Sbostic 	while (index(separators, c) == NULL) {
42836559Sbostic 		*p++ = c;
42936559Sbostic 		c = readchar();
43036559Sbostic 	}
43136559Sbostic 	*p = 0;
43236559Sbostic 	(void) close(fd);
43336559Sbostic 	if (open(namebuf, flags, mode) < 0) {
43436559Sbostic 		adbprintf("%s: cannot %s\n", namebuf, err);
43536559Sbostic 		_exit(0);
43636559Sbostic 		/* NOTREACHED */
43736559Sbostic 	}
43836559Sbostic }
43936559Sbostic 
44036559Sbostic struct bkpt *
scanbkpt(a)44136559Sbostic scanbkpt(a)
44236559Sbostic 	register addr_t a;
44336559Sbostic {
44436559Sbostic 	register struct bkpt *bp;
44536559Sbostic 
44636559Sbostic 	for (bp = bkpthead; bp != NULL; bp = bp->next)
44736559Sbostic 		if (bp->state != BKPT_FREE && bp->loc == a)
44836559Sbostic 			break;
44936559Sbostic 	return (bp);
45036559Sbostic }
45136559Sbostic 
bpwait()45236559Sbostic bpwait()
45336559Sbostic {
45436559Sbostic 	register int w;
45536559Sbostic 	union wait status;
45636559Sbostic 
45736559Sbostic 	(void) signal(SIGINT, SIG_IGN);
45836559Sbostic 	while ((w = wait(&status)) != pid && w != -1)
45936559Sbostic 		 /* void */ ;
46036559Sbostic 	(void) signal(SIGINT, intcatch);
46136559Sbostic 	if (w == -1) {
46236559Sbostic 		pid = 0;
46336559Sbostic 		errflag = BADWAIT;
46436559Sbostic 	} else if (!WIFSTOPPED(status)) {
46536559Sbostic 		sigcode = 0;
46636559Sbostic 		if ((signo = status.w_termsig) != 0)
46736559Sbostic 			sigprint();
46836559Sbostic 		if (status.w_coredump) {
46936559Sbostic 			prints(" - core dumped");
47036559Sbostic 			(void) close(corefile.fd);
47136559Sbostic 			setcore();
47236559Sbostic 		}
47336559Sbostic 		pid = 0;
47436559Sbostic 		bpstate = BPOUT;
47536559Sbostic 		errflag = ENDPCS;
47636559Sbostic 	} else {
47736559Sbostic 		signo = status.w_stopsig;
47836559Sbostic 		sigcode = ptrace(PT_READ_U, pid,
47936559Sbostic 				 &((struct user *)0)->u_code, 0); /* XXX */
48036559Sbostic 		if (signo != SIGTRAP)
48136559Sbostic 			sigprint();
48236559Sbostic 		else
48336559Sbostic 			signo = 0;
48436559Sbostic 		flushbuf();
48536559Sbostic 	}
48636559Sbostic }
487