diff options
author | rsc <devnull@localhost> | 2004-04-19 19:30:50 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2004-04-19 19:30:50 +0000 |
commit | 84114f06650ba3db950532b1d0cd1d7e18b4b6be (patch) | |
tree | 4a5aa4819d01f1798bf86c3420db542c74092a6f /src/cmd/db | |
parent | a84cbb2a17c9d0b88c561d5b7cb50d79a19e7c46 (diff) | |
download | plan9port-84114f06650ba3db950532b1d0cd1d7e18b4b6be.tar.gz plan9port-84114f06650ba3db950532b1d0cd1d7e18b4b6be.tar.bz2 plan9port-84114f06650ba3db950532b1d0cd1d7e18b4b6be.zip |
debugger
Diffstat (limited to 'src/cmd/db')
-rw-r--r-- | src/cmd/db/command.c | 311 | ||||
-rw-r--r-- | src/cmd/db/defs.h | 111 | ||||
-rw-r--r-- | src/cmd/db/expr.c | 397 | ||||
-rw-r--r-- | src/cmd/db/fns.h | 91 | ||||
-rw-r--r-- | src/cmd/db/format.c | 388 | ||||
-rw-r--r-- | src/cmd/db/input.c | 169 | ||||
-rw-r--r-- | src/cmd/db/main.c | 262 | ||||
-rw-r--r-- | src/cmd/db/mkfile | 26 | ||||
-rw-r--r-- | src/cmd/db/output.c | 159 | ||||
-rw-r--r-- | src/cmd/db/pcs.c | 177 | ||||
-rw-r--r-- | src/cmd/db/print.c | 406 | ||||
-rw-r--r-- | src/cmd/db/regs.c | 44 | ||||
-rw-r--r-- | src/cmd/db/runpcs.c | 205 | ||||
-rw-r--r-- | src/cmd/db/setup.c | 145 | ||||
-rw-r--r-- | src/cmd/db/trcrun.c | 288 |
15 files changed, 3179 insertions, 0 deletions
diff --git a/src/cmd/db/command.c b/src/cmd/db/command.c new file mode 100644 index 00000000..55ed02a8 --- /dev/null +++ b/src/cmd/db/command.c @@ -0,0 +1,311 @@ +/* + * + * debugger + * + */ + +#include "defs.h" +#include "fns.h" + +char BADEQ[] = "unexpected `='"; + +BOOL executing; +extern char *lp; + +char eqformat[ARB] = "z"; +char stformat[ARB] = "zMi"; + +ADDR ditto; + +ADDR dot; +WORD dotinc; +WORD adrval, cntval, loopcnt; +int adrflg, cntflg; + +/* command decoding */ + +int +command(char *buf, int defcom) +{ + char *reg; + char savc; + char *savlp=lp; + char savlc = lastc; + char savpc = peekc; + static char lastcom = '=', savecom = '='; + + if (defcom == 0) + defcom = lastcom; + if (buf) { + if (*buf==EOR) + return(FALSE); + clrinp(); + lp=buf; + } + do { + adrflg=expr(0); /* first address */ + if (adrflg){ + dot=expv; + ditto=expv; + } + adrval=dot; + + if (rdc()==',' && expr(0)) { /* count */ + cntflg=TRUE; + cntval=expv; + } else { + cntflg=FALSE; + cntval=1; + reread(); + } + + if (!eol(rdc())) + lastcom=lastc; /* command */ + else { + if (adrflg==0) + dot=inkdot(dotinc); + reread(); + lastcom=defcom; + } + switch(lastcom) { + case '/': + case '=': + case '?': + savecom = lastcom; + acommand(lastcom); + break; + + case '>': + lastcom = savecom; + savc=rdc(); + if (reg=regname(savc)) + rput(correg, reg, dot); + else + error("bad variable"); + break; + + case '!': + lastcom=savecom; + shell(); + break; + + case '$': + lastcom=savecom; + printdollar(nextchar()); + break; + + case ':': + if (!executing) { + executing=TRUE; + subpcs(nextchar()); + executing=FALSE; + lastcom=savecom; + } + break; + + case 0: + prints(DBNAME); + break; + + default: + error("bad command"); + } + flushbuf(); + } while (rdc()==';'); + if (buf == 0) + reread(); + else { + clrinp(); + lp=savlp; + lastc = savlc; + peekc = savpc; + } + + if(adrflg) + return dot; + return 1; +} + +/* + * [/?][wml] + */ + +void +acommand(int pc) +{ + int eqcom; + Map *map; + char *fmt; + char buf[512]; + + if (pc == '=') { + eqcom = 1; + fmt = eqformat; + map = dotmap; + } else { + eqcom = 0; + fmt = stformat; + if (pc == '/') + map = cormap; + else + map = symmap; + } + if (!map) { + sprint(buf, "no map for %c", pc); + error(buf); + } + + switch (rdc()) + { + case 'm': + if (eqcom) + error(BADEQ); + cmdmap(map); + break; + + case 'L': + case 'l': + if (eqcom) + error(BADEQ); + cmdsrc(lastc, map); + break; + + case 'W': + case 'w': + if (eqcom) + error(BADEQ); + cmdwrite(lastc, map); + break; + + default: + reread(); + getformat(fmt); + scanform(cntval, !eqcom, fmt, map, eqcom); + } +} + +void +cmdsrc(int c, Map *map) +{ + u32int w; + long locval, locmsk; + ADDR savdot; + ushort sh; + char buf[512]; + int ret; + + if (c == 'L') + dotinc = 4; + else + dotinc = 2; + savdot=dot; + expr(1); + locval=expv; + if (expr(0)) + locmsk=expv; + else + locmsk = ~0; + if (c == 'L') + while ((ret = get4(map, dot, &w)) > 0 && (w&locmsk) != locval) + dot = inkdot(dotinc); + else + while ((ret = get2(map, dot, &sh)) > 0 && (sh&locmsk) != locval) + dot = inkdot(dotinc); + if (ret < 0) { + dot=savdot; + error("%r"); + } + symoff(buf, 512, dot, CANY); + dprint(buf); +} + +static char badwrite[] = "can't write process memory or text image"; + +void +cmdwrite(int wcom, Map *map) +{ + ADDR savdot; + char *format; + int pass; + + if (wcom == 'w') + format = "x"; + else + format = "X"; + expr(1); + pass = 0; + do { + pass++; + savdot=dot; + exform(1, 1, format, map, 0, pass); + dot=savdot; + if (wcom == 'W') { + if (put4(map, dot, expv) <= 0) + error(badwrite); + } else { + if (put2(map, dot, expv) <= 0) + error(badwrite); + } + savdot=dot; + dprint("=%8t"); + exform(1, 0, format, map, 0, pass); + newline(); + } while (expr(0)); + dot=savdot; +} + +/* + * collect a register name; return register offset + * this is not what i'd call a good division of labour + */ + +char * +regname(int regnam) +{ + static char buf[64]; + char *p; + int c; + + p = buf; + *p++ = regnam; + while (isalnum(c = readchar())) { + if (p >= buf+sizeof(buf)-1) + error("register name too long"); + *p++ = c; + } + *p = 0; + reread(); + return (buf); +} + +/* + * shell escape + */ + +void +shell(void) +{ + int rc, unixpid; + char *argp = lp; + + while (lastc!=EOR) + rdc(); + if ((unixpid=fork())==0) { + *lp=0; + execl("/bin/rc", "rc", "-c", argp, 0); + exits("execl"); /* botch */ + } else if (unixpid == -1) { + error("cannot fork"); + } else { + mkfault = 0; + while ((rc = waitpid()) != unixpid){ + if(rc == -1 && mkfault){ + mkfault = 0; + continue; + } + break; + } + prints("!"); + reread(); + } +} diff --git a/src/cmd/db/defs.h b/src/cmd/db/defs.h new file mode 100644 index 00000000..02ef0854 --- /dev/null +++ b/src/cmd/db/defs.h @@ -0,0 +1,111 @@ +/* + * db - common definitions + * something of a grab-bag + */ + +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <ctype.h> + +#include <mach.h> + +typedef long WORD; +typedef ulong ADDR; + +#define HUGEINT 0x7fffffff /* enormous WORD */ + +#define MAXOFF 0x1000000 +#define INCDIR "/usr/lib/adb" +#define DBNAME "db\n" +#define CMD_VERBS "?/=>!$: \t" + +typedef int BOOL; + +#define MAXPOS 80 +#define MAXLIN 128 +#define ARB 512 +#define MAXCOM 64 +#define MAXARG 32 +#define LINSIZ 4096 +#define MAXSYM 255 + +#define EOR '\n' +#define SPC ' ' +#define TB '\t' + +#define STDIN 0 +#define STDOUT 1 + +#define TRUE (-1) +#define FALSE 0 + + +/* + * run modes + */ + +#define SINGLE 1 +#define CONTIN 2 + +/* + * breakpoints + */ + +#define BKPTCLR 0 /* not a real breakpoint */ +#define BKPTSET 1 /* real, ready to trap */ +#define BKPTSKIP 2 /* real, skip over it next time */ +#define BKPTTMP 3 /* temporary; clear when it happens */ + +struct bkpt { + ADDR loc; + uchar save[4]; + int count; + int initcnt; + int flag; + char comm[MAXCOM]; + struct bkpt *nxtbkpt; +}; +typedef struct bkpt BKPT; + +#define BADREG (-1) + +/* + * common globals + */ + +extern WORD adrval; +extern vlong expv; +extern int adrflg; +extern WORD cntval; +extern int cntflg; +extern WORD loopcnt; +extern ADDR maxoff; +extern ADDR localval; +extern ADDR maxfile; +extern ADDR maxstor; + +extern ADDR dot; +extern WORD dotinc; + +extern int xargc; + +extern BOOL wtflag; +extern char *corfil, *symfil; +extern BOOL mkfault; +extern BOOL regdirty; + +extern int pid; +extern int pcsactive; +#define NNOTE 10 +extern int nnote; +extern char note[NNOTE][ERRMAX]; + +extern int ending; +extern Fhdr *corhdr, *symhdr; +extern Map *cormap, *symmap, *dotmap; +extern Regs *correg; + +extern BKPT *bkpthead; +extern int kflag; +extern int lastc, peekc; diff --git a/src/cmd/db/expr.c b/src/cmd/db/expr.c new file mode 100644 index 00000000..8d33e7f4 --- /dev/null +++ b/src/cmd/db/expr.c @@ -0,0 +1,397 @@ +/* + * + * debugger + * + */ + +#include "defs.h" +#include "fns.h" + +static long dbround(long, long); + +extern ADDR ditto; +vlong expv; + +static WORD +ascval(void) +{ + Rune r; + + if (readchar() == 0) + return (0); + r = lastc; + while(quotchar()) /*discard chars to ending quote */ + ; + return((WORD) r); +} + +/* + * read a floating point number + * the result must fit in a WORD + */ + +static WORD +fpin(char *buf) +{ + union { + WORD w; + float f; + } x; + + x.f = atof(buf); + return (x.w); +} + +WORD +defval(WORD w) +{ + if (expr(0)) + return (expv); + else + return (w); +} + +int +expr(int a) +{ /* term | term dyadic expr | */ + int rc; + WORD lhs; + + rdc(); + reread(); + rc=term(a); + while (rc) { + lhs = expv; + switch ((int)readchar()) { + + case '+': + term(a|1); + expv += lhs; + break; + + case '-': + term(a|1); + expv = lhs - expv; + break; + + case '#': + term(a|1); + expv = dbround(lhs,expv); + break; + + case '*': + term(a|1); + expv *= lhs; + break; + + case '%': + term(a|1); + if(expv != 0) + expv = lhs/expv; + else{ + if(lhs) + expv = 1; + else + expv = 0; + } + break; + + case '&': + term(a|1); + expv &= lhs; + break; + + case '|': + term(a|1); + expv |= lhs; + break; + + case ')': + if ((a&2)==0) + error("unexpected `)'"); + + default: + reread(); + return(rc); + } + } + return(rc); +} + +int +term(int a) +{ /* item | monadic item | (expr) | */ + u32int u; + + switch ((int)readchar()) { + + case '*': + term(a|1); + if (get4(cormap, (ADDR)expv, &u) < 0) + error("%r"); + expv = u; + return(1); + + case '@': + term(a|1); + if (get4(symmap, (ADDR)expv, &u) < 0) + error("%r"); + expv = u; + return(1); + + case '-': + term(a|1); + expv = -expv; + return(1); + + case '~': + term(a|1); + expv = ~expv; + return(1); + + case '(': + expr(2); + if (readchar()!=')') + error("syntax error: `)' expected"); + return(1); + + default: + reread(); + return(item(a)); + } +} + +int +item(int a) +{ /* name [ . local ] | number | . | ^ | <register | 'x | | */ + char *base; + char savc; + ulong u; + Symbol s; + char gsym[MAXSYM], lsym[MAXSYM]; + + readchar(); + if (isfileref()) { + readfname(gsym); + rdc(); /* skip white space */ + if (lastc == ':') { /* it better be */ + rdc(); /* skip white space */ + if (!getnum(readchar)) + error("bad number"); + if (expv == 0) + expv = 1; /* file begins at line 1 */ + if(file2pc(gsym, expv, &u) < 0) + error("%r"); + expv = u; + return 1; + } + error("bad file location"); + } else if (symchar(0)) { + readsym(gsym); + if (lastc=='.') { + readchar(); /* ugh */ + if (lastc == '.') { + lsym[0] = '.'; + readchar(); + readsym(lsym+1); + } else if (symchar(0)) { + readsym(lsym); + } else + lsym[0] = 0; + if (localaddr(cormap, correg, gsym, lsym, &u) < 0) + error("%r"); + expv = u; + } + else { + if (lookupsym(0, gsym, &s) < 0) + error("symbol not found"); + if (s.loc.type != LADDR) + error("symbol not kept in memory"); + expv = s.loc.addr; + } + reread(); + } else if (getnum(readchar)) { + ; + } else if (lastc=='.') { + readchar(); + if (!symchar(0) && lastc != '.') { + expv = dot; + } else { + if (findsym(locaddr(dbrget(cormap, mach->pc)), CTEXT, &s) < 0) + error("no current function"); + if (lastc == '.') { + lsym[0] = '.'; + readchar(); + readsym(lsym+1); + } else + readsym(lsym); + if (localaddr(cormap, correg, s.name, lsym, &u) < 0) + error("%r"); + expv = u; + } + reread(); + } else if (lastc=='"') { + expv=ditto; + } else if (lastc=='+') { + expv=inkdot(dotinc); + } else if (lastc=='^') { + expv=inkdot(-dotinc); + } else if (lastc=='<') { + savc=rdc(); + base = regname(savc); + expv = dbrget(cormap, base); + } + else if (lastc=='\'') + expv = ascval(); + else if (a) + error("address expected"); + else { + reread(); + return(0); + } + return(1); +} + +#define MAXBASE 16 + +/* service routines for expression reading */ +int +getnum(int (*rdf)(void)) +{ + char *cp; + int base, d; + BOOL fpnum; + char num[MAXLIN]; + + base = 0; + fpnum = FALSE; + if (lastc == '#') { + base = 16; + (*rdf)(); + } + if (convdig(lastc) >= MAXBASE) + return (0); + if (lastc == '0') + switch ((*rdf)()) { + case 'x': + case 'X': + base = 16; + (*rdf)(); + break; + + case 't': + case 'T': + base = 10; + (*rdf)(); + break; + + case 'o': + case 'O': + base = 8; + (*rdf)(); + break; + default: + if (base == 0) + base = 8; + break; + } + if (base == 0) + base = 10; + expv = 0; + for (cp = num, *cp = lastc; ;(*rdf)()) { + if ((d = convdig(lastc)) < base) { + expv *= base; + expv += d; + *cp++ = lastc; + } + else if (lastc == '.') { + fpnum = TRUE; + *cp++ = lastc; + } else { + reread(); + break; + } + } + if (fpnum) + expv = fpin(num); + return (1); +} + +void +readsym(char *isymbol) +{ + char *p; + Rune r; + + p = isymbol; + do { + if (p < &isymbol[MAXSYM-UTFmax-1]){ + r = lastc; + p += runetochar(p, &r); + } + readchar(); + } while (symchar(1)); + *p = 0; +} + +void +readfname(char *filename) +{ + char *p; + Rune c; + + /* snarf chars until un-escaped char in terminal char set */ + p = filename; + do { + if ((c = lastc) != '\\' && p < &filename[MAXSYM-UTFmax-1]) + p += runetochar(p, &c); + readchar(); + } while (c == '\\' || strchr(CMD_VERBS, lastc) == 0); + *p = 0; + reread(); +} + +int +convdig(int c) +{ + if (isdigit(c)) + return(c-'0'); + else if (!isxdigit(c)) + return(MAXBASE); + else if (isupper(c)) + return(c-'A'+10); + else + return(c-'a'+10); +} + +int +symchar(int dig) +{ + if (lastc=='\\') { + readchar(); + return(TRUE); + } + return(isalpha(lastc) || lastc>0x80 || lastc=='_' || dig && isdigit(lastc)); +} + +static long +dbround(long a, long b) +{ + long w; + + w = (a/b)*b; + if (a!=w) + w += b; + return(w); +} + +ulong +dbrget(Map *map, char *name) +{ + ulong u; + + USED(map); + if(rget(correg, name, &u) < 0) + return ~(ulong)0; + return u; +} diff --git a/src/cmd/db/fns.h b/src/cmd/db/fns.h new file mode 100644 index 00000000..32bd94fb --- /dev/null +++ b/src/cmd/db/fns.h @@ -0,0 +1,91 @@ +void acommand(int); +void attachprocess(void); +void bkput(BKPT*, int); +void bpwait(void); +int charpos(void); +void chkerr(void); +void clrinp(void); +void cmdmap(Map*); +void cmdsrc(int, Map*); +void cmdwrite(int, Map*); +int command(char*, int); +int convdig(int); +void ctrace(int); +WORD defval(WORD); +void delbp(void); +ulong dbrget(Map*, char*); +void done(void); +int dprint(char*, ...); +Map* dumbmap(int); +void endline(void); +void endpcs(void); +int eol(int); +void error(char*); +void errors(char*, char*); +void execbkpt(BKPT*, int); +char* exform(int, int, char*, Map*, int, int); +int expr(int); +/* +void fixregs(Map*); +void adjustreg(char*, ulong, long); +*/ +void flush(void); +void flushbuf(void); +char* getfname(void); +void getformat(char*); +int getnum(int (*)(void)); +void grab(void); +void iclose(int, int); +ADDR inkdot(long); +int isfileref(void); +int item(int); +void killpcs(void); +void kmsys(void); +void main(int, char**); +int mapimage(void); +void newline(void); +int nextchar(void); +void notes(void); +void oclose(void); +void outputinit(void); +void printc(int); +void printdollar(int); +void printesc(int); +void printlocals(Symbol*, Regs*); +void printmap(char*, Map*); +void printparams(Symbol*, Regs*); +void printpc(void); +void printregs(int); +void prints(char*); +void printsource(long); +void printsym(void); +void printsyscall(void); +int quotchar(void); +int rdc(void); +int readchar(void); +void readsym(char*); +void redirin(int, char*); +void redirout(char*); +void readfname(char *); +void reread(void); +char* regname(int); +//vlong rget(Map*, char*); +Regdesc* rname(char*); +//void rput(Map*, char*, vlong); +int runpcs(int, int); +void runrun(int); +void runstep(ulong, int); +BKPT* scanbkpt(ADDR adr); +void scanform(long, int, char*, Map*, int); +void setbp(void); +void setcor(void); +void setsym(void); +void setup(void); +void setvec(void); +void shell(void); +void startpcs(void); +void subpcs(int); +int symchar(int); +int term(int); +void ungrab(void); +int valpr(long, int); diff --git a/src/cmd/db/format.c b/src/cmd/db/format.c new file mode 100644 index 00000000..ef053646 --- /dev/null +++ b/src/cmd/db/format.c @@ -0,0 +1,388 @@ +/* + * + * debugger + * + */ + +#include "defs.h" +#include "fns.h" + +void +scanform(long icount, int prt, char *ifp, Map *map, int literal) +{ + char *fp; + char c; + int fcount; + ADDR savdot; + int firstpass; + + firstpass = 1; + while (icount) { + fp=ifp; + savdot=dot; + /*now loop over format*/ + while (*fp) { + if (!isdigit(*fp)) + fcount = 1; + else { + fcount = 0; + while (isdigit(c = *fp++)) { + fcount *= 10; + fcount += c-'0'; + } + fp--; + } + if (*fp==0) + break; + fp=exform(fcount,prt,fp,map,literal,firstpass); + firstpass = 0; + } + dotinc=dot-savdot; + dot=savdot; + if (--icount) + dot=inkdot(dotinc); + } +} + +char * +exform(int fcount, int prt, char *ifp, Map *map, int literal, int firstpass) +{ + /* execute single format item `fcount' times + * sets `dotinc' and moves `dot' + * returns address of next format item + */ + vlong v; + WORD w; + ulong savdot; + u16int u2; + u32int u4; + u64int u8; + char *fp; + char c, modifier; + int i; + ushort sh, *sp; + uchar ch, *cp; + Symbol s; + char buf[512]; + extern int printcol; + + fp = 0; + while (fcount > 0) { + fp = ifp; + c = *fp; + modifier = *fp++; + if (firstpass) { + firstpass = 0; + if (!literal && (c == 'i' || c == 'I' || c == 'M') + && (dot & (mach->pcquant-1))) { + dprint("warning: instruction not aligned"); + printc('\n'); + } + if (prt && modifier != 'a' && modifier != 'A') { + symoff(buf, 512, dot, CANY); + dprint("%s%c%16t", buf, map==symmap? '?':'/'); + } + } + if (printcol==0 && modifier != 'a' && modifier != 'A') + dprint("\t\t"); + switch(modifier) { + + case SPC: + case TB: + dotinc = 0; + break; + + case 't': + case 'T': + dprint("%*t", fcount); + dotinc = 0; + return(fp); + + case 'a': + symoff(buf, sizeof(buf), dot, CANY); + dprint("%s%c%16t", buf, map==symmap? '?':'/'); + dotinc = 0; + break; + + case 'A': + dprint("%#lux%10t", dot); + dotinc = 0; + break; + + case 'p': + if (get4(map, dot, &u4) < 0) + error("%r"); + w = u4; + symoff(buf, sizeof(buf), w, CANY); + dprint("%s%16t", buf); + dotinc = mach->szaddr; + break; + + case 'u': + case 'd': + case 'x': + case 'o': + case 'q': + if (literal) + u2 = (ushort) dot; + else if (get2(map, dot, &u2) < 0) + error("%r"); + w = u2; + dotinc = 2; + if (c == 'u') + dprint("%-8lud", w); + else if (c == 'x') + dprint("%-8#lux", w); + else if (c == 'd') + dprint("%-8ld", w); + else if (c == 'o') + dprint("%-8#luo", w); + else if (c == 'q') + dprint("%-8#lo", w); + break; + + case 'U': + case 'D': + case 'X': + case 'O': + case 'Q': + if (literal) + u4 = (long) dot; + else if (get4(map, dot, &u4) < 0) + error("%r"); + dotinc = 4; + if (c == 'U') + dprint("%-16lud", u4); + else if (c == 'X') + dprint("%-16#lux", u4); + else if (c == 'D') + dprint("%-16ld", u4); + else if (c == 'O') + dprint("%-#16luo", u4); + else if (c == 'Q') + dprint("%-#16lo", u4); + break; + case 'Z': + case 'V': + case 'Y': + if (literal) + v = dot; + else if (get8(map, dot, &u8) < 0) + error("%r"); + dotinc = 8; + if (c == 'Y') + dprint("%-20#llux", u8); + else if (c == 'V') + dprint("%-20lld", u8); + else if (c == 'Z') + dprint("%-20llud", u8); + break; + case 'B': + case 'b': + case 'c': + case 'C': + if (literal) + ch = (uchar) dot; + else if (get1(map, dot, &ch, 1) < 0) + error("%r"); + if (modifier == 'C') + printesc(ch); + else if (modifier == 'B' || modifier == 'b') + dprint("%-8#lux", (long) ch); + else + printc(ch); + dotinc = 1; + break; + + case 'r': + if (literal) + sh = (ushort) dot; + else if (get2(map, dot, &sh) < 0) + error("%r"); + dprint("%C", sh); + dotinc = 2; + break; + + case 'R': + if (literal) { + sp = (u16int*)(void*)˙ + dprint("%C%C", sp[0], sp[1]); + endline(); + dotinc = 4; + break; + } + savdot=dot; + while ((i = get2(map, dot, &u2) > 0) && u2) { + dot=inkdot(2); + dprint("%C", u2); + endline(); + } + if (i < 0) + error("%r"); + dotinc = dot-savdot+2; + dot=savdot; + break; + + case 's': + if (literal) { + cp = (uchar*)(void*)˙ + for (i = 0; i < 4; i++) + buf[i] = cp[i]; + buf[i] = 0; + dprint("%s", buf); + endline(); + dotinc = 4; + break; + } + savdot = dot; + for(;;){ + i = 0; + do{ + if (get1(map, dot, (uchar*)(void*)&buf[i], 1) < 0) + error("%r"); + dot = inkdot(1); + i++; + }while(!fullrune(buf, i)); + if(buf[0] == 0) + break; + buf[i] = 0; + dprint("%s", buf); + endline(); + } + dotinc = dot-savdot+1; + dot = savdot; + break; + + case 'S': + if (literal) { + cp = (uchar*) ˙ + for (i = 0; i < 4; i++) + printesc(cp[i]); + endline(); + dotinc = 4; + break; + } + savdot=dot; + while ((i = get1(map, dot, &ch, 1) > 0) && ch) { + dot=inkdot(1); + printesc(ch); + endline(); + } + if (i < 0) + error("%r"); + dotinc = dot-savdot+1; + dot=savdot; + break; + + + case 'I': + case 'i': + dotinc = mach->das(map, dot, modifier, buf, sizeof(buf)); + if (dotinc < 0) + error("%r"); + dprint("%s\n", buf); + break; + + case 'M': + dotinc = mach->hexinst(map, dot, buf, sizeof(buf)); + if (dotinc < 0) + error("%r"); + dprint("%s", buf); + if (*fp) { + dotinc = 0; + dprint("%48t"); + } else + dprint("\n"); + break; + + case 'f': + /* BUG: 'f' and 'F' assume szdouble is sizeof(vlong) in the literal case */ + if (literal) { + v = mach->swap8((ulong)dot); + memmove(buf, &v, mach->szfloat); + }else if (get1(map, dot, (uchar*)buf, mach->szfloat) < 0) + error("%r"); + mach->ftoa32(buf, sizeof(buf), (void*) buf); + dprint("%s\n", buf); + dotinc = mach->szfloat; + break; + + case 'F': + /* BUG: 'f' and 'F' assume szdouble is sizeof(vlong) in the literal case */ + if (literal) { + v = mach->swap8(dot); + memmove(buf, &v, mach->szdouble); + }else if (get1(map, dot, (uchar*)buf, mach->szdouble) < 0) + error("%r"); + mach->ftoa64(buf, sizeof(buf), (void*) buf); + dprint("%s\n", buf); + dotinc = mach->szdouble; + break; + + case 'n': + case 'N': + printc('\n'); + dotinc=0; + break; + + case '"': + dotinc=0; + while (*fp != '"' && *fp) + printc(*fp++); + if (*fp) + fp++; + break; + + case '^': + dot=inkdot(-dotinc*fcount); + return(fp); + + case '+': + dot=inkdot((WORD)fcount); + return(fp); + + case '-': + dot=inkdot(-(WORD)fcount); + return(fp); + + case 'z': + if (findsym(locaddr(dot), CTEXT, &s) >= 0) + dprint("%s() ", s.name); + printsource(dot); + printc(EOR); + return fp; + + default: + error("bad modifier"); + } + if (map->seg[0].fd >= 0) + dot=inkdot(dotinc); + fcount--; + endline(); + } + + return(fp); +} + +void +printesc(int c) +{ + static char hex[] = "0123456789abcdef"; + + if (c < SPC || c >= 0177) + dprint("\\x%c%c", hex[(c&0xF0)>>4], hex[c&0xF]); + else + printc(c); +} + +ADDR +inkdot(WORD incr) +{ + ADDR newdot; + + newdot=dot+incr; + if ((incr >= 0 && newdot < dot) + || (incr < 0 && newdot > dot)) + error("address wraparound"); + return(newdot); +} diff --git a/src/cmd/db/input.c b/src/cmd/db/input.c new file mode 100644 index 00000000..8cd091b0 --- /dev/null +++ b/src/cmd/db/input.c @@ -0,0 +1,169 @@ +/* + * + * debugger + * + */ + +#include "defs.h" +#include "fns.h" + +Rune line[LINSIZ]; +extern int infile; +Rune *lp; +int peekc,lastc = EOR; +int eof; + +/* input routines */ + +int +eol(int c) +{ + return(c==EOR || c==';'); +} + +int +rdc(void) +{ + do { + readchar(); + } while (lastc==SPC || lastc==TB); + return(lastc); +} + +void +reread(void) +{ + peekc = lastc; +} + +void +clrinp(void) +{ + flush(); + lp = 0; + peekc = 0; +} + +int +readrune(int fd, Rune *r) +{ + char buf[UTFmax]; + int i; + + for(i=0; i<UTFmax && !fullrune(buf, i); i++) + if(read(fd, buf+i, 1) <= 0) + return -1; + chartorune(r, buf); + return 1; +} + +int +readchar(void) +{ + Rune *p; + + if (eof) + lastc=0; + else if (peekc) { + lastc = peekc; + peekc = 0; + } + else { + if (lp==0) { + for (p = line; p < &line[LINSIZ-1]; p++) { + eof = readrune(infile, p) <= 0; + if (mkfault) { + eof = 0; + error(0); + } + if (eof) { + p--; + break; + } + if (*p == EOR) { + if (p <= line) + break; + if (p[-1] != '\\') + break; + p -= 2; + } + } + p[1] = 0; + lp = line; + } + if ((lastc = *lp) != 0) + lp++; + } + return(lastc); +} + +int +nextchar(void) +{ + if (eol(rdc())) { + reread(); + return(0); + } + return(lastc); +} + +int +quotchar(void) +{ + if (readchar()=='\\') + return(readchar()); + else if (lastc=='\'') + return(0); + else + return(lastc); +} + +void +getformat(char *deformat) +{ + char *fptr; + BOOL quote; + Rune r; + + fptr=deformat; + quote=FALSE; + while ((quote ? readchar()!=EOR : !eol(readchar()))){ + r = lastc; + fptr += runetochar(fptr, &r); + if (lastc == '"') + quote = ~quote; + } + lp--; + if (fptr!=deformat) + *fptr = '\0'; +} + +/* + * check if the input line if of the form: + * <filename>:<digits><verb> ... + * + * we handle this case specially because we have to look ahead + * at the token after the colon to decide if it is a file reference + * or a colon-command with a symbol name prefix. + */ + +int +isfileref(void) +{ + Rune *cp; + + for (cp = lp-1; *cp && !strchr(CMD_VERBS, *cp); cp++) + if (*cp == '\\' && cp[1]) /* escape next char */ + cp++; + if (*cp && cp > lp-1) { + while (*cp == ' ' || *cp == '\t') + cp++; + if (*cp++ == ':') { + while (*cp == ' ' || *cp == '\t') + cp++; + if (isdigit(*cp)) + return 1; + } + } + return 0; +} diff --git a/src/cmd/db/main.c b/src/cmd/db/main.c new file mode 100644 index 00000000..8e574037 --- /dev/null +++ b/src/cmd/db/main.c @@ -0,0 +1,262 @@ +/* + * db - main command loop and error/interrupt handling + */ +#include "defs.h" +#include "fns.h" + +int wtflag = OREAD; +BOOL kflag; + +BOOL mkfault; +ADDR maxoff; + +int xargc; /* bullshit */ + +extern BOOL executing; +extern int infile; +int exitflg; +extern int eof; + +int alldigs(char*); +void fault(void*, char*); + +extern char *Ipath; +jmp_buf env; +static char *errmsg; + +Fhdr *symhdr, *corhdr; + +void +usage(void) +{ + fprint(2, "usage: db [-kw] [-m machine] [-I dir] [symfile] [pid]\n"); + exits("usage"); +} + +void +main(int argc, char **argv) +{ + int i, omode; + char *s; + char *name; + Fhdr *hdr; + + name = 0; + outputinit(); + maxoff = MAXOFF; + omode = OREAD; + ARGBEGIN{ + default: + usage(); + case 'A': + abort(); + case 'k': + kflag = 1; + break; + case 'w': + omode = ORDWR; + break; + case 'I': + s = ARGF(); + if(s == 0) + dprint("missing -I argument\n"); + else + Ipath = s; + break; + case 'm': + name = ARGF(); + if(name == 0) + dprint("missing -m argument\n"); + break; + }ARGEND + + /* + * Unix and Plan 9 differ on what the right order of pid, text, and core is. + * I never remember anyway. Let's just accept them in any order. + */ + for(i=0; i<argc; i++){ + if(alldigs(argv[i])){ + if(pid){ + dprint("already have pid %d; ignoring pid %d\n", pid, argv[i]); + continue; + } + if(corhdr){ + dprint("already have core %s; ignoring pid %d\n", corfil, pid); + continue; + } + pid = atoi(argv[i]); + continue; + } + if((hdr = crackhdr(argv[i], omode)) == nil){ + dprint("crackhdr %s: %r\n", argv[i]); + continue; + } + dprint("%s: %s %s %s\n", argv[i], hdr->aname, hdr->mname, hdr->fname); + if(hdr->ftype == FCORE){ + if(pid){ + dprint("already have pid %d; ignoring core %s\n", pid, argv[i]); + uncrackhdr(hdr); + continue; + } + if(corhdr){ + dprint("already have core %s; ignoring core %s\n", corfil, argv[i]); + uncrackhdr(hdr); + continue; + } + corhdr = hdr; + corfil = argv[i]; + }else{ + if(symhdr){ + dprint("already have text %s; ignoring text %s\n", symfil, argv[i]); + uncrackhdr(hdr); + continue; + } + symhdr = hdr; + symfil = argv[i]; + } + } + + if(symhdr==nil){ + symfil = "a.out"; + if(pid){ + if((s = proctextfile(pid)) != nil){ + dprint("pid %d: text %s\n", pid, s); + symfil = s; + } + } + /* XXX pull command from core */ + + if((symhdr = crackhdr(symfil, omode)) == nil){ + dprint("crackhdr %s: %r\n", symfil); + symfil = nil; + } + } + + if(!mach) + mach = machcpu; + + /* + * Set up maps. + */ + symmap = allocmap(); + cormap = allocmap(); + if(symmap == nil || cormap == nil) + sysfatal("allocating maps: %r"); + + if(symhdr){ + if(mapfile(symhdr, 0, symmap, nil) < 0) + dprint("mapping %s: %r\n", symfil); + mapfile(symhdr, 0, cormap, nil); + } + + dotmap = dumbmap(-1); + + /* + * show initial state and drop into the execution loop. + */ + notify(fault); + setsym(); + if(setjmp(env) == 0){ + if (pid || corhdr) + setcor(); /* could get error */ + if (correg) { + dprint("%s\n", mach->exc(cormap, correg)); + printpc(); + } + } + + setjmp(env); + if (executing) + delbp(); + executing = FALSE; + for (;;) { + flushbuf(); + if (errmsg) { + dprint(errmsg); + printc('\n'); + errmsg = 0; + exitflg = 0; + } + if (mkfault) { + mkfault=0; + printc('\n'); + prints(DBNAME); + } + clrinp(); + rdc(); + reread(); + if (eof) { + if (infile == STDIN) + done(); + iclose(-1, 0); + eof = 0; + longjmp(env, 1); + } + exitflg = 0; + command(0, 0); + reread(); + if (rdc() != '\n') + error("newline expected"); + } +} + +int +alldigs(char *s) +{ + while(*s){ + if(*s<'0' || '9'<*s) + return 0; + s++; + } + return 1; +} + +void +done(void) +{ + if (pid) + endpcs(); + exits(exitflg? "error": 0); +} + +/* + * An error occurred; save the message for later printing, + * close open files, and reset to main command loop. + */ +void +error(char *n) +{ + errmsg = n; + iclose(0, 1); + oclose(); + flush(); + delbp(); + ending = 0; + longjmp(env, 1); +} + +void +errors(char *m, char *n) +{ + static char buf[128]; + + sprint(buf, "%s: %s", m, n); + error(buf); +} + +/* + * An interrupt occurred; + * seek to the end of the current file + * and remember that there was a fault. + */ +void +fault(void *a, char *s) +{ + USED(a); + if(strncmp(s, "interrupt", 9) == 0){ + seek(infile, 0L, 2); + mkfault++; + noted(NCONT); + } + noted(NDFLT); +} diff --git a/src/cmd/db/mkfile b/src/cmd/db/mkfile new file mode 100644 index 00000000..65b87977 --- /dev/null +++ b/src/cmd/db/mkfile @@ -0,0 +1,26 @@ +<$PLAN9/src/mkhdr + +TARG=db +OFILES=\ + command.$O\ + expr.$O\ + format.$O\ + input.$O\ + main.$O\ + output.$O\ + pcs.$O\ + runpcs.$O\ + regs.$O\ + trcrun.$O\ + print.$O\ + setup.$O\ + +HFILES=defs.h\ + fns.h\ + +SHORTLIB=mach bio 9 + +<$PLAN9/src/mkone + +CFLAGS=$CFLAGS -I../libmach2 + diff --git a/src/cmd/db/output.c b/src/cmd/db/output.c new file mode 100644 index 00000000..176cec28 --- /dev/null +++ b/src/cmd/db/output.c @@ -0,0 +1,159 @@ +/* + * + * debugger + * + */ + +#include "defs.h" +#include "fns.h" + +int printcol = 0; +int infile = STDIN; +int maxpos = MAXPOS; + +Biobuf bstdout; + +void +printc(int c) +{ + dprint("%c", c); +} + +/* was move to next f1-sized tab stop; now just print a tab */ +int +tconv(Fmt *f) +{ + return fmtstrcpy(f, "\t"); +} + +void +flushbuf(void) +{ + if (printcol != 0) + printc(EOR); +} + +void +prints(char *s) +{ + dprint("%s",s); +} + +void +newline(void) +{ + printc(EOR); +} + +#define MAXIFD 5 +struct { + int fd; + int r9; +} istack[MAXIFD]; +int ifiledepth; + +void +iclose(int stack, int err) +{ + if (err) { + if (infile) { + close(infile); + infile=STDIN; + } + while (--ifiledepth >= 0) + if (istack[ifiledepth].fd) + close(istack[ifiledepth].fd); + ifiledepth = 0; + } else if (stack == 0) { + if (infile) { + close(infile); + infile=STDIN; + } + } else if (stack > 0) { + if (ifiledepth >= MAXIFD) + error("$<< nested too deeply"); + istack[ifiledepth].fd = infile; + ifiledepth++; + infile = STDIN; + } else { + if (infile) { + close(infile); + infile=STDIN; + } + if (ifiledepth > 0) { + infile = istack[--ifiledepth].fd; + } + } +} + +void +oclose(void) +{ + flushbuf(); + Bterm(&bstdout); + Binit(&bstdout, 1, OWRITE); +} + +void +redirout(char *file) +{ + int fd; + + if (file == 0){ + oclose(); + return; + } + flushbuf(); + if ((fd = open(file, 1)) >= 0) + seek(fd, 0L, 2); + else if ((fd = create(file, 1, 0666)) < 0) + error("cannot create"); + Bterm(&bstdout); + Binit(&bstdout, fd, OWRITE); +} + +void +endline(void) +{ + + if (maxpos <= printcol) + newline(); +} + +void +flush(void) +{ + Bflush(&bstdout); +} + +int +dprint(char *fmt, ...) +{ + int n, w; + char *p; + char buf[4096]; + Rune r; + va_list arg; + + if(mkfault) + return -1; + va_start(arg, fmt); + n = vseprint(buf, buf+sizeof buf, fmt, arg) - buf; + va_end(arg); + Bwrite(&bstdout, buf, n); + for(p=buf; *p; p+=w){ + w = chartorune(&r, p); + if(r == '\n') + printcol = 0; + else + printcol++; + } + return n; +} + +void +outputinit(void) +{ + Binit(&bstdout, 1, OWRITE); + fmtinstall('t', tconv); +} diff --git a/src/cmd/db/pcs.c b/src/cmd/db/pcs.c new file mode 100644 index 00000000..b876f50a --- /dev/null +++ b/src/cmd/db/pcs.c @@ -0,0 +1,177 @@ +/* + * + * debugger + * + */ + +#include "defs.h" +#include "fns.h" + +char NOPCS[] = "no process"; + +/* sub process control */ + +void +subpcs(int modif) +{ + int check; + int runmode; + int keepnote; + int n, r; + ulong line, curr; + BKPT *bk; + char *comptr; + + runmode=SINGLE; + r = 0; + keepnote=0; + loopcnt=cntval; + switch (modif) { + + /* delete breakpoint */ + case 'd': + case 'D': + if ((bk=scanbkpt(dot)) == 0) + error("no breakpoint set"); + bk->flag=BKPTCLR; + return; + + /* set breakpoint */ + case 'b': + case 'B': + if (bk=scanbkpt(dot)) + bk->flag=BKPTCLR; + for (bk=bkpthead; bk; bk=bk->nxtbkpt) + if (bk->flag == BKPTCLR) + break; + if (bk==0) { + bk = (BKPT *)malloc(sizeof(*bk)); + if (bk == 0) + error("too many breakpoints"); + bk->nxtbkpt=bkpthead; + bkpthead=bk; + } + bk->loc = dot; + bk->initcnt = bk->count = cntval; + bk->flag = modif == 'b' ? BKPTSET : BKPTTMP; + check=MAXCOM-1; + comptr=bk->comm; + rdc(); + reread(); + do { + *comptr++ = readchar(); + } while (check-- && lastc!=EOR); + *comptr=0; + if(bk->comm[0] != EOR && cntflg == FALSE) + bk->initcnt = bk->count = HUGEINT; + reread(); + if (check) + return; + error("bkpt command too long"); + + /* exit */ + case 'k' : + case 'K': + if (pid == 0) + error(NOPCS); + dprint("%d: killed", pid); + pcsactive = 1; /* force 'kill' ctl */ + endpcs(); + return; + + /* run program */ + case 'r': + case 'R': + endpcs(); + setup(); + runmode = CONTIN; + break; + + /* single step */ + case 's': + if (pid == 0) { + setup(); + loopcnt--; + } + runmode=SINGLE; + keepnote=defval(1); + break; + case 'S': + if (pid == 0) { + setup(); + loopcnt--; + } + keepnote=defval(1); + if(pc2line(dbrget(cormap, mach->pc), &line) < 0) + error("%r"); + n = loopcnt; + dprint("%s: running\n", symfil); + flush(); + for (loopcnt = 1; n > 0; loopcnt = 1) { + r = runpcs(SINGLE, keepnote); + if(pc2line(dot, &curr) < 0) + error("%r"); + if (line != curr) { /* on a new line of c */ + line = curr; + n--; + } + } + loopcnt = 0; + break; + /* continue with optional note */ + case 'c': + case 'C': + if (pid==0) + error(NOPCS); + runmode=CONTIN; + keepnote=defval(1); + break; + + case 'n': /* deal with notes */ + if (pid==0) + error(NOPCS); + n=defval(-1); + if(n>=0 && n<nnote){ + nnote--; + memmove(note[n], note[n+1], (nnote-n)*sizeof(note[0])); + } + notes(); + return; + + case 'h': /* halt the current process */ + if (adrflg && adrval == 0) { + if (pid == 0) + error(NOPCS); + ungrab(); + } + else { + grab(); + dprint("stopped at%16t"); + goto Return; + } + return; + + case 'x': /* continue executing the current process */ + if (pid == 0) + error(NOPCS); + ungrab(); + return; + + default: + error("bad `:' command"); + } + + if (loopcnt>0) { + dprint("%s: running\n", symfil); + flush(); + r = runpcs(runmode,keepnote); + } + if (r) + dprint("breakpoint%16t"); + else + dprint("stopped at%16t"); + Return: + delbp(); + printpc(); + notes(); +} diff --git a/src/cmd/db/print.c b/src/cmd/db/print.c new file mode 100644 index 00000000..d136a78b --- /dev/null +++ b/src/cmd/db/print.c @@ -0,0 +1,406 @@ +/* + * + * debugger + * + */ +#include "defs.h" +#include "fns.h" + +extern int infile; +extern int outfile; +extern int maxpos; + +/* general printing routines ($) */ + +char *Ipath = INCDIR; +static int tracetype; +static void printfp(Map*, int); + +/* + * callback on stack trace + */ +static int +ptrace(Map *map, Regs *regs, ulong pc, ulong nextpc, Symbol *sym, int depth) +{ + char buf[512]; + + USED(map); + if(sym){ + dprint("%s(", sym->name); + printparams(sym, regs); + dprint(") "); + }else + dprint("%#lux ", pc); + printsource(pc); + + dprint(" called from "); + symoff(buf, 512, nextpc, CTEXT); + dprint("%s ", buf); +/* printsource(nextpc); */ + dprint("\n"); + if(tracetype == 'C' && sym) + printlocals(sym, regs); + return depth<40; +} + +static ulong *adrregvals; + +static int +adrrw(Regs *regs, char *name, ulong *val, int isr) +{ + int i; + + if((i = windindex(name)) == -1) + return correg->rw(correg, name, val, isr); + if(isr){ + *val = adrregvals[i]; + return 0; + } + werrstr("saved registers are immutable"); + return -1; +} + +Regs* +adrregs(void) +{ + int i; + static Regs r; + static u32int x; + + if(adrregvals== nil){ + adrregvals = malloc(mach->nwindreg*sizeof(adrregvals[0])); + if(adrregvals == nil) + error("%r"); + } + for(i=0; i<mach->nwindreg; i++){ + if(get4(cormap, adrval+4*i, &x) < 0) + error("%r"); + adrregvals[i] = x; + } + r.rw = adrrw; + return &r; +} + +void +printdollar(int modif) +{ + int i; + u32int u4; + BKPT *bk; + Symbol s; + int stack; + char *fname; + char buf[512]; + Regs *r; + + if (cntflg==0) + cntval = -1; + switch (modif) { + + case '<': + if (cntval == 0) { + while (readchar() != EOR) + ; + reread(); + break; + } + if (rdc() == '<') + stack = 1; + else { + stack = 0; + reread(); + } + fname = getfname(); + redirin(stack, fname); + break; + + case '>': + fname = getfname(); + redirout(fname); + break; + + case 'a': + attachprocess(); + break; + + case 'k': + kmsys(); + break; + + case 'q': + case 'Q': + done(); + + case 'w': + maxpos=(adrflg?adrval:MAXPOS); + break; + + case 'S': + printsym(); + break; + + case 's': + maxoff=(adrflg?adrval:MAXOFF); + break; + + case 'm': + printmap("? map", symmap); + printmap("/ map", cormap); + break; + + case 0: + case '?': + if (pid) + dprint("pid = %d\n",pid); + else + prints("no process\n"); + flushbuf(); + + case 'r': + case 'R': + printregs(modif); + return; + + case 'f': + case 'F': + printfp(cormap, modif); + return; + + case 'c': + case 'C': + tracetype = modif; + if (adrflg) + r = adrregs(); + else + r = correg; + if(stacktrace(cormap, correg, ptrace) <= 0) + error("no stack frame"); + break; + + /*print externals*/ + case 'e': + for (i = 0; indexsym(i, &s)>=0; i++) { + if (s.class==CDATA) + if (s.loc.type==LADDR) + if (get4(cormap, s.loc.addr, &u4) > 0) + dprint("%s/%12t%#lux\n", s.name, (ulong)u4); + } + break; + + /*print breakpoints*/ + case 'b': + case 'B': + for (bk=bkpthead; bk; bk=bk->nxtbkpt) + if (bk->flag) { + symoff(buf, 512, (WORD)bk->loc, CTEXT); + dprint(buf); + if (bk->count != 1) + dprint(",%d", bk->count); + dprint(":%c %s", bk->flag == BKPTTMP ? 'B' : 'b', bk->comm); + } + break; + + case 'M': + fname = getfname(); + if (machbyname(fname) == 0) + dprint("unknown name\n");; + break; + default: + error("bad `$' command"); + } + +} + +char * +getfname(void) +{ + static char fname[ARB]; + char *p; + + if (rdc() == EOR) { + reread(); + return (0); + } + p = fname; + do { + *p++ = lastc; + if (p >= &fname[ARB-1]) + error("filename too long"); + } while (rdc() != EOR); + *p = 0; + reread(); + return (fname); +} + +static void +printfp(Map *map, int modif) +{ + Regdesc *rp; + int i; + int ret; + char buf[512]; + + for (i = 0, rp = mach->reglist; rp->name; rp += ret) { + ret = 1; + if (!(rp->flags&RFLT)) + continue; + ret = fpformat(map, rp, buf, sizeof(buf), modif); + if (ret < 0) { + werrstr("Register %s: %r", rp->name); + error("%r"); + } + /* double column print */ + if (i&0x01) + dprint("%40t%-8s%-12s\n", rp->name, buf); + else + dprint("\t%-8s%-12s", rp->name, buf); + i++; + } +} + +void +redirin(int stack, char *file) +{ + char pfile[ARB]; + + if (file == 0) { + iclose(-1, 0); + return; + } + iclose(stack, 0); + if ((infile = open(file, 0)) < 0) { + strcpy(pfile, Ipath); + strcat(pfile, "/"); + strcat(pfile, file); + if ((infile = open(pfile, 0)) < 0) { + infile = STDIN; + error("cannot open"); + } + } +} + +void +printmap(char *s, Map *map) +{ + int i; + + if (!map) + return; + if (map == symmap) + dprint("%s%12t`%s'\n", s, symfil==nil ? "-" : symfil); + else if (map == cormap) + dprint("%s%12t`%s'\n", s, corfil==nil ? "-" : corfil); + else + dprint("%s\n", s); + for (i = 0; i < map->nseg; i++) { + dprint("%s%8t%-16#lux %-16#lux %-16#lux %s\n", map->seg[i].name, + map->seg[i].base, map->seg[i].base+map->seg[i].size, map->seg[i].offset, + map->seg[i].file ? map->seg[i].file : ""); + } +} + +/* + * dump the raw symbol table + */ +void +printsym(void) +{ + int i; + Symbol *sp, s; + + for (i=0; indexsym(i, &s)>=0; i++){ + sp = &s; + switch(sp->type) { + case 't': + case 'l': + dprint("%8#lux t %s\n", sp->loc.addr, sp->name); + break; + case 'T': + case 'L': + dprint("%8#lux T %s\n", sp->loc.addr, sp->name); + break; + case 'D': + case 'd': + case 'B': + case 'b': + case 'a': + case 'p': + case 'm': + dprint("%8#lux %c %s\n", sp->loc.addr, sp->type, sp->name); + break; + default: + break; + } + } +} + +#define STRINGSZ 128 + +/* + * print the value of dot as file:line + */ +void +printsource(long dot) +{ + char str[STRINGSZ]; + + if (fileline(dot, str, STRINGSZ) >= 0) + dprint("%s", str); +} + +void +printpc(void) +{ + char buf[512]; + ulong u; + + if(rget(correg, mach->pc, &u) < 0) + error("%r"); + dot = u; + if(dot){ + printsource((long)dot); + printc(' '); + symoff(buf, sizeof(buf), (long)dot, CTEXT); + dprint("%s/", buf); + if (mach->das(cormap, dot, 'i', buf, sizeof(buf)) < 0) + error("%r"); + dprint("%16t%s\n", buf); + } +} + +void +printlocals(Symbol *fn, Regs *regs) +{ + int i; + u32int v; + Symbol s; + + for (i = 0; indexlsym(fn, i, &s)>=0; i++) { + if (s.class != CAUTO) + continue; + if(lget4(cormap, correg, s.loc, &v) >= 0) + dprint("%8t%s.%s/%10t%#lux\n", fn->name, s.name, v); + else + dprint("%8t%s.%s/%10t?\n", fn->name, s.name); + } +} + +void +printparams(Symbol *fn, Regs *regs) +{ + int i; + Symbol s; + u32int v; + int first = 0; + + for (i = 0; indexlsym(fn, i, &s)>=0; i++) { + if (s.class != CPARAM) + continue; + if (first++) + dprint(", "); + if(lget4(cormap, correg, s.loc, &v) >= 0) + dprint("%s=%#lux", s.name, v); + else + dprint("%s=?", s.name); + } +} diff --git a/src/cmd/db/regs.c b/src/cmd/db/regs.c new file mode 100644 index 00000000..4a9a4426 --- /dev/null +++ b/src/cmd/db/regs.c @@ -0,0 +1,44 @@ +/* + * code to keep track of registers + */ + +#include "defs.h" +#include "fns.h" + +/* + * print the registers + */ +void +printregs(int c) +{ + Regdesc *rp; + int i; + ulong u; + + if(correg == nil){ + dprint("registers not mapped\n"); + return; + } + + for (i = 1, rp = mach->reglist; rp->name; rp++, i++) { + if ((rp->flags & RFLT)) { + if (c != 'R') + continue; + if (rp->format == '8' || rp->format == '3') + continue; + } + rget(correg, rp->name, &u); + if(rp->format == 'Y') + dprint("%-8s %-20#llux", rp->name, (uvlong)u); + else + dprint("%-8s %-12#lux", rp->name, (ulong)u); + if ((i % 3) == 0) { + dprint("\n"); + i = 0; + } + } + if (i != 1) + dprint("\n"); + dprint ("%s\n", mach->exc(cormap, correg)); + printpc(); +} diff --git a/src/cmd/db/runpcs.c b/src/cmd/db/runpcs.c new file mode 100644 index 00000000..4c05366b --- /dev/null +++ b/src/cmd/db/runpcs.c @@ -0,0 +1,205 @@ +/* + * + * debugger + * + */ + +#include "defs.h" +#include "fns.h" + +BKPT *bkpthead; + +BOOL bpin; + +int pid; +int nnote; +int ending; +char note[NNOTE][ERRMAX]; + +/* service routines for sub process control */ + +int +runpcs(int runmode, int keepnote) +{ + int rc; + BKPT *bkpt; + ADDR x; + + rc = 0; + if (adrflg) + rput(correg, mach->pc, dot); + if(rget(correg, mach->pc, &dot) < 0) + error("%r"); + flush(); + while (--loopcnt >= 0) { + if(loopcnt != 0) + printpc(); + if (runmode == SINGLE) { + bkpt = scanbkpt(dot); + if (bkpt) { + switch(bkpt->flag){ + case BKPTTMP: + bkpt->flag = BKPTCLR; + break; + case BKPTSKIP: + bkpt->flag = BKPTSET; + break; + } + } + runstep(dot, keepnote); + } else { + if(rget(correg, mach->pc, &x) < 0) + error("%r"); + if ((bkpt = scanbkpt(x)) != 0) { + execbkpt(bkpt, keepnote); + keepnote = 0; + } + setbp(); + runrun(keepnote); + } + keepnote = 0; + delbp(); + if(rget(correg, mach->pc, &dot) < 0) + error("%r"); + /* real note? */ + if (nnote > 0) { + keepnote = 1; + rc = 0; + continue; + } + bkpt = scanbkpt(dot); + if(bkpt == 0){ + keepnote = 0; + rc = 0; + continue; + } + /* breakpoint */ + if (bkpt->flag == BKPTTMP) + bkpt->flag = BKPTCLR; + else if (bkpt->flag == BKPTSKIP) { + execbkpt(bkpt, keepnote); + keepnote = 0; + loopcnt++; /* we didn't really stop */ + continue; + } + else { + bkpt->flag = BKPTSKIP; + --bkpt->count; + if ((bkpt->comm[0] == EOR || command(bkpt->comm, ':') != 0) + && bkpt->count != 0) { + execbkpt(bkpt, keepnote); + keepnote = 0; + loopcnt++; + continue; + } + bkpt->count = bkpt->initcnt; + } + rc = 1; + } + return(rc); +} + +/* + * finish the process off; + * kill if still running + */ + +void +endpcs(void) +{ + BKPT *bk; + + if(ending) + return; + ending = 1; + if (pid) { + if(pcsactive){ + killpcs(); + pcsactive = 0; + } + pid=0; + nnote=0; + for (bk=bkpthead; bk; bk = bk->nxtbkpt) + if (bk->flag == BKPTTMP) + bk->flag = BKPTCLR; + else if (bk->flag != BKPTCLR) + bk->flag = BKPTSET; + } + bpin = FALSE; + ending = 0; +} + +/* + * start up the program to be debugged in a child + */ + +void +setup(void) +{ + + nnote = 0; + startpcs(); + bpin = FALSE; + pcsactive = 1; +} + +/* + * skip over a breakpoint: + * remove breakpoints, then single step + * so we can put it back + */ +void +execbkpt(BKPT *bk, int keepnote) +{ + runstep(bk->loc, keepnote); + bk->flag = BKPTSET; +} + +/* + * find the breakpoint at adr, if any + */ + +BKPT * +scanbkpt(ADDR adr) +{ + BKPT *bk; + + for (bk = bkpthead; bk; bk = bk->nxtbkpt) + if (bk->flag != BKPTCLR && bk->loc == adr) + break; + return(bk); +} + +/* + * remove all breakpoints from the process' address space + */ + +void +delbp(void) +{ + BKPT *bk; + + if (bpin == FALSE || pid == 0) + return; + for (bk = bkpthead; bk; bk = bk->nxtbkpt) + if (bk->flag != BKPTCLR) + bkput(bk, 0); + bpin = FALSE; +} + +/* + * install all the breakpoints + */ + +void +setbp(void) +{ + BKPT *bk; + + if (bpin == TRUE || pid == 0) + return; + for (bk = bkpthead; bk; bk = bk->nxtbkpt) + if (bk->flag != BKPTCLR) + bkput(bk, 1); + bpin = TRUE; +} diff --git a/src/cmd/db/setup.c b/src/cmd/db/setup.c new file mode 100644 index 00000000..02871e2b --- /dev/null +++ b/src/cmd/db/setup.c @@ -0,0 +1,145 @@ +/* + * init routines + */ +#include "defs.h" +#include "fns.h" + +char *symfil; +char *corfil; + +Map *symmap; +Map *cormap; +Regs *correg; +Map *dotmap; + +void +setsym(void) +{ + if(symhdr && syminit(symhdr) < 0) + dprint("syminit: %r\n"); +/* + Symbol s; + if (mach->sbreg && lookup(0, mach->sbreg, &s) < 0) + mach->sb = s.loc.addr; +*/ +} + +void +setcor(void) +{ + unmapproc(cormap); + unmapfile(corhdr, cormap); + free(correg); + correg = nil; + + if (pid > 0) { + if (mapproc(pid, cormap, &correg) < 0) + dprint("mapproc %d: %r\n", pid); + } else { + if (corhdr) { + if (mapfile(corhdr, 0, cormap, &correg) < 0) + dprint("mapfile %s: %r\n", corfil); + } else + dprint("no core image\n"); + } + kmsys(); + return; +} + +Map* +dumbmap(int fd) +{ + Map *dumb; + Seg s; + + dumb = allocmap(); + memset(&s, 0, sizeof s); + s.fd = fd; + s.base = 0; + s.offset = 0; + s.size = 0xFFFFFFFF; + s.name = "data"; + s.file = "<dumb>"; + if(addseg(dumb, s) < 0){ + freemap(dumb); + return nil; + } + if(mach == nil) + mach = machcpu; + return dumb; +} + +/* + * set up maps for a direct process image (/proc) + */ +void +cmdmap(Map *map) +{ + int i; + char name[MAXSYM]; + + rdc(); + readsym(name); + i = findseg(map, name, nil); + if (i < 0) /* not found */ + error("Invalid map name"); + + if (expr(0)) { + // if (strcmp(name, "text") == 0) + // textseg(expv, &fhdr); + map->seg[i].base = expv; + } else + error("Invalid base address"); + if (expr(0)) + map->seg[i].size = expv - map->seg[i].base; + else + error("Invalid end address"); + if (expr(0)) + map->seg[i].offset = expv; + else + error("Invalid file offset"); +/* + if (rdc()=='?' && map == cormap) { + if (fcor) + close(fcor); + fcor=fsym; + corfil = symfil; + cormap = symmap; + } else if (lastc == '/' && map == symmap) { + if (fsym) + close(fsym); + fsym=fcor; + symfil=corfil; + symmap=cormap; + } else + reread(); +*/ +} + +void +kmsys(void) +{ + int i; + + i = findseg(symmap, "text", symfil); + if (i >= 0) { + symmap->seg[i].base = symmap->seg[i].base&~mach->ktmask; + symmap->seg[i].size = -symmap->seg[i].base; + } + i = findseg(symmap, "data", symfil); + if (i >= 0) { + symmap->seg[i].base = symmap->seg[i].base&~mach->ktmask; + symmap->seg[i].size = -symmap->seg[i].base; + } +} + +void +attachprocess(void) +{ + if (!adrflg) { + dprint("used pid$a\n"); + return; + } + pid = adrval; + setcor(); +} diff --git a/src/cmd/db/trcrun.c b/src/cmd/db/trcrun.c new file mode 100644 index 00000000..807f902e --- /dev/null +++ b/src/cmd/db/trcrun.c @@ -0,0 +1,288 @@ +/* + * functions for running the debugged process + */ + +#include "defs.h" +#include "fns.h" + + +int child; +int msgfd = -1; +int notefd = -1; +int pcspid = -1; +int pcsactive = 0; + +void +setpcs(void) +{ + char buf[128]; + + if(pid && pid != pcspid){ + if(msgfd >= 0){ + close(msgfd); + msgfd = -1; + } + if(notefd >= 0){ + close(notefd); + notefd = -1; + } + pcspid = -1; + sprint(buf, "/proc/%d/ctl", pid); + msgfd = open(buf, OWRITE); + if(msgfd < 0) + error("can't open control file"); + sprint(buf, "/proc/%d/note", pid); + notefd = open(buf, ORDWR); + if(notefd < 0) + error("can't open note file"); + pcspid = pid; + } +} + +void +msgpcs(char *msg) +{ + char err[ERRMAX]; + + setpcs(); + if(write(msgfd, msg, strlen(msg)) < 0 && !ending){ + errstr(err, sizeof err); + if(strcmp(err, "interrupted") != 0) + endpcs(); + errors("can't write control file", err); + } +} + +/* + * empty the note buffer and toss pending breakpoint notes + */ +void +unloadnote(void) +{ + char err[ERRMAX]; + + setpcs(); + for(; nnote<NNOTE; nnote++){ + switch(read(notefd, note[nnote], sizeof note[nnote])){ + case -1: + errstr(err, sizeof err); + if(strcmp(err, "interrupted") != 0) + endpcs(); + errors("can't read note file", err); + case 0: + return; + } + note[nnote][ERRMAX-1] = '\0'; + if(strncmp(note[nnote], "sys: breakpoint", 15) == 0) + --nnote; + } +} + +/* + * reload the note buffer + */ +void +loadnote(void) +{ + int i; + char err[ERRMAX]; + + setpcs(); + for(i=0; i<nnote; i++){ + if(write(notefd, note[i], strlen(note[i])) < 0){ + errstr(err, sizeof err); + if(strcmp(err, "interrupted") != 0) + endpcs(); + errors("can't write note file", err); + } + } + nnote = 0; +} + +void +notes(void) +{ + int n; + + if(nnote == 0) + return; + dprint("notes:\n"); + for(n=0; n<nnote; n++) + dprint("%d:\t%s\n", n, note[n]); +} + +void +killpcs(void) +{ + msgpcs("kill"); +} + +void +grab(void) +{ + flush(); + msgpcs("stop"); + bpwait(); +} + +void +ungrab(void) +{ + msgpcs("start"); +} + +void +doexec(void) +{ + char *argl[MAXARG]; + char args[LINSIZ]; + char *p; + char **ap; + char *thisarg; + + ap = argl; + p = args; + *ap++ = symfil; + for (rdc(); lastc != EOR;) { + thisarg = p; + if (lastc == '<' || lastc == '>') { + *p++ = lastc; + rdc(); + } + while (lastc != EOR && lastc != SPC && lastc != TB) { + *p++ = lastc; + readchar(); + } + if (lastc == SPC || lastc == TB) + rdc(); + *p++ = 0; + if (*thisarg == '<') { + close(0); + if (open(&thisarg[1], OREAD) < 0) { + print("%s: cannot open\n", &thisarg[1]); + _exits(0); + } + } + else if (*thisarg == '>') { + close(1); + if (create(&thisarg[1], OWRITE, 0666) < 0) { + print("%s: cannot create\n", &thisarg[1]); + _exits(0); + } + } + else + *ap++ = thisarg; + } + *ap = 0; + exec(symfil, argl); + perror(symfil); +} + +char procname[100]; + +void +startpcs(void) +{ + if ((pid = fork()) == 0) { + pid = getpid(); + msgpcs("hang"); + doexec(); + exits(0); + } + + if (pid == -1) + error("can't fork"); + child++; + sprint(procname, "/proc/%d/mem", pid); + corfil = procname; + msgpcs("waitstop"); + bpwait(); + if (adrflg) + rput(correg, mach->pc, adrval); + while (rdc() != EOR) + ; + reread(); +} + +void +runstep(ulong loc, int keepnote) +{ + int nfoll; + ulong foll[3]; + BKPT bkpt[3]; + int i; + + if(mach->foll == 0){ + dprint("stepping unimplemented; assuming not a branch\n"); + nfoll = 1; + foll[0] = loc+mach->pcquant; + }else { + nfoll = mach->foll(cormap, correg, loc, foll); + if (nfoll < 0) + error("%r"); + } + memset(bkpt, 0, sizeof bkpt); + for(i=0; i<nfoll; i++){ + if(foll[i] == loc) + error("can't single step: next instruction is dot"); + bkpt[i].loc = foll[i]; + bkput(&bkpt[i], 1); + } + runrun(keepnote); + for(i=0; i<nfoll; i++) + bkput(&bkpt[i], 0); +} + +void +bpwait(void) +{ + setcor(); + unloadnote(); +} + +void +runrun(int keepnote) +{ + int on; + + on = nnote; + unloadnote(); + if(on != nnote){ + notes(); + error("not running: new notes pending"); + } + if(keepnote) + loadnote(); + else + nnote = 0; + flush(); + msgpcs("startstop"); + bpwait(); +} + +void +bkput(BKPT *bp, int install) +{ + char buf[256]; + ulong loc; + int ret; + + errstr(buf, sizeof buf); +/* + if(mach->bpfix) + loc = (*mach->bpfix)(bp->loc); + else +*/ + loc = bp->loc; + if(install){ + ret = get1(cormap, loc, bp->save, mach->bpsize); + if (ret > 0) + ret = put1(cormap, loc, mach->bpinst, mach->bpsize); + }else + ret = put1(cormap, loc, bp->save, mach->bpsize); + if(ret < 0){ + sprint(buf, "can't set breakpoint at %#llux: %r", bp->loc); + print(buf); + read(0, buf, 100); + } +} |