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