#include "u.h"#include "../port/lib.h"#include "mem.h"#include "dat.h"#include "fns.h"#include "error.h"#include <interp.h>#include <isa.h>#include "runt.h" /* * Enable the heap device for environments that allow debugging => * Must be 1 for a production environment. */int SECURE = 0; enum{ Qdir, Qctl, Qdbgctl, Qheap, Qns, Qnsgrp, Qpgrp, Qstack, Qstatus, Qtext, Qwait, Qfd, Qexception,}; /* * must be in same order as enum */Dirtab progdir[] ={ "ctl", {Qctl}, 0, 0200, "dbgctl", {Qdbgctl}, 0, 0600, "heap", {Qheap}, 0, 0600, "ns", {Qns}, 0, 0400, "nsgrp", {Qnsgrp}, 0, 0444, "pgrp", {Qpgrp}, 0, 0444, "stack", {Qstack}, 0, 0400, "status", {Qstatus}, 0, 0444, "text", {Qtext}, 0, 0000, "wait", {Qwait}, 0, 0400, "fd", {Qfd}, 0, 0400, "exception", {Qexception}, 0, 0400,}; enum{ CMkill, CMkillgrp, CMrestricted, CMexceptions, CMprivate}; staticCmdtab progcmd[] = { CMkill, "kill", 1, CMkillgrp, "killgrp", 1, CMrestricted, "restricted", 1, CMexceptions, "exceptions", 2, CMprivate, "private", 1,}; enum{ CDstep, CDtoret, CDcont, CDstart, CDstop, CDunstop, CDmaim, CDbpt}; staticCmdtab progdbgcmd[] = { CDstep, "step", 0, /* known below to be first, to cope with stepN */ CDtoret, "toret", 1, CDcont, "cont", 1, CDstart, "start", 1, CDstop, "stop", 1, CDunstop, "unstop", 1, CDmaim, "maim", 1, CDbpt, "bpt", 4,}; typedef struct Heapqry Heapqry;struct Heapqry{ char fmt; ulong addr; ulong module; int count;}; typedef struct Bpt Bpt; struct Bpt{ Bpt *next; int pc; char *file; char path[1];}; typedef struct Progctl Progctl;struct Progctl{ Rendez r; int ref; Proc *debugger; /* waiting for dbgxec */ char *msg; /* reply from dbgxec */ int step; /* instructions to try */ int stop; /* stop running the program */ Bpt* bpts; /* active breakpoints */ Queue* q; /* status queue */}; #define QSHIFT 4 /* location in qid of pid */#define QID(q) (((ulong)(q).path&0x0000000F)>>0)#define QPID(pid) (((pid)<<QSHIFT))#define PID(q) ((q).vers)#define PATH(q) ((ulong)(q).path&~((1<<QSHIFT)-1)) static char *progstate[] = /* must correspond to include/interp.h */{ "alt", /* blocked in alt instruction */ "send", /* waiting to send */ "recv", /* waiting to recv */ "debug", /* debugged */ "ready", /* ready to be scheduled */ "release", /* interpreter released */ "exiting", /* exit because of kill or error */ "broken", /* thread crashed */}; static void dbgstep(Progctl*, Prog*, int);static void dbgstart(Prog*);static void freebpts(Bpt*);static Bpt* delbpt(Bpt*, char*, int);static Bpt* setbpt(Bpt*, char*, int);static void mntscan(Mntwalk*, Pgrp*);extern Type *Trdchan;extern Type *Twrchan;extern Module* modules;static char Emisalign[] = "misaligned address"; static intproggen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp){ Qid qid; Prog *p; char *e; Osenv *o; ulong pid, path, perm, len; if(s == DEVDOTDOT){ mkqid(&qid, Qdir, 0, QTDIR); devdir(c, qid, "#p", 0, eve, DMDIR|0555, dp); return 1; } if((ulong)c->qid.path == Qdir) { if(name != nil){ /* ignore s and use name to find pid */ pid = strtoul(name, &e, 0); if(pid == 0 || *e != '\0') return -1; acquire(); p = progpid(pid); if(p == nil){ release(); return -1; } }else{ acquire(); p = progn(s); if(p == nil) { release(); return -1; } pid = p->pid; } o = p->osenv; sprint(up->genbuf, "%lud", pid); if(name != nil && strcmp(name, up->genbuf) != 0){ release(); return -1; } mkqid(&qid, pid<<QSHIFT, pid, QTDIR); devdir(c, qid, up->genbuf, 0, o->user, DMDIR|0555, dp); release(); return 1; } if(s >= nelem(progdir)) return -1; tab = &progdir[s]; path = PATH(c->qid); acquire(); p = progpid(PID(c->qid)); if(p == nil) { release(); return -1; } o = p->osenv; perm = tab->perm; if((perm & 7) == 0) perm = (perm|(perm>>3)|(perm>>6)) & o->pgrp->progmode; len = tab->length; mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE); devdir(c, qid, tab->name, len, o->user, perm, dp); release(); return 1;} static Chan*progattach(char *spec){ return devattach('p', spec);} static Walkqid*progwalk(Chan *c, Chan *nc, char **name, int nname){ return devwalk(c, nc, name, nname, 0, 0, proggen);} static intprogstat(Chan *c, uchar *db, int n){ return devstat(c, db, n, 0, 0, proggen);} static Chan*progopen(Chan *c, int omode){ Prog *p; Osenv *o; Progctl *ctl; int perm; if(c->qid.type & QTDIR) return devopen(c, omode, 0, 0, proggen); acquire(); if (waserror()) { release(); nexterror(); } p = progpid(PID(c->qid)); if(p == nil) error(Ethread); o = p->osenv; perm = progdir[QID(c->qid)-1].perm; if((perm & 7) == 0) perm = (perm|(perm>>3)|(perm>>6)) & o->pgrp->progmode; devpermcheck(o->user, perm, omode); omode = openmode(omode); switch(QID(c->qid)){ default: error(Egreg); case Qnsgrp: case Qpgrp: case Qtext: case Qstatus: case Qstack: case Qctl: case Qfd: case Qexception: break; case Qwait: c->aux = qopen(1024, Qmsg, nil, nil); if(c->aux == nil) error(Enomem); o->childq = c->aux; break; case Qns: c->aux = malloc(sizeof(Mntwalk)); if(c->aux == nil) error(Enomem); break; case Qheap: if(SECURE || o->pgrp->privatemem || omode != ORDWR) error(Eperm); c->aux = malloc(sizeof(Heapqry)); if(c->aux == nil) error(Enomem); break; case Qdbgctl: if(SECURE || o->pgrp->privatemem || omode != ORDWR) error(Eperm); ctl = malloc(sizeof(Progctl)); if(ctl == nil) error(Enomem); ctl->q = qopen(1024, Qmsg, nil, nil); if(ctl->q == nil) { free(ctl); error(Enomem); } ctl->bpts = nil; ctl->ref = 1; c->aux = ctl; break; } if(p->state != Pexiting) c->qid.vers = p->pid; poperror(); release(); c->offset = 0; c->mode = omode; c->flag |= COPEN; return c;} static intprogwstat(Chan *c, uchar *db, int n){ Dir d; Prog *p; char *u; Osenv *o; if(c->qid.type&QTDIR) error(Eperm); acquire(); p = progpid(PID(c->qid)); if(p == nil) { release(); error(Ethread); } u = up->env->user; o = p->osenv; if(strcmp(u, o->user) != 0 && strcmp(u, eve) != 0) { release(); error(Eperm); } n = convM2D(db, n, &d, nil); if(n == 0){ release(); error(Eshortstat); } if(d.mode != ~0UL) o->pgrp->progmode = d.mode&0777; release(); return n;} static voidclosedbgctl(Progctl *ctl, Prog *p){ Osenv *o; if(ctl->ref-- > 1) return; freebpts(ctl->bpts); if(p != nil){ o = p->osenv; if(o->debug == ctl){ o->debug = nil; p->xec = xec; } } qfree(ctl->q); free(ctl);} static voidprogclose(Chan *c){ int i; Prog *f; Osenv *o; Progctl *ctl; switch(QID(c->qid)) { case Qns: case Qheap: free(c->aux); break; case Qdbgctl: if((c->flag & COPEN) == 0) return; ctl = c->aux; acquire(); closedbgctl(ctl, progpid(PID(c->qid))); release(); break; case Qwait: acquire(); i = 0; for(;;) { f = progn(i++); if(f == nil) break; o = f->osenv; if(o->waitq == c->aux) o->waitq = nil; if(o->childq == c->aux) o->childq = nil; } release(); qfree(c->aux); }} static intprogsize(Prog *p){ int size; Frame *f; uchar *fp; Modlink *m; m = p->R.M; size = 0; if(m->MP != H) size += hmsize(D2H(m->MP)); if(m->prog != nil) size += msize(m->prog); fp = p->R.FP; while(fp != nil) { f = (Frame*)fp; fp = f->fp; if(f->mr != nil) { if(f->mr->MP != H) size += hmsize(D2H(f->mr->MP)); if(f->mr->prog != nil) size += msize(f->mr->prog); } if(f->t == nil) size += msize(SEXTYPE(f)); } return size/1024;} static longprogoffset(long offset, char *va, int *np){ if(offset > 0) { offset -= *np; if(offset < 0) { memmove(va, va+*np+offset, -offset); *np = -offset; } else *np = 0; } return offset;} static intprogqidwidth(Chan *c){ char buf[32]; return sprint(buf, "%lud", c->qid.vers);} intprogfdprint(Chan *c, int fd, int w, char *s, int ns){ int n; if(w == 0) w = progqidwidth(c); n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n", fd, &"r w rw"[(c->mode&3)<<1], devtab[c->type]->dc, c->dev, c->qid.path, w, c->qid.vers, c->qid.type, c->iounit, c->offset, c->name->s); return n;} static intprogfds(Osenv *o, char *va, int count, long offset){ Fgrp *f; Chan *c; int n, i, w, ww; Lines 1–500 of 1510. Load more
#include "u.h" #include "../port/lib.h" #include "mem.h" #include "dat.h" #include "fns.h" #include "error.h" #include <interp.h> #include <isa.h> #include "runt.h" /* * Enable the heap device for environments that allow debugging => * Must be 1 for a production environment. */ int SECURE = 0; enum { Qdir, Qctl, Qdbgctl, Qheap, Qns, Qnsgrp, Qpgrp, Qstack, Qstatus, Qtext, Qwait, Qfd, Qexception, }; /* * must be in same order as enum */ Dirtab progdir[] = { "ctl", {Qctl}, 0, 0200, "dbgctl", {Qdbgctl}, 0, 0600, "heap", {Qheap}, 0, 0600, "ns", {Qns}, 0, 0400, "nsgrp", {Qnsgrp}, 0, 0444, "pgrp", {Qpgrp}, 0, 0444, "stack", {Qstack}, 0, 0400, "status", {Qstatus}, 0, 0444, "text", {Qtext}, 0, 0000, "wait", {Qwait}, 0, 0400, "fd", {Qfd}, 0, 0400, "exception", {Qexception}, 0, 0400, }; enum { CMkill, CMkillgrp, CMrestricted, CMexceptions, CMprivate }; static Cmdtab progcmd[] = { CMkill, "kill", 1, CMkillgrp, "killgrp", 1, CMrestricted, "restricted", 1, CMexceptions, "exceptions", 2, CMprivate, "private", 1, }; enum { CDstep, CDtoret, CDcont, CDstart, CDstop, CDunstop, CDmaim, CDbpt }; static Cmdtab progdbgcmd[] = { CDstep, "step", 0, /* known below to be first, to cope with stepN */ CDtoret, "toret", 1, CDcont, "cont", 1, CDstart, "start", 1, CDstop, "stop", 1, CDunstop, "unstop", 1, CDmaim, "maim", 1, CDbpt, "bpt", 4, }; typedef struct Heapqry Heapqry; struct Heapqry { char fmt; ulong addr; ulong module; int count; }; typedef struct Bpt Bpt; struct Bpt { Bpt *next; int pc; char *file; char path[1]; }; typedef struct Progctl Progctl; struct Progctl { Rendez r; int ref; Proc *debugger; /* waiting for dbgxec */ char *msg; /* reply from dbgxec */ int step; /* instructions to try */ int stop; /* stop running the program */ Bpt* bpts; /* active breakpoints */ Queue* q; /* status queue */ }; #define QSHIFT 4 /* location in qid of pid */ #define QID(q) (((ulong)(q).path&0x0000000F)>>0) #define QPID(pid) (((pid)<<QSHIFT)) #define PID(q) ((q).vers) #define PATH(q) ((ulong)(q).path&~((1<<QSHIFT)-1)) static char *progstate[] = /* must correspond to include/interp.h */ { "alt", /* blocked in alt instruction */ "send", /* waiting to send */ "recv", /* waiting to recv */ "debug", /* debugged */ "ready", /* ready to be scheduled */ "release", /* interpreter released */ "exiting", /* exit because of kill or error */ "broken", /* thread crashed */ }; static void dbgstep(Progctl*, Prog*, int); static void dbgstart(Prog*); static void freebpts(Bpt*); static Bpt* delbpt(Bpt*, char*, int); static Bpt* setbpt(Bpt*, char*, int); static void mntscan(Mntwalk*, Pgrp*); extern Type *Trdchan; extern Type *Twrchan; extern Module* modules; static char Emisalign[] = "misaligned address"; static int proggen(Chan *c, char *name, Dirtab *tab, int, int s, Dir *dp) { Qid qid; Prog *p; char *e; Osenv *o; ulong pid, path, perm, len; if(s == DEVDOTDOT){ mkqid(&qid, Qdir, 0, QTDIR); devdir(c, qid, "#p", 0, eve, DMDIR|0555, dp); return 1; } if((ulong)c->qid.path == Qdir) { if(name != nil){ /* ignore s and use name to find pid */ pid = strtoul(name, &e, 0); if(pid == 0 || *e != '\0') return -1; acquire(); p = progpid(pid); if(p == nil){ release(); return -1; } }else{ acquire(); p = progn(s); if(p == nil) { release(); return -1; } pid = p->pid; } o = p->osenv; sprint(up->genbuf, "%lud", pid); if(name != nil && strcmp(name, up->genbuf) != 0){ release(); return -1; } mkqid(&qid, pid<<QSHIFT, pid, QTDIR); devdir(c, qid, up->genbuf, 0, o->user, DMDIR|0555, dp); release(); return 1; } if(s >= nelem(progdir)) return -1; tab = &progdir[s]; path = PATH(c->qid); acquire(); p = progpid(PID(c->qid)); if(p == nil) { release(); return -1; } o = p->osenv; perm = tab->perm; if((perm & 7) == 0) perm = (perm|(perm>>3)|(perm>>6)) & o->pgrp->progmode; len = tab->length; mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE); devdir(c, qid, tab->name, len, o->user, perm, dp); release(); return 1; } static Chan* progattach(char *spec) { return devattach('p', spec); } static Walkqid* progwalk(Chan *c, Chan *nc, char **name, int nname) { return devwalk(c, nc, name, nname, 0, 0, proggen); } static int progstat(Chan *c, uchar *db, int n) { return devstat(c, db, n, 0, 0, proggen); } static Chan* progopen(Chan *c, int omode) { Prog *p; Osenv *o; Progctl *ctl; int perm; if(c->qid.type & QTDIR) return devopen(c, omode, 0, 0, proggen); acquire(); if (waserror()) { release(); nexterror(); } p = progpid(PID(c->qid)); if(p == nil) error(Ethread); o = p->osenv; perm = progdir[QID(c->qid)-1].perm; if((perm & 7) == 0) perm = (perm|(perm>>3)|(perm>>6)) & o->pgrp->progmode; devpermcheck(o->user, perm, omode); omode = openmode(omode); switch(QID(c->qid)){ default: error(Egreg); case Qnsgrp: case Qpgrp: case Qtext: case Qstatus: case Qstack: case Qctl: case Qfd: case Qexception: break; case Qwait: c->aux = qopen(1024, Qmsg, nil, nil); if(c->aux == nil) error(Enomem); o->childq = c->aux; break; case Qns: c->aux = malloc(sizeof(Mntwalk)); if(c->aux == nil) error(Enomem); break; case Qheap: if(SECURE || o->pgrp->privatemem || omode != ORDWR) error(Eperm); c->aux = malloc(sizeof(Heapqry)); if(c->aux == nil) error(Enomem); break; case Qdbgctl: if(SECURE || o->pgrp->privatemem || omode != ORDWR) error(Eperm); ctl = malloc(sizeof(Progctl)); if(ctl == nil) error(Enomem); ctl->q = qopen(1024, Qmsg, nil, nil); if(ctl->q == nil) { free(ctl); error(Enomem); } ctl->bpts = nil; ctl->ref = 1; c->aux = ctl; break; } if(p->state != Pexiting) c->qid.vers = p->pid; poperror(); release(); c->offset = 0; c->mode = omode; c->flag |= COPEN; return c; } static int progwstat(Chan *c, uchar *db, int n) { Dir d; Prog *p; char *u; Osenv *o; if(c->qid.type&QTDIR) error(Eperm); acquire(); p = progpid(PID(c->qid)); if(p == nil) { release(); error(Ethread); } u = up->env->user; o = p->osenv; if(strcmp(u, o->user) != 0 && strcmp(u, eve) != 0) { release(); error(Eperm); } n = convM2D(db, n, &d, nil); if(n == 0){ release(); error(Eshortstat); } if(d.mode != ~0UL) o->pgrp->progmode = d.mode&0777; release(); return n; } static void closedbgctl(Progctl *ctl, Prog *p) { Osenv *o; if(ctl->ref-- > 1) return; freebpts(ctl->bpts); if(p != nil){ o = p->osenv; if(o->debug == ctl){ o->debug = nil; p->xec = xec; } } qfree(ctl->q); free(ctl); } static void progclose(Chan *c) { int i; Prog *f; Osenv *o; Progctl *ctl; switch(QID(c->qid)) { case Qns: case Qheap: free(c->aux); break; case Qdbgctl: if((c->flag & COPEN) == 0) return; ctl = c->aux; acquire(); closedbgctl(ctl, progpid(PID(c->qid))); release(); break; case Qwait: acquire(); i = 0; for(;;) { f = progn(i++); if(f == nil) break; o = f->osenv; if(o->waitq == c->aux) o->waitq = nil; if(o->childq == c->aux) o->childq = nil; } release(); qfree(c->aux); } } static int progsize(Prog *p) { int size; Frame *f; uchar *fp; Modlink *m; m = p->R.M; size = 0; if(m->MP != H) size += hmsize(D2H(m->MP)); if(m->prog != nil) size += msize(m->prog); fp = p->R.FP; while(fp != nil) { f = (Frame*)fp; fp = f->fp; if(f->mr != nil) { if(f->mr->MP != H) size += hmsize(D2H(f->mr->MP)); if(f->mr->prog != nil) size += msize(f->mr->prog); } if(f->t == nil) size += msize(SEXTYPE(f)); } return size/1024; } static long progoffset(long offset, char *va, int *np) { if(offset > 0) { offset -= *np; if(offset < 0) { memmove(va, va+*np+offset, -offset); *np = -offset; } else *np = 0; } return offset; } static int progqidwidth(Chan *c) { char buf[32]; return sprint(buf, "%lud", c->qid.vers); } int progfdprint(Chan *c, int fd, int w, char *s, int ns) { int n; if(w == 0) w = progqidwidth(c); n = snprint(s, ns, "%3d %.2s %C %4ld (%.16llux %*lud %.2ux) %5ld %8lld %s\n", fd, &"r w rw"[(c->mode&3)<<1], devtab[c->type]->dc, c->dev, c->qid.path, w, c->qid.vers, c->qid.type, c->iounit, c->offset, c->name->s); return n; } static int progfds(Osenv *o, char *va, int count, long offset) { Fgrp *f; Chan *c; int n, i, w, ww;