| #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"); |
| } |
| |
| Map* |
| dumbmap(int fd) |
| { |
| Map *dumb; |
| Seg s; |
| |
| dumb = allocmap(); |
| memset(&s, 0, sizeof s); |
| s.fd = fd; |
| s.base = 0; |
| s.offset = 0; |
| s.size = 0xFFFFFFFF; |
| s.name = "data"; |
| s.file = "<dumb>"; |
| if(addseg(dumb, s) < 0){ |
| freemap(dumb); |
| return nil; |
| } |
| if(mach == nil) |
| mach = machcpu; |
| return dumb; |
| } |
| |
| void |
| main(int argc, char *argv[]) |
| { |
| Lsym *volatile 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 |
| |
| USED(pid); |
| |
| fmtinstall('Z', Zfmt); |
| fmtinstall('L', locfmt); |
| Binit(&bioout, 1, OWRITE); |
| bout = &bioout; |
| |
| initexpr(); |
| initprint(); |
| kinit(); |
| initialising = 1; |
| pushfile(0); |
| loadvars(); |
| installbuiltin(); |
| acidregs = mallocz(sizeof *acidregs, 1); |
| acidregs->rw = acidregsrw; |
| |
| 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(unsharp("#9/acid/port")); |
| for(i = 0; i < nlm; i++) { |
| if(access(lm[i], AREAD) >= 0) |
| loadmodule(lm[i]); |
| else { |
| sprint(buf, "#9/acid/%s", lm[i]); |
| loadmodule(unsharp(buf)); |
| } |
| } |
| |
| userinit(); |
| varsym(); |
| |
| l = look("acidmap"); |
| if(l && l->proc) { |
| if(setjmp(err) == 0){ |
| 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); |
| */ |
| } |
| |
| void |
| setstring(char *var, char *s) |
| { |
| Lsym *l; |
| Value *v; |
| |
| l = mkvar(var); |
| v = l->v; |
| v->store.fmt = 's'; |
| v->set = 1; |
| v->store.u.string = strnode(s ? s : ""); |
| v->type = TSTRING; |
| } |
| |
| static int |
| attachfiles(int argc, char **argv) |
| { |
| volatile int pid; |
| Lsym *l; |
| |
| pid = 0; |
| interactive = 0; |
| USED(pid); |
| |
| if(setjmp(err)) |
| return -1; |
| |
| attachargs(argc, argv, wtflag?ORDWR:OREAD, 1); |
| |
| setstring("objtype", mach->name); |
| setstring("textfile", symfil); |
| setstring("systype", symhdr ? symhdr->aname : ""); |
| setstring("corefile", corfil); |
| |
| l = mkvar("pids"); |
| l->v->set = 1; |
| l->v->type = TLIST; |
| l->v->store.u.l = nil; |
| |
| if(corpid) |
| sproc(corpid); |
| if(corhdr) |
| setcore(corhdr); |
| varreg(); |
| return 0; |
| } |
| |
| void |
| setcore(Fhdr *hdr) |
| { |
| int i; |
| Lsym *l; |
| Value *v; |
| List **tail, *tl; |
| |
| 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; |
| |
| l = mkvar("pid"); |
| v = l->v; |
| v->store.fmt = 'D'; |
| v->set = 1; |
| v->store.u.ival = hdr->pid; |
| |
| setstring("corefile", corfil); |
| setstring("cmdline", hdr->cmdline); |
| |
| l = mkvar("pids"); |
| l->v->set = 1; |
| l->v->type = TLIST; |
| l->v->store.u.l = nil; |
| tail = &l->v->store.u.l; |
| for(i=0; i<hdr->nthread; i++){ |
| tl = al(TINT); |
| tl->store.u.ival = hdr->thread[i].id; |
| tl->store.fmt = 'X'; |
| *tail = tl; |
| tail = &tl->next; |
| } |
| |
| if(hdr->nthread) |
| sproc(hdr->thread[0].id); |
| } |
| |
| void |
| die(void) |
| { |
| Lsym *s; |
| List *f; |
| int first; |
| |
| Bprint(bout, "\n"); |
| |
| first = 1; |
| s = look("proclist"); |
| if(s && s->v->type == TLIST) { |
| for(f = s->v->store.u.l; f; f = f->next){ |
| detachproc((int)f->store.u.ival); |
| Bprint(bout, "%s %d", first ? "/bin/kill -9" : "", (int)f->store.u.ival); |
| first = 0; |
| } |
| } |
| if(!first) |
| Bprint(bout, "\n"); |
| exits(0); |
| } |
| |
| void |
| userinit(void) |
| { |
| Lsym *l; |
| Node *n; |
| char buf[128], *p; |
| |
| sprint(buf, "#9/acid/%s", mach->name); |
| loadmodule(unsharp(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(s64int 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; |
| case TCON: |
| marktree(v->store.u.con); |
| 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; |
| } |