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 *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 }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;
177 volatile int pid;
178 char *s;
179 int i, omode;
180 Fhdr *hdr;
181 Lsym *l;
182 Value *v;
184 pid = 0;
185 interactive = 0;
186 if(setjmp(err))
187 return -1;
189 /*
190 * Unix and Plan 9 differ on what the right order of pid, text, and core is.
191 * I never remember anyway. Let's just accept them in any order.
192 */
193 omode = wtflag ? ORDWR : OREAD;
194 for(i=0; i<argc; i++){
195 if(isnumeric(argv[i])){
196 if(pid){
197 fprint(2, "already have pid %d; ignoring pid %d\n", pid, argv[i]);
198 continue;
200 if(corhdr){
201 fprint(2, "already have core %s; ignoring pid %d\n", corfil, pid);
202 continue;
204 pid = atoi(argv[i]);
205 continue;
207 if((hdr = crackhdr(argv[i], omode)) == nil){
208 fprint(2, "crackhdr %s: %r\n", argv[i]);
209 if(argc == 1 && (fd = open(argv[i], omode)) > 0){
210 fprint(2, "loading %s direct mapped\n", argv[i]);
211 symmap = dumbmap(fd);
212 cormap = dumbmap(fd);
213 symfil = argv[i];
214 corfil = argv[i];
215 goto Run;
217 continue;
219 fprint(2, "%s: %s %s %s\n", argv[i], hdr->aname, hdr->mname, hdr->fname);
220 if(hdr->ftype == FCORE){
221 if(pid){
222 fprint(2, "already have pid %d; ignoring core %s\n", pid, argv[i]);
223 uncrackhdr(hdr);
224 continue;
226 if(corhdr){
227 fprint(2, "already have core %s; ignoring core %s\n", corfil, argv[i]);
228 uncrackhdr(hdr);
229 continue;
231 corhdr = hdr;
232 corfil = argv[i];
233 }else{
234 if(symhdr){
235 fprint(2, "already have text %s; ignoring text %s\n", symfil, argv[i]);
236 uncrackhdr(hdr);
237 continue;
239 symhdr = hdr;
240 symfil = argv[i];
244 if(symhdr==nil){
245 symfil = "a.out";
246 if(pid){
247 if((s = proctextfile(pid)) != nil){
248 fprint(2, "pid %d: text %s\n", pid, s);
249 symfil = s;
252 /* XXX pull command from core */
254 if((symhdr = crackhdr(symfil, omode)) == nil){
255 fprint(2, "crackhdr %s: %r\n", symfil);
256 symfil = nil;
260 if(symhdr)
261 symopen(symhdr);
263 if(!mach)
264 mach = machcpu;
266 /*
267 * Set up maps.
268 */
269 symmap = allocmap();
270 cormap = allocmap();
271 if(symmap == nil || cormap == nil)
272 sysfatal("allocating maps: %r");
274 if(symhdr){
275 if(mapfile(symhdr, 0, symmap, nil) < 0)
276 fprint(2, "mapping %s: %r\n", symfil);
277 mapfile(symhdr, 0, cormap, nil);
280 Run:
281 l = mkvar("objtype");
282 v = l->v;
283 v->store.fmt = 's';
284 v->set = 1;
285 v->store.u.string = strnode(mach->name);
286 v->type = TSTRING;
288 l = mkvar("textfile");
289 v = l->v;
290 v->store.fmt = 's';
291 v->set = 1;
292 v->store.u.string = strnode(symfil ? symfil : "");
293 v->type = TSTRING;
295 l = mkvar("systype");
296 v = l->v;
297 v->store.fmt = 's';
298 v->set = 1;
299 v->store.u.string = strnode(symhdr ? symhdr->aname : "");
300 v->type = TSTRING;
302 l = mkvar("corefile");
303 v = l->v;
304 v->store.fmt = 's';
305 v->set = 1;
306 v->store.u.string = strnode(corfil ? corfil : "");
307 v->type = TSTRING;
309 if(pid)
310 sproc(pid);
311 if(corhdr)
312 setcore(corhdr);
313 varreg();
314 return 0;
317 void
318 setcore(Fhdr *hdr)
320 unmapproc(cormap);
321 unmapfile(corhdr, cormap);
322 free(correg);
323 correg = nil;
325 if(hdr == nil)
326 error("no core");
327 if(mapfile(hdr, 0, cormap, &correg) < 0)
328 error("mapfile %s: %r", hdr->filename);
329 corhdr = hdr;
330 corfil = hdr->filename;
333 void
334 die(void)
336 Lsym *s;
337 List *f;
339 Bprint(bout, "\n");
341 s = look("proclist");
342 if(s && s->v->type == TLIST) {
343 for(f = s->v->store.u.l; f; f = f->next){
344 detachproc((int)f->store.u.ival);
345 Bprint(bout, "/bin/kill -9 %d\n", (int)f->store.u.ival);
348 exits(0);
351 void
352 userinit(void)
354 Lsym *l;
355 Node *n;
356 char buf[128], *p;
358 sprint(buf, "#9/acid/%s", mach->name);
359 loadmodule(unsharp(buf));
360 p = getenv("HOME");
361 if(p != 0) {
362 sprint(buf, "%s/lib/acid", p);
363 silent = 1;
364 loadmodule(buf);
367 interactive = 0;
368 if(setjmp(err)) {
369 unwind();
370 return;
372 l = look("acidinit");
373 if(l && l->proc) {
374 n = an(ONAME, ZN, ZN);
375 n->sym = l;
376 n = an(OCALL, n, ZN);
377 execute(n);
381 void
382 loadmodule(char *s)
384 interactive = 0;
385 if(setjmp(err)) {
386 unwind();
387 return;
389 pushfile(s);
390 silent = 0;
391 yyparse();
392 popio();
393 return;
396 Node*
397 an(int op, Node *l, Node *r)
399 Node *n;
401 n = gmalloc(sizeof(Node));
402 memset(n, 0, sizeof(Node));
403 n->gc.gclink = gcl;
404 gcl = (Gc*)n;
405 n->op = op;
406 n->left = l;
407 n->right = r;
408 return n;
411 List*
412 al(int t)
414 List *l;
416 l = gmalloc(sizeof(List));
417 memset(l, 0, sizeof(List));
418 l->type = t;
419 l->gc.gclink = gcl;
420 gcl = (Gc*)l;
421 return l;
424 Node*
425 con(int v)
427 Node *n;
429 n = an(OCONST, ZN, ZN);
430 n->store.u.ival = v;
431 n->store.fmt = 'X';
432 n->type = TINT;
433 return n;
436 void
437 fatal(char *fmt, ...)
439 char buf[128];
440 va_list arg;
442 va_start(arg, fmt);
443 vseprint(buf, buf+sizeof(buf), fmt, arg);
444 va_end(arg);
445 fprint(2, "%s: %Z (fatal problem) %s\n", argv0, buf);
446 exits(buf);
449 void
450 yyerror(char *fmt, ...)
452 char buf[128];
453 va_list arg;
455 if(strcmp(fmt, "syntax error") == 0) {
456 yyerror("syntax error, near symbol '%s'", symbol);
457 return;
459 va_start(arg, fmt);
460 vseprint(buf, buf+sizeof(buf), fmt, arg);
461 va_end(arg);
462 print("%Z: %s\n", buf);
465 void
466 marktree(Node *n)
469 if(n == 0)
470 return;
472 marktree(n->left);
473 marktree(n->right);
475 n->gc.gcmark = 1;
476 if(n->op != OCONST)
477 return;
479 switch(n->type) {
480 case TSTRING:
481 n->store.u.string->gc.gcmark = 1;
482 break;
483 case TLIST:
484 marklist(n->store.u.l);
485 break;
486 case TCODE:
487 marktree(n->store.u.cc);
488 break;
492 void
493 marklist(List *l)
495 while(l) {
496 l->gc.gcmark = 1;
497 switch(l->type) {
498 case TSTRING:
499 l->store.u.string->gc.gcmark = 1;
500 break;
501 case TLIST:
502 marklist(l->store.u.l);
503 break;
504 case TCODE:
505 marktree(l->store.u.cc);
506 break;
508 l = l->next;
512 void
513 gc(void)
515 int i;
516 Lsym *f;
517 Value *v;
518 Gc *m, **p, *next;
520 if(dogc < Mempergc)
521 return;
522 dogc = 0;
524 /* Mark */
525 for(m = gcl; m; m = m->gclink)
526 m->gcmark = 0;
528 /* Scan */
529 for(i = 0; i < Hashsize; i++) {
530 for(f = hash[i]; f; f = f->hash) {
531 marktree(f->proc);
532 if(f->lexval != Tid)
533 continue;
534 for(v = f->v; v; v = v->pop) {
535 switch(v->type) {
536 case TSTRING:
537 v->store.u.string->gc.gcmark = 1;
538 break;
539 case TLIST:
540 marklist(v->store.u.l);
541 break;
542 case TCODE:
543 marktree(v->store.u.cc);
544 break;
550 /* Free */
551 p = &gcl;
552 for(m = gcl; m; m = next) {
553 next = m->gclink;
554 if(m->gcmark == 0) {
555 *p = next;
556 free(m); /* Sleazy reliance on my malloc */
558 else
559 p = &m->gclink;
563 void*
564 gmalloc(long l)
566 void *p;
568 dogc += l;
569 p = malloc(l);
570 if(p == 0)
571 fatal("out of memory");
572 return p;
575 void
576 checkqid(int f1, int pid)
578 int fd;
579 Dir *d1, *d2;
580 char buf[128];
582 if(kernel)
583 return;
585 d1 = dirfstat(f1);
586 if(d1 == nil){
587 print("checkqid: (qid not checked) dirfstat: %r\n");
588 return;
591 sprint(buf, "/proc/%d/text", pid);
592 fd = open(buf, OREAD);
593 if(fd < 0 || (d2 = dirfstat(fd)) == nil){
594 print("checkqid: (qid not checked) dirstat %s: %r\n", buf);
595 free(d1);
596 if(fd >= 0)
597 close(fd);
598 return;
601 close(fd);
603 if(d1->qid.path != d2->qid.path || d1->qid.vers != d2->qid.vers || d1->qid.type != d2->qid.type){
604 print("path %llux %llux vers %lud %lud type %d %d\n",
605 d1->qid.path, d2->qid.path, d1->qid.vers, d2->qid.vers, d1->qid.type, d2->qid.type);
606 print("warning: image does not match text for pid %d\n", pid);
608 free(d1);
609 free(d2);
612 void
613 catcher(void *junk, char *s)
615 USED(junk);
617 if(strstr(s, "interrupt")) {
618 gotint = 1;
619 noted(NCONT);
621 if(strstr(s, "child"))
622 noted(NCONT);
623 fprint(2, "note: %s\n", s);
624 noted(NDFLT);
627 char*
628 system(void)
630 char *cpu, *p, *q;
631 static char kernel[128];
633 cpu = getenv("cputype");
634 if(cpu == 0) {
635 cpu = "mips";
636 print("$cputype not set; assuming %s\n", cpu);
638 p = getenv("terminal");
639 if(p == 0 || (p=strchr(p, ' ')) == 0 || p[1] == ' ' || p[1] == 0) {
640 p = "9power";
641 print("missing or bad $terminal; assuming %s\n", p);
643 else{
644 p++;
645 q = strchr(p, ' ');
646 if(q)
647 *q = 0;
648 sprint(kernel, "/%s/9%s", cpu, p);
650 return kernel;
653 int
654 isnumeric(char *s)
656 while(*s) {
657 if(*s < '0' || *s > '9')
658 return 0;
659 s++;
661 return 1;
664 int
665 xfmt(Fmt *f)
667 f->flags ^= FmtSharp;
668 return __ifmt(f);