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