tWorking on better handling of multithreading in general and core dumps in particular.  See notes: - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
LICENSE
---
commit 4f2ac1b76b04df503944e86c2e7f152c2ff53f0e
parent a5f9ff62b2d70a5b75efe8e4f993aec10f209095
Author: rsc 
Date:   Sun, 23 Jan 2005 22:48:19 +0000

Working on better handling of multithreading in general
and core dumps in particular.  See notes:

new types: register is something that when dereferenced gives you
        the registers.  the Ureg is no longer mapped at 0.
        refconst is something that gives a constant when dereferenced.

new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values

new builtin var("foo") is equivalent to the variable foo
        (it returns foo but can also be used as the lhs of an assignment).

new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
        note that getregs and setregs operate on register locations, not the
                register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
tthe default register settings are as in resetregs(), not small numbers.

new acid variables coretext, pids, systype, corefile, cmdline.

new behavior: local variable lookup, stk, etc., use the acid values of registers
        (*PC, *SP, and so on), so the thread support code can change the context
        completely.

unary + is applicable to more data types and prints more often.

Diffstat:
  M src/cmd/acid/Notes                  |      30 ++++++++++++++++++++++++++++++
  M src/cmd/acid/acid.h                 |      11 ++++++++++-
  M src/cmd/acid/builtin.c              |     166 +++++++++++++++++++++++++------
  M src/cmd/acid/dbg.y                  |       3 +--
  M src/cmd/acid/exec.c                 |     187 ++++++++++++++++++++-----------
  M src/cmd/acid/expr.c                 |     129 ++++++++++++++++++++++++++-----
  M src/cmd/acid/main.c                 |     114 ++++++++++++++++++++++---------
  M src/cmd/acid/print.c                |       4 ++++
  M src/cmd/acid/proc.c                 |      51 +++++++++++++++++++------------
  M src/cmd/acid/util.c                 |       5 ++---

10 files changed, 526 insertions(+), 174 deletions(-)
---
diff --git a/src/cmd/acid/Notes b/src/cmd/acid/Notes
t@@ -20,6 +20,8 @@ map() returns 5-tuples: (name, filename, base, end, offset)
 
 map() expects a 5-tuple too
 
+new acid maps() prints maps nicely.
+
 strace expects a list of register names and values like
         {"PC", *PC, "SP", *SP}
 
t@@ -41,6 +43,34 @@ new builtin deltextfile(file) removes a file from the set of open text files.
 
 both textfile and deltextfile update symbols.
 
+new types: register is something that when dereferenced gives you
+        the registers.  the Ureg is no longer mapped at 0.
+        refconst is something that gives a constant when dereferenced.
+
+new builtin register("AX") creates register values
+new builtin refconst(0x123) creates refconst values
+
+new builtin var("foo") is equivalent to the variable foo
+        (it returns foo but can also be used as the lhs of an assignment).
+
+new acid function getregs() returns a list of the current values of registers.
+new acid function setregs() sets the current registers to those values.
+        note that getregs and setregs operate on register locations, not the
+                register values themselves.  
+new acid function resetregs() sets registers to register("AX"), etc.
+new acid function clearregs() sets all registers to constant -1.
+
+the default register settings are as in resetregs(), not small numbers.
+the Ureg is not mapped at 0 anymore.
+
+new acid variables coretext, pids, systype, corefile, cmdline.
+
+new behavior: local variable lookup, stk, etc., use the acid values of registers
+        (*PC, *SP, and so on), so the thread support code can change the context
+        completely.
+
+unary + is applicable to more data types and prints more often.
+
 ====
 
 yet to be done:
diff --git a/src/cmd/acid/acid.h b/src/cmd/acid/acid.h
t@@ -44,6 +44,7 @@ Extern int        interactive;
 Extern Node*        code;
 Extern int        na;
 Extern int        wtflag;
+Extern Regs*        acidregs;
 Extern Regs*        correg;
 Extern Map*        cormap;
 Extern Map*        symmap;
t@@ -76,6 +77,8 @@ enum
         TSTRING,
         TLIST,
         TCODE,
+        TREG,
+        TCON,
         NUMT,
 };
 
t@@ -129,6 +132,8 @@ struct Store
                 String*        string;
                 List*        l;
                 Node*        cc;
+                char*        reg;
+                Node*        con;
         } u;
 };
 
t@@ -182,6 +187,7 @@ struct String
         int        len;
 };
 
+int        acidregsrw(Regs*, char*, ulong*, int);
 List*        addlist(List*, List*);
 void        addvarsym(Fhdr*);
 List*        al(int);
t@@ -212,6 +218,7 @@ void        gc(void);
 char*        getstatus(int);
 void*        gmalloc(long);
 void        indir(Map*, ulong, char, Node*);
+void        indirreg(Regs*, char*, char, Node*);
 void        initexpr(void);
 void        initprint(void);
 void        installbuiltin(void);
