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
usage(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*
dumbmap(int fd)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
main(int argc,char * argv[])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
setstring(char * var,char * s)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
attachfiles(int argc,char ** argv)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
setcore(Fhdr * hdr)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
die(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
userinit(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
loadmodule(char * s)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*
an(int op,Node * l,Node * r)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*
al(int t)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*
con(s64int v)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
fatal(char * fmt,...)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
yyerror(char * fmt,...)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
marktree(Node * n)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
marklist(List * l)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
gc(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*
gmalloc(long l)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
checkqid(int f1,int pid)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
catcher(void * junk,char * s)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*
system(void)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
isnumeric(char * s)600 isnumeric(char *s)
601 {
602 	while(*s) {
603 		if(*s < '0' || *s > '9')
604 			return 0;
605 		s++;
606 	}
607 	return 1;
608 }
609