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