t@@ -257,7 +264,8 @@ void        userinit(void);
 void        varreg(void);
 void        varsym(void);
 void        whatis(Lsym*);
-void        windir(Map*, Node*, Node*, Node*);
+void        windir(Map*, Node, Node*, Node*);
+void        windirreg(Regs*, char*, Node*, Node*);
 void        yyerror(char*, ...);
 int        yylex(void);
 int        yyparse(void);
t@@ -313,5 +321,6 @@ enum
         OFMT,
         OEVAL,
         OWHAT,
+        OUPLUS,
         NUMO,
 };
diff --git a/src/cmd/acid/builtin.c b/src/cmd/acid/builtin.c
t@@ -44,6 +44,9 @@ void        regexp(Node*, Node*);
 void textfile(Node*, Node*);
 void deltextfile(Node*, Node*);
 void stringn(Node*, Node*);
+void xregister(Node*, Node*);
+void refconst(Node*, Node*);
+void dolook(Node*, Node*);
 
 typedef struct Btab Btab;
 struct Btab
t@@ -52,13 +55,12 @@ struct Btab
         void        (*fn)(Node*, Node*);
 } tab[] =
 {
+        "access",        doaccess,
         "atof",                cvtatof,
         "atoi",                cvtatoi,
         "deltextfile",        deltextfile,
         "error",        doerror,
         "file",                getfile,
-        "readfile",        readfile,
-        "access",        doaccess,
         "filepc",        filepc,
         "fnbound",        funcbound,
         "fmt",                fmt,
t@@ -76,8 +78,11 @@ struct Btab
         "print",        bprint,
         "printto",        printto,
         "rc",                rc,
+        "readfile",        readfile,
         "reason",        reason,
+        "refconst",        refconst,
         "regexp",        regexp,
+        "register",        xregister,
         "setproc",        setproc,
         "start",        start,
         "startstop",        startstop,
t@@ -87,6 +92,7 @@ struct Btab
         "stringn",        stringn,
         "sysstop",                sysstop,
         "textfile",        textfile,
+        "var",        dolook,
         "waitstop",        waitstop,
         0
 };
t@@ -317,6 +323,65 @@ xkill(Node *r, Node *args)
 }
 
 void
+xregister(Node *r, Node *args)
+{
+        Regdesc *rp;
+        Node res;
+
+        if(args == 0)
+                error("register(string): arg count");
+        expr(args, &res);
+        if(res.type != TSTRING)
+                error("register(string): arg type");
+
+        if((rp = regdesc(res.store.u.string->string)) == nil)
+                error("no such register");
+
+        r->op = OCONST;
+        r->type = TREG;
+        r->store.fmt = rp->format;
+        r->store.u.reg = rp->name;
+}
+
+void
+refconst(Node *r, Node *args)
+{
+        Node *n;
+
+        if(args == 0)
+                error("refconst(expr): arg count");
+
+        n = an(OCONST, ZN, ZN);
+        expr(args, n);
+
+        r->op = OCONST;
+        r->type = TCON;
+        r->store.u.con = n;
+}
+
+void
+dolook(Node *r, Node *args)
+{
+        Node res;
+        Lsym *l;
+
+        if(args == 0)
+                error("var(string): arg count");
+        expr(args, &res);
+        if(res.type != TSTRING)
+                error("var(string): arg type");
+
+        r->op = OCONST;
+        if((l = look(res.store.u.string->string)) == nil || l->v->set == 0){
+                r->type = TLIST;
+                r->store.u.l = nil;
+        }else{
+                r->type = l->v->type;
+                r->store = l->v->store;
+        }
+}
+
+void
 status(Node *r, Node *args)
 {
         Node res;
t@@ -350,7 +415,7 @@ reason(Node *r, Node *args)
         r->op = OCONST;
         r->type = TSTRING;
         r->store.fmt = 's';
-        r->store.u.string = strnode((*mach->exc)(cormap, correg));
+        r->store.u.string = strnode((*mach->exc)(cormap, acidregs));
 }
 
 void
t@@ -367,7 +432,7 @@ follow(Node *r, Node *args)
         if(res.type != TINT)
                 error("follow(addr): arg type");
 
-        n = (*mach->foll)(cormap, correg, res.store.u.ival, f);
+        n = (*mach->foll)(cormap, acidregs, res.store.u.ival, f);
         if (n < 0)
                 error("follow(addr): %r");
         tail = &r->store.u.l;
t@@ -953,7 +1018,7 @@ straceregrw(Regs *regs, char *name, ulong *val, int isr)
                         *val = sregs[i].val;
                         return 0;
                 }
-        return rget(correg, name, val);
+        return rget(acidregs, name, val);
 }
 
 void
t@@ -1058,6 +1123,65 @@ patom(char type, Store *res)
         int i;
         char buf[512];
         extern char *typenames[];
