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 *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, pid;177 char *s;178 int i, omode;179 Fhdr *hdr;180 Lsym *l;181 Value *v;183 pid = 0;184 interactive = 0;185 if(setjmp(err))186 return -1;188 /*189 * Unix and Plan 9 differ on what the right order of pid, text, and core is.190 * I never remember anyway. Let's just accept them in any order.191 */192 omode = wtflag ? ORDWR : OREAD;193 for(i=0; i<argc; i++){194 if(isnumeric(argv[i])){195 if(pid){196 fprint(2, "already have pid %d; ignoring pid %d\n", pid, argv[i]);197 continue;198 }199 if(corhdr){200 fprint(2, "already have core %s; ignoring pid %d\n", corfil, pid);201 continue;202 }203 pid = atoi(argv[i]);204 continue;205 }206 if((hdr = crackhdr(argv[i], omode)) == nil){207 fprint(2, "crackhdr %s: %r\n", argv[i]);208 if(argc == 1 && (fd = open(argv[i], omode)) > 0){209 fprint(2, "loading %s direct mapped\n", argv[i]);210 symmap = dumbmap(fd);211 cormap = dumbmap(fd);212 symfil = argv[i];213 corfil = argv[i];214 goto Run;215 }216 continue;217 }218 fprint(2, "%s: %s %s %s\n", argv[i], hdr->aname, hdr->mname, hdr->fname);219 if(hdr->ftype == FCORE){220 if(pid){221 fprint(2, "already have pid %d; ignoring core %s\n", pid, argv[i]);222 uncrackhdr(hdr);223 continue;224 }225 if(corhdr){226 fprint(2, "already have core %s; ignoring core %s\n", corfil, argv[i]);227 uncrackhdr(hdr);228 continue;229 }230 corhdr = hdr;231 corfil = argv[i];232 }else{233 if(symhdr){234 fprint(2, "already have text %s; ignoring text %s\n", symfil, argv[i]);235 uncrackhdr(hdr);236 continue;237 }238 symhdr = hdr;239 symfil = argv[i];240 }241 }243 if(symhdr==nil){244 symfil = "a.out";245 if(pid){246 if((s = proctextfile(pid)) != nil){247 fprint(2, "pid %d: text %s\n", pid, s);248 symfil = s;249 }250 }251 /* XXX pull command from core */253 if((symhdr = crackhdr(symfil, omode)) == nil){254 fprint(2, "crackhdr %s: %r\n", symfil);255 symfil = nil;256 }257 }259 if(symhdr)260 syminit(symhdr);262 if(!mach)263 mach = machcpu;265 /*266 * Set up maps.267 */268 symmap = allocmap();269 cormap = allocmap();270 if(symmap == nil || cormap == nil)271 sysfatal("allocating maps: %r");273 if(symhdr){274 if(mapfile(symhdr, 0, symmap, nil) < 0)275 fprint(2, "mapping %s: %r\n", symfil);276 mapfile(symhdr, 0, cormap, nil);277 }279 Run:280 l = mkvar("objtype");281 v = l->v;282 v->store.fmt = 's';283 v->set = 1;284 v->store.u.string = strnode(mach->name);285 v->type = TSTRING;287 l = mkvar("textfile");288 v = l->v;289 v->store.fmt = 's';290 v->set = 1;291 v->store.u.string = strnode(symfil ? symfil : "");292 v->type = TSTRING;294 l = mkvar("systype");295 v = l->v;296 v->store.fmt = 's';297 v->set = 1;298 v->store.u.string = strnode(symhdr ? symhdr->aname : "");299 v->type = TSTRING;301 l = mkvar("corefile");302 v = l->v;303 v->store.fmt = 's';304 v->set = 1;305 v->store.u.string = strnode(corfil ? corfil : "");306 v->type = TSTRING;308 if(pid)309 sproc(pid);310 if(corhdr)311 setcore(corhdr);312 varreg();313 return 0;314 }316 void317 setcore(Fhdr *hdr)318 {319 unmapproc(cormap);320 unmapfile(corhdr, cormap);321 free(correg);322 correg = nil;324 if(hdr == nil)325 error("no core");326 if(mapfile(hdr, 0, cormap, &correg) < 0)327 error("mapfile %s: %r", hdr->filename);328 corhdr = hdr;329 corfil = hdr->filename;330 }332 void333 die(void)334 {335 Lsym *s;336 List *f;338 Bprint(bout, "\n");340 s = look("proclist");341 if(s && s->v->type == TLIST) {342 for(f = s->v->store.u.l; f; f = f->next){343 detachproc((int)f->store.u.ival);344 Bprint(bout, "/bin/kill -9 %d\n", (int)f->store.u.ival);345 }346 }347 exits(0);348 }350 void351 userinit(void)352 {353 Lsym *l;354 Node *n;355 char buf[128], *p;357 sprint(buf, "#9/acid/%s", mach->name);358 loadmodule(unsharp(buf));359 p = getenv("home");360 if(p != 0) {361 sprint(buf, "%s/lib/acid", p);362 silent = 1;363 loadmodule(buf);364 }366 interactive = 0;367 if(setjmp(err)) {368 unwind();369 return;370 }371 l = look("acidinit");372 if(l && l->proc) {373 n = an(ONAME, ZN, ZN);374 n->sym = l;375 n = an(OCALL, n, ZN);376 execute(n);377 }378 }380 void381 loadmodule(char *s)382 {383 interactive = 0;384 if(setjmp(err)) {385 unwind();386 return;387 }388 pushfile(s);389 silent = 0;390 yyparse();391 popio();392 return;393 }395 Node*396 an(int op, Node *l, Node *r)397 {398 Node *n;400 n = gmalloc(sizeof(Node));401 memset(n, 0, sizeof(Node));402 n->gc.gclink = gcl;403 gcl = (Gc*)n;404 n->op = op;405 n->left = l;406 n->right = r;407 return n;408 }410 List*411 al(int t)412 {413 List *l;415 l = gmalloc(sizeof(List));416 memset(l, 0, sizeof(List));417 l->type = t;418 l->gc.gclink = gcl;419 gcl = (Gc*)l;420 return l;421 }423 Node*424 con(int v)425 {426 Node *n;428 n = an(OCONST, ZN, ZN);429 n->store.u.ival = v;430 n->store.fmt = 'X';431 n->type = TINT;432 return n;433 }435 void436 fatal(char *fmt, ...)437 {438 char buf[128];439 va_list arg;441 va_start(arg, fmt);442 vseprint(buf, buf+sizeof(buf), fmt, arg);443 va_end(arg);444 fprint(2, "%s: %Z (fatal problem) %s\n", argv0, buf);445 exits(buf);446 }448 void449 yyerror(char *fmt, ...)450 {451 char buf[128];452 va_list arg;454 if(strcmp(fmt, "syntax error") == 0) {455 yyerror("syntax error, near symbol '%s'", symbol);456 return;457 }458 va_start(arg, fmt);459 vseprint(buf, buf+sizeof(buf), fmt, arg);460 va_end(arg);461 print("%Z: %s\n", buf);462 }464 void465 marktree(Node *n)466 {468 if(n == 0)469 return;471 marktree(n->left);472 marktree(n->right);474 n->gc.gcmark = 1;475 if(n->op != OCONST)476 return;478 switch(n->type) {479 case TSTRING:480 n->store.u.string->gc.gcmark = 1;481 break;482 case TLIST:483 marklist(n->store.u.l);484 break;485 case TCODE:486 marktree(n->store.u.cc);487 break;488 }489 }491 void492 marklist(List *l)493 {494 while(l) {495 l->gc.gcmark = 1;496 switch(l->type) {497 case TSTRING:498 l->store.u.string->gc.gcmark = 1;499 break;500 case TLIST:501 marklist(l->store.u.l);502 break;503 case TCODE:504 marktree(l->store.u.cc);505 break;506 }507 l = l->next;508 }509 }511 void512 gc(void)513 {514 int i;515 Lsym *f;516 Value *v;517 Gc *m, **p, *next;519 if(dogc < Mempergc)520 return;521 dogc = 0;523 /* Mark */524 for(m = gcl; m; m = m->gclink)525 m->gcmark = 0;527 /* Scan */528 for(i = 0; i < Hashsize; i++) {529 for(f = hash[i]; f; f = f->hash) {530 marktree(f->proc);531 if(f->lexval != Tid)532 continue;533 for(v = f->v; v; v = v->pop) {534 switch(v->type) {535 case TSTRING:536 v->store.u.string->gc.gcmark = 1;537 break;538 case TLIST:539 marklist(v->store.u.l);540 break;541 case TCODE:542 marktree(v->store.u.cc);543 break;544 }545 }546 }547 }549 /* Free */550 p = &gcl;551 for(m = gcl; m; m = next) {552 next = m->gclink;553 if(m->gcmark == 0) {554 *p = next;555 free(m); /* Sleazy reliance on my malloc */556 }557 else558 p = &m->gclink;559 }560 }562 void*563 gmalloc(long l)564 {565 void *p;567 dogc += l;568 p = malloc(l);569 if(p == 0)570 fatal("out of memory");571 return p;572 }574 void575 checkqid(int f1, int pid)576 {577 int fd;578 Dir *d1, *d2;579 char buf[128];581 if(kernel)582 return;584 d1 = dirfstat(f1);585 if(d1 == nil){586 print("checkqid: (qid not checked) dirfstat: %r\n");587 return;588 }590 sprint(buf, "/proc/%d/text", pid);591 fd = open(buf, OREAD);592 if(fd < 0 || (d2 = dirfstat(fd)) == nil){593 print("checkqid: (qid not checked) dirstat %s: %r\n", buf);594 free(d1);595 if(fd >= 0)596 close(fd);597 return;598 }600 close(fd);602 if(d1->qid.path != d2->qid.path || d1->qid.vers != d2->qid.vers || d1->qid.type != d2->qid.type){603 print("path %llux %llux vers %lud %lud type %d %d\n",604 d1->qid.path, d2->qid.path, d1->qid.vers, d2->qid.vers, d1->qid.type, d2->qid.type);605 print("warning: image does not match text for pid %d\n", pid);606 }607 free(d1);608 free(d2);609 }611 void612 catcher(void *junk, char *s)613 {614 USED(junk);616 if(strstr(s, "interrupt")) {617 gotint = 1;618 noted(NCONT);619 }620 if(strstr(s, "child"))621 noted(NCONT);622 fprint(2, "note: %s\n", s);623 noted(NDFLT);624 }626 char*627 system(void)628 {629 char *cpu, *p, *q;630 static char kernel[128];632 cpu = getenv("cputype");633 if(cpu == 0) {634 cpu = "mips";635 print("$cputype not set; assuming %s\n", cpu);636 }637 p = getenv("terminal");638 if(p == 0 || (p=strchr(p, ' ')) == 0 || p[1] == ' ' || p[1] == 0) {639 p = "9power";640 print("missing or bad $terminal; assuming %s\n", p);641 }642 else{643 p++;644 q = strchr(p, ' ');645 if(q)646 *q = 0;647 sprint(kernel, "/%s/9%s", cpu, p);648 }649 return kernel;650 }652 int653 isnumeric(char *s)654 {655 while(*s) {656 if(*s < '0' || *s > '9')657 return 0;658 s++;659 }660 return 1;661 }663 int664 xfmt(Fmt *f)665 {666 f->flags ^= FmtSharp;667 return __ifmt(f);668 }