diff options
Diffstat (limited to 'src/cmd/acid/main.c')
-rw-r--r-- | src/cmd/acid/main.c | 630 |
1 files changed, 630 insertions, 0 deletions
diff --git a/src/cmd/acid/main.c b/src/cmd/acid/main.c new file mode 100644 index 00000000..dccff268 --- /dev/null +++ b/src/cmd/acid/main.c @@ -0,0 +1,630 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> +#define Extern +#include "acid.h" +#include "y.tab.h" + +extern int __ifmt(Fmt*); + +static Biobuf bioout; +static char* lm[16]; +static int nlm; +static char* mtype; + +static int attachfiles(int, char**); +int xfmt(Fmt*); +int isnumeric(char*); +void die(void); +void setcore(Fhdr*); + +void +usage(void) +{ + fprint(2, "usage: acid [-c core] [-l module] [-m machine] [-qrw] [-k] [pid] [file]\n"); + exits("usage"); +} + +void +main(int argc, char *argv[]) +{ + Lsym *l; + Node *n; + char buf[128], *s; + int pid, i; + + argv0 = argv[0]; + pid = 0; + quiet = 1; + + mtype = 0; + ARGBEGIN{ + case 'A': + abort(); + break; + case 'm': + mtype = ARGF(); + break; + case 'w': + wtflag = 1; + break; + case 'l': + s = ARGF(); + if(s == 0) + usage(); + lm[nlm++] = s; + break; + case 'k': + kernel++; + break; + case 'q': + quiet = 0; + break; + case 'r': + pid = 1; + remote++; + kernel++; + break; + default: + usage(); + }ARGEND + + fmtinstall('x', xfmt); + fmtinstall('Z', Zfmt); + fmtinstall('L', locfmt); + 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(argc, argv) < 0) + varreg(); /* use default register set on error */ + if(mach == nil) + mach = machcpu; + + symhdr = nil; /* not supposed to use this anymore */ + + l = mkvar("acid"); + l->v->set = 1; + l->v->type = TLIST; + l->v->store.u.l = nil; + + loadmodule("/usr/local/plan9/acid/port"); + for(i = 0; i < nlm; i++) { + if(access(lm[i], AREAD) >= 0) + loadmodule(lm[i]); + else { + sprint(buf, "/usr/local/plan9/acid/%s", 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; + + notify(catcher); + + 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(int argc, char **argv) +{ + char *s; + int i, omode; + Fhdr *hdr; + Lsym *l; + Value *v; + + interactive = 0; + if(setjmp(err)) + return -1; + + /* + * Unix and Plan 9 differ on what the right order of pid, text, and core is. + * I never remember anyway. Let's just accept them in any order. + */ + omode = wtflag ? ORDWR : OREAD; + for(i=0; i<argc; i++){ + if(isnumeric(argv[i])){ + if(pid){ + fprint(2, "already have pid %d; ignoring pid %d\n", pid, argv[i]); + continue; + } + if(corhdr){ + fprint(2, "already have core %s; ignoring pid %d\n", corfil, pid); + continue; + } + pid = atoi(argv[i]); + continue; + } + if((hdr = crackhdr(argv[i], omode)) == nil){ + fprint(2, "crackhdr %s: %r\n", argv[i]); + continue; + } + fprint(2, "%s: %s %s %s\n", argv[i], hdr->aname, hdr->mname, hdr->fname); + if(hdr->ftype == FCORE){ + if(pid){ + fprint(2, "already have pid %d; ignoring core %s\n", pid, argv[i]); + uncrackhdr(hdr); + continue; + } + if(corhdr){ + fprint(2, "already have core %s; ignoring core %s\n", corfil, argv[i]); + uncrackhdr(hdr); + continue; + } + corhdr = hdr; + corfil = argv[i]; + }else{ + if(symhdr){ + fprint(2, "already have text %s; ignoring text %s\n", symfil, argv[i]); + uncrackhdr(hdr); + continue; + } + symhdr = hdr; + symfil = argv[i]; + } + } + + if(symhdr==nil){ + symfil = "a.out"; + if(pid){ + if((s = proctextfile(pid)) != nil){ + fprint(2, "pid %d: text %s\n", pid, s); + symfil = s; + } + } + /* XXX pull command from core */ + + if((hdr = crackhdr(symfil, omode)) == nil){ + fprint(2, "crackhdr %s: %r\n", symfil); + symfil = nil; + } + } + + if(symhdr) + syminit(symhdr); + + if(!mach) + mach = machcpu; + + /* + * Set up maps. + */ + symmap = allocmap(); + cormap = allocmap(); + if(symmap == nil || cormap == nil) + sysfatal("allocating maps: %r"); + + if(symhdr){ + if(mapfile(symhdr, 0, symmap, nil) < 0) + fprint(2, "mapping %s: %r\n", symfil); + mapfile(symhdr, 0, cormap, nil); + } + + 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; + + l = mkvar("corefile"); + v = l->v; + v->store.fmt = 's'; + v->set = 1; + v->store.u.string = strnode(corfil ? corfil : ""); + v->type = TSTRING; + + if(pid) + sproc(pid); + if(corhdr) + setcore(corhdr); + varreg(); + return 0; +} + +void +setcore(Fhdr *hdr) +{ + unmapproc(cormap); + unmapfile(corhdr, cormap); + free(correg); + correg = nil; + + if(hdr == nil) + error("no core"); + if(mapfile(hdr, 0, cormap, &correg) < 0) + error("mapfile %s: %r", hdr->filename); + corhdr = hdr; + corfil = hdr->filename; +} + +void +die(void) +{ + Lsym *s; + List *f; + + Bprint(bout, "\n"); + + 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); + } + } + exits(0); +} + +void +userinit(void) +{ + Lsym *l; + Node *n; + char buf[128], *p; + + sprint(buf, "/usr/local/plan9/acid/%s", mach->name); + loadmodule(buf); + p = getenv("home"); + if(p != 0) { + sprint(buf, "%s/lib/acid", p); + silent = 1; + 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; +} + +Node* +an(int op, Node *l, Node *r) +{ + Node *n; + + n = gmalloc(sizeof(Node)); + memset(n, 0, sizeof(Node)); + n->gc.gclink = gcl; + gcl = (Gc*)n; + n->op = op; + n->left = l; + n->right = r; + return n; +} + +List* +al(int t) +{ + List *l; + + l = gmalloc(sizeof(List)); + memset(l, 0, sizeof(List)); + l->type = t; + l->gc.gclink = gcl; + gcl = (Gc*)l; + return l; +} + +Node* +con(int v) +{ + Node *n; + + n = an(OCONST, ZN, ZN); + n->store.u.ival = v; + n->store.fmt = 'X'; + n->type = TINT; + return n; +} + +void +fatal(char *fmt, ...) +{ + char buf[128]; + va_list arg; + + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + fprint(2, "%s: %Z (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); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + print("%Z: %s\n", buf); +} + +void +marktree(Node *n) +{ + + if(n == 0) + return; + + marktree(n->left); + marktree(n->right); + + n->gc.gcmark = 1; + if(n->op != OCONST) + return; + + switch(n->type) { + case TSTRING: + n->store.u.string->gc.gcmark = 1; + break; + case TLIST: + marklist(n->store.u.l); + break; + case TCODE: + marktree(n->store.u.cc); + break; + } +} + +void +marklist(List *l) +{ + while(l) { + l->gc.gcmark = 1; + switch(l->type) { + case TSTRING: + l->store.u.string->gc.gcmark = 1; + break; + case TLIST: + marklist(l->store.u.l); + break; + case TCODE: + marktree(l->store.u.cc); + 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->store.u.string->gc.gcmark = 1; + break; + case TLIST: + marklist(v->store.u.l); + break; + case TCODE: + marktree(v->store.u.cc); + 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"); + return p; +} + +void +checkqid(int f1, int pid) +{ + int fd; + Dir *d1, *d2; + char buf[128]; + + if(kernel) + return; + + d1 = dirfstat(f1); + if(d1 == nil){ + print("checkqid: (qid not checked) dirfstat: %r\n"); + return; + } + + sprint(buf, "/proc/%d/text", pid); + fd = open(buf, OREAD); + if(fd < 0 || (d2 = dirfstat(fd)) == nil){ + print("checkqid: (qid not checked) dirstat %s: %r\n", buf); + free(d1); + if(fd >= 0) + close(fd); + return; + } + + close(fd); + + if(d1->qid.path != d2->qid.path || d1->qid.vers != d2->qid.vers || d1->qid.type != d2->qid.type){ + print("path %llux %llux vers %lud %lud type %d %d\n", + d1->qid.path, d2->qid.path, d1->qid.vers, d2->qid.vers, d1->qid.type, d2->qid.type); + print("warning: image does not match text for pid %d\n", pid); + } + free(d1); + free(d2); +} + +void +catcher(void *junk, char *s) +{ + USED(junk); + + if(strstr(s, "interrupt")) { + gotint = 1; + noted(NCONT); + } + if(strstr(s, "child")) + noted(NCONT); +fprint(2, "note: %s\n", s); + noted(NDFLT); +} + +char* +system(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/9%s", cpu, p); + } + return kernel; +} + +int +isnumeric(char *s) +{ + while(*s) { + if(*s < '0' || *s > '9') + return 0; + s++; + } + return 1; +} + +int +xfmt(Fmt *f) +{ + f->flags ^= FmtSharp; + return __ifmt(f); +} |