+        Node *n;
+
+        switch(type){
+        case TREG:
+                Bprint(bout, "register(\"%s\")", res->u.reg);
+                return;
+        case TCON:
+                Bprint(bout, "refconst(");
+                n = res->u.con;
+                patom(n->type, &n->store);
+                Bprint(bout, ")");
+                return;
+        }
+
+        switch(res->fmt){
+        case 'c':
+        case 'C':
+        case 'r':
+        case 'B':
+        case 'b':
+        case 'X':
+        case 'x':
+        case 'W':
+        case 'D':
+        case 'd':
+        case 'u':
+        case 'U':
+        case 'Z':
+        case 'V':
+        case 'Y':
+        case 'o':
+        case 'O':
+        case 'q':
+        case 'Q':
+        case 'a':
+        case 'A':
+        case 'I':
+        case 'i':
+                if(type != TINT){
+                badtype:
+                        Bprint(bout, "*%s\\%c*", typenames[(uchar)type], res->fmt);
+                        return;
+                }
+                break;
+
+        case 'f':
+        case 'F':
+                if(type != TFLOAT)
+                        goto badtype;
+                break;
+
+        case 's':
+        case 'g':
+        case 'G':
+        case 'R':
+                if(type != TSTRING)
+                        goto badtype;
+                break;
+        }
 
         switch(res->fmt) {
         case 'c':
t@@ -1129,24 +1253,15 @@ patom(char type, Store *res)
                 break;
         case 'f':
         case 'F':
-                if(type != TFLOAT)
-                        Bprint(bout, "*%c<%s>*", res->fmt, typenames[(uchar)type]);
-                else
-                        Bprint(bout, "%g", res->u.fval);
+                Bprint(bout, "%g", res->u.fval);
                 break;
         case 's':
         case 'g':
         case 'G':
-                if(type != TSTRING)
-                        Bprint(bout, "*%c<%s>*", res->fmt, typenames[(uchar)type]);
-                else
-                        Bwrite(bout, res->u.string->string, res->u.string->len);
+                Bwrite(bout, res->u.string->string, res->u.string->len);
                 break;
         case 'R':
-                if(type != TSTRING)
-                        Bprint(bout, "*%c<%s>*", res->fmt, typenames[(uchar)type]);
-                else
-                        Bprint(bout, "%S", (Rune*)res->u.string->string);
+                Bprint(bout, "%S", (Rune*)res->u.string->string);
                 break;
         case 'a':
         case 'A':
t@@ -1155,14 +1270,10 @@ patom(char type, Store *res)
                 break;
         case 'I':
         case 'i':
-                if(type != TINT)
-                        Bprint(bout, "*%c<%s>*", res->fmt, typenames[(uchar)type]);
-                else {
-                        if (symmap == nil || (*mach->das)(symmap, res->u.ival, res->fmt, buf, sizeof(buf)) < 0)
-                                Bprint(bout, "no instruction");
-                        else
-                                Bprint(bout, "%s", buf);
-                }
+                if (symmap == nil || (*mach->das)(symmap, res->u.ival, res->fmt, buf, sizeof(buf)) < 0)
+                        Bprint(bout, "no instruction");
+                else
+                        Bprint(bout, "%s", buf);
                 break;
         }
 }
t@@ -1406,6 +1517,7 @@ textfile(Node *r, Node *args)
                         unmapfile(corhdr, cormap);
                         mapfile(fp, base, cormap, nil);
                         free(correg);
+                        correg = nil;
                         mapfile(corhdr, 0, cormap, &correg);
                 }
                 if(symopen(fp) < 0)
t@@ -1476,8 +1588,6 @@ deltextfile(Node *r, Node *args)
                 error("symbol file %s not open", file);
 }
 
-int xget1(Map *m, ulong addr, u8int *a, int n);
-
 void
 stringn(Node *r, Node *args)
 {
t@@ -1507,7 +1617,7 @@ stringn(Node *r, Node *args)
 
         r->type = TSTRING;
         for(i=0; i
diff --git a/src/cmd/acid/dbg.y b/src/cmd/acid/dbg.y
t@@ -282,8 +282,7 @@ monexpr                : term
                 }
                 | '+' monexpr
                 {
-                        $$ = con(0);
-                        $$ = an(OADD, $2, $$);
+                        $$ = an(OUPLUS, $2, ZN);
                 }
                 | '-' monexpr
                 {
diff --git a/src/cmd/acid/exec.c b/src/cmd/acid/exec.c
t@@ -202,56 +202,6 @@ convflt(Node *r, char *flt)
         }
 }
 
