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