xref: /csrg-svn/old/adb/common_source/pcs.c (revision 36578)
136559Sbostic #ifndef lint
2*36578Storek static char sccsid[] = "@(#)pcs.c	5.3 (Berkeley) 01/17/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;
45*36578Storek 	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 */
6636559Sbostic 		if ((bp = scanbkpt(dot)) != NULL)
6736559Sbostic 			bp->state = BKPT_FREE;
6836559Sbostic 		else {
6936559Sbostic 			for (bp = bkpthead; bp != NULL; bp = bp->next)
7036559Sbostic 				if (bp->state == BKPT_FREE)
7136559Sbostic 					break;
7236559Sbostic 			if (bp == NULL) {
7336559Sbostic 				bp = (struct bkpt *)malloc(sizeof *bp);
7436559Sbostic 				if (bp == NULL)
7536559Sbostic 					error(EXBKPT);
7636559Sbostic 				bp->next = bkpthead;
7736559Sbostic 				bkpthead = bp;
7836559Sbostic 			}
7936559Sbostic 		}
8036559Sbostic 		bp->loc = dot;
8136559Sbostic 		bp->initcnt = bp->count = ecount;
8236559Sbostic 		bp->state = BKPT_SET;
8336559Sbostic 		check = MAX_BKPTCOM - 1;
8436559Sbostic 		comptr = bp->comm;
8536559Sbostic 		(void) rdc();
8636559Sbostic 		unreadc();
8736559Sbostic 		do {
8836559Sbostic 			*comptr++ = readchar();
8936559Sbostic 		} while (check-- && lastc != '\n');
9036559Sbostic 		*comptr = 0;
9136559Sbostic 		unreadc();
9236559Sbostic 		if (check == 0)
9336559Sbostic 			error(SZBKPT);
9436559Sbostic 		return;
9536559Sbostic 
9636559Sbostic 	case 'k':
9736559Sbostic 	case 'K':
9836559Sbostic 		/* kill process */
9936559Sbostic 		if (pid == 0)
10036559Sbostic 			error(NOPCS);
10136559Sbostic 		adbprintf("%d: killed", pid);
10236559Sbostic 		endpcs();
10336559Sbostic 		return;
10436559Sbostic 
10536559Sbostic 	case 'r':
10636559Sbostic 	case 'R':
10736559Sbostic 		/* run program */
10836559Sbostic 		endpcs();
10936559Sbostic 		setup();
11036559Sbostic 		runcount = ecount;
111*36578Storek 		runmode = CONTINUOUS;
11236559Sbostic 		execsig = 0;
11336559Sbostic 		if (gavedot) {
11436559Sbostic 			if (scanbkpt(dot) == NULL)
11536559Sbostic 				runcount++;
11636559Sbostic 		} else {
11736559Sbostic 			if (scanbkpt(entrypc()) == NULL)
11836559Sbostic 				runcount++;
11936559Sbostic 		}
12036559Sbostic 		break;
12136559Sbostic 
12236559Sbostic 	case 's':
12336559Sbostic 	case 'S':
12436559Sbostic 		/* single step, with optional signal */
12536559Sbostic 		runcount = ecount;
12636559Sbostic 		if (pid) {
12736559Sbostic 			runmode = SINGLESTEP;
12836559Sbostic 			execsig = oexpr() ? expv : signo;
12936559Sbostic 		} else {
13036559Sbostic 			setup();
131*36578Storek 			runmode = SINGLESTEP;
13236559Sbostic 			execsig = 0;
133*36578Storek 			runcount--;
13436559Sbostic 		}
13536559Sbostic 		break;
13636559Sbostic 
13736559Sbostic 	case 'c':
13836559Sbostic 	case 'C':
13936559Sbostic 	case 0:
14036559Sbostic 		/* continue with optional signal */
14136559Sbostic 		runcount = ecount;
14236559Sbostic 		if (pid == 0)
14336559Sbostic 			error(NOPCS);
14436559Sbostic 		runmode = CONTINUOUS;
14536559Sbostic 		execsig = oexpr() ? expv : signo;
14636559Sbostic 		break;
14736559Sbostic 
14836559Sbostic 	default:
14936559Sbostic 		error(BADMOD);
150*36578Storek 		/* NOTREACHED */
15136559Sbostic 	}
15236559Sbostic 
153*36578Storek 	if (runcount > 0 && runpcs(runmode, execsig))
15436559Sbostic 		adbprintf("breakpoint%16t");
15536559Sbostic 	else
15636559Sbostic 		adbprintf("stopped at%16t");
15736559Sbostic 	delbp();
15836559Sbostic 	printpc();
15936559Sbostic }
16036559Sbostic 
16136559Sbostic /*
16236559Sbostic  * Print all breakpoints.
16336559Sbostic  */
16436559Sbostic printbkpts()
16536559Sbostic {
16636559Sbostic 	register struct bkpt *b;
16736559Sbostic 
16836559Sbostic 	adbprintf("breakpoints\ncount%8tbkpt%24tcommand\n");
16936559Sbostic 	for (b = bkpthead; b != NULL; b = b->next) {
17036559Sbostic 		if (b->state != BKPT_FREE) {
17136559Sbostic 			adbprintf("%-8.8D", b->count);
17236559Sbostic 			psymoff("%R", b->loc, SP_INSTR, maxoff, "%24t");
17336559Sbostic 			prints(b->comm);
17436559Sbostic 		}
17536559Sbostic 	}
17636559Sbostic }
17736559Sbostic 
17836559Sbostic /*
17936559Sbostic  * Remove (restore to original instruction(s)) all breakpoints.
18036559Sbostic  */
18136559Sbostic delbp()
18236559Sbostic {
18336559Sbostic 	register struct bkpt *b;
18436559Sbostic 
18536559Sbostic 	if (bpstate != BPOUT) {
18636559Sbostic 		for (b = bkpthead; b != NULL; b = b->next)
18736559Sbostic 			if (b->state != BKPT_FREE && clr_bpt(b))
18836559Sbostic 				bperr(b, "clear");
18936559Sbostic 		bpstate = BPOUT;
19036559Sbostic 	}
19136559Sbostic }
19236559Sbostic 
19336559Sbostic /*
19436559Sbostic  * Insert all breakpoints.
19536559Sbostic  */
19636559Sbostic setbp()
19736559Sbostic {
19836559Sbostic 	register struct bkpt *b;
19936559Sbostic 
20036559Sbostic 	if (bpstate != BPIN) {
20136559Sbostic 		for (b = bkpthead; b != NULL; b = b->next)
20236559Sbostic 			if (b->state != BKPT_FREE && set_bpt(b))
20336559Sbostic 				bperr(b, "set");
20436559Sbostic 		bpstate = BPIN;
20536559Sbostic 	}
20636559Sbostic }
20736559Sbostic 
20836559Sbostic static
20936559Sbostic bperr(b, how)
21036559Sbostic 	struct bkpt *b;
21136559Sbostic 	char *how;
21236559Sbostic {
21336559Sbostic 
21436559Sbostic 	adbprintf("cannot %s breakpoint: ", how);
21536559Sbostic 	psymoff("%R", b->loc, SP_INSTR, maxoff, "\n");
21636559Sbostic }
21736559Sbostic 
21836559Sbostic /*
21936559Sbostic  * ... return true iff stopped due to breakpoint
22036559Sbostic  */
22136559Sbostic int
222*36578Storek runpcs(runmode, execsig)
223*36578Storek 	int runmode, execsig;
22436559Sbostic {
22536559Sbostic 	register struct bkpt *bkpt;
22636559Sbostic 	int rc;
22736559Sbostic 
22836559Sbostic 	/* always set pc, so that expr>pc works too */
229*36578Storek 	setpc(gavedot ? dot : getpc());
23036559Sbostic 	adbprintf("%s: running\n", symfile.name);
23136559Sbostic 	while (--runcount >= 0) {
23236559Sbostic 		/* BEGIN XXX (machine dependent?, delete ptrace, etc) */
23336559Sbostic 		if (runmode == SINGLESTEP)
23436559Sbostic 			delbp();	/* hardware handles single-stepping */
23536559Sbostic 		else {	/* continuing from a breakpoint is hard */
236*36578Storek 			if ((bkpt = scanbkpt(getpc())) != NULL) {
23736559Sbostic 				execbkpt(bkpt, execsig);
23836559Sbostic 				execsig = 0;
23936559Sbostic 			}
24036559Sbostic 			setbp();
24136559Sbostic 		}
24236559Sbostic 		(void) ptrace(runmode == CONTINUOUS ? PT_CONTINUE : PT_STEP,
243*36578Storek 			pid, (int *)getpc(), execsig);
24436559Sbostic 		/* END XXX */
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 
31836559Sbostic 	(void) close(symfile.fd);
31936559Sbostic 	symfile.fd = -1;
32036559Sbostic #ifndef VFORK
32136559Sbostic #define vfork fork
32236559Sbostic #endif
32336559Sbostic 	if ((pid = vfork()) == 0) {
32436559Sbostic 		(void) ptrace(PT_TRACE_ME, 0, (int *)0, 0);	/* XXX */
32536559Sbostic #ifdef VFORK
32636559Sbostic 		(void) signal(SIGTRAP, nullsig);
32736559Sbostic #endif
32836559Sbostic 		(void) signal(SIGINT, sigint);
32936559Sbostic 		(void) signal(SIGQUIT, sigquit);
33036559Sbostic 		doexec();
33136559Sbostic 		exit(0);
33236559Sbostic 	} else if (pid == -1)
33336559Sbostic 		error(NOFORK);
33436559Sbostic 	else {
33536559Sbostic 		bpwait();
33636559Sbostic 		readregs();
33736559Sbostic 		symfile.fd = open(symfile.name, wtflag);
33836559Sbostic 		if (errflag) {
33936559Sbostic 			adbprintf("%s: cannot execute\n", symfile.name);
34036559Sbostic 			endpcs();
34136559Sbostic 			error((char *)0);
34236559Sbostic 		}
34336559Sbostic 	}
34436559Sbostic 	bpstate = BPOUT;
34536559Sbostic }
34636559Sbostic 
34736559Sbostic execbkpt(bp, execsig)
34836559Sbostic 	struct bkpt *bp;
34936559Sbostic 	int execsig;
35036559Sbostic {
35136559Sbostic 
35236559Sbostic #ifdef DEBUG
35336559Sbostic 	adbprintf("exbkpt: %d\n", bp->count);
35436559Sbostic #endif
35536559Sbostic 	delbp();
35636559Sbostic 	(void) ptrace(PT_STEP, pid, (int *)bp->loc, execsig);	/* XXX */
35736559Sbostic 	bp->state = BKPT_SET;
35836559Sbostic 	bpwait();
35936559Sbostic 	checkerr();
36036559Sbostic 	readregs();
36136559Sbostic }
36236559Sbostic 
36336559Sbostic static char separators[] = "<> \t\n";
36436559Sbostic 
36536559Sbostic doexec()
36636559Sbostic {
36736559Sbostic 	register char *p, **ap;
36836559Sbostic 	register int c;
36936559Sbostic 	char *argl[LINELEN / 2 + 1];
37036559Sbostic 	char args[LINELEN];
37136559Sbostic 	extern char **environ;
37236559Sbostic 	char *index();
37336559Sbostic 
37436559Sbostic 	ap = argl;
37536559Sbostic 	p = args;
37636559Sbostic 	*ap++ = symfile.name;
37736559Sbostic 	do {
37836559Sbostic 		switch (c = rdc()) {
37936559Sbostic 
38036559Sbostic 		case '\n':
38136559Sbostic 			break;
38236559Sbostic 
38336559Sbostic 		case '<':
38436559Sbostic 			setfile(0, O_RDONLY, 0, p, "open");
38536559Sbostic 			break;
38636559Sbostic 
38736559Sbostic 		case '>':
38836559Sbostic 			setfile(1, O_CREAT|O_WRONLY, 0666, p, "create");
38936559Sbostic 			break;
39036559Sbostic 
39136559Sbostic 		default:
39236559Sbostic 			*ap = p;
39336559Sbostic 			while (index(separators, c) == NULL) {
39436559Sbostic 				*p++ = c;
39536559Sbostic 				c = readchar();
39636559Sbostic 			}
39736559Sbostic 			*p++ = '\0';
39836559Sbostic 			ap++;
39936559Sbostic 		}
40036559Sbostic 	} while (c != '\n');
40136559Sbostic 	unreadc();
40236559Sbostic 	*ap++ = 0;
403*36578Storek 	execve(symfile.name, argl, environ);
40436559Sbostic 	perror(symfile.name);
40536559Sbostic }
40636559Sbostic 
40736559Sbostic static int
40836559Sbostic setfile(fd, flags, mode, namebuf, err)
40936559Sbostic 	int fd, flags, mode;
41036559Sbostic 	char *namebuf, *err;
41136559Sbostic {
41236559Sbostic 	register char *p = namebuf;
41336559Sbostic 	register int c = rdc();
41436559Sbostic 
41536559Sbostic 	while (index(separators, c) == NULL) {
41636559Sbostic 		*p++ = c;
41736559Sbostic 		c = readchar();
41836559Sbostic 	}
41936559Sbostic 	*p = 0;
42036559Sbostic 	(void) close(fd);
42136559Sbostic 	if (open(namebuf, flags, mode) < 0) {
42236559Sbostic 		adbprintf("%s: cannot %s\n", namebuf, err);
42336559Sbostic 		_exit(0);
42436559Sbostic 		/* NOTREACHED */
42536559Sbostic 	}
42636559Sbostic }
42736559Sbostic 
42836559Sbostic struct bkpt *
42936559Sbostic scanbkpt(a)
43036559Sbostic 	register addr_t a;
43136559Sbostic {
43236559Sbostic 	register struct bkpt *bp;
43336559Sbostic 
43436559Sbostic 	for (bp = bkpthead; bp != NULL; bp = bp->next)
43536559Sbostic 		if (bp->state != BKPT_FREE && bp->loc == a)
43636559Sbostic 			break;
43736559Sbostic 	return (bp);
43836559Sbostic }
43936559Sbostic 
44036559Sbostic bpwait()
44136559Sbostic {
44236559Sbostic 	register int w;
44336559Sbostic 	union wait status;
44436559Sbostic 
44536559Sbostic 	(void) signal(SIGINT, SIG_IGN);
44636559Sbostic 	while ((w = wait(&status)) != pid && w != -1)
44736559Sbostic 		 /* void */ ;
44836559Sbostic 	(void) signal(SIGINT, intcatch);
44936559Sbostic 	if (w == -1) {
45036559Sbostic 		pid = 0;
45136559Sbostic 		errflag = BADWAIT;
45236559Sbostic 	} else if (!WIFSTOPPED(status)) {
45336559Sbostic 		sigcode = 0;
45436559Sbostic 		if ((signo = status.w_termsig) != 0)
45536559Sbostic 			sigprint();
45636559Sbostic 		if (status.w_coredump) {
45736559Sbostic 			prints(" - core dumped");
45836559Sbostic 			(void) close(corefile.fd);
45936559Sbostic 			setcore();
46036559Sbostic 		}
46136559Sbostic 		pid = 0;
46236559Sbostic 		bpstate = BPOUT;
46336559Sbostic 		errflag = ENDPCS;
46436559Sbostic 	} else {
46536559Sbostic 		signo = status.w_stopsig;
46636559Sbostic 		sigcode = ptrace(PT_READ_U, pid,
46736559Sbostic 				 &((struct user *)0)->u_code, 0); /* XXX */
46836559Sbostic 		if (signo != SIGTRAP)
46936559Sbostic 			sigprint();
47036559Sbostic 		else
47136559Sbostic 			signo = 0;
47236559Sbostic 		flushbuf();
47336559Sbostic 	}
47436559Sbostic }
475