bds@lzaz.ATT.COM (B.SZABLAK) (12/22/88)
/* * mdb.c - MINIX program debugger * * Written by Bruce D. Szablak * * This free software is provided for non-commerical use. No warrantee * of fitness for any use is implied. You get what you pay for. Anyone * may make modifications and distribute them, but please keep this header * in the distribution. */ #define T_OK 0 #define T_GETINS 1 #define T_GETDATA 2 #define T_GETUSER 3 #define T_SETINS 4 #define T_SETDATA 5 #define T_SETUSER 6 #define T_RESUME 7 #define T_EXIT 8 #define T_STEP 9 #include "stdio.h" #include "signal.h" #include "ctype.h" #include "setjmp.h" #include "user.h" struct proc *prc; #define BP_REG 14 #define MAXLINE 120 #define REG(r) ((long)&((struct proc *)0)->p_reg[r]) #define PC ((long)&((struct proc *)0)->p_pcpsw.pc) #define MAXB 10 #define MAXP 3 #define MAXARG 20 #define SIZ (1 + sizeof(struct proc)/sizeof(long)) #define MAXLINE 120 long ptrace(), strtol(), reg_addr(), lbuf[SIZ], saddr, eaddr, dasm(); int curpid, cursig; char *strcpy(), *prog, sbuf[MAXLINE], cbuf[MAXLINE], *cmd, *addr_to_name(), *getexp(), *cmdstart; jmp_buf mainlp; extern errno; struct b_pnt { struct b_pnt *nxt, *prv; long addr; long oldval; char cmd[1]; } *b_head, *curpnt; cleanup() { curpid = 0; curpnt = 0; while (b_head) freepnt(b_head); } dowait() { int stat, ls, hs; while (wait(&stat) != curpid) {}; ls = stat & 0xFF; hs = (stat >> 8) & 0xFF; if (ls == 0) { if (hs != 127) printf("child exited with status %d\n", hs); cleanup(); return 0; } if (hs == 0) { printf("child terminated by signal %d\n", ls & 0x7F); if (ls & 0x80) printf("(core dumped)\n"); cleanup(); return 0; } return cursig = hs; } update() { int i; for (i = 0; i < (SIZ-1); i++) { lbuf[i] = ptrace(T_GETUSER, curpid, (long)(i*sizeof(long)),0L); } saddr = (long)prc->p_map[T].mem_vir << CLICK_SHIFT; eaddr = (long)(prc->p_map[D].mem_vir + prc->p_map[D].mem_len) << CLICK_SHIFT; } findbpnt(verbose) { for (curpnt = b_head; curpnt; curpnt = curpnt->nxt) { if (curpnt->addr == prc->p_pcpsw.pc) { ptrace(T_SETINS, curpid, curpnt->addr, curpnt->oldval); if (curpnt->cmd[0] != '\n') cmd = strcpy(cbuf, curpnt->cmd); else if (verbose) printf("Breakpoint hit.\n"); return; } } if (verbose) printf("Unknown breakpoint hit.\n"); } disp_regs() { int i; if (curpid <= 0) { printf("No active process.\n"); return 1; } printf("\npc=%lx psw=%x\n\n",(long)prc->p_pcpsw.pc, prc->p_pcpsw.psw); printf( " 0 1 2 3 4 5 6 7\nD"); for (i = 0; i < 8; i++) printf(" %08lx", prc->p_reg[i]); printf("\nA"); for (; i < NR_REGS; i++) printf(" %08lx", prc->p_reg[i]); printf(" %08lx\n\n", (long)prc->p_sp); return 0; } char * skip(s) register char *s; { while (isspace(*s)) ++s; return *s ? s : s-1; } endcmd() { while (*cmd != '\n' && *cmd != ';') ++cmd; } #define BREAK(l) (0xA0000000 | ((l) & 0xFFFF)) exebpnt(restart) { ptrace(T_STEP, curpid, 0L, (long)restart); if (dowait() == 0) return 1; ptrace(T_SETINS, curpid, curpnt->addr, BREAK(curpnt->oldval)); curpnt = 0; return 0; } tstart(req, verbose, val, cnt) { if (curpid == 0) { if (verbose) printf("No active process.\n"); return; } if (req == T_EXIT) { ptrace(T_EXIT, curpid, 0L, (long)val); dowait(); return; } if (cnt==0) cnt = 1; do { if (curpnt) { if (exebpnt(val)) return; if (req == T_RESUME) cnt++; val = 0; } else { ptrace(req, curpid, 0L, (long)val); if (dowait() == 0) return; val = 0; switch (cursig) { case SIGEMT: /* breakpoint */ update(); findbpnt(cnt <= 1); break; case SIGTRAP: /* trace trap? */ if (req == T_STEP) break; default: /* signal */ val = cursig; break; } } } while (--cnt > 0); update(); dasm((long)prc->p_pcpsw.pc, 1, 1); } catch(sig) { signal(sig, catch); if (sig == SIGINT || sig == SIGQUIT) return; tstart(T_EXIT, 0, sig, 0); exit(0); } run(name, argstr, tflg) char *name, *argstr; { int procid; if( (procid = fork()) == 0 ) { char *argv[MAXARG], *inf = 0, *outf = 0; int argc; if (tflg && ptrace(T_OK, 0, 0L, 0L) < 0) { perror("ptrace"); exit(127); } argv[0] = name; for (argc = 1; ; ) { argstr = skip(argstr); if (*argstr == '\n' || *argstr == ';') { argv[argc] = 0; if (inf) freopen(inf, "r", stdin); if (outf) freopen(outf, "w", stdout); execv(name, argv); perror("execv"); exit( 127 ); } if (*argstr == '<') inf = argstr+1; else if (*argstr == '>') outf = argstr+1; else if (argc == MAXARG) { printf("Too many arguments.\n"); exit(127); } else argv[argc++] = argstr; while (!isspace(*argstr)) argstr++; if (*argstr == '\n') argstr[1] = '\n', argstr[2] = 0; *argstr++ = 0; } } if (procid < 0) { printf("Fork failed.\n"); } return procid; } #define ADDQ(l) (((l >> 16) & 0xF1FF) == 0x508F) #define ADDQ_CNT(l) ((((l >> 25) - 1) & 7) + 1) #define LEA(l) ((l >> 16) == 0x4FEF) #define LEA_DISP(l) ((long)(int)l) #define ADDA(l) ((int)(l >> 16) == 0xDFFC) backtrace(all) { char sep; long pc, bp, off, val, obp; if (curpid <= 0) { printf("No process.\n"); return; } pc = prc->p_pcpsw.pc; bp = prc->p_reg[BP_REG]; if (bp == 0) { printf("No active frame.\n"); return; } errno = 0; do { symbolic(pc, '('); pc = ptrace(T_GETDATA, curpid, bp+4, 0L); off = ptrace(T_GETDATA, curpid, pc, 0L); obp = bp; bp += 2*sizeof(val); if (ADDQ(off)) off = ADDQ_CNT(off) + bp; else if (LEA(off)) off = LEA_DISP(off) + bp; else if (ADDA(off)) off = ptrace(T_GETDATA, curpid, pc+2, 0L) + bp; else goto skiplp; for (;;) { if (errno) return; val = ptrace(T_GETDATA, curpid, bp, 0L) >> 16; printf("0x%04x", (int)val); bp += sizeof(int); if (bp >= off) break; putc(',', stdout); } skiplp: fputs(")\n", stdout); bp = ptrace(T_GETDATA, curpid, obp, 0L); } while (all && bp); } freepnt(pnt) struct b_pnt *pnt; { if (pnt->prv) pnt->prv->nxt = pnt->nxt; else b_head = pnt->nxt; if (pnt->nxt) pnt->nxt->prv = pnt->prv; if (curpid > 0) ptrace(T_SETINS, curpid, pnt->addr, pnt->oldval); free(pnt); if (pnt == curpnt) curpnt = 0; } breakpt(addr, cmd) long addr; char *cmd; { char *s; struct b_pnt *new, *malloc(); int lng; if (curpid <= 0) { printf("No active process.\n"); return; } for (new = b_head; new; new=new->nxt) if (new->addr == addr) { printf("Breakpoint already exists here.\n"); return; } new = malloc(sizeof(struct b_pnt) + strlen(cmd)); if (new == 0) { printf("No room.\n"); return; } new->nxt = b_head; new->prv = 0; if (b_head) b_head->prv = new; b_head = new; new->addr = addr; strcpy(new->cmd, cmd); new->oldval = ptrace(T_GETINS, curpid, addr, 0L); ptrace(T_SETINS, curpid, addr, BREAK(new->oldval)); if (ptrace(T_GETINS, curpid, addr, 0L) != BREAK(new->oldval)) { perror("Can't set breakpoint"); freepnt(new); } } modify(addr, cnt, verbose) long addr; { long curval, off; if (curpid == 0) { printf("No active process.\n"); return; } curval = ptrace(T_GETDATA, curpid, addr, 0L); do { if (cursig == SIGTRAP) cursig = 0; if (verbose) { off = ptrace(T_GETUSER, curpid, PC, 0L); dasm(off, 1, 0); } if (curpnt && exebpnt(cursig)) return; else { ptrace(T_STEP, curpid, addr, 0L); switch (dowait()) { case 0: return; case SIGEMT: update(); findbpnt(0); break; } } if (curval != ptrace(T_GETDATA, curpid, addr, 0L)) { printf("Modification detected\n"); break; } } while (--cnt); update(); dasm(prc->p_pcpsw.pc, 1, 1); return; } display(addr, req) long addr; { int count, size, out, shift; long val, msk; char fmt; if (curpid == 0) { printf("No active process\n"); return; } count = strtol(cmd, &cmd, 0); if (count == 0) count = 1; if (*cmd == 'i' || *cmd == 'I') { if (req == T_GETUSER) { printf("Can't disassemble a register's contents.\n"); longjmp(mainlp); } dasm(addr, count, *cmd == 'i'); return; } switch (*cmd++) { case 'b': size = sizeof(char); break; case 'h': size = sizeof(short); break; case 'l': size = sizeof(long); break; default : size = sizeof(int); --cmd; break; } switch (fmt = *cmd) { case 'c': count *= size; size = sizeof(char); break; case 's': addr = ptrace(req, curpid, addr, 0L); req = T_GETDATA; case 'a': size = sizeof(char); break; } out = 0; msk = size == sizeof(long) ? 0xFFFFFFFF : (1L << (8*size)) - 1; shift = 32 - 8*size; do { val = (ptrace(req, curpid, addr, 0L) >> shift) & msk; if (out == 0) printf("\n0x%08lx: ", addr); switch (fmt) { case 'c': printf(isprint(val) ? " %c " : "\\%03o ", (char)val); if (++out == 8) out = 0; break; case 'u': printf("%12lu ", val); if (++out == 4) out = 0; break; case 'x': printf("%*lx ", 2*size, val); if (++out == (size == 4 ? 4 : 8)) out = 0; break; case 'o': printf("%*lo ", 3*size, val); if (++out == (size == 4 ? 4 : 8)) out = 0; break; case 's': case 'a': if (val) fputc((char)val, stdout); else goto exitlp; if (++out == 64) out = 0; break; default: case 'd': printf("%12ld ", val); if (++out == 4) out = 0; break; } addr += size; } while (--count > 0 || fmt == 's' || fmt == 'a'); exitlp: fputc('\n', stdout); } fill(addr, req) long addr; { int count, size, shift, seg; long val, msk, nval; char fmt; if (curpid == 0) { printf("No active process\n"); return; } count = strtol(cmd, &cmd, 0); switch (*cmd++) { case 'b': size = sizeof(char); break; case 'h': size = sizeof(short); break; case 'l': size = sizeof(long); break; default : size = sizeof(int); --cmd; break; } shift = 32 - 8*size; msk = (0x80000000 >> 8*size); cmd = getexp(cmd, &nval, &seg); nval <<= shift; do { val = ptrace(req, curpid, addr, 0L) | (nval & msk); val &= (nval | ~msk); ptrace(req+3, curpid, addr, val); addr += size; } while (--count>0); } command(savestr) char *savestr; { char c, *p; int i, seg; long exp; struct b_pnt *bp; seg = S; /* don't restrict segment expressions are in */ cmdstart = cmd = skip(cmd); cmd = getexp(cmd, &exp, &seg); if (exp == 0) { seg = T; exp = prc->p_pcpsw.pc; } switch (c = *cmd++) { case '!': /* escape to shell OR set variable to value */ if (cmd == cmdstart+1) { cmd = skip(cmd); if (*cmd == '\n' || *cmd == ';') { i = run("/bin/sh", "\n", 0); } else { for (p=cmd+1; *p && !isspace(*p); p++) {}; *p++ = 0; i = run(cmd, *p ? p : "\n", 0); } if (i > 0) while (wait(&seg) != i) {}; break; } if (seg == 'T') { printf("Can only modify data variables.\n"); break; } fill(exp, T_GETDATA); break; case 'T': /* top line of backtrace */ backtrace(0); break; case 't': /* back trace */ backtrace(1); break; case '/': /* print variable value */ display(exp, T_GETDATA); break; case 'x': /* print registers and instruction */ if (disp_regs()) break; /*FALLTHROUGH*/ case 'X': /* print instruction */ i = strtol(cmd, &cmd, 0); if (curpid > 0) dasm(exp, i ? i : 1, 1); else printf("No active process.\n"); break; case 'R': /* run program with no args */ case 'r': /* run program with args (possibly defaulted) */ tstart(T_EXIT, 0, 0, 0); if (c == 'r') { cmd = skip(cmd); if (*cmd == '\n' || *cmd == ';') cmd = sbuf; else strcpy(sbuf, cmd); } else { cmd = "\n"; } if (curpid = run(prog, cmd, 1)) { if (dowait()) { ptrace(T_SETUSER, curpid, REG(BP_REG), 0L); update(); printf("Process stopped.\n"); } } break; case 'c': /* continue program - ignore signal */ cursig = 0; case 'C': /* continue program - handle signal */ i = 0; if (seg == T && curpnt == 0 && cmd != cmdstart+1) { breakpt(exp, "\n"); curpnt = b_head; ptrace(T_SETINS, curpid, curpnt->addr, curpnt->oldval); i = 1; } tstart(T_RESUME, 1, cursig, (int)strtol(cmd, &cmd, 0)); if (i) /* remove temporary bp */ { freepnt(b_head); } if (cursig == SIGEMT) return; if (curpid) printf("Process stopped by signal %d\n", cursig); break; case 'i': /* single step - ignore signal */ tstart(T_STEP, 1, 0, (int)strtol(cmd, &cmd, 0)); break; case 'I': /* single step - handle signal */ tstart(T_STEP, 1, cursig, (int)strtol(cmd, &cmd, 0)); break; case 'm': /* single step until location modified */ case 'M': /* single step until location modified - verbose */ modify(exp, (int)strtol(cmd, &cmd, 0), c == 'M'); break; case 'k': /* kill current program */ tstart(T_EXIT, 1, 0, 0); break; case 'b': /* set a breakpoint at the given line */ if (seg == D) { printf("Address not in text space.\n"); return; } breakpt(exp, skip(cmd)); cmd = "\n"; return; case 'B': /* print list of currently active breakpoints */ for (i = 1, bp = b_head; bp; bp=bp->nxt, i++) { p = addr_to_name(bp->addr - saddr, &exp); printf("%2d: %s+0x%lx (0x%lx) - %s", i, p, exp, bp->addr, bp->cmd); } break; case 'd': /* delete breakpoint */ if (seg == T) { for (bp = b_head; bp && --exp; bp=bp->nxt) {}; if (bp) { freepnt(bp); break; } } printf("No such breakpoint.\n"); break; case 'D': /* delete all breakpoints */ while(b_head) freepnt(b_head); break; case 'q': /* quit */ tstart(T_EXIT, 0, 0, 0L, 0); exit(0); case '\n': case ';': if (isdigit(*cmdstart)) symbolic(exp, '\n'); else printf("0x%lx\n", exp); --cmd; break; case '$': cmdstart = cmd; cmd = skip(cmd+2); if (*cmd == '!') { cmd++; fill(reg_addr(cmdstart), T_GETUSER); break; } if (*skip(cmd+2) == '/') { cmd++; display(reg_addr(cmdstart), T_GETUSER); break; } /*FALLTHROUGH*/ default: printf("Unknown command.\n"); break; } while (*cmd != '\n' && *cmd != ';') ++cmd; if (*cmd == ';') cmd = skip(cmd+1); } main(argc, argv) char *argv[]; { int i; prc = lbuf; for (i = 1; i < NSIG; i++) signal(i, catch); strcpy(sbuf, "\n"); prog = argc > 1 ? argv[1] : "a.out"; if (argc > 2) getsyms(argv[2]); setjmp(&mainlp); while ((printf("* "), fflush(stdout), fgets(cbuf, sizeof(cbuf), stdin)) != EOF) { if (strlen(cbuf) == sizeof(cbuf)-1) { printf("Command line too long.\n"); continue; } cmd = cbuf; command(); while (*cmd != '\n') command(); } tstart(T_EXIT, 0, 0, 0); exit(0); }
bds@lzaz.ATT.COM (B.SZABLAK) (12/22/88)
/* * dbexp.c - MINIX expresion parser * * Written by Bruce D. Szablak * * This free software is provided for non-commerical use. No warrantee * of fitness for any use is implied. You get what you pay for. Anyone * may make modifications and distribute them, but please keep this header * in the distribution. NOTE: A PORTION OF THIS FILE IS DERIVED FROM THE * SOURCE TO ANM.C. BEWARE THAT OTHER RESTRICTIONS MAY APPLY. */ #include <ctype.h> #include <setjmp.h> #include <stdio.h> #include "user.h" #include "out.h" extern jmp_buf mainlp; extern curpid; int nsyms; struct outname *nbufp = NULL; long value(), strtol(), lookup(), ptrace(); #define idchar(c) (isalpha(c) || isdigit(c) || (c) == '_') char * addr_to_name(rel_addr, off_p) long rel_addr, *off_p; { register int i, l = 0, r = nsyms; do { i = (l + r) >> 1; if (rel_addr < nbufp[i].on_valu) r = i; else if (rel_addr > nbufp[i].on_valu) l = i + 1; else break; } while (l < r); if (l == nsyms || r == 0) { *off_p = rel_addr; return "_start"; } if (rel_addr < nbufp[i].on_valu) i--; *off_p = rel_addr - nbufp[i].on_valu; return nbufp[i].on_mptr; } symbolic(addr, sep) long addr; char sep; { long off; extern long saddr, eaddr; if (addr < saddr || addr > eaddr) { printf("0x%lx%c", addr, sep); return; } fputs(addr_to_name(addr - saddr, &off), stdout); if (off) printf("+0x%lx", off); fputc(sep, stdout); } char * getexp(buf, exp_p, seg_p) char *buf; int *seg_p; long *exp_p; { extern char *skip(); long v = 0L; buf = skip(buf); if ((isalpha(*buf) && (isspace(buf[1]) || buf[1]==';')) || *buf=='\n' || *buf==';' || *buf=='/' || *buf == '!') { *exp_p = 0L; return buf; } v = value(buf, &buf, seg_p); buf = skip(buf); if (*buf == '+') { v += value(skip(buf+1), &buf, seg_p); } else if (*buf == '-') { v -= value(skip(buf+1), &buf, seg_p); } *exp_p = v; return skip(buf); } long reg_addr(s) char *s; { long val; switch (*s++) { case 'a': case 'A': val = 32; break; case 'd': case 'D': val = 0; break; default: goto error; } if (*s >= '0' && *s <= '7') { return val + 4*(*s - '0'); } error: printf("Unknown register: %2.2s\n", s); longjmp(mainlp); } long value(s, s_p, seg_p) char *s, **s_p; int *seg_p; { long k; if (*s == '\'') /* handle character constants here */ { *s_p = s + 2; return s[1]; } if (*s == '-' || isdigit(*s)) { return strtol(s, s_p, 0); } if (*s == '$') { k = reg_addr(s+1); *s_p = s + 3; return ptrace(3, curpid, k, 0L); } return lookup(s, s_p, seg_p); } long lookup(s, s_p, seg_p) char *s, **s_p; int *seg_p; { extern long saddr; char c; int i, l; for (l = 1; idchar(s[l]); ++l ) {} c = s[l]; s[l] = 0; if (strcmp("_start", s) == 0) { *seg_p = T; *(*s_p = s + 6) = c; return saddr; } for (i = 0; i < nsyms; i++) if (strcmp(nbufp[i].on_mptr, s) == 0) { *seg_p = (nbufp[i].on_type & S_TYP) == S_MIN ? T : D; *(*s_p = s + l) = c; return nbufp[i].on_valu + saddr; } printf("%s: symbol not found\n", s); longjmp(mainlp); } /******************END OF ORIGINAL CODE***********************/ /* * The following code is actually a highly edited * version of anm.c - The ACK version of nm * That file's header follows: */ /* @(#)anm.c 1.6 */ /* ** print symbol tables for ** ACK object files ** ** anm [-gopruns] [name ...] */ #define ushort unsigned short #define ushort unsigned short long off; char *malloc(); char *realloc(); long s_base[S_MAX]; /* for specially encoded bases */ getsyms(file) char *file; { int compare(); FILE *fi; struct outsect sbuf; struct outhead hbuf; struct outname nbuf; char *cbufp; long fi_to_co; long n; unsigned readcount; int j; fi = fopen(file,"r"); if (fi == NULL) { fprintf(stderr, "db: cannot open %s\n", file); return; } getofmt((char *)&hbuf, SF_HEAD, fi); if (BADMAGIC(hbuf)) { fprintf(stderr, "db: %s-- bad format\n", file); fclose(fi); return; } n = hbuf.oh_nname; if (n == 0) { fprintf(stderr, "db: %s-- no name list\n", file); fclose(fi); return; } if (hbuf.oh_nchar == 0) { fprintf(stderr, "db: %s-- no names\n", file); fclose(fi); return; } if ((readcount = hbuf.oh_nchar) != hbuf.oh_nchar) { fprintf(stderr, "db: string area too big in %s\n", file); exit(2); } /* store special section bases */ if (hbuf.oh_flags & HF_8086) { int i; for (i=0; i<hbuf.oh_nsect; i++) { getofmt((char *)&sbuf, SF_SECT, fi); s_base[i+S_MIN] = (sbuf.os_base>>12) & 03777760; } } if ((cbufp = (char *)malloc(readcount)) == NULL) { fprintf(stderr, "db: out of memory on %s\n", file); exit(2); } fseek(fi, OFF_CHAR(hbuf), 0); if (fread(cbufp, 1, readcount, fi) == 0) { fprintf(stderr, "db: read error on %s\n", file); exit(2); } fi_to_co = (long)cbufp - OFF_CHAR(hbuf); fseek(fi, OFF_NAME(hbuf), 0); nsyms = 0; while (--n >= 0) { getofmt((char *)&nbuf, SF_NAME, fi); if (nbuf.on_foff == 0) continue; /* skip entries without names */ if ((nbuf.on_type&S_EXT)==0) continue; nbuf.on_mptr = (char *)(nbuf.on_foff + fi_to_co); /* adjust value for specially encoded bases */ if (hbuf.oh_flags & HF_8086) { if (((nbuf.on_type&S_ETC) == 0) || ((nbuf.on_type&S_ETC) == S_SCT)) { j = nbuf.on_type&S_TYP; if ((j>=S_MIN) && (j<=S_MAX)) nbuf.on_valu += s_base[j]; } } if (nbufp == NULL) nbufp = (struct outname *)malloc(sizeof(struct outname)); else nbufp = (struct outname *)realloc(nbufp, (nsyms+1)*sizeof(struct outname)); if (nbufp == NULL) { fprintf(stderr, "db: out of memory on %s\n", file); exit(2); } nbufp[nsyms++] = nbuf; } qsort(nbufp, nsyms, sizeof(struct outname), compare); fclose(fi); } compare(p1, p2) struct outname *p1, *p2; { if (p1->on_valu < p2->on_valu) return -1; if (p1->on_valu > p2->on_valu) return 1; return 0; } getofmt(p, s, f) register char *p; register char *s; register FILE *f; { register i; register long l; for (;;) { switch (*s++) { /* case '0': p++; continue; */ case '1': *p++ = getc(f); continue; case '2': i = getc(f); i |= (getc(f) << 8); *((short *)p) = i; p += sizeof(short); continue; case '4': l = (long)getc(f); l |= ((long)getc(f) << 8); l |= ((long)getc(f) << 16); l |= ((long)getc(f) << 24); *((long *)p) = l; p += sizeof(long); continue; default: case '\0': break; } break; } }
bds@lzaz.ATT.COM (B.SZABLAK) (12/22/88)
/* * mdbdis.c - MINIX program disassembler for the debugger * * Written by Bruce D. Szablak * * This free software is provided for non-commerical use. No warrantee * of fitness for any use is implied. You get what you pay for. Anyone * may make modifications and distribute them, but please keep this header * in the distribution. */ #include <stdio.h> #define BYTE 0 #define WORD 1 #define LONG 2 #define BFIELD(w,b,l) (((w) >> ((b)-(l)+1)) & (int)((1L<<(l))-1)) #define BTST(w,b) ((w) & (1 << (b))) char opwfmt[] = "%s.%c\t"; #define OPI(s,w) printf(opwfmt, s, w) char size[] = "bwl"; char *cc[] = {"ra", "f", "hi", "ls", "cc", "cs", "ne", "eq", "vc", "vs", "pl", "mi", "ge", "lt", "gt", "le" }; char *bitop[] = { "btst", "bchg", "bclr", "bset" }; char *imedop[] = { "ori", "andi", "subi", "addi", "?", "eori", "cmpi" }; char *misc1[] = { "negx", "clr", "neg", "not" }; char *misc2[] = { "reset", "nop", "stop", "rte", "??", "rts", "trapv", "rtr" }; char *shf[] = { "as", "ls", "rox", "ro" }; char *fmts[] = { "d%d", "a%d", "(a%d)", "(a%d)+", "-(a%d)" }; extern curpid; extern char *addr_to_name(); extern long saddr, eaddr; long gaddr, gbuf, ptrace(); int gempty, gisize, gjmp; short gword() { if (gempty) { gempty = 0; gbuf = ptrace(1, curpid, gaddr, 0L); gaddr += 2; return gbuf >> 16; } gempty = 1; gaddr += 2; return gbuf; } long glong() { gempty = 1; gbuf = ptrace(1, curpid, gaddr, 0L); gaddr += 4; return gbuf; } reladdr(sep) char sep; { int d = gword(); symbolic(gaddr + d - 2, sep); } movem(from, predec, rmsk) { int b, f = 0; if (!from) putc(',', stdout); for (b = 16; b--; rmsk >>= 1) { if (rmsk & 1) { if (f) putc('/', stdout); else f = 1; if (predec) printf("%c%d", b>7 ? 'a' : 'd', b % 8); else printf("%c%d", b>7 ? 'd' : 'a', 7 - b % 8); } } if (from) putc(',', stdout); } op1(mode,reg) { int d; char *s; long l; if (mode < 5) { printf(fmts[mode], reg); return; } if (mode == 5) { printf("%d(a%d)", gword(), reg); return; } if (mode == 6) { d = gword(); printf("%d(a%d,%c%d.%c)", BFIELD(d,7,8) | (BTST(d,7) ? 0xFF00 : 0), reg, BTST(d,15) ? 'a' : 'd', BFIELD(d,14,3), BTST(d,11) ? 'l' : 'w'); return; } switch (reg) { case 0: printf("%d", gword()); break; case 1: symbolic(glong(), '\0'); break; case 2: l = gaddr; printf("%d(pc) {", d = gword()); symbolic(l+d, '}'); break; case 3: d = gword(); printf("%d(pc,%c%d.%c)", BFIELD(d,7,8) | (BTST(d,7) ? 0xFF00 : 0), BTST(d,15) ? 'a' : 'd', BFIELD(d,14,3), BTST(d,11) ? 'l' : 'w'); break; case 4: putc('#', stdout); if (gisize == LONG) symbolic(glong(), '\0'); else if (gisize == BYTE) printf("%d", (char)gword()); else printf("%d", gword()); break; case 5: printf("sr"); break; } } op2(f,m1,r1,m2,r2) /* f set means order passed, clear reverses order */ { if (f) op1(m1,r1); else op1(m2,r2); putc(',',stdout); if (f) op1(m2,r2); else op1(m1,r1); } opmode(op, opm, reg, m, r) char *op; { OPI(op, size[gisize=BFIELD(opm,1,2)]); op2(BTST(opm,2),0,reg,m,r); } long dasm(addr,cnt, symflg) long addr; { int tflg = 0; register unsigned int w, m1, m2, r1, r2, op; char ds; gaddr = addr; gempty = 1; while (tflg || cnt--) { tflg = 0; if (symflg) symbolic(gaddr, '\t'); else printf("0x%lx ", gaddr); w = gword(); m1 = BFIELD(w,8,3); m2 = BFIELD(w,5,3); r1 = BFIELD(w,11,3); r2 = BFIELD(w,2,3); op = BFIELD(w,15,4); switch (op) { case 0x0: if (m2 == 1) { OPI("movep", BTST(w,6) ? 'l' : 'w'); op2(BTST(w,7),0,r1,5,r2); break; } if (BTST(w,8)) { OPI(bitop[BFIELD(w,7,2)], m2 ? 'b' : 'l'); op2(1,0,r1,m2,r2); break; } if (r2 == 4) { OPI(bitop[BFIELD(w,7,2)], m2 ? 'b' : 'l'); gisize = WORD; op2(1,7,4,m2,r2); break; } OPI(imedop[r1],size[gisize = m1]); op2(1,7,4,m2,r2); break; case 0x1: gisize = BYTE; goto domove; case 0x2: gisize = LONG; goto domove; case 0x3: gisize = WORD; domove: OPI("move", size[gisize]); op2(1,m2,r2,m1,r1); break; case 0x4: if (BTST(w,8)) { if (BTST(w,6)) { printf("lea\t"); op1(m2,r2); printf(",a%d", r1); break; } printf("chk\t"); op1(m2,r2); printf(",d%d", r1); break; } if (r1 < 4) { if (m1 == 3) { printf("move\t"); gisize = WORD; if (r1 == 0) printf("sr,"); op1(m2,r2); if (r1 == 2) printf(",ccr"); if (r1 == 3) printf(",sr"); break; } OPI(misc1[r1], size[m1]); op1(m2,r2); break; } else if (r1 == 4) { switch(m1) { case 0: printf("nbcd\t"); break; case 1: printf(m2 ? "pea\t" : "swap\t"); break; case 2: case 3: OPI(m2 ? "movem" : "ext", BTST(w,6) ? 'l' : 'w'); if (m2) movem(1,m2==4, gword()); break; } op1(m2,r2); break; } if (r1 == 5) { if (m1 == 3) printf("tas\t"); else OPI("tst", size[m1]); op1(m2,r2); break; } if (r1 == 6) { OPI("movem", BTST(w,6) ? 'l' : 'w'); op = gword(); op1(m2,r2); movem(0,m2==4,op); break; } if (BTST(w,7)) { printf(BTST(w,6) ? "jmp\t" : "jsr\t"); op1(m2,r2); break; } switch (m2) { case 0: case 1: printf("trap\t#%d", BFIELD(w,3,4)); tflg = 1; break; case 2: printf("link\ta%d,#%d", r2, gword()); break; case 3: printf("unlk\ta%d", r2); break; case 4: printf("move.l a%d,usp", r2); break; case 5: printf("move.l usp,a%d", r2); break; case 6: printf(misc2[r2]); break; } break; case 0x5: if (BFIELD(w,7,2) == 3) { op = BFIELD(w,11,4); if (m2 == 1) { printf("db%s\td%d,",cc[op], r2); reladdr('\0'); } else { printf("s%s\t",cc[op]); op1(m2,r2); } } else { printf("%sq\t#%d,",BTST(w,8)?"sub":"add", ((r1 - 1) & 7) + 1); op1(m2,r2); } break; case 0x6: ds = BFIELD(w,7,8); printf("b%s.%c\t", cc[BFIELD(w,11,4)], ds ? 's' : 'w'); if (m1) symbolic(gaddr+ds); else reladdr('\0'); break; case 0x7: printf("moveq\t#%d,d%d",BFIELD(w,7,8),r1); break; case 0x8: if (m1 == 3 || m1 == 7) { printf("div%c\t", BTST(w,8) ? 's' : 'u'); op2(0,0,r1,m2,r2); } else if (m1 == 4 && (m2 == 1 || m2 == 0)) { printf(m2 ? "sbcd\t-(a%d),-(a%d)" : "sbcd\td%d,d%d", r2, r1); } else { opmode("or",m1,r1,m2,r2); } break; case 0x9: case 0xD: if ((m2 == 0 || m2 == 1) && m1 > 3 && m1 < 7) { OPI(op == 9 ? "subx" : "addx", size[BFIELD(w,7,2)]); m2 <<= 2; op2(1,m2,r2,m2,r1); } else if (m1 == 3 || m1 == 7) { gisize = m1 == 3 ? WORD : LONG; OPI(op==9 ? "sub" : "add", size[gisize]); op2(1,m2,r2,1,r1); } else { opmode(op==9 ? "sub" : "add",m1,r1,m2,r2); } break; case 0xB: if (BTST(w,8)) { if (m2 == 1) { OPI("cmpm", size[BFIELD(w,7,2)]); printf("(a%d)+,(a%d)+",r2,r1); } else { opmode("eor",m1,r1,m2,r2); } } else { opmode("cmp",m1,r1,m2,r2); } break; case 0xC: if (m1 == 3 || m1 == 7) { printf("mul%c\t", m1==7 ? 's' : 'u'); op2(0,0,r1,m2,r2); } else if (m1 == 4 && (m2 == 1 || m2 == 0)) { printf(m2 ? "abcd\t-(a%d),-(a%d)" : "abcd\td%d,d%d", r2, r1); } else if (m1 == 5) { op = BTST(w,3) ? 'a' : 'd'; printf("exg\t%c%d,%c%d",op,r1,op,r2); } else if (m1 == 6) { printf("exg\td%d,a%d",r1,r2); } else { opmode("and",m1,r1,m2,r2); } break; case 0xE: if (BFIELD(w,7,2) == 3) { printf("%s%c\t",shf[BFIELD(w,10,2)], BTST(w,8) ? 'l' : 'r'); op1(m2,r2); } else { printf("%s%c\t",shf[BFIELD(w,4,2)], BTST(w,8) ? 'l' : 'r'); if (BTST(w,5)) { op2(1,0,r1,0,r2); } else { printf("#%d,",r1); op1(0,r2); } } break; case 0xA: case 0xF: printf("%x", w); break; } putc('\n',stdout); } return gaddr; }
Steinsbo%hsr.uninett%NORUNIX.BITNET@cunyvm.cuny.edu (Bjarne Steinsbo) (01/04/89)
>X-Originator: "B.SZABLAK" <bds@lzaz.att.com> >X-Bitnet-Sender: info-minix-request@UDEL.EDU >Organization: AT&T ISL Lincroft NJ USA /* * mdb.c - MINIX program debugger * * Written by Bruce D. Szablak * * This free software is provided for non-commerical use. No warrantee * of fitness for any use is implied. You get what you pay for. Anyone * may make modifications and distribute them, but please keep this header * in the distribution. */ #define T_OK 0 #define T_GETINS 1 #define T_GETDATA 2 #define T_GETUSER 3 #define T_SETINS 4 #define T_SETDATA 5 #define T_SETUSER 6 #define T_RESUME 7 #define T_EXIT 8 #define T_STEP 9 #include "stdio.h" #include "signal.h" #include "ctype.h" #include "setjmp.h" #include "user.h" struct proc *prc; #define BP_REG 14 #define MAXLINE 120 #define REG(r) ((long)&((struct proc *)0)->p_regr|) #define PC ((long)&((struct proc *)0)->p_pcpsw.pc) #define MAXB 10 #define MAXP 3 #define MAXARG 20 #define SIZ (1 + sizeof(struct proc)/sizeof(long)) #define MAXLINE 120 long ptrace(), strtol(), reg_addr(), lbufSIZ|, saddr, eaddr, dasm(); int curpid, cursig; char *strcpy(), *prog, sbufMAXLINE|, cbufMAXLINE|, *cmd, *addr_to_name(), *getexp(), *cmdstart; jmp_buf mainlp; extern errno; struct b_pnt { struct b_pnt *nxt, *prv; long addr; long oldval; char cmd1|; } *b_head, *curpnt; cleanup() { curpid = 0; curpnt = 0; while (b_head) freepnt(b_head); } dowait() { int stat, ls, hs; while (wait(&stat) != curpid) {}; ls = stat & 0xFF; hs = (stat >> 8) & 0xFF; if (ls == 0) { if (hs != 127) printf("child exited with status %d\n", hs); cleanup(); return 0; } if (hs == 0) { printf("child terminated by signal %d\n", ls & 0x7F); if (ls & 0x80) printf("(core dumped)\n"); cleanup(); return 0; } return cursig = hs; } update() { int i; for (i = 0; i < (SIZ-1); i++) { lbufi| = ptrace(T_GETUSER, curpid, (long)(i*sizeof(long)),0L); } saddr = (long)prc->p_mapT|.mem_vir << CLICK_SHIFT; eaddr = (long)(prc->p_mapD|.mem_vir + prc->p_mapD|.mem_len) << CLICK_SHIFT; } findbpnt(verbose) { for (curpnt = b_head; curpnt; curpnt = curpnt->nxt) { if (curpnt->addr == prc->p_pcpsw.pc) { ptrace(T_SETINS, curpid, curpnt->addr, curpnt->oldval); if (curpnt->cmd0| != '\n') cmd = strcpy(cbuf, curpnt->cmd); else if (verbose) printf("Breakpoint hit.\n"); return; } } if (verbose) printf("Unknown breakpoint hit.\n"); } disp_regs() { int i; if (curpid <= 0) { printf("No active process.\n"); return 1; } printf("\npc=%lx psw=%x\n\n",(long)prc->p_pcpsw.pc, prc->p_pcpsw.psw); printf( " 0 1 2 3 4 5 6 7\nD"); for (i = 0; i < 8; i++) printf(" %08lx", prc->p_regi|); printf("\nA"); for (; i < NR_REGS; i++) printf(" %08lx", prc->p_regi|); printf(" %08lx\n\n", (long)prc->p_sp); return 0; } char * skip(s) register char *s; { while (isspace(*s)) ++s; return *s ? s : s-1; } endcmd() { while (*cmd != '\n' && *cmd != ';') ++cmd; } #define BREAK(l) (0xA0000000 | ((l) & 0xFFFF)) exebpnt(restart) { ptrace(T_STEP, curpid, 0L, (long)restart); if (dowait() == 0) return 1; ptrace(T_SETINS, curpid, curpnt->addr, BREAK(curpnt->oldval)); curpnt = 0; return 0; } tstart(req, verbose, val, cnt) { if (curpid == 0) { if (verbose) printf("No active process.\n"); return; } if (req == T_EXIT) { ptrace(T_EXIT, curpid, 0L, (long)val); dowait(); return; } if (cnt==0) cnt = 1; do { if (curpnt) { if (exebpnt(val)) return; if (req == T_RESUME) cnt++; val = 0; } else { ptrace(req, curpid, 0L, (long)val); if (dowait() == 0) return; val = 0; switch (cursig) { case SIGEMT: /* breakpoint */ update(); findbpnt(cnt <= 1); break; case SIGTRAP: /* trace trap? */ if (req == T_STEP) break; default: /* signal */ val = cursig; break; } } } while (--cnt > 0); update(); dasm((long)prc->p_pcpsw.pc, 1, 1); } catch(sig) { signal(sig, catch); if (sig == SIGINT || sig == SIGQUIT) return; tstart(T_EXIT, 0, sig, 0); exit(0); } run(name, argstr, tflg) char *name, *argstr; { int procid; if( (procid = fork()) == 0 ) { char *argvMAXARG|, *inf = 0, *outf = 0; int argc; if (tflg && ptrace(T_OK, 0, 0L, 0L) < 0) { perror("ptrace"); exit(127); } argv0| = name; for (argc = 1; ; ) { argstr = skip(argstr); if (*argstr == '\n' || *argstr == ';') { argvargc| = 0; if (inf) freopen(inf, "r", stdin); if (outf) freopen(outf, "w", stdout); execv(name, argv); perror("execv"); exit( 127 ); } if (*argstr == '<') inf = argstr+1; else if (*argstr == '>') outf = argstr+1; else if (argc == MAXARG) { printf("Too many arguments.\n"); exit(127); } else argvargc++| = argstr; while (!isspace(*argstr)) argstr++; if (*argstr == '\n') argstr1| = '\n', argstr2| = 0; *argstr++ = 0; } } if (procid < 0) { printf("Fork failed.\n"); } return procid; } #define ADDQ(l) (((l >> 16) & 0xF1FF) == 0x508F) #define ADDQ_CNT(l) ((((l >> 25) - 1) & 7) + 1) #define LEA(l) ((l >> 16) == 0x4FEF) #define LEA_DISP(l) ((long)(int)l) #define ADDA(l) ((int)(l >> 16) == 0xDFFC) backtrace(all) { char sep; long pc, bp, off, val, obp; if (curpid <= 0) { printf("No process.\n"); return; } pc = prc->p_pcpsw.pc; bp = prc->p_regBP_REG|; if (bp == 0) { printf("No active frame.\n"); return; } errno = 0; do { symbolic(pc, '('); pc = ptrace(T_GETDATA, curpid, bp+4, 0L); off = ptrace(T_GETDATA, curpid, pc, 0L); obp = bp; bp += 2*sizeof(val); if (ADDQ(off)) off = ADDQ_CNT(off) + bp; else if (LEA(off)) off = LEA_DISP(off) + bp; else if (ADDA(off)) off = ptrace(T_GETDATA, curpid, pc+2, 0L) + bp; else goto skiplp; for (;;) { if (errno) return; val = ptrace(T_GETDATA, curpid, bp, 0L) >> 16; printf("0x%04x", (int)val); bp += sizeof(int); if (bp >= off) break; putc(',', stdout); } skiplp: fputs(")\n", stdout); bp = ptrace(T_GETDATA, curpid, obp, 0L); } while (all && bp); } freepnt(pnt) struct b_pnt *pnt; { if (pnt->prv) pnt->prv->nxt = pnt->nxt; else b_head = pnt->nxt; if (pnt->nxt) pnt->nxt->prv = pnt->prv; if (curpid > 0) ptrace(T_SETINS, curpid, pnt->addr, pnt->oldval); free(pnt); if (pnt == curpnt) curpnt = 0; } breakpt(addr, cmd) long addr; char *cmd; { char *s; struct b_pnt *new, *malloc(); int lng; if (curpid <= 0) { printf("No active process.\n"); return; } for (new = b_head; new; new=new->nxt) if (new->addr == addr) { printf("Breakpoint already exists here.\n"); return; } new = malloc(sizeof(struct b_pnt) + strlen(cmd)); if (new == 0) { printf("No room.\n"); return; } new->nxt = b_head; new->prv = 0; if (b_head) b_head->prv = new; b_head = new; new->addr = addr; strcpy(new->cmd, cmd); new->oldval = ptrace(T_GETINS, curpid, addr, 0L); ptrace(T_SETINS, curpid, addr, BREAK(new->oldval)); if (ptrace(T_GETINS, curpid, addr, 0L) != BREAK(new->oldval)) { perror("Can't set breakpoint"); freepnt(new); } } modify(addr, cnt, verbose) long addr; { long curval, off; if (curpid == 0) { printf("No active process.\n"); return; } curval = ptrace(T_GETDATA, curpid, addr, 0L); do { if (cursig == SIGTRAP) cursig = 0; if (verbose) { off = ptrace(T_GETUSER, curpid, PC, 0L); dasm(off, 1, 0); } if (curpnt && exebpnt(cursig)) return; else { ptrace(T_STEP, curpid, addr, 0L); switch (dowait()) { case 0: return; case SIGEMT: update(); findbpnt(0); break; } } if (curval != ptrace(T_GETDATA, curpid, addr, 0L)) { printf("Modification detected\n"); break; } } while (--cnt); update(); dasm(prc->p_pcpsw.pc, 1, 1); return; } display(addr, req) long addr; { int count, size, out, shift; long val, msk; char fmt; if (curpid == 0) { printf("No active process\n"); return; } count = strtol(cmd, &cmd, 0); if (count == 0) count = 1; if (*cmd == 'i' || *cmd == 'I') { if (req == T_GETUSER) { printf("Can't disassemble a register's contents.\n"); longjmp(mainlp); } dasm(addr, count, *cmd == 'i'); return; } switch (*cmd++) { case 'b': size = sizeof(char); break; case 'h': size = sizeof(short); break; case 'l': size = sizeof(long); break; default : size = sizeof(int); --cmd; break; } switch (fmt = *cmd) { case 'c': count *= size; size = sizeof(char); break; case 's': addr = ptrace(req, curpid, addr, 0L); req = T_GETDATA; case 'a': size = sizeof(char); break; } out = 0; msk = size == sizeof(long) ? 0xFFFFFFFF : (1L << (8*size)) - 1; shift = 32 - 8*size; do { val = (ptrace(req, curpid, addr, 0L) >> shift) & msk; if (out == 0) printf("\n0x%08lx: ", addr); switch (fmt) { case 'c': printf(isprint(val) ? " %c " : "\\%03o ", (char)val); if (++out == 8) out = 0; break; case 'u': printf("%12lu ", val); if (++out == 4) out = 0; break; case 'x': printf("%*lx ", 2*size, val); if (++out == (size == 4 ? 4 : 8)) out = 0; break; case 'o': printf("%*lo ", 3*size, val); if (++out == (size == 4 ? 4 : 8)) out = 0; break; case 's': case 'a': if (val) fputc((char)val, stdout); else goto exitlp; if (++out == 64) out = 0; break; default: case 'd': printf("%12ld ", val); if (++out == 4) out = 0; break; } addr += size; } while (--count > 0 || fmt == 's' || fmt == 'a'); exitlp: fputc('\n', stdout); } fill(addr, req) long addr; { int count, size, shift, seg; long val, msk, nval; char fmt; if (curpid == 0) { printf("No active process\n"); return; } count = strtol(cmd, &cmd, 0); switch (*cmd++) { case 'b': size = sizeof(char); break; case 'h': size = sizeof(short); break; case 'l': size = sizeof(long); break; default : size = sizeof(int); --cmd; break; } shift = 32 - 8*size; msk = (0x80000000 >> 8*size); cmd = getexp(cmd, &nval, &seg); nval <<= shift; do { val = ptrace(req, curpid, addr, 0L) | (nval & msk); val &= (nval | ~msk); ptrace(req+3, curpid, addr, val); addr += size; } while (--count>0); } command(savestr) char *savestr; { char c, *p; int i, seg; long exp; struct b_pnt *bp; seg = S; /* don't restrict segment expressions are in */ cmdstart = cmd = skip(cmd); cmd = getexp(cmd, &exp, &seg); if (exp == 0) { seg = T; exp = prc->p_pcpsw.pc; } switch (c = *cmd++) { case '!': /* escape to shell OR set variable to value */ if (cmd == cmdstart+1) { cmd = skip(cmd); if (*cmd == '\n' || *cmd == ';') { i = run("/bin/sh", "\n", 0); } else { for (p=cmd+1; *p && !isspace(*p); p++) {}; *p++ = 0; i = run(cmd, *p ? p : "\n", 0); } if (i > 0) while (wait(&seg) != i) {}; break; } if (seg == 'T') { printf("Can only modify data variables.\n"); break; } fill(exp, T_GETDATA); break; case 'T': /* top line of backtrace */ backtrace(0); break; case 't': /* back trace */ backtrace(1); break; case '/': /* print variable value */ display(exp, T_GETDATA); break; case 'x': /* print registers and instruction */ if (disp_regs()) break; /*FALLTHROUGH*/ case 'X': /* print instruction */ i = strtol(cmd, &cmd, 0); if (curpid > 0) dasm(exp, i ? i : 1, 1); else printf("No active process.\n"); break; case 'R': /* run program with no args */ case 'r': /* run program with args (possibly defaulted) */ tstart(T_EXIT, 0, 0, 0); if (c == 'r') { cmd = skip(cmd); if (*cmd == '\n' || *cmd == ';') cmd = sbuf; else strcpy(sbuf, cmd); } else { cmd = "\n"; } if (curpid = run(prog, cmd, 1)) { if (dowait()) { ptrace(T_SETUSER, curpid, REG(BP_REG), 0L); update(); printf("Process stopped.\n"); } } break; case 'c': /* continue program - ignore signal */ cursig = 0; case 'C': /* continue program - handle signal */ i = 0; if (seg == T && curpnt == 0 && cmd != cmdstart+1) { breakpt(exp, "\n"); curpnt = b_head; ptrace(T_SETINS, curpid, curpnt->addr, curpnt->oldval); i = 1; } tstart(T_RESUME, 1, cursig, (int)strtol(cmd, &cmd, 0)); if (i) /* remove temporary bp */ { freepnt(b_head); } if (cursig == SIGEMT) return; if (curpid) printf("Process stopped by signal %d\n", cursig); break; case 'i': /* single step - ignore signal */ tstart(T_STEP, 1, 0, (int)strtol(cmd, &cmd, 0)); break; case 'I': /* single step - handle signal */ tstart(T_STEP, 1, cursig, (int)strtol(cmd, &cmd, 0)); break; case 'm': /* single step until location modified */ case 'M': /* single step until location modified - verbose */ modify(exp, (int)strtol(cmd, &cmd, 0), c == 'M'); break; case 'k': /* kill current program */ tstart(T_EXIT, 1, 0, 0); break; case 'b': /* set a breakpoint at the given line */ if (seg == D) { printf("Address not in text space.\n"); return; } breakpt(exp, skip(cmd)); cmd = "\n"; return; case 'B': /* print list of currently active breakpoints */ for (i = 1, bp = b_head; bp; bp=bp->nxt, i++) { p = addr_to_name(bp->addr - saddr, &exp); printf("%2d: %s+0x%lx (0x%lx) - %s", i, p, exp, bp->addr, bp->cmd); } break; case 'd': /* delete breakpoint */ if (seg == T) { for (bp = b_head; bp && --exp; bp=bp->nxt) {}; if (bp) { freepnt(bp); break; } } printf("No such breakpoint.\n"); break; case 'D': /* delete all breakpoints */ while(b_head) freepnt(b_head); break; case 'q': /* quit */ tstart(T_EXIT, 0, 0, 0L, 0); exit(0); case '\n': case ';': if (isdigit(*cmdstart)) symbolic(exp, '\n'); else printf("0x%lx\n", exp); --cmd; break; case '$': cmdstart = cmd; cmd = skip(cmd+2); if (*cmd == '!') { cmd++; fill(reg_addr(cmdstart), T_GETUSER); break; } if (*skip(cmd+2) == '/') { cmd++; display(reg_addr(cmdstart), T_GETUSER); break; } /*FALLTHROUGH*/ default: printf("Unknown command.\n"); break; } while (*cmd != '\n' && *cmd != ';') ++cmd; if (*cmd == ';') cmd = skip(cmd+1); } main(argc, argv) char *argv|; { int i; prc = lbuf; for (i = 1; i < NSIG; i++) signal(i, catch); strcpy(sbuf, "\n"); prog = argc > 1 ? argv1| : "a.out"; if (argc > 2) getsyms(argv2|); setjmp(&mainlp); while ((printf("* "), fflush(stdout), fgets(cbuf, sizeof(cbuf), stdin)) != EOF) { if (strlen(cbuf) == sizeof(cbuf)-1) { printf("Command line too long.\n"); continue; } cmd = cbuf; command(); while (*cmd != '\n') command(); } tstart(T_EXIT, 0, 0, 0); exit(0); }