Blob
- Date:
- Message:
- Working on better handling of multithreading in general and core dumps in particular. See notes: new types: register is something that when dereferenced gives you the registers. the Ureg is no longer mapped at 0. refconst is something that gives a constant when dereferenced. new builtin register("AX") creates register values new builtin refconst(0x123) creates refconst values new builtin var("foo") is equivalent to the variable foo (it returns foo but can also be used as the lhs of an assignment). new acid function getregs() returns a list of the current values of registers. new acid function setregs() sets the current registers to those values. note that getregs and setregs operate on register locations, not the register values themselves. new acid function resetregs() sets registers to register("AX"), etc. new acid function clearregs() sets all registers to constant -1. the default register settings are as in resetregs(), not small numbers. new acid variables coretext, pids, systype, corefile, cmdline. new behavior: local variable lookup, stk, etc., use the acid values of registers (*PC, *SP, and so on), so the thread support code can change the context completely. unary + is applicable to more data types and prints more often.
- Actions:
- History | Blame | Raw File
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();109 acidregs = mallocz(sizeof *acidregs, 1);110 acidregs->rw = acidregsrw;112 if(mtype && machbyname(mtype) == 0)113 print("unknown machine %s", mtype);115 if (attachfiles(argc, argv) < 0)116 varreg(); /* use default register set on error */117 if(mach == nil)118 mach = machcpu;120 symhdr = nil; /* not supposed to use this anymore */122 l = mkvar("acid");123 l->v->set = 1;124 l->v->type = TLIST;125 l->v->store.u.l = nil;127 loadmodule(unsharp("#9/acid/port"));128 for(i = 0; i < nlm; i++) {129 if(access(lm[i], AREAD) >= 0)130 loadmodule(lm[i]);131 else {132 sprint(buf, "#9/acid/%s", lm[i]);133 loadmodule(unsharp(buf));134 }135 }137 userinit();138 varsym();140 l = look("acidmap");141 if(l && l->proc) {142 if(setjmp(err) == 0){143 n = an(ONAME, ZN, ZN);144 n->sym = l;145 n = an(OCALL, n, ZN);146 execute(n);147 }148 }150 interactive = 1;151 initialising = 0;152 line = 1;154 notify(catcher);156 for(;;) {157 if(setjmp(err)) {158 Binit(&bioout, 1, OWRITE);159 unwind();160 }161 stacked = 0;163 Bprint(bout, "acid; ");165 if(yyparse() != 1)166 die();167 restartio();169 unwind();170 }171 /*172 Bputc(bout, '\n');173 exits(0);174 */175 }177 void178 setstring(char *var, char *s)179 {180 Lsym *l;181 Value *v;183 l = mkvar(var);184 v = l->v;185 v->store.fmt = 's';186 v->set = 1;187 v->store.u.string = strnode(s ? s : "");188 v->type = TSTRING;189 }191 static int192 attachfiles(int argc, char **argv)193 {194 int fd;195 volatile int pid;196 char *s, *t;197 int i, omode;198 Fhdr *hdr;199 Lsym *l;201 pid = 0;202 interactive = 0;203 if(setjmp(err))204 return -1;206 /*207 * Unix and Plan 9 differ on what the right order of pid, text, and core is.208 * I never remember anyway. Let's just accept them in any order.209 */210 omode = wtflag ? ORDWR : OREAD;211 for(i=0; i<argc; i++){212 if(isnumeric(argv[i])){213 if(pid){214 fprint(2, "already have pid %d; ignoring pid %d\n", pid, argv[i]);215 continue;216 }217 if(corhdr){218 fprint(2, "already have core %s; ignoring pid %d\n", corfil, pid);219 continue;220 }221 pid = atoi(argv[i]);222 continue;223 }224 if((hdr = crackhdr(argv[i], omode)) == nil){225 fprint(2, "crackhdr %s: %r\n", argv[i]);226 if(argc == 1 && (fd = open(argv[i], omode)) > 0){227 fprint(2, "loading %s direct mapped\n", argv[i]);228 symmap = dumbmap(fd);229 cormap = dumbmap(fd);230 symfil = argv[i];231 corfil = argv[i];232 goto Run;233 }234 continue;235 }236 fprint(2, "%s: %s %s %s\n", argv[i], hdr->aname, hdr->mname, hdr->fname);237 if(hdr->ftype == FCORE){238 if(pid){239 fprint(2, "already have pid %d; ignoring core %s\n", pid, argv[i]);240 uncrackhdr(hdr);241 continue;242 }243 if(corhdr){244 fprint(2, "already have core %s; ignoring core %s\n", corfil, argv[i]);245 uncrackhdr(hdr);246 continue;247 }248 corhdr = hdr;249 corfil = argv[i];250 }else{251 if(symhdr){252 fprint(2, "already have text %s; ignoring text %s\n", symfil, argv[i]);253 uncrackhdr(hdr);254 continue;255 }256 symhdr = hdr;257 symfil = argv[i];258 }259 }261 if(symhdr==nil){262 symfil = "a.out";263 if(pid){264 if((s = proctextfile(pid)) != nil){265 fprint(2, "pid %d: text %s\n", pid, s);266 symfil = s;267 }268 }269 if(corhdr){270 /*271 * prog gives only the basename of the command,272 * so try the command line for a path.273 */274 if((s = strdup(corhdr->cmdline)) != nil){275 t = strchr(s, ' ');276 if(t)277 *t = 0;278 if((t = searchpath(s)) != nil){279 fprint(2, "core: text %s\n", t);280 symfil = t;281 }282 free(s);283 }284 }286 if((symhdr = crackhdr(symfil, omode)) == nil){287 fprint(2, "crackhdr %s: %r\n", symfil);288 symfil = nil;289 }else290 fprint(2, "%s: %s %s %s\n", symfil, symhdr->aname, symhdr->mname, symhdr->fname);291 }293 if(symhdr)294 symopen(symhdr);296 if(!mach)297 mach = machcpu;299 /*300 * Set up maps.301 */302 symmap = allocmap();303 cormap = allocmap();304 if(symmap == nil || cormap == nil)305 sysfatal("allocating maps: %r");307 if(symhdr){308 if(mapfile(symhdr, 0, symmap, nil) < 0)309 fprint(2, "mapping %s: %r\n", symfil);310 mapfile(symhdr, 0, cormap, nil);311 }313 Run:314 setstring("objtype", mach->name);315 setstring("textfile", symfil);316 setstring("systype", symhdr ? symhdr->aname : "");317 setstring("corefile", corfil);319 l = mkvar("pids");320 l->v->set = 1;321 l->v->type = TLIST;322 l->v->store.u.l = nil;324 if(pid)325 sproc(pid);326 if(corhdr)327 setcore(corhdr);328 varreg();329 return 0;330 }332 void333 setcore(Fhdr *hdr)334 {335 int i;336 Lsym *l;337 Value *v;338 List **tail, *tl;340 unmapproc(cormap);341 unmapfile(corhdr, cormap);342 free(correg);343 correg = nil;345 if(hdr == nil)346 error("no core");347 if(mapfile(hdr, 0, cormap, &correg) < 0)348 error("mapfile %s: %r", hdr->filename);349 corhdr = hdr;350 corfil = hdr->filename;352 l = mkvar("pid");353 v = l->v;354 v->store.fmt = 'D';355 v->set = 1;356 v->store.u.ival = hdr->pid;358 setstring("corefile", corfil);359 setstring("cmdline", hdr->cmdline);361 l = mkvar("pids");362 l->v->set = 1;363 l->v->type = TLIST;364 l->v->store.u.l = nil;365 tail = &l->v->store.u.l;366 for(i=0; i<hdr->nthread; i++){367 tl = al(TINT);368 tl->store.u.ival = hdr->thread[i].id;369 tl->store.fmt = 'X';370 *tail = tl;371 tail = &tl->next;372 }374 if(hdr->nthread)375 sproc(hdr->thread[0].id);376 }378 void379 die(void)380 {381 Lsym *s;382 List *f;383 int first;385 Bprint(bout, "\n");387 first = 1;388 s = look("proclist");389 if(s && s->v->type == TLIST) {390 for(f = s->v->store.u.l; f; f = f->next){391 detachproc((int)f->store.u.ival);392 Bprint(bout, "%s %d", first ? "/bin/kill -9" : "", (int)f->store.u.ival);393 first = 0;394 }395 }396 if(!first)397 Bprint(bout, "\n");398 exits(0);399 }401 void402 userinit(void)403 {404 Lsym *l;405 Node *n;406 char buf[128], *p;408 sprint(buf, "#9/acid/%s", mach->name);409 loadmodule(unsharp(buf));410 p = getenv("HOME");411 if(p != 0) {412 sprint(buf, "%s/lib/acid", p);413 silent = 1;414 loadmodule(buf);415 }417 interactive = 0;418 if(setjmp(err)) {419 unwind();420 return;421 }422 l = look("acidinit");423 if(l && l->proc) {424 n = an(ONAME, ZN, ZN);425 n->sym = l;426 n = an(OCALL, n, ZN);427 execute(n);428 }429 }431 void432 loadmodule(char *s)433 {434 interactive = 0;435 if(setjmp(err)) {436 unwind();437 return;438 }439 pushfile(s);440 silent = 0;441 yyparse();442 popio();443 return;444 }446 Node*447 an(int op, Node *l, Node *r)448 {449 Node *n;451 n = gmalloc(sizeof(Node));452 memset(n, 0, sizeof(Node));453 n->gc.gclink = gcl;454 gcl = (Gc*)n;455 n->op = op;456 n->left = l;457 n->right = r;458 return n;459 }461 List*462 al(int t)463 {464 List *l;466 l = gmalloc(sizeof(List));467 memset(l, 0, sizeof(List));468 l->type = t;469 l->gc.gclink = gcl;470 gcl = (Gc*)l;471 return l;472 }474 Node*475 con(int v)476 {477 Node *n;479 n = an(OCONST, ZN, ZN);480 n->store.u.ival = v;481 n->store.fmt = 'X';482 n->type = TINT;483 return n;484 }486 void487 fatal(char *fmt, ...)488 {489 char buf[128];490 va_list arg;492 va_start(arg, fmt);493 vseprint(buf, buf+sizeof(buf), fmt, arg);494 va_end(arg);495 fprint(2, "%s: %Z (fatal problem) %s\n", argv0, buf);496 exits(buf);497 }499 void500 yyerror(char *fmt, ...)501 {502 char buf[128];503 va_list arg;505 if(strcmp(fmt, "syntax error") == 0) {506 yyerror("syntax error, near symbol '%s'", symbol);507 return;508 }509 va_start(arg, fmt);510 vseprint(buf, buf+sizeof(buf), fmt, arg);511 va_end(arg);512 print("%Z: %s\n", buf);513 }515 void516 marktree(Node *n)517 {519 if(n == 0)520 return;522 marktree(n->left);523 marktree(n->right);525 n->gc.gcmark = 1;526 if(n->op != OCONST)527 return;529 switch(n->type) {530 case TSTRING:531 n->store.u.string->gc.gcmark = 1;532 break;533 case TLIST:534 marklist(n->store.u.l);535 break;536 case TCODE:537 marktree(n->store.u.cc);538 break;539 }540 }542 void543 marklist(List *l)544 {545 while(l) {546 l->gc.gcmark = 1;547 switch(l->type) {548 case TSTRING:549 l->store.u.string->gc.gcmark = 1;550 break;551 case TLIST:552 marklist(l->store.u.l);553 break;554 case TCODE:555 marktree(l->store.u.cc);556 break;557 }558 l = l->next;559 }560 }562 void563 gc(void)564 {565 int i;566 Lsym *f;567 Value *v;568 Gc *m, **p, *next;570 if(dogc < Mempergc)571 return;572 dogc = 0;574 /* Mark */575 for(m = gcl; m; m = m->gclink)576 m->gcmark = 0;578 /* Scan */579 for(i = 0; i < Hashsize; i++) {580 for(f = hash[i]; f; f = f->hash) {581 marktree(f->proc);582 if(f->lexval != Tid)583 continue;584 for(v = f->v; v; v = v->pop) {585 switch(v->type) {586 case TSTRING:587 v->store.u.string->gc.gcmark = 1;588 break;589 case TLIST:590 marklist(v->store.u.l);591 break;592 case TCODE:593 marktree(v->store.u.cc);594 break;595 case TCON:596 marktree(v->store.u.con);597 break;598 }599 }600 }601 }603 /* Free */604 p = &gcl;605 for(m = gcl; m; m = next) {606 next = m->gclink;607 if(m->gcmark == 0) {608 *p = next;609 free(m); /* Sleazy reliance on my malloc */610 }611 else612 p = &m->gclink;613 }614 }616 void*617 gmalloc(long l)618 {619 void *p;621 dogc += l;622 p = malloc(l);623 if(p == 0)624 fatal("out of memory");625 return p;626 }628 void629 checkqid(int f1, int pid)630 {631 int fd;632 Dir *d1, *d2;633 char buf[128];635 if(kernel)636 return;638 d1 = dirfstat(f1);639 if(d1 == nil){640 print("checkqid: (qid not checked) dirfstat: %r\n");641 return;642 }644 sprint(buf, "/proc/%d/text", pid);645 fd = open(buf, OREAD);646 if(fd < 0 || (d2 = dirfstat(fd)) == nil){647 print("checkqid: (qid not checked) dirstat %s: %r\n", buf);648 free(d1);649 if(fd >= 0)650 close(fd);651 return;652 }654 close(fd);656 if(d1->qid.path != d2->qid.path || d1->qid.vers != d2->qid.vers || d1->qid.type != d2->qid.type){657 print("path %llux %llux vers %lud %lud type %d %d\n",658 d1->qid.path, d2->qid.path, d1->qid.vers, d2->qid.vers, d1->qid.type, d2->qid.type);659 print("warning: image does not match text for pid %d\n", pid);660 }661 free(d1);662 free(d2);663 }665 void666 catcher(void *junk, char *s)667 {668 USED(junk);670 if(strstr(s, "interrupt")) {671 gotint = 1;672 noted(NCONT);673 }674 if(strstr(s, "child"))675 noted(NCONT);676 fprint(2, "note: %s\n", s);677 noted(NDFLT);678 }680 char*681 system(void)682 {683 char *cpu, *p, *q;684 static char kernel[128];686 cpu = getenv("cputype");687 if(cpu == 0) {688 cpu = "mips";689 print("$cputype not set; assuming %s\n", cpu);690 }691 p = getenv("terminal");692 if(p == 0 || (p=strchr(p, ' ')) == 0 || p[1] == ' ' || p[1] == 0) {693 p = "9power";694 print("missing or bad $terminal; assuming %s\n", p);695 }696 else{697 p++;698 q = strchr(p, ' ');699 if(q)700 *q = 0;701 sprint(kernel, "/%s/9%s", cpu, p);702 }703 return kernel;704 }706 int707 isnumeric(char *s)708 {709 while(*s) {710 if(*s < '0' || *s > '9')711 return 0;712 s++;713 }714 return 1;715 }717 int718 xfmt(Fmt *f)719 {720 f->flags ^= FmtSharp;721 return __ifmt(f);722 }