-static char*
-regbyoff(ulong addr)
-{
-        Regdesc *r;
-
-        if(mach == nil)
-                error("no mach, no registers");
-        for(r=mach->reglist; r->name; r++)
-                if(r->offset == addr)
-                        return r->name;
-        error("no register at %#lux", addr);
-        return nil;
-}
-
-int
-xget1(Map *m, ulong addr, u8int *a, int n)
-{
-        if(addr < 0x100 && correg)
-                return lget1(m, correg, locreg(regbyoff(addr)), a, n);
-        else
-                return get1(m, addr, a, n);
-}
-
-int
-xget2(Map *m, ulong addr, u16int *a)
-{
-        if(addr < 0x100 && correg)
-                return lget2(m, correg, locreg(regbyoff(addr)), a);
-        else
-                return get2(m, addr, a);
-}
-
-int
-xget4(Map *m, ulong addr, u32int *a)
-{
-        if(addr < 0x100 && correg)
-                return lget4(m, correg, locreg(regbyoff(addr)), a);
-        else
-                return get4(m, addr, a);
-}
-
-int
-xget8(Map *m, ulong addr, u64int *a)
-{
-        if(addr < 0x100 && correg)
-                return lget8(m, correg, locreg(regbyoff(addr)), a);
-        else
-                return get8(m, addr, a);
-}
-
 void
 indir(Map *m, ulong addr, char fmt, Node *r)
 {
t@@ -272,7 +222,7 @@ indir(Map *m, ulong addr, char fmt, Node *r)
         case 'C':
         case 'b':
                 r->type = TINT;
-                ret = xget1(m, addr, &cval, 1);
+                ret = get1(m, addr, &cval, 1);
                 if (ret < 0)
                         error("indir: %r");
                 r->store.u.ival = cval;
t@@ -284,7 +234,7 @@ indir(Map *m, ulong addr, char fmt, Node *r)
         case 'q':
         case 'r':
                 r->type = TINT;
-                ret = xget2(m, addr, &sval);
+                ret = get2(m, addr, &sval);
                 if (ret < 0)
                         error("indir: %r");
                 r->store.u.ival = sval;
t@@ -298,7 +248,7 @@ indir(Map *m, ulong addr, char fmt, Node *r)
         case 'O':
         case 'Q':
                 r->type = TINT;
-                ret = xget4(m, addr, &ival);
+                ret = get4(m, addr, &ival);
                 if (ret < 0)
                         error("indir: %r");
                 r->store.u.ival = ival;
t@@ -308,7 +258,7 @@ indir(Map *m, ulong addr, char fmt, Node *r)
         case 'Y':
         case 'Z':
                 r->type = TINT;
-                ret = xget8(m, addr, &vval);
+                ret = get8(m, addr, &vval);
                 if (ret < 0)
                         error("indir: %r");
                 r->store.u.ival = vval;
t@@ -316,7 +266,7 @@ indir(Map *m, ulong addr, char fmt, Node *r)
         case 's':
                 r->type = TSTRING;
                 for(i = 0; i < sizeof(buf)-1; i++) {
-                        ret = xget1(m, addr, (uchar*)&buf[i], 1);
+                        ret = get1(m, addr, (uchar*)&buf[i], 1);
                         if (ret < 0)
                                 error("indir: %r");
                         addr++;
t@@ -331,7 +281,7 @@ indir(Map *m, ulong addr, char fmt, Node *r)
         case 'R':
                 r->type = TSTRING;
                 for(i = 0; i < sizeof(buf)-2; i += 2) {
-                        ret = xget1(m, addr, (uchar*)&buf[i], 2);
+                        ret = get1(m, addr, (uchar*)&buf[i], 2);
                         if (ret < 0)
                                 error("indir: %r");
                         addr += 2;
t@@ -351,14 +301,14 @@ indir(Map *m, ulong addr, char fmt, Node *r)
                 r->store.u.string = strnode(buf);
                 break;
         case 'f':
-                ret = xget1(m, addr, (uchar*)buf, mach->szfloat);
+                ret = get1(m, addr, (uchar*)buf, mach->szfloat);
                 if (ret < 0)
                         error("indir: %r");
                 mach->ftoa32(buf, sizeof(buf), (void*) buf);
                 convflt(r, buf);
                 break;
         case 'g':
-                ret = xget1(m, addr, (uchar*)buf, mach->szfloat);
+                ret = get1(m, addr, (uchar*)buf, mach->szfloat);
                 if (ret < 0)
                         error("indir: %r");
                 mach->ftoa32(buf, sizeof(buf), (void*) buf);
t@@ -366,14 +316,14 @@ indir(Map *m, ulong addr, char fmt, Node *r)
                 r->store.u.string = strnode(buf);
                 break;
         case 'F':
-                ret = xget1(m, addr, (uchar*)buf, mach->szdouble);
+                ret = get1(m, addr, (uchar*)buf, mach->szdouble);
                 if (ret < 0)
                         error("indir: %r");
                 mach->ftoa64(buf, sizeof(buf), (void*) buf);
                 convflt(r, buf);
                 break;
         case '3':        /* little endian ieee 80 with hole in bytes 8&9 */
-                ret = xget1(m, addr, (uchar*)reg, 10);
+                ret = get1(m, addr, (uchar*)reg, 10);
                 if (ret < 0)
                         error("indir: %r");
                 memmove(reg+10, reg+8, 2);        /* open hole */
t@@ -382,14 +332,14 @@ indir(Map *m, ulong addr, char fmt, Node *r)
                 convflt(r, buf);
                 break;
         case '8':        /* big-endian ieee 80 */
-                ret = xget1(m, addr, (uchar*)reg, 10);
+                ret = get1(m, addr, (uchar*)reg, 10);
                 if (ret < 0)
                         error("indir: %r");
                 beieeeftoa80(buf, sizeof(buf), reg);
                 convflt(r, buf);
                 break;
         case 'G':
-                ret = xget1(m, addr, (uchar*)buf, mach->szdouble);
+                ret = get1(m, addr, (uchar*)buf, mach->szdouble);
                 if (ret < 0)
                         error("indir: %r");
                 mach->ftoa64(buf, sizeof(buf), (void*) buf);
t@@ -400,21 +350,70 @@ indir(Map *m, ulong addr, char fmt, Node *r)
 }
 
 void
-windir(Map *m, Node *addr, Node *rval, Node *r)
+indirreg(Regs *regs, char *name, char fmt, Node *r)
+{
+        ulong val;
+
+        if(regs == 0)
+                error("no register set for *%s=", name);
+
+        r->op = OCONST;
+        r->store.fmt = fmt;
+        switch(fmt){
+        default:
+                error("bad pointer format '%c' for *%s", fmt, name);
+        case 'c':
+        case 'C':
+        case 'b':
+        case 'x':
+        case 'd':
+        case 'u':
+        case 'o':
+        case 'q':
+        case 'r':
+        case 'a':
+        case 'A':
+        case 'B':
+        case 'X':
+        case 'D':
+        case 'U':
+        case 'O':
+        case 'Q':
+        case 'V':
+        case 'W':
+        case 'Y':
+        case 'Z':
+                if(rget(regs, name, &val) < 0)
+                        error("reading %s: %r", name);
+                r->type = TINT;
+                r->store.u.ival = val;
+                break;
+        case 'f':
+        case 'g':
+        case 'F':
+        case '3':
+        case '8':
+        case 'G':
+                error("floating point registers not supported");
+                break;
+        }
+}
+
+void
+windir(Map *m, Node aes, Node *rval, Node *r)
 {
         uchar cval;
         ushort sval;
-        Node res, aes;
+        Node res;
         int ret;
 
         if(m == 0)
                 error("no map for */@=");
 
-        expr(rval, &res);
-        expr(addr, &aes);
-
         if(aes.type != TINT)
-                error("bad type lhs of @/*");
+                error("bad type lhs of */@=");
+
+        expr(rval, &res);
 
         if(m != cormap && wtflag == 0)
                 error("not in write mode");
t@@ -466,6 +465,58 @@ windir(Map *m, Node *addr, Node *rval, Node *r)
 }
 
 void
+windirreg(Regs *regs, char *name, Node *rval, Node *r)
+{
+        Node res;
+
+        if(regs == 0)
+                error("no register set for *%s=", name);
+
+        expr(rval, &res);
+
+        r->type = res.type;
+        r->store.fmt = res.store.fmt;
+        r->store = res.store;
+
+        switch(res.store.fmt){
+        default:
+                error("bad format '%c' for *%s=", res.store.fmt, name);
+        case 'c':
+        case 'C':
+        case 'b':
+        case 'x':
+        case 'd':
+        case 'u':
+        case 'o':
+        case 'q':
+        case 'r':
+        case 'a':
+        case 'A':
+        case 'B':
+        case 'X':
+        case 'D':
+        case 'U':
+        case 'O':
+        case 'Q':
+        case 'V':
+        case 'W':
+        case 'Y':
+        case 'Z':
+                if(rput(regs, name, res.store.u.ival) < 0)
+                        error("writing %s: %r", name);
+                break;
+        case 'f':
+        case 'g':
+        case 'F':
+        case '3':
+        case '8':
+        case 'G':
+                error("floating point registers not supported");
+                break;
+        }
+}
+
+void
 call(char *fn, Node *parameters, Node *local, Node *body, Node *retexp)
 {
         int np, i;
diff --git a/src/cmd/acid/expr.c b/src/cmd/acid/expr.c
t@@ -63,11 +63,29 @@ fmtsize(Value *v)
         }
 }
 
-void
+Lsym*
 chklval(Node *lp)
 {
-        if(lp->op != ONAME)
-                error("need l-value");
+        Node res;
+        Lsym *s;
+
+        if(lp->op == ONAME)
+                return lp->sym;
+
+        if(lp->op == OCALL){
+                s = chklval(lp->left);
+                if(strcmp(s->name, "var") == 0        
+                && (lp->builtin || s->proc == 0)){
+                        if(lp->right == 0)
+                                error("var(string): arg count");
+                        expr(lp->right, &res);
+                        if(res.type != TSTRING)
+                                error("var(string): arg type");
+                        return mkvar(res.store.u.string->string);
+                }
+        }
+        error("need l-value");
+        return nil;        
 }
 
 void
t@@ -107,12 +125,24 @@ oindm(Node *n, Node *res)
         if(m == 0)
                 m = symmap;
         expr(n->left, &l);
-        if(l.type != TINT)
+        switch(l.type){
+        default:
                 error("bad type for *");
-        if(m == 0)
-                error("no map for *");
-        indir(m, l.store.u.ival, l.store.fmt, res);
-        res->store.comt = l.store.comt;
+        case TINT:
+                if(m == 0)
+                        error("no map for *");
+                indir(m, l.store.u.ival, l.store.fmt, res);
+                res->store.comt = l.store.comt;
+                break;
+        case TREG:
+                indirreg(correg, l.store.u.reg, l.store.fmt, res);
+                res->store.comt = l.store.comt;
+                break;
+        case TCON:
+                *res = *l.store.u.con;
+                res->store.comt = l.store.comt;
+                break;
+        }
 }
 
 void
