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