summaryrefslogtreecommitdiff
path: root/sys/src/cmd/db
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/cmd/db
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/cmd/db')
-rwxr-xr-xsys/src/cmd/db/command.c310
-rwxr-xr-xsys/src/cmd/db/defs.h110
-rwxr-xr-xsys/src/cmd/db/expr.c378
-rwxr-xr-xsys/src/cmd/db/fns.h89
-rwxr-xr-xsys/src/cmd/db/format.c386
-rwxr-xr-xsys/src/cmd/db/input.c166
-rwxr-xr-xsys/src/cmd/db/main.c210
-rwxr-xr-xsys/src/cmd/db/mkfile22
-rwxr-xr-xsys/src/cmd/db/output.c160
-rwxr-xr-xsys/src/cmd/db/pcs.c175
-rwxr-xr-xsys/src/cmd/db/print.c374
-rwxr-xr-xsys/src/cmd/db/regs.c131
-rwxr-xr-xsys/src/cmd/db/runpcs.c199
-rwxr-xr-xsys/src/cmd/db/setup.c208
-rwxr-xr-xsys/src/cmd/db/trcrun.c286
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*) &dot;
+ 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*) &dot;
+ 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*) &dot;
+ 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);
+ }
+}