xref: /inferno-os/utils/acid/main.c (revision 4eb166cf184c1f102fb79e31b1465ea3e2021c39)
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