diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/db |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/db')
-rwxr-xr-x | sys/src/cmd/db/command.c | 310 | ||||
-rwxr-xr-x | sys/src/cmd/db/defs.h | 110 | ||||
-rwxr-xr-x | sys/src/cmd/db/expr.c | 378 | ||||
-rwxr-xr-x | sys/src/cmd/db/fns.h | 89 | ||||
-rwxr-xr-x | sys/src/cmd/db/format.c | 386 | ||||
-rwxr-xr-x | sys/src/cmd/db/input.c | 166 | ||||
-rwxr-xr-x | sys/src/cmd/db/main.c | 210 | ||||
-rwxr-xr-x | sys/src/cmd/db/mkfile | 22 | ||||
-rwxr-xr-x | sys/src/cmd/db/output.c | 160 | ||||
-rwxr-xr-x | sys/src/cmd/db/pcs.c | 175 | ||||
-rwxr-xr-x | sys/src/cmd/db/print.c | 374 | ||||
-rwxr-xr-x | sys/src/cmd/db/regs.c | 131 | ||||
-rwxr-xr-x | sys/src/cmd/db/runpcs.c | 199 | ||||
-rwxr-xr-x | sys/src/cmd/db/setup.c | 208 | ||||
-rwxr-xr-x | sys/src/cmd/db/trcrun.c | 286 |
15 files changed, 3204 insertions, 0 deletions
diff --git a/sys/src/cmd/db/command.c b/sys/src/cmd/db/command.c new file mode 100755 index 000000000..c45f306df --- /dev/null +++ b/sys/src/cmd/db/command.c @@ -0,0 +1,310 @@ +/* + * + * debugger + * + */ + +#include "defs.h" +#include "fns.h" + +char BADEQ[] = "unexpected `='"; + +BOOL executing; +extern Rune *lp; + +char eqformat[ARB] = "z"; +char stformat[ARB] = "zMi"; + +ADDR ditto; + +ADDR dot; +int dotinc; +WORD adrval, cntval, loopcnt; +int adrflg, cntflg; + +/* command decoding */ + +command(char *buf, int defcom) +{ + char *reg; + char savc; + Rune *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=(Rune*)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(cormap, reg, dot); + else + error("bad variable"); + break; + + case '!': + lastcom=savecom; + shell(); + break; + + case '$': + lastcom=savecom; + printtrace(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) { + snprint(buf, sizeof(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) +{ + ulong 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 = (char*)lp; + + while (lastc!=EOR) + rdc(); + if ((unixpid=fork())==0) { + *lp=0; + execl("/bin/rc", "rc", "-c", argp, nil); + 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/sys/src/cmd/db/defs.h b/sys/src/cmd/db/defs.h new file mode 100755 index 000000000..5a12ba4cc --- /dev/null +++ b/sys/src/cmd/db/defs.h @@ -0,0 +1,110 @@ +/* + * adb - common definitions + * something of a grab-bag + */ + +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <ctype.h> + +#include <mach.h> + +typedef ulong WORD; +typedef uvlong 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 */ + +typedef struct bkpt BKPT; +struct bkpt { + ADDR loc; + uchar save[4]; + int count; + int initcnt; + int flag; + char comm[MAXCOM]; + BKPT *nxtbkpt; +}; + +#define BADREG (-1) + +/* + * common globals + */ + +extern WORD adrval; +extern uvlong 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 int dotinc; + +extern int xargc; + +extern BOOL wtflag; +extern char *corfil, *symfil; +extern int fcor, fsym; +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 Map *cormap, *symmap, *dotmap; + +extern BKPT *bkpthead; +extern int kflag; +extern int lastc, peekc; diff --git a/sys/src/cmd/db/expr.c b/sys/src/cmd/db/expr.c new file mode 100755 index 000000000..d51079371 --- /dev/null +++ b/sys/src/cmd/db/expr.c @@ -0,0 +1,378 @@ +/* + * + * debugger + * + */ + +#include "defs.h" +#include "fns.h" + +static long round(long, long); + +extern ADDR ditto; +uvlong 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); +} + +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 = round(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); +} + +term(int a) +{ /* item | monadic item | (expr) | */ + ADDR e; + + switch ((int)readchar()) { + + case '*': + term(a|1); + if (geta(cormap, expv, &e) < 0) + error("%r"); + expv = e; + return(1); + + case '@': + term(a|1); + if (geta(symmap, expv, &e) < 0) + error("%r"); + expv = e; + 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)); + } +} + +item(int a) +{ /* name [ . local ] | number | . | ^ | <register | 'x | | */ + char *base; + char savc; + uvlong e; + 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 */ + expv = file2pc(gsym, expv); + if (expv == -1) + error("%r"); + 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, gsym, lsym, &e, rget) < 0) + error("%r"); + expv = e; + } + else { + if (lookup(0, gsym, &s) == 0) + error("symbol not found"); + expv = s.value; + } + reread(); + } else if (getnum(readchar)) { + ; + } else if (lastc=='.') { + readchar(); + if (!symchar(0) && lastc != '.') { + expv = dot; + } else { + if (findsym(rget(cormap, mach->pc), CTEXT, &s) == 0) + error("no current function"); + if (lastc == '.') { + lsym[0] = '.'; + readchar(); + readsym(lsym+1); + } else + readsym(lsym); + if (localaddr(cormap, s.name, lsym, &e, rget) < 0) + error("%r"); + expv = e; + } + 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 = rget(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 */ +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(); +} + +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); +} + +symchar(int dig) +{ + if (lastc=='\\') { + readchar(); + return(TRUE); + } + return(isalpha(lastc) || lastc>0x80 || lastc=='_' || dig && isdigit(lastc)); +} + +static long +round(long a, long b) +{ + long w; + + w = (a/b)*b; + if (a!=w) + w += b; + return(w); +} diff --git a/sys/src/cmd/db/fns.h b/sys/src/cmd/db/fns.h new file mode 100755 index 000000000..6f6b38d15 --- /dev/null +++ b/sys/src/cmd/db/fns.h @@ -0,0 +1,89 @@ +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); +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 flush(void); +void flushbuf(void); +char* getfname(void); +void getformat(char*); +int getnum(int (*)(void)); +void grab(void); +void iclose(int, int); +ADDR inkdot(int); +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 printesc(int); +void printlocals(Symbol *, ADDR); +void printmap(char*, Map*); +void printparams(Symbol *, ADDR); +void printpc(void); +void printregs(int); +void prints(char*); +void printsource(ADDR); +void printsym(void); +void printsyscall(void); +void printtrace(int); +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); +uvlong rget(Map*, char*); +Reglist* rname(char*); +void rput(Map*, char*, vlong); +int runpcs(int, int); +void runrun(int); +void runstep(uvlong, 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); + +#pragma varargck argpos dprint 1 +#pragma varargck type "t" void diff --git a/sys/src/cmd/db/format.c b/sys/src/cmd/db/format.c new file mode 100755 index 000000000..78bc5f65b --- /dev/null +++ b/sys/src/cmd/db/format.c @@ -0,0 +1,386 @@ +/* + * + * 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 + */ + uvlong v; + ulong w; + ADDR savdot; + 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("%#llux%10t", dot); + dotinc = 0; + break; + + case 'p': + if (get4(map, dot, &w) < 0) + error("%r"); + 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) + sh = (ushort) dot; + else if (get2(map, dot, &sh) < 0) + error("%r"); + w = sh; + 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) + w = (long) dot; + else if (get4(map, dot, &w) < 0) + error("%r"); + dotinc = 4; + if (c == 'U') + dprint("%-16lud", w); + else if (c == 'X') + dprint("%-16#lux", w); + else if (c == 'D') + dprint("%-16ld", w); + else if (c == 'O') + dprint("%-#16luo", w); + else if (c == 'Q') + dprint("%-#16lo", w); + break; + case 'Z': + case 'V': + case 'Y': + if (literal) + v = dot; + else if (get8(map, dot, &v) < 0) + error("%r"); + dotinc = 8; + if (c == 'Y') + dprint("%-20#llux", v); + else if (c == 'V') + dprint("%-20lld", v); + else if (c == 'Z') + dprint("%-20llud", v); + 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 = (ushort*) ˙ + dprint("%C%C", sp[0], sp[1]); + endline(); + dotinc = 4; + break; + } + savdot=dot; + while ((i = get2(map, dot, &sh) > 0) && sh) { + dot=inkdot(2); + dprint("%C", sh); + endline(); + } + if (i < 0) + error("%r"); + dotinc = dot-savdot+2; + dot=savdot; + break; + + case 's': + if (literal) { + cp = (uchar*) ˙ + 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*)&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': + i = machdata->das(map, dot, modifier, buf, sizeof(buf)); + if (i < 0) + error("%r"); + dotinc = i; + dprint("%s\n", buf); + break; + + case 'M': + i = machdata->hexinst(map, dot, buf, sizeof(buf)); + if (i < 0) + error("%r"); + dotinc = i; + 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 = machdata->swav(dot); + memmove(buf, &v, mach->szfloat); + }else if (get1(map, dot, (uchar*)buf, mach->szfloat) < 0) + error("%r"); + machdata->sftos(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 = machdata->swav(dot); + memmove(buf, &v, mach->szdouble); + }else if (get1(map, dot, (uchar*)buf, mach->szdouble) < 0) + error("%r"); + machdata->dftos(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(dot, CTEXT, &s)) + 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(int incr) +{ + ADDR newdot; + + newdot=dot+incr; + if ((incr >= 0 && newdot < dot) + || (incr < 0 && newdot > dot)) + error("address wraparound"); + return(newdot); +} diff --git a/sys/src/cmd/db/input.c b/sys/src/cmd/db/input.c new file mode 100755 index 000000000..0d2470497 --- /dev/null +++ b/sys/src/cmd/db/input.c @@ -0,0 +1,166 @@ +/* + * + * debugger + * + */ + +#include "defs.h" +#include "fns.h" + +Rune line[LINSIZ]; +extern int infile; +Rune *lp; +int peekc,lastc = EOR; +int eof; + +/* input routines */ + +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); +} + +nextchar(void) +{ + if (eol(rdc())) { + reread(); + return(0); + } + return(lastc); +} + +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/sys/src/cmd/db/main.c b/sys/src/cmd/db/main.c new file mode 100755 index 000000000..4c9eb4287 --- /dev/null +++ b/sys/src/cmd/db/main.c @@ -0,0 +1,210 @@ +/* + * 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; + +void +main(int argc, char **argv) +{ + char b1[100]; + char b2[100]; + char *s; + char *name; + + name = 0; + outputinit(); + maxoff = MAXOFF; + ARGBEGIN{ + case 'k': + kflag = 1; + break; + case 'w': + wtflag = ORDWR; /* suitable for open() */ + 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 + symfil = 0; + corfil = 0; + if (argc > 0 && !alldigs(argv[0])) { + symfil = argv[0]; + argv++; + argc--; + } + if(argc==1 && alldigs(argv[0])){ + char *cpu, *p, *q; + + pid = atoi(argv[0]); + pcsactive = 0; + if (!symfil) { + if(kflag){ + cpu = getenv("cputype"); + if(cpu == 0){ + cpu = "386"; + dprint("$cputype not set; assuming %s\n", cpu); + } + p = getenv("terminal"); + if(p==0 || (p=strchr(p, ' '))==0 || p[1]==' ' || p[1]==0){ + strcpy(b1, "/386/9pc"); + dprint("missing or bad $terminal; assuming %s\n", b1); + }else{ + p++; + q = strchr(p, ' '); + if(q) + *q = 0; + sprint(b1, "/%s/9%s", cpu, p); + + } + }else + sprint(b1, "/proc/%s/text", argv[0]); + symfil = b1; + } + sprint(b2, "/proc/%s/mem", argv[0]); + corfil = b2; + } else if (argc > 0) { + fprint(2, "Usage: db [-kw] [-m machine] [-I dir] [symfile] [pid]\n"); + exits("usage"); + } + if (!symfil) + symfil = "8.out"; + xargc = argc; + notify(fault); + setsym(); + dotmap = dumbmap(-1); + if (name && machbyname(name) == 0) + dprint ("unknown machine %s", name); + dprint("%s binary\n", mach->name); + if(setjmp(env) == 0){ + if (corfil) { + setcor(); /* could get error */ + dprint("%s\n", machdata->excep(cormap, rget)); + 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/sys/src/cmd/db/mkfile b/sys/src/cmd/db/mkfile new file mode 100755 index 000000000..90a6de2fa --- /dev/null +++ b/sys/src/cmd/db/mkfile @@ -0,0 +1,22 @@ +</$objtype/mkfile + +TARG=db +OFILES=\ + command.$O\ + expr.$O\ + format.$O\ + input.$O\ + main.$O\ + output.$O\ + pcs.$O\ + print.$O\ + runpcs.$O\ + setup.$O\ + regs.$O\ + trcrun.$O\ + +HFILES=defs.h\ + fns.h\ + +BIN=/$objtype/bin +< /sys/src/cmd/mkone diff --git a/sys/src/cmd/db/output.c b/sys/src/cmd/db/output.c new file mode 100755 index 000000000..5f0eadaa1 --- /dev/null +++ b/sys/src/cmd/db/output.c @@ -0,0 +1,160 @@ +/* + * + * debugger + * + */ + +#include "defs.h" +#include "fns.h" + +int printcol = 0; +int infile = STDIN; +int maxpos = MAXPOS; + +Biobuf stdout; + +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(&stdout); + Binit(&stdout, 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(&stdout); + Binit(&stdout, fd, OWRITE); +} + +void +endline(void) +{ + + if (maxpos <= printcol) + newline(); +} + +void +flush(void) +{ + Bflush(&stdout); +} + +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); +//Bprint(&stdout, "[%s]", fmt); + Bwrite(&stdout, 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(&stdout, 1, OWRITE); + fmtinstall('t', tconv); +} diff --git a/sys/src/cmd/db/pcs.c b/sys/src/cmd/db/pcs.c new file mode 100755 index 000000000..de002430a --- /dev/null +++ b/sys/src/cmd/db/pcs.c @@ -0,0 +1,175 @@ +/* + * + * 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; + long 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); + line = pc2line(rget(cormap, mach->pc)); + n = loopcnt; + dprint("%s: running\n", symfil); + flush(); + for (loopcnt = 1; n > 0; loopcnt = 1) { + r = runpcs(SINGLE, keepnote); + curr = pc2line(dot); + 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/sys/src/cmd/db/print.c b/sys/src/cmd/db/print.c new file mode 100755 index 000000000..cb7938274 --- /dev/null +++ b/sys/src/cmd/db/print.c @@ -0,0 +1,374 @@ +/* + * + * 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 void +ptrace(Map *map, uvlong pc, uvlong sp, Symbol *sym) +{ + char buf[512]; + + USED(map); + dprint("%s(", sym->name); + printparams(sym, sp); + dprint(") "); + printsource(sym->value); + dprint(" called from "); + symoff(buf, 512, pc, CTEXT); + dprint("%s ", buf); + printsource(pc); + dprint("\n"); + if(tracetype == 'C') + printlocals(sym, sp); +} + +void +printtrace(int modif) +{ + int i; + uvlong pc, sp, link; + ulong w; + BKPT *bk; + Symbol s; + int stack; + char *fname; + char buf[512]; + + 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 (machdata->ctrace) { + if (adrflg) { + /* + * trace from jmpbuf for multi-threaded code. + * assume sp and pc are in adjacent locations + * and mach->szaddr in size. + */ + if (geta(cormap, adrval, &sp) < 0 || + geta(cormap, adrval+mach->szaddr, &pc) < 0) + error("%r"); + } else { + sp = rget(cormap, mach->sp); + pc = rget(cormap, mach->pc); + } + if(mach->link) + link = rget(cormap, mach->link); + else + link = 0; + if (machdata->ctrace(cormap, pc, sp, link, ptrace) <= 0) + error("no stack frame"); + } + break; + + /*print externals*/ + case 'e': + for (i = 0; globalsym(&s, i); i++) { + if (get4(cormap, s.value, &w) > 0) + dprint("%s/%12t%#lux\n", s.name, w); + } + 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) +{ + Reglist *rp; + int i; + int ret; + char buf[512]; + + for (i = 0, rp = mach->reglist; rp->rname; rp += ret) { + ret = 1; + if (!(rp->rflags&RFLT)) + continue; + ret = fpformat(map, rp, buf, sizeof(buf), modif); + if (ret < 0) { + werrstr("Register %s: %r", rp->rname); + error("%r"); + } + /* double column print */ + if (i&0x01) + dprint("%40t%-8s%-12s\n", rp->rname, buf); + else + dprint("\t%-8s%-12s", rp->rname, buf); + i++; + } +} + +void +redirin(int stack, char *file) +{ + char *pfile; + + if (file == 0) { + iclose(-1, 0); + return; + } + iclose(stack, 0); + if ((infile = open(file, 0)) < 0) { + pfile = smprint("%s/%s", Ipath, file); + infile = open(pfile, 0); + free(pfile); + if(infile < 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, fsym < 0 ? "-" : symfil); + else if (map == cormap) + dprint("%s%12t`%s'\n", s, fcor < 0 ? "-" : corfil); + else + dprint("%s\n", s); + for (i = 0; i < map->nsegs; i++) { + if (map->seg[i].inuse) + dprint("%s%8t%-16#llux %-16#llux %-16#llux\n", + map->seg[i].name, map->seg[i].b, + map->seg[i].e, map->seg[i].f); + } +} + +/* + * dump the raw symbol table + */ +void +printsym(void) +{ + int i; + Sym *sp; + + for (i = 0; sp = getsym(i); i++) { + switch(sp->type) { + case 't': + case 'l': + dprint("%16#llux t %s\n", sp->value, sp->name); + break; + case 'T': + case 'L': + dprint("%16#llux T %s\n", sp->value, sp->name); + break; + case 'D': + case 'd': + case 'B': + case 'b': + case 'a': + case 'p': + case 'm': + dprint("%16#llux %c %s\n", sp->value, sp->type, sp->name); + break; + default: + break; + } + } +} + +#define STRINGSZ 128 + +/* + * print the value of dot as file:line + */ +void +printsource(ADDR dot) +{ + char str[STRINGSZ]; + + if (fileline(str, STRINGSZ, dot)) + dprint("%s", str); +} + +void +printpc(void) +{ + char buf[512]; + + dot = rget(cormap, mach->pc); + if(dot){ + printsource((long)dot); + printc(' '); + symoff(buf, sizeof(buf), (long)dot, CTEXT); + dprint("%s/", buf); + if (machdata->das(cormap, dot, 'i', buf, sizeof(buf)) < 0) + error("%r"); + dprint("%16t%s\n", buf); + } +} + +void +printlocals(Symbol *fn, ADDR fp) +{ + int i; + ulong w; + Symbol s; + + s = *fn; + for (i = 0; localsym(&s, i); i++) { + if (s.class != CAUTO) + continue; + if (get4(cormap, fp-s.value, &w) > 0) + dprint("%8t%s.%s/%10t%#lux\n", fn->name, s.name, w); + else + dprint("%8t%s.%s/%10t?\n", fn->name, s.name); + } +} + +void +printparams(Symbol *fn, ADDR fp) +{ + int i; + Symbol s; + ulong w; + int first = 0; + + fp += mach->szaddr; /* skip saved pc */ + s = *fn; + for (i = 0; localsym(&s, i); i++) { + if (s.class != CPARAM) + continue; + if (first++) + dprint(", "); + if (get4(cormap, fp+s.value, &w) > 0) + dprint("%s=%#lux", s.name, w); + } +} diff --git a/sys/src/cmd/db/regs.c b/sys/src/cmd/db/regs.c new file mode 100755 index 000000000..e82c1cc88 --- /dev/null +++ b/sys/src/cmd/db/regs.c @@ -0,0 +1,131 @@ +/* + * code to keep track of registers + */ + +#include "defs.h" +#include "fns.h" + +/* + * translate a name to a magic register offset + */ +Reglist* +rname(char *name) +{ + Reglist *rp; + + for (rp = mach->reglist; rp->rname; rp++) + if (strcmp(name, rp->rname) == 0) + return rp; + return 0; +} + +static uvlong +getreg(Map *map, Reglist *rp) +{ + uvlong v; + ulong w; + ushort s; + int ret; + + v = 0; + ret = 0; + switch (rp->rformat) + { + case 'x': + ret = get2(map, rp->roffs, &s); + v = s; + break; + case 'f': + case 'X': + ret = get4(map, rp->roffs, &w); + v = w; + break; + case 'F': + case 'W': + case 'Y': + ret = get8(map, rp->roffs, &v); + break; + default: + werrstr("can't retrieve register %s", rp->rname); + error("%r"); + } + if (ret < 0) { + werrstr("Register %s: %r", rp->rname); + error("%r"); + } + return v; +} + +uvlong +rget(Map *map, char *name) +{ + Reglist *rp; + + rp = rname(name); + if (!rp) + error("invalid register name"); + return getreg(map, rp); +} + +void +rput(Map *map, char *name, vlong v) +{ + Reglist *rp; + int ret; + + rp = rname(name); + if (!rp) + error("invalid register name"); + if (rp->rflags & RRDONLY) + error("register is read-only"); + switch (rp->rformat) + { + case 'x': + ret = put2(map, rp->roffs, (ushort) v); + break; + case 'X': + case 'f': + case 'F': + ret = put4(map, rp->roffs, (long) v); + break; + case 'Y': + ret = put8(map, rp->roffs, v); + break; + default: + ret = -1; + } + if (ret < 0) + error("can't write register"); +} +/* + * print the registers + */ +void +printregs(int c) +{ + Reglist *rp; + int i; + uvlong v; + + for (i = 1, rp = mach->reglist; rp->rname; rp++, i++) { + if ((rp->rflags & RFLT)) { + if (c != 'R') + continue; + if (rp->rformat == '8' || rp->rformat == '3') + continue; + } + v = getreg(cormap, rp); + if(rp->rformat == 'Y') + dprint("%-8s %-20#llux", rp->rname, v); + else + dprint("%-8s %-12#lux", rp->rname, (ulong)v); + if ((i % 3) == 0) { + dprint("\n"); + i = 0; + } + } + if (i != 1) + dprint("\n"); + dprint ("%s\n", machdata->excep(cormap, rget)); + printpc(); +} diff --git a/sys/src/cmd/db/runpcs.c b/sys/src/cmd/db/runpcs.c new file mode 100755 index 000000000..45eef43ce --- /dev/null +++ b/sys/src/cmd/db/runpcs.c @@ -0,0 +1,199 @@ +/* + * + * 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 */ + +runpcs(int runmode, int keepnote) +{ + int rc; + BKPT *bkpt; + + rc = 0; + if (adrflg) + rput(cormap, mach->pc, dot); + dot = rget(cormap, mach->pc); + 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 ((bkpt = scanbkpt(rget(cormap, mach->pc))) != 0) { + execbkpt(bkpt, keepnote); + keepnote = 0; + } + setbp(); + runrun(keepnote); + } + keepnote = 0; + delbp(); + dot = rget(cormap, mach->pc); + /* 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/sys/src/cmd/db/setup.c b/sys/src/cmd/db/setup.c new file mode 100755 index 000000000..d1e60ffb9 --- /dev/null +++ b/sys/src/cmd/db/setup.c @@ -0,0 +1,208 @@ + +/* + * init routines + */ +#include "defs.h" +#include "fns.h" + +char *symfil; +char *corfil; + +Map *symmap; +Map *cormap; +Map *dotmap; + +int fsym, fcor; +static Fhdr fhdr; + +static int getfile(char*, int, int); + +void +setsym(void) +{ + Symbol s; + + if((fsym = getfile(symfil, 1, wtflag)) < 0) { + symmap = dumbmap(-1); + return; + } + if (crackhdr(fsym, &fhdr)) { + machbytype(fhdr.type); + symmap = loadmap(symmap, fsym, &fhdr); + if (symmap == 0) + symmap = dumbmap(fsym); + if (syminit(fsym, &fhdr) < 0) + dprint("%r\n"); + if (mach->sbreg && lookup(0, mach->sbreg, &s)) + mach->sb = s.value; + } + else + symmap = dumbmap(fsym); +} + +void +setcor(void) +{ + int i; + + if (cormap) { + for (i = 0; i < cormap->nsegs; i++) + if (cormap->seg[i].inuse) + close(cormap->seg[i].fd); + } + + fcor = getfile(corfil, 2, ORDWR); + if (fcor <= 0) { + if (cormap) + free(cormap); + cormap = dumbmap(-1); + return; + } + if(pid > 0) { /* provide addressability to executing process */ + cormap = attachproc(pid, kflag, fcor, &fhdr); + if (!cormap) + cormap = dumbmap(-1); + } else { + cormap = newmap(cormap, 2); + if (!cormap) + cormap = dumbmap(-1); + setmap(cormap, fcor, fhdr.txtaddr, fhdr.txtaddr+fhdr.txtsz, fhdr.txtaddr, "text"); + setmap(cormap, fcor, fhdr.dataddr, 0xffffffff, fhdr.dataddr, "data"); + } + kmsys(); + return; +} + +Map * +dumbmap(int fd) +{ + Map *dumb; + + extern Mach mi386; + extern Machdata i386mach; + + dumb = newmap(0, 1); + setmap(dumb, fd, 0, 0xffffffff, 0, "data"); + if (!mach) /* default machine = 386 */ + mach = &mi386; + if (!machdata) + machdata = &i386mach; + return dumb; +} + +/* + * set up maps for a direct process image (/proc) + */ + +void +cmdmap(Map *map) +{ + int i; + char name[MAXSYM]; + + extern char lastc; + + rdc(); + readsym(name); + i = findseg(map, name); + if (i < 0) /* not found */ + error("Invalid map name"); + + if (expr(0)) { + if (strcmp(name, "text") == 0) + textseg(expv, &fhdr); + map->seg[i].b = expv; + } else + error("Invalid base address"); + if (expr(0)) + map->seg[i].e = expv; + else + error("Invalid end address"); + if (expr(0)) + map->seg[i].f = 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(); +} + +static int +getfile(char *filnam, int cnt, int omode) +{ + int f; + + if (filnam == 0) + return -1; + if (strcmp(filnam, "-") == 0) + return 0; + f = open(filnam, omode|OCEXEC); + if(f < 0 && omode == ORDWR){ + f = open(filnam, OREAD|OCEXEC); + if(f >= 0) + dprint("%s open read-only\n", filnam); + } + if (f < 0 && xargc > cnt) + if (wtflag) + f = create(filnam, 1, 0666); + if (f < 0) { + dprint("cannot open `%s': %r\n", filnam); + return -1; + } + return f; +} + +void +kmsys(void) +{ + int i; + + i = findseg(symmap, "text"); + if (i >= 0) { + symmap->seg[i].b = symmap->seg[i].b&~mach->ktmask; + symmap->seg[i].e = ~0; + } + i = findseg(symmap, "data"); + if (i >= 0) { + symmap->seg[i].b |= mach->kbase; + symmap->seg[i].e |= mach->kbase; + } +} + +void +attachprocess(void) +{ + char buf[100]; + Dir *sym, *mem; + int fd; + + if (!adrflg) { + dprint("used pid$a\n"); + return; + } + sym = dirfstat(fsym); + sprint(buf, "/proc/%lud/mem", adrval); + corfil = buf; + setcor(); + sprint(buf, "/proc/%lud/text", adrval); + fd = open(buf, OREAD); + mem = nil; + if (sym==nil || fd < 0 || (mem=dirfstat(fd))==nil + || sym->qid.path != mem->qid.path) + dprint("warning: text images may be inconsistent\n"); + free(sym); + free(mem); + if (fd >= 0) + close(fd); +} diff --git a/sys/src/cmd/db/trcrun.c b/sys/src/cmd/db/trcrun.c new file mode 100755 index 000000000..7207c9e9c --- /dev/null +++ b/sys/src/cmd/db/trcrun.c @@ -0,0 +1,286 @@ +/* + * 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(cormap, mach->pc, adrval); + while (rdc() != EOR) + ; + reread(); +} + +void +runstep(uvlong loc, int keepnote) +{ + int nfoll; + uvlong foll[3]; + BKPT bkpt[3]; + int i; + + if(machdata->foll == 0){ + dprint("stepping unimplemented; assuming not a branch\n"); + nfoll = 1; + foll[0] = loc+mach->pcquant; + }else { + nfoll = machdata->foll(cormap, loc, rget, 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]; + ADDR loc; + int ret; + + errstr(buf, sizeof buf); + if(machdata->bpfix) + loc = (*machdata->bpfix)(bp->loc); + else + loc = bp->loc; + if(install){ + ret = get1(cormap, loc, bp->save, machdata->bpsize); + if (ret > 0) + ret = put1(cormap, loc, machdata->bpinst, machdata->bpsize); + }else + ret = put1(cormap, loc, bp->save, machdata->bpsize); + if(ret < 0){ + sprint(buf, "can't set breakpoint at %#llux: %r", bp->loc); + print(buf); + read(0, buf, 100); + } +} |