Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include <ctype.h>
5 #include <mach.h>
6 #include <regexp.h>
7 #define Extern extern
8 #include "acid.h"
9 #include "y.tab.h"
11 void cvtatof(Node*, Node*);
12 void cvtatoi(Node*, Node*);
13 void cvtitoa(Node*, Node*);
14 void bprint(Node*, Node*);
15 void funcbound(Node*, Node*);
16 void printto(Node*, Node*);
17 void getfile(Node*, Node*);
18 void fmt(Node*, Node*);
19 void pcfile(Node*, Node*);
20 void pcline(Node*, Node*);
21 void setproc(Node*, Node*);
22 void strace(Node*, Node*);
23 void follow(Node*, Node*);
24 void reason(Node*, Node*);
25 void newproc(Node*, Node*);
26 void startstop(Node*, Node*);
27 void match(Node*, Node*);
28 void status(Node*, Node*);
29 void xkill(Node*,Node*);
30 void waitstop(Node*, Node*);
31 void sysstop(Node*, Node*);
32 void stop(Node*, Node*);
33 void start(Node*, Node*);
34 void filepc(Node*, Node*);
35 void doerror(Node*, Node*);
36 void rc(Node*, Node*);
37 void doaccess(Node*, Node*);
38 void map(Node*, Node*);
39 void readfile(Node*, Node*);
40 void interpret(Node*, Node*);
41 void include(Node*, Node*);
42 void includepipe(Node*, Node*);
43 void regexp(Node*, Node*);
44 void textfile(Node*, Node*);
45 void deltextfile(Node*, Node*);
46 void stringn(Node*, Node*);
47 void xregister(Node*, Node*);
48 void refconst(Node*, Node*);
49 void dolook(Node*, Node*);
51 typedef struct Btab Btab;
52 struct Btab
53 {
54 char *name;
55 void (*fn)(Node*, Node*);
56 } tab[] =
57 {
58 "access", doaccess,
59 "atof", cvtatof,
60 "atoi", cvtatoi,
61 "deltextfile", deltextfile,
62 "error", doerror,
63 "file", getfile,
64 "filepc", filepc,
65 "fnbound", funcbound,
66 "fmt", fmt,
67 "follow", follow,
68 "include", include,
69 "includepipe", includepipe,
70 "interpret", interpret,
71 "itoa", cvtitoa,
72 "kill", xkill,
73 "map", map,
74 "match", match,
75 "newproc", newproc,
76 "pcfile", pcfile,
77 "pcline", pcline,
78 "print", bprint,
79 "printto", printto,
80 "rc", rc,
81 "readfile", readfile,
82 "reason", reason,
83 "refconst", refconst,
84 "regexp", regexp,
85 "register", xregister,
86 "setproc", setproc,
87 "start", start,
88 "startstop", startstop,
89 "status", status,
90 "stop", stop,
91 "strace", strace,
92 "stringn", stringn,
93 "sysstop", sysstop,
94 "textfile", textfile,
95 "var", dolook,
96 "waitstop", waitstop,
97 0
98 };
100 void
101 mkprint(Lsym *s)
103 prnt = malloc(sizeof(Node));
104 memset(prnt, 0, sizeof(Node));
105 prnt->op = OCALL;
106 prnt->left = malloc(sizeof(Node));
107 memset(prnt->left, 0, sizeof(Node));
108 prnt->left->sym = s;
111 void
112 installbuiltin(void)
114 Btab *b;
115 Lsym *s;
117 b = tab;
118 while(b->name) {
119 s = look(b->name);
120 if(s == 0)
121 s = enter(b->name, Tid);
123 s->builtin = b->fn;
124 if(b->fn == bprint)
125 mkprint(s);
126 b++;
130 void
131 match(Node *r, Node *args)
133 int i;
134 List *f;
135 Node *av[Maxarg];
136 Node resi, resl;
138 na = 0;
139 flatten(av, args);
140 if(na != 2)
141 error("match(obj, list): arg count");
143 expr(av[1], &resl);
144 if(resl.type != TLIST)
145 error("match(obj, list): need list");
146 expr(av[0], &resi);
148 r->op = OCONST;
149 r->type = TINT;
150 r->store.fmt = 'D';
151 r->store.u.ival = -1;
153 i = 0;
154 for(f = resl.store.u.l; f; f = f->next) {
155 if(resi.type == f->type) {
156 switch(resi.type) {
157 case TINT:
158 if(resi.store.u.ival == f->store.u.ival) {
159 r->store.u.ival = i;
160 return;
162 break;
163 case TFLOAT:
164 if(resi.store.u.fval == f->store.u.fval) {
165 r->store.u.ival = i;
166 return;
168 break;
169 case TSTRING:
170 if(scmp(resi.store.u.string, f->store.u.string)) {
171 r->store.u.ival = i;
172 return;
174 break;
175 case TLIST:
176 error("match(obj, list): not defined for list");
179 i++;
183 void
184 newproc(Node *r, Node *args)
186 int i;
187 Node res;
188 char *p, *e;
189 char *argv[Maxarg], buf[Strsize];
191 i = 1;
192 argv[0] = symfil;
194 if(args) {
195 expr(args, &res);
196 if(res.type != TSTRING)
197 error("newproc(): arg not string");
198 if(res.store.u.string->len >= sizeof(buf))
199 error("newproc(): too many arguments");
200 memmove(buf, res.store.u.string->string, res.store.u.string->len);
201 buf[res.store.u.string->len] = '\0';
202 p = buf;
203 e = buf+res.store.u.string->len;
204 for(;;) {
205 while(p < e && (*p == '\t' || *p == ' '))
206 *p++ = '\0';
207 if(p >= e)
208 break;
209 argv[i++] = p;
210 if(i >= Maxarg)
211 error("newproc: too many arguments");
212 while(p < e && *p != '\t' && *p != ' ')
213 p++;
216 argv[i] = 0;
217 r->op = OCONST;
218 r->type = TINT;
219 r->store.fmt = 'D';
220 r->store.u.ival = nproc(argv);
223 void
224 startstop(Node *r, Node *args)
226 Node res;
228 USED(r);
229 if(args == 0)
230 error("startstop(pid): no pid");
231 expr(args, &res);
232 if(res.type != TINT)
233 error("startstop(pid): arg type");
235 msg(res.store.u.ival, "startstop");
236 notes(res.store.u.ival);
237 dostop(res.store.u.ival);
240 void
241 waitstop(Node *r, Node *args)
243 Node res;
245 USED(r);
246 if(args == 0)
247 error("waitstop(pid): no pid");
248 expr(args, &res);
249 if(res.type != TINT)
250 error("waitstop(pid): arg type");
252 Bflush(bout);
253 msg(res.store.u.ival, "waitstop");
254 notes(res.store.u.ival);
255 dostop(res.store.u.ival);
258 void
259 sysstop(Node *r, Node *args)
261 Node res;
263 USED(r);
264 if(args == 0)
265 error("waitstop(pid): no pid");
266 expr(args, &res);
267 if(res.type != TINT)
268 error("waitstop(pid): arg type");
270 Bflush(bout);
271 msg(res.store.u.ival, "sysstop");
272 notes(res.store.u.ival);
273 dostop(res.store.u.ival);
276 void
277 start(Node *r, Node *args)
279 Node res;
281 USED(r);
282 if(args == 0)
283 error("start(pid): no pid");
284 expr(args, &res);
285 if(res.type != TINT)
286 error("start(pid): arg type");
288 msg(res.store.u.ival, "start");
291 void
292 stop(Node *r, Node *args)
294 Node res;
296 USED(r);
297 if(args == 0)
298 error("stop(pid): no pid");
299 expr(args, &res);
300 if(res.type != TINT)
301 error("stop(pid): arg type");
303 Bflush(bout);
304 msg(res.store.u.ival, "stop");
305 notes(res.store.u.ival);
306 dostop(res.store.u.ival);
309 void
310 xkill(Node *r, Node *args)
312 Node res;
314 USED(r);
315 if(args == 0)
316 error("kill(pid): no pid");
317 expr(args, &res);
318 if(res.type != TINT)
319 error("kill(pid): arg type");
321 msg(res.store.u.ival, "kill");
322 deinstall(res.store.u.ival);
325 void
326 xregister(Node *r, Node *args)
328 Regdesc *rp;
329 Node res;
331 if(args == 0)
332 error("register(string): arg count");
333 expr(args, &res);
334 if(res.type != TSTRING)
335 error("register(string): arg type");
337 if((rp = regdesc(res.store.u.string->string)) == nil)
338 error("no such register");
340 r->op = OCONST;
341 r->type = TREG;
342 r->store.fmt = rp->format;
343 r->store.u.reg = rp->name;
346 void
347 refconst(Node *r, Node *args)
349 Node *n;
351 if(args == 0)
352 error("refconst(expr): arg count");
354 n = an(OCONST, ZN, ZN);
355 expr(args, n);
357 r->op = OCONST;
358 r->type = TCON;
359 r->store.u.con = n;
362 void
363 dolook(Node *r, Node *args)
365 Node res;
366 Lsym *l;
368 if(args == 0)
369 error("var(string): arg count");
370 expr(args, &res);
371 if(res.type != TSTRING)
372 error("var(string): arg type");
374 r->op = OCONST;
375 if((l = look(res.store.u.string->string)) == nil || l->v->set == 0){
376 r->type = TLIST;
377 r->store.u.l = nil;
378 }else{
379 r->type = l->v->type;
380 r->store = l->v->store;
384 void
385 status(Node *r, Node *args)
387 Node res;
388 char *p;
390 USED(r);
391 if(args == 0)
392 error("status(pid): no pid");
393 expr(args, &res);
394 if(res.type != TINT)
395 error("status(pid): arg type");
397 p = getstatus(res.store.u.ival);
398 r->store.u.string = strnode(p);
399 r->op = OCONST;
400 r->store.fmt = 's';
401 r->type = TSTRING;
404 void
405 reason(Node *r, Node *args)
407 Node res;
409 if(args == 0)
410 error("reason(cause): no cause");
411 expr(args, &res);
412 if(res.type != TINT)
413 error("reason(cause): arg type");
415 r->op = OCONST;
416 r->type = TSTRING;
417 r->store.fmt = 's';
418 r->store.u.string = strnode((*mach->exc)(cormap, acidregs));
421 void
422 follow(Node *r, Node *args)
424 int n, i;
425 Node res;
426 ulong f[10];
427 List **tail, *l;
429 if(args == 0)
430 error("follow(addr): no addr");
431 expr(args, &res);
432 if(res.type != TINT)
433 error("follow(addr): arg type");
435 n = (*mach->foll)(cormap, acidregs, res.store.u.ival, f);
436 if (n < 0)
437 error("follow(addr): %r");
438 tail = &r->store.u.l;
439 for(i = 0; i < n; i++) {
440 l = al(TINT);
441 l->store.u.ival = f[i];
442 l->store.fmt = 'X';
443 *tail = l;
444 tail = &l->next;
448 void
449 funcbound(Node *r, Node *args)
451 int n;
452 Node res;
453 ulong bounds[2];
454 List *l;
456 if(args == 0)
457 error("fnbound(addr): no addr");
458 expr(args, &res);
459 if(res.type != TINT)
460 error("fnbound(addr): arg type");
462 n = fnbound(res.store.u.ival, bounds);
463 if (n != 0) {
464 r->store.u.l = al(TINT);
465 l = r->store.u.l;
466 l->store.u.ival = bounds[0];
467 l->store.fmt = 'X';
468 l->next = al(TINT);
469 l = l->next;
470 l->store.u.ival = bounds[1];
471 l->store.fmt = 'X';
475 void
476 setproc(Node *r, Node *args)
478 Node res;
480 USED(r);
481 if(args == 0)
482 error("setproc(pid): no pid");
483 expr(args, &res);
484 if(res.type != TINT)
485 error("setproc(pid): arg type");
487 sproc(res.store.u.ival);
490 void
491 filepc(Node *r, Node *args)
493 int i;
494 Node res;
495 char *p, c;
496 ulong v;
498 if(args == 0)
499 error("filepc(filename:line): arg count");
500 expr(args, &res);
501 if(res.type != TSTRING)
502 error("filepc(filename:line): arg type");
504 p = strchr(res.store.u.string->string, ':');
505 if(p == 0)
506 error("filepc(filename:line): bad arg format");
508 c = *p;
509 *p++ = '\0';
510 i = file2pc(res.store.u.string->string, atoi(p), &v);
511 p[-1] = c;
512 if(i < 0)
513 error("filepc(filename:line): can't find address");
515 r->op = OCONST;
516 r->type = TINT;
517 r->store.fmt = 'D';
518 r->store.u.ival = v;
521 void
522 interpret(Node *r, Node *args)
524 Node res;
525 int isave;
527 if(args == 0)
528 error("interpret(string): arg count");
529 expr(args, &res);
530 if(res.type != TSTRING)
531 error("interpret(string): arg type");
533 pushstr(&res);
535 isave = interactive;
536 interactive = 0;
537 r->store.u.ival = yyparse();
538 interactive = isave;
539 popio();
540 r->op = OCONST;
541 r->type = TINT;
542 r->store.fmt = 'D';
545 void
546 include(Node *r, Node *args)
548 char *file, *libfile;
549 static char buf[1024];
550 Node res;
551 int isave;
553 if(args == 0)
554 error("include(string): arg count");
555 expr(args, &res);
556 if(res.type != TSTRING)
557 error("include(string): arg type");
559 Bflush(bout);
561 libfile = nil;
562 file = res.store.u.string->string;
563 if(access(file, AREAD) < 0 && file[0] != '/'){
564 snprint(buf, sizeof buf, "#9/acid/%s", file);
565 libfile = unsharp(buf);
566 if(access(libfile, AREAD) >= 0){
567 strecpy(buf, buf+sizeof buf, libfile);
568 file = buf;
570 free(libfile);
573 pushfile(file);
574 isave = interactive;
575 interactive = 0;
576 r->store.u.ival = yyparse();
577 interactive = isave;
578 popio();
579 r->op = OCONST;
580 r->type = TINT;
581 r->store.fmt = 'D';
584 void
585 includepipe(Node *r, Node *args)
587 Node res;
588 int i, isave, pid, pip[2];
589 char *argv[4];
590 Waitmsg *w;
592 USED(r);
593 if(args == 0)
594 error("includepipe(string): arg count");
595 expr(args, &res);
596 if(res.type != TSTRING)
597 error("includepipe(string): arg type");
599 Bflush(bout);
601 argv[0] = "rc";
602 argv[1] = "-c";
603 argv[2] = res.store.u.string->string;
604 argv[3] = 0;
606 if(pipe(pip) < 0)
607 error("pipe: %r");
609 pid = fork();
610 switch(pid) {
611 case -1:
612 close(pip[0]);
613 close(pip[1]);
614 error("fork: %r");
615 case 0:
616 close(pip[0]);
617 close(0);
618 open("/dev/null", OREAD);
619 dup(pip[1], 1);
620 if(pip[1] > 1)
621 close(pip[1]);
622 for(i=3; i<100; i++)
623 close(i);
624 exec("rc", argv);
625 sysfatal("exec rc: %r");
628 close(pip[1]);
629 pushfd(pip[0]);
631 isave = interactive;
632 interactive = 0;
633 r->store.u.ival = yyparse();
634 interactive = isave;
635 popio();
637 r->op = OCONST;
638 r->type = TINT;
639 r->store.fmt = 'D';
641 w = waitfor(pid);
642 if(w->msg && w->msg[0])
643 error("includepipe(\"%s\"): %s", argv[2], w->msg); /* leaks w */
644 free(w);
647 void
648 rc(Node *r, Node *args)
650 Node res;
651 int pid;
652 char *p, *q, *argv[4];
653 Waitmsg *w;
655 USED(r);
656 if(args == 0)
657 error("rc(string): arg count");
658 expr(args, &res);
659 if(res.type != TSTRING)
660 error("rc(string): arg type");
662 argv[0] = "rc";
663 argv[1] = "-c";
664 argv[2] = res.store.u.string->string;
665 argv[3] = 0;
667 pid = fork();
668 switch(pid) {
669 case -1:
670 error("fork %r");
671 case 0:
672 exec("rc", argv);
673 exits(0);
674 default:
675 w = waitfor(pid);
676 break;
678 p = w->msg;
679 q = strrchr(p, ':');
680 if (q)
681 p = q+1;
683 r->op = OCONST;
684 r->type = TSTRING;
685 r->store.u.string = strnode(p);
686 free(w);
687 r->store.fmt = 's';
690 void
691 doerror(Node *r, Node *args)
693 Node res;
695 USED(r);
696 if(args == 0)
697 error("error(string): arg count");
698 expr(args, &res);
699 if(res.type != TSTRING)
700 error("error(string): arg type");
702 error(res.store.u.string->string);
705 void
706 doaccess(Node *r, Node *args)
708 Node res;
710 if(args == 0)
711 error("access(filename): arg count");
712 expr(args, &res);
713 if(res.type != TSTRING)
714 error("access(filename): arg type");
716 r->op = OCONST;
717 r->type = TINT;
718 r->store.fmt = 'D';
719 r->store.u.ival = 0;
720 if(access(res.store.u.string->string, 4) == 0)
721 r->store.u.ival = 1;
724 void
725 readfile(Node *r, Node *args)
727 Node res;
728 int n, fd;
729 char *buf;
730 Dir *db;
732 if(args == 0)
733 error("readfile(filename): arg count");
734 expr(args, &res);
735 if(res.type != TSTRING)
736 error("readfile(filename): arg type");
738 fd = open(res.store.u.string->string, OREAD);
739 if(fd < 0)
740 return;
742 db = dirfstat(fd);
743 if(db == nil || db->length == 0)
744 n = 8192;
745 else
746 n = db->length;
747 free(db);
749 buf = malloc(n);
750 n = read(fd, buf, n);
752 if(n > 0) {
753 r->op = OCONST;
754 r->type = TSTRING;
755 r->store.u.string = strnodlen(buf, n);
756 r->store.fmt = 's';
758 free(buf);
759 close(fd);
762 void
763 getfile(Node *r, Node *args)
765 int n;
766 char *p;
767 Node res;
768 String *s;
769 Biobuf *bp;
770 List **l, *new;
772 if(args == 0)
773 error("file(filename): arg count");
774 expr(args, &res);
775 if(res.type != TSTRING)
776 error("file(filename): arg type");
778 r->op = OCONST;
779 r->type = TLIST;
780 r->store.u.l = 0;
782 p = res.store.u.string->string;
783 bp = Bopen(p, OREAD);
784 if(bp == 0)
785 return;
787 l = &r->store.u.l;
788 for(;;) {
789 p = Brdline(bp, '\n');
790 n = Blinelen(bp);
791 if(p == 0) {
792 if(n == 0)
793 break;
794 s = strnodlen(0, n);
795 Bread(bp, s->string, n);
797 else
798 s = strnodlen(p, n-1);
800 new = al(TSTRING);
801 new->store.u.string = s;
802 new->store.fmt = 's';
803 *l = new;
804 l = &new->next;
806 Bterm(bp);
809 void
810 cvtatof(Node *r, Node *args)
812 Node res;
814 if(args == 0)
815 error("atof(string): arg count");
816 expr(args, &res);
817 if(res.type != TSTRING)
818 error("atof(string): arg type");
820 r->op = OCONST;
821 r->type = TFLOAT;
822 r->store.u.fval = atof(res.store.u.string->string);
823 r->store.fmt = 'f';
826 void
827 cvtatoi(Node *r, Node *args)
829 Node res;
831 if(args == 0)
832 error("atoi(string): arg count");
833 expr(args, &res);
834 if(res.type != TSTRING)
835 error("atoi(string): arg type");
837 r->op = OCONST;
838 r->type = TINT;
839 r->store.u.ival = strtoul(res.store.u.string->string, 0, 0);
840 r->store.fmt = 'D';
843 void
844 cvtitoa(Node *r, Node *args)
846 Node res;
847 Node *av[Maxarg];
848 int ival;
849 char buf[128], *fmt;
851 if(args == 0)
852 err:
853 error("itoa(number [, printformat]): arg count");
854 na = 0;
855 flatten(av, args);
856 if(na == 0 || na > 2)
857 goto err;
858 expr(av[0], &res);
859 if(res.type != TINT)
860 error("itoa(integer): arg type");
861 ival = (int)res.store.u.ival;
862 fmt = "%d";
863 if(na == 2){
864 expr(av[1], &res);
865 if(res.type != TSTRING)
866 error("itoa(integer, string): arg type");
867 fmt = res.store.u.string->string;
870 sprint(buf, fmt, ival);
871 r->op = OCONST;
872 r->type = TSTRING;
873 r->store.u.string = strnode(buf);
874 r->store.fmt = 's';
877 List*
878 mapent(Map *m)
880 int i;
881 List *l, *n, **t, *h;
883 h = 0;
884 t = &h;
885 for(i = 0; i < m->nseg; i++) {
886 l = al(TSTRING);
887 n = al(TLIST);
888 n->store.u.l = l;
889 *t = n;
890 t = &n->next;
891 l->store.u.string = strnode(m->seg[i].name);
892 l->store.fmt = 's';
893 l->next = al(TSTRING);
894 l = l->next;
895 l->store.u.string = strnode(m->seg[i].file ? m->seg[i].file : "");
896 l->store.fmt = 's';
897 l->next = al(TINT);
898 l = l->next;
899 l->store.u.ival = m->seg[i].base;
900 l->store.fmt = 'X';
901 l->next = al(TINT);
902 l = l->next;
903 l->store.u.ival = m->seg[i].base + m->seg[i].size;
904 l->store.fmt = 'X';
905 l->next = al(TINT);
906 l = l->next;
907 l->store.u.ival = m->seg[i].offset;
908 l->store.fmt = 'X';
910 return h;
913 void
914 map(Node *r, Node *args)
916 int i;
917 Map *m;
918 List *l;
919 char *nam, *fil;
920 Node *av[Maxarg], res;
922 na = 0;
923 flatten(av, args);
925 if(na != 0) {
926 expr(av[0], &res);
927 if(res.type != TLIST)
928 error("map(list): map needs a list");
929 if(listlen(res.store.u.l) != 5)
930 error("map(list): list must have 5 entries");
932 l = res.store.u.l;
933 if(l->type != TSTRING)
934 error("map name must be a string");
935 nam = l->store.u.string->string;
936 l = l->next;
937 if(l->type != TSTRING)
938 error("map file must be a string");
939 fil = l->store.u.string->string;
940 m = symmap;
941 i = findseg(m, nam, fil);
942 if(i < 0) {
943 m = cormap;
944 i = findseg(m, nam, fil);
946 if(i < 0)
947 error("%s %s is not a map entry", nam, fil);
948 l = l->next;
949 if(l->type != TINT)
950 error("map entry not int");
951 m->seg[i].base = l->store.u.ival;
952 /*
953 if (strcmp(ent, "text") == 0)
954 textseg(l->store.u.ival, &fhdr);
955 */
956 l = l->next;
957 if(l->type != TINT)
958 error("map entry not int");
959 m->seg[i].size = l->store.u.ival - m->seg[i].base;
960 l = l->next;
961 if(l->type != TINT)
962 error("map entry not int");
963 m->seg[i].offset = l->store.u.ival;
966 r->type = TLIST;
967 r->store.u.l = 0;
968 if(symmap)
969 r->store.u.l = mapent(symmap);
970 if(cormap) {
971 if(r->store.u.l == 0)
972 r->store.u.l = mapent(cormap);
973 else {
974 for(l = r->store.u.l; l->next; l = l->next)
976 l->next = mapent(cormap);
981 void
982 flatten(Node **av, Node *n)
984 if(n == 0)
985 return;
987 switch(n->op) {
988 case OLIST:
989 flatten(av, n->left);
990 flatten(av, n->right);
991 break;
992 default:
993 av[na++] = n;
994 if(na >= Maxarg)
995 error("too many function arguments");
996 break;
1000 static struct
1002 char *name;
1003 ulong val;
1004 } sregs[Maxarg/2];
1005 static int nsregs;
1007 static int
1008 straceregrw(Regs *regs, char *name, ulong *val, int isr)
1010 int i;
1012 if(!isr){
1013 werrstr("saved registers cannot be written");
1014 return -1;
1016 for(i=0; i<nsregs; i++)
1017 if(strcmp(sregs[i].name, name) == 0){
1018 *val = sregs[i].val;
1019 return 0;
1021 return rget(acidregs, name, val);
1024 void
1025 strace(Node *r, Node *args)
1027 Node *av[Maxarg], res;
1028 List *l;
1029 Regs regs;
1031 na = 0;
1032 flatten(av, args);
1034 if(na != 1)
1035 error("strace(list): want one arg");
1037 expr(av[0], &res);
1038 if(res.type != TLIST)
1039 error("strace(list): strace needs a list");
1040 l = res.store.u.l;
1041 if(listlen(l)%2)
1042 error("strace(list): strace needs an even-length list");
1043 for(nsregs=0; l; nsregs++){
1044 if(l->type != TSTRING)
1045 error("strace({r,v,r,v,...}): non-string name");
1046 sregs[nsregs].name = l->store.u.string->string;
1047 if(regdesc(sregs[nsregs].name) == nil)
1048 error("strace: bad register '%s'", sregs[nsregs].name);
1049 l = l->next;
1051 if(l == nil)
1052 error("cannot happen in strace");
1053 if(l->type != TINT)
1054 error("strace: non-int value for %s", sregs[nsregs].name);
1055 sregs[nsregs].val = l->store.u.ival;
1056 l = l->next;
1058 regs.rw = straceregrw;
1060 tracelist = 0;
1061 if(stacktrace(cormap, &regs, trlist) <= 0)
1062 error("no stack frame");
1063 r->type = TLIST;
1064 r->store.u.l = tracelist;
1067 void
1068 regerror(char *msg)
1070 error(msg);
1073 void
1074 regexp(Node *r, Node *args)
1076 Node res;
1077 Reprog *rp;
1078 Node *av[Maxarg];
1080 na = 0;
1081 flatten(av, args);
1082 if(na != 2)
1083 error("regexp(pattern, string): arg count");
1084 expr(av[0], &res);
1085 if(res.type != TSTRING)
1086 error("regexp(pattern, string): pattern must be string");
1087 rp = regcomp(res.store.u.string->string);
1088 if(rp == 0)
1089 return;
1091 expr(av[1], &res);
1092 if(res.type != TSTRING)
1093 error("regexp(pattern, string): bad string");
1095 r->store.fmt = 'D';
1096 r->type = TINT;
1097 r->store.u.ival = regexec(rp, res.store.u.string->string, 0, 0);
1098 free(rp);
1101 char vfmt[] = "aBbcCdDfFgGiIoOqQrRsSuUVxXYZ";
1103 void
1104 fmt(Node *r, Node *args)
1106 Node res;
1107 Node *av[Maxarg];
1109 na = 0;
1110 flatten(av, args);
1111 if(na != 2)
1112 error("fmt(obj, fmt): arg count");
1113 expr(av[1], &res);
1114 if(res.type != TINT || strchr(vfmt, res.store.u.ival) == 0)
1115 error("fmt(obj, fmt): bad format '%c'", (char)res.store.u.ival);
1116 expr(av[0], r);
1117 r->store.fmt = res.store.u.ival;
1120 void
1121 patom(char type, Store *res)
1123 int i;
1124 char buf[512];
1125 extern char *typenames[];
1126 Node *n;
1128 switch(type){
1129 case TREG:
1130 Bprint(bout, "register(\"%s\")", res->u.reg);
1131 return;
1132 case TCON:
1133 Bprint(bout, "refconst(");
1134 n = res->u.con;
1135 patom(n->type, &n->store);
1136 Bprint(bout, ")");
1137 return;
1140 switch(res->fmt){
1141 case 'c':
1142 case 'C':
1143 case 'r':
1144 case 'B':
1145 case 'b':
1146 case 'X':
1147 case 'x':
1148 case 'W':
1149 case 'D':
1150 case 'd':
1151 case 'u':
1152 case 'U':
1153 case 'Z':
1154 case 'V':
1155 case 'Y':
1156 case 'o':
1157 case 'O':
1158 case 'q':
1159 case 'Q':
1160 case 'a':
1161 case 'A':
1162 case 'I':
1163 case 'i':
1164 if(type != TINT){
1165 badtype:
1166 Bprint(bout, "*%s\\%c*", typenames[(uchar)type], res->fmt);
1167 return;
1169 break;
1171 case 'f':
1172 case 'F':
1173 if(type != TFLOAT)
1174 goto badtype;
1175 break;
1177 case 's':
1178 case 'g':
1179 case 'G':
1180 case 'R':
1181 if(type != TSTRING)
1182 goto badtype;
1183 break;
1186 switch(res->fmt) {
1187 case 'c':
1188 Bprint(bout, "%c", (int)res->u.ival);
1189 break;
1190 case 'C':
1191 if(res->u.ival < ' ' || res->u.ival >= 0x7f)
1192 Bprint(bout, "%3d", (int)res->u.ival&0xff);
1193 else
1194 Bprint(bout, "%3c", (int)res->u.ival);
1195 break;
1196 case 'r':
1197 Bprint(bout, "%C", (int)res->u.ival);
1198 break;
1199 case 'B':
1200 memset(buf, '0', 34);
1201 buf[1] = 'b';
1202 for(i = 0; i < 32; i++) {
1203 if(res->u.ival & (1<<i))
1204 buf[33-i] = '1';
1206 buf[35] = '\0';
1207 Bprint(bout, "%s", buf);
1208 break;
1209 case 'b':
1210 Bprint(bout, "%.2x", (int)res->u.ival&0xff);
1211 break;
1212 case 'X':
1213 Bprint(bout, "%.8lux", (ulong)res->u.ival);
1214 break;
1215 case 'x':
1216 Bprint(bout, "%.4lux", (ulong)res->u.ival&0xffff);
1217 break;
1218 case 'W':
1219 Bprint(bout, "%.16llux", res->u.ival);
1220 break;
1221 case 'D':
1222 Bprint(bout, "%d", (int)res->u.ival);
1223 break;
1224 case 'd':
1225 Bprint(bout, "%d", (ushort)res->u.ival);
1226 break;
1227 case 'u':
1228 Bprint(bout, "%d", (int)res->u.ival&0xffff);
1229 break;
1230 case 'U':
1231 Bprint(bout, "%lud", (ulong)res->u.ival);
1232 break;
1233 case 'Z':
1234 Bprint(bout, "%llud", res->u.ival);
1235 break;
1236 case 'V':
1237 Bprint(bout, "%lld", res->u.ival);
1238 break;
1239 case 'Y':
1240 Bprint(bout, "%.16llux", res->u.ival);
1241 break;
1242 case 'o':
1243 Bprint(bout, "0%.11uo", (int)res->u.ival&0xffff);
1244 break;
1245 case 'O':
1246 Bprint(bout, "0%.6uo", (int)res->u.ival);
1247 break;
1248 case 'q':
1249 Bprint(bout, "0%.11o", (short)(res->u.ival&0xffff));
1250 break;
1251 case 'Q':
1252 Bprint(bout, "0%.6o", (int)res->u.ival);
1253 break;
1254 case 'f':
1255 case 'F':
1256 Bprint(bout, "%g", res->u.fval);
1257 break;
1258 case 's':
1259 case 'g':
1260 case 'G':
1261 Bwrite(bout, res->u.string->string, res->u.string->len);
1262 break;
1263 case 'R':
1264 Bprint(bout, "%S", (Rune*)res->u.string->string);
1265 break;
1266 case 'a':
1267 case 'A':
1268 symoff(buf, sizeof(buf), res->u.ival, CANY);
1269 Bprint(bout, "%s", buf);
1270 break;
1271 case 'I':
1272 case 'i':
1273 if (symmap == nil || (*mach->das)(symmap, res->u.ival, res->fmt, buf, sizeof(buf)) < 0)
1274 Bprint(bout, "no instruction");
1275 else
1276 Bprint(bout, "%s", buf);
1277 break;
1281 void
1282 blprint(List *l)
1284 Store *res;
1286 Bprint(bout, "{");
1287 while(l) {
1288 switch(l->type) {
1289 case TINT:
1290 res = &l->store;
1291 if(res->fmt == 'c'){
1292 Bprint(bout, "\'%c\'", (int)res->u.ival);
1293 break;
1294 }else if(res->fmt == 'r'){
1295 Bprint(bout, "\'%C\'", (int)res->u.ival);
1296 break;
1298 /* fall through */
1299 default:
1300 patom(l->type, &l->store);
1301 break;
1302 case TSTRING:
1303 Bputc(bout, '"');
1304 patom(l->type, &l->store);
1305 Bputc(bout, '"');
1306 break;
1307 case TLIST:
1308 blprint(l->store.u.l);
1309 break;
1310 case TCODE:
1311 pcode(l->store.u.cc, 0);
1312 break;
1314 l = l->next;
1315 if(l)
1316 Bprint(bout, ", ");
1318 Bprint(bout, "}");
1321 int
1322 comx(Node res)
1324 Lsym *sl;
1325 Node *n, xx;
1327 if(res.store.fmt != 'a' && res.store.fmt != 'A')
1328 return 0;
1330 if(res.store.comt == 0 || res.store.comt->base == 0)
1331 return 0;
1333 sl = res.store.comt->base;
1334 if(sl->proc) {
1335 res.left = ZN;
1336 res.right = ZN;
1337 n = an(ONAME, ZN, ZN);
1338 n->sym = sl;
1339 n = an(OCALL, n, &res);
1340 n->left->sym = sl;
1341 expr(n, &xx);
1342 return 1;
1344 print("(%s)", sl->name);
1345 return 0;
1348 void
1349 bprint(Node *r, Node *args)
1351 int i, nas;
1352 Node res, *av[Maxarg];
1354 USED(r);
1355 na = 0;
1356 flatten(av, args);
1357 nas = na;
1358 for(i = 0; i < nas; i++) {
1359 expr(av[i], &res);
1360 switch(res.type) {
1361 default:
1362 if(comx(res))
1363 break;
1364 patom(res.type, &res.store);
1365 break;
1366 case TCODE:
1367 pcode(res.store.u.cc, 0);
1368 break;
1369 case TLIST:
1370 blprint(res.store.u.l);
1371 break;
1374 if(ret == 0)
1375 Bputc(bout, '\n');
1378 void
1379 printto(Node *r, Node *args)
1381 int fd;
1382 Biobuf *b;
1383 int i, nas;
1384 Node res, *av[Maxarg];
1386 USED(r);
1387 na = 0;
1388 flatten(av, args);
1389 nas = na;
1391 expr(av[0], &res);
1392 if(res.type != TSTRING)
1393 error("printto(string, ...): need string");
1395 fd = create(res.store.u.string->string, OWRITE, 0666);
1396 if(fd < 0)
1397 fd = open(res.store.u.string->string, OWRITE);
1398 if(fd < 0)
1399 error("printto: open %s: %r", res.store.u.string->string);
1401 b = gmalloc(sizeof(Biobuf));
1402 Binit(b, fd, OWRITE);
1404 Bflush(bout);
1405 io[iop++] = bout;
1406 bout = b;
1408 for(i = 1; i < nas; i++) {
1409 expr(av[i], &res);
1410 switch(res.type) {
1411 default:
1412 if(comx(res))
1413 break;
1414 patom(res.type, &res.store);
1415 break;
1416 case TLIST:
1417 blprint(res.store.u.l);
1418 break;
1421 if(ret == 0)
1422 Bputc(bout, '\n');
1424 Bterm(b);
1425 close(fd);
1426 free(b);
1427 bout = io[--iop];
1430 void
1431 pcfile(Node *r, Node *args)
1433 Node res;
1434 char *p, buf[128];
1436 if(args == 0)
1437 error("pcfile(addr): arg count");
1438 expr(args, &res);
1439 if(res.type != TINT)
1440 error("pcfile(addr): arg type");
1442 r->type = TSTRING;
1443 r->store.fmt = 's';
1444 if(fileline(res.store.u.ival, buf, sizeof(buf)) < 0) {
1445 r->store.u.string = strnode("?file?");
1446 return;
1448 p = strrchr(buf, ':');
1449 if(p == 0)
1450 error("pcfile(addr): funny file %s", buf);
1451 *p = '\0';
1452 r->store.u.string = strnode(buf);
1455 void
1456 pcline(Node *r, Node *args)
1458 Node res;
1459 char *p, buf[128];
1461 if(args == 0)
1462 error("pcline(addr): arg count");
1463 expr(args, &res);
1464 if(res.type != TINT)
1465 error("pcline(addr): arg type");
1467 r->type = TINT;
1468 r->store.fmt = 'D';
1469 if(fileline(res.store.u.ival, buf, sizeof(buf)) < 0) {
1470 r->store.u.ival = 0;
1471 return;
1474 p = strrchr(buf, ':');
1475 if(p == 0)
1476 error("pcline(addr): funny file %s", buf);
1477 r->store.u.ival = atoi(p+1);
1480 void
1481 textfile(Node *r, Node *args)
1483 char *file;
1484 long base;
1485 Fhdr *fp;
1486 Node res, *av[Maxarg];
1487 List *l, *l2, **tail, *list, *tl;
1489 na = 0;
1490 flatten(av, args);
1492 if(na != 0) {
1493 expr(av[0], &res);
1494 if(res.type != TLIST)
1495 error("textfile(list): textfile needs a list");
1496 if(listlen(res.store.u.l) != 2)
1497 error("textfile(list): list must have 2 entries");
1499 l = res.store.u.l;
1500 if(l->type != TSTRING)
1501 error("textfile name must be a string");
1502 file = l->store.u.string->string;
1504 l = l->next;
1505 if(l->type != TINT)
1506 error("textfile base must be an int");
1507 base = l->store.u.ival;
1509 if((fp = crackhdr(file, OREAD)) == nil)
1510 error("crackhdr %s: %r", file);
1511 Bflush(bout);
1512 fp->base = base;
1513 fprint(2, "%s: %s %s %s\n", file, fp->aname, fp->mname, fp->fname);
1514 if(mapfile(fp, base, symmap, nil) < 0)
1515 fprint(2, "mapping %s: %r\n", file);
1516 if(corhdr){
1517 unmapfile(corhdr, cormap);
1518 mapfile(fp, base, cormap, nil);
1519 free(correg);
1520 correg = nil;
1521 mapfile(corhdr, 0, cormap, &correg);
1523 if(symopen(fp) < 0)
1524 fprint(2, "symopen %s: %r\n", file);
1525 else
1526 addvarsym(fp);
1527 return;
1530 l2 = nil;
1531 tail = &l2;
1532 for(fp=fhdrlist; fp; fp=fp->next){
1533 if(fp->ftype == FCORE)
1534 continue;
1535 tl = al(TLIST);
1536 *tail = tl;
1537 tail = &tl->next;
1539 list = al(TSTRING);
1540 tl->store.u.l = list;
1541 list->store.u.string = strnode(fp->filename);
1542 list->store.fmt = 's';
1543 list->next = al(TINT);
1544 list = list->next;
1545 list->store.fmt = 'X';
1546 list->store.u.ival = fp->base;
1549 r->type = TLIST;
1550 r->store.u.l = l2;
1553 void
1554 deltextfile(Node *r, Node *args)
1556 int did;
1557 char *file;
1558 Fhdr *fp, *fpnext;
1559 Node res, *av[Maxarg];
1561 na = 0;
1562 flatten(av, args);
1564 if(na != 1)
1565 error("deltextfile(string): arg count");
1567 expr(av[0], &res);
1568 if(res.type != TSTRING)
1569 error("deltextfile(string): arg type");
1570 file = res.store.u.string->string;
1572 did = 0;
1573 for(fp=fhdrlist; fp; fp=fpnext){
1574 fpnext = fp->next;
1575 if(fp->ftype == FCORE)
1576 continue;
1577 if(strcmp(file, fp->filename) == 0){
1578 did = 1;
1579 if(fp == symhdr)
1580 error("cannot remove symbols from main text file");
1581 unmapfile(fp, symmap);
1582 uncrackhdr(fp);
1586 delvarsym(file);
1587 if(!did)
1588 error("symbol file %s not open", file);
1591 void
1592 stringn(Node *r, Node *args)
1594 uint addr;
1595 int i, n, ret;
1596 Node res, *av[Maxarg];
1597 char *buf;
1599 na = 0;
1600 flatten(av, args);
1601 if(na != 2)
1602 error("stringn(addr, n): arg count");
1604 expr(av[0], &res);
1605 if(res.type != TINT)
1606 error("stringn(addr, n): arg type");
1607 addr = res.store.u.ival;
1609 expr(av[1], &res);
1610 if(res.type != TINT)
1611 error("stringn(addr,n): arg type");
1612 n = res.store.u.ival;
1614 buf = malloc(n+1);
1615 if(buf == nil)
1616 error("out of memory");
1618 r->type = TSTRING;
1619 for(i=0; i<n; i++){
1620 ret = get1(cormap, addr, (uchar*)&buf[i], 1);
1621 if(ret < 0){
1622 free(buf);
1623 error("indir: %r");
1625 addr++;
1627 buf[n] = 0;
1628 r->store.u.string = strnode(buf);
1629 free(buf);