t@@ -145,7 +175,7 @@ oframe(Node *n, Node *res)
         while(*p && *p == '$')
                 p++;
         lp = n->left;
-        if(localaddr(cormap, correg, p, lp->sym->name, &ival) < 0)
+        if(localaddr(cormap, acidregs, p, lp->sym->name, &ival) < 0)
                 error("colon: %r");
                 
         res->store.u.ival = ival;
t@@ -296,19 +326,24 @@ void
 oasgn(Node *n, Node *res)
 {
         Node *lp, r;
+        Node aes;
         Value *v;
 
         lp = n->left;
         switch(lp->op) {
         case OINDM:
-                windir(cormap, lp->left, n->right, res);
+                expr(lp->left, &aes);
+                if(aes.type == TREG)
+                        windirreg(correg, aes.store.u.reg, n->right, res);
+                else
+                        windir(cormap, aes, n->right, res);
                 break;
         case OINDC:
-                windir(symmap, lp->left, n->right, res);
+                expr(lp->left, &aes);
+                windir(symmap, aes, n->right, res);
                 break;
         default:
-                chklval(lp);
-                v = lp->sym->v;
+                v = chklval(lp)->v;
                 expr(n->right, &r);
                 v->set = 1;
                 v->type = r.type;
t@@ -871,8 +906,7 @@ oeinc(Node *n, Node *res)
 {
         Value *v;
 
-        chklval(n->left);
-        v = n->left->sym->v;
+        v = chklval(n->left)->v;
         res->op = OCONST;
         res->type = v->type;
         switch(v->type) {
t@@ -899,8 +933,7 @@ opinc(Node *n, Node *res)
 {
         Value *v;
 
-        chklval(n->left);
-        v = n->left->sym->v;
+        v = chklval(n->left)->v;
         res->op = OCONST;
         res->type = v->type;
         res->store = v->store;
t@@ -932,9 +965,7 @@ ocall(Node *n, Node *res)
         res->type = TLIST;
         res->store.u.l = 0;
 
-        chklval(n->left);
-        s = n->left->sym;
-
+        s = chklval(n->left);
         if(n->builtin && !s->builtin){
                 error("no builtin %s", s->name);
                 return;
t@@ -959,6 +990,12 @@ ofmt(Node *n, Node *res)
 }
 
 void
+ouplus(Node *n, Node *res)
+{
+        expr(n->left, res);
+}
+
+void
 owhat(Node *n, Node *res)
 {
         res->op = OCONST;                /* Default return value */
t@@ -1021,6 +1058,7 @@ initexpop(void)
         expop[OFMT] = ofmt;
         expop[OEVAL] = oeval;
         expop[OWHAT] = owhat;
+        expop[OUPLUS] = ouplus;
 }
 
 void
t@@ -1030,3 +1068,54 @@ initexpr(void)
         initexpop();
 }
 
+int
+acidregsrw(Regs *r, char *name, ulong *u, int isr)
+{
+        Lsym *l;
+        Value *v;
+        Node *n;
+        ulong addr;
+        u32int u32;
+
+        if(!isr){
+                werrstr("cannot write registers");
+                return -1;
+        }
+        USED(r);
+        l = look(name);
+        if(l == nil){
+                werrstr("register %s not found", name);
+                return -1;
+        }
+        v = l->v;
+        switch(v->type){
+        default:
+                werrstr("*%s: bad type", name);
+                return -1;
+        case TREG:
+                if(correg == nil){
+                        werrstr("*%s: register %s not mapped", name, v->store.u.reg);
+                        return -1;
+                }
+                return rget(correg, v->store.u.reg, u);
+        case TCON:
+                n = v->store.u.con;
+                if(n->op != OCONST || n->type != TINT){
+                        werrstr("*%s: bad register constant", name);
+                        return -1;
+                }
+                *u = n->store.u.ival;
+                return 0;
+        case TINT:
+                if(cormap == nil){
+                        werrstr("*%s: core not mapped", name);
+                        return -1;
+                }
+                addr = v->store.u.ival;
+                /* XXX should use format to determine size */
+                if(get4(cormap, addr, &u32) < 0)
+                        return -1;
+                *u = u32;
+                return 0;
+        }
+}
diff --git a/src/cmd/acid/main.c b/src/cmd/acid/main.c
t@@ -106,6 +106,8 @@ main(int argc, char *argv[])
         pushfile(0);
         loadvars();
         installbuiltin();
+        acidregs = mallocz(sizeof *acidregs, 1);
+        acidregs->rw = acidregsrw;
 
         if(mtype && machbyname(mtype) == 0)
                 print("unknown machine %s", mtype);
t@@ -172,16 +174,29 @@ main(int argc, char *argv[])
 */
 }
 
+void
+setstring(char *var, char *s)
+{
+        Lsym *l;
+        Value *v;
+
+        l = mkvar(var);
+        v = l->v;
+        v->store.fmt = 's';
+        v->set = 1;
+        v->store.u.string = strnode(s ? s : "");
+        v->type = TSTRING;
+}
+
 static int
 attachfiles(int argc, char **argv)
 {
         int fd;
         volatile int pid;
-        char *s;
+        char *s, *t;
         int i, omode;
         Fhdr *hdr;
         Lsym *l;
-        Value *v;
 
         pid = 0;
         interactive = 0;
t@@ -220,7 +235,6 @@ attachfiles(int argc, char **argv)
                 }
                 fprint(2, "%s: %s %s %s\n", argv[i], hdr->aname, hdr->mname, hdr->fname);
                 if(hdr->ftype == FCORE){
-                        fprint(2, "cmd: %s\n", hdr->cmd);
                         if(pid){
                                 fprint(2, "already have pid %d; ignoring core %s\n", pid, argv[i]);
                                 uncrackhdr(hdr);
t@@ -252,12 +266,28 @@ attachfiles(int argc, char **argv)
                                 symfil = s;
                         }
                 }
-                /* XXX pull command from core */
+                if(corhdr){
+                        /*
+                         * prog gives only the basename of the command,
+                         * so try the command line for a path.
+                         */
+                        if((s = strdup(corhdr->cmdline)) != nil){
+                                t = strchr(s, ' ');
+                                if(t)
+                                        *t = 0;
+                                if((t = searchpath(s)) != nil){
+                                        fprint(2, "core: text %s\n", t);
+                                        symfil = t;
+                                }
+                                free(s);
+                        }
+                }
 
                 if((symhdr = crackhdr(symfil, omode)) == nil){
                         fprint(2, "crackhdr %s: %r\n", symfil);
                         symfil = nil;
-                }
+                }else
+                        fprint(2, "%s: %s %s %s\n", symfil, symhdr->aname, symhdr->mname, symhdr->fname);        
         }
 
         if(symhdr)
t@@ -281,33 +311,15 @@ attachfiles(int argc, char **argv)
         }
 
 Run:
