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