aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/acid/builtin.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-04-19 19:32:07 +0000
committerrsc <devnull@localhost>2004-04-19 19:32:07 +0000
commit564ca709d0e20d4fc46744bd858f14cff94ab382 (patch)
tree47bf49710238a6cb7112682e7bd0885f82544759 /src/cmd/acid/builtin.c
parent22a7368ef24d5c530a275dd0db0bd4f23b1c3ce3 (diff)
downloadplan9port-564ca709d0e20d4fc46744bd858f14cff94ab382.tar.gz
plan9port-564ca709d0e20d4fc46744bd858f14cff94ab382.tar.bz2
plan9port-564ca709d0e20d4fc46744bd858f14cff94ab382.zip
acid
Diffstat (limited to 'src/cmd/acid/builtin.c')
-rw-r--r--src/cmd/acid/builtin.c1460
1 files changed, 1460 insertions, 0 deletions
diff --git a/src/cmd/acid/builtin.c b/src/cmd/acid/builtin.c
new file mode 100644
index 00000000..492fdfb4
--- /dev/null
+++ b/src/cmd/acid/builtin.c
@@ -0,0 +1,1460 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <ctype.h>
+#include <mach.h>
+#include <regexp.h>
+#define Extern extern
+#include "acid.h"
+#include "y.tab.h"
+
+void cvtatof(Node*, Node*);
+void cvtatoi(Node*, Node*);
+void cvtitoa(Node*, Node*);
+void bprint(Node*, Node*);
+void funcbound(Node*, Node*);
+void printto(Node*, Node*);
+void getfile(Node*, Node*);
+void fmt(Node*, Node*);
+void pcfile(Node*, Node*);
+void pcline(Node*, Node*);
+void setproc(Node*, Node*);
+void strace(Node*, Node*);
+void follow(Node*, Node*);
+void reason(Node*, Node*);
+void newproc(Node*, Node*);
+void startstop(Node*, Node*);
+void match(Node*, Node*);
+void status(Node*, Node*);
+void xkill(Node*,Node*);
+void waitstop(Node*, Node*);
+void sysstop(Node*, Node*);
+void stop(Node*, Node*);
+void start(Node*, Node*);
+void filepc(Node*, Node*);
+void doerror(Node*, Node*);
+void rc(Node*, Node*);
+void doaccess(Node*, Node*);
+void map(Node*, Node*);
+void readfile(Node*, Node*);
+void interpret(Node*, Node*);
+void include(Node*, Node*);
+void includepipe(Node*, Node*);
+void regexp(Node*, Node*);
+void textfile(Node*, Node*);
+void deltextfile(Node*, Node*);
+
+typedef struct Btab Btab;
+struct Btab
+{
+ char *name;
+ void (*fn)(Node*, Node*);
+} tab[] =
+{
+ "atof", cvtatof,
+ "atoi", cvtatoi,
+ "deltextfile", deltextfile,
+ "error", doerror,
+ "file", getfile,
+ "readfile", readfile,
+ "access", doaccess,
+ "filepc", filepc,
+ "fnbound", funcbound,
+ "fmt", fmt,
+ "follow", follow,
+ "include", include,
+ "includepipe", includepipe,
+ "interpret", interpret,
+ "itoa", cvtitoa,
+ "kill", xkill,
+ "map", map,
+ "match", match,
+ "newproc", newproc,
+ "pcfile", pcfile,
+ "pcline", pcline,
+ "print", bprint,
+ "printto", printto,
+ "rc", rc,
+ "reason", reason,
+ "regexp", regexp,
+ "setproc", setproc,
+ "start", start,
+ "startstop", startstop,
+ "status", status,
+ "stop", stop,
+ "strace", strace,
+ "sysstop", sysstop,
+ "textfile", textfile,
+ "waitstop", waitstop,
+ 0
+};
+
+void
+mkprint(Lsym *s)
+{
+ prnt = malloc(sizeof(Node));
+ memset(prnt, 0, sizeof(Node));
+ prnt->op = OCALL;
+ prnt->left = malloc(sizeof(Node));
+ memset(prnt->left, 0, sizeof(Node));
+ prnt->left->sym = s;
+}
+
+void
+installbuiltin(void)
+{
+ Btab *b;
+ Lsym *s;
+
+ b = tab;
+ while(b->name) {
+ s = look(b->name);
+ if(s == 0)
+ s = enter(b->name, Tid);
+
+ s->builtin = b->fn;
+ if(b->fn == bprint)
+ mkprint(s);
+ b++;
+ }
+}
+
+void
+match(Node *r, Node *args)
+{
+ int i;
+ List *f;
+ Node *av[Maxarg];
+ Node resi, resl;
+
+ na = 0;
+ flatten(av, args);
+ if(na != 2)
+ error("match(obj, list): arg count");
+
+ expr(av[1], &resl);
+ if(resl.type != TLIST)
+ error("match(obj, list): need list");
+ expr(av[0], &resi);
+
+ r->op = OCONST;
+ r->type = TINT;
+ r->store.fmt = 'D';
+ r->store.u.ival = -1;
+
+ i = 0;
+ for(f = resl.store.u.l; f; f = f->next) {
+ if(resi.type == f->type) {
+ switch(resi.type) {
+ case TINT:
+ if(resi.store.u.ival == f->store.u.ival) {
+ r->store.u.ival = i;
+ return;
+ }
+ break;
+ case TFLOAT:
+ if(resi.store.u.fval == f->store.u.fval) {
+ r->store.u.ival = i;
+ return;
+ }
+ break;
+ case TSTRING:
+ if(scmp(resi.store.u.string, f->store.u.string)) {
+ r->store.u.ival = i;
+ return;
+ }
+ break;
+ case TLIST:
+ error("match(obj, list): not defined for list");
+ }
+ }
+ i++;
+ }
+}
+
+void
+newproc(Node *r, Node *args)
+{
+ int i;
+ Node res;
+ char *p, *e;
+ char *argv[Maxarg], buf[Strsize];
+
+ i = 1;
+ argv[0] = symfil;
+
+ if(args) {
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("newproc(): arg not string");
+ if(res.store.u.string->len >= sizeof(buf))
+ error("newproc(): too many arguments");
+ memmove(buf, res.store.u.string->string, res.store.u.string->len);
+ buf[res.store.u.string->len] = '\0';
+ p = buf;
+ e = buf+res.store.u.string->len;
+ for(;;) {
+ while(p < e && (*p == '\t' || *p == ' '))
+ *p++ = '\0';
+ if(p >= e)
+ break;
+ argv[i++] = p;
+ if(i >= Maxarg)
+ error("newproc: too many arguments");
+ while(p < e && *p != '\t' && *p != ' ')
+ p++;
+ }
+ }
+ argv[i] = 0;
+ r->op = OCONST;
+ r->type = TINT;
+ r->store.fmt = 'D';
+ r->store.u.ival = nproc(argv);
+}
+
+void
+startstop(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("startstop(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("startstop(pid): arg type");
+
+ msg(res.store.u.ival, "startstop");
+ notes(res.store.u.ival);
+ dostop(res.store.u.ival);
+}
+
+void
+waitstop(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("waitstop(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("waitstop(pid): arg type");
+
+ Bflush(bout);
+ msg(res.store.u.ival, "waitstop");
+ notes(res.store.u.ival);
+ dostop(res.store.u.ival);
+}
+
+void
+sysstop(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("waitstop(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("waitstop(pid): arg type");
+
+ Bflush(bout);
+ msg(res.store.u.ival, "sysstop");
+ notes(res.store.u.ival);
+ dostop(res.store.u.ival);
+}
+
+void
+start(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("start(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("start(pid): arg type");
+
+ msg(res.store.u.ival, "start");
+}
+
+void
+stop(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("stop(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("stop(pid): arg type");
+
+ Bflush(bout);
+ msg(res.store.u.ival, "stop");
+ notes(res.store.u.ival);
+ dostop(res.store.u.ival);
+}
+
+void
+xkill(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("kill(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("kill(pid): arg type");
+
+ msg(res.store.u.ival, "kill");
+ deinstall(res.store.u.ival);
+}
+
+void
+status(Node *r, Node *args)
+{
+ Node res;
+ char *p;
+
+ USED(r);
+ if(args == 0)
+ error("status(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("status(pid): arg type");
+
+ p = getstatus(res.store.u.ival);
+ r->store.u.string = strnode(p);
+ r->op = OCONST;
+ r->store.fmt = 's';
+ r->type = TSTRING;
+}
+
+void
+reason(Node *r, Node *args)
+{
+ Node res;
+
+ if(args == 0)
+ error("reason(cause): no cause");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("reason(cause): arg type");
+
+ r->op = OCONST;
+ r->type = TSTRING;
+ r->store.fmt = 's';
+ r->store.u.string = strnode((*mach->exc)(cormap, correg));
+}
+
+void
+follow(Node *r, Node *args)
+{
+ int n, i;
+ Node res;
+ ulong f[10];
+ List **tail, *l;
+
+ if(args == 0)
+ error("follow(addr): no addr");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("follow(addr): arg type");
+
+ n = (*mach->foll)(cormap, correg, res.store.u.ival, f);
+ if (n < 0)
+ error("follow(addr): %r");
+ tail = &r->store.u.l;
+ for(i = 0; i < n; i++) {
+ l = al(TINT);
+ l->store.u.ival = f[i];
+ l->store.fmt = 'X';
+ *tail = l;
+ tail = &l->next;
+ }
+}
+
+void
+funcbound(Node *r, Node *args)
+{
+ int n;
+ Node res;
+ ulong bounds[2];
+ List *l;
+
+ if(args == 0)
+ error("fnbound(addr): no addr");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("fnbound(addr): arg type");
+
+ n = fnbound(res.store.u.ival, bounds);
+ if (n != 0) {
+ r->store.u.l = al(TINT);
+ l = r->store.u.l;
+ l->store.u.ival = bounds[0];
+ l->store.fmt = 'X';
+ l->next = al(TINT);
+ l = l->next;
+ l->store.u.ival = bounds[1];
+ l->store.fmt = 'X';
+ }
+}
+
+void
+setproc(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("setproc(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("setproc(pid): arg type");
+
+ sproc(res.store.u.ival);
+}
+
+void
+filepc(Node *r, Node *args)
+{
+ int i;
+ Node res;
+ char *p, c;
+ ulong v;
+
+ if(args == 0)
+ error("filepc(filename:line): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("filepc(filename:line): arg type");
+
+ p = strchr(res.store.u.string->string, ':');
+ if(p == 0)
+ error("filepc(filename:line): bad arg format");
+
+ c = *p;
+ *p++ = '\0';
+ i = file2pc(res.store.u.string->string, atoi(p), &v);
+ p[-1] = c;
+ if(i < 0)
+ error("filepc(filename:line): can't find address");
+
+ r->op = OCONST;
+ r->type = TINT;
+ r->store.fmt = 'D';
+ r->store.u.ival = v;
+}
+
+void
+interpret(Node *r, Node *args)
+{
+ Node res;
+ int isave;
+
+ if(args == 0)
+ error("interpret(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("interpret(string): arg type");
+
+ pushstr(&res);
+
+ isave = interactive;
+ interactive = 0;
+ r->store.u.ival = yyparse();
+ interactive = isave;
+ popio();
+ r->op = OCONST;
+ r->type = TINT;
+ r->store.fmt = 'D';
+}
+
+void
+include(Node *r, Node *args)
+{
+ Node res;
+ int isave;
+
+ if(args == 0)
+ error("include(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("include(string): arg type");
+
+ Bflush(bout);
+ pushfile(res.store.u.string->string);
+
+ isave = interactive;
+ interactive = 0;
+ r->store.u.ival = yyparse();
+ interactive = isave;
+ popio();
+ r->op = OCONST;
+ r->type = TINT;
+ r->store.fmt = 'D';
+}
+
+void
+includepipe(Node *r, Node *args)
+{
+ Node res;
+ int i, isave, pid, pip[2];
+ char *argv[4];
+ Waitmsg *w;
+
+ USED(r);
+ if(args == 0)
+ error("includepipe(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("includepipe(string): arg type");
+
+ Bflush(bout);
+
+ argv[0] = "rc";
+ argv[1] = "-c";
+ argv[2] = res.store.u.string->string;
+ argv[3] = 0;
+
+ if(pipe(pip) < 0)
+ error("pipe: %r");
+
+ pid = fork();
+ switch(pid) {
+ case -1:
+ close(pip[0]);
+ close(pip[1]);
+ error("fork: %r");
+ case 0:
+ close(pip[0]);
+ close(0);
+ open("/dev/null", OREAD);
+ dup(pip[1], 1);
+ if(pip[1] > 1)
+ close(pip[1]);
+ for(i=3; i<100; i++)
+ close(i);
+ exec("rc", argv);
+ sysfatal("exec rc: %r");
+ }
+
+ close(pip[1]);
+ pushfd(pip[0]);
+
+ isave = interactive;
+ interactive = 0;
+ r->store.u.ival = yyparse();
+ interactive = isave;
+ popio();
+ r->op = OCONST;
+ r->type = TINT;
+ r->store.fmt = 'D';
+
+ w = waitfor(pid);
+ if(w->msg && w->msg[0])
+ error("includepipe(\"%s\"): %s", argv[2], w->msg); /* leaks w */
+ free(w);
+}
+
+void
+rc(Node *r, Node *args)
+{
+ Node res;
+ int pid;
+ char *p, *q, *argv[4];
+ Waitmsg *w;
+
+ USED(r);
+ if(args == 0)
+ error("rc(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("rc(string): arg type");
+
+ argv[0] = "rc";
+ argv[1] = "-c";
+ argv[2] = res.store.u.string->string;
+ argv[3] = 0;
+
+ pid = fork();
+ switch(pid) {
+ case -1:
+ error("fork %r");
+ case 0:
+ exec("rc", argv);
+ exits(0);
+ default:
+ w = waitfor(pid);
+ break;
+ }
+ p = w->msg;
+ q = strrchr(p, ':');
+ if (q)
+ p = q+1;
+
+ r->op = OCONST;
+ r->type = TSTRING;
+ r->store.u.string = strnode(p);
+ free(w);
+ r->store.fmt = 's';
+}
+
+void
+doerror(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(args == 0)
+ error("error(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("error(string): arg type");
+
+ error(res.store.u.string->string);
+}
+
+void
+doaccess(Node *r, Node *args)
+{
+ Node res;
+
+ if(args == 0)
+ error("access(filename): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("access(filename): arg type");
+
+ r->op = OCONST;
+ r->type = TINT;
+ r->store.u.ival = 0;
+ if(access(res.store.u.string->string, 4) == 0)
+ r->store.u.ival = 1;
+}
+
+void
+readfile(Node *r, Node *args)
+{
+ Node res;
+ int n, fd;
+ char *buf;
+ Dir *db;
+
+ if(args == 0)
+ error("readfile(filename): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("readfile(filename): arg type");
+
+ fd = open(res.store.u.string->string, OREAD);
+ if(fd < 0)
+ return;
+
+ db = dirfstat(fd);
+ if(db == nil || db->length == 0)
+ n = 8192;
+ else
+ n = db->length;
+ free(db);
+
+ buf = malloc(n);
+ n = read(fd, buf, n);
+
+ if(n > 0) {
+ r->op = OCONST;
+ r->type = TSTRING;
+ r->store.u.string = strnodlen(buf, n);
+ r->store.fmt = 's';
+ }
+ free(buf);
+ close(fd);
+}
+
+void
+getfile(Node *r, Node *args)
+{
+ int n;
+ char *p;
+ Node res;
+ String *s;
+ Biobuf *bp;
+ List **l, *new;
+
+ if(args == 0)
+ error("file(filename): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("file(filename): arg type");
+
+ r->op = OCONST;
+ r->type = TLIST;
+ r->store.u.l = 0;
+
+ p = res.store.u.string->string;
+ bp = Bopen(p, OREAD);
+ if(bp == 0)
+ return;
+
+ l = &r->store.u.l;
+ for(;;) {
+ p = Brdline(bp, '\n');
+ n = Blinelen(bp);
+ if(p == 0) {
+ if(n == 0)
+ break;
+ s = strnodlen(0, n);
+ Bread(bp, s->string, n);
+ }
+ else
+ s = strnodlen(p, n-1);
+
+ new = al(TSTRING);
+ new->store.u.string = s;
+ new->store.fmt = 's';
+ *l = new;
+ l = &new->next;
+ }
+ Bterm(bp);
+}
+
+void
+cvtatof(Node *r, Node *args)
+{
+ Node res;
+
+ if(args == 0)
+ error("atof(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("atof(string): arg type");
+
+ r->op = OCONST;
+ r->type = TFLOAT;
+ r->store.u.fval = atof(res.store.u.string->string);
+ r->store.fmt = 'f';
+}
+
+void
+cvtatoi(Node *r, Node *args)
+{
+ Node res;
+
+ if(args == 0)
+ error("atoi(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("atoi(string): arg type");
+
+ r->op = OCONST;
+ r->type = TINT;
+ r->store.u.ival = strtoul(res.store.u.string->string, 0, 0);
+ r->store.fmt = 'D';
+}
+
+void
+cvtitoa(Node *r, Node *args)
+{
+ Node res;
+ Node *av[Maxarg];
+ int ival;
+ char buf[128], *fmt;
+
+ if(args == 0)
+err:
+ error("itoa(number [, printformat]): arg count");
+ na = 0;
+ flatten(av, args);
+ if(na == 0 || na > 2)
+ goto err;
+ expr(av[0], &res);
+ if(res.type != TINT)
+ error("itoa(integer): arg type");
+ ival = (int)res.store.u.ival;
+ fmt = "%d";
+ if(na == 2){
+ expr(av[1], &res);
+ if(res.type != TSTRING)
+ error("itoa(integer, string): arg type");
+ fmt = res.store.u.string->string;
+ }
+
+ sprint(buf, fmt, ival);
+ r->op = OCONST;
+ r->type = TSTRING;
+ r->store.u.string = strnode(buf);
+ r->store.fmt = 's';
+}
+
+List*
+mapent(Map *m)
+{
+ int i;
+ List *l, *n, **t, *h;
+
+ h = 0;
+ t = &h;
+ for(i = 0; i < m->nseg; i++) {
+ l = al(TSTRING);
+ n = al(TLIST);
+ n->store.u.l = l;
+ *t = n;
+ t = &n->next;
+ l->store.u.string = strnode(m->seg[i].name);
+ l->store.fmt = 's';
+ l->next = al(TSTRING);
+ l = l->next;
+ l->store.u.string = strnode(m->seg[i].file ? m->seg[i].file : "");
+ l->store.fmt = 's';
+ l->next = al(TINT);
+ l = l->next;
+ l->store.u.ival = m->seg[i].base;
+ l->store.fmt = 'X';
+ l->next = al(TINT);
+ l = l->next;
+ l->store.u.ival = m->seg[i].base + m->seg[i].size;
+ l->store.fmt = 'X';
+ l->next = al(TINT);
+ l = l->next;
+ l->store.u.ival = m->seg[i].offset;
+ l->store.fmt = 'X';
+ }
+ return h;
+}
+
+void
+map(Node *r, Node *args)
+{
+ int i;
+ Map *m;
+ List *l;
+ char *nam, *fil;
+ Node *av[Maxarg], res;
+
+ na = 0;
+ flatten(av, args);
+
+ if(na != 0) {
+ expr(av[0], &res);
+ if(res.type != TLIST)
+ error("map(list): map needs a list");
+ if(listlen(res.store.u.l) != 5)
+ error("map(list): list must have 5 entries");
+
+ l = res.store.u.l;
+ if(l->type != TSTRING)
+ error("map name must be a string");
+ nam = l->store.u.string->string;
+ l = l->next;
+ if(l->type != TSTRING)
+ error("map file must be a string");
+ fil = l->store.u.string->string;
+ m = symmap;
+ i = findseg(m, nam, fil);
+ if(i < 0) {
+ m = cormap;
+ i = findseg(m, nam, fil);
+ }
+ if(i < 0)
+ error("%s %s is not a map entry", nam, fil);
+ l = l->next;
+ if(l->type != TINT)
+ error("map entry not int");
+ m->seg[i].base = l->store.u.ival;
+/*
+ if (strcmp(ent, "text") == 0)
+ textseg(l->store.u.ival, &fhdr);
+*/
+ l = l->next;
+ if(l->type != TINT)
+ error("map entry not int");
+ m->seg[i].size = l->store.u.ival - m->seg[i].base;
+ l = l->next;
+ if(l->type != TINT)
+ error("map entry not int");
+ m->seg[i].offset = l->store.u.ival;
+ }
+
+ r->type = TLIST;
+ r->store.u.l = 0;
+ if(symmap)
+ r->store.u.l = mapent(symmap);
+ if(cormap) {
+ if(r->store.u.l == 0)
+ r->store.u.l = mapent(cormap);
+ else {
+ for(l = r->store.u.l; l->next; l = l->next)
+ ;
+ l->next = mapent(cormap);
+ }
+ }
+}
+
+void
+flatten(Node **av, Node *n)
+{
+ if(n == 0)
+ return;
+
+ switch(n->op) {
+ case OLIST:
+ flatten(av, n->left);
+ flatten(av, n->right);
+ break;
+ default:
+ av[na++] = n;
+ if(na >= Maxarg)
+ error("too many function arguments");
+ break;
+ }
+}
+
+static struct
+{
+ char *name;
+ ulong val;
+} sregs[Maxarg/2];
+static int nsregs;
+
+static int
+straceregrw(Regs *regs, char *name, ulong *val, int isr)
+{
+ int i;
+
+ if(!isr){
+ werrstr("saved registers cannot be written");
+ return -1;
+ }
+ for(i=0; i<nsregs; i++)
+ if(strcmp(sregs[i].name, name) == 0){
+ *val = sregs[i].val;
+ return 0;
+ }
+ return rget(correg, name, val);
+}
+
+void
+strace(Node *r, Node *args)
+{
+ Node *av[Maxarg], res;
+ List *l;
+ Regs regs;
+
+ na = 0;
+ flatten(av, args);
+
+ if(na != 1)
+ error("strace(list): want one arg");
+
+ expr(av[0], &res);
+ if(res.type != TLIST)
+ error("strace(list): strace needs a list");
+ l = res.store.u.l;
+ if(listlen(l)%2)
+ error("strace(list): strace needs an even-length list");
+ for(nsregs=0; l; nsregs++){
+ if(l->type != TSTRING)
+ error("strace({r,v,r,v,...}): non-string name");
+ sregs[nsregs].name = l->store.u.string->string;
+ if(regdesc(sregs[nsregs].name) == nil)
+ error("strace: bad register '%s'", sregs[nsregs].name);
+ l = l->next;
+
+ if(l == nil)
+ error("cannot happen in strace");
+ if(l->type != TINT)
+ error("strace: non-int value for %s", sregs[nsregs].name);
+ sregs[nsregs].val = l->store.u.ival;
+ l = l->next;
+ }
+ regs.rw = straceregrw;
+
+ tracelist = 0;
+ if(stacktrace(cormap, &regs, trlist) <= 0)
+ error("no stack frame");
+ r->type = TLIST;
+ r->store.u.l = tracelist;
+}
+
+void
+regerror(char *msg)
+{
+ error(msg);
+}
+
+void
+regexp(Node *r, Node *args)
+{
+ Node res;
+ Reprog *rp;
+ Node *av[Maxarg];
+
+ na = 0;
+ flatten(av, args);
+ if(na != 2)
+ error("regexp(pattern, string): arg count");
+ expr(av[0], &res);
+ if(res.type != TSTRING)
+ error("regexp(pattern, string): pattern must be string");
+ rp = regcomp(res.store.u.string->string);
+ if(rp == 0)
+ return;
+
+ expr(av[1], &res);
+ if(res.type != TSTRING)
+ error("regexp(pattern, string): bad string");
+
+ r->store.fmt = 'D';
+ r->type = TINT;
+ r->store.u.ival = regexec(rp, res.store.u.string->string, 0, 0);
+ free(rp);
+}
+
+char vfmt[] = "aBbcCdDfFgGiIoOqQrRsSuUVxXYZ";
+
+void
+fmt(Node *r, Node *args)
+{
+ Node res;
+ Node *av[Maxarg];
+
+ na = 0;
+ flatten(av, args);
+ if(na != 2)
+ error("fmt(obj, fmt): arg count");
+ expr(av[1], &res);
+ if(res.type != TINT || strchr(vfmt, res.store.u.ival) == 0)
+ error("fmt(obj, fmt): bad format '%c'", (char)res.store.u.ival);
+ expr(av[0], r);
+ r->store.fmt = res.store.u.ival;
+}
+
+void
+patom(char type, Store *res)
+{
+ int i;
+ char buf[512];
+ extern char *typenames[];
+
+ switch(res->fmt) {
+ case 'c':
+ Bprint(bout, "%c", (int)res->u.ival);
+ break;
+ case 'C':
+ if(res->u.ival < ' ' || res->u.ival >= 0x7f)
+ Bprint(bout, "%3d", (int)res->u.ival&0xff);
+ else
+ Bprint(bout, "%3c", (int)res->u.ival);
+ break;
+ case 'r':
+ Bprint(bout, "%C", (int)res->u.ival);
+ break;
+ case 'B':
+ memset(buf, '0', 34);
+ buf[1] = 'b';
+ for(i = 0; i < 32; i++) {
+ if(res->u.ival & (1<<i))
+ buf[33-i] = '1';
+ }
+ buf[35] = '\0';
+ Bprint(bout, "%s", buf);
+ break;
+ case 'b':
+ Bprint(bout, "%.2x", (int)res->u.ival&0xff);
+ break;
+ case 'X':
+ Bprint(bout, "%.8lux", (ulong)res->u.ival);
+ break;
+ case 'x':
+ Bprint(bout, "%.4lux", (ulong)res->u.ival&0xffff);
+ break;
+ case 'W':
+ Bprint(bout, "%.16llux", res->u.ival);
+ break;
+ case 'D':
+ Bprint(bout, "%d", (int)res->u.ival);
+ break;
+ case 'd':
+ Bprint(bout, "%d", (ushort)res->u.ival);
+ break;
+ case 'u':
+ Bprint(bout, "%d", (int)res->u.ival&0xffff);
+ break;
+ case 'U':
+ Bprint(bout, "%lud", (ulong)res->u.ival);
+ break;
+ case 'Z':
+ Bprint(bout, "%llud", res->u.ival);
+ break;
+ case 'V':
+ Bprint(bout, "%lld", res->u.ival);
+ break;
+ case 'Y':
+ Bprint(bout, "%.16llux", res->u.ival);
+ break;
+ case 'o':
+ Bprint(bout, "0%.11uo", (int)res->u.ival&0xffff);
+ break;
+ case 'O':
+ Bprint(bout, "0%.6uo", (int)res->u.ival);
+ break;
+ case 'q':
+ Bprint(bout, "0%.11o", (short)(res->u.ival&0xffff));
+ break;
+ case 'Q':
+ Bprint(bout, "0%.6o", (int)res->u.ival);
+ break;
+ case 'f':
+ case 'F':
+ if(type != TFLOAT)
+ Bprint(bout, "*%c<%s>*", res->fmt, typenames[(uchar)type]);
+ else
+ Bprint(bout, "%g", res->u.fval);
+ break;
+ case 's':
+ case 'g':
+ case 'G':
+ if(type != TSTRING)
+ Bprint(bout, "*%c<%s>*", res->fmt, typenames[(uchar)type]);
+ else
+ Bwrite(bout, res->u.string->string, res->u.string->len);
+ break;
+ case 'R':
+ if(type != TSTRING)
+ Bprint(bout, "*%c<%s>*", res->fmt, typenames[(uchar)type]);
+ else
+ Bprint(bout, "%S", (Rune*)res->u.string->string);
+ break;
+ case 'a':
+ case 'A':
+ symoff(buf, sizeof(buf), res->u.ival, CANY);
+ Bprint(bout, "%s", buf);
+ break;
+ case 'I':
+ case 'i':
+ if(type != TINT)
+ Bprint(bout, "*%c<%s>*", res->fmt, typenames[(uchar)type]);
+ else {
+ if (symmap == nil || (*mach->das)(symmap, res->u.ival, res->fmt, buf, sizeof(buf)) < 0)
+ Bprint(bout, "no instruction");
+ else
+ Bprint(bout, "%s", buf);
+ }
+ break;
+ }
+}
+
+void
+blprint(List *l)
+{
+ Store *res;
+
+ Bprint(bout, "{");
+ while(l) {
+ switch(l->type) {
+ case TINT:
+ res = &l->store;
+ if(res->fmt == 'c'){
+ Bprint(bout, "\'%c\'", (int)res->u.ival);
+ break;
+ }else if(res->fmt == 'r'){
+ Bprint(bout, "\'%C\'", (int)res->u.ival);
+ break;
+ }
+ /* fall through */
+ default:
+ patom(l->type, &l->store);
+ break;
+ case TSTRING:
+ Bputc(bout, '"');
+ patom(l->type, &l->store);
+ Bputc(bout, '"');
+ break;
+ case TLIST:
+ blprint(l->store.u.l);
+ break;
+ case TCODE:
+ pcode(l->store.u.cc, 0);
+ break;
+ }
+ l = l->next;
+ if(l)
+ Bprint(bout, ", ");
+ }
+ Bprint(bout, "}");
+}
+
+int
+comx(Node res)
+{
+ Lsym *sl;
+ Node *n, xx;
+
+ if(res.store.fmt != 'a' && res.store.fmt != 'A')
+ return 0;
+
+ if(res.store.comt == 0 || res.store.comt->base == 0)
+ return 0;
+
+ sl = res.store.comt->base;
+ if(sl->proc) {
+ res.left = ZN;
+ res.right = ZN;
+ n = an(ONAME, ZN, ZN);
+ n->sym = sl;
+ n = an(OCALL, n, &res);
+ n->left->sym = sl;
+ expr(n, &xx);
+ return 1;
+ }
+ print("(%s)", sl->name);
+ return 0;
+}
+
+void
+bprint(Node *r, Node *args)
+{
+ int i, nas;
+ Node res, *av[Maxarg];
+
+ USED(r);
+ na = 0;
+ flatten(av, args);
+ nas = na;
+ for(i = 0; i < nas; i++) {
+ expr(av[i], &res);
+ switch(res.type) {
+ default:
+ if(comx(res))
+ break;
+ patom(res.type, &res.store);
+ break;
+ case TCODE:
+ pcode(res.store.u.cc, 0);
+ break;
+ case TLIST:
+ blprint(res.store.u.l);
+ break;
+ }
+ }
+ if(ret == 0)
+ Bputc(bout, '\n');
+}
+
+void
+printto(Node *r, Node *args)
+{
+ int fd;
+ Biobuf *b;
+ int i, nas;
+ Node res, *av[Maxarg];
+
+ USED(r);
+ na = 0;
+ flatten(av, args);
+ nas = na;
+
+ expr(av[0], &res);
+ if(res.type != TSTRING)
+ error("printto(string, ...): need string");
+
+ fd = create(res.store.u.string->string, OWRITE, 0666);
+ if(fd < 0)
+ fd = open(res.store.u.string->string, OWRITE);
+ if(fd < 0)
+ error("printto: open %s: %r", res.store.u.string->string);
+
+ b = gmalloc(sizeof(Biobuf));
+ Binit(b, fd, OWRITE);
+
+ Bflush(bout);
+ io[iop++] = bout;
+ bout = b;
+
+ for(i = 1; i < nas; i++) {
+ expr(av[i], &res);
+ switch(res.type) {
+ default:
+ if(comx(res))
+ break;
+ patom(res.type, &res.store);
+ break;
+ case TLIST:
+ blprint(res.store.u.l);
+ break;
+ }
+ }
+ if(ret == 0)
+ Bputc(bout, '\n');
+
+ Bterm(b);
+ close(fd);
+ free(b);
+ bout = io[--iop];
+}
+
+void
+pcfile(Node *r, Node *args)
+{
+ Node res;
+ char *p, buf[128];
+
+ if(args == 0)
+ error("pcfile(addr): arg count");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("pcfile(addr): arg type");
+
+ r->type = TSTRING;
+ r->store.fmt = 's';
+ if(fileline(res.store.u.ival, buf, sizeof(buf)) < 0) {
+ r->store.u.string = strnode("?file?");
+ return;
+ }
+ p = strrchr(buf, ':');
+ if(p == 0)
+ error("pcfile(addr): funny file %s", buf);
+ *p = '\0';
+ r->store.u.string = strnode(buf);
+}
+
+void
+pcline(Node *r, Node *args)
+{
+ Node res;
+ char *p, buf[128];
+
+ if(args == 0)
+ error("pcline(addr): arg count");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("pcline(addr): arg type");
+
+ r->type = TINT;
+ r->store.fmt = 'D';
+ if(fileline(res.store.u.ival, buf, sizeof(buf)) < 0) {
+ r->store.u.ival = 0;
+ return;
+ }
+
+ p = strrchr(buf, ':');
+ if(p == 0)
+ error("pcline(addr): funny file %s", buf);
+ r->store.u.ival = atoi(p+1);
+}
+
+void
+textfile(Node *r, Node *args)
+{
+ char *file;
+ long base;
+ Fhdr *fp;
+ Node res, *av[Maxarg];
+ List *l, *l2, **tail, *list, *tl;
+
+ na = 0;
+ flatten(av, args);
+
+ if(na != 0) {
+ expr(av[0], &res);
+ if(res.type != TLIST)
+ error("textfile(list): textfile needs a list");
+ if(listlen(res.store.u.l) != 2)
+ error("textfile(list): list must have 2 entries");
+
+ l = res.store.u.l;
+ if(l->type != TSTRING)
+ error("textfile name must be a string");
+ file = l->store.u.string->string;
+
+ l = l->next;
+ if(l->type != TINT)
+ error("textfile base must be an int");
+ base = l->store.u.ival;
+
+ if((fp = crackhdr(file, OREAD)) == nil)
+ error("crackhdr %s: %r", file);
+ Bflush(bout);
+ fp->base = base;
+ fprint(2, "%s: %s %s %s\n", file, fp->aname, fp->mname, fp->fname);
+ if(mapfile(fp, base, symmap, nil) < 0)
+ fprint(2, "mapping %s: %r\n", file);
+ if(corhdr){
+ unmapfile(corhdr, cormap);
+ mapfile(fp, base, cormap, nil);
+ free(correg);
+ mapfile(corhdr, 0, cormap, &correg);
+ }
+ if(syminit(fp) < 0)
+ fprint(2, "syminit %s: %r\n", file);
+ else
+ addvarsym(fp);
+ return;
+ }
+
+ l2 = nil;
+ tail = &l2;
+ for(fp=fhdrlist; fp; fp=fp->next){
+ if(fp->ftype == FCORE)
+ continue;
+ tl = al(TLIST);
+ *tail = tl;
+ tail = &tl->next;
+
+ list = al(TSTRING);
+ tl->store.u.l = list;
+ list->store.u.string = strnode(fp->filename);
+ list->store.fmt = 's';
+ list->next = al(TINT);
+ list = list->next;
+ list->store.fmt = 'X';
+ list->store.u.ival = fp->base;
+ }
+
+ r->type = TLIST;
+ r->store.u.l = l2;
+}
+
+void
+deltextfile(Node *r, Node *args)
+{
+ int did;
+ char *file;
+ Fhdr *fp, *fpnext;
+ Node res, *av[Maxarg];
+
+ na = 0;
+ flatten(av, args);
+
+ if(na != 1)
+ error("deltextfile(string): arg count");
+
+ expr(av[0], &res);
+ if(res.type != TSTRING)
+ error("deltextfile(string): arg type");
+ file = res.store.u.string->string;
+
+ did = 0;
+ for(fp=fhdrlist; fp; fp=fpnext){
+ fpnext = fp->next;
+ if(fp->ftype == FCORE)
+ continue;
+ if(strcmp(file, fp->filename) == 0){
+ did = 1;
+ if(fp == symhdr)
+ error("cannot remove symbols from main text file");
+ unmapfile(fp, symmap);
+ uncrackhdr(fp);
+ }
+ }
+
+ delvarsym(file);
+ if(!did)
+ error("symbol file %s not open", file);
+}
+