/*#include */ #include #include #include "mach.h" #define Extern #include "acid.h" #include "y.tab.h" char *argv0; char *acidlib; static Biobuf bioout; static char prog[128]; static char* lm[16]; static int nlm; static char* mtype; static int attachfiles(char*, int); int xconv(va_list*, Fconv*); extern gfltconv(va_list *, Fconv*); int isnumeric(char*); void die(void); void usage(void) { fprint(2, "usage: acid [-l module] [-m machine] [-qrw] [-k] [-d flag] [-R tty] [pid] [file]\n"); exits("usage"); } void main(int argc, char *argv[]) { Dir db; Lsym *l; Node *n; char buf[128], *s; int pid, i; char *p; char afile[256]; argv0 = argv[0]; pid = 0; aout = "v.out"; quiet = 1; /* turn off all debugging */ protodebug = 0; mtype = 0; ARGBEGIN{ case 'm': mtype = ARGF(); break; case 'w': wtflag = 1; break; case 'l': s = ARGF(); if(s == 0) usage(); lm[nlm++] = s; break; case 'd': p = ARGF(); if (p == 0) usage(); while (*p) { setdbg_opt(*p, 0); /* don't print set message */ p++; } break; case 'k': kernel++; break; case 'q': quiet = 0; break; case 'r': pid = 1; remote++; kernel++; break; case 'R': pid = 1; rdebug++; s = ARGF(); if(s == 0) usage(); remfd = opentty(s, 19200); if(remfd < 0){ fprint(2, "acid: can't open %s: %r\n", s); exits("open"); } break; default: usage(); }ARGEND if(argc > 0) { if(remote || rdebug) aout = argv[0]; else if(isnumeric(argv[0])) { pid = atoi(argv[0]); sprint(prog, "/proc/%d/text", pid); aout = prog; if(argc > 1) aout = argv[1]; else if(kernel) aout = mysystem(); } else { if(kernel) { print("-k requires a pid"); kernel = 0; } aout = argv[0]; } } else if(rdebug) aout = "/386/bpc"; else if(remote) aout = "/mips/bcarrera"; fmtinstall('x', xconv); fmtinstall('L', Lconv); fmtinstall('f', gfltconv); fmtinstall('F', gfltconv); fmtinstall('g', gfltconv); fmtinstall('G', gfltconv); fmtinstall('e', gfltconv); fmtinstall('E', gfltconv); Binit(&bioout, 1, OWRITE); bout = &bioout; kinit(); initialising = 1; pushfile(0); loadvars(); installbuiltin(); if(mtype && machbyname(mtype) == 0) print("unknown machine %s", mtype); if (attachfiles(aout, pid) < 0) varreg(); /* use default register set on error */ acidlib = getenv("ACIDLIB"); if(acidlib == nil){ p = getenv("ROOT"); if(p == nil) p = "/usr/inferno"; snprint(afile, sizeof(afile)-1, "%s/lib/acid", p); acidlib = strdup(afile); } snprint(afile, sizeof(afile)-1, "%s/port", acidlib); loadmodule(afile); for(i = 0; i < nlm; i++) { if(dirstat(lm[i], &db) >= 0) loadmodule(lm[i]); else { sprint(buf, "%s/%s", acidlib, lm[i]); loadmodule(buf); } } userinit(); varsym(); l = look("acidmap"); if(l && l->proc) { n = an(ONAME, ZN, ZN); n->sym = l; n = an(OCALL, n, ZN); execute(n); } interactive = 1; initialising = 0; line = 1; setup_os_notify(); for(;;) { if(setjmp(err)) { Binit(&bioout, 1, OWRITE); unwind(); } stacked = 0; Bprint(bout, "acid: "); if(yyparse() != 1) die(); restartio(); unwind(); } Bputc(bout, '\n'); exits(0); } static int attachfiles(char *aout, int pid) { interactive = 0; if(setjmp(err)) return -1; if(aout) { /* executable given */ if(wtflag) text = open(aout, ORDWR); else text = open(aout, OREAD); if(text < 0) error("%s: can't open %s: %r\n", argv0, aout); readtext(aout); } if(pid) /* pid given */ sproc(pid); return 0; } void die(void) { Lsym *s; List *f; Bprint(bout, "\n"); s = look("proclist"); if(!rdebug && s && s->v->type == TLIST) { for(f = s->v->vstore.u0.sl; f; f = f->next) Bprint(bout, "echo kill > /proc/%d/ctl\n", (int)f->lstore.u0.sival); } exits(0); } void userinit(void) { Lsym *l; Node *n; char buf[256], *p; p = getenv("home"); if(p == 0) p = getenv("HOME"); if(p != 0) { snprint(buf, sizeof(buf)-1, "%s/lib/acid", p); silent = 1; loadmodule(buf); } if(rdebug){ snprint(buf, sizeof(buf)-1, "%s/rdebug", acidlib); loadmodule(buf); } snprint(buf, sizeof(buf)-1, "%s/%s", acidlib, mach->name); loadmodule(buf); interactive = 0; if(setjmp(err)) { unwind(); return; } l = look("acidinit"); if(l && l->proc) { n = an(ONAME, ZN, ZN); n->sym = l; n = an(OCALL, n, ZN); execute(n); } } void loadmodule(char *s) { interactive = 0; if(setjmp(err)) { unwind(); return; } pushfile(s); silent = 0; yyparse(); popio(); return; } void readtext(char *s) { Dir d; Lsym *l; Value *v; Symbol sym; extern Machdata mipsmach; if(mtype != 0){ symmap = newmap(0, 1); if(symmap == 0) print("%s: (error) loadmap: cannot make symbol map\n", argv0); if(dirfstat(text, &d) < 0) d.length = 1<<24; setmap(symmap, text, 0, d.length, 0, "binary"); return; } machdata = &mipsmach; if(!crackhdr(text, &fhdr)) { print("can't decode file header\n"); return; } symmap = loadmap(0, text, &fhdr); if(symmap == 0) print("%s: (error) loadmap: cannot make symbol map\n", argv0); if(syminit(text, &fhdr) < 0) { print("%s: (error) syminit: %r\n", argv0); return; } print("%s:%s\n\n", s, fhdr.name); if(mach->sbreg && lookup(0, mach->sbreg, &sym)) { mach->sb = sym.value; l = enter("SB", Tid); l->v->vstore.fmt = 'X'; l->v->vstore.u0.sival = mach->sb; l->v->type = TINT; l->v->set = 1; } l = mkvar("objtype"); v = l->v; v->vstore.fmt = 's'; v->set = 1; v->vstore.u0.sstring = strnode(mach->name); v->type = TSTRING; l = mkvar("textfile"); v = l->v; v->vstore.fmt = 's'; v->set = 1; v->vstore.u0.sstring = strnode(s); v->type = TSTRING; machbytype(fhdr.type); varreg(); } Node* an(int op, Node *l, Node *r) { Node *n; n = gmalloc(sizeof(Node)); n->ngc.gclink = gcl; gcl = &n->ngc; n->op = op; n->left = l; n->right = r; return n; } List* al(int t) { List *l; l = gmalloc(sizeof(List)); l->type = t; l->lgc.gclink = gcl; gcl = &l->lgc; return l; } Node* con(int v) { Node *n; n = an(OCONST, ZN, ZN); n->nstore.u0.sival = v; n->nstore.fmt = 'X'; n->type = TINT; return n; } void fatal(char *fmt, ...) { char buf[128]; va_list arg; va_start(arg, fmt); doprint(buf, buf+sizeof(buf), fmt, arg); va_end(arg); fprint(2, "%s: %L (fatal problem) %s\n", argv0, buf); exits(buf); } void yyerror(char *fmt, ...) { char buf[128]; va_list arg; if(strcmp(fmt, "syntax error") == 0) { yyerror("syntax error, near symbol '%s'", symbol); return; } va_start(arg, fmt); doprint(buf, buf+sizeof(buf), fmt, arg); va_end(arg); print("%L: %s\n", buf); } void marktree(Node *n) { if(n == 0) return; marktree(n->left); marktree(n->right); n->ngc.gcmark = 1; if(n->op != OCONST) return; switch(n->type) { case TSTRING: n->nstore.u0.sstring->sgc.gcmark = 1; break; case TLIST: marklist(n->nstore.u0.sl); break; case TCODE: marktree(n->nstore.u0.scc); break; } } void marklist(List *l) { while(l) { l->lgc.gcmark = 1; switch(l->type) { case TSTRING: l->lstore.u0.sstring->sgc.gcmark = 1; break; case TLIST: marklist(l->lstore.u0.sl); break; case TCODE: marktree(l->lstore.u0.scc); break; } l = l->next; } } void gc(void) { int i; Lsym *f; Value *v; Gc *m, **p, *next; if(dogc < Mempergc) return; dogc = 0; /* Mark */ for(m = gcl; m; m = m->gclink) m->gcmark = 0; /* Scan */ for(i = 0; i < Hashsize; i++) { for(f = hash[i]; f; f = f->hash) { marktree(f->proc); if(f->lexval != Tid) continue; for(v = f->v; v; v = v->pop) { switch(v->type) { case TSTRING: v->vstore.u0.sstring->sgc.gcmark = 1; break; case TLIST: marklist(v->vstore.u0.sl); break; case TCODE: marktree(v->vstore.u0.scc); break; } } } } /* Free */ p = &gcl; for(m = gcl; m; m = next) { next = m->gclink; if(m->gcmark == 0) { *p = next; free(m); /* Sleazy reliance on my malloc */ } else p = &m->gclink; } } void* gmalloc(long l) { void *p; dogc += l; p = malloc(l); if(p == 0) fatal("out of memory"); memset(p, 0, l); return p; } void checkqid(int f1, int pid) { int fd; Dir d1, d2; char buf[128]; if(kernel || rdebug) return; if(dirfstat(f1, &d1) < 0) fatal("checkqid: (qid not checked) dirfstat: %r"); sprint(buf, "/proc/%d/text", pid); fd = open(buf, OREAD); if(fd < 0 || dirfstat(fd, &d2) < 0) fatal("checkqid: (qid not checked) dirstat %s: %r", buf); close(fd); if(memcmp(&d1.qid, &d2.qid, sizeof(d2.qid))) print("warning: image does not match text\n"); } char* mysystem(void) { char *cpu, *p, *q; static char kernel[128]; cpu = getenv("cputype"); if(cpu == 0) { cpu = "mips"; print("$cputype not set; assuming %s\n", cpu); } p = getenv("terminal"); if(p == 0 || (p=strchr(p, ' ')) == 0 || p[1] == ' ' || p[1] == 0) { p = "9power"; print("missing or bad $terminal; assuming %s\n", p); } else{ p++; q = strchr(p, ' '); if(q) *q = 0; sprint(kernel, "/%s/b%s", cpu, p); } return kernel; } int isnumeric(char *s) { while(*s) { if(*s < '0' || *s > '9') return 0; s++; } return 1; } int xconv(va_list *arg, Fconv *f) { f->f3 |= 1<<2; return numbconv(arg, f); }