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 /*
170 Bputc(bout, '\n');
171 exits(0);
172 */
175 static int
176 attachfiles(int argc, char **argv)
178 int fd;
179 volatile int pid;
180 char *s;
181 int i, omode;
182 Fhdr *hdr;
183 Lsym *l;
184 Value *v;
186 pid = 0;
187 interactive = 0;
188 if(setjmp(err))
189 return -1;
191 /*
192 * Unix and Plan 9 differ on what the right order of pid, text, and core is.
193 * I never remember anyway. Let's just accept them in any order.
194 */
195 omode = wtflag ? ORDWR : OREAD;
196 for(i=0; i<argc; i++){
197 if(isnumeric(argv[i])){
198 if(pid){
199 fprint(2, "already have pid %d; ignoring pid %d\n", pid, argv[i]);
200 continue;
202 if(corhdr){
203 fprint(2, "already have core %s; ignoring pid %d\n", corfil, pid);
204 continue;
206 pid = atoi(argv[i]);
207 continue;
209 if((hdr = crackhdr(argv[i], omode)) == nil){
210 fprint(2, "crackhdr %s: %r\n", argv[i]);
211 if(argc == 1 && (fd = open(argv[i], omode)) > 0){
212 fprint(2, "loading %s direct mapped\n", argv[i]);
213 symmap = dumbmap(fd);
214 cormap = dumbmap(fd);
215 symfil = argv[i];
216 corfil = argv[i];
217 goto Run;
219 continue;
221 fprint(2, "%s: %s %s %s\n", argv[i], hdr->aname, hdr->mname, hdr->fname);
222 if(hdr->ftype == FCORE){
223 if(pid){
224 fprint(2, "already have pid %d; ignoring core %s\n", pid, argv[i]);
225 uncrackhdr(hdr);
226 continue;
228 if(corhdr){
229 fprint(2, "already have core %s; ignoring core %s\n", corfil, argv[i]);
230 uncrackhdr(hdr);
231 continue;
233 corhdr = hdr;
234 corfil = argv[i];
235 }else{
236 if(symhdr){
237 fprint(2, "already have text %s; ignoring text %s\n", symfil, argv[i]);
238 uncrackhdr(hdr);
239 continue;
241 symhdr = hdr;
242 symfil = argv[i];
246 if(symhdr==nil){
247 symfil = "a.out";
248 if(pid){
249 if((s = proctextfile(pid)) != nil){
250 fprint(2, "pid %d: text %s\n", pid, s);
251 symfil = s;
254 /* XXX pull command from core */
256 if((symhdr = crackhdr(symfil, omode)) == nil){
257 fprint(2, "crackhdr %s: %r\n", symfil);
258 symfil = nil;
262 if(symhdr)
263 symopen(symhdr);
265 if(!mach)
266 mach = machcpu;
268 /*
269 * Set up maps.
270 */
271 symmap = allocmap();
272 cormap = allocmap();
273 if(symmap == nil || cormap == nil)
274 sysfatal("allocating maps: %r");
276 if(symhdr){
277 if(mapfile(symhdr, 0, symmap, nil) < 0)
278 fprint(2, "mapping %s: %r\n", symfil);
279 mapfile(symhdr, 0, cormap, nil);
282 Run:
283 l = mkvar("objtype");
284 v = l->v;
285 v->store.fmt = 's';
286 v->set = 1;
287 v->store.u.string = strnode(mach->name);
288 v->type = TSTRING;
290 l = mkvar("textfile");
291 v = l->v;
292 v->store.fmt = 's';
293 v->set = 1;
294 v->store.u.string = strnode(symfil ? symfil : "");
295 v->type = TSTRING;
297 l = mkvar("systype");
298 v = l->v;
299 v->store.fmt = 's';
300 v->set = 1;
301 v->store.u.string = strnode(symhdr ? symhdr->aname : "");
302 v->type = TSTRING;
304 l = mkvar("corefile");
305 v = l->v;
306 v->store.fmt = 's';
307 v->set = 1;
308 v->store.u.string = strnode(corfil ? corfil : "");
309 v->type = TSTRING;
311 if(pid)
312 sproc(pid);
313 if(corhdr)
314 setcore(corhdr);
315 varreg();
316 return 0;
319 void
320 setcore(Fhdr *hdr)
322 unmapproc(cormap);
323 unmapfile(corhdr, cormap);
324 free(correg);
325 correg = nil;
327 if(hdr == nil)
328 error("no core");
329 if(mapfile(hdr, 0, cormap, &correg) < 0)
330 error("mapfile %s: %r", hdr->filename);
331 corhdr = hdr;
332 corfil = hdr->filename;
335 void
336 die(void)
338 Lsym *s;
339 List *f;
341 Bprint(bout, "\n");
343 s = look("proclist");
344 if(s && s->v->type == TLIST) {
345 for(f = s->v->store.u.l; f; f = f->next){
346 detachproc((int)f->store.u.ival);
347 Bprint(bout, "/bin/kill -9 %d\n", (int)f->store.u.ival);
350 exits(0);
353 void
354 userinit(void)
356 Lsym *l;
357 Node *n;
358 char buf[128], *p;
360 sprint(buf, "#9/acid/%s", mach->name);
361 loadmodule(unsharp(buf));
362 p = getenv("HOME");
363 if(p != 0) {
364 sprint(buf, "%s/lib/acid", p);
365 silent = 1;
366 loadmodule(buf);
369 interactive = 0;
370 if(setjmp(err)) {
371 unwind();
372 return;
374 l = look("acidinit");
375 if(l && l->proc) {
376 n = an(ONAME, ZN, ZN);
377 n->sym = l;
378 n = an(OCALL, n, ZN);
379 execute(n);
383 void
384 loadmodule(char *s)
386 interactive = 0;
387 if(setjmp(err)) {
388 unwind();
389 return;
391 pushfile(s);
392 silent = 0;
393 yyparse();
394 popio();
395 return;
398 Node*
399 an(int op, Node *l, Node *r)
401 Node *n;
403 n = gmalloc(sizeof(Node));
404 memset(n, 0, sizeof(Node));
405 n->gc.gclink = gcl;
406 gcl = (Gc*)n;
407 n->op = op;
408 n->left = l;
409 n->right = r;
410 return n;
413 List*
414 al(int t)
416 List *l;
418 l = gmalloc(sizeof(List));
419 memset(l, 0, sizeof(List));
420 l->type = t;
421 l->gc.gclink = gcl;
422 gcl = (Gc*)l;
423 return l;
426 Node*
427 con(int v)
429 Node *n;
431 n = an(OCONST, ZN, ZN);
432 n->store.u.ival = v;
433 n->store.fmt = 'X';
434 n->type = TINT;
435 return n;
438 void
439 fatal(char *fmt, ...)
441 char buf[128];
442 va_list arg;
444 va_start(arg, fmt);
445 vseprint(buf, buf+sizeof(buf), fmt, arg);
446 va_end(arg);
447 fprint(2, "%s: %Z (fatal problem) %s\n", argv0, buf);
448 exits(buf);
451 void
452 yyerror(char *fmt, ...)
454 char buf[128];
455 va_list arg;
457 if(strcmp(fmt, "syntax error") == 0) {
458 yyerror("syntax error, near symbol '%s'", symbol);
459 return;
461 va_start(arg, fmt);
462 vseprint(buf, buf+sizeof(buf), fmt, arg);
463 va_end(arg);
464 print("%Z: %s\n", buf);
467 void
468 marktree(Node *n)
471 if(n == 0)
472 return;
474 marktree(n->left);
475 marktree(n->right);
477 n->gc.gcmark = 1;
478 if(n->op != OCONST)
479 return;
481 switch(n->type) {
482 case TSTRING:
483 n->store.u.string->gc.gcmark = 1;
484 break;
485 case TLIST:
486 marklist(n->store.u.l);
487 break;
488 case TCODE:
489 marktree(n->store.u.cc);
490 break;
494 void
495 marklist(List *l)
497 while(l) {
498 l->gc.gcmark = 1;
499 switch(l->type) {
500 case TSTRING:
501 l->store.u.string->gc.gcmark = 1;
502 break;
503 case TLIST:
504 marklist(l->store.u.l);
505 break;
506 case TCODE:
507 marktree(l->store.u.cc);
508 break;
510 l = l->next;
514 void
515 gc(void)
517 int i;
518 Lsym *f;
519 Value *v;
520 Gc *m, **p, *next;
522 if(dogc < Mempergc)
523 return;
524 dogc = 0;
526 /* Mark */
527 for(m = gcl; m; m = m->gclink)
528 m->gcmark = 0;
530 /* Scan */
531 for(i = 0; i < Hashsize; i++) {
532 for(f = hash[i]; f; f = f->hash) {
533 marktree(f->proc);
534 if(f->lexval != Tid)
535 continue;
536 for(v = f->v; v; v = v->pop) {
537 switch(v->type) {
538 case TSTRING:
539 v->store.u.string->gc.gcmark = 1;
540 break;
541 case TLIST:
542 marklist(v->store.u.l);
543 break;
544 case TCODE:
545 marktree(v->store.u.cc);
546 break;
552 /* Free */
553 p = &gcl;
554 for(m = gcl; m; m = next) {
555 next = m->gclink;
556 if(m->gcmark == 0) {
557 *p = next;
558 free(m); /* Sleazy reliance on my malloc */
560 else
561 p = &m->gclink;
565 void*
566 gmalloc(long l)
568 void *p;
570 dogc += l;
571 p = malloc(l);
572 if(p == 0)
573 fatal("out of memory");
574 return p;
577 void
578 checkqid(int f1, int pid)
580 int fd;
581 Dir *d1, *d2;
582 char buf[128];
584 if(kernel)
585 return;
587 d1 = dirfstat(f1);
588 if(d1 == nil){
589 print("checkqid: (qid not checked) dirfstat: %r\n");
590 return;
593 sprint(buf, "/proc/%d/text", pid);
594 fd = open(buf, OREAD);
595 if(fd < 0 || (d2 = dirfstat(fd)) == nil){
596 print("checkqid: (qid not checked) dirstat %s: %r\n", buf);
597 free(d1);
598 if(fd >= 0)
599 close(fd);
600 return;
603 close(fd);
605 if(d1->qid.path != d2->qid.path || d1->qid.vers != d2->qid.vers || d1->qid.type != d2->qid.type){
606 print("path %llux %llux vers %lud %lud type %d %d\n",
607 d1->qid.path, d2->qid.path, d1->qid.vers, d2->qid.vers, d1->qid.type, d2->qid.type);
608 print("warning: image does not match text for pid %d\n", pid);
610 free(d1);
611 free(d2);
614 void
615 catcher(void *junk, char *s)
617 USED(junk);
619 if(strstr(s, "interrupt")) {
620 gotint = 1;
621 noted(NCONT);
623 if(strstr(s, "child"))
624 noted(NCONT);
625 fprint(2, "note: %s\n", s);
626 noted(NDFLT);
629 char*
630 system(void)
632 char *cpu, *p, *q;
633 static char kernel[128];
635 cpu = getenv("cputype");
636 if(cpu == 0) {
637 cpu = "mips";
638 print("$cputype not set; assuming %s\n", cpu);
640 p = getenv("terminal");
641 if(p == 0 || (p=strchr(p, ' ')) == 0 || p[1] == ' ' || p[1] == 0) {
642 p = "9power";
643 print("missing or bad $terminal; assuming %s\n", p);
645 else{
646 p++;
647 q = strchr(p, ' ');
648 if(q)
649 *q = 0;
650 sprint(kernel, "/%s/9%s", cpu, p);
652 return kernel;
655 int
656 isnumeric(char *s)
658 while(*s) {
659 if(*s < '0' || *s > '9')
660 return 0;
661 s++;
663 return 1;
666 int
667 xfmt(Fmt *f)
669 f->flags ^= FmtSharp;
670 return __ifmt(f);