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 Bputc(bout, '\n');170 exits(0);171 }173 static int174 attachfiles(int argc, char **argv)175 {176 int fd;177 volatile int pid;178 char *s;179 int i, omode;180 Fhdr *hdr;181 Lsym *l;182 Value *v;184 pid = 0;185 interactive = 0;186 if(setjmp(err))187 return -1;189 /*190 * Unix and Plan 9 differ on what the right order of pid, text, and core is.191 * I never remember anyway. Let's just accept them in any order.192 */193 omode = wtflag ? ORDWR : OREAD;194 for(i=0; i<argc; i++){195 if(isnumeric(argv[i])){196 if(pid){197 fprint(2, "already have pid %d; ignoring pid %d\n", pid, argv[i]);198 continue;199 }200 if(corhdr){201 fprint(2, "already have core %s; ignoring pid %d\n", corfil, pid);202 continue;203 }204 pid = atoi(argv[i]);205 continue;206 }207 if((hdr = crackhdr(argv[i], omode)) == nil){208 fprint(2, "crackhdr %s: %r\n", argv[i]);209 if(argc == 1 && (fd = open(argv[i], omode)) > 0){210 fprint(2, "loading %s direct mapped\n", argv[i]);211 symmap = dumbmap(fd);212 cormap = dumbmap(fd);213 symfil = argv[i];214 corfil = argv[i];215 goto Run;216 }217 continue;218 }219 fprint(2, "%s: %s %s %s\n", argv[i], hdr->aname, hdr->mname, hdr->fname);220 if(hdr->ftype == FCORE){221 if(pid){222 fprint(2, "already have pid %d; ignoring core %s\n", pid, argv[i]);223 uncrackhdr(hdr);224 continue;225 }226 if(corhdr){227 fprint(2, "already have core %s; ignoring core %s\n", corfil, argv[i]);228 uncrackhdr(hdr);229 continue;230 }231 corhdr = hdr;232 corfil = argv[i];233 }else{234 if(symhdr){235 fprint(2, "already have text %s; ignoring text %s\n", symfil, argv[i]);236 uncrackhdr(hdr);237 continue;238 }239 symhdr = hdr;240 symfil = argv[i];241 }242 }244 if(symhdr==nil){245 symfil = "a.out";246 if(pid){247 if((s = proctextfile(pid)) != nil){248 fprint(2, "pid %d: text %s\n", pid, s);249 symfil = s;250 }251 }252 /* XXX pull command from core */254 if((symhdr = crackhdr(symfil, omode)) == nil){255 fprint(2, "crackhdr %s: %r\n", symfil);256 symfil = nil;257 }258 }260 if(symhdr)261 symopen(symhdr);263 if(!mach)264 mach = machcpu;266 /*267 * Set up maps.268 */269 symmap = allocmap();270 cormap = allocmap();271 if(symmap == nil || cormap == nil)272 sysfatal("allocating maps: %r");274 if(symhdr){275 if(mapfile(symhdr, 0, symmap, nil) < 0)276 fprint(2, "mapping %s: %r\n", symfil);277 mapfile(symhdr, 0, cormap, nil);278 }280 Run:281 l = mkvar("objtype");282 v = l->v;283 v->store.fmt = 's';284 v->set = 1;285 v->store.u.string = strnode(mach->name);286 v->type = TSTRING;288 l = mkvar("textfile");289 v = l->v;290 v->store.fmt = 's';291 v->set = 1;292 v->store.u.string = strnode(symfil ? symfil : "");293 v->type = TSTRING;295 l = mkvar("systype");296 v = l->v;297 v->store.fmt = 's';298 v->set = 1;299 v->store.u.string = strnode(symhdr ? symhdr->aname : "");300 v->type = TSTRING;302 l = mkvar("corefile");303 v = l->v;304 v->store.fmt = 's';305 v->set = 1;306 v->store.u.string = strnode(corfil ? corfil : "");307 v->type = TSTRING;309 if(pid)310 sproc(pid);311 if(corhdr)312 setcore(corhdr);313 varreg();314 return 0;315 }317 void318 setcore(Fhdr *hdr)319 {320 unmapproc(cormap);321 unmapfile(corhdr, cormap);322 free(correg);323 correg = nil;325 if(hdr == nil)326 error("no core");327 if(mapfile(hdr, 0, cormap, &correg) < 0)328 error("mapfile %s: %r", hdr->filename);329 corhdr = hdr;330 corfil = hdr->filename;331 }333 void334 die(void)335 {336 Lsym *s;337 List *f;339 Bprint(bout, "\n");341 s = look("proclist");342 if(s && s->v->type == TLIST) {343 for(f = s->v->store.u.l; f; f = f->next){344 detachproc((int)f->store.u.ival);345 Bprint(bout, "/bin/kill -9 %d\n", (int)f->store.u.ival);346 }347 }348 exits(0);349 }351 void352 userinit(void)353 {354 Lsym *l;355 Node *n;356 char buf[128], *p;358 sprint(buf, "#9/acid/%s", mach->name);359 loadmodule(unsharp(buf));360 p = getenv("HOME");361 if(p != 0) {362 sprint(buf, "%s/lib/acid", p);363 silent = 1;364 loadmodule(buf);365 }367 interactive = 0;368 if(setjmp(err)) {369 unwind();370 return;371 }372 l = look("acidinit");373 if(l && l->proc) {374 n = an(ONAME, ZN, ZN);375 n->sym = l;376 n = an(OCALL, n, ZN);377 execute(n);378 }379 }381 void382 loadmodule(char *s)383 {384 interactive = 0;385 if(setjmp(err)) {386 unwind();387 return;388 }389 pushfile(s);390 silent = 0;391 yyparse();392 popio();393 return;394 }396 Node*397 an(int op, Node *l, Node *r)398 {399 Node *n;401 n = gmalloc(sizeof(Node));402 memset(n, 0, sizeof(Node));403 n->gc.gclink = gcl;404 gcl = (Gc*)n;405 n->op = op;406 n->left = l;407 n->right = r;408 return n;409 }411 List*412 al(int t)413 {414 List *l;416 l = gmalloc(sizeof(List));417 memset(l, 0, sizeof(List));418 l->type = t;419 l->gc.gclink = gcl;420 gcl = (Gc*)l;421 return l;422 }424 Node*425 con(int v)426 {427 Node *n;429 n = an(OCONST, ZN, ZN);430 n->store.u.ival = v;431 n->store.fmt = 'X';432 n->type = TINT;433 return n;434 }436 void437 fatal(char *fmt, ...)438 {439 char buf[128];440 va_list arg;442 va_start(arg, fmt);443 vseprint(buf, buf+sizeof(buf), fmt, arg);444 va_end(arg);445 fprint(2, "%s: %Z (fatal problem) %s\n", argv0, buf);446 exits(buf);447 }449 void450 yyerror(char *fmt, ...)451 {452 char buf[128];453 va_list arg;455 if(strcmp(fmt, "syntax error") == 0) {456 yyerror("syntax error, near symbol '%s'", symbol);457 return;458 }459 va_start(arg, fmt);460 vseprint(buf, buf+sizeof(buf), fmt, arg);461 va_end(arg);462 print("%Z: %s\n", buf);463 }465 void466 marktree(Node *n)467 {469 if(n == 0)470 return;472 marktree(n->left);473 marktree(n->right);475 n->gc.gcmark = 1;476 if(n->op != OCONST)477 return;479 switch(n->type) {480 case TSTRING:481 n->store.u.string->gc.gcmark = 1;482 break;483 case TLIST:484 marklist(n->store.u.l);485 break;486 case TCODE:487 marktree(n->store.u.cc);488 break;489 }490 }492 void493 marklist(List *l)494 {495 while(l) {496 l->gc.gcmark = 1;497 switch(l->type) {498 case TSTRING:499 l->store.u.string->gc.gcmark = 1;500 break;501 case TLIST:502 marklist(l->store.u.l);503 break;504 case TCODE:505 marktree(l->store.u.cc);506 break;507 }508 l = l->next;509 }510 }512 void513 gc(void)514 {515 int i;516 Lsym *f;517 Value *v;518 Gc *m, **p, *next;520 if(dogc < Mempergc)521 return;522 dogc = 0;524 /* Mark */525 for(m = gcl; m; m = m->gclink)526 m->gcmark = 0;528 /* Scan */529 for(i = 0; i < Hashsize; i++) {530 for(f = hash[i]; f; f = f->hash) {531 marktree(f->proc);532 if(f->lexval != Tid)533 continue;534 for(v = f->v; v; v = v->pop) {535 switch(v->type) {536 case TSTRING:537 v->store.u.string->gc.gcmark = 1;538 break;539 case TLIST:540 marklist(v->store.u.l);541 break;542 case TCODE:543 marktree(v->store.u.cc);544 break;545 }546 }547 }548 }550 /* Free */551 p = &gcl;552 for(m = gcl; m; m = next) {553 next = m->gclink;554 if(m->gcmark == 0) {555 *p = next;556 free(m); /* Sleazy reliance on my malloc */557 }558 else559 p = &m->gclink;560 }561 }563 void*564 gmalloc(long l)565 {566 void *p;568 dogc += l;569 p = malloc(l);570 if(p == 0)571 fatal("out of memory");572 return p;573 }575 void576 checkqid(int f1, int pid)577 {578 int fd;579 Dir *d1, *d2;580 char buf[128];582 if(kernel)583 return;585 d1 = dirfstat(f1);586 if(d1 == nil){587 print("checkqid: (qid not checked) dirfstat: %r\n");588 return;589 }591 sprint(buf, "/proc/%d/text", pid);592 fd = open(buf, OREAD);593 if(fd < 0 || (d2 = dirfstat(fd)) == nil){594 print("checkqid: (qid not checked) dirstat %s: %r\n", buf);595 free(d1);596 if(fd >= 0)597 close(fd);598 return;599 }601 close(fd);603 if(d1->qid.path != d2->qid.path || d1->qid.vers != d2->qid.vers || d1->qid.type != d2->qid.type){604 print("path %llux %llux vers %lud %lud type %d %d\n",605 d1->qid.path, d2->qid.path, d1->qid.vers, d2->qid.vers, d1->qid.type, d2->qid.type);606 print("warning: image does not match text for pid %d\n", pid);607 }608 free(d1);609 free(d2);610 }612 void613 catcher(void *junk, char *s)614 {615 USED(junk);617 if(strstr(s, "interrupt")) {618 gotint = 1;619 noted(NCONT);620 }621 if(strstr(s, "child"))622 noted(NCONT);623 fprint(2, "note: %s\n", s);624 noted(NDFLT);625 }627 char*628 system(void)629 {630 char *cpu, *p, *q;631 static char kernel[128];633 cpu = getenv("cputype");634 if(cpu == 0) {635 cpu = "mips";636 print("$cputype not set; assuming %s\n", cpu);637 }638 p = getenv("terminal");639 if(p == 0 || (p=strchr(p, ' ')) == 0 || p[1] == ' ' || p[1] == 0) {640 p = "9power";641 print("missing or bad $terminal; assuming %s\n", p);642 }643 else{644 p++;645 q = strchr(p, ' ');646 if(q)647 *q = 0;648 sprint(kernel, "/%s/9%s", cpu, p);649 }650 return kernel;651 }653 int654 isnumeric(char *s)655 {656 while(*s) {657 if(*s < '0' || *s > '9')658 return 0;659 s++;660 }661 return 1;662 }664 int665 xfmt(Fmt *f)666 {667 f->flags ^= FmtSharp;668 return __ifmt(f);669 }