xref: /plan9/sys/src/cmd/acid/main.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
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	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 int	isnumeric(char*);
20 void	die(void);
21 
22 void
23 usage(void)
24 {
25 	fprint(2, "usage: acid [-kqw] [-l library] [-m machine] [pid] [file]\n");
26 	exits("usage");
27 }
28 
29 void
30 main(int argc, char *argv[])
31 {
32 	Lsym *l;
33 	Node *n;
34 	char *s;
35 	int pid, i;
36 
37 	argv0 = argv[0];
38 	pid = 0;
39 	aout = "8.out";
40 	quiet = 1;
41 
42 	mtype = 0;
43 	ARGBEGIN{
44 	case 'm':
45 		mtype = ARGF();
46 		break;
47 	case 'w':
48 		wtflag = 1;
49 		break;
50 	case 'l':
51 		s = ARGF();
52 		if(s == 0)
53 			usage();
54 		lm[nlm++] = s;
55 		break;
56 	case 'k':
57 		kernel++;
58 		break;
59 	case 'q':
60 		quiet = 0;
61 		break;
62 	case 'r':
63 		pid = 1;
64 		remote++;
65 		kernel++;
66 		break;
67 	default:
68 		usage();
69 	}ARGEND
70 
71 	if(argc > 0) {
72 		if(remote)
73 			aout = argv[0];
74 		else
75 		if(isnumeric(argv[0])) {
76 			pid = strtol(argv[0], 0, 0);
77 			snprint(prog, sizeof(prog), "/proc/%d/text", pid);
78 			aout = prog;
79 			if(argc > 1)
80 				aout = argv[1];
81 			else if(kernel)
82 				aout = system();
83 		}
84 		else {
85 			if(kernel) {
86 				fprint(2, "acid: -k requires a pid\n");
87 				usage();
88 			}
89 			aout = argv[0];
90 		}
91 	} else
92 	if(remote)
93 		aout = "/mips/9ch";
94 
95 	fmtinstall('x', xfmt);
96 	fmtinstall('L', Lfmt);
97 	Binit(&bioout, 1, OWRITE);
98 	bout = &bioout;
99 
100 	kinit();
101 	initialising = 1;
102 	pushfile(0);
103 	loadvars();
104 	installbuiltin();
105 
106 	if(mtype && machbyname(mtype) == 0)
107 		print("unknown machine %s", mtype);
108 
109 	if (attachfiles(aout, pid) < 0)
110 		varreg();		/* use default register set on error */
111 
112 	loadmodule("/sys/lib/acid/port");
113 	for(i = 0; i < nlm; i++) {
114 		if(access(lm[i], AREAD) >= 0)
115 			loadmodule(lm[i]);
116 		else {
117 			s = smprint("/sys/lib/acid/%s", lm[i]);
118 			loadmodule(s);
119 			free(s);
120 		}
121 	}
122 
123 	userinit();
124 	varsym();
125 
126 	l = look("acidmap");
127 	if(l && l->proc) {
128 		n = an(ONAME, ZN, ZN);
129 		n->sym = l;
130 		n = an(OCALL, n, ZN);
131 		execute(n);
132 	}
133 
134 	interactive = 1;
135 	initialising = 0;
136 	line = 1;
137 
138 	notify(catcher);
139 
140 	for(;;) {
141 		if(setjmp(err)) {
142 			Binit(&bioout, 1, OWRITE);
143 			unwind();
144 		}
145 		stacked = 0;
146 
147 		Bprint(bout, "acid: ");
148 
149 		if(yyparse() != 1)
150 			die();
151 		restartio();
152 
153 		unwind();
154 	}
155 	/* not reached */
156 }
157 
158 static int
159 attachfiles(char *aout, int pid)
160 {
161 	interactive = 0;
162 	if(setjmp(err))
163 		return -1;
164 
165 	if(aout) {				/* executable given */
166 		if(wtflag)
167 			text = open(aout, ORDWR);
168 		else
169 			text = open(aout, OREAD);
170 
171 		if(text < 0)
172 			error("%s: can't open %s: %r\n", argv0, aout);
173 		readtext(aout);
174 	}
175 	if(pid)					/* pid given */
176 		sproc(pid);
177 	return 0;
178 }
179 
180 void
181 die(void)
182 {
183 	Lsym *s;
184 	List *f;
185 
186 	Bprint(bout, "\n");
187 
188 	s = look("proclist");
189 	if(s && s->v->type == TLIST) {
190 		for(f = s->v->l; f; f = f->next)
191 			Bprint(bout, "echo kill > /proc/%d/ctl\n", (int)f->ival);
192 	}
193 	exits(0);
194 }
195 
196 void
197 userinit(void)
198 {
199 	Lsym *l;
200 	Node *n;
201 	char *buf, *p;
202 
203 	buf = smprint("/sys/lib/acid/%s", mach->name);
204 	loadmodule(buf);
205 	free(buf);
206 	p = getenv("home");
207 	if(p != 0) {
208 		buf = smprint("%s/lib/acid", p);
209 		silent = 1;
210 		loadmodule(buf);
211 		free(buf);
212 	}
213 
214 	interactive = 0;
215 	if(setjmp(err)) {
216 		unwind();
217 		return;
218 	}
219 	l = look("acidinit");
220 	if(l && l->proc) {
221 		n = an(ONAME, ZN, ZN);
222 		n->sym = l;
223 		n = an(OCALL, n, ZN);
224 		execute(n);
225 	}
226 }
227 
228 void
229 loadmodule(char *s)
230 {
231 	interactive = 0;
232 	if(setjmp(err)) {
233 		unwind();
234 		return;
235 	}
236 	pushfile(s);
237 	silent = 0;
238 	yyparse();
239 	popio();
240 	return;
241 }
242 
243 void
244 readtext(char *s)
245 {
246 	Dir *d;
247 	Lsym *l;
248 	Value *v;
249 	uvlong length;
250 	Symbol sym;
251 	extern Machdata mipsmach;
252 
253 	if(mtype != 0){
254 		symmap = newmap(0, 1);
255 		if(symmap == 0)
256 			print("%s: (error) loadmap: cannot make symbol map\n", argv0);
257 		length = 1<<24;
258 		d = dirfstat(text);
259 		if(d != nil){
260 			length = d->length;
261 			free(d);
262 		}
263 		setmap(symmap, text, 0, length, 0, "binary");
264 		return;
265 	}
266 
267 	machdata = &mipsmach;
268 
269 	if(!crackhdr(text, &fhdr)) {
270 		print("can't decode file header\n");
271 		return;
272 	}
273 
274 	symmap = loadmap(0, text, &fhdr);
275 	if(symmap == 0)
276 		print("%s: (error) loadmap: cannot make symbol map\n", argv0);
277 
278 	if(syminit(text, &fhdr) < 0) {
279 		print("%s: (error) syminit: %r\n", argv0);
280 		return;
281 	}
282 	print("%s:%s\n\n", s, fhdr.name);
283 
284 	if(mach->sbreg && lookup(0, mach->sbreg, &sym)) {
285 		mach->sb = sym.value;
286 		l = enter("SB", Tid);
287 		l->v->fmt = 'X';
288 		l->v->ival = mach->sb;
289 		l->v->type = TINT;
290 		l->v->set = 1;
291 	}
292 
293 	l = mkvar("objtype");
294 	v = l->v;
295 	v->fmt = 's';
296 	v->set = 1;
297 	v->string = strnode(mach->name);
298 	v->type = TSTRING;
299 
300 	l = mkvar("textfile");
301 	v = l->v;
302 	v->fmt = 's';
303 	v->set = 1;
304 	v->string = strnode(s);
305 	v->type = TSTRING;
306 
307 	machbytype(fhdr.type);
308 	varreg();
309 }
310 
311 Node*
312 an(int op, Node *l, Node *r)
313 {
314 	Node *n;
315 
316 	n = gmalloc(sizeof(Node));
317 	memset(n, 0, sizeof(Node));
318 	n->gclink = gcl;
319 	gcl = n;
320 	n->op = op;
321 	n->left = l;
322 	n->right = r;
323 	return n;
324 }
325 
326 List*
327 al(int t)
328 {
329 	List *l;
330 
331 	l = gmalloc(sizeof(List));
332 	memset(l, 0, sizeof(List));
333 	l->type = t;
334 	l->gclink = gcl;
335 	gcl = l;
336 	return l;
337 }
338 
339 Node*
340 con(vlong v)
341 {
342 	Node *n;
343 
344 	n = an(OCONST, ZN, ZN);
345 	n->ival = v;
346 	n->fmt = 'W';
347 	n->type = TINT;
348 	return n;
349 }
350 
351 void
352 fatal(char *fmt, ...)
353 {
354 	char buf[128];
355 	va_list arg;
356 
357 	va_start(arg, fmt);
358 	vseprint(buf, buf+sizeof(buf), fmt, arg);
359 	va_end(arg);
360 	fprint(2, "%s: %L (fatal problem) %s\n", argv0, buf);
361 	exits(buf);
362 }
363 
364 void
365 yyerror(char *fmt, ...)
366 {
367 	char buf[128];
368 	va_list arg;
369 
370 	if(strcmp(fmt, "syntax error") == 0) {
371 		yyerror("syntax error, near symbol '%s'", symbol);
372 		return;
373 	}
374 	va_start(arg, fmt);
375 	vseprint(buf, buf+sizeof(buf), fmt, arg);
376 	va_end(arg);
377 	print("%L: %s\n", buf);
378 }
379 
380 void
381 marktree(Node *n)
382 {
383 
384 	if(n == 0)
385 		return;
386 
387 	marktree(n->left);
388 	marktree(n->right);
389 
390 	n->gcmark = 1;
391 	if(n->op != OCONST)
392 		return;
393 
394 	switch(n->type) {
395 	case TSTRING:
396 		n->string->gcmark = 1;
397 		break;
398 	case TLIST:
399 		marklist(n->l);
400 		break;
401 	case TCODE:
402 		marktree(n->cc);
403 		break;
404 	}
405 }
406 
407 void
408 marklist(List *l)
409 {
410 	while(l) {
411 		l->gcmark = 1;
412 		switch(l->type) {
413 		case TSTRING:
414 			l->string->gcmark = 1;
415 			break;
416 		case TLIST:
417 			marklist(l->l);
418 			break;
419 		case TCODE:
420 			marktree(l->cc);
421 			break;
422 		}
423 		l = l->next;
424 	}
425 }
426 
427 void
428 gc(void)
429 {
430 	int i;
431 	Lsym *f;
432 	Value *v;
433 	Gc *m, **p, *next;
434 
435 	if(dogc < Mempergc)
436 		return;
437 	dogc = 0;
438 
439 	/* Mark */
440 	for(m = gcl; m; m = m->gclink)
441 		m->gcmark = 0;
442 
443 	/* Scan */
444 	for(i = 0; i < Hashsize; i++) {
445 		for(f = hash[i]; f; f = f->hash) {
446 			marktree(f->proc);
447 			if(f->lexval != Tid)
448 				continue;
449 			for(v = f->v; v; v = v->pop) {
450 				switch(v->type) {
451 				case TSTRING:
452 					v->string->gcmark = 1;
453 					break;
454 				case TLIST:
455 					marklist(v->l);
456 					break;
457 				case TCODE:
458 					marktree(v->cc);
459 					break;
460 				}
461 			}
462 		}
463 	}
464 
465 	/* Free */
466 	p = &gcl;
467 	for(m = gcl; m; m = next) {
468 		next = m->gclink;
469 		if(m->gcmark == 0) {
470 			*p = next;
471 			free(m);	/* Sleazy reliance on my malloc */
472 		}
473 		else
474 			p = &m->gclink;
475 	}
476 }
477 
478 void*
479 gmalloc(long l)
480 {
481 	void *p;
482 
483 	dogc += l;
484 	p = malloc(l);
485 	if(p == 0)
486 		fatal("out of memory");
487 	return p;
488 }
489 
490 void
491 checkqid(int f1, int pid)
492 {
493 	int fd;
494 	Dir *d1, *d2;
495 	char buf[128];
496 
497 	if(kernel)
498 		return;
499 
500 	d1 = dirfstat(f1);
501 	if(d1 == nil){
502 		print("checkqid: (qid not checked) dirfstat: %r\n");
503 		return;
504 	}
505 
506 	snprint(buf, sizeof(buf), "/proc/%d/text", pid);
507 	fd = open(buf, OREAD);
508 	if(fd < 0 || (d2 = dirfstat(fd)) == nil){
509 		print("checkqid: (qid not checked) dirstat %s: %r\n", buf);
510 		free(d1);
511 		if(fd >= 0)
512 			close(fd);
513 		return;
514 	}
515 
516 	close(fd);
517 
518 	if(d1->qid.path != d2->qid.path || d1->qid.vers != d2->qid.vers || d1->qid.type != d2->qid.type){
519 		print("path %llux %llux vers %lud %lud type %d %d\n",
520 			d1->qid.path, d2->qid.path, d1->qid.vers, d2->qid.vers, d1->qid.type, d2->qid.type);
521 		print("warning: image does not match text for pid %d\n", pid);
522 	}
523 	free(d1);
524 	free(d2);
525 }
526 
527 void
528 catcher(void *junk, char *s)
529 {
530 	USED(junk);
531 
532 	if(strstr(s, "interrupt")) {
533 		gotint = 1;
534 		noted(NCONT);
535 	}
536 	noted(NDFLT);
537 }
538 
539 char*
540 system(void)
541 {
542 	char *cpu, *p, *q;
543 	static char *kernel;
544 
545 	cpu = getenv("cputype");
546 	if(cpu == 0) {
547 		cpu = "mips";
548 		print("$cputype not set; assuming %s\n", cpu);
549 	}
550 	p = getenv("terminal");
551 	if(p == 0 || (p=strchr(p, ' ')) == 0 || p[1] == ' ' || p[1] == 0) {
552 		p = "ch";
553 		print("missing or bad $terminal; assuming %s\n", p);
554 	}
555 	else{
556 		p++;
557 		q = strchr(p, ' ');
558 		if(q)
559 			*q = 0;
560 	}
561 
562 	if(kernel != nil)
563 		free(kernel);
564 	kernel = smprint("/%s/9%s", cpu, p);
565 
566 	return kernel;
567 }
568 
569 int
570 isnumeric(char *s)
571 {
572 	while(*s) {
573 		if(*s < '0' || *s > '9')
574 			return 0;
575 		s++;
576 	}
577 	return 1;
578 }
579 
580 int
581 xfmt(Fmt *f)
582 {
583 	f->flags ^= FmtSharp;
584 	return _ifmt(f);
585 }
586