-        l = mkvar("objtype");
-        v = l->v;
-        v->store.fmt = 's';
-        v->set = 1;
-        v->store.u.string = strnode(mach->name);
-        v->type = TSTRING;
-
-        l = mkvar("textfile");
-        v = l->v;
-        v->store.fmt = 's';
-        v->set = 1;
-        v->store.u.string = strnode(symfil ? symfil : "");
-        v->type = TSTRING;
-
-        l = mkvar("systype");
-        v = l->v;
-        v->store.fmt = 's';
-        v->set = 1;
-        v->store.u.string = strnode(symhdr ? symhdr->aname : "");
-        v->type = TSTRING;
+        setstring("objtype", mach->name);
+        setstring("textfile", symfil);
+        setstring("systype", symhdr ? symhdr->aname : "");
+        setstring("corefile", corfil);
 
-        l = mkvar("corefile");
-        v = l->v;
-        v->store.fmt = 's';
-        v->set = 1;
-        v->store.u.string = strnode(corfil ? corfil : "");
-        v->type = TSTRING;
+        l = mkvar("pids");
+        l->v->set = 1;
+        l->v->type = TLIST;
+        l->v->store.u.l = nil;
 
         if(pid)
                 sproc(pid);
t@@ -320,6 +332,11 @@ Run:
 void
 setcore(Fhdr *hdr)
 {
+        int i;
+        Lsym *l;
+        Value *v;
+        List **tail, *tl;
+
         unmapproc(cormap);
         unmapfile(corhdr, cormap);
         free(correg);
t@@ -331,6 +348,31 @@ setcore(Fhdr *hdr)
                 error("mapfile %s: %r", hdr->filename);
         corhdr = hdr;
         corfil = hdr->filename;
+
+        l = mkvar("pid");
+        v = l->v;
+        v->store.fmt = 'D';
+        v->set = 1;
+        v->store.u.ival = hdr->pid;
+
+        setstring("corefile", corfil);
+        setstring("cmdline", hdr->cmdline);
+
+        l = mkvar("pids");
+        l->v->set = 1;
+        l->v->type = TLIST;
+        l->v->store.u.l = nil;
+        tail = &l->v->store.u.l;
+        for(i=0; inthread; i++){
+                tl = al(TINT);
+                tl->store.u.ival = hdr->thread[i].id;
+                tl->store.fmt = 'X';
+                *tail = tl;
+                tail = &tl->next;
+        }
+
+        if(hdr->nthread)
+                sproc(hdr->thread[0].id);
 }
 
 void
