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