Blob


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"
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 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 }
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 void
53 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 }ARGEND
96 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));
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);
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();
159 stacked = 0;
161 Bprint(bout, "acid; ");
163 if(yyparse() != 1)
164 die();
165 restartio();
167 unwind();
169 Bputc(bout, '\n');
170 exits(0);
173 static int
174 attachfiles(int argc, char **argv)
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;
199 if(corhdr){
200 fprint(2, "already have core %s; ignoring pid %d\n", corfil, pid);
201 continue;
203 pid = atoi(argv[i]);
204 continue;
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;
216 continue;
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;
225 if(corhdr){
226 fprint(2, "already have core %s; ignoring core %s\n", corfil, argv[i]);
227 uncrackhdr(hdr);
228 continue;
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;
238 symhdr = hdr;
239 symfil = argv[i];
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;
251 /* XXX pull command from core */
253 if((symhdr = crackhdr(symfil, omode)) == nil){
254 fprint(2, "crackhdr %s: %r\n", symfil);
255 symfil = nil;
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);
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;
316 void
317 setcore(Fhdr *hdr)
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;
332 void
333 die(void)
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);
347 exits(0);
350 void
351 userinit(void)
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);
366 interactive = 0;
367 if(setjmp(err)) {
368 unwind();
369 return;
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);
380 void
381 loadmodule(char *s)
383 interactive = 0;
384 if(setjmp(err)) {
385 unwind();
386 return;
388 pushfile(s);
389 silent = 0;
390 yyparse();
391 popio();
392 return;
395 Node*
396 an(int op, Node *l, Node *r)
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;
410 List*
411 al(int t)
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;
423 Node*
424 con(int v)
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;
435 void
436 fatal(char *fmt, ...)
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);
448 void
449 yyerror(char *fmt, ...)
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;
458 va_start(arg, fmt);
459 vseprint(buf, buf+sizeof(buf), fmt, arg);
460 va_end(arg);
461 print("%Z: %s\n", buf);
464 void
465 marktree(Node *n)
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;
491 void
492 marklist(List *l)
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;
507 l = l->next;
511 void
512 gc(void)
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;
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 */
557 else
558 p = &m->gclink;
562 void*
563 gmalloc(long l)
565 void *p;
567 dogc += l;
568 p = malloc(l);
569 if(p == 0)
570 fatal("out of memory");
571 return p;
574 void
575 checkqid(int f1, int pid)
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;
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;
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);
607 free(d1);
608 free(d2);
611 void
612 catcher(void *junk, char *s)
614 USED(junk);
616 if(strstr(s, "interrupt")) {
617 gotint = 1;
618 noted(NCONT);
620 if(strstr(s, "child"))
621 noted(NCONT);
622 fprint(2, "note: %s\n", s);
623 noted(NDFLT);
626 char*
627 system(void)
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);
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);
642 else{
643 p++;
644 q = strchr(p, ' ');
645 if(q)
646 *q = 0;
647 sprint(kernel, "/%s/9%s", cpu, p);
649 return kernel;
652 int
653 isnumeric(char *s)
655 while(*s) {
656 if(*s < '0' || *s > '9')
657 return 0;
658 s++;
660 return 1;
663 int
664 xfmt(Fmt *f)
666 f->flags ^= FmtSharp;
667 return __ifmt(f);