t@@ -338,16 +380,21 @@ die(void)
 {
         Lsym *s;
         List *f;
+        int first;
 
         Bprint(bout, "\n");
 
+        first = 1;
         s = look("proclist");
         if(s && s->v->type == TLIST) {
                 for(f = s->v->store.u.l; f; f = f->next){
                         detachproc((int)f->store.u.ival);
-                        Bprint(bout, "/bin/kill -9 %d\n", (int)f->store.u.ival);
+                        Bprint(bout, "%s %d", first ? "/bin/kill -9" : "", (int)f->store.u.ival);
+                        first = 0;
                 }
         }
+        if(!first)
+                Bprint(bout, "\n");
         exits(0);
 }
 
t@@ -545,6 +592,9 @@ gc(void)
                                 case TCODE:
                                         marktree(v->store.u.cc);
                                         break;
+                                case TCON:
+                                        marktree(v->store.u.con);
+                                        break;
                                 }
                         }
                 }
diff --git a/src/cmd/acid/print.c b/src/cmd/acid/print.c
t@@ -401,6 +401,10 @@ pexpr(Node *n)
                 if(n->sym)
                         Bprint(bout, " %s", n->sym->name);
                 break;
+        case OUPLUS:
+                Bprint(bout, "+");
+                pexpr(l);
+                break;
         }
 }
 
