main.c (9006B)
1 #include <u.h> 2 #include <libc.h> 3 #include <bio.h> 4 #include <mach.h> 5 #define Extern 6 #include "acid.h" 7 #include "y.tab.h" 8 9 extern int __ifmt(Fmt*); 10 11 static Biobuf bioout; 12 static char* lm[16]; 13 static int nlm; 14 static char* mtype; 15 16 static int attachfiles(int, char**); 17 int xfmt(Fmt*); 18 int isnumeric(char*); 19 void die(void); 20 void setcore(Fhdr*); 21 22 void 23 usage(void) 24 { 25 fprint(2, "usage: acid [-c core] [-l module] [-m machine] [-qrw] [-k] [pid] [file]\n"); 26 exits("usage"); 27 } 28 29 Map* 30 dumbmap(int fd) 31 { 32 Map *dumb; 33 Seg s; 34 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 } 51 52 void 53 main(int argc, char *argv[]) 54 { 55 Lsym *volatile l; 56 Node *n; 57 char buf[128], *s; 58 int pid, i; 59 60 argv0 = argv[0]; 61 pid = 0; 62 quiet = 1; 63 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 }ARGEND 95 96 USED(pid); 97 98 fmtinstall('Z', Zfmt); 99 fmtinstall('L', locfmt); 100 Binit(&bioout, 1, OWRITE); 101 bout = &bioout; 102 103 initexpr(); 104 initprint(); 105 kinit(); 106 initialising = 1; 107 pushfile(0); 108 loadvars(); 109 installbuiltin(); 110 acidregs = mallocz(sizeof *acidregs, 1); 111 acidregs->rw = acidregsrw; 112 113 if(mtype && machbyname(mtype) == 0) 114 print("unknown machine %s", mtype); 115 116 if (attachfiles(argc, argv) < 0) 117 varreg(); /* use default register set on error */ 118 if(mach == nil) 119 mach = machcpu; 120 121 symhdr = nil; /* not supposed to use this anymore */ 122 123 l = mkvar("acid"); 124 l->v->set = 1; 125 l->v->type = TLIST; 126 l->v->store.u.l = nil; 127 128 loadmodule(unsharp("#9/acid/port")); 129 for(i = 0; i < nlm; i++) { 130 if(access(lm[i], AREAD) >= 0) 131 loadmodule(lm[i]); 132 else { 133 sprint(buf, "#9/acid/%s", lm[i]); 134 loadmodule(unsharp(buf)); 135 } 136 } 137 138 userinit(); 139 varsym(); 140 141 l = look("acidmap"); 142 if(l && l->proc) { 143 if(setjmp(err) == 0){ 144 n = an(ONAME, ZN, ZN); 145 n->sym = l; 146 n = an(OCALL, n, ZN); 147 execute(n); 148 } 149 } 150 151 interactive = 1; 152 initialising = 0; 153 line = 1; 154 155 notify(catcher); 156 157 for(;;) { 158 if(setjmp(err)) { 159 Binit(&bioout, 1, OWRITE); 160 unwind(); 161 } 162 stacked = 0; 163 164 Bprint(bout, "acid; "); 165 166 if(yyparse() != 1) 167 die(); 168 restartio(); 169 170 unwind(); 171 } 172 /* 173 Bputc(bout, '\n'); 174 exits(0); 175 */ 176 } 177 178 void 179 setstring(char *var, char *s) 180 { 181 Lsym *l; 182 Value *v; 183 184 l = mkvar(var); 185 v = l->v; 186 v->store.fmt = 's'; 187 v->set = 1; 188 v->store.u.string = strnode(s ? s : ""); 189 v->type = TSTRING; 190 } 191 192 static int 193 attachfiles(int argc, char **argv) 194 { 195 volatile int pid; 196 Lsym *l; 197 198 pid = 0; 199 interactive = 0; 200 USED(pid); 201 202 if(setjmp(err)) 203 return -1; 204 205 attachargs(argc, argv, wtflag?ORDWR:OREAD, 1); 206 207 setstring("objtype", mach->name); 208 setstring("textfile", symfil); 209 setstring("systype", symhdr ? symhdr->aname : ""); 210 setstring("corefile", corfil); 211 212 l = mkvar("pids"); 213 l->v->set = 1; 214 l->v->type = TLIST; 215 l->v->store.u.l = nil; 216 217 if(corpid) 218 sproc(corpid); 219 if(corhdr) 220 setcore(corhdr); 221 varreg(); 222 return 0; 223 } 224 225 void 226 setcore(Fhdr *hdr) 227 { 228 int i; 229 Lsym *l; 230 Value *v; 231 List **tail, *tl; 232 233 unmapproc(cormap); 234 unmapfile(corhdr, cormap); 235 free(correg); 236 correg = nil; 237 238 if(hdr == nil) 239 error("no core"); 240 if(mapfile(hdr, 0, cormap, &correg) < 0) 241 error("mapfile %s: %r", hdr->filename); 242 corhdr = hdr; 243 corfil = hdr->filename; 244 245 l = mkvar("pid"); 246 v = l->v; 247 v->store.fmt = 'D'; 248 v->set = 1; 249 v->store.u.ival = hdr->pid; 250 251 setstring("corefile", corfil); 252 setstring("cmdline", hdr->cmdline); 253 254 l = mkvar("pids"); 255 l->v->set = 1; 256 l->v->type = TLIST; 257 l->v->store.u.l = nil; 258 tail = &l->v->store.u.l; 259 for(i=0; i<hdr->nthread; i++){ 260 tl = al(TINT); 261 tl->store.u.ival = hdr->thread[i].id; 262 tl->store.fmt = 'X'; 263 *tail = tl; 264 tail = &tl->next; 265 } 266 267 if(hdr->nthread) 268 sproc(hdr->thread[0].id); 269 } 270 271 void 272 die(void) 273 { 274 Lsym *s; 275 List *f; 276 int first; 277 278 Bprint(bout, "\n"); 279 280 first = 1; 281 s = look("proclist"); 282 if(s && s->v->type == TLIST) { 283 for(f = s->v->store.u.l; f; f = f->next){ 284 detachproc((int)f->store.u.ival); 285 Bprint(bout, "%s %d", first ? "/bin/kill -9" : "", (int)f->store.u.ival); 286 first = 0; 287 } 288 } 289 if(!first) 290 Bprint(bout, "\n"); 291 exits(0); 292 } 293 294 void 295 userinit(void) 296 { 297 Lsym *l; 298 Node *n; 299 char buf[128], *p; 300 301 sprint(buf, "#9/acid/%s", mach->name); 302 loadmodule(unsharp(buf)); 303 p = getenv("HOME"); 304 if(p != 0) { 305 sprint(buf, "%s/lib/acid", p); 306 silent = 1; 307 loadmodule(buf); 308 } 309 310 interactive = 0; 311 if(setjmp(err)) { 312 unwind(); 313 return; 314 } 315 l = look("acidinit"); 316 if(l && l->proc) { 317 n = an(ONAME, ZN, ZN); 318 n->sym = l; 319 n = an(OCALL, n, ZN); 320 execute(n); 321 } 322 } 323 324 void 325 loadmodule(char *s) 326 { 327 interactive = 0; 328 if(setjmp(err)) { 329 unwind(); 330 return; 331 } 332 pushfile(s); 333 silent = 0; 334 yyparse(); 335 popio(); 336 return; 337 } 338 339 Node* 340 an(int op, Node *l, Node *r) 341 { 342 Node *n; 343 344 n = gmalloc(sizeof(Node)); 345 memset(n, 0, sizeof(Node)); 346 n->gc.gclink = gcl; 347 gcl = (Gc*)n; 348 n->op = op; 349 n->left = l; 350 n->right = r; 351 return n; 352 } 353 354 List* 355 al(int t) 356 { 357 List *l; 358 359 l = gmalloc(sizeof(List)); 360 memset(l, 0, sizeof(List)); 361 l->type = t; 362 l->gc.gclink = gcl; 363 gcl = (Gc*)l; 364 return l; 365 } 366 367 Node* 368 con(s64int v) 369 { 370 Node *n; 371 372 n = an(OCONST, ZN, ZN); 373 n->store.u.ival = v; 374 n->store.fmt = 'X'; 375 n->type = TINT; 376 return n; 377 } 378 379 void 380 fatal(char *fmt, ...) 381 { 382 char buf[128]; 383 va_list arg; 384 385 va_start(arg, fmt); 386 vseprint(buf, buf+sizeof(buf), fmt, arg); 387 va_end(arg); 388 fprint(2, "%s: %Z (fatal problem) %s\n", argv0, buf); 389 exits(buf); 390 } 391 392 void 393 yyerror(char *fmt, ...) 394 { 395 char buf[128]; 396 va_list arg; 397 398 if(strcmp(fmt, "syntax error") == 0) { 399 yyerror("syntax error, near symbol '%s'", symbol); 400 return; 401 } 402 va_start(arg, fmt); 403 vseprint(buf, buf+sizeof(buf), fmt, arg); 404 va_end(arg); 405 print("%Z: %s\n", buf); 406 } 407 408 void 409 marktree(Node *n) 410 { 411 412 if(n == 0) 413 return; 414 415 marktree(n->left); 416 marktree(n->right); 417 418 n->gc.gcmark = 1; 419 if(n->op != OCONST) 420 return; 421 422 switch(n->type) { 423 case TSTRING: 424 n->store.u.string->gc.gcmark = 1; 425 break; 426 case TLIST: 427 marklist(n->store.u.l); 428 break; 429 case TCODE: 430 marktree(n->store.u.cc); 431 break; 432 } 433 } 434 435 void 436 marklist(List *l) 437 { 438 while(l) { 439 l->gc.gcmark = 1; 440 switch(l->type) { 441 case TSTRING: 442 l->store.u.string->gc.gcmark = 1; 443 break; 444 case TLIST: 445 marklist(l->store.u.l); 446 break; 447 case TCODE: 448 marktree(l->store.u.cc); 449 break; 450 } 451 l = l->next; 452 } 453 } 454 455 void 456 gc(void) 457 { 458 int i; 459 Lsym *f; 460 Value *v; 461 Gc *m, **p, *next; 462 463 if(dogc < Mempergc) 464 return; 465 dogc = 0; 466 467 /* Mark */ 468 for(m = gcl; m; m = m->gclink) 469 m->gcmark = 0; 470 471 /* Scan */ 472 for(i = 0; i < Hashsize; i++) { 473 for(f = hash[i]; f; f = f->hash) { 474 marktree(f->proc); 475 if(f->lexval != Tid) 476 continue; 477 for(v = f->v; v; v = v->pop) { 478 switch(v->type) { 479 case TSTRING: 480 v->store.u.string->gc.gcmark = 1; 481 break; 482 case TLIST: 483 marklist(v->store.u.l); 484 break; 485 case TCODE: 486 marktree(v->store.u.cc); 487 break; 488 case TCON: 489 marktree(v->store.u.con); 490 break; 491 } 492 } 493 } 494 } 495 496 /* Free */ 497 p = &gcl; 498 for(m = gcl; m; m = next) { 499 next = m->gclink; 500 if(m->gcmark == 0) { 501 *p = next; 502 free(m); /* Sleazy reliance on my malloc */ 503 } 504 else 505 p = &m->gclink; 506 } 507 } 508 509 void* 510 gmalloc(long l) 511 { 512 void *p; 513 514 dogc += l; 515 p = malloc(l); 516 if(p == 0) 517 fatal("out of memory"); 518 return p; 519 } 520 521 void 522 checkqid(int f1, int pid) 523 { 524 int fd; 525 Dir *d1, *d2; 526 char buf[128]; 527 528 if(kernel) 529 return; 530 531 d1 = dirfstat(f1); 532 if(d1 == nil){ 533 print("checkqid: (qid not checked) dirfstat: %r\n"); 534 return; 535 } 536 537 sprint(buf, "/proc/%d/text", pid); 538 fd = open(buf, OREAD); 539 if(fd < 0 || (d2 = dirfstat(fd)) == nil){ 540 print("checkqid: (qid not checked) dirstat %s: %r\n", buf); 541 free(d1); 542 if(fd >= 0) 543 close(fd); 544 return; 545 } 546 547 close(fd); 548 549 if(d1->qid.path != d2->qid.path || d1->qid.vers != d2->qid.vers || d1->qid.type != d2->qid.type){ 550 print("path %#llux %#llux vers %lud %lud type %d %d\n", 551 d1->qid.path, d2->qid.path, d1->qid.vers, d2->qid.vers, d1->qid.type, d2->qid.type); 552 print("warning: image does not match text for pid %d\n", pid); 553 } 554 free(d1); 555 free(d2); 556 } 557 558 void 559 catcher(void *junk, char *s) 560 { 561 USED(junk); 562 563 if(strstr(s, "interrupt")) { 564 gotint = 1; 565 noted(NCONT); 566 } 567 if(strstr(s, "child")) 568 noted(NCONT); 569 fprint(2, "note: %s\n", s); 570 noted(NDFLT); 571 } 572 573 char* 574 system(void) 575 { 576 char *cpu, *p, *q; 577 static char kernel[128]; 578 579 cpu = getenv("cputype"); 580 if(cpu == 0) { 581 cpu = "mips"; 582 print("$cputype not set; assuming %s\n", cpu); 583 } 584 p = getenv("terminal"); 585 if(p == 0 || (p=strchr(p, ' ')) == 0 || p[1] == ' ' || p[1] == 0) { 586 p = "9power"; 587 print("missing or bad $terminal; assuming %s\n", p); 588 } 589 else{ 590 p++; 591 q = strchr(p, ' '); 592 if(q) 593 *q = 0; 594 sprint(kernel, "/%s/9%s", cpu, p); 595 } 596 return kernel; 597 } 598 599 int 600 isnumeric(char *s) 601 { 602 while(*s) { 603 if(*s < '0' || *s > '9') 604 return 0; 605 s++; 606 } 607 return 1; 608 }