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 waitsyscall(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*);
50 void step1(Node*, Node*);
52 typedef struct Btab Btab;
53 struct Btab
54 {
55 char *name;
56 void (*fn)(Node*, Node*);
57 } tab[] =
58 {
59 "access", doaccess,
60 "atof", cvtatof,
61 "atoi", cvtatoi,
62 "deltextfile", deltextfile,
63 "error", doerror,
64 "file", getfile,
65 "filepc", filepc,
66 "fnbound", funcbound,
67 "fmt", fmt,
68 "follow", follow,
69 "include", include,
70 "includepipe", includepipe,
71 "interpret", interpret,
72 "itoa", cvtitoa,
73 "kill", xkill,
74 "map", map,
75 "match", match,
76 "newproc", newproc,
77 "pcfile", pcfile,
78 "pcline", pcline,
79 "print", bprint,
80 "printto", printto,
81 "rc", rc,
82 "readfile", readfile,
83 "reason", reason,
84 "refconst", refconst,
85 "regexp", regexp,
86 "register", xregister,
87 "setproc", setproc,
88 "start", start,
89 "startstop", startstop,
90 "status", status,
91 "step1", step1,
92 "stop", stop,
93 "strace", strace,
94 "stringn", stringn,
95 "textfile", textfile,
96 "var", dolook,
97 "waitstop", waitstop,
98 "waitsyscall", waitsyscall,
99 0
100 };
102 void
103 mkprint(Lsym *s)
105 prnt = malloc(sizeof(Node));
106 memset(prnt, 0, sizeof(Node));
107 prnt->op = OCALL;
108 prnt->left = malloc(sizeof(Node));
109 memset(prnt->left, 0, sizeof(Node));
110 prnt->left->sym = s;
113 void
114 installbuiltin(void)
116 Btab *b;
117 Lsym *s;
119 b = tab;
120 while(b->name) {
121 s = look(b->name);
122 if(s == 0)
123 s = enter(b->name, Tid);
125 s->builtin = b->fn;
126 if(b->fn == bprint)
127 mkprint(s);
128 b++;
132 void
133 match(Node *r, Node *args)
135 int i;
136 List *f;
137 Node *av[Maxarg];
138 Node resi, resl;
140 na = 0;
141 flatten(av, args);
142 if(na != 2)
143 error("match(obj, list): arg count");
145 expr(av[1], &resl);
146 if(resl.type != TLIST)
147 error("match(obj, list): need list");
148 expr(av[0], &resi);
150 r->op = OCONST;
151 r->type = TINT;
152 r->store.fmt = 'D';
153 r->store.u.ival = -1;
155 i = 0;
156 for(f = resl.store.u.l; f; f = f->next) {
157 if(resi.type == f->type) {
158 switch(resi.type) {
159 case TINT:
160 if(resi.store.u.ival == f->store.u.ival) {
161 r->store.u.ival = i;
162 return;
164 break;
165 case TFLOAT:
166 if(resi.store.u.fval == f->store.u.fval) {
167 r->store.u.ival = i;
168 return;
170 break;
171 case TSTRING:
172 if(scmp(resi.store.u.string, f->store.u.string)) {
173 r->store.u.ival = i;
174 return;
176 break;
177 case TLIST:
178 error("match(obj, list): not defined for list");
181 i++;
185 void
186 newproc(Node *r, Node *args)
188 int i;
189 Node res;
190 char *p, *e;
191 char *argv[Maxarg], buf[Strsize];
193 i = 1;
194 argv[0] = symfil;
196 if(args) {
197 expr(args, &res);
198 if(res.type != TSTRING)
199 error("newproc(): arg not string");
200 if(res.store.u.string->len >= sizeof(buf))
201 error("newproc(): too many arguments");
202 memmove(buf, res.store.u.string->string, res.store.u.string->len);
203 buf[res.store.u.string->len] = '\0';
204 p = buf;
205 e = buf+res.store.u.string->len;
206 for(;;) {
207 while(p < e && (*p == '\t' || *p == ' '))
208 *p++ = '\0';
209 if(p >= e)
210 break;
211 argv[i++] = p;
212 if(i >= Maxarg)
213 error("newproc: too many arguments");
214 while(p < e && *p != '\t' && *p != ' ')
215 p++;
218 argv[i] = 0;
219 r->op = OCONST;
220 r->type = TINT;
221 r->store.fmt = 'D';
222 r->store.u.ival = nproc(argv);
225 void
226 step1(Node *r, Node *args)
228 Node res;
230 USED(r);
231 if(args == 0)
232 error("step1(pid): no pid");
233 expr(args, &res);
234 if(res.type != TINT)
235 error("step1(pid): arg type");
237 msg(res.store.u.ival, "step");
238 notes(res.store.u.ival);
239 dostop(res.store.u.ival);
242 void
243 startstop(Node *r, Node *args)
245 Node res;
247 USED(r);
248 if(args == 0)
249 error("startstop(pid): no pid");
250 expr(args, &res);
251 if(res.type != TINT)
252 error("startstop(pid): arg type");
254 msg(res.store.u.ival, "startstop");
255 notes(res.store.u.ival);
256 dostop(res.store.u.ival);
259 void
260 waitstop(Node *r, Node *args)
262 Node res;
264 USED(r);
265 if(args == 0)
266 error("waitstop(pid): no pid");
267 expr(args, &res);
268 if(res.type != TINT)
269 error("waitstop(pid): arg type");
271 Bflush(bout);
272 msg(res.store.u.ival, "waitstop");
273 notes(res.store.u.ival);
274 dostop(res.store.u.ival);
277 void
278 waitsyscall(Node *r, Node *args)
280 Node res;
282 USED(r);
283 if(args == 0)
284 error("waitsyscall(pid): no pid");
285 expr(args, &res);
286 if(res.type != TINT)
287 error("waitsycall(pid): arg type");
289 Bflush(bout);
290 msg(res.store.u.ival, "sysstop");
291 notes(res.store.u.ival);
292 dostop(res.store.u.ival);
295 void
296 start(Node *r, Node *args)
298 Node res;
300 USED(r);
301 if(args == 0)
302 error("start(pid): no pid");
303 expr(args, &res);
304 if(res.type != TINT)
305 error("start(pid): arg type");
307 msg(res.store.u.ival, "start");
310 void
311 stop(Node *r, Node *args)
313 Node res;
315 USED(r);
316 if(args == 0)
317 error("stop(pid): no pid");
318 expr(args, &res);
319 if(res.type != TINT)
320 error("stop(pid): arg type");
322 Bflush(bout);
323 msg(res.store.u.ival, "stop");
324 notes(res.store.u.ival);
325 dostop(res.store.u.ival);
328 void
329 xkill(Node *r, Node *args)
331 Node res;
333 USED(r);
334 if(args == 0)
335 error("kill(pid): no pid");
336 expr(args, &res);
337 if(res.type != TINT)
338 error("kill(pid): arg type");
340 msg(res.store.u.ival, "kill");
341 deinstall(res.store.u.ival);
344 void
345 xregister(Node *r, Node *args)
347 int tid;
348 Regdesc *rp;
349 Node res, resid;
350 Node *av[Maxarg];
352 na = 0;
353 flatten(av, args);
354 if(na != 1/* && na != 2 */)
355 error("register(name): arg count");
357 expr(av[0], &res);
358 if(res.type != TSTRING)
359 error("register(name): arg type: name should be string");
360 tid = 0;
361 if(na == 2){
362 expr(av[1], &resid);
363 if(resid.type != TINT)
364 error("register(name[, threadid]): arg type: threadid should be int");
365 tid = resid.store.u.ival;
367 if((rp = regdesc(res.store.u.string->string)) == nil)
368 error("no such register");
369 r->op = OCONST;
370 r->type = TREG;
371 r->store.fmt = rp->format;
372 r->store.u.reg.name = rp->name;
373 r->store.u.reg.thread = tid;
376 void
377 refconst(Node *r, Node *args)
379 Node *n;
381 if(args == 0)
382 error("refconst(expr): arg count");
384 n = an(OCONST, ZN, ZN);
385 expr(args, n);
387 r->op = OCONST;
388 r->type = TCON;
389 r->store.u.con = n;
392 void
393 dolook(Node *r, Node *args)
395 Node res;
396 Lsym *l;
398 if(args == 0)
399 error("var(string): arg count");
400 expr(args, &res);
401 if(res.type != TSTRING)
402 error("var(string): arg type");
404 r->op = OCONST;
405 if((l = look(res.store.u.string->string)) == nil || l->v->set == 0){
406 r->type = TLIST;
407 r->store.u.l = nil;
408 }else{
409 r->type = l->v->type;
410 r->store = l->v->store;
414 void
415 status(Node *r, Node *args)
417 Node res;
418 char *p;
420 USED(r);
421 if(args == 0)
422 error("status(pid): no pid");
423 expr(args, &res);
424 if(res.type != TINT)
425 error("status(pid): arg type");
427 p = getstatus(res.store.u.ival);
428 r->store.u.string = strnode(p);
429 r->op = OCONST;
430 r->store.fmt = 's';
431 r->type = TSTRING;
434 void
435 reason(Node *r, Node *args)
437 Node res;
439 if(args == 0)
440 error("reason(cause): no cause");
441 expr(args, &res);
442 if(res.type != TINT)
443 error("reason(cause): arg type");
445 r->op = OCONST;
446 r->type = TSTRING;
447 r->store.fmt = 's';
448 r->store.u.string = strnode((*mach->exc)(cormap, acidregs));
451 void
452 follow(Node *r, Node *args)
454 int n, i;
455 Node res;
456 u64int f[10];
457 List **tail, *l;
459 if(args == 0)
460 error("follow(addr): no addr");
461 expr(args, &res);
462 if(res.type != TINT)
463 error("follow(addr): arg type");
465 n = (*mach->foll)(cormap, acidregs, res.store.u.ival, f);
466 if (n < 0)
467 error("follow(addr): %r");
468 tail = &r->store.u.l;
469 for(i = 0; i < n; i++) {
470 l = al(TINT);
471 l->store.u.ival = f[i];
472 l->store.fmt = 'X';
473 *tail = l;
474 tail = &l->next;
478 void
479 funcbound(Node *r, Node *args)
481 int n;
482 Node res;
483 u64int bounds[2];
484 List *l;
486 if(args == 0)
487 error("fnbound(addr): no addr");
488 expr(args, &res);
489 if(res.type != TINT)
490 error("fnbound(addr): arg type");
492 n = fnbound(res.store.u.ival, bounds);
493 if (n >= 0) {
494 r->store.u.l = al(TINT);
495 l = r->store.u.l;
496 l->store.u.ival = bounds[0];
497 l->store.fmt = 'X';
498 l->next = al(TINT);
499 l = l->next;
500 l->store.u.ival = bounds[1];
501 l->store.fmt = 'X';
505 void
506 setproc(Node *r, Node *args)
508 Node res;
510 USED(r);
511 if(args == 0)
512 error("setproc(pid): no pid");
513 expr(args, &res);
514 if(res.type != TINT)
515 error("setproc(pid): arg type");
517 sproc(res.store.u.ival);
520 void
521 filepc(Node *r, Node *args)
523 int i;
524 Node res;
525 char *p, c;
526 u64int v;
528 if(args == 0)
529 error("filepc(filename:line): arg count");
530 expr(args, &res);
531 if(res.type != TSTRING)
532 error("filepc(filename:line): arg type");
534 p = strchr(res.store.u.string->string, ':');
535 if(p == 0)
536 error("filepc(filename:line): bad arg format");
538 c = *p;
539 *p++ = '\0';
540 i = file2pc(res.store.u.string->string, atoi(p), &v);
541 p[-1] = c;
542 if(i < 0)
543 error("filepc(filename:line): can't find address");
545 r->op = OCONST;
546 r->type = TINT;
547 r->store.fmt = 'D';
548 r->store.u.ival = v;
551 void
552 interpret(Node *r, Node *args)
554 Node res;
555 int isave;
557 if(args == 0)
558 error("interpret(string): arg count");
559 expr(args, &res);
560 if(res.type != TSTRING)
561 error("interpret(string): arg type");
563 pushstr(&res);
565 isave = interactive;
566 interactive = 0;
567 r->store.u.ival = yyparse();
568 interactive = isave;
569 popio();
570 r->op = OCONST;
571 r->type = TINT;
572 r->store.fmt = 'D';
575 void
576 include(Node *r, Node *args)
578 char *file, *libfile;
579 static char buf[1024];
580 Node res;
581 int isave;
583 if(args == 0)
584 error("include(string): arg count");
585 expr(args, &res);
586 if(res.type != TSTRING)
587 error("include(string): arg type");
589 Bflush(bout);
591 libfile = nil;
592 file = res.store.u.string->string;
593 if(access(file, AREAD) < 0 && file[0] != '/'){
594 snprint(buf, sizeof buf, "#9/acid/%s", file);
595 libfile = unsharp(buf);
596 if(access(libfile, AREAD) >= 0){
597 strecpy(buf, buf+sizeof buf, libfile);
598 file = buf;
600 free(libfile);
603 pushfile(file);
604 isave = interactive;
605 interactive = 0;
606 r->store.u.ival = yyparse();
607 interactive = isave;
608 popio();
609 r->op = OCONST;
610 r->type = TINT;
611 r->store.fmt = 'D';
614 void
615 includepipe(Node *r, Node *args)
617 Node res;
618 int i, isave, pid, pip[2];
619 char *argv[4];
620 Waitmsg *w;
622 USED(r);
623 if(args == 0)
624 error("includepipe(string): arg count");
625 expr(args, &res);
626 if(res.type != TSTRING)
627 error("includepipe(string): arg type");
629 Bflush(bout);
631 argv[0] = "rc";
632 argv[1] = "-c";
633 argv[2] = res.store.u.string->string;
634 argv[3] = 0;
636 if(pipe(pip) < 0)
637 error("pipe: %r");
639 pid = fork();
640 switch(pid) {
641 case -1:
642 close(pip[0]);
643 close(pip[1]);
644 error("fork: %r");
645 case 0:
646 close(pip[0]);
647 close(0);
648 open("/dev/null", OREAD);
649 dup(pip[1], 1);
650 if(pip[1] > 1)
651 close(pip[1]);
652 for(i=3; i<100; i++)
653 close(i);
654 exec("rc", argv);
655 sysfatal("exec rc: %r");
658 close(pip[1]);
659 pushfd(pip[0]);
661 isave = interactive;
662 interactive = 0;
663 r->store.u.ival = yyparse();
664 interactive = isave;
665 popio();
667 r->op = OCONST;
668 r->type = TINT;
669 r->store.fmt = 'D';
671 w = waitfor(pid);
672 if(w->msg && w->msg[0])
673 error("includepipe(\"%s\"): %s", argv[2], w->msg); /* leaks w */
674 free(w);
677 void
678 rc(Node *r, Node *args)
680 Node res;
681 int pid;
682 char *p, *q, *argv[4];
683 Waitmsg *w;
685 USED(r);
686 if(args == 0)
687 error("rc(string): arg count");
688 expr(args, &res);
689 if(res.type != TSTRING)
690 error("rc(string): arg type");
692 argv[0] = "rc";
693 argv[1] = "-c";
694 argv[2] = res.store.u.string->string;
695 argv[3] = 0;
697 pid = fork();
698 switch(pid) {
699 case -1:
700 error("fork %r");
701 case 0:
702 exec("rc", argv);
703 exits(0);
704 default:
705 w = waitfor(pid);
706 break;
708 p = w->msg;
709 q = strrchr(p, ':');
710 if (q)
711 p = q+1;
713 r->op = OCONST;
714 r->type = TSTRING;
715 r->store.u.string = strnode(p);
716 free(w);
717 r->store.fmt = 's';
720 void
721 doerror(Node *r, Node *args)
723 Node res;
725 USED(r);
726 if(args == 0)
727 error("error(string): arg count");
728 expr(args, &res);
729 if(res.type != TSTRING)
730 error("error(string): arg type");
732 error(res.store.u.string->string);
735 void
736 doaccess(Node *r, Node *args)
738 Node res;
740 if(args == 0)
741 error("access(filename): arg count");
742 expr(args, &res);
743 if(res.type != TSTRING)
744 error("access(filename): arg type");
746 r->op = OCONST;
747 r->type = TINT;
748 r->store.fmt = 'D';
749 r->store.u.ival = 0;
750 if(access(res.store.u.string->string, 4) == 0)
751 r->store.u.ival = 1;
754 void
755 readfile(Node *r, Node *args)
757 Node res;
758 int n, fd;
759 char *buf;
760 Dir *db;
762 if(args == 0)
763 error("readfile(filename): arg count");
764 expr(args, &res);
765 if(res.type != TSTRING)
766 error("readfile(filename): arg type");
768 fd = open(res.store.u.string->string, OREAD);
769 if(fd < 0)
770 return;
772 db = dirfstat(fd);
773 if(db == nil || db->length == 0)
774 n = 8192;
775 else
776 n = db->length;
777 free(db);
779 buf = malloc(n);
780 n = read(fd, buf, n);
782 if(n > 0) {
783 r->op = OCONST;
784 r->type = TSTRING;
785 r->store.u.string = strnodlen(buf, n);
786 r->store.fmt = 's';
788 free(buf);
789 close(fd);
792 void
793 getfile(Node *r, Node *args)
795 int n;
796 char *p;
797 Node res;
798 String *s;
799 Biobuf *bp;
800 List **l, *new;
802 if(args == 0)
803 error("file(filename): arg count");
804 expr(args, &res);
805 if(res.type != TSTRING)
806 error("file(filename): arg type");
808 r->op = OCONST;
809 r->type = TLIST;
810 r->store.u.l = 0;
812 p = res.store.u.string->string;
813 bp = Bopen(p, OREAD);
814 if(bp == 0)
815 return;
817 l = &r->store.u.l;
818 for(;;) {
819 p = Brdline(bp, '\n');
820 n = Blinelen(bp);
821 if(p == 0) {
822 if(n == 0)
823 break;
824 s = strnodlen(0, n);
825 Bread(bp, s->string, n);
827 else
828 s = strnodlen(p, n-1);
830 new = al(TSTRING);
831 new->store.u.string = s;
832 new->store.fmt = 's';
833 *l = new;
834 l = &new->next;
836 Bterm(bp);
839 void
840 cvtatof(Node *r, Node *args)
842 Node res;
844 if(args == 0)
845 error("atof(string): arg count");
846 expr(args, &res);
847 if(res.type != TSTRING)
848 error("atof(string): arg type");
850 r->op = OCONST;
851 r->type = TFLOAT;
852 r->store.u.fval = atof(res.store.u.string->string);
853 r->store.fmt = 'f';
856 void
857 cvtatoi(Node *r, Node *args)
859 Node res;
861 if(args == 0)
862 error("atoi(string): arg count");
863 expr(args, &res);
864 if(res.type != TSTRING)
865 error("atoi(string): arg type");
867 r->op = OCONST;
868 r->type = TINT;
869 r->store.u.ival = strtoull(res.store.u.string->string, 0, 0);
870 r->store.fmt = 'D';
873 void
874 cvtitoa(Node *r, Node *args)
876 Node res;
877 Node *av[Maxarg];
878 s64int ival;
879 char buf[128], *fmt;
881 if(args == 0)
882 err:
883 error("itoa(number [, printformat]): arg count");
884 na = 0;
885 flatten(av, args);
886 if(na == 0 || na > 2)
887 goto err;
888 expr(av[0], &res);
889 if(res.type != TINT)
890 error("itoa(integer): arg type");
891 ival = (int)res.store.u.ival;
892 fmt = "%d";
893 if(na == 2){
894 expr(av[1], &res);
895 if(res.type != TSTRING)
896 error("itoa(integer, string): arg type");
897 fmt = res.store.u.string->string;
900 sprint(buf, fmt, ival);
901 r->op = OCONST;
902 r->type = TSTRING;
903 r->store.u.string = strnode(buf);
904 r->store.fmt = 's';
907 List*
908 mapent(Map *m)
910 int i;
911 List *l, *n, **t, *h;
913 h = 0;
914 t = &h;
915 for(i = 0; i < m->nseg; i++) {
916 l = al(TSTRING);
917 n = al(TLIST);
918 n->store.u.l = l;
919 *t = n;
920 t = &n->next;
921 l->store.u.string = strnode(m->seg[i].name);
922 l->store.fmt = 's';
923 l->next = al(TSTRING);
924 l = l->next;
925 l->store.u.string = strnode(m->seg[i].file ? m->seg[i].file : "");
926 l->store.fmt = 's';
927 l->next = al(TINT);
928 l = l->next;
929 l->store.u.ival = m->seg[i].base;
930 l->store.fmt = 'X';
931 l->next = al(TINT);
932 l = l->next;
933 l->store.u.ival = m->seg[i].base + m->seg[i].size;
934 l->store.fmt = 'X';
935 l->next = al(TINT);
936 l = l->next;
937 l->store.u.ival = m->seg[i].offset;
938 l->store.fmt = 'X';
940 return h;
943 void
944 map(Node *r, Node *args)
946 int i;
947 Map *m;
948 List *l;
949 char *nam, *fil;
950 Node *av[Maxarg], res;
952 na = 0;
953 flatten(av, args);
955 if(na != 0) {
956 expr(av[0], &res);
957 if(res.type != TLIST)
958 error("map(list): map needs a list");
959 if(listlen(res.store.u.l) != 5)
960 error("map(list): list must have 5 entries");
962 l = res.store.u.l;
963 if(l->type != TSTRING)
964 error("map name must be a string");
965 nam = l->store.u.string->string;
966 l = l->next;
967 if(l->type != TSTRING)
968 error("map file must be a string");
969 fil = l->store.u.string->string;
970 m = symmap;
971 i = findseg(m, nam, fil);
972 if(i < 0) {
973 m = cormap;
974 i = findseg(m, nam, fil);
976 if(i < 0)
977 error("%s %s is not a map entry", nam, fil);
978 l = l->next;
979 if(l->type != TINT)
980 error("map entry not int");
981 m->seg[i].base = l->store.u.ival;
982 /*
983 if (strcmp(ent, "text") == 0)
984 textseg(l->store.u.ival, &fhdr);
985 */
986 l = l->next;
987 if(l->type != TINT)
988 error("map entry not int");
989 m->seg[i].size = l->store.u.ival - m->seg[i].base;
990 l = l->next;
991 if(l->type != TINT)
992 error("map entry not int");
993 m->seg[i].offset = l->store.u.ival;
996 r->type = TLIST;
997 r->store.u.l = 0;
998 if(symmap)
999 r->store.u.l = mapent(symmap);
1000 if(cormap) {
1001 if(r->store.u.l == 0)
1002 r->store.u.l = mapent(cormap);
1003 else {
1004 for(l = r->store.u.l; l->next; l = l->next)
1006 l->next = mapent(cormap);
1011 void
1012 flatten(Node **av, Node *n)
1014 if(n == 0)
1015 return;
1017 switch(n->op) {
1018 case OLIST:
1019 flatten(av, n->left);
1020 flatten(av, n->right);
1021 break;
1022 default:
1023 av[na++] = n;
1024 if(na >= Maxarg)
1025 error("too many function arguments");
1026 break;
1030 static struct
1032 char *name;
1033 u64int val;
1034 } sregs[Maxarg/2];
1035 static int nsregs;
1037 static int
1038 straceregrw(Regs *regs, char *name, u64int *val, int isr)
1040 int i;
1042 if(!isr){
1043 werrstr("saved registers cannot be written");
1044 return -1;
1046 for(i=0; i<nsregs; i++)
1047 if(strcmp(sregs[i].name, name) == 0){
1048 *val = sregs[i].val;
1049 return 0;
1051 return rget(acidregs, name, val);
1054 void
1055 strace(Node *r, Node *args)
1057 Node *av[Maxarg], res;
1058 List *l;
1059 Regs regs;
1061 na = 0;
1062 flatten(av, args);
1064 if(na != 1)
1065 error("strace(list): want one arg");
1067 expr(av[0], &res);
1068 if(res.type != TLIST)
1069 error("strace(list): strace needs a list");
1070 l = res.store.u.l;
1071 if(listlen(l)%2)
1072 error("strace(list): strace needs an even-length list");
1073 for(nsregs=0; l; nsregs++){
1074 if(l->type != TSTRING)
1075 error("strace({r,v,r,v,...}): non-string name");
1076 sregs[nsregs].name = l->store.u.string->string;
1077 if(regdesc(sregs[nsregs].name) == nil)
1078 error("strace: bad register '%s'", sregs[nsregs].name);
1079 l = l->next;
1081 if(l == nil)
1082 error("cannot happen in strace");
1083 if(l->type != TINT)
1084 error("strace: non-int value for %s", sregs[nsregs].name);
1085 sregs[nsregs].val = l->store.u.ival;
1086 l = l->next;
1088 regs.rw = straceregrw;
1090 tracelist = 0;
1091 if(stacktrace(cormap, &regs, trlist) <= 0)
1092 error("no stack frame");
1093 r->type = TLIST;
1094 r->store.u.l = tracelist;
1097 void
1098 regerror(char *msg)
1100 error(msg);
1103 void
1104 regexp(Node *r, Node *args)
1106 Node res;
1107 Reprog *rp;
1108 Node *av[Maxarg];
1110 na = 0;
1111 flatten(av, args);
1112 if(na != 2)
1113 error("regexp(pattern, string): arg count");
1114 expr(av[0], &res);
1115 if(res.type != TSTRING)
1116 error("regexp(pattern, string): pattern must be string");
1117 rp = regcomp(res.store.u.string->string);
1118 if(rp == 0)
1119 return;
1121 expr(av[1], &res);
1122 if(res.type != TSTRING)
1123 error("regexp(pattern, string): bad string");
1125 r->store.fmt = 'D';
1126 r->type = TINT;
1127 r->store.u.ival = regexec(rp, res.store.u.string->string, 0, 0);
1128 free(rp);
1131 char vfmt[] = "aBbcCdDfFgGiIoOqQrRsSuUVxXYZ";
1133 void
1134 fmt(Node *r, Node *args)
1136 Node res;
1137 Node *av[Maxarg];
1139 na = 0;
1140 flatten(av, args);
1141 if(na != 2)
1142 error("fmt(obj, fmt): arg count");
1143 expr(av[1], &res);
1144 if(res.type != TINT || strchr(vfmt, res.store.u.ival) == 0)
1145 error("fmt(obj, fmt): bad format '%c'", (char)res.store.u.ival);
1146 expr(av[0], r);
1147 r->store.fmt = res.store.u.ival;
1150 void
1151 patom(char type, Store *res)
1153 int i;
1154 char buf[512];
1155 extern char *typenames[];
1156 Node *n;
1158 switch(type){
1159 case TREG:
1160 if(res->u.reg.thread)
1161 Bprint(bout, "register(\"%s\", %#ux)", res->u.reg.name, res->u.reg.thread);
1162 else
1163 Bprint(bout, "register(\"%s\")", res->u.reg.name);
1164 return;
1165 case TCON:
1166 Bprint(bout, "refconst(");
1167 n = res->u.con;
1168 patom(n->type, &n->store);
1169 Bprint(bout, ")");
1170 return;
1173 switch(res->fmt){
1174 case 'c':
1175 case 'C':
1176 case 'r':
1177 case 'B':
1178 case 'b':
1179 case 'X':
1180 case 'x':
1181 case 'W':
1182 case 'D':
1183 case 'd':
1184 case 'u':
1185 case 'U':
1186 case 'Z':
1187 case 'V':
1188 case 'Y':
1189 case 'o':
1190 case 'O':
1191 case 'q':
1192 case 'Q':
1193 case 'a':
1194 case 'A':
1195 case 'I':
1196 case 'i':
1197 if(type != TINT){
1198 badtype:
1199 Bprint(bout, "*%s\\%c*", typenames[(uchar)type], res->fmt);
1200 return;
1202 break;
1204 case 'f':
1205 case 'F':
1206 if(type != TFLOAT)
1207 goto badtype;
1208 break;
1210 case 's':
1211 case 'g':
1212 case 'G':
1213 case 'R':
1214 if(type != TSTRING)
1215 goto badtype;
1216 break;
1219 switch(res->fmt) {
1220 case 'c':
1221 Bprint(bout, "%c", (int)res->u.ival);
1222 break;
1223 case 'C':
1224 if(res->u.ival < ' ' || res->u.ival >= 0x7f)
1225 Bprint(bout, "%3d", (int)res->u.ival&0xff);
1226 else
1227 Bprint(bout, "%3c", (int)res->u.ival);
1228 break;
1229 case 'r':
1230 Bprint(bout, "%C", (int)res->u.ival);
1231 break;
1232 case 'B':
1233 memset(buf, '0', 34);
1234 buf[1] = 'b';
1235 for(i = 0; i < 32; i++) {
1236 if(res->u.ival & (1<<i))
1237 buf[33-i] = '1';
1239 buf[35] = '\0';
1240 Bprint(bout, "%s", buf);
1241 break;
1242 case 'b':
1243 Bprint(bout, "%#.2x", (int)res->u.ival&0xff);
1244 break;
1245 case 'X':
1246 Bprint(bout, "%#.8lux", (ulong)res->u.ival);
1247 break;
1248 case 'x':
1249 Bprint(bout, "%#.4lux", (ulong)res->u.ival&0xffff);
1250 break;
1251 case 'W':
1252 Bprint(bout, "%#.16llux", res->u.ival);
1253 break;
1254 case 'D':
1255 Bprint(bout, "%d", (int)res->u.ival);
1256 break;
1257 case 'd':
1258 Bprint(bout, "%d", (ushort)res->u.ival);
1259 break;
1260 case 'u':
1261 Bprint(bout, "%d", (int)res->u.ival&0xffff);
1262 break;
1263 case 'U':
1264 Bprint(bout, "%lud", (ulong)res->u.ival);
1265 break;
1266 case 'Z':
1267 Bprint(bout, "%llud", res->u.ival);
1268 break;
1269 case 'V':
1270 Bprint(bout, "%lld", res->u.ival);
1271 break;
1272 case 'Y':
1273 Bprint(bout, "%#.16llux", res->u.ival);
1274 break;
1275 case 'o':
1276 Bprint(bout, "%#.11uo", (int)res->u.ival&0xffff);
1277 break;
1278 case 'O':
1279 Bprint(bout, "%#.6uo", (int)res->u.ival);
1280 break;
1281 case 'q':
1282 Bprint(bout, "%#.11o", (short)(res->u.ival&0xffff));
1283 break;
1284 case 'Q':
1285 Bprint(bout, "%#.6o", (int)res->u.ival);
1286 break;
1287 case 'f':
1288 case 'F':
1289 Bprint(bout, "%g", res->u.fval);
1290 break;
1291 case 's':
1292 case 'g':
1293 case 'G':
1294 Bwrite(bout, res->u.string->string, res->u.string->len);
1295 break;
1296 case 'R':
1297 Bprint(bout, "%S", (Rune*)res->u.string->string);
1298 break;
1299 case 'a':
1300 case 'A':
1301 symoff(buf, sizeof(buf), res->u.ival, CANY);
1302 Bprint(bout, "%s", buf);
1303 break;
1304 case 'I':
1305 case 'i':
1306 if (symmap == nil || (*mach->das)(symmap, res->u.ival, res->fmt, buf, sizeof(buf)) < 0)
1307 Bprint(bout, "no instruction");
1308 else
1309 Bprint(bout, "%s", buf);
1310 break;
1314 void
1315 blprint(List *l)
1317 Store *res;
1319 Bprint(bout, "{");
1320 while(l) {
1321 switch(l->type) {
1322 case TINT:
1323 res = &l->store;
1324 if(res->fmt == 'c'){
1325 Bprint(bout, "\'%c\'", (int)res->u.ival);
1326 break;
1327 }else if(res->fmt == 'r'){
1328 Bprint(bout, "\'%C\'", (int)res->u.ival);
1329 break;
1331 /* fall through */
1332 default:
1333 patom(l->type, &l->store);
1334 break;
1335 case TSTRING:
1336 Bputc(bout, '"');
1337 patom(l->type, &l->store);
1338 Bputc(bout, '"');
1339 break;
1340 case TLIST:
1341 blprint(l->store.u.l);
1342 break;
1343 case TCODE:
1344 pcode(l->store.u.cc, 0);
1345 break;
1347 l = l->next;
1348 if(l)
1349 Bprint(bout, ", ");
1351 Bprint(bout, "}");
1354 int
1355 comx(Node res)
1357 Lsym *sl;
1358 Node *n, xx;
1360 if(res.store.fmt != 'a' && res.store.fmt != 'A')
1361 return 0;
1363 if(res.store.comt == 0 || res.store.comt->base == 0)
1364 return 0;
1366 sl = res.store.comt->base;
1367 if(sl->proc) {
1368 res.left = ZN;
1369 res.right = ZN;
1370 n = an(ONAME, ZN, ZN);
1371 n->sym = sl;
1372 n = an(OCALL, n, &res);
1373 n->left->sym = sl;
1374 expr(n, &xx);
1375 return 1;
1377 print("(%s)", sl->name);
1378 return 0;
1381 void
1382 bprint(Node *r, Node *args)
1384 int i, nas;
1385 Node res, *av[Maxarg];
1387 USED(r);
1388 na = 0;
1389 flatten(av, args);
1390 nas = na;
1391 for(i = 0; i < nas; i++) {
1392 expr(av[i], &res);
1393 switch(res.type) {
1394 default:
1395 if(comx(res))
1396 break;
1397 patom(res.type, &res.store);
1398 break;
1399 case TCODE:
1400 pcode(res.store.u.cc, 0);
1401 break;
1402 case TLIST:
1403 blprint(res.store.u.l);
1404 break;
1407 if(ret == 0)
1408 Bputc(bout, '\n');
1411 void
1412 printto(Node *r, Node *args)
1414 int fd;
1415 Biobuf *b;
1416 int i, nas;
1417 Node res, *av[Maxarg];
1419 USED(r);
1420 na = 0;
1421 flatten(av, args);
1422 nas = na;
1424 expr(av[0], &res);
1425 if(res.type != TSTRING)
1426 error("printto(string, ...): need string");
1428 fd = create(res.store.u.string->string, OWRITE, 0666);
1429 if(fd < 0)
1430 fd = open(res.store.u.string->string, OWRITE);
1431 if(fd < 0)
1432 error("printto: open %s: %r", res.store.u.string->string);
1434 b = gmalloc(sizeof(Biobuf));
1435 Binit(b, fd, OWRITE);
1437 Bflush(bout);
1438 io[iop++] = bout;
1439 bout = b;
1441 for(i = 1; i < nas; i++) {
1442 expr(av[i], &res);
1443 switch(res.type) {
1444 default:
1445 if(comx(res))
1446 break;
1447 patom(res.type, &res.store);
1448 break;
1449 case TLIST:
1450 blprint(res.store.u.l);
1451 break;
1454 if(ret == 0)
1455 Bputc(bout, '\n');
1457 Bterm(b);
1458 close(fd);
1459 free(b);
1460 bout = io[--iop];
1463 void
1464 pcfile(Node *r, Node *args)
1466 Node res;
1467 char *p, buf[128];
1469 if(args == 0)
1470 error("pcfile(addr): arg count");
1471 expr(args, &res);
1472 if(res.type != TINT)
1473 error("pcfile(addr): arg type");
1475 r->type = TSTRING;
1476 r->store.fmt = 's';
1477 if(fileline(res.store.u.ival, buf, sizeof(buf)) < 0) {
1478 r->store.u.string = strnode("?file?");
1479 return;
1481 p = strrchr(buf, ':');
1482 if(p == 0)
1483 error("pcfile(addr): funny file %s", buf);
1484 *p = '\0';
1485 r->store.u.string = strnode(buf);
1488 void
1489 pcline(Node *r, Node *args)
1491 Node res;
1492 char *p, buf[128];
1494 if(args == 0)
1495 error("pcline(addr): arg count");
1496 expr(args, &res);
1497 if(res.type != TINT)
1498 error("pcline(addr): arg type");
1500 r->type = TINT;
1501 r->store.fmt = 'D';
1502 if(fileline(res.store.u.ival, buf, sizeof(buf)) < 0) {
1503 r->store.u.ival = 0;
1504 return;
1507 p = strrchr(buf, ':');
1508 if(p == 0)
1509 error("pcline(addr): funny file %s", buf);
1510 r->store.u.ival = atoi(p+1);
1513 void
1514 textfile(Node *r, Node *args)
1516 char *file;
1517 long base;
1518 Fhdr *fp;
1519 Node res, *av[Maxarg];
1520 List *l, *l2, **tail, *list, *tl;
1522 na = 0;
1523 flatten(av, args);
1525 if(na != 0) {
1526 expr(av[0], &res);
1527 if(res.type != TLIST)
1528 error("textfile(list): textfile needs a list");
1529 if(listlen(res.store.u.l) != 2)
1530 error("textfile(list): list must have 2 entries");
1532 l = res.store.u.l;
1533 if(l->type != TSTRING)
1534 error("textfile name must be a string");
1535 file = l->store.u.string->string;
1537 l = l->next;
1538 if(l->type != TINT)
1539 error("textfile base must be an int");
1540 base = l->store.u.ival;
1542 if((fp = crackhdr(file, OREAD)) == nil)
1543 error("crackhdr %s: %r", file);
1544 Bflush(bout);
1545 fp->base = base;
1546 fprint(2, "%s: %s %s %s\n", file, fp->aname, fp->mname, fp->fname);
1547 if(mapfile(fp, base, symmap, nil) < 0)
1548 fprint(2, "mapping %s: %r\n", file);
1549 if(corhdr){
1550 unmapfile(corhdr, cormap);
1551 mapfile(fp, base, cormap, nil);
1552 free(correg);
1553 correg = nil;
1554 mapfile(corhdr, 0, cormap, &correg);
1556 if(symopen(fp) < 0)
1557 fprint(2, "symopen %s: %r\n", file);
1558 else
1559 addvarsym(fp);
1560 return;
1563 l2 = nil;
1564 tail = &l2;
1565 for(fp=fhdrlist; fp; fp=fp->next){
1566 if(fp->ftype == FCORE)
1567 continue;
1568 tl = al(TLIST);
1569 *tail = tl;
1570 tail = &tl->next;
1572 list = al(TSTRING);
1573 tl->store.u.l = list;
1574 list->store.u.string = strnode(fp->filename);
1575 list->store.fmt = 's';
1576 list->next = al(TINT);
1577 list = list->next;
1578 list->store.fmt = 'X';
1579 list->store.u.ival = fp->base;
1582 r->type = TLIST;
1583 r->store.u.l = l2;
1586 void
1587 deltextfile(Node *r, Node *args)
1589 int did;
1590 char *file;
1591 Fhdr *fp, *fpnext;
1592 Node res, *av[Maxarg];
1594 na = 0;
1595 flatten(av, args);
1597 if(na != 1)
1598 error("deltextfile(string): arg count");
1600 expr(av[0], &res);
1601 if(res.type != TSTRING)
1602 error("deltextfile(string): arg type");
1603 file = res.store.u.string->string;
1605 did = 0;
1606 for(fp=fhdrlist; fp; fp=fpnext){
1607 fpnext = fp->next;
1608 if(fp->ftype == FCORE)
1609 continue;
1610 if(strcmp(file, fp->filename) == 0){
1611 did = 1;
1612 if(fp == symhdr)
1613 error("cannot remove symbols from main text file");
1614 unmapfile(fp, symmap);
1615 uncrackhdr(fp);
1619 delvarsym(file);
1620 if(!did)
1621 error("symbol file %s not open", file);
1624 void
1625 stringn(Node *r, Node *args)
1627 uint addr;
1628 int i, n, ret;
1629 Node res, *av[Maxarg];
1630 char *buf;
1632 na = 0;
1633 flatten(av, args);
1634 if(na != 2)
1635 error("stringn(addr, n): arg count");
1637 expr(av[0], &res);
1638 if(res.type != TINT)
1639 error("stringn(addr, n): arg type");
1640 addr = res.store.u.ival;
1642 expr(av[1], &res);
1643 if(res.type != TINT)
1644 error("stringn(addr,n): arg type");
1645 n = res.store.u.ival;
1647 buf = malloc(n+1);
1648 if(buf == nil)
1649 error("out of memory");
1651 r->type = TSTRING;
1652 for(i=0; i<n; i++){
1653 ret = get1(cormap, addr, (uchar*)&buf[i], 1);
1654 if(ret < 0){
1655 free(buf);
1656 error("indir: %r");
1658 addr++;
1660 buf[n] = 0;
1661 r->store.u.string = strnode(buf);
1662 free(buf);