Blob
1 #include <u.h>2 #include <libc.h>3 #include <bio.h>4 #include <mach.h>5 #define Extern6 #include "acid.h"7 #include "y.tab.h"9 extern int __ifmt(Fmt*);11 static Biobuf bioout;12 static char* lm[16];13 static int nlm;14 static char* mtype;16 static int attachfiles(int, char**);17 int xfmt(Fmt*);18 int isnumeric(char*);19 void die(void);20 void setcore(Fhdr*);22 void23 usage(void)24 {25 fprint(2, "usage: acid [-c core] [-l module] [-m machine] [-qrw] [-k] [pid] [file]\n");26 exits("usage");27 }29 Map*30 dumbmap(int fd)31 {32 Map *dumb;33 Seg s;35 dumb = allocmap();36 memset(&s, 0, sizeof s);37 s.fd = fd;38 s.base = 0;39 s.offset = 0;40 s.size = 0xFFFFFFFF;41 s.name = "data";42 s.file = "<dumb>";43 if(addseg(dumb, s) < 0){44 freemap(dumb);45 return nil;46 }47 if(mach == nil)48 mach = machcpu;49 return dumb;50 }52 void53 main(int argc, char *argv[])54 {55 Lsym *volatile l;56 Node *n;57 char buf[128], *s;58 int pid, i;60 argv0 = argv[0];61 pid = 0;62 quiet = 1;64 mtype = 0;65 ARGBEGIN{66 case 'A':67 abort();68 break;69 case 'm':70 mtype = ARGF();71 break;72 case 'w':73 wtflag = 1;74 break;75 case 'l':76 s = ARGF();77 if(s == 0)78 usage();79 lm[nlm++] = s;80 break;81 case 'k':82 kernel++;83 break;84 case 'q':85 quiet = 0;86 break;87 case 'r':88 pid = 1;89 remote++;90 kernel++;91 break;92 default:93 usage();94 }ARGEND96 fmtinstall('x', xfmt);97 fmtinstall('Z', Zfmt);98 fmtinstall('L', locfmt);99 Binit(&bioout, 1, OWRITE);100 bout = &bioout;102 initexpr();103 initprint();104 kinit();105 initialising = 1;106 pushfile(0);107 loadvars();108 installbuiltin();110 if(mtype && machbyname(mtype) == 0)111 print("unknown machine %s", mtype);113 if (attachfiles(argc, argv) < 0)114 varreg(); /* use default register set on error */115 if(mach == nil)116 mach = machcpu;118 symhdr = nil; /* not supposed to use this anymore */120 l = mkvar("acid");121 l->v->set = 1;122 l->v->type = TLIST;123 l->v->store.u.l = nil;125 loadmodule(unsharp("#9/acid/port"));126 for(i = 0; i < nlm; i++) {127 if(access(lm[i], AREAD) >= 0)128 loadmodule(lm[i]);129 else {130 sprint(buf, "#9/acid/%s", lm[i]);131 loadmodule(unsharp(buf));132 }133 }135 userinit();136 varsym();138 l = look("acidmap");139 if(l && l->proc) {140 if(setjmp(err) == 0){141 n = an(ONAME, ZN, ZN);142 n->sym = l;143 n = an(OCALL, n, ZN);144 execute(n);145 }146 }148 interactive = 1;149 initialising = 0;150 line = 1;152 notify(catcher);154 for(;;) {155 if(setjmp(err)) {156 Binit(&bioout, 1, OWRITE);157 unwind();158 }159 stacked = 0;161 Bprint(bout, "acid; ");163 if(yyparse() != 1)164 die();165 restartio();167 unwind();168 }169 /*170 Bputc(bout, '\n');171 exits(0);172 */173 }175 static int176 attachfiles(int argc, char **argv)177 {178 int fd;179 volatile int pid;180 char *s;181 int i, omode;182 Fhdr *hdr;183 Lsym *l;184 Value *v;186 pid = 0;187 interactive = 0;188 if(setjmp(err))189 return -1;191 /*192 * Unix and Plan 9 differ on what the right order of pid, text, and core is.193 * I never remember anyway. Let's just accept them in any order.194 */195 omode = wtflag ? ORDWR : OREAD;196 for(i=0; i<argc; i++){197 if(isnumeric(argv[i])){198 if(pid){199 fprint(2, "already have pid %d; ignoring pid %d\n", pid, argv[i]);200 continue;201 }202 if(corhdr){203 fprint(2, "already have core %s; ignoring pid %d\n", corfil, pid);204 continue;205 }206 pid = atoi(argv[i]);207 continue;208 }209 if((hdr = crackhdr(argv[i], omode)) == nil){210 fprint(2, "crackhdr %s: %r\n", argv[i]);211 if(argc == 1 && (fd = open(argv[i], omode)) > 0){212 fprint(2, "loading %s direct mapped\n", argv[i]);213 symmap = dumbmap(fd);214 cormap = dumbmap(fd);215 symfil = argv[i];216 corfil = argv[i];217 goto Run;218 }219 continue;220 }221 fprint(2, "%s: %s %s %s\n", argv[i], hdr->aname, hdr->mname, hdr->fname);222 if(hdr->ftype == FCORE){223 if(pid){224 fprint(2, "already have pid %d; ignoring core %s\n", pid, argv[i]);225 uncrackhdr(hdr);226 continue;227 }228 if(corhdr){229 fprint(2, "already have core %s; ignoring core %s\n", corfil, argv[i]);230 uncrackhdr(hdr);231 continue;232 }233 corhdr = hdr;234 corfil = argv[i];235 }else{236 if(symhdr){237 fprint(2, "already have text %s; ignoring text %s\n", symfil, argv[i]);238 uncrackhdr(hdr);239 continue;240 }241 symhdr = hdr;242 symfil = argv[i];243 }244 }246 if(symhdr==nil){247 symfil = "a.out";248 if(pid){249 if((s = proctextfile(pid)) != nil){250 fprint(2, "pid %d: text %s\n", pid, s);251 symfil = s;252 }253 }254 /* XXX pull command from core */256 if((symhdr = crackhdr(symfil, omode)) == nil){257 fprint(2, "crackhdr %s: %r\n", symfil);258 symfil = nil;259 }260 }262 if(symhdr)263 symopen(symhdr);265 if(!mach)266 mach = machcpu;268 /*269 * Set up maps.270 */271 symmap = allocmap();272 cormap = allocmap();273 if(symmap == nil || cormap == nil)274 sysfatal("allocating maps: %r");276 if(symhdr){277 if(mapfile(symhdr, 0, symmap, nil) < 0)278 fprint(2, "mapping %s: %r\n", symfil);279 mapfile(symhdr, 0, cormap, nil);280 }282 Run:283 l = mkvar("objtype");284 v = l->v;285 v->store.fmt = 's';286 v->set = 1;287 v->store.u.string = strnode(mach->name);288 v->type = TSTRING;290 l = mkvar("textfile");291 v = l->v;292 v->store.fmt = 's';293 v->set = 1;294 v->store.u.string = strnode(symfil ? symfil : "");295 v->type = TSTRING;297 l = mkvar("systype");298 v = l->v;299 v->store.fmt = 's';300 v->set = 1;301 v->store.u.string = strnode(symhdr ? symhdr->aname : "");302 v->type = TSTRING;304 l = mkvar("corefile");305 v = l->v;306 v->store.fmt = 's';307 v->set = 1;308 v->store.u.string = strnode(corfil ? corfil : "");309 v->type = TSTRING;311 if(pid)312 sproc(pid);313 if(corhdr)314 setcore(corhdr);315 varreg();316 return 0;317 }319 void320 setcore(Fhdr *hdr)321 {322 unmapproc(cormap);323 unmapfile(corhdr, cormap);324 free(correg);325 correg = nil;327 if(hdr == nil)328 error("no core");329 if(mapfile(hdr, 0, cormap, &correg) < 0)330 error("mapfile %s: %r", hdr->filename);331 corhdr = hdr;332 corfil = hdr->filename;333 }335 void336 die(void)337 {338 Lsym *s;339 List *f;341 Bprint(bout, "\n");343 s = look("proclist");344 if(s && s->v->type == TLIST) {345 for(f = s->v->store.u.l; f; f = f->next){346 detachproc((int)f->store.u.ival);347 Bprint(bout, "/bin/kill -9 %d\n", (int)f->store.u.ival);348 }349 }350 exits(0);351 }353 void354 userinit(void)355 {356 Lsym *l;357 Node *n;358 char buf[128], *p;360 sprint(buf, "#9/acid/%s", mach->name);361 loadmodule(unsharp(buf));362 p = getenv("HOME");363 if(p != 0) {364 sprint(buf, "%s/lib/acid", p);365 silent = 1;366 loadmodule(buf);367 }369 interactive = 0;370 if(setjmp(err)) {371 unwind();372 return;373 }374 l = look("acidinit");375 if(l && l->proc) {376 n = an(ONAME, ZN, ZN);377 n->sym = l;378 n = an(OCALL, n, ZN);379 execute(n);380 }381 }383 void384 loadmodule(char *s)385 {386 interactive = 0;387 if(setjmp(err)) {388 unwind();389 return;390 }391 pushfile(s);392 silent = 0;393 yyparse();394 popio();395 return;396 }398 Node*399 an(int op, Node *l, Node *r)400 {401 Node *n;403 n = gmalloc(sizeof(Node));404 memset(n, 0, sizeof(Node));405 n->gc.gclink = gcl;406 gcl = (Gc*)n;407 n->op = op;408 n->left = l;409 n->right = r;410 return n;411 }413 List*414 al(int t)415 {416 List *l;418 l = gmalloc(sizeof(List));419 memset(l, 0, sizeof(List));420 l->type = t;421 l->gc.gclink = gcl;422 gcl = (Gc*)l;423 return l;424 }426 Node*427 con(int v)428 {429 Node *n;431 n = an(OCONST, ZN, ZN);432 n->store.u.ival = v;433 n->store.fmt = 'X';434 n->type = TINT;435 return n;436 }438 void439 fatal(char *fmt, ...)440 {441 char buf[128];442 va_list arg;444 va_start(arg, fmt);445 vseprint(buf, buf+sizeof(buf), fmt, arg);446 va_end(arg);447 fprint(2, "%s: %Z (fatal problem) %s\n", argv0, buf);448 exits(buf);449 }451 void452 yyerror(char *fmt, ...)453 {454 char buf[128];455 va_list arg;457 if(strcmp(fmt, "syntax error") == 0) {458 yyerror("syntax error, near symbol '%s'", symbol);459 return;460 }461 va_start(arg, fmt);462 vseprint(buf, buf+sizeof(buf), fmt, arg);463 va_end(arg);464 print("%Z: %s\n", buf);465 }467 void468 marktree(Node *n)469 {471 if(n == 0)472 return;474 marktree(n->left);475 marktree(n->right);477 n->gc.gcmark = 1;478 if(n->op != OCONST)479 return;481 switch(n->type) {482 case TSTRING:483 n->store.u.string->gc.gcmark = 1;484 break;485 case TLIST:486 marklist(n->store.u.l);487 break;488 case TCODE:489 marktree(n->store.u.cc);490 break;491 }492 }494 void495 marklist(List *l)496 {497 while(l) {498 l->gc.gcmark = 1;499 switch(l->type) {500 case TSTRING:501 l->store.u.string->gc.gcmark = 1;502 break;503 case TLIST:504 marklist(l->store.u.l);505 break;506 case TCODE:507 marktree(l->store.u.cc);508 break;509 }510 l = l->next;511 }512 }514 void515 gc(void)516 {517 int i;518 Lsym *f;519 Value *v;520 Gc *m, **p, *next;522 if(dogc < Mempergc)523 return;524 dogc = 0;526 /* Mark */527 for(m = gcl; m; m = m->gclink)528 m->gcmark = 0;530 /* Scan */531 for(i = 0; i < Hashsize; i++) {532 for(f = hash[i]; f; f = f->hash) {533 marktree(f->proc);534 if(f->lexval != Tid)535 continue;536 for(v = f->v; v; v = v->pop) {537 switch(v->type) {538 case TSTRING:539 v->store.u.string->gc.gcmark = 1;540 break;541 case TLIST:542 marklist(v->store.u.l);543 break;544 case TCODE:545 marktree(v->store.u.cc);546 break;547 }548 }549 }550 }552 /* Free */553 p = &gcl;554 for(m = gcl; m; m = next) {555 next = m->gclink;556 if(m->gcmark == 0) {557 *p = next;558 free(m); /* Sleazy reliance on my malloc */559 }560 else561 p = &m->gclink;562 }563 }565 void*566 gmalloc(long l)567 {568 void *p;570 dogc += l;571 p = malloc(l);572 if(p == 0)573 fatal("out of memory");574 return p;575 }577 void578 checkqid(int f1, int pid)579 {580 int fd;581 Dir *d1, *d2;582 char buf[128];584 if(kernel)585 return;587 d1 = dirfstat(f1);588 if(d1 == nil){589 print("checkqid: (qid not checked) dirfstat: %r\n");590 return;591 }593 sprint(buf, "/proc/%d/text", pid);594 fd = open(buf, OREAD);595 if(fd < 0 || (d2 = dirfstat(fd)) == nil){596 print("checkqid: (qid not checked) dirstat %s: %r\n", buf);597 free(d1);598 if(fd >= 0)599 close(fd);600 return;601 }603 close(fd);605 if(d1->qid.path != d2->qid.path || d1->qid.vers != d2->qid.vers || d1->qid.type != d2->qid.type){606 print("path %llux %llux vers %lud %lud type %d %d\n",607 d1->qid.path, d2->qid.path, d1->qid.vers, d2->qid.vers, d1->qid.type, d2->qid.type);608 print("warning: image does not match text for pid %d\n", pid);609 }610 free(d1);611 free(d2);612 }614 void615 catcher(void *junk, char *s)616 {617 USED(junk);619 if(strstr(s, "interrupt")) {620 gotint = 1;621 noted(NCONT);622 }623 if(strstr(s, "child"))624 noted(NCONT);625 fprint(2, "note: %s\n", s);626 noted(NDFLT);627 }629 char*630 system(void)631 {632 char *cpu, *p, *q;633 static char kernel[128];635 cpu = getenv("cputype");636 if(cpu == 0) {637 cpu = "mips";638 print("$cputype not set; assuming %s\n", cpu);639 }640 p = getenv("terminal");641 if(p == 0 || (p=strchr(p, ' ')) == 0 || p[1] == ' ' || p[1] == 0) {642 p = "9power";643 print("missing or bad $terminal; assuming %s\n", p);644 }645 else{646 p++;647 q = strchr(p, ' ');648 if(q)649 *q = 0;650 sprint(kernel, "/%s/9%s", cpu, p);651 }652 return kernel;653 }655 int656 isnumeric(char *s)657 {658 while(*s) {659 if(*s < '0' || *s > '9')660 return 0;661 s++;662 }663 return 1;664 }666 int667 xfmt(Fmt *f)668 {669 f->flags ^= FmtSharp;670 return __ifmt(f);671 }