1 /*#include <u.h>*/ 2 #include <lib9.h> 3 #include <bio.h> 4 #include "mach.h" 5 #define Extern 6 #include "acid.h" 7 #include "y.tab.h" 8 9 char *argv0; 10 char *acidlib; 11 static Biobuf bioout; 12 static char prog[128]; 13 static char* lm[16]; 14 static int nlm; 15 static char* mtype; 16 17 static int attachfiles(char*, int); 18 int xfmt(Fmt*); 19 extern int gfltconv(Fmt*), _ifmt(Fmt*); 20 int isnumeric(char*); 21 void die(void); 22 23 void 24 usage(void) 25 { 26 fprint(2, "usage: acid [-l module] [-m machine] [-qrw] [-k] [-d flag] [-R tty] [pid] [file]\n"); 27 exits("usage"); 28 } 29 30 void 31 main(int argc, char *argv[]) 32 { 33 Dir *db; 34 Lsym *l; 35 Node *n; 36 char buf[128], *s; 37 int pid, i; 38 char *p; 39 char afile[512]; 40 41 argv0 = argv[0]; 42 pid = 0; 43 aout = "v.out"; 44 quiet = 1; 45 /* turn off all debugging */ 46 protodebug = 0; 47 48 mtype = 0; 49 ARGBEGIN{ 50 case 'm': 51 mtype = ARGF(); 52 break; 53 case 'w': 54 wtflag = 1; 55 break; 56 case 'l': 57 s = ARGF(); 58 if(s == 0) 59 usage(); 60 lm[nlm++] = s; 61 break; 62 case 'd': 63 p = ARGF(); 64 if (p == 0) 65 usage(); 66 while (*p) { 67 setdbg_opt(*p, 0); /* don't print set message */ 68 p++; 69 } 70 break; 71 case 'k': 72 kernel++; 73 break; 74 case 'q': 75 quiet = 0; 76 break; 77 case 'r': 78 pid = 1; 79 remote++; 80 kernel++; 81 break; 82 case 'R': 83 pid = 1; 84 rdebug++; 85 s = ARGF(); 86 if(s == 0) 87 usage(); 88 remfd = opentty(s, 0); 89 if(remfd < 0){ 90 fprint(2, "acid: can't open %s: %r\n", s); 91 exits("open"); 92 } 93 break; 94 default: 95 usage(); 96 }ARGEND 97 98 if(argc > 0) { 99 if(remote || rdebug) 100 aout = argv[0]; 101 else 102 if(isnumeric(argv[0])) { 103 pid = atoi(argv[0]); 104 sprint(prog, "/proc/%d/text", pid); 105 aout = prog; 106 if(argc > 1) 107 aout = argv[1]; 108 else if(kernel) 109 aout = mysystem(); 110 } 111 else { 112 if(kernel) { 113 print("-k requires a pid"); 114 kernel = 0; 115 } 116 aout = argv[0]; 117 } 118 } else if(rdebug) 119 aout = "/386/bpc"; 120 else if(remote) 121 aout = "/mips/bcarrera"; 122 123 fmtinstall('x', xfmt); 124 fmtinstall('L', Lfmt); 125 fmtinstall('f', gfltconv); 126 fmtinstall('F', gfltconv); 127 fmtinstall('g', gfltconv); 128 fmtinstall('G', gfltconv); 129 fmtinstall('e', gfltconv); 130 fmtinstall('E', gfltconv); 131 Binit(&bioout, 1, OWRITE); 132 bout = &bioout; 133 134 kinit(); 135 initialising = 1; 136 pushfile(0); 137 loadvars(); 138 installbuiltin(); 139 140 if(mtype && machbyname(mtype) == 0) 141 print("unknown machine %s", mtype); 142 143 if (attachfiles(aout, pid) < 0) 144 varreg(); /* use default register set on error */ 145 146 acidlib = getenv("ACIDLIB"); 147 if(acidlib == nil){ 148 p = getenv("ROOT"); 149 if(p == nil) 150 p = "/usr/inferno"; 151 snprint(afile, sizeof(afile)-1, "%s/lib/acid", p); 152 acidlib = strdup(afile); 153 } 154 155 snprint(afile, sizeof(afile)-1, "%s/port", acidlib); 156 loadmodule(afile); 157 for(i = 0; i < nlm; i++) { 158 if((db = dirstat(lm[i])) != nil) { 159 free(db); 160 loadmodule(lm[i]); 161 } else { 162 sprint(buf, "%s/%s", acidlib, lm[i]); 163 loadmodule(buf); 164 } 165 } 166 167 userinit(); 168 varsym(); 169 170 l = look("acidmap"); 171 if(l && l->proc) { 172 n = an(ONAME, ZN, ZN); 173 n->sym = l; 174 n = an(OCALL, n, ZN); 175 execute(n); 176 } 177 178 interactive = 1; 179 initialising = 0; 180 line = 1; 181 182 setup_os_notify(); 183 184 for(;;) { 185 if(setjmp(err)) { 186 Binit(&bioout, 1, OWRITE); 187 unwind(); 188 } 189 stacked = 0; 190 191 Bprint(bout, "acid: "); 192 193 if(yyparse() != 1) 194 die(); 195 restartio(); 196 197 unwind(); 198 } 199 Bputc(bout, '\n'); 200 exits(0); 201 } 202 203 static int 204 attachfiles(char *aout, int pid) 205 { 206 interactive = 0; 207 if(setjmp(err)) 208 return -1; 209 210 if(aout) { /* executable given */ 211 if(wtflag) 212 text = open(aout, ORDWR); 213 else 214 text = open(aout, OREAD); 215 216 if(text < 0) 217 error("%s: can't open %s: %r\n", argv0, aout); 218 readtext(aout); 219 } 220 if(pid) /* pid given */ 221 sproc(pid); 222 return 0; 223 } 224 225 void 226 die(void) 227 { 228 Lsym *s; 229 List *f; 230 231 Bprint(bout, "\n"); 232 233 s = look("proclist"); 234 if(!rdebug && s && s->v->type == TLIST) { 235 for(f = s->v->vstore.u0.sl; f; f = f->next) 236 Bprint(bout, "echo kill > /proc/%d/ctl\n", (int)f->lstore.u0.sival); 237 } 238 exits(0); 239 } 240 241 void 242 userinit(void) 243 { 244 Lsym *l; 245 Node *n; 246 char buf[512], *p; 247 248 249 p = getenv("home"); 250 if(p == 0) 251 p = getenv("HOME"); 252 if(p != 0) { 253 snprint(buf, sizeof(buf)-1, "%s/lib/acid", p); 254 silent = 1; 255 loadmodule(buf); 256 } 257 258 if(rdebug){ 259 snprint(buf, sizeof(buf)-1, "%s/rdebug", acidlib); 260 loadmodule(buf); 261 } 262 263 snprint(buf, sizeof(buf)-1, "%s/%s", acidlib, mach->name); 264 loadmodule(buf); 265 266 interactive = 0; 267 if(setjmp(err)) { 268 unwind(); 269 return; 270 } 271 l = look("acidinit"); 272 if(l && l->proc) { 273 n = an(ONAME, ZN, ZN); 274 n->sym = l; 275 n = an(OCALL, n, ZN); 276 execute(n); 277 } 278 } 279 280 void 281 loadmodule(char *s) 282 { 283 interactive = 0; 284 if(setjmp(err)) { 285 unwind(); 286 return; 287 } 288 pushfile(s); 289 silent = 0; 290 yyparse(); 291 popio(); 292 return; 293 } 294 295 void 296 readtext(char *s) 297 { 298 Dir *d; 299 Lsym *l; 300 Value *v; 301 Symbol sym; 302 ulong length; 303 extern Machdata mipsmach; 304 305 if(mtype != 0){ 306 symmap = newmap(0, 1); 307 if(symmap == 0) 308 print("%s: (error) loadmap: cannot make symbol map\n", argv0); 309 length = 1<<24; 310 d = dirfstat(text); 311 if(d != nil) { 312 length = d->length; 313 free(d); 314 } 315 setmap(symmap, text, 0, length, 0, "binary"); 316 free(d); 317 return; 318 } 319 320 machdata = &mipsmach; 321 322 if(!crackhdr(text, &fhdr)) { 323 print("can't decode file header\n"); 324 return; 325 } 326 327 symmap = loadmap(0, text, &fhdr); 328 if(symmap == 0) 329 print("%s: (error) loadmap: cannot make symbol map\n", argv0); 330 331 if(syminit(text, &fhdr) < 0) { 332 print("%s: (error) syminit: %r\n", argv0); 333 return; 334 } 335 print("%s:%s\n\n", s, fhdr.name); 336 337 if(mach->sbreg && lookup(0, mach->sbreg, &sym)) { 338 mach->sb = sym.value; 339 l = enter("SB", Tid); 340 l->v->vstore.fmt = 'X'; 341 l->v->vstore.u0.sival = mach->sb; 342 l->v->type = TINT; 343 l->v->set = 1; 344 } 345 346 l = mkvar("objtype"); 347 v = l->v; 348 v->vstore.fmt = 's'; 349 v->set = 1; 350 v->vstore.u0.sstring = strnode(mach->name); 351 v->type = TSTRING; 352 353 l = mkvar("textfile"); 354 v = l->v; 355 v->vstore.fmt = 's'; 356 v->set = 1; 357 v->vstore.u0.sstring = strnode(s); 358 v->type = TSTRING; 359 360 machbytype(fhdr.type); 361 varreg(); 362 } 363 364 Node* 365 an(int op, Node *l, Node *r) 366 { 367 Node *n; 368 369 n = gmalloc(sizeof(Node)); 370 n->ngc.gclink = gcl; 371 gcl = &n->ngc; 372 n->op = op; 373 n->left = l; 374 n->right = r; 375 return n; 376 } 377 378 List* 379 al(int t) 380 { 381 List *l; 382 383 l = gmalloc(sizeof(List)); 384 l->type = t; 385 l->lgc.gclink = gcl; 386 gcl = &l->lgc; 387 return l; 388 } 389 390 Node* 391 con(int v) 392 { 393 Node *n; 394 395 n = an(OCONST, ZN, ZN); 396 n->nstore.u0.sival = v; 397 n->nstore.fmt = 'X'; 398 n->type = TINT; 399 return n; 400 } 401 402 void 403 fatal(char *fmt, ...) 404 { 405 char buf[128]; 406 va_list arg; 407 408 va_start(arg, fmt); 409 vseprint(buf, buf+sizeof(buf), fmt, arg); 410 va_end(arg); 411 fprint(2, "%s: %L (fatal problem) %s\n", argv0, buf); 412 exits(buf); 413 } 414 415 void 416 yyerror(char *fmt, ...) 417 { 418 char buf[128]; 419 va_list arg; 420 421 if(strcmp(fmt, "syntax error") == 0) { 422 yyerror("syntax error, near symbol '%s'", symbol); 423 return; 424 } 425 va_start(arg, fmt); 426 vseprint(buf, buf+sizeof(buf), fmt, arg); 427 va_end(arg); 428 print("%L: %s\n", buf); 429 } 430 431 void 432 marktree(Node *n) 433 { 434 435 if(n == 0) 436 return; 437 438 marktree(n->left); 439 marktree(n->right); 440 441 n->ngc.gcmark = 1; 442 if(n->op != OCONST) 443 return; 444 445 switch(n->type) { 446 case TSTRING: 447 n->nstore.u0.sstring->sgc.gcmark = 1; 448 break; 449 case TLIST: 450 marklist(n->nstore.u0.sl); 451 break; 452 case TCODE: 453 marktree(n->nstore.u0.scc); 454 break; 455 } 456 } 457 458 void 459 marklist(List *l) 460 { 461 while(l) { 462 l->lgc.gcmark = 1; 463 switch(l->type) { 464 case TSTRING: 465 l->lstore.u0.sstring->sgc.gcmark = 1; 466 break; 467 case TLIST: 468 marklist(l->lstore.u0.sl); 469 break; 470 case TCODE: 471 marktree(l->lstore.u0.scc); 472 break; 473 } 474 l = l->next; 475 } 476 } 477 478 void 479 gc(void) 480 { 481 int i; 482 Lsym *f; 483 Value *v; 484 Gc *m, **p, *next; 485 486 if(dogc < Mempergc) 487 return; 488 dogc = 0; 489 490 /* Mark */ 491 for(m = gcl; m; m = m->gclink) 492 m->gcmark = 0; 493 494 /* Scan */ 495 for(i = 0; i < Hashsize; i++) { 496 for(f = hash[i]; f; f = f->hash) { 497 marktree(f->proc); 498 if(f->lexval != Tid) 499 continue; 500 for(v = f->v; v; v = v->pop) { 501 switch(v->type) { 502 case TSTRING: 503 v->vstore.u0.sstring->sgc.gcmark = 1; 504 break; 505 case TLIST: 506 marklist(v->vstore.u0.sl); 507 break; 508 case TCODE: 509 marktree(v->vstore.u0.scc); 510 break; 511 } 512 } 513 } 514 } 515 516 /* Free */ 517 p = &gcl; 518 for(m = gcl; m; m = next) { 519 next = m->gclink; 520 if(m->gcmark == 0) { 521 *p = next; 522 free(m); /* Sleazy reliance on my malloc */ 523 } 524 else 525 p = &m->gclink; 526 } 527 } 528 529 void* 530 gmalloc(long l) 531 { 532 void *p; 533 534 dogc += l; 535 p = malloc(l); 536 if(p == 0) 537 fatal("out of memory"); 538 memset(p, 0, l); 539 return p; 540 } 541 542 void 543 checkqid(int f1, int pid) 544 { 545 int fd; 546 Dir *d1, *d2; 547 char buf[128]; 548 549 if(kernel || rdebug) 550 return; 551 552 d1 = dirfstat(f1); 553 if(d1 == nil) 554 fatal("checkqid: (qid not checked) dirfstat: %r"); 555 556 sprint(buf, "/proc/%d/text", pid); 557 fd = open(buf, OREAD); 558 if(fd < 0 || (d2 = dirfstat(fd)) == nil){ 559 fatal("checkqid: (qid not checked) dirstat %s: %r", buf); 560 return; /* not reached */ 561 } 562 563 close(fd); 564 565 if(d1->qid.path != d2->qid.path || d1->qid.vers != d2->qid.vers || d1->qid.type != d2->qid.type){ 566 print("path %llux %llux vers %lud %lud type %d %d\n", 567 d1->qid.path, d2->qid.path, d1->qid.vers, d2->qid.vers, d1->qid.type, d2->qid.type); 568 print("warning: image does not match text for pid %d\n", pid); 569 } 570 free(d1); 571 free(d2); 572 } 573 574 char* 575 mysystem(void) 576 { 577 char *cpu, *p, *q; 578 static char kernel[128]; 579 580 cpu = getenv("cputype"); 581 if(cpu == 0) { 582 cpu = "mips"; 583 print("$cputype not set; assuming %s\n", cpu); 584 } 585 p = getenv("terminal"); 586 if(p == 0 || (p=strchr(p, ' ')) == 0 || p[1] == ' ' || p[1] == 0) { 587 p = "9power"; 588 print("missing or bad $terminal; assuming %s\n", p); 589 } 590 else{ 591 p++; 592 q = strchr(p, ' '); 593 if(q) 594 *q = 0; 595 sprint(kernel, "/%s/b%s", cpu, p); 596 } 597 return kernel; 598 } 599 600 int 601 isnumeric(char *s) 602 { 603 while(*s) { 604 if(*s < '0' || *s > '9') 605 return 0; 606 s++; 607 } 608 return 1; 609 } 610 611 int 612 xfmt(Fmt *f) 613 { 614 f->flags ^= FmtSharp; 615 return _ifmt(f); 616 } 617