This incorporates Russ's comments. Not tested. - vx32 - Local 9vx git repository for patches.
       
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
 (DIR) commit 134707956d7d6de532ab5b4f9e5ae385e8c35cde
 (DIR) parent 07aabcf40153d6d889d70686e1b814f53a4f4ca2
 (HTM) Author: rminnich@nox.hsd1.ca.comcast.net <none@none>
       Date:   Tue, 20 Apr 2010 01:39:41 -0700
       
       This incorporates Russ's comments. Not tested.
       
       Diffstat:
         src/9vx/Makefrag                    |       2 +-
         src/9vx/a/AUTOGEN                   |       1 -
         src/9vx/a/devproc.c                 |      10 +++++-----
         src/9vx/a/devram.c                  |     394 -------------------------------
         src/9vx/a/portdat.h                 |       1 -
         src/9vx/a/proc.c                    |      10 +++++-----
         src/9vx/devram.c                    |     405 +++++++++++++++++++++++++++++++
         src/9vx/trap.c                      |     513 ++++++++++++++++---------------
       
       8 files changed, 675 insertions(+), 661 deletions(-)
       ---
 (DIR) diff --git a/src/9vx/Makefrag b/src/9vx/Makefrag
       @@ -33,6 +33,7 @@ PLAN9_OBJS = \
                        devip-posix.o \
                        devmntloop.o \
                        devmouse.o \
       +                devram.o \
                        devtab.o \
                        factotum.o \
                        kprocdev.o \
       @@ -74,7 +75,6 @@ PLAN9_A_OBJS = \
                        devmnt.o \
                        devproc.o \
                        devpipe.o \
       -                devram.o \
                        devroot.o \
                        devsd.o \
                        devsrv.o \
 (DIR) diff --git a/src/9vx/a/AUTOGEN b/src/9vx/a/AUTOGEN
       @@ -38,7 +38,6 @@ autofiles="
        /sys/src/9/port/devmnt.c
        /sys/src/9/port/devpipe.c
        /sys/src/9/port/devproc.c
       -/sys/src/9/port/devram.c
        /sys/src/9/port/devroot.c
        /sys/src/9/port/devsrv.c
        /sys/src/9/port/devtls.c
 (DIR) diff --git a/src/9vx/a/devproc.c b/src/9vx/a/devproc.c
       @@ -31,7 +31,7 @@ enum
                Qtext,
                Qwait,
                Qprofile,
       -        Qtruss,
       +        Qsyscall,
        };
        
        enum
       @@ -85,7 +85,7 @@ Dirtab procdir[] =
                "text",                {Qtext},        0,                        0000,
                "wait",                {Qwait},        0,                        0400,
                "profile",        {Qprofile},        0,                        0400,
       -        "truss",        {Qtruss},        0,                        0400,
       +        "syscall",        {Qsyscall},        0,                        0400,
        };
        
        static
       @@ -399,7 +399,7 @@ procopen(Chan *c, int omode)
                case Qwait:
                case Qregs:
                case Qfpregs:
       -        case Qtruss:
       +        case Qsyscall:
                        nonone(p);
                        break;
        
       @@ -709,8 +709,8 @@ procread(Chan *c, void *va, long n, vlong off)
                        memmove(a, &up->genbuf[offset], n);
                        return n;
        
       -        case Qtruss:
       -                if (! p->syscalltrace)
       +        case Qsyscall:
       +                if(!p->syscalltrace)
                                return 0;
                        n = readstr(offset, a, n, p->syscalltrace);
                        return n;
 (DIR) diff --git a/src/9vx/a/devram.c b/src/9vx/a/devram.c
       @@ -1,394 +0,0 @@
       -#include        "u.h"
       -#include        "lib.h"
       -#include        "mem.h"
       -#include        "dat.h"
       -#include        "fns.h"
       -#include        "error.h"
       -
       -#include        "netif.h"
       -
       -ttypedef struct Ram        Ram;
       -struct Ram
       -{
       -        QLock lk;
       -        Ram        *next;
       -        int        ref;
       -        /* simple for now */
       -        unsigned char **pages;
       -        int pagecount;
       -        int size;
       -        int        qref[2];
       -        ulong        path;
       -};
       -
       -struct
       -{
       -        Lock lk;
       -        ulong        path;
       -} ramalloc;
       -
       -enum
       -{
       -        Qdir,
       -        Qdata0,
       -        Qctl,
       -};
       -
       -Dirtab ramdir[] =
       -{
       -        ".",                {Qdir,0,QTDIR},        0,                DMDIR|0500,
       -        "data",                {Qdata0},        0,                0600,
       -        "ctl",        {Qctl},        0,                0600,
       -};
       -#define NPIPEDIR 3
       -
       -static void
       -raminit(void)
       -{
       -}
       -
       -/*
       - *  create a ram, no streams are created until an open
       - */
       -static Chan*
       -ramattach(char *spec)
       -{
       -        Ram *p;
       -        Chan *c;
       -
       -        c = devattach('R', spec);
       -        p = malloc(sizeof(Ram));
       -        if(p == 0)
       -                exhausted("memory");
       -        p->ref = 1;
       -        p->size = 0;
       -        p->pagecount = 1;
       -        p->pages = mallocz(sizeof(char *), 1);
       -        p->pages[0] = mallocz(BY2PG, 1);
       -        lock(&ramalloc.lk);
       -        p->path = ++ramalloc.path;
       -        unlock(&ramalloc.lk);
       -
       -        mkqid(&c->qid, NETQID(2*p->path, Qdir), 0, QTDIR);
       -        c->aux = p;
       -        c->dev = 0;
       -        return c;
       -}
       -
       -static int
       -ramgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
       -{
       -        Qid q;
       -        int len;
       -        Ram *p;
       -
       -        if(i == DEVDOTDOT){
       -                devdir(c, c->qid, "#R", 0, eve, DMDIR|0555, dp);
       -                return 1;
       -        }
       -        i++;        /* skip . */
       -        if(tab==0 || i>=ntab)
       -                return -1;
       -
       -        tab += i;
       -        p = c->aux;
       -        switch((ulong)tab->qid.path){
       -        case Qdata0:
       -                len = p->size;
       -                break;
       -        case Qctl:
       -                len = 0;
       -                break;
       -        default:
       -                len = tab->length;
       -                break;
       -        }
       -        mkqid(&q, NETQID(NETID(c->qid.path), tab->qid.path), 0, QTFILE);
       -        devdir(c, q, tab->name, len, eve, tab->perm, dp);
       -        return 1;
       -}
       -
       -
       -static Walkqid*
       -ramwalk(Chan *c, Chan *nc, char **name, int nname)
       -{
       -        Walkqid *wq;
       -        Ram *p;
       -
       -        wq = devwalk(c, nc, name, nname, ramdir, NPIPEDIR, ramgen);
       -        if(wq != nil && wq->clone != nil && wq->clone != c){
       -                p = c->aux;
       -                qlock(&p->lk);
       -                p->ref++;
       -                if(c->flag & COPEN){
       -                        print("channel open in ramwalk\n");
       -                        switch(NETTYPE(c->qid.path)){
       -                        case Qdata0:
       -                                p->qref[0]++;
       -                                break;
       -                        case Qctl:
       -                                p->qref[1]++;
       -                                break;
       -                        }
       -                }
       -                qunlock(&p->lk);
       -        }
       -        return wq;
       -}
       -
       -static int
       -ramstat(Chan *c, uchar *db, int n)
       -{
       -        Ram *p;
       -        Dir dir;
       -
       -        p = c->aux;
       -
       -        switch(NETTYPE(c->qid.path)){
       -        case Qdir:
       -                devdir(c, c->qid, ".", 0, eve, DMDIR|0555, &dir);
       -                break;
       -        case Qdata0:
       -                devdir(c, c->qid, "data", p->size, eve, 0600, &dir);
       -                break;
       -        case Qctl:
       -                devdir(c, c->qid, "ctl", 0, eve, 0600, &dir);
       -                break;
       -        default:
       -                panic("ramstat");
       -        }
       -        n = convD2M(&dir, db, n);
       -        if(n < BIT16SZ)
       -                error(Eshortstat);
       -        return n;
       -}
       -
       -/*
       - *  if the stream doesn't exist, create it
       - */
       -static Chan*
       -ramopen(Chan *c, int omode)
       -{
       -        Ram *p;
       -
       -        if(c->qid.type & QTDIR){
       -                if(omode != OREAD)
       -                        error(Ebadarg);
       -                c->mode = omode;
       -                c->flag |= COPEN;
       -                c->offset = 0;
       -                return c;
       -        }
       -
       -        p = c->aux;
       -        qlock(&p->lk);
       -        switch(NETTYPE(c->qid.path)){
       -        case Qdata0:
       -                p->qref[0]++;
       -                break;
       -        case Qctl:
       -                p->qref[1]++;
       -                break;
       -        }
       -        qunlock(&p->lk);
       -
       -        c->mode = openmode(omode);
       -        c->flag |= COPEN;
       -        c->offset = 0;
       -        c->iounit = qiomaxatomic;
       -        return c;
       -}
       -
       -static void
       -ramclose(Chan *c)
       -{
       -        Ram *p;
       -
       -        p = c->aux;
       -        qlock(&p->lk);
       -
       -        if(c->flag & COPEN){
       -                switch(NETTYPE(c->qid.path)){
       -                case Qdata0:
       -                        p->qref[0]--;
       -                        break;
       -                case Qctl:
       -                        p->qref[1]--;
       -                        break;
       -                }
       -        }
       -
       -        /*
       -         *  free the structure on last close
       -         */
       -        p->ref--;
       -        if(p->ref == 0){
       -                int i;
       -                qunlock(&p->lk);
       -                for(i = 0; i < p->pagecount; i++)
       -                        free(p->pages[i]);
       -                free(p->pages);
       -                free(p);
       -        } else
       -                qunlock(&p->lk);
       -}
       -
       -static long rampageread(Ram *p, void *va, long n, vlong offset)
       -{
       -        int i;
       -        long total = n, offinpage, leninpage;
       -
       -        /* figure out what range we can actually read */
       -        if (offset > p->size)
       -                return 0;
       -        if (offset + n > p->size) 
       -                n = p->size - offset;
       -        /* granular copy */
       -        for(i = offset / BY2PG; n > 0; i++) {
       -                /* i is the page */
       -                offinpage = offset & (BY2PG - 1);
       -                leninpage = BY2PG - offinpage;
       -                /* unless there is too little left ... */
       -                if (leninpage > n)
       -                        leninpage = n;
       -                memcpy(va, p->pages[i] + offinpage, leninpage);
       -                offset += offinpage;
       -                n -= leninpage; 
       -                va += leninpage;
       -        }
       -        return total;
       -}
       -
       -static long
       -ramread(Chan *c, void *va, long n, vlong offset)
       -{
       -        Ram *p;
       -        char *buf, *s, *e;
       -
       -        p = c->aux;
       -
       -        switch(NETTYPE(c->qid.path)){
       -        case Qdir:
       -                return devdirread(c, va, n, ramdir, NPIPEDIR, ramgen);
       -        case Qdata0:
       -                return rampageread(p, va, n, offset);
       -        case Qctl:
       -                buf = smalloc(8192);
       -                s = buf;
       -                e = buf + 8192;
       -                s = seprint(s, e, "pages %p count %d ", p->pages, p->pagecount);
       -                seprint(s, e, "size %d\n", p->size);
       -                n = readstr(offset, va, n, buf);
       -                free(buf);
       -                return n;
       -        default:
       -                panic("ramread");
       -        }
       -        return -1;        /* not reached */
       -}
       -
       -/* for the range offset .. offset + n, make sure we have pages */
       -static void pages(Ram *p, long n, vlong offset)
       -{
       -        int i;
       -        int newpagecount;
       -        unsigned char **newpages;
       -        newpagecount = (offset + n + BY2PG-1)/BY2PG;
       -        if (newpagecount > p->pagecount) {
       -                newpages = mallocz(sizeof(char *) * newpagecount, 1);
       -                if (! newpages)
       -                        error("No more pages in devram");
       -                memcpy(newpages, p->pages, sizeof(char *) * p->pagecount);
       -                free(p->pages);
       -                p->pages = newpages;
       -                p->pagecount = newpagecount;
       -                /* now allocate them */
       -                for(i = offset / BY2PG; i < newpagecount; i++) {
       -                        if (p->pages[i])
       -                                continue;
       -                        p->pages[i] = mallocz(BY2PG, 1);
       -                }
       -        }
       -}
       -static long rampagewrite(Ram *p, void *va, long n, vlong offset)
       -{
       -        int i;
       -        long total = n, offinpage, leninpage;
       -        long newsize;
       -        pages(p, n, offset);
       -        
       -        /* granular copy */
       -        newsize = offset + n;
       -        for(i = offset / BY2PG; n > 0; i++) {
       -                /* i is the page */
       -                offinpage = offset & (BY2PG - 1);
       -                leninpage = BY2PG - offinpage;
       -                /* unless there is too little left ... */
       -                if (leninpage > n)
       -                        leninpage = n;
       -                memcpy(p->pages[i] + offinpage, va, leninpage);
       -                offset += leninpage;
       -                n -= leninpage; 
       -                va += leninpage;
       -        }
       -        p->size = newsize > p->size? newsize : p->size;
       -        return total;
       -}
       -static long
       -ramwrite(Chan *c, void *va, long n, vlong offset)
       -{
       -        Ram *p;
       -
       -        if(!islo())
       -                print("ramwrite hi %lux\n", getcallerpc(&c));
       -        p = c->aux;
       -        switch(NETTYPE(c->qid.path)){
       -        case Qdata0:
       -                n = rampagewrite(p, va, n, offset);
       -                break;
       -
       -        case Qctl:
       -                if (strcmp(va, "free") == 0) {
       -                        int i;
       -                        unsigned char **new = mallocz(sizeof(char *), 1);
       -                        unsigned char *page = p->pages[0];
       -                        for(i = 1; i < p->pagecount; i++)
       -                                free(p->pages[i]);
       -                        free(p->pages);
       -                        p->pages = new;
       -                        p->pages[0] = page;
       -                        p->size = 0;
       -                        p->pagecount = 1;
       -                } else {
       -                        error("bad command");
       -                }
       -                break;
       -
       -        default:
       -                panic("ramwrite");
       -        }
       -
       -        return n;
       -}
       -
       -
       -Dev ramdevtab = {
       -        'R',
       -        "ram",
       -
       -        devreset,
       -        raminit,
       -        devshutdown,
       -        ramattach,
       -        ramwalk,
       -        ramstat,
       -        ramopen,
       -        devcreate,
       -        ramclose,
       -        ramread,
       -        devbread,
       -        ramwrite,
       -        devbwrite,
       -        devremove,
       -        devwstat,
       -};
 (DIR) diff --git a/src/9vx/a/portdat.h b/src/9vx/a/portdat.h
       @@ -754,7 +754,6 @@ struct Proc
                PMMU pmmu;
                /* syscall trace */
                char *syscalltrace;
       -        
        };
        
        enum
 (DIR) diff --git a/src/9vx/a/proc.c b/src/9vx/a/proc.c
       @@ -616,7 +616,7 @@ newproc(void)
                p->fpstate = FPinit;
                p->kp = 0;
                p->procctl = 0;
       -        if(up && (up->procctl == Proc_tracesyscall))
       +        if(up && up->procctl == Proc_tracesyscall)
                        p->procctl = Proc_tracesyscall;
                else
                        p->procctl = 0;
       @@ -839,7 +839,7 @@ twakeup(Ureg *ureg, Timer *t)
        void
        ttsleep(Rendez *r, int (*fn)(void*), void *arg, ulong ms)
        {
       -        if (up->timer.tt){
       +        if(up->timer.tt){
                        print("tsleep: timer active: mode %d, tf 0x%lux\n", up->timer.tmode, up->timer.tf);
                        timerdel(&up->timer);
                }
       @@ -856,7 +856,7 @@ tsleep(Rendez *r, int (*fn)(void*), void *arg, ulong ms)
                        nexterror();
                }
                sleep(r, tfn, arg);
       -        if (up->timer.tt)
       +        if(up->timer.tt)
                        timerdel(&up->timer);
                up->timer.twhen = 0;
                poperror();
       @@ -1052,10 +1052,10 @@ pexit(char *exitstr, int freemem)
                Chan *dot;
                void (*pt)(Proc*, int, vlong);
        
       -        if (up->syscalltrace)
       +        if(up->syscalltrace)
                        free(up->syscalltrace);
                up->alarm = 0;
       -        if (up->timer.tt)
       +        if(up->timer.tt)
                        timerdel(&up->timer);
                pt = proctrace;
                if(pt)
 (DIR) diff --git a/src/9vx/devram.c b/src/9vx/devram.c
       @@ -0,0 +1,405 @@
       +#include        "u.h"
       +#include        "lib.h"
       +#include        "mem.h"
       +#include        "dat.h"
       +#include        "fns.h"
       +#include        "error.h"
       +
       +#include        "netif.h"
       +
       +ttypedef struct Ram        Ram;
       +struct Ram
       +{
       +        QLock lk;
       +        Ram        *next;
       +        int        ref;
       +        /* simple for now */
       +        uchar **pages;
       +        int pagecount;
       +        int size;
       +        int        qref[2];
       +        ulong        path;
       +};
       +
       +struct
       +{
       +        Lock lk;
       +        ulong        path;
       +} ramalloc;
       +
       +enum
       +{
       +        Qdir,
       +        Qdata0,
       +        Qctl,
       +};
       +
       +Dirtab ramdir[] =
       +{
       +        ".",                {Qdir,0,QTDIR},        0,                DMDIR|0500,
       +        "data",                {Qdata0},        0,                0600,
       +        "ctl",        {Qctl},        0,                0600,
       +};
       +#define NPIPEDIR 3
       +
       +static void
       +raminit(void)
       +{
       +}
       +
       +/*
       + *  create a ram, no streams are created until an open
       + */
       +static Chan*
       +ramattach(char *spec)
       +{
       +        Ram *p;
       +        Chan *c;
       +
       +        c = devattach('R', spec);
       +        p = malloc(sizeof(Ram));
       +        if(p == 0)
       +                exhausted("memory");
       +        p->ref = 1;
       +        p->size = 0;
       +        p->pagecount = 1;
       +        p->pages = mallocz(sizeof(char *), 1);
       +        p->pages[0] = mallocz(BY2PG, 1);
       +        lock(&ramalloc.lk);
       +        p->path = ++ramalloc.path;
       +        unlock(&ramalloc.lk);
       +
       +        mkqid(&c->qid, NETQID(2*p->path, Qdir), 0, QTDIR);
       +        c->aux = p;
       +        c->dev = 0;
       +        return c;
       +}
       +
       +static int
       +ramgen(Chan *c, char *name, Dirtab *tab, int ntab, int i, Dir *dp)
       +{
       +        Qid q;
       +        int len;
       +        Ram *p;
       +
       +        if(i == DEVDOTDOT){
       +                devdir(c, c->qid, "#R", 0, eve, DMDIR|0555, dp);
       +                return 1;
       +        }
       +        i++;        /* skip . */
       +        if(tab==0 || i>=ntab)
       +                return -1;
       +
       +        tab += i;
       +        p = c->aux;
       +        switch((ulong)tab->qid.path){
       +        case Qdata0:
       +                len = p->size;
       +                break;
       +        case Qctl:
       +                len = 0;
       +                break;
       +        default:
       +                len = tab->length;
       +                break;
       +        }
       +        mkqid(&q, NETQID(NETID(c->qid.path), tab->qid.path), 0, QTFILE);
       +        devdir(c, q, tab->name, len, eve, tab->perm, dp);
       +        return 1;
       +}
       +
       +
       +static Walkqid*
       +ramwalk(Chan *c, Chan *nc, char **name, int nname)
       +{
       +        Walkqid *wq;
       +        Ram *p;
       +
       +        wq = devwalk(c, nc, name, nname, ramdir, NPIPEDIR, ramgen);
       +        if(wq != nil && wq->clone != nil && wq->clone != c){
       +                p = c->aux;
       +                qlock(&p->lk);
       +                p->ref++;
       +                if(c->flag & COPEN){
       +                        print("channel open in ramwalk\n");
       +                        switch(NETTYPE(c->qid.path)){
       +                        case Qdata0:
       +                                p->qref[0]++;
       +                                break;
       +                        case Qctl:
       +                                p->qref[1]++;
       +                                break;
       +                        }
       +                }
       +                qunlock(&p->lk);
       +        }
       +        return wq;
       +}
       +
       +static int
       +ramstat(Chan *c, uchar *db, int n)
       +{
       +        Ram *p;
       +        Dir dir;
       +
       +        p = c->aux;
       +
       +        switch(NETTYPE(c->qid.path)){
       +        case Qdir:
       +                devdir(c, c->qid, ".", 0, eve, DMDIR|0555, &dir);
       +                break;
       +        case Qdata0:
       +                devdir(c, c->qid, "data", p->size, eve, 0600, &dir);
       +                break;
       +        case Qctl:
       +                devdir(c, c->qid, "ctl", 0, eve, 0600, &dir);
       +                break;
       +        default:
       +                panic("ramstat");
       +        }
       +        n = convD2M(&dir, db, n);
       +        if(n < BIT16SZ)
       +                error(Eshortstat);
       +        return n;
       +}
       +
       +/*
       + *  if the stream doesn't exist, create it
       + */
       +static Chan*
       +ramopen(Chan *c, int omode)
       +{
       +        Ram *p;
       +
       +        if(c->qid.type & QTDIR){
       +                if(omode != OREAD)
       +                        error(Ebadarg);
       +                c->mode = omode;
       +                c->flag |= COPEN;
       +                c->offset = 0;
       +                return c;
       +        }
       +
       +        p = c->aux;
       +        qlock(&p->lk);
       +        switch(NETTYPE(c->qid.path)){
       +        case Qdata0:
       +                p->qref[0]++;
       +                break;
       +        case Qctl:
       +                p->qref[1]++;
       +                break;
       +        }
       +        qunlock(&p->lk);
       +
       +        c->mode = openmode(omode);
       +        c->flag |= COPEN;
       +        c->offset = 0;
       +        c->iounit = qiomaxatomic;
       +        return c;
       +}
       +
       +static void
       +ramclose(Chan *c)
       +{
       +        Ram *p;
       +
       +        p = c->aux;
       +        qlock(&p->lk);
       +
       +        if(c->flag & COPEN){
       +                switch(NETTYPE(c->qid.path)){
       +                case Qdata0:
       +                        p->qref[0]--;
       +                        break;
       +                case Qctl:
       +                        p->qref[1]--;
       +                        break;
       +                }
       +        }
       +
       +        /*
       +         *  free the structure on last close
       +         */
       +        p->ref--;
       +        if(p->ref == 0){
       +                int i;
       +                qunlock(&p->lk);
       +                for(i = 0; i < p->pagecount; i++)
       +                        free(p->pages[i]);
       +                free(p->pages);
       +                free(p);
       +        } else
       +                qunlock(&p->lk);
       +}
       +
       +static long 
       +rampageread(Ram *p, void *va, long n, vlong offset)
       +{
       +        int i;
       +        long total, offinpage, leninpage;
       +
       +        total = n;
       +
       +        /* figure out what range we can actually read */
       +        if(offset > p->size)
       +                return 0;
       +        if(offset + n > p->size) 
       +                n = p->size - offset;
       +        /* granular copy */
       +        for(i = offset / BY2PG; n > 0; i++) {
       +                /* i is the page */
       +                offinpage = offset & (BY2PG - 1);
       +                leninpage = BY2PG - offinpage;
       +                /* unless there is too little left ... */
       +                if(leninpage > n)
       +                        leninpage = n;
       +                memcpy(va, p->pages[i] + offinpage, leninpage);
       +                offset += offinpage;
       +                n -= leninpage; 
       +                va += leninpage;
       +        }
       +        return total;
       +}
       +
       +static long
       +ramread(Chan *c, void *va, long n, vlong offset)
       +{
       +        Ram *p;
       +        char *buf, *s, *e;
       +
       +        p = c->aux;
       +
       +        switch(NETTYPE(c->qid.path)){
       +        case Qdir:
       +                return devdirread(c, va, n, ramdir, NPIPEDIR, ramgen);
       +        case Qdata0:
       +                return rampageread(p, va, n, offset);
       +        case Qctl:
       +                buf = smalloc(8192);
       +                s = buf;
       +                e = buf + 8192;
       +                s = seprint(s, e, "pages %p count %d ", p->pages, p->pagecount);
       +                seprint(s, e, "size %d\n", p->size);
       +                n = readstr(offset, va, n, buf);
       +                free(buf);
       +                return n;
       +        default:
       +                panic("ramread");
       +        }
       +        return -1;        /* not reached */
       +}
       +
       +/* for the range offset .. offset + n, make sure we have pages */
       +static 
       +void pages(Ram *p, long n, vlong offset)
       +{
       +        int i;
       +        int newpagecount;
       +        uchar **newpages;
       +
       +        newpagecount = (offset + n + BY2PG-1)/BY2PG;
       +        if(newpagecount > p->pagecount) {
       +                newpages = mallocz(sizeof(char *) * newpagecount, 1);
       +                if(!newpages)
       +                        error("No more pages in devram");
       +                memcpy(newpages, p->pages, sizeof(char *) * p->pagecount);
       +                free(p->pages);
       +                p->pages = newpages;
       +                p->pagecount = newpagecount;
       +                /* now allocate them */
       +                for(i = offset / BY2PG; i < newpagecount; i++) {
       +                        if(p->pages[i])
       +                                continue;
       +                        p->pages[i] = mallocz(BY2PG, 1);
       +                }
       +        }
       +}
       +
       +static long 
       +rampagewrite(Ram *p, void *va, long n, vlong offset)
       +{
       +        int i;
       +        long total, offinpage, leninpage;
       +        long newsize;
       +
       +        total = n;
       +        pages(p, n, offset);
       +        
       +        /* granular copy */
       +        newsize = offset + n;
       +        for(i = offset / BY2PG; n > 0; i++) {
       +                /* i is the page */
       +                offinpage = offset & (BY2PG - 1);
       +                leninpage = BY2PG - offinpage;
       +                /* unless there is too little left ... */
       +                if(leninpage > n)
       +                        leninpage = n;
       +                memcpy(p->pages[i] + offinpage, va, leninpage);
       +                offset += leninpage;
       +                n -= leninpage; 
       +                va += leninpage;
       +        }
       +        p->size = newsize > p->size? newsize : p->size;
       +        return total;
       +}
       +static long
       +ramwrite(Chan *c, void *va, long n, vlong offset)
       +{
       +        Ram *p;
       +        int i;
       +        uchar **new;
       +        uchar *page;
       +
       +        if(!islo())
       +                print("ramwrite hi %lux\n", getcallerpc(&c));
       +        p = c->aux;
       +        switch(NETTYPE(c->qid.path)){
       +        case Qdata0:
       +                n = rampagewrite(p, va, n, offset);
       +                break;
       +
       +        case Qctl:
       +                if(strcmp(va, "free") == 0) {
       +                        new = mallocz(sizeof(char *), 1);
       +                        page = p->pages[0];
       +                        for(i = 1; i < p->pagecount; i++)
       +                                free(p->pages[i]);
       +                        free(p->pages);
       +                        p->pages = new;
       +                        p->pages[0] = page;
       +                        p->size = 0;
       +                        p->pagecount = 1;
       +                } else {
       +                        error("bad command");
       +                }
       +                break;
       +
       +        default:
       +                panic("ramwrite");
       +        }
       +
       +        return n;
       +}
       +
       +
       +Dev ramdevtab = {
       +        'R',
       +        "ram",
       +
       +        devreset,
       +        raminit,
       +        devshutdown,
       +        ramattach,
       +        ramwalk,
       +        ramstat,
       +        ramopen,
       +        devcreate,
       +        ramclose,
       +        ramread,
       +        devbread,
       +        ramwrite,
       +        devbwrite,
       +        devremove,
       +        devwstat,
       +};
 (DIR) diff --git a/src/9vx/trap.c b/src/9vx/trap.c
       @@ -178,358 +178,363 @@ dumpregs(Ureg* ureg)
                 */
        }
        
       +/* rsc: combine these into one? */
       +static void
       +fmtrwdata(Fmt *f, ulong s, int max, char *suffix)
       +{
       +        char *es, *t, *src;
       +        int n;
       +        int i;
       +
       +        src = (char *) s;
       +        uvalidaddr(s, 1, 0);
       +        es = vmemchr((void *)s, 0, max);
       +        n = es - src;
       +        t = smalloc(n+1);
       +        for(i = 0; i < n; i++)
       +                if (isgraph(src[i]))
       +                        t[i] = src[i];
       +                else
       +                        t[i] = '.';
       +
       +        fmtprint(f, "%08ux/%s%s", s, t, suffix);
       +        free(t);
       +}
       +
       +static void
       +fmtuserstring(Fmt *f, ulong s, char *suffix)
       +{
       +        char *es, *t, *src;
       +        int n;
       +
       +        src = (char *)s;
       +        uvalidaddr((ulong)s, 1, 0);
       +        es = vmemchr((void *)s, 0, 1<<16);
       +        n = es - src;
       +        t = smalloc(n+1);
       +        memmove(t, src, n);
       +        t[n] = 0;
       +        fmtprint(f, "%08ux/%q%s", s, t, suffix);
       +        free(t);
       +}
       +
        static void
        syscallprint(Ureg *ureg)
        {
       -        uint32 *sp = (uint32*)(up->pmmu.uzero + ureg->usp);
       -        int syscallno = ureg->ax;
       -        char *prefix;
       -        vlong offset = 0;
       -        char *special = "";
       +        uint32 *sp;
       +        int syscallno;
       +        vlong offset;
       +        Fmt fmt;
       +        int len, i;
       +          char *argv;
       +
       +        sp = (uint32*)(up->pmmu.uzero + ureg->usp);
       +        syscallno = ureg->ax;
       +        offset = 0;
       +        fmtstrinit(&fmt);
       +        fmtprint(&fmt, "%d %s", up->pid, up->text);
        
                /* accomodate process-private system calls */
       -        /* special! */
       -        if ((syscallno == RFORK)  && (sp[2] & RFPROC))
       -                special="Proc";
        
       -        if (syscallno > nelem(sysctab))
       -                prefix = smprint("%d %s %d %#ux", up->pid, up->text, syscallno, sp[0]);
       +        if(syscallno > nelem(sysctab))
       +                fmtprint(&fmt, " %d %#x", syscallno, sp[0]);
                else
       -                prefix = smprint("%d %s %s%s %#ux", up->pid, up->text, special, sysctab[syscallno], sp[0]);
       +                fmtprint(&fmt, "%s %#ux", sysctab[syscallno], sp[0]);
       +
       +        if(up->syscalltrace)
       +                free(up->syscalltrace);
        
       -        if (up->syscalltrace)
       -                panic("syscallprint");
                switch(syscallno) {
                case SYSR1:
       -                up->syscalltrace = smprint("%s %08ux %08ux %08ux", prefix, sp[1], sp[2], sp[3]);
       +                fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
                        break;
                case _ERRSTR:
       -                up->syscalltrace = smprint("%s %#ux/", prefix, sp[1]);
       +                fmtuserstring(&fmt, sp[1], "");
                        break;
       -        case BIND:{
       -                char *s1 =  uvalidaddr(sp[1], 1, 0);
       -                char *s2 =  uvalidaddr(sp[2], 1, 0);
       -                up->syscalltrace = smprint("%s %08x/%s  %08x/%s %#ux", prefix,  sp[1], s1, sp[2], s2, sp[3]);
       +        case BIND:
       +                fmtuserstring(&fmt, sp[1], " ");
       +                fmtuserstring(&fmt, sp[2], " ");
       +                fmtprint(&fmt, "%#ux",  sp[3]);
       +                break;
       +        case CHDIR:
       +                fmtuserstring(&fmt, sp[1], "");
                        break;
       -        }
       -        case CHDIR:{
       -                char *s =  uvalidaddr(sp[1], 1, 0);
       -                up->syscalltrace = smprint("%s %08x/%s  ", prefix, 
       -                sp[1], s);
       -        break;
       -        }
                case CLOSE:
       -                up->syscalltrace = smprint("%s %d", prefix, sp[1]);
       +                fmtprint(&fmt, "%d", sp[1]);
                        break;
                case DUP:
       -                up->syscalltrace = smprint("%s %08ux %08ux", prefix, sp[1], sp[2]);
       +                fmtprint(&fmt, "%08ux %08ux", sp[1], sp[2]);
                        break;
                case ALARM:
       -                up->syscalltrace = smprint("%s %08ux ", prefix, sp[1]);
       +                fmtprint(&fmt, "%08ux ", sp[1]);
                        break;
       -        case EXEC: {
       -                char *execargs;
       -                char *name =uvalidaddr(sp[1], 1, 0);
       -                uint32 *argv = uvalidaddr(sp[2], 1, 0);
       -                int j = 0, i;
       -                execargs = mallocz(4096,1);
       -                j += snprint(execargs, 4096, "%08ux/\"%s\" ",sp[1], name);
       -                /* more than 4096 of args, we just don't do */
       -                for(i = 0; argv[i] && (j > 5); i++) {
       -                        char *str = uvalidaddr(argv[i], 1, 0);
       -                        j += snprint(execargs+j,4096-j, "%08ux/%s ", argv[i], str);
       +        case EXEC: 
       +                fmtuserstring(&fmt, sp[1], "");
       +                argv = uvalidaddr(sp[2], 1, 0);
       +                for(i = 0; argv[i]; i++) {
       +                        fmtprint(&fmt, " ");
       +                        fmtuserstring(&fmt, argv[i], "");
                        }
       -                /* assume */
       -                if (j == 5)
       -                        snprint(up->syscalltrace+j,4096-j, " ...");
       -                up->syscalltrace = smprint("%s %s", prefix, execargs);
       -                free(execargs);
                        break;
       -        }
       -        case EXITS:{
       -                char *msg = sp[1] ? uvalidaddr(sp[1], 1, 0) : "";
       -                up->syscalltrace = smprint("%s %08ux", prefix, sp[1], msg);
       +        case EXITS:
       +                 fmtuserstring(&fmt, sp[1], "");
                        break;
       -        }
                case _FSESSION:
       -                up->syscalltrace = smprint("%s %08ux %08ux %08ux", prefix, sp[1], sp[2], sp[3]);
       +                fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
                        break;
       -        case FAUTH:{
       -                char *aname = uvalidaddr(sp[2], 1, 0);
       -                up->syscalltrace = smprint("%s %08ux %08ux/%s", prefix, sp[1], aname);
       +        case FAUTH:
       +                fmtprint(&fmt, "%08ux", sp[1]);
       +                fmtuserstring(&fmt, sp[2], "");
                        break;
       -        }
       -        case _FSTAT:{
       -                up->syscalltrace = smprint("%s %08ux %#ux %08ux", prefix, sp[1], sp[2], sp[3]);
       +        case _FSTAT:
       +                fmtprint(&fmt, "%08ux %#ux %08ux", sp[1], sp[2], sp[3]);
                        break;
       -        }
                case SEGBRK:
       -                up->syscalltrace = smprint("%s %#ux %#ux", prefix, sp[1], sp[2]);
       +                fmtprint(&fmt, "%#ux %#ux", sp[1], sp[2]);
                        break;
       -        case _MOUNT:{
       -                char *old =uvalidaddr(sp[3], 1, 0);
       -                char *aname = sp[5] ? uvalidaddr(sp[5], 1, 0) : "";
       -                up->syscalltrace = smprint("%s %d %d %08ux=%s %08ux %#ux/%s", prefix, 
       -                        sp[1], sp[2], sp[3], old, sp[4],sp[5], aname);
       +        case _MOUNT:
       +                fmtprint(&fmt, "%d %d ", sp[1], sp[2]);
       +                fmtuserstring(&fmt, sp[3], " ");
       +                fmtprint(&fmt, "%08ux ", sp[4]);
       +                fmtuserstring(&fmt, sp[5], "");
                        break;
       -        }
       -        case OPEN: {
       -                char *s;
       -                s = uvalidaddr(sp[1], 1, 0);
       -                up->syscalltrace = smprint("%s %08x/%s %08ux", prefix, sp[1], s, sp[2]);
       +        case OPEN:
       +                fmtuserstring(&fmt, sp[1], " ");
       +                fmtprint(&fmt, "%08ux", sp[2]);
                        break;
       -        }
                case OSEEK:
       -                up->syscalltrace = smprint("%s %08ux %08ux", prefix, sp[1], sp[2]);
       +                fmtprint(&fmt, "%08ux %08ux", sp[1], sp[2]);
                        break;
       -        case SLEEP: {
       -                up->syscalltrace = smprint("%s %d", prefix, sp[1]);
       +        case SLEEP: 
       +                fmtprint(&fmt, "%d", sp[1]);
                        break;
       -        }
       -        case _STAT:{
       -                char *name = uvalidaddr(sp[1], 1, 0);
       -                up->syscalltrace = smprint("%s %08ux/%s %#ux %d", prefix,  sp[1], name, sp[2], sp[3]);
       +        case _STAT:
       +                fmtuserstring(&fmt, sp[1], " ");
       +                fmtprint(&fmt, "%#ux %d", sp[2], sp[3]);
                        break;
       -        }
       -        case RFORK:{
       -                up->syscalltrace = smprint("%s %08ux", prefix, sp[1] );
       +        case RFORK:
       +                fmtprint(&fmt, "%08ux", sp[1] );
                        break;
       -        }
                case PIPE: 
       -                up->syscalltrace = smprint("%s", prefix);
                        break;
       -        case CREATE:{
       -                char *name = uvalidaddr(sp[1], 1, 0);
       -                up->syscalltrace = smprint("%s %#ux/\"%s\" %08ux %08ux", prefix, sp[1], name, sp[2], sp[3]);
       +        case CREATE:
       +                fmtuserstring(&fmt, sp[1], " ");
       +                fmtprint(&fmt, "%08ux %08ux", sp[2], sp[3]);
                        break;
       -        }
                case FD2PATH:
       -                up->syscalltrace = smprint("%s %d %#ux %d", prefix, sp[1], sp[2], sp[3]);
       +                fmtprint(&fmt, "%d ", sp[1]);
                        break;
                case BRK_:
       -                up->syscalltrace = smprint("%s %08ux %08ux %08ux", prefix, 
       -                sp[1], sp[2], sp[3]);
       +                fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
                        break;
       -        case REMOVE:{
       -                char *name = uvalidaddr(sp[1], 1, 0);
       -                up->syscalltrace = smprint("%s %#ux/%s", prefix, 
       -                sp[1], name);
       +        case REMOVE:
       +                fmtuserstring(&fmt, sp[1], " ");
                        break;
       -        }
                /* deprecated */
                case _WSTAT:
       -                up->syscalltrace = smprint("%s %08ux %08ux %08ux", prefix, sp[1], sp[2], sp[3]);
       +                fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
                        break;
                case _FWSTAT:
       -                up->syscalltrace = smprint("%s %08ux %08ux %08ux", prefix, sp[1], sp[2], sp[3]);
       +                fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
                        break;
                case NOTIFY:
       -                up->syscalltrace = smprint("%s %08ux %08ux %08ux", prefix, sp[1], sp[2], sp[3]);
       +                fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
                        break;
                case NOTED:
       -                up->syscalltrace = smprint("%s %08ux %08ux %08ux", prefix, sp[1], sp[2], sp[3]);
       +                fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
                        break;
                case SEGATTACH:
       -                up->syscalltrace = smprint("%s %08ux %08ux %08ux", prefix, sp[1], sp[2], sp[3]);
       +                fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
                        break;
                case SEGDETACH:
       -                up->syscalltrace = smprint("%s %08ux %08ux %08ux", prefix, sp[1], sp[2], sp[3]);
       +                fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
                        break;
                case SEGFREE:
       -                up->syscalltrace = smprint("%s %08ux %08ux %08ux", prefix, sp[1], sp[2], sp[3]);
       +                fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
                        break;
                case SEGFLUSH:
       -                up->syscalltrace = smprint("%s %08ux %08ux %08ux", prefix, sp[1], sp[2], sp[3]);
       +                fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
                        break;
                case RENDEZVOUS:
       -                up->syscalltrace = smprint("%s %08ux %08ux %08ux", prefix, 
       -                sp[1], sp[2], sp[3]);
       +                fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
                        break;
       -        case UNMOUNT:{
       -                char *name = uvalidaddr(sp[1], 1, 0);
       -                up->syscalltrace = smprint("%s %#ux/%s", prefix, sp[1], name);
       +        case UNMOUNT:
       +                fmtuserstring(&fmt, sp[1], " ");
                        break;
       -        }
                case _WAIT:
       -                up->syscalltrace = smprint("%s %08ux %08ux %08ux", prefix, sp[1], sp[2], sp[3]);
       +                fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
                        break;
                case SEMACQUIRE:
       -                up->syscalltrace = smprint("%s %08ux %#ux %d", prefix, sp[1], sp[2], sp[3]);
       +                fmtprint(&fmt, "%08ux %#ux %d", sp[1], sp[2], sp[3]);
                        break;
                case SEMRELEASE:
       -                up->syscalltrace = smprint("%s %08ux %#ux %d", prefix, sp[1], sp[2], sp[3]);
       +                fmtprint(&fmt, "%08ux %#ux %d", sp[1], sp[2], sp[3]);
                        break;
                case SEEK:
       -                up->syscalltrace = smprint("%s %08ux %016ux %08ux", prefix, sp[1], *(vlong *)&sp[2], sp[4]);
       +                fmtprint(&fmt, "%08ux %016ux %08ux", sp[1], *(vlong *)&sp[2], sp[4]);
                        break;
       -        case FVERSION:{
       -                char *version = uvalidaddr(sp[1], 1, 0);
       -                up->syscalltrace = smprint("%s %08ux %08ux %08ux/%s", prefix, sp[1], sp[2], sp[3], version);
       +        case FVERSION:
       +                fmtprint(&fmt, "%08ux %08ux ", sp[1], sp[2]);
       +                fmtuserstring(&fmt, sp[5], "");
                        break;
       -        }
                case ERRSTR:
       -                up->syscalltrace = smprint("%s %#ux/", prefix, sp[1]);
       +                fmtprint(&fmt, "%#ux/", sp[1]);
                        break;
                case WSTAT:
       -        case STAT:{
       -                char *name = uvalidaddr(sp[1], 1, 0);
       -                up->syscalltrace = smprint("%s %08ux %08ux/%s %08ux", prefix, sp[1], sp[2], name, sp[3]);
       +        case STAT:
       +                fmtprint(&fmt, "%08ux ", sp[1]);
       +                fmtuserstring(&fmt, sp[2], " ");
       +                fmtprint(&fmt, "%08ux", sp[3]);
                        break;
       -        }
                case FSTAT:
                case FWSTAT:
       -                up->syscalltrace = smprint("%s %08ux %08ux %08ux", prefix, sp[1], sp[2], sp[3]);
       +                fmtprint(&fmt, "%08ux %08ux %08ux", sp[1], sp[2], sp[3]);
                        break;
       -        case MOUNT:{
       -                char *old =uvalidaddr(sp[3], 1, 0);
       -                char *aname = sp[5]? uvalidaddr(sp[5], 1, 0) : "";
       -                up->syscalltrace = smprint("%s %d %d %08ux=%s %08ux %#ux/", prefix, sp[1], sp[2], sp[3], old, sp[4],sp[5], aname);
       +        case MOUNT:
       +                fmtprint(&fmt, "%d %d ", sp[1], sp[3]);
       +                fmtuserstring(&fmt, sp[3], " ");
       +                fmtprint(&fmt, "%08ux", sp[4]);
       +                fmtuserstring(&fmt, sp[5], "");
                        break;
       -        }
                case AWAIT:
       -                up->syscalltrace = smprint("%s %08ux %#ux", prefix, sp[1], sp[2]);
       +                fmtprint(&fmt, "%08ux %#ux", sp[1], sp[2]);
                        break;
                case _READ: 
                case PREAD:
       -                up->syscalltrace = smprint("%s %d %#ux", prefix, sp[1], sp[2]);
       +                fmtprint(&fmt, "%d %#ux", sp[1], sp[2]);
                        break;
                case _WRITE:
                        offset = -1;
       -        case PWRITE:{
       -                int len = sp[3] > 64 ? 64 : sp[3];
       -                  char *s = uvalidaddr(sp[2], len, 0);
       -                int i;
       -                char a[65];
       -                memset(a, 0, sizeof(a));
       -                for(i = 0; i < len; i++)
       -                        a[i] = isgraph(s[i]) ? s[i] : '.';
       -                if (! offset)
       +        case PWRITE:
       +                fmtprint(&fmt, "%d ", sp[1]);
       +                if (sp[3] < 64)
       +                        len = sp[3];
       +                else
       +                        len = 64;
       +                 fmtrwdata(&fmt, sp[2], len, " ");
       +                if(! offset)
                                offset = *(vlong *)&sp[4];
       -                up->syscalltrace = smprint("%s %d %#ux/\"%s\" %d %#llx", prefix, sp[1], sp[2], a, sp[3], offset);
       +                fmtprint(&fmt, "%d %#llx", sp[3], offset);
                        break;
                }
       -        }
       -        free(prefix);        
       +        up->syscalltrace = fmtstrflush(&fmt);
        }
        
        static void
        retprint(Ureg *ureg, int syscallno, uvlong start, uvlong stop)
        {
       -        char *prefix = nil;
       -        int errstrlen = 0;
       -        vlong offset = 0;
       +        int errstrlen, len;
       +        vlong offset;
       +        char *errstr;
       +        Fmt fmt;
       +
       +        fmtstrinit(&fmt);
       +        len = 0;
       +        errstrlen = 0;
       +        offset = 0;
       +        if (ureg->ax == -1)
       +                errstr = "\"\"";
       +        else
       +                errstr = up->errstr;
       +
       +        if(up->syscalltrace)
       +                free(up->syscalltrace);
        
       -        if (up->syscalltrace)
       -                panic("retprint");
                switch(syscallno) {
       -                case SYSR1:
       -                case BIND:
       -                case CHDIR:
       -                case CLOSE:
       -                case DUP:
       -                case ALARM:
       -                case EXEC:
       -                case EXITS:
       -                case _FSESSION:
       -                case FAUTH:
       -                case _FSTAT:
       -                case SEGBRK:
       -                case _MOUNT:
       -                case OPEN:
       -                case OSEEK:
       -                case SLEEP:
       -                case _STAT:
       -                case _WRITE:
       -                case PIPE:
       -                case CREATE:
       -                case BRK_:
       -                case REMOVE:
       -                case _WSTAT:
       -                case _FWSTAT:
       -                case NOTIFY:
       -                case NOTED:
       -                case SEGATTACH:
       -                case SEGDETACH:
       -                case SEGFREE:
       -                case SEGFLUSH:
       -                case RENDEZVOUS:
       -                case UNMOUNT:
       -                case _WAIT:
       -                case SEMACQUIRE:
       -                case SEMRELEASE:
       -                case SEEK:
       -                case FVERSION:
       -                case STAT:
       -                case FSTAT:
       -                case WSTAT:
       -                case FWSTAT:
       -                case MOUNT:
       -                case PWRITE:
       -                case RFORK:
       -                default: 
       +        case SYSR1:
       +        case BIND:
       +        case CHDIR:
       +        case CLOSE:
       +        case DUP:
       +        case ALARM:
       +        case EXEC:
       +        case EXITS:
       +        case _FSESSION:
       +        case FAUTH:
       +        case _FSTAT:
       +        case SEGBRK:
       +        case _MOUNT:
       +        case OPEN:
       +        case OSEEK:
       +        case SLEEP:
       +        case _STAT:
       +        case _WRITE:
       +        case PIPE:
       +        case CREATE:
       +        case BRK_:
       +        case REMOVE:
       +        case _WSTAT:
       +        case _FWSTAT:
       +        case NOTIFY:
       +        case NOTED:
       +        case SEGATTACH:
       +        case SEGDETACH:
       +        case SEGFREE:
       +        case SEGFLUSH:
       +        case RENDEZVOUS:
       +        case UNMOUNT:
       +        case _WAIT:
       +        case SEMACQUIRE:
       +        case SEMRELEASE:
       +        case SEEK:
       +        case FVERSION:
       +        case STAT:
       +        case FSTAT:
       +        case WSTAT:
       +        case FWSTAT:
       +        case MOUNT:
       +        case PWRITE:
       +        case RFORK:
       +        default: 
       +        break;
       +        case AWAIT:
       +                if(ureg->ax > 0){
       +                        fmtuserstring(&fmt, up->s.args[1], "");
       +                } else {
       +                        fmtprint(&fmt, "\"\" %d", up->s.args[1]);
       +                }
                        break;
       -                case AWAIT:{
       -                        /* already filled in but we need the pointer -- only check read */
       -                        char *msg = uvalidaddr(up->s.args[0], 1, 0), *msgp;
       -                        if (ureg->ax > 0){
       -                                msgp = mallocz(ureg->ax+1, 1);
       -                                memmove(msgp, msg, ureg->ax);
       -                                prefix = smprint("/\"%s\" %d", msgp, up->s.args[1]);
       -                                free(msgp);
       -                        } else {
       -                                prefix = smprint("\"\" %d", up->s.args[1]);
       -                        }
       -                        break;
       +        case _ERRSTR:
       +                errstrlen = 64;
       +        case ERRSTR:
       +                if(! errstrlen)
       +                        errstrlen = up->s.args[1];
       +                if(ureg->ax > 0){
       +                        fmtuserstring(&fmt, up->s.args[0], " ");
       +                        fmtprint(&fmt, "%d", errstrlen);
       +                } else {
       +                        fmtprint(&fmt, "\"\" %d", errstrlen);
                        }
       -                case _ERRSTR:
       -                        errstrlen = 64;
       -                case ERRSTR:{
       -                        /* already filled in but we need the pointer -- only check read */
       -                        char *msg = uvalidaddr(up->s.args[0], 1, 0);
       -                        if (! errstrlen)
       -                                errstrlen = up->s.args[1];
       -                        if (ureg->ax > 0){
       -                                prefix = smprint("/\"%s\" %d", msg, errstrlen);
       -                        } else {
       -                                prefix = smprint("\"\" %d", errstrlen);
       -                        }
       -                        break;
       +                break;
       +        case FD2PATH:
       +                if(ureg->ax == -1)
       +                        fmtprint(&fmt, "\"\" %d", up->s.args[2]);
       +                else {
       +                        fmtuserstring(&fmt, up->s.args[1], " ");
       +                        fmtprint(&fmt, "%d", errstrlen);
                        }
       -                case FD2PATH:
       -                        if(ureg->ax == -1)
       -                                up->syscalltrace = smprint("/\"\" %d", up->s.args[2]);
       -                        else {
       -                                char *s = uvalidaddr(up->s.args[1], 1, 0);
       -                                up->syscalltrace = smprint("/\"%s\" %d", s, up->s.args[2]);
       -                        }
       -                        break;
       -                case _READ:
       -                        offset = -1;
       -                case PREAD:
       -                        if(ureg->ax == -1)
       -                                prefix = smprint("/\"\" %d 0x%ullx", up->s.args[2], *(vlong *)&up->s.args[3]);
       -                        else {
       -                                int len = ureg->ax > 64 ? 64 : ureg->ax;
       -                                char *s = uvalidaddr(up->s.args[1], len, 0);
       -                                char a[65];
       -                                int i;
       -                                memset(a, 0, sizeof(a));
       -                                for(i = 0; i < len; i++)
       -                                        a[i] = isgraph(s[i]) ? s[i] : '.';
       -                                if (! offset)
       -                                        offset = *(vlong *)&up->s.args[3];
       -                                prefix = smprint("/\"%s\" %d %#llx", a, up->s.args[2], offset);
       -                        }
                        break;
       +        case _READ:
       +                offset = -1;
       +        case PREAD:
       +                if(ureg->ax == -1)
       +                        fmtprint(&fmt, "/\"\" %d 0x%ullx", up->s.args[2], *(vlong *)&up->s.args[3]);
       +                else {
       +                        if (ureg->ax > 64)
       +                                len = 64;
       +                        else
       +                                len = ureg->ax;
       +                        fmtrwdata(&fmt, up->s.args[1], len, " ");
       +                        if(! offset)
       +                                offset = *(vlong *)&up->s.args[3];
       +                        fmtprint(&fmt, "%d %#llx", up->s.args[2], offset);
       +                }
       +        break;
                }
        
       -        if (prefix){
       -                up->syscalltrace = smprint("%s = %d %s %#ullx %#ullx\n", prefix, ureg->ax, ureg->ax == -1 ? up->errstr : "\"\"", start, stop);
       -                free(prefix);
       -        } else {
       -                up->syscalltrace = smprint(" = %d %s %#ullx %#ullx\n", ureg->ax, ureg->ax == -1  ? up->errstr : "\"\"", start, stop);
       -        }
       -        
       +        fmtprint(&fmt, " = %d %s %#ullx %#ullx\n", ureg->ax, errstr, start, stop);
       +
       +        up->syscalltrace = fmtstrflush(&fmt);
        }
        /*
         * Handle a system call.
       @@ -543,8 +548,9 @@ syscall(Ureg *ureg)
                long        ret;
                int s;
                ulong scallnr;
       -        vlong startnsec = 0ULL, stopnsec = 0ULL;
       +        vlong startnsec, stopnsec;
        
       +        USED(startnsec);
                cycles(&up->kentry);
                m->syscall++;
                up->insyscall = 1;
       @@ -555,9 +561,9 @@ syscall(Ureg *ureg)
                        up->procctl = Proc_stopme;
                        syscallprint(ureg);
                        procctl(up);
       -                if (up->syscalltrace)
       +                if(up->syscalltrace)
                                free(up->syscalltrace);
       -                up->syscalltrace = NULL;
       +                up->syscalltrace = nil;
                        startnsec = todget(nil);
                }
        
       @@ -624,10 +630,9 @@ syscall(Ureg *ureg)
                        s = splhi();
                        procctl(up);
                        splx(s);
       -                /* you must have read the string by now. The free above is really not needed */
       -                if (up->syscalltrace)
       +                if(up->syscalltrace)
                                free(up->syscalltrace);
       -                up->syscalltrace = NULL;
       +                up->syscalltrace = nil;
                }
        
                up->insyscall = 0;