diff --git a/src/cmd/acid/proc.c b/src/cmd/acid/proc.c
t@@ -21,30 +21,39 @@ sproc(int xpid)
         if(pid == xpid)
                 return;
 
-        if(xpid <= 0)
-                error("bad pid");
-
-        unmapproc(cormap);
-        unmapfile(corhdr, cormap);
-        free(correg);
-        correg = nil;
-
-        if(mapproc(xpid, cormap, &correg) < 0)
-                error("setproc %d: %r", xpid);
-
-        /* XXX check text file here? */
-
+        if(corhdr){
+                free(correg);
+                correg = nil;
+                correg = coreregs(corhdr, xpid);
+                if(correg == nil)
+                        error("no such pid in core dump");
+        }else{
+                /* XXX should only change register set here if cormap already mapped */                
+                if(xpid <= 0)
+                        error("bad pid");
+                unmapproc(cormap);
+                unmapfile(corhdr, cormap);
+                free(correg);
+                correg = nil;
+
+                if(mapproc(xpid, cormap, &correg) < 0)
+                        error("setproc %d: %r", xpid);
+
+                /* XXX check text file here? */
+
+                for(i=0; inseg; i++){
+                        if(cormap->seg[i].file == nil){
+                                if(strcmp(cormap->seg[i].name, "data") == 0)
+                                        cormap->seg[i].name = "*data";
+                                if(strcmp(cormap->seg[i].name, "text") == 0)
+                                        cormap->seg[i].name = "*text";
+                        }
+                }
+        }
         pid = xpid;
         s = look("pid");
         s->v->store.u.ival = pid;
 
-        for(i=0; inseg; i++)
-                if(cormap->seg[i].file == nil){
-                        if(strcmp(cormap->seg[i].name, "data") == 0)
-                                cormap->seg[i].name = "*data";
-                        if(strcmp(cormap->seg[i].name, "text") == 0)
-                                cormap->seg[i].name = "*text";
-                }
         install(pid);
 }
 
t@@ -165,6 +174,7 @@ install(int pid)
         s->v->set = 1;
 }
 
+/*
 static int
 installed(int pid)
 {
t@@ -175,6 +185,7 @@ installed(int pid)
                         return 1;
         return 0;
 }
+*/
 
 void
 deinstall(int pid)
diff --git a/src/cmd/acid/util.c b/src/cmd/acid/util.c
t@@ -61,7 +61,6 @@ varsym(void)
                         continue;
                 addvarsym(fp);
         }
-
         if(l->v->store.u.l == nil)
                 print("no debugging symbols\n");
 }
t@@ -217,9 +216,9 @@ varreg(void)
                 l = mkvar(r->name);
                 v = l->v;
                 v->set = 1;
-                v->store.u.ival = r->offset;
+                v->store.u.reg = r->name;
                 v->store.fmt = r->format;
-                v->type = TINT;
+                v->type = TREG;
 
                 li = al(TSTRING);
                 li->store.u.string = strnode(r->name);