diff options
author | rsc <devnull@localhost> | 2004-04-19 19:32:07 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2004-04-19 19:32:07 +0000 |
commit | 564ca709d0e20d4fc46744bd858f14cff94ab382 (patch) | |
tree | 47bf49710238a6cb7112682e7bd0885f82544759 /src/cmd/acid | |
parent | 22a7368ef24d5c530a275dd0db0bd4f23b1c3ce3 (diff) | |
download | plan9port-564ca709d0e20d4fc46744bd858f14cff94ab382.tar.gz plan9port-564ca709d0e20d4fc46744bd858f14cff94ab382.tar.bz2 plan9port-564ca709d0e20d4fc46744bd858f14cff94ab382.zip |
acid
Diffstat (limited to 'src/cmd/acid')
-rw-r--r-- | src/cmd/acid/Notes | 49 | ||||
-rw-r--r-- | src/cmd/acid/acid.h | 313 | ||||
-rw-r--r-- | src/cmd/acid/builtin.c | 1460 | ||||
-rw-r--r-- | src/cmd/acid/dbg.y | 413 | ||||
-rw-r--r-- | src/cmd/acid/dot.c | 153 | ||||
-rw-r--r-- | src/cmd/acid/exec.c | 538 | ||||
-rw-r--r-- | src/cmd/acid/expr.c | 1018 | ||||
-rw-r--r-- | src/cmd/acid/lex.c | 661 | ||||
-rw-r--r-- | src/cmd/acid/list.c | 270 | ||||
-rw-r--r-- | src/cmd/acid/main.c | 630 | ||||
-rw-r--r-- | src/cmd/acid/mkfile | 32 | ||||
-rw-r--r-- | src/cmd/acid/print.c | 446 | ||||
-rw-r--r-- | src/cmd/acid/proc.c | 251 | ||||
-rw-r--r-- | src/cmd/acid/util.c | 344 |
14 files changed, 6578 insertions, 0 deletions
diff --git a/src/cmd/acid/Notes b/src/cmd/acid/Notes new file mode 100644 index 00000000..597bf58c --- /dev/null +++ b/src/cmd/acid/Notes @@ -0,0 +1,49 @@ +Changes from the Plan 9 acid (beyond the +obvious changes necessary to compile without +Ken's compiler and with the new libmach interface). +======================================== + +the input-line print verb is %Z, so that %L can be for locations + +the register block is explicitly "mapped" at 0 by xget1, xget2, ... + for compatibility with old acid, even though libmach + doesn't participate in this lie anymore. + +main accepts pid, file, and core in any order + +the ptab only records pids (no ctl fd anymore). + +new builtin sysstop(pid) runs pid until the next syscall + +map() returns 5-tuples: (name, filename, base, end, offset) + filename is new + +map() expects a 5-tuple too + +strace expects a list of register names and values like + {"PC", *PC, "SP", *SP} + +strace returns 5-tuples now: + {fn, pc, callerpc, paramlist, locallist} + +new builtin includepipe(cmd) includes the standard output + of running cmd. + +symbols returns 4-tuples now: {name, type, addr, file} + +new builtin textfile() returns the current set of open text files + as a list of {file, base} pairs. + +new builtin textfile({file, base}) adds a new file's symbols and text + offset by base for relocatables. + +new builtin deltextfile(file) removes a file from the set of open text files. + +both textfile and deltextfile update symbols. + +==== + +yet to be done: + +elflink has the linking info for elf on linux + diff --git a/src/cmd/acid/acid.h b/src/cmd/acid/acid.h new file mode 100644 index 00000000..729341b3 --- /dev/null +++ b/src/cmd/acid/acid.h @@ -0,0 +1,313 @@ +/* acid.h */ +enum +{ + Eof = -1, + Strsize = 4096, + Hashsize = 128, + Maxarg = 512, + NFD = 100, + Maxproc = 50, + Maxval = 10, + Mempergc = 1024*1024, +}; + +/* #pragma varargck type "L" void */ + +typedef struct Node Node; +typedef struct String String; +typedef struct Lsym Lsym; +typedef struct List List; +typedef struct Store Store; +typedef struct Gc Gc; +typedef struct Strc Strc; +typedef struct Rplace Rplace; +typedef struct Ptab Ptab; +typedef struct Value Value; +typedef struct Type Type; +typedef struct Frtype Frtype; + +Extern int kernel; +Extern int nlcount; +Extern int remote; +Extern int text; +Extern int cor; +Extern int silent; +Extern Fhdr *fhdr; +Extern Fhdr *chdr; +Extern int line; +Extern Biobuf* bout; +Extern Biobuf* io[32]; +Extern int iop; +Extern int pid; +Extern char symbol[Strsize]; +Extern int interactive; +Extern Node* code; +Extern int na; +Extern int wtflag; +Extern Regs* correg; +Extern Map* cormap; +Extern Map* symmap; +Extern Lsym* hash[Hashsize]; +Extern long dogc; +Extern Rplace* ret; +Extern char* symfil; +Extern char* corfil; +Extern int gotint; +Extern long flen; +Extern Gc* gcl; +Extern int stacked; +Extern jmp_buf err; +Extern Node* prnt; +Extern Node* fomt; +Extern List* tracelist; +Extern int initialising; +Extern int quiet; +Extern Fhdr* corhdr; +Extern Fhdr* symhdr; + +extern void (*expop[])(Node*, Node*); +#define expr(n, r) (r)->store.comt=0; (*expop[(unsigned char)((n)->op)])(n, r); + +enum +{ + TINT, + TFLOAT, + TSTRING, + TLIST, + TCODE, +}; + +struct Type +{ + Type* next; + int offset; + char fmt; + char depth; + Lsym* type; + Lsym* tag; + Lsym* base; +}; + +struct Frtype +{ + Lsym* var; + Type* type; + Frtype* next; +}; + +struct Ptab +{ + int pid; +/* int ctl; */ +}; +Extern Ptab ptab[Maxproc]; + +struct Rplace +{ + jmp_buf rlab; + Node* stak; + Node* val; + Lsym* local; + Lsym** tail; +}; + +struct Gc +{ + char gcmark; + Gc* gclink; +}; + +struct Store +{ + char fmt; + Type* comt; + union { + vlong ival; + double fval; + String* string; + List* l; + Node* cc; + } u; +}; + +struct List +{ + Gc gc; + List* next; + char type; + Store store; +}; + +struct Value +{ + char set; + char type; + Store store; + Value* pop; + Lsym* scope; + Rplace* ret; +}; + +struct Lsym +{ + char* name; + int lexval; + Lsym* hash; + Value* v; + Type* lt; + Node* proc; + Frtype* local; + void (*builtin)(Node*, Node*); +}; + +struct Node +{ + Gc gc; + char op; + char type; + Node* left; + Node* right; + Lsym* sym; + int builtin; + Store store; +}; +#define ZN (Node*)0 + +struct String +{ + Gc gc; + char *string; + int len; +}; + +List* addlist(List*, List*); +void addvarsym(Fhdr*); +List* al(int); +Node* an(int, Node*, Node*); +void append(Node*, Node*, Node*); +int bool(Node*); +void build(Node*); +void call(char*, Node*, Node*, Node*, Node*); +void catcher(void*, char*); +void checkqid(int, int); +void cmd(void); +Node* con(int); +List* construct(Node*); +void ctrace(int); +void decl(Node*); +void defcomplex(Node*, Node*); +void deinstall(int); +void delete(List*, int n, Node*); +void delvarsym(char*); +void dostop(int); +Lsym* enter(char*, int); +void error(char*, ...); +void execute(Node*); +void fatal(char*, ...); +ulong findframe(ulong); +void flatten(Node**, Node*); +void gc(void); +char* getstatus(int); +void* gmalloc(long); +void indir(Map*, ulong, char, Node*); +void installbuiltin(void); +void kinit(void); +int Zfmt(Fmt*); +int listcmp(List*, List*); +int listlen(List*); +List* listvar(char*, long); +void loadmodule(char*); +void loadvars(void); +Lsym* look(char*); +void ltag(char*); +void marklist(List*); +Lsym* mkvar(char*); +void msg(int, char*); +void notes(int); +int nproc(char**); +void nthelem(List*, int, Node*); +int numsym(char); +void odot(Node*, Node*); +void pcode(Node*, int); +void pexpr(Node*); +int popio(void); +void pstr(String*); +void pushfd(int); +void pushfile(char*); +void pushstr(Node*); +ulong raddr(char*); +void readtext(char*); +void readcore(void); +void restartio(void); +String *runenode(Rune*); +int scmp(String*, String*); +void sproc(int); +String* stradd(String*, String*); +String* strnode(char*); +String* strnodlen(char*, int); +#define system acidsystem +char* system(void); +int trlist(Map*, Regs*, ulong, ulong, Symbol*, int); +void unwind(void); +void userinit(void); +void varreg(void); +void varsym(void); +Waitmsg* waitfor(int); +void whatis(Lsym*); +void windir(Map*, Node*, Node*, Node*); +void yyerror(char*, ...); +int yylex(void); +int yyparse(void); + +enum +{ + ONAME, + OCONST, + OMUL, + ODIV, + OMOD, + OADD, + OSUB, + ORSH, + OLSH, + OLT, + OGT, + OLEQ, + OGEQ, + OEQ, + ONEQ, + OLAND, + OXOR, + OLOR, + OCAND, + OCOR, + OASGN, + OINDM, + OEDEC, + OEINC, + OPINC, + OPDEC, + ONOT, + OIF, + ODO, + OLIST, + OCALL, + OCTRUCT, + OWHILE, + OELSE, + OHEAD, + OTAIL, + OAPPEND, + ORET, + OINDEX, + OINDC, + ODOT, + OLOCAL, + OFRAME, + OCOMPLEX, + ODELETE, + OCAST, + OFMT, + OEVAL, + OWHAT, +}; 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, ®s, 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); +} + diff --git a/src/cmd/acid/dbg.y b/src/cmd/acid/dbg.y new file mode 100644 index 00000000..afdf538c --- /dev/null +++ b/src/cmd/acid/dbg.y @@ -0,0 +1,413 @@ +%{ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> +#define Extern extern +#include "acid.h" +%} + +%union +{ + Node *node; + Lsym *sym; + ulong ival; + float fval; + String *string; +} + +%type <node> expr monexpr term stmnt name args zexpr slist +%type <node> member members mname castexpr idlist +%type <sym> zname + +%left ';' +%right '=' +%left Tfmt +%left Toror +%left Tandand +%left '|' +%left '^' +%left '&' +%left Teq Tneq +%left '<' '>' Tleq Tgeq +%left Tlsh Trsh +%left '+' '-' +%left '*' '/' '%' +%right Tdec Tinc Tindir '.' '[' '(' + +%token <sym> Tid +%token <ival> Tconst Tfmt +%token <fval> Tfconst +%token <string> Tstring +%token Tif Tdo Tthen Telse Twhile Tloop Thead Ttail Tappend Tfn Tret Tlocal +%token Tcomplex Twhat Tdelete Teval Tbuiltin + +%% + +prog : + | prog bigstmnt + ; + +bigstmnt : stmnt + { + /* hold on to current command for gc */ + mkvar("_thiscmd")->proc = $1; + execute($1); + gc(); + if(interactive && nlcount){ + Bprint(bout, "acid; "); + nlcount = 0; + } + } + | Tfn Tid '(' args ')' zsemi '{' slist '}' + { + $2->proc = an(OLIST, $4, $8); + } + | Tfn Tid + { + $2->proc = nil; + } + | Tcomplex name '{' members '}' ';' + { + defcomplex($2, $4); + } + ; + +zsemi : + | ';' zsemi + +members : member + | members member + { + $$ = an(OLIST, $1, $2); + } + ; + +mname : Tid + { + $$ = an(ONAME, ZN, ZN); + $$->sym = $1; + } + ; + +member : Tconst Tconst mname ';' + { + $3->store.u.ival = $2; + $3->store.fmt = $1; + $$ = $3; + } + | Tconst mname Tconst mname ';' + { + $4->store.u.ival = $3; + $4->store.fmt = $1; + $4->right = $2; + $$ = $4; + } + | mname Tconst mname ';' + { + $3->store.u.ival = $2; + $3->left = $1; + $$ = $3; + } + | '{' members '}' ';' + { + $$ = an(OCTRUCT, $2, ZN); + } + ; + +zname : + { $$ = 0; } + | Tid + ; + +slist : stmnt + | slist stmnt + { + $$ = an(OLIST, $1, $2); + } + ; + +stmnt : zexpr ';' + | '{' slist '}' + { + $$ = $2; + } + | Tif expr Tthen stmnt + { + $$ = an(OIF, $2, $4); + } + | Tif expr Tthen stmnt Telse stmnt + { + $$ = an(OIF, $2, an(OELSE, $4, $6)); + } + | Tloop expr ',' expr Tdo stmnt + { + $$ = an(ODO, an(OLIST, $2, $4), $6); + } + | Twhile expr Tdo stmnt + { + $$ = an(OWHILE, $2, $4); + } + | Tret expr ';' + { + $$ = an(ORET, $2, ZN); + } + | Tlocal idlist + { + $$ = an(OLOCAL, $2, ZN); + } + | Tcomplex Tid name ';' + { + $$ = an(OCOMPLEX, $3, ZN); + $$->sym = $2; + } + ; + +idlist : Tid + { + $$ = an(ONAME, ZN, ZN); + $$->sym = $1; + } + | idlist ',' Tid + { + $$ = an(ONAME, $1, ZN); + $$->sym = $3; + } + ; + +zexpr : + { $$ = 0; } + | expr + ; + +expr : castexpr + | expr '*' expr + { + $$ = an(OMUL, $1, $3); + } + | expr '/' expr + { + $$ = an(ODIV, $1, $3); + } + | expr '%' expr + { + $$ = an(OMOD, $1, $3); + } + | expr '+' expr + { + $$ = an(OADD, $1, $3); + } + | expr '-' expr + { + $$ = an(OSUB, $1, $3); + } + | expr Trsh expr + { + $$ = an(ORSH, $1, $3); + } + | expr Tlsh expr + { + $$ = an(OLSH, $1, $3); + } + | expr '<' expr + { + $$ = an(OLT, $1, $3); + } + | expr '>' expr + { + $$ = an(OGT, $1, $3); + } + | expr Tleq expr + { + $$ = an(OLEQ, $1, $3); + } + | expr Tgeq expr + { + $$ = an(OGEQ, $1, $3); + } + | expr Teq expr + { + $$ = an(OEQ, $1, $3); + } + | expr Tneq expr + { + $$ = an(ONEQ, $1, $3); + } + | expr '&' expr + { + $$ = an(OLAND, $1, $3); + } + | expr '^' expr + { + $$ = an(OXOR, $1, $3); + } + | expr '|' expr + { + $$ = an(OLOR, $1, $3); + } + | expr Tandand expr + { + $$ = an(OCAND, $1, $3); + } + | expr Toror expr + { + $$ = an(OCOR, $1, $3); + } + | expr '=' expr + { + $$ = an(OASGN, $1, $3); + } + | expr Tfmt + { + $$ = an(OFMT, $1, con($2)); + } + ; + +castexpr : monexpr + | '(' Tid ')' monexpr + { + $$ = an(OCAST, $4, ZN); + $$->sym = $2; + } + ; + +monexpr : term + | '*' monexpr + { + $$ = an(OINDM, $2, ZN); + } + | '@' monexpr + { + $$ = an(OINDC, $2, ZN); + } + | '+' monexpr + { + $$ = con(0); + $$ = an(OADD, $2, $$); + } + | '-' monexpr + { + $$ = con(0); + $$ = an(OSUB, $$, $2); + } + | Tdec monexpr + { + $$ = an(OEDEC, $2, ZN); + } + | Tinc monexpr + { + $$ = an(OEINC, $2, ZN); + } + | Thead monexpr + { + $$ = an(OHEAD, $2, ZN); + } + | Ttail monexpr + { + $$ = an(OTAIL, $2, ZN); + } + | Tappend monexpr ',' monexpr + { + $$ = an(OAPPEND, $2, $4); + } + | Tdelete monexpr ',' monexpr + { + $$ = an(ODELETE, $2, $4); + } + | '!' monexpr + { + $$ = an(ONOT, $2, ZN); + } + | '~' monexpr + { + $$ = an(OXOR, $2, con(-1)); + } + | Teval monexpr + { + $$ = an(OEVAL, $2, ZN); + } + ; + +term : '(' expr ')' + { + $$ = $2; + } + | '{' args '}' + { + $$ = an(OCTRUCT, $2, ZN); + } + | term '[' expr ']' + { + $$ = an(OINDEX, $1, $3); + } + | term Tdec + { + $$ = an(OPDEC, $1, ZN); + } + | term '.' Tid + { + $$ = an(ODOT, $1, ZN); + $$->sym = $3; + } + | term Tindir Tid + { + $$ = an(ODOT, an(OINDM, $1, ZN), ZN); + $$->sym = $3; + } + | term Tinc + { + $$ = an(OPINC, $1, ZN); + } + | name '(' args ')' + { + $$ = an(OCALL, $1, $3); + } + | Tbuiltin name '(' args ')' + { + $$ = an(OCALL, $2, $4); + $$->builtin = 1; + } + | name + | Tconst + { + $$ = con($1); + } + | Tfconst + { + $$ = an(OCONST, ZN, ZN); + $$->type = TFLOAT; + $$->store.fmt = 'f'; + $$->store.u.fval = $1; + } + | Tstring + { + $$ = an(OCONST, ZN, ZN); + $$->type = TSTRING; + $$->store.u.string = $1; + $$->store.fmt = 's'; + } + | Twhat zname + { + $$ = an(OWHAT, ZN, ZN); + $$->sym = $2; + } + ; + +name : Tid + { + $$ = an(ONAME, ZN, ZN); + $$->sym = $1; + } + | Tid ':' name + { + $$ = an(OFRAME, $3, ZN); + $$->sym = $1; + } + ; + +args : zexpr + | args ',' zexpr + { + $$ = an(OLIST, $1, $3); + } + ; diff --git a/src/cmd/acid/dot.c b/src/cmd/acid/dot.c new file mode 100644 index 00000000..07b8c194 --- /dev/null +++ b/src/cmd/acid/dot.c @@ -0,0 +1,153 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <ctype.h> +#include <mach.h> +#define Extern extern +#include "acid.h" + +Type* +srch(Type *t, char *s) +{ + Type *f; + + f = 0; + while(t) { + if(strcmp(t->tag->name, s) == 0) { + if(f == 0 || t->depth < f->depth) + f = t; + } + t = t->next; + } + return f; +} + +void +odot(Node *n, Node *r) +{ + char *s; + Type *t; + Node res; + ulong addr; + + s = n->sym->name; + if(s == 0) + fatal("dodot: no tag"); + + expr(n->left, &res); + if(res.store.comt == 0) + error("no type specified for (expr).%s", s); + + if(res.type != TINT) + error("pointer must be integer for (expr).%s", s); + + t = srch(res.store.comt, s); + if(t == 0) + error("no tag for (expr).%s", s); + + /* Propagate types */ + if(t->type) + r->store.comt = t->type->lt; + + addr = res.store.u.ival+t->offset; + if(t->fmt == 'a') { + r->op = OCONST; + r->store.fmt = 'a'; + r->type = TINT; + r->store.u.ival = addr; + } + else + indir(cormap, addr, t->fmt, r); + +} + +static Type **tail; +static Lsym *base; + +void +buildtype(Node *m, int d) +{ + Type *t; + + if(m == ZN) + return; + + switch(m->op) { + case OLIST: + buildtype(m->left, d); + buildtype(m->right, d); + break; + + case OCTRUCT: + buildtype(m->left, d+1); + break; + default: + t = malloc(sizeof(Type)); + t->next = 0; + t->depth = d; + t->tag = m->sym; + t->base = base; + t->offset = m->store.u.ival; + if(m->left) { + t->type = m->left->sym; + t->fmt = 'a'; + } + else { + t->type = 0; + if(m->right) + t->type = m->right->sym; + t->fmt = m->store.fmt; + } + + *tail = t; + tail = &t->next; + } +} + +void +defcomplex(Node *tn, Node *m) +{ + tail = &tn->sym->lt; + base = tn->sym; + buildtype(m, 0); +} + +void +decl(Node *n) +{ + Node *l; + Value *v; + Frtype *f; + Lsym *type; + + type = n->sym; + if(type->lt == 0) + error("%s is not a complex type", type->name); + + l = n->left; + if(l->op == ONAME) { + v = l->sym->v; + v->store.comt = type->lt; + v->store.fmt = 'a'; + return; + } + + /* + * Frame declaration + */ + for(f = l->sym->local; f; f = f->next) { + if(f->var == l->left->sym) { + f->type = n->sym->lt; + return; + } + } + f = malloc(sizeof(Frtype)); + if(f == 0) + fatal("out of memory"); + + f->type = type->lt; + + f->var = l->left->sym; + f->next = l->sym->local; + l->sym->local = f; +} diff --git a/src/cmd/acid/exec.c b/src/cmd/acid/exec.c new file mode 100644 index 00000000..1d5b231a --- /dev/null +++ b/src/cmd/acid/exec.c @@ -0,0 +1,538 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <ctype.h> +#include <mach.h> +#define Extern extern +#include "acid.h" + +void +error(char *fmt, ...) +{ + int i; + char buf[2048]; + va_list arg; + + /* Unstack io channels */ + if(iop != 0) { + for(i = 1; i < iop; i++) + Bterm(io[i]); + bout = io[0]; + iop = 0; + } + + ret = 0; + gotint = 0; + Bflush(bout); + if(silent) + silent = 0; + else { + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + fprint(2, "%Z: (error) %s\n", buf); + } + while(popio()) + ; + interactive = 1; + longjmp(err, 1); +} + +void +unwind(void) +{ + int i; + Lsym *s; + Value *v; + + for(i = 0; i < Hashsize; i++) { + for(s = hash[i]; s; s = s->hash) { + while(s->v->pop) { + v = s->v->pop; + free(s->v); + s->v = v; + } + } + } +} + +void +execute(Node *n) +{ + Value *v; + Lsym *sl; + Node *l, *r; + int i, s, e; + Node res, xx; + static int stmnt; + + gc(); + if(gotint) + error("interrupted"); + + if(n == 0) + return; + + if(stmnt++ > 5000) { + Bflush(bout); + stmnt = 0; + } + + l = n->left; + r = n->right; + + switch(n->op) { + default: + expr(n, &res); + if(ret || (res.type == TLIST && res.store.u.l == 0)) + break; + prnt->right = &res; + expr(prnt, &xx); + break; + case OASGN: + case OCALL: + expr(n, &res); + break; + case OCOMPLEX: + decl(n); + break; + case OLOCAL: + for(n = n->left; n; n = n->left) { + if(ret == 0) + error("local not in function"); + sl = n->sym; + if(sl->v->ret == ret) + error("%s declared twice", sl->name); + v = gmalloc(sizeof(Value)); + v->ret = ret; + v->pop = sl->v; + sl->v = v; + v->scope = 0; + *(ret->tail) = sl; + ret->tail = &v->scope; + v->set = 0; + } + break; + case ORET: + if(ret == 0) + error("return not in function"); + expr(n->left, ret->val); + longjmp(ret->rlab, 1); + case OLIST: + execute(n->left); + execute(n->right); + break; + case OIF: + expr(l, &res); + if(r && r->op == OELSE) { + if(bool(&res)) + execute(r->left); + else + execute(r->right); + } + else if(bool(&res)) + execute(r); + break; + case OWHILE: + for(;;) { + expr(l, &res); + if(!bool(&res)) + break; + execute(r); + } + break; + case ODO: + expr(l->left, &res); + if(res.type != TINT) + error("loop must have integer start"); + s = res.store.u.ival; + expr(l->right, &res); + if(res.type != TINT) + error("loop must have integer end"); + e = res.store.u.ival; + for(i = s; i <= e; i++) + execute(r); + break; + } +} + +int +bool(Node *n) +{ + int true = 0; + + if(n->op != OCONST) + fatal("bool: not const"); + + switch(n->type) { + case TINT: + if(n->store.u.ival != 0) + true = 1; + break; + case TFLOAT: + if(n->store.u.fval != 0.0) + true = 1; + break; + case TSTRING: + if(n->store.u.string->len) + true = 1; + break; + case TLIST: + if(n->store.u.l) + true = 1; + break; + } + return true; +} + +void +convflt(Node *r, char *flt) +{ + char c; + + c = flt[0]; + if(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) { + r->type = TSTRING; + r->store.fmt = 's'; + r->store.u.string = strnode(flt); + } + else { + r->type = TFLOAT; + r->store.u.fval = atof(flt); + } +} + +static char* +regbyoff(ulong addr) +{ + Regdesc *r; + + if(mach == nil) + error("no mach, no registers"); + for(r=mach->reglist; r->name; r++) + if(r->offset == addr) + return r->name; + error("no register at %#lux", addr); + return nil; +} + +int +xget1(Map *m, ulong addr, u8int *a, int n) +{ + if(addr < 0x100) + return lget1(m, correg, locreg(regbyoff(addr)), a, n); + else + return get1(m, addr, a, n); +} + +int +xget2(Map *m, ulong addr, u16int *a) +{ + if(addr < 0x100) + return lget2(m, correg, locreg(regbyoff(addr)), a); + else + return get2(m, addr, a); +} + +int +xget4(Map *m, ulong addr, u32int *a) +{ + if(addr < 0x100) + return lget4(m, correg, locreg(regbyoff(addr)), a); + else + return get4(m, addr, a); +} + +int +xget8(Map *m, ulong addr, u64int *a) +{ + if(addr < 0x100) + return lget8(m, correg, locreg(regbyoff(addr)), a); + else + return get8(m, addr, a); +} + +void +indir(Map *m, ulong addr, char fmt, Node *r) +{ + int i; + u32int ival; + u64int vval; + int ret; + u8int cval; + u16int sval; + char buf[512], reg[12]; + + r->op = OCONST; + r->store.fmt = fmt; + switch(fmt) { + default: + error("bad pointer format '%c' for *", fmt); + case 'c': + case 'C': + case 'b': + r->type = TINT; + ret = xget1(m, addr, &cval, 1); + if (ret < 0) + error("indir: %r"); + r->store.u.ival = cval; + break; + case 'x': + case 'd': + case 'u': + case 'o': + case 'q': + case 'r': + r->type = TINT; + ret = xget2(m, addr, &sval); + if (ret < 0) + error("indir: %r"); + r->store.u.ival = sval; + break; + case 'a': + case 'A': + case 'B': + case 'X': + case 'D': + case 'U': + case 'O': + case 'Q': + r->type = TINT; + ret = xget4(m, addr, &ival); + if (ret < 0) + error("indir: %r"); + r->store.u.ival = ival; + break; + case 'V': + case 'W': + case 'Y': + case 'Z': + r->type = TINT; + ret = xget8(m, addr, &vval); + if (ret < 0) + error("indir: %r"); + r->store.u.ival = vval; + break; + case 's': + r->type = TSTRING; + for(i = 0; i < sizeof(buf)-1; i++) { + ret = xget1(m, addr, (uchar*)&buf[i], 1); + if (ret < 0) + error("indir: %r"); + addr++; + if(buf[i] == '\0') + break; + } + buf[i] = 0; + if(i == 0) + strcpy(buf, "(null)"); + r->store.u.string = strnode(buf); + break; + case 'R': + r->type = TSTRING; + for(i = 0; i < sizeof(buf)-2; i += 2) { + ret = xget1(m, addr, (uchar*)&buf[i], 2); + if (ret < 0) + error("indir: %r"); + addr += 2; + if(buf[i] == 0 && buf[i+1] == 0) + break; + } + buf[i++] = 0; + buf[i] = 0; + r->store.u.string = runenode((Rune*)buf); + break; + case 'i': + case 'I': + if ((*mach->das)(m, addr, fmt, buf, sizeof(buf)) < 0) + error("indir: %r"); + r->type = TSTRING; + r->store.fmt = 's'; + r->store.u.string = strnode(buf); + break; + case 'f': + ret = xget1(m, addr, (uchar*)buf, mach->szfloat); + if (ret < 0) + error("indir: %r"); + mach->ftoa32(buf, sizeof(buf), (void*) buf); + convflt(r, buf); + break; + case 'g': + ret = xget1(m, addr, (uchar*)buf, mach->szfloat); + if (ret < 0) + error("indir: %r"); + mach->ftoa32(buf, sizeof(buf), (void*) buf); + r->type = TSTRING; + r->store.u.string = strnode(buf); + break; + case 'F': + ret = xget1(m, addr, (uchar*)buf, mach->szdouble); + if (ret < 0) + error("indir: %r"); + mach->ftoa64(buf, sizeof(buf), (void*) buf); + convflt(r, buf); + break; + case '3': /* little endian ieee 80 with hole in bytes 8&9 */ + ret = xget1(m, addr, (uchar*)reg, 10); + if (ret < 0) + error("indir: %r"); + memmove(reg+10, reg+8, 2); /* open hole */ + memset(reg+8, 0, 2); /* fill it */ + leieeeftoa80(buf, sizeof(buf), reg); + convflt(r, buf); + break; + case '8': /* big-endian ieee 80 */ + ret = xget1(m, addr, (uchar*)reg, 10); + if (ret < 0) + error("indir: %r"); + beieeeftoa80(buf, sizeof(buf), reg); + convflt(r, buf); + break; + case 'G': + ret = xget1(m, addr, (uchar*)buf, mach->szdouble); + if (ret < 0) + error("indir: %r"); + mach->ftoa64(buf, sizeof(buf), (void*) buf); + r->type = TSTRING; + r->store.u.string = strnode(buf); + break; + } +} + +void +windir(Map *m, Node *addr, Node *rval, Node *r) +{ + uchar cval; + ushort sval; + Node res, aes; + int ret; + + if(m == 0) + error("no map for */@="); + + expr(rval, &res); + expr(addr, &aes); + + if(aes.type != TINT) + error("bad type lhs of @/*"); + + if(m != cormap && wtflag == 0) + error("not in write mode"); + + r->type = res.type; + r->store.fmt = res.store.fmt; + r->store = res.store; + + switch(res.store.fmt) { + default: + error("bad pointer format '%c' for */@=", res.store.fmt); + case 'c': + case 'C': + case 'b': + cval = res.store.u.ival; + ret = put1(m, aes.store.u.ival, &cval, 1); + break; + case 'r': + case 'x': + case 'd': + case 'u': + case 'o': + sval = res.store.u.ival; + ret = put2(m, aes.store.u.ival, sval); + r->store.u.ival = sval; + break; + case 'a': + case 'A': + case 'B': + case 'X': + case 'D': + case 'U': + case 'O': + ret = put4(m, aes.store.u.ival, res.store.u.ival); + break; + case 'V': + case 'W': + case 'Y': + case 'Z': + ret = put8(m, aes.store.u.ival, res.store.u.ival); + break; + case 's': + case 'R': + ret = put1(m, aes.store.u.ival, (uchar*)res.store.u.string->string, res.store.u.string->len); + break; + } + if (ret < 0) + error("windir: %r"); +} + +void +call(char *fn, Node *parameters, Node *local, Node *body, Node *retexp) +{ + int np, i; + Rplace rlab; + Node *n, res; + Value *v, *f; + Lsym *s, *next; + Node *avp[Maxarg], *ava[Maxarg]; + + rlab.local = 0; + + na = 0; + flatten(avp, parameters); + np = na; + na = 0; + flatten(ava, local); + if(np != na) { + if(np < na) + error("%s: too few arguments", fn); + error("%s: too many arguments", fn); + } + + rlab.tail = &rlab.local; + + ret = &rlab; + for(i = 0; i < np; i++) { + n = ava[i]; + switch(n->op) { + default: + error("%s: %d formal not a name", fn, i); + case ONAME: + expr(avp[i], &res); + s = n->sym; + break; + case OINDM: + res.store.u.cc = avp[i]; + res.type = TCODE; + res.store.comt = 0; + if(n->left->op != ONAME) + error("%s: %d formal not a name", fn, i); + s = n->left->sym; + break; + } + if(s->v->ret == ret) + error("%s already declared at this scope", s->name); + + v = gmalloc(sizeof(Value)); + v->ret = ret; + v->pop = s->v; + s->v = v; + v->scope = 0; + *(rlab.tail) = s; + rlab.tail = &v->scope; + + v->store = res.store; + v->type = res.type; + v->set = 1; + } + + ret->val = retexp; + if(setjmp(rlab.rlab) == 0) + execute(body); + + for(s = rlab.local; s; s = next) { + f = s->v; + next = f->scope; + s->v = f->pop; + free(f); + } +} diff --git a/src/cmd/acid/expr.c b/src/cmd/acid/expr.c new file mode 100644 index 00000000..46e522bf --- /dev/null +++ b/src/cmd/acid/expr.c @@ -0,0 +1,1018 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <ctype.h> +#include <mach.h> +#define Extern extern +#include "acid.h" + +static int fsize[] = +{ + ['A'] 4, + ['B'] 4, + ['C'] 1, + ['D'] 4, + ['F'] 8, + ['G'] 8, + ['O'] 4, + ['Q'] 4, + ['R'] 4, + ['S'] 4, + ['U'] 4, + ['V'] 8, + ['X'] 4, + ['Y'] 8, + ['W'] 8, + ['Z'] 8, + ['a'] 4, + ['b'] 1, + ['c'] 1, + ['d'] 2, + ['f'] 4, + ['g'] 4, + ['o'] 2, + ['q'] 2, + ['r'] 2, + ['s'] 4, + ['u'] 2, + ['x'] 2, +}; + +int +fmtsize(Value *v) +{ + int ret; + + switch(v->store.fmt) { + default: + return fsize[(unsigned char)v->store.fmt]; + case 'i': + case 'I': + if(v->type != TINT || mach == 0) + error("no size for i fmt pointer ++/--"); + ret = (*mach->instsize)(symmap, v->store.u.ival); + if(ret < 0) { + ret = (*mach->instsize)(symmap, v->store.u.ival); + if(ret < 0) + error("%r"); + } + return ret; + } +} + +void +chklval(Node *lp) +{ + if(lp->op != ONAME) + error("need l-value"); +} + +void +olist(Node *n, Node *res) +{ + expr(n->left, res); + expr(n->right, res); +} + +void +oeval(Node *n, Node *res) +{ + expr(n->left, res); + if(res->type != TCODE) + error("bad type for eval"); + expr(res->store.u.cc, res); +} + +void +ocast(Node *n, Node *res) +{ + if(n->sym->lt == 0) + error("%s is not a complex type", n->sym->name); + + expr(n->left, res); + res->store.comt = n->sym->lt; + res->store.fmt = 'a'; +} + +void +oindm(Node *n, Node *res) +{ + Map *m; + Node l; + + m = cormap; + if(m == 0) + m = symmap; + expr(n->left, &l); + if(l.type != TINT) + error("bad type for *"); + if(m == 0) + error("no map for *"); + indir(m, l.store.u.ival, l.store.fmt, res); + res->store.comt = l.store.comt; +} + +void +oindc(Node *n, Node *res) +{ + Map *m; + Node l; + + m = symmap; + if(m == 0) + m = cormap; + expr(n->left, &l); + if(l.type != TINT) + error("bad type for @"); + if(m == 0) + error("no map for @"); + indir(m, l.store.u.ival, l.store.fmt, res); + res->store.comt = l.store.comt; +} + +void +oframe(Node *n, Node *res) +{ + char *p; + Node *lp; + ulong ival; + Frtype *f; + + p = n->sym->name; + while(*p && *p == '$') + p++; + lp = n->left; + if(localaddr(cormap, correg, p, lp->sym->name, &ival) < 0) + error("colon: %r"); + + res->store.u.ival = ival; + res->op = OCONST; + res->store.fmt = 'X'; + res->type = TINT; + + /* Try and set comt */ + for(f = n->sym->local; f; f = f->next) { + if(f->var == lp->sym) { + res->store.comt = f->type; + res->store.fmt = 'a'; + break; + } + } +} + +void +oindex(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + + if(r.type != TINT) + error("bad type for []"); + + switch(l.type) { + default: + error("lhs[] has bad type"); + case TINT: + indir(cormap, l.store.u.ival+(r.store.u.ival*fsize[(unsigned char)l.store.fmt]), l.store.fmt, res); + res->store.comt = l.store.comt; + res->store.fmt = l.store.fmt; + break; + case TLIST: + nthelem(l.store.u.l, r.store.u.ival, res); + break; + case TSTRING: + res->store.u.ival = 0; + if(r.store.u.ival >= 0 && r.store.u.ival < l.store.u.string->len) { + int xx8; /* to get around bug in vc */ + xx8 = r.store.u.ival; + res->store.u.ival = l.store.u.string->string[xx8]; + } + res->op = OCONST; + res->type = TINT; + res->store.fmt = 'c'; + break; + } +} + +void +oappend(Node *n, Node *res) +{ + Node r, l; + + expr(n->left, &l); + expr(n->right, &r); + if(l.type != TLIST) + error("must append to list"); + append(res, &l, &r); +} + +void +odelete(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + if(l.type != TLIST) + error("must delete from list"); + if(r.type != TINT) + error("delete index must be integer"); + + delete(l.store.u.l, r.store.u.ival, res); +} + +void +ohead(Node *n, Node *res) +{ + Node l; + + expr(n->left, &l); + if(l.type != TLIST) + error("head needs list"); + res->op = OCONST; + if(l.store.u.l) { + res->type = l.store.u.l->type; + res->store = l.store.u.l->store; + } + else { + res->type = TLIST; + res->store.u.l = 0; + } +} + +void +otail(Node *n, Node *res) +{ + Node l; + + expr(n->left, &l); + if(l.type != TLIST) + error("tail needs list"); + res->op = OCONST; + res->type = TLIST; + if(l.store.u.l) + res->store.u.l = l.store.u.l->next; + else + res->store.u.l = 0; +} + +void +oconst(Node *n, Node *res) +{ + res->op = OCONST; + res->type = n->type; + res->store = n->store; + res->store.comt = n->store.comt; +} + +void +oname(Node *n, Node *res) +{ + Value *v; + + v = n->sym->v; + if(v->set == 0) + error("%s used but not set", n->sym->name); + res->op = OCONST; + res->type = v->type; + res->store = v->store; + res->store.comt = v->store.comt; +} + +void +octruct(Node *n, Node *res) +{ + res->op = OCONST; + res->type = TLIST; + res->store.u.l = construct(n->left); +} + +void +oasgn(Node *n, Node *res) +{ + Node *lp, r; + Value *v; + + lp = n->left; + switch(lp->op) { + case OINDM: + windir(cormap, lp->left, n->right, res); + break; + case OINDC: + windir(symmap, lp->left, n->right, res); + break; + default: + chklval(lp); + v = lp->sym->v; + expr(n->right, &r); + v->set = 1; + v->type = r.type; + v->store = r.store; + res->op = OCONST; + res->type = v->type; + res->store = v->store; + res->store.comt = v->store.comt; + } +} + +void +oadd(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TFLOAT; + switch(l.type) { + default: + error("bad lhs type +"); + case TINT: + switch(r.type) { + case TINT: + res->type = TINT; + res->store.u.ival = l.store.u.ival+r.store.u.ival; + break; + case TFLOAT: + res->store.u.fval = l.store.u.ival+r.store.u.fval; + break; + default: + error("bad rhs type +"); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->store.u.fval = l.store.u.fval+r.store.u.ival; + break; + case TFLOAT: + res->store.u.fval = l.store.u.fval+r.store.u.fval; + break; + default: + error("bad rhs type +"); + } + break; + case TSTRING: + if(r.type == TSTRING) { + res->type = TSTRING; + res->store.fmt = 's'; + res->store.u.string = stradd(l.store.u.string, r.store.u.string); + break; + } + error("bad rhs for +"); + case TLIST: + res->type = TLIST; + switch(r.type) { + case TLIST: + res->store.u.l = addlist(l.store.u.l, r.store.u.l); + break; + default: + r.left = 0; + r.right = 0; + res->store.u.l = addlist(l.store.u.l, construct(&r)); + break; + } + } +} + +void +osub(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TFLOAT; + switch(l.type) { + default: + error("bad lhs type -"); + case TINT: + switch(r.type) { + case TINT: + res->type = TINT; + res->store.u.ival = l.store.u.ival-r.store.u.ival; + break; + case TFLOAT: + res->store.u.fval = l.store.u.ival-r.store.u.fval; + break; + default: + error("bad rhs type -"); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->store.u.fval = l.store.u.fval-r.store.u.ival; + break; + case TFLOAT: + res->store.u.fval = l.store.u.fval-r.store.u.fval; + break; + default: + error("bad rhs type -"); + } + break; + } +} + +void +omul(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TFLOAT; + switch(l.type) { + default: + error("bad lhs type *"); + case TINT: + switch(r.type) { + case TINT: + res->type = TINT; + res->store.u.ival = l.store.u.ival*r.store.u.ival; + break; + case TFLOAT: + res->store.u.fval = l.store.u.ival*r.store.u.fval; + break; + default: + error("bad rhs type *"); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->store.u.fval = l.store.u.fval*r.store.u.ival; + break; + case TFLOAT: + res->store.u.fval = l.store.u.fval*r.store.u.fval; + break; + default: + error("bad rhs type *"); + } + break; + } +} + +void +odiv(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TFLOAT; + switch(l.type) { + default: + error("bad lhs type /"); + case TINT: + switch(r.type) { + case TINT: + res->type = TINT; + if(r.store.u.ival == 0) + error("zero divide"); + res->store.u.ival = l.store.u.ival/r.store.u.ival; + break; + case TFLOAT: + if(r.store.u.fval == 0) + error("zero divide"); + res->store.u.fval = l.store.u.ival/r.store.u.fval; + break; + default: + error("bad rhs type /"); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->store.u.fval = l.store.u.fval/r.store.u.ival; + break; + case TFLOAT: + res->store.u.fval = l.store.u.fval/r.store.u.fval; + break; + default: + error("bad rhs type /"); + } + break; + } +} + +void +omod(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TINT; + if(l.type != TINT || r.type != TINT) + error("bad expr type %"); + res->store.u.ival = l.store.u.ival%r.store.u.ival; +} + +void +olsh(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TINT; + if(l.type != TINT || r.type != TINT) + error("bad expr type <<"); + res->store.u.ival = l.store.u.ival<<r.store.u.ival; +} + +void +orsh(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TINT; + if(l.type != TINT || r.type != TINT) + error("bad expr type >>"); + res->store.u.ival = (unsigned)l.store.u.ival>>r.store.u.ival; +} + +void +olt(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TINT; + switch(l.type) { + default: + error("bad lhs type <"); + case TINT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.ival < r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.ival < r.store.u.fval; + break; + default: + error("bad rhs type <"); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.fval < r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.fval < r.store.u.fval; + break; + default: + error("bad rhs type <"); + } + break; + } +} + +void +ogt(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = 'D'; + res->op = OCONST; + res->type = TINT; + switch(l.type) { + default: + error("bad lhs type >"); + case TINT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.ival > r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.ival > r.store.u.fval; + break; + default: + error("bad rhs type >"); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.fval > r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.fval > r.store.u.fval; + break; + default: + error("bad rhs type >"); + } + break; + } +} + +void +oleq(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = 'D'; + res->op = OCONST; + res->type = TINT; + switch(l.type) { + default: + error("bad expr type <="); + case TINT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.ival <= r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.ival <= r.store.u.fval; + break; + default: + error("bad expr type <="); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.fval <= r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.fval <= r.store.u.fval; + break; + default: + error("bad expr type <="); + } + break; + } +} + +void +ogeq(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = 'D'; + res->op = OCONST; + res->type = TINT; + switch(l.type) { + default: + error("bad lhs type >="); + case TINT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.ival >= r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.ival >= r.store.u.fval; + break; + default: + error("bad rhs type >="); + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.fval >= r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.fval >= r.store.u.fval; + break; + default: + error("bad rhs type >="); + } + break; + } +} + +void +oeq(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = 'D'; + res->op = OCONST; + res->type = TINT; + res->store.u.ival = 0; + switch(l.type) { + default: + break; + case TINT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.ival == r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.ival == r.store.u.fval; + break; + default: + break; + } + break; + case TFLOAT: + switch(r.type) { + case TINT: + res->store.u.ival = l.store.u.fval == r.store.u.ival; + break; + case TFLOAT: + res->store.u.ival = l.store.u.fval == r.store.u.fval; + break; + default: + break; + } + break; + case TSTRING: + if(r.type == TSTRING) { + res->store.u.ival = scmp(r.store.u.string, l.store.u.string); + break; + } + break; + case TLIST: + if(r.type == TLIST) { + res->store.u.ival = listcmp(l.store.u.l, r.store.u.l); + break; + } + break; + } + if(n->op == ONEQ) + res->store.u.ival = !res->store.u.ival; +} + + +void +oland(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TINT; + if(l.type != TINT || r.type != TINT) + error("bad expr type &"); + res->store.u.ival = l.store.u.ival&r.store.u.ival; +} + +void +oxor(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TINT; + if(l.type != TINT || r.type != TINT) + error("bad expr type ^"); + res->store.u.ival = l.store.u.ival^r.store.u.ival; +} + +void +olor(Node *n, Node *res) +{ + Node l, r; + + expr(n->left, &l); + expr(n->right, &r); + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TINT; + if(l.type != TINT || r.type != TINT) + error("bad expr type |"); + res->store.u.ival = l.store.u.ival|r.store.u.ival; +} + +void +ocand(Node *n, Node *res) +{ + Node l, r; + + res->store.fmt = l.store.fmt; + res->op = OCONST; + res->type = TINT; + res->store.u.ival = 0; + expr(n->left, &l); + if(bool(&l) == 0) + return; + expr(n->right, &r); + if(bool(&r) == 0) + return; + res->store.u.ival = 1; +} + +void +onot(Node *n, Node *res) +{ + Node l; + + res->op = OCONST; + res->type = TINT; + res->store.u.ival = 0; + expr(n->left, &l); + if(bool(&l) == 0) + res->store.u.ival = 1; +} + +void +ocor(Node *n, Node *res) +{ + Node l, r; + + res->op = OCONST; + res->type = TINT; + res->store.u.ival = 0; + expr(n->left, &l); + if(bool(&l)) { + res->store.u.ival = 1; + return; + } + expr(n->right, &r); + if(bool(&r)) { + res->store.u.ival = 1; + return; + } +} + +void +oeinc(Node *n, Node *res) +{ + Value *v; + + chklval(n->left); + v = n->left->sym->v; + res->op = OCONST; + res->type = v->type; + switch(v->type) { + case TINT: + if(n->op == OEDEC) + v->store.u.ival -= fmtsize(v); + else + v->store.u.ival += fmtsize(v); + break; + case TFLOAT: + if(n->op == OEDEC) + v->store.u.fval--; + else + v->store.u.fval++; + break; + default: + error("bad type for pre --/++"); + } + res->store = v->store; +} + +void +opinc(Node *n, Node *res) +{ + Value *v; + + chklval(n->left); + v = n->left->sym->v; + res->op = OCONST; + res->type = v->type; + res->store = v->store; + switch(v->type) { + case TINT: + if(n->op == OPDEC) + v->store.u.ival -= fmtsize(v); + else + v->store.u.ival += fmtsize(v); + break; + case TFLOAT: + if(n->op == OPDEC) + v->store.u.fval--; + else + v->store.u.fval++; + break; + default: + error("bad type for post --/++"); + } +} + +void +ocall(Node *n, Node *res) +{ + Lsym *s; + Rplace *rsav; + + res->op = OCONST; /* Default return value */ + res->type = TLIST; + res->store.u.l = 0; + + chklval(n->left); + s = n->left->sym; + + if(n->builtin && !s->builtin){ + error("no builtin %s", s->name); + return; + } + if(s->builtin && (n->builtin || s->proc == 0)) { + (*s->builtin)(res, n->right); + return; + } + if(s->proc == 0) + error("no function %s", s->name); + + rsav = ret; + call(s->name, n->right, s->proc->left, s->proc->right, res); + ret = rsav; +} + +void +ofmt(Node *n, Node *res) +{ + expr(n->left, res); + res->store.fmt = n->right->store.u.ival; +} + +void +owhat(Node *n, Node *res) +{ + res->op = OCONST; /* Default return value */ + res->type = TLIST; + res->store.u.l = 0; + whatis(n->sym); +} + +void (*expop[])(Node*, Node*) = +{ + [ONAME] oname, + [OCONST] oconst, + [OMUL] omul, + [ODIV] odiv, + [OMOD] omod, + [OADD] oadd, + [OSUB] osub, + [ORSH] orsh, + [OLSH] olsh, + [OLT] olt, + [OGT] ogt, + [OLEQ] oleq, + [OGEQ] ogeq, + [OEQ] oeq, + [ONEQ] oeq, + [OLAND] oland, + [OXOR] oxor, + [OLOR] olor, + [OCAND] ocand, + [OCOR] ocor, + [OASGN] oasgn, + [OINDM] oindm, + [OEDEC] oeinc, + [OEINC] oeinc, + [OPINC] opinc, + [OPDEC] opinc, + [ONOT] onot, + [OIF] 0, + [ODO] 0, + [OLIST] olist, + [OCALL] ocall, + [OCTRUCT] octruct, + [OWHILE] 0, + [OELSE] 0, + [OHEAD] ohead, + [OTAIL] otail, + [OAPPEND] oappend, + [ORET] 0, + [OINDEX] oindex, + [OINDC] oindc, + [ODOT] odot, + [OLOCAL] 0, + [OFRAME] oframe, + [OCOMPLEX] 0, + [ODELETE] odelete, + [OCAST] ocast, + [OFMT] ofmt, + [OEVAL] oeval, + [OWHAT] owhat, +}; diff --git a/src/cmd/acid/lex.c b/src/cmd/acid/lex.c new file mode 100644 index 00000000..40f6400e --- /dev/null +++ b/src/cmd/acid/lex.c @@ -0,0 +1,661 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <ctype.h> +#include <mach.h> +#define Extern extern +#include "acid.h" +#include "y.tab.h" + +struct keywd +{ + char *name; + int terminal; +} +keywds[] = +{ + "do", Tdo, + "if", Tif, + "then", Tthen, + "else", Telse, + "while", Twhile, + "loop", Tloop, + "head", Thead, + "tail", Ttail, + "append", Tappend, + "defn", Tfn, + "return", Tret, + "local", Tlocal, + "aggr", Tcomplex, + "union", Tcomplex, + "adt", Tcomplex, + "complex", Tcomplex, + "delete", Tdelete, + "whatis", Twhat, + "eval", Teval, + "builtin", Tbuiltin, + 0, 0 +}; + +char cmap[256] = +{ + ['0'] '\0'+1, + ['n'] '\n'+1, + ['r'] '\r'+1, + ['t'] '\t'+1, + ['b'] '\b'+1, + ['f'] '\f'+1, + ['a'] '\a'+1, + ['v'] '\v'+1, + ['\\'] '\\'+1, + ['"'] '"'+1, +}; + +void +kinit(void) +{ + int i; + + for(i = 0; keywds[i].name; i++) + enter(keywds[i].name, keywds[i].terminal); +} + +typedef struct IOstack IOstack; +struct IOstack +{ + char *name; + int line; + char *text; + char *ip; + Biobuf *fin; + IOstack *prev; +}; +IOstack *lexio; + +void +setacidfile(void) +{ + char *name; + Lsym *l; + + if(lexio) + name = lexio->name; + else + name = ""; + l = mkvar("acidfile"); + l->v->set = 1; + l->v->store.fmt = 's'; + l->v->type = TSTRING; + l->v->store.u.string = strnode(name); +} + +void +pushfile(char *file) +{ + Biobuf *b; + IOstack *io; + + if(file) + b = Bopen(file, OREAD); + else{ + b = Bopen(unsharp("#d/0"), OREAD); + file = "<stdin>"; + } + + if(b == 0) + error("pushfile: %s: %r", file); + + io = malloc(sizeof(IOstack)); + if(io == 0) + fatal("no memory"); + io->name = strdup(file); + if(io->name == 0) + fatal("no memory"); + io->line = line; + line = 1; + io->text = 0; + io->fin = b; + io->prev = lexio; + lexio = io; + setacidfile(); +} + +void +pushfd(int fd) +{ + pushfile("/dev/null"); + close(lexio->fin->fid); + free(lexio->name); + lexio->name = smprint("<fd#d>", fd); + lexio->fin->fid = fd; +} + +void +pushstr(Node *s) +{ + IOstack *io; + + io = malloc(sizeof(IOstack)); + if(io == 0) + fatal("no memory"); + io->line = line; + line = 1; + io->name = strdup("<string>"); + if(io->name == 0) + fatal("no memory"); + io->line = line; + line = 1; + io->text = strdup(s->store.u.string->string); + if(io->text == 0) + fatal("no memory"); + io->ip = io->text; + io->fin = 0; + io->prev = lexio; + lexio = io; + setacidfile(); +} + +void +restartio(void) +{ + Bflush(lexio->fin); + Binit(lexio->fin, 0, OREAD); +} + +int +popio(void) +{ + IOstack *s; + + if(lexio == 0) + return 0; + + if(lexio->prev == 0){ + if(lexio->fin) + restartio(); + return 0; + } + + if(lexio->fin) + Bterm(lexio->fin); + else + free(lexio->text); + free(lexio->name); + line = lexio->line; + s = lexio; + lexio = s->prev; + free(s); + setacidfile(); + return 1; +} + +int +Zfmt(Fmt *f) +{ + int i; + char buf[1024]; + IOstack *e; + + e = lexio; + if(e) { + i = sprint(buf, "%s:%d", e->name, line); + while(e->prev) { + e = e->prev; + if(initialising && e->prev == 0) + break; + i += sprint(buf+i, " [%s:%d]", e->name, e->line); + } + } else + sprint(buf, "no file:0"); + fmtstrcpy(f, buf); + return 0; +} + +void +unlexc(int s) +{ + if(s == '\n') + line--; + + if(lexio->fin) + Bungetc(lexio->fin); + else + lexio->ip--; +} + +int +lexc(void) +{ + int c; + + if(lexio->fin) { + c = Bgetc(lexio->fin); + if(gotint) + error("interrupt"); + return c; + } + + c = *lexio->ip++; + if(c == 0) + return -1; + return c; +} + +int +escchar(char c) +{ + int n; + char buf[Strsize]; + + if(c >= '0' && c <= '9') { + n = 1; + buf[0] = c; + for(;;) { + c = lexc(); + if(c == Eof) + error("%d: <eof> in escape sequence", line); + if(strchr("0123456789xX", c) == 0) { + unlexc(c); + break; + } + buf[n++] = c; + } + buf[n] = '\0'; + return strtol(buf, 0, 0); + } + + n = cmap[(unsigned char)c]; + if(n == 0) + return c; + return n-1; +} + +void +eatstring(void) +{ + int esc, c, cnt; + char buf[Strsize]; + + esc = 0; + for(cnt = 0;;) { + c = lexc(); + switch(c) { + case Eof: + error("%d: <eof> in string constant", line); + + case '\n': + error("newline in string constant"); + goto done; + + case '\\': + if(esc) + goto Default; + esc = 1; + break; + + case '"': + if(esc == 0) + goto done; + + /* Fall through */ + default: + Default: + if(esc) { + c = escchar(c); + esc = 0; + } + buf[cnt++] = c; + break; + } + if(cnt >= Strsize) + error("string token too long"); + } +done: + buf[cnt] = '\0'; + yylval.string = strnode(buf); +} + +void +eatnl(void) +{ + int c; + + line++; + for(;;) { + c = lexc(); + if(c == Eof) + error("eof in comment"); + if(c == '\n') + return; + } +} + +int +yylex(void) +{ + int c; + extern char vfmt[]; + +loop: + Bflush(bout); + c = lexc(); + switch(c) { + case Eof: + if(gotint) { + gotint = 0; + stacked = 0; + Bprint(bout, "\nacid; "); + goto loop; + } + return Eof; + + case '"': + eatstring(); + return Tstring; + + case ' ': + case '\t': + goto loop; + + case '\n': + line++; + if(interactive == 0) + goto loop; + if(stacked) { + print("\t"); + goto loop; + } + nlcount++; + return ';'; + + case '.': + c = lexc(); + unlexc(c); + if(isdigit(c)) + return numsym('.'); + + return '.'; + + case '(': + case ')': + case '[': + case ']': + case ';': + case ':': + case ',': + case '~': + case '?': + case '*': + case '@': + case '^': + case '%': + return c; + case '{': + stacked++; + return c; + case '}': + stacked--; + return c; + + case '\\': + c = lexc(); + if(strchr(vfmt, c) == 0) { + unlexc(c); + return '\\'; + } + yylval.ival = c; + return Tfmt; + + case '!': + c = lexc(); + if(c == '=') + return Tneq; + unlexc(c); + return '!'; + + case '+': + c = lexc(); + if(c == '+') + return Tinc; + unlexc(c); + return '+'; + + case '/': + c = lexc(); + if(c == '/') { + eatnl(); + goto loop; + } + unlexc(c); + return '/'; + + case '\'': + c = lexc(); + if(c == '\\') + yylval.ival = escchar(lexc()); + else + yylval.ival = c; + c = lexc(); + if(c != '\'') { + error("missing '"); + unlexc(c); + } + return Tconst; + + case '&': + c = lexc(); + if(c == '&') + return Tandand; + unlexc(c); + return '&'; + + case '=': + c = lexc(); + if(c == '=') + return Teq; + unlexc(c); + return '='; + + case '|': + c = lexc(); + if(c == '|') + return Toror; + unlexc(c); + return '|'; + + case '<': + c = lexc(); + if(c == '=') + return Tleq; + if(c == '<') + return Tlsh; + unlexc(c); + return '<'; + + case '>': + c = lexc(); + if(c == '=') + return Tgeq; + if(c == '>') + return Trsh; + unlexc(c); + return '>'; + + case '-': + c = lexc(); + + if(c == '>') + return Tindir; + + if(c == '-') + return Tdec; + unlexc(c); + return '-'; + + default: + return numsym(c); + } +} + +int +numsym(char first) +{ + int c, isbin, isfloat, ishex; + char *sel, *p; + Lsym *s; + + symbol[0] = first; + p = symbol; + + ishex = 0; + isbin = 0; + isfloat = 0; + if(first == '.') + isfloat = 1; + + if(isdigit(*p++) || isfloat) { + for(;;) { + c = lexc(); + if(c < 0) + error("%d: <eof> eating symbols", line); + + if(c == '\n') + line++; + sel = "01234567890.xb"; + if(ishex) + sel = "01234567890abcdefABCDEF"; + else if(isbin) + sel = "01"; + else if(isfloat) + sel = "01234567890eE-+"; + + if(strchr(sel, c) == 0) { + unlexc(c); + break; + } + if(c == '.') + isfloat = 1; + if(!isbin && c == 'x') + ishex = 1; + if(!ishex && c == 'b') + isbin = 1; + *p++ = c; + } + *p = '\0'; + if(isfloat) { + yylval.fval = atof(symbol); + return Tfconst; + } + + if(isbin) + yylval.ival = strtoul(symbol+2, 0, 2); + else + yylval.ival = strtoul(symbol, 0, 0); + return Tconst; + } + + for(;;) { + c = lexc(); + if(c < 0) + error("%d <eof> eating symbols", line); + if(c == '\n') + line++; + if(c != '_' && c != '$' && c <= '~' && !isalnum(c)) { /* checking against ~ lets UTF names through */ + unlexc(c); + break; + } + *p++ = c; + } + + *p = '\0'; + + s = look(symbol); + if(s == 0) + s = enter(symbol, Tid); + + yylval.sym = s; + return s->lexval; +} + +Lsym* +enter(char *name, int t) +{ + Lsym *s; + ulong h; + char *p; + Value *v; + + h = 0; + for(p = name; *p; p++) + h = h*3 + *p; + h %= Hashsize; + + s = gmalloc(sizeof(Lsym)); + memset(s, 0, sizeof(Lsym)); + s->name = strdup(name); + + s->hash = hash[h]; + hash[h] = s; + s->lexval = t; + + v = gmalloc(sizeof(Value)); + s->v = v; + + v->store.fmt = 'X'; + v->type = TINT; + memset(v, 0, sizeof(Value)); + + return s; +} + +void +delsym(Lsym *s) +{ + char *q; + ulong h; + Lsym *p; + + h = 0; + for(q = s->name; *q; q++) + h = h*3 + *q; + h %= Hashsize; + + if(hash[h] == s) + hash[h] = s->hash; + else{ + for(p=hash[h]; p && p->hash != s; p=p->hash) + ; + if(p) + p->hash = s->hash; + } + s->hash = nil; +} + +Lsym* +look(char *name) +{ + Lsym *s; + ulong h; + char *p; + + h = 0; + for(p = name; *p; p++) + h = h*3 + *p; + h %= Hashsize; + + for(s = hash[h]; s; s = s->hash) + if(strcmp(name, s->name) == 0) + return s; + return 0; +} + +Lsym* +mkvar(char *s) +{ + Lsym *l; + + l = look(s); + if(l == 0) + l = enter(s, Tid); + return l; +} diff --git a/src/cmd/acid/list.c b/src/cmd/acid/list.c new file mode 100644 index 00000000..76214b2d --- /dev/null +++ b/src/cmd/acid/list.c @@ -0,0 +1,270 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <ctype.h> +#include <mach.h> +#define Extern extern +#include "acid.h" + +static List **tail; + +List* +construct(Node *l) +{ + List *lh, **save; + + save = tail; + lh = 0; + tail = &lh; + build(l); + tail = save; + + return lh; +} + +int +listlen(List *l) +{ + int len; + + len = 0; + while(l) { + len++; + l = l->next; + } + return len; +} + +void +build(Node *n) +{ + List *l; + Node res; + + if(n == 0) + return; + + switch(n->op) { + case OLIST: + build(n->left); + build(n->right); + return; + default: + expr(n, &res); + l = al(res.type); + l->store = res.store; + *tail = l; + tail = &l->next; + } +} + +List* +addlist(List *l, List *r) +{ + List *f; + + if(l == 0) + return r; + + for(f = l; f->next; f = f->next) + ; + f->next = r; + + return l; +} + +void +append(Node *r, Node *list, Node *val) +{ + List *l, *f; + + l = al(val->type); + l->store = val->store; + l->next = 0; + + r->op = OCONST; + r->type = TLIST; + + if(list->store.u.l == 0) { + list->store.u.l = l; + r->store.u.l = l; + return; + } + for(f = list->store.u.l; f->next; f = f->next) + ; + f->next = l; + r->store.u.l = list->store.u.l; +} + +int +listcmp(List *l, List *r) +{ + if(l == r) + return 1; + + while(l) { + if(r == 0) + return 0; + if(l->type != r->type) + return 0; + switch(l->type) { + case TINT: + if(l->store.u.ival != r->store.u.ival) + return 0; + break; + case TFLOAT: + if(l->store.u.fval != r->store.u.fval) + return 0; + break; + case TSTRING: + if(scmp(l->store.u.string, r->store.u.string) == 0) + return 0; + break; + case TLIST: + if(listcmp(l->store.u.l, r->store.u.l) == 0) + return 0; + break; + } + l = l->next; + r = r->next; + } + if(l != r) + return 0; + return 1; +} + +void +nthelem(List *l, int n, Node *res) +{ + if(n < 0) + error("negative index in []"); + + while(l && n--) + l = l->next; + + res->op = OCONST; + if(l == 0) { + res->type = TLIST; + res->store.u.l = 0; + return; + } + res->type = l->type; + res->store = l->store; +} + +void +delete(List *l, int n, Node *res) +{ + List **tl; + + if(n < 0) + error("negative index in delete"); + + res->op = OCONST; + res->type = TLIST; + res->store.u.l = l; + + for(tl = &res->store.u.l; l && n--; l = l->next) + tl = &l->next; + + if(l == 0) + error("element beyond end of list"); + *tl = l->next; +} + +List* +listvar(char *s, long v) +{ + List *l, *tl; + + tl = al(TLIST); + + l = al(TSTRING); + tl->store.u.l = l; + l->store.fmt = 's'; + l->store.u.string = strnode(s); + l->next = al(TINT); + l = l->next; + l->store.fmt = 'X'; + l->store.u.ival = v; + + return tl; +} + +static List* +listlocals(Map *map, Regs *regs, Symbol *fn, int class) +{ + int i; + u32int val; + Symbol s; + List **tail, *l2; + + l2 = 0; + tail = &l2; + if(fn == nil) + return l2; + for(i = 0; indexlsym(fn, i, &s)>=0; i++) { + if(s.class != class) + continue; + if(class == CAUTO && s.name[0] == '.') + continue; + if(lget4(map, regs, s.loc, &val) < 0) + continue; + *tail = listvar(s.name, val); + tail = &(*tail)->next; + } + return l2; +} + +static List* +listparams(Map *map, Regs *regs, Symbol *fn) +{ + return listlocals(map, regs, fn, CPARAM); +} + +static List* +listautos(Map *map, Regs *regs, Symbol *fn) +{ + return listlocals(map, regs, fn, CAUTO); +} + +int +trlist(Map *map, Regs *regs, ulong pc, ulong callerpc, Symbol *sym, int depth) +{ + List *q, *l; + static List **tail; + + if (tracelist == 0) /* first time */ + tail = &tracelist; + + q = al(TLIST); + *tail = q; + tail = &q->next; + + l = al(TINT); /* Function address */ + q->store.u.l = l; + l->store.u.ival = sym ? sym->loc.addr : pc; + l->store.fmt = 'X'; + + l->next = al(TINT); /* actual pc address */ + l = l->next; + l->store.u.ival = pc; + l->store.fmt = 'X'; + + l->next = al(TINT); /* called from address */ + l = l->next; + l->store.u.ival = callerpc; + l->store.fmt = 'X'; + + l->next = al(TLIST); /* make list of params */ + l = l->next; + if(sym) + l->store.u.l = listparams(map, regs, sym); + + l->next = al(TLIST); /* make list of locals */ + l = l->next; + if(sym) + l->store.u.l = listautos(map, regs, sym); + + return depth<40; +} diff --git a/src/cmd/acid/main.c b/src/cmd/acid/main.c new file mode 100644 index 00000000..dccff268 --- /dev/null +++ b/src/cmd/acid/main.c @@ -0,0 +1,630 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <mach.h> +#define Extern +#include "acid.h" +#include "y.tab.h" + +extern int __ifmt(Fmt*); + +static Biobuf bioout; +static char* lm[16]; +static int nlm; +static char* mtype; + +static int attachfiles(int, char**); +int xfmt(Fmt*); +int isnumeric(char*); +void die(void); +void setcore(Fhdr*); + +void +usage(void) +{ + fprint(2, "usage: acid [-c core] [-l module] [-m machine] [-qrw] [-k] [pid] [file]\n"); + exits("usage"); +} + +void +main(int argc, char *argv[]) +{ + Lsym *l; + Node *n; + char buf[128], *s; + int pid, i; + + argv0 = argv[0]; + pid = 0; + quiet = 1; + + mtype = 0; + ARGBEGIN{ + case 'A': + abort(); + break; + case 'm': + mtype = ARGF(); + break; + case 'w': + wtflag = 1; + break; + case 'l': + s = ARGF(); + if(s == 0) + usage(); + lm[nlm++] = s; + break; + case 'k': + kernel++; + break; + case 'q': + quiet = 0; + break; + case 'r': + pid = 1; + remote++; + kernel++; + break; + default: + usage(); + }ARGEND + + fmtinstall('x', xfmt); + fmtinstall('Z', Zfmt); + fmtinstall('L', locfmt); + Binit(&bioout, 1, OWRITE); + bout = &bioout; + + kinit(); + initialising = 1; + pushfile(0); + loadvars(); + installbuiltin(); + + if(mtype && machbyname(mtype) == 0) + print("unknown machine %s", mtype); + + if (attachfiles(argc, argv) < 0) + varreg(); /* use default register set on error */ + if(mach == nil) + mach = machcpu; + + symhdr = nil; /* not supposed to use this anymore */ + + l = mkvar("acid"); + l->v->set = 1; + l->v->type = TLIST; + l->v->store.u.l = nil; + + loadmodule("/usr/local/plan9/acid/port"); + for(i = 0; i < nlm; i++) { + if(access(lm[i], AREAD) >= 0) + loadmodule(lm[i]); + else { + sprint(buf, "/usr/local/plan9/acid/%s", lm[i]); + loadmodule(buf); + } + } + + userinit(); + varsym(); + + l = look("acidmap"); + if(l && l->proc) { + n = an(ONAME, ZN, ZN); + n->sym = l; + n = an(OCALL, n, ZN); + execute(n); + } + + interactive = 1; + initialising = 0; + line = 1; + + notify(catcher); + + for(;;) { + if(setjmp(err)) { + Binit(&bioout, 1, OWRITE); + unwind(); + } + stacked = 0; + + Bprint(bout, "acid; "); + + if(yyparse() != 1) + die(); + restartio(); + + unwind(); + } + Bputc(bout, '\n'); + exits(0); +} + +static int +attachfiles(int argc, char **argv) +{ + char *s; + int i, omode; + Fhdr *hdr; + Lsym *l; + Value *v; + + interactive = 0; + if(setjmp(err)) + return -1; + + /* + * Unix and Plan 9 differ on what the right order of pid, text, and core is. + * I never remember anyway. Let's just accept them in any order. + */ + omode = wtflag ? ORDWR : OREAD; + for(i=0; i<argc; i++){ + if(isnumeric(argv[i])){ + if(pid){ + fprint(2, "already have pid %d; ignoring pid %d\n", pid, argv[i]); + continue; + } + if(corhdr){ + fprint(2, "already have core %s; ignoring pid %d\n", corfil, pid); + continue; + } + pid = atoi(argv[i]); + continue; + } + if((hdr = crackhdr(argv[i], omode)) == nil){ + fprint(2, "crackhdr %s: %r\n", argv[i]); + continue; + } + fprint(2, "%s: %s %s %s\n", argv[i], hdr->aname, hdr->mname, hdr->fname); + if(hdr->ftype == FCORE){ + if(pid){ + fprint(2, "already have pid %d; ignoring core %s\n", pid, argv[i]); + uncrackhdr(hdr); + continue; + } + if(corhdr){ + fprint(2, "already have core %s; ignoring core %s\n", corfil, argv[i]); + uncrackhdr(hdr); + continue; + } + corhdr = hdr; + corfil = argv[i]; + }else{ + if(symhdr){ + fprint(2, "already have text %s; ignoring text %s\n", symfil, argv[i]); + uncrackhdr(hdr); + continue; + } + symhdr = hdr; + symfil = argv[i]; + } + } + + if(symhdr==nil){ + symfil = "a.out"; + if(pid){ + if((s = proctextfile(pid)) != nil){ + fprint(2, "pid %d: text %s\n", pid, s); + symfil = s; + } + } + /* XXX pull command from core */ + + if((hdr = crackhdr(symfil, omode)) == nil){ + fprint(2, "crackhdr %s: %r\n", symfil); + symfil = nil; + } + } + + if(symhdr) + syminit(symhdr); + + if(!mach) + mach = machcpu; + + /* + * Set up maps. + */ + symmap = allocmap(); + cormap = allocmap(); + if(symmap == nil || cormap == nil) + sysfatal("allocating maps: %r"); + + if(symhdr){ + if(mapfile(symhdr, 0, symmap, nil) < 0) + fprint(2, "mapping %s: %r\n", symfil); + mapfile(symhdr, 0, cormap, nil); + } + + l = mkvar("objtype"); + v = l->v; + v->store.fmt = 's'; + v->set = 1; + v->store.u.string = strnode(mach->name); + v->type = TSTRING; + + l = mkvar("textfile"); + v = l->v; + v->store.fmt = 's'; + v->set = 1; + v->store.u.string = strnode(symfil ? symfil : ""); + v->type = TSTRING; + + l = mkvar("systype"); + v = l->v; + v->store.fmt = 's'; + v->set = 1; + v->store.u.string = strnode(symhdr ? symhdr->aname : ""); + v->type = TSTRING; + + l = mkvar("corefile"); + v = l->v; + v->store.fmt = 's'; + v->set = 1; + v->store.u.string = strnode(corfil ? corfil : ""); + v->type = TSTRING; + + if(pid) + sproc(pid); + if(corhdr) + setcore(corhdr); + varreg(); + return 0; +} + +void +setcore(Fhdr *hdr) +{ + unmapproc(cormap); + unmapfile(corhdr, cormap); + free(correg); + correg = nil; + + if(hdr == nil) + error("no core"); + if(mapfile(hdr, 0, cormap, &correg) < 0) + error("mapfile %s: %r", hdr->filename); + corhdr = hdr; + corfil = hdr->filename; +} + +void +die(void) +{ + Lsym *s; + List *f; + + Bprint(bout, "\n"); + + s = look("proclist"); + if(s && s->v->type == TLIST) { + for(f = s->v->store.u.l; f; f = f->next){ + detachproc((int)f->store.u.ival); + Bprint(bout, "/bin/kill -9 %d\n", (int)f->store.u.ival); + } + } + exits(0); +} + +void +userinit(void) +{ + Lsym *l; + Node *n; + char buf[128], *p; + + sprint(buf, "/usr/local/plan9/acid/%s", mach->name); + loadmodule(buf); + p = getenv("home"); + if(p != 0) { + sprint(buf, "%s/lib/acid", p); + silent = 1; + loadmodule(buf); + } + + interactive = 0; + if(setjmp(err)) { + unwind(); + return; + } + l = look("acidinit"); + if(l && l->proc) { + n = an(ONAME, ZN, ZN); + n->sym = l; + n = an(OCALL, n, ZN); + execute(n); + } +} + +void +loadmodule(char *s) +{ + interactive = 0; + if(setjmp(err)) { + unwind(); + return; + } + pushfile(s); + silent = 0; + yyparse(); + popio(); + return; +} + +Node* +an(int op, Node *l, Node *r) +{ + Node *n; + + n = gmalloc(sizeof(Node)); + memset(n, 0, sizeof(Node)); + n->gc.gclink = gcl; + gcl = (Gc*)n; + n->op = op; + n->left = l; + n->right = r; + return n; +} + +List* +al(int t) +{ + List *l; + + l = gmalloc(sizeof(List)); + memset(l, 0, sizeof(List)); + l->type = t; + l->gc.gclink = gcl; + gcl = (Gc*)l; + return l; +} + +Node* +con(int v) +{ + Node *n; + + n = an(OCONST, ZN, ZN); + n->store.u.ival = v; + n->store.fmt = 'X'; + n->type = TINT; + return n; +} + +void +fatal(char *fmt, ...) +{ + char buf[128]; + va_list arg; + + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + fprint(2, "%s: %Z (fatal problem) %s\n", argv0, buf); + exits(buf); +} + +void +yyerror(char *fmt, ...) +{ + char buf[128]; + va_list arg; + + if(strcmp(fmt, "syntax error") == 0) { + yyerror("syntax error, near symbol '%s'", symbol); + return; + } + va_start(arg, fmt); + vseprint(buf, buf+sizeof(buf), fmt, arg); + va_end(arg); + print("%Z: %s\n", buf); +} + +void +marktree(Node *n) +{ + + if(n == 0) + return; + + marktree(n->left); + marktree(n->right); + + n->gc.gcmark = 1; + if(n->op != OCONST) + return; + + switch(n->type) { + case TSTRING: + n->store.u.string->gc.gcmark = 1; + break; + case TLIST: + marklist(n->store.u.l); + break; + case TCODE: + marktree(n->store.u.cc); + break; + } +} + +void +marklist(List *l) +{ + while(l) { + l->gc.gcmark = 1; + switch(l->type) { + case TSTRING: + l->store.u.string->gc.gcmark = 1; + break; + case TLIST: + marklist(l->store.u.l); + break; + case TCODE: + marktree(l->store.u.cc); + break; + } + l = l->next; + } +} + +void +gc(void) +{ + int i; + Lsym *f; + Value *v; + Gc *m, **p, *next; + + if(dogc < Mempergc) + return; + dogc = 0; + + /* Mark */ + for(m = gcl; m; m = m->gclink) + m->gcmark = 0; + + /* Scan */ + for(i = 0; i < Hashsize; i++) { + for(f = hash[i]; f; f = f->hash) { + marktree(f->proc); + if(f->lexval != Tid) + continue; + for(v = f->v; v; v = v->pop) { + switch(v->type) { + case TSTRING: + v->store.u.string->gc.gcmark = 1; + break; + case TLIST: + marklist(v->store.u.l); + break; + case TCODE: + marktree(v->store.u.cc); + break; + } + } + } + } + + /* Free */ + p = &gcl; + for(m = gcl; m; m = next) { + next = m->gclink; + if(m->gcmark == 0) { + *p = next; + free(m); /* Sleazy reliance on my malloc */ + } + else + p = &m->gclink; + } +} + +void* +gmalloc(long l) +{ + void *p; + + dogc += l; + p = malloc(l); + if(p == 0) + fatal("out of memory"); + return p; +} + +void +checkqid(int f1, int pid) +{ + int fd; + Dir *d1, *d2; + char buf[128]; + + if(kernel) + return; + + d1 = dirfstat(f1); + if(d1 == nil){ + print("checkqid: (qid not checked) dirfstat: %r\n"); + return; + } + + sprint(buf, "/proc/%d/text", pid); + fd = open(buf, OREAD); + if(fd < 0 || (d2 = dirfstat(fd)) == nil){ + print("checkqid: (qid not checked) dirstat %s: %r\n", buf); + free(d1); + if(fd >= 0) + close(fd); + return; + } + + close(fd); + + if(d1->qid.path != d2->qid.path || d1->qid.vers != d2->qid.vers || d1->qid.type != d2->qid.type){ + print("path %llux %llux vers %lud %lud type %d %d\n", + d1->qid.path, d2->qid.path, d1->qid.vers, d2->qid.vers, d1->qid.type, d2->qid.type); + print("warning: image does not match text for pid %d\n", pid); + } + free(d1); + free(d2); +} + +void +catcher(void *junk, char *s) +{ + USED(junk); + + if(strstr(s, "interrupt")) { + gotint = 1; + noted(NCONT); + } + if(strstr(s, "child")) + noted(NCONT); +fprint(2, "note: %s\n", s); + noted(NDFLT); +} + +char* +system(void) +{ + char *cpu, *p, *q; + static char kernel[128]; + + cpu = getenv("cputype"); + if(cpu == 0) { + cpu = "mips"; + print("$cputype not set; assuming %s\n", cpu); + } + p = getenv("terminal"); + if(p == 0 || (p=strchr(p, ' ')) == 0 || p[1] == ' ' || p[1] == 0) { + p = "9power"; + print("missing or bad $terminal; assuming %s\n", p); + } + else{ + p++; + q = strchr(p, ' '); + if(q) + *q = 0; + sprint(kernel, "/%s/9%s", cpu, p); + } + return kernel; +} + +int +isnumeric(char *s) +{ + while(*s) { + if(*s < '0' || *s > '9') + return 0; + s++; + } + return 1; +} + +int +xfmt(Fmt *f) +{ + f->flags ^= FmtSharp; + return __ifmt(f); +} diff --git a/src/cmd/acid/mkfile b/src/cmd/acid/mkfile new file mode 100644 index 00000000..dded62a6 --- /dev/null +++ b/src/cmd/acid/mkfile @@ -0,0 +1,32 @@ +<$PLAN9/src/mkhdr + +TARG=acid +UOFILES=\ + main.$O\ + lex.$O\ + util.$O\ + exec.$O\ + expr.$O\ + list.$O\ + builtin.$O\ + proc.$O\ + dot.$O\ + print.$O\ + +OFILES=$UOFILES y.tab.$O + +YFILES=dbg.y +HFILES=acid.h + +BIN=/home/rsc/bin + +SHORTLIB=mach2 regexp9 bio 9 + +<$PLAN9/src/mkone + +CFLAGS=$CFLAGS -I../libmach2 + +lex.$O: y.tab.h +util.$O: y.tab.h +builtin.$O: y.tab.h +main.$O: y.tab.h diff --git a/src/cmd/acid/print.c b/src/cmd/acid/print.c new file mode 100644 index 00000000..00d7b737 --- /dev/null +++ b/src/cmd/acid/print.c @@ -0,0 +1,446 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <ctype.h> +#include <mach.h> +#define Extern extern +#include "acid.h" + +static char *binop[] = +{ + [OMUL] "*", + [ODIV] "/", + [OMOD] "%", + [OADD] "+", + [OSUB] "-", + [ORSH] ">>", + [OLSH] "<<", + [OLT] "<", + [OGT] ">", + [OLEQ] "<=", + [OGEQ] ">=", + [OEQ] "==", + [ONEQ] "!=", + [OLAND] "&", + [OXOR] "^", + [OLOR] "|", + [OCAND] "&&", + [OCOR] "||", + [OASGN] " = ", +}; + +static char *tabs = "\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t"; +char *typenames[] = +{ + [TINT] "integer", + [TFLOAT] "float", + [TSTRING] "string", + [TLIST] "list", + [TCODE] "code", +}; + +int +cmp(const void *va, const void *vb) +{ + char **a = (char**)va; + char **b = (char**)vb; + + return strcmp(*a, *b); +} + +void +fundefs(void) +{ + Lsym *l; + char **vec; + int i, j, n, max, col, f, g, s; + + max = 0; + f = 0; + g = 100; + vec = malloc(sizeof(char*)*g); + if(vec == 0) + fatal("out of memory"); + + for(i = 0; i < Hashsize; i++) { + for(l = hash[i]; l; l = l->hash) { + if(l->proc == 0 && l->builtin == 0) + continue; + n = strlen(l->name); + if(n > max) + max = n; + if(f >= g) { + g *= 2; + vec = realloc(vec, sizeof(char*)*g); + if(vec == 0) + fatal("out of memory"); + } + vec[f++] = l->name; + } + } + qsort(vec, f, sizeof(char*), cmp); + max++; + col = 60/max; + s = (f+col-1)/col; + + for(i = 0; i < s; i++) { + for(j = i; j < f; j += s) + Bprint(bout, "%-*s", max, vec[j]); + Bprint(bout, "\n"); + } +} + +void +whatis(Lsym *l) +{ + int t; + int def; + Type *ti; + + if(l == 0) { + fundefs(); + return; + } + + def = 0; + if(l->v->set) { + t = l->v->type; + Bprint(bout, "%s variable", typenames[t]); + if(t == TINT || t == TFLOAT) + Bprint(bout, " format %c", l->v->store.fmt); + if(l->v->store.comt) + Bprint(bout, " complex %s", + l->v->store.comt->base->name); + Bputc(bout, '\n'); + def = 1; + } + if(l->lt) { + Bprint(bout, "complex %s {\n", l->name); + for(ti = l->lt; ti; ti = ti->next) { + if(ti->type) { + if(ti->fmt == 'a') { + Bprint(bout, "\t%s %d %s;\n", + ti->type->name, ti->offset, + ti->tag->name); + } + else { + Bprint(bout, "\t'%c' %s %d %s;\n", + ti->fmt, ti->type->name, ti->offset, + ti->tag->name); + } + } + else + Bprint(bout, "\t'%c' %d %s;\n", + ti->fmt, ti->offset, ti->tag->name); + } + Bprint(bout, "};\n"); + def = 1; + } + if(l->proc) { + Bprint(bout, "defn %s(", l->name); + pexpr(l->proc->left); + Bprint(bout, ") {\n"); + pcode(l->proc->right, 1); + Bprint(bout, "}\n"); + def = 1; + } + if(l->builtin) { + Bprint(bout, "builtin function\n"); + def = 1; + } + if(def == 0) + Bprint(bout, "%s is undefined\n", l->name); +} + +void +slist(Node *n, int d) +{ + if(n == 0) + return; + if(n->op == OLIST) + Bprint(bout, "%.*s{\n", d-1, tabs); + pcode(n, d); + if(n->op == OLIST) + Bprint(bout, "%.*s}\n", d-1, tabs); +} + +void +pcode(Node *n, int d) +{ + Node *r, *l; + + if(n == 0) + return; + + r = n->right; + l = n->left; + + switch(n->op) { + default: + Bprint(bout, "%.*s", d, tabs); + pexpr(n); + Bprint(bout, ";\n"); + break; + case OLIST: + pcode(n->left, d); + pcode(n->right, d); + break; + case OLOCAL: + Bprint(bout, "%.*slocal", d, tabs); + while(l) { + Bprint(bout, " %s", l->sym->name); + l = l->left; + if(l == 0) + Bprint(bout, ";\n"); + else + Bprint(bout, ","); + } + break; + case OCOMPLEX: + Bprint(bout, "%.*scomplex %s %s;\n", d, tabs, n->sym->name, l->sym->name); + break; + case OIF: + Bprint(bout, "%.*sif ", d, tabs); + pexpr(l); + d++; + Bprint(bout, " then\n"); + if(r && r->op == OELSE) { + slist(r->left, d); + Bprint(bout, "%.*selse\n", d-1, tabs); + slist(r->right, d); + } + else + slist(r, d); + break; + case OWHILE: + Bprint(bout, "%.*swhile ", d, tabs); + pexpr(l); + d++; + Bprint(bout, " do\n"); + slist(r, d); + break; + case ORET: + Bprint(bout, "%.*sreturn ", d, tabs); + pexpr(l); + Bprint(bout, ";\n"); + break; + case ODO: + Bprint(bout, "%.*sloop ", d, tabs); + pexpr(l->left); + Bprint(bout, ", "); + pexpr(l->right); + Bprint(bout, " do\n"); + slist(r, d+1); + } +} + +void +pexpr(Node *n) +{ + Node *r, *l; + + if(n == 0) + return; + + r = n->right; + l = n->left; + + switch(n->op) { + case ONAME: + Bprint(bout, "%s", n->sym->name); + break; + case OCONST: + switch(n->type) { + case TINT: + Bprint(bout, "%d", (int)n->store.u.ival); + break; + case TFLOAT: + Bprint(bout, "%g", n->store.u.fval); + break; + case TSTRING: + pstr(n->store.u.string); + break; + case TLIST: + break; + } + break; + case OMUL: + case ODIV: + case OMOD: + case OADD: + case OSUB: + case ORSH: + case OLSH: + case OLT: + case OGT: + case OLEQ: + case OGEQ: + case OEQ: + case ONEQ: + case OLAND: + case OXOR: + case OLOR: + case OCAND: + case OCOR: + Bputc(bout, '('); + pexpr(l); + Bprint(bout, binop[(uchar)n->op]); + pexpr(r); + Bputc(bout, ')'); + break; + case OASGN: + pexpr(l); + Bprint(bout, binop[(uchar)n->op]); + pexpr(r); + break; + case OINDM: + Bprint(bout, "*"); + pexpr(l); + break; + case OEDEC: + Bprint(bout, "--"); + pexpr(l); + break; + case OEINC: + Bprint(bout, "++"); + pexpr(l); + break; + case OPINC: + pexpr(l); + Bprint(bout, "++"); + break; + case OPDEC: + pexpr(l); + Bprint(bout, "--"); + break; + case ONOT: + Bprint(bout, "!"); + pexpr(l); + break; + case OLIST: + pexpr(l); + if(r) { + Bprint(bout, ","); + pexpr(r); + } + break; + case OCALL: + pexpr(l); + Bprint(bout, "("); + pexpr(r); + Bprint(bout, ")"); + break; + case OCTRUCT: + Bprint(bout, "{"); + pexpr(l); + Bprint(bout, "}"); + break; + case OHEAD: + Bprint(bout, "head "); + pexpr(l); + break; + case OTAIL: + Bprint(bout, "tail "); + pexpr(l); + break; + case OAPPEND: + Bprint(bout, "append "); + pexpr(l); + Bprint(bout, ","); + pexpr(r); + break; + case ODELETE: + Bprint(bout, "delete "); + pexpr(l); + Bprint(bout, ","); + pexpr(r); + break; + case ORET: + Bprint(bout, "return "); + pexpr(l); + break; + case OINDEX: + pexpr(l); + Bprint(bout, "["); + pexpr(r); + Bprint(bout, "]"); + break; + case OINDC: + Bprint(bout, "@"); + pexpr(l); + break; + case ODOT: + pexpr(l); + Bprint(bout, ".%s", n->sym->name); + break; + case OFRAME: + Bprint(bout, "%s:%s", n->sym->name, l->sym->name); + break; + case OCAST: + Bprint(bout, "(%s)", n->sym->name); + pexpr(l); + break; + case OFMT: + pexpr(l); + Bprint(bout, "\\%c", (int)r->store.u.ival); + break; + case OEVAL: + Bprint(bout, "eval "); + pexpr(l); + break; + case OWHAT: + Bprint(bout, "whatis"); + if(n->sym) + Bprint(bout, " %s", n->sym->name); + break; + } +} + +void +pstr(String *s) +{ + int i, c; + + Bputc(bout, '"'); + for(i = 0; i < s->len; i++) { + c = s->string[i]; + switch(c) { + case '\0': + c = '0'; + break; + case '\n': + c = 'n'; + break; + case '\r': + c = 'r'; + break; + case '\t': + c = 't'; + break; + case '\b': + c = 'b'; + break; + case '\f': + c = 'f'; + break; + case '\a': + c = 'a'; + break; + case '\v': + c = 'v'; + break; + case '\\': + c = '\\'; + break; + case '"': + c = '"'; + break; + default: + Bputc(bout, c); + continue; + } + Bputc(bout, '\\'); + Bputc(bout, c); + } + Bputc(bout, '"'); +} diff --git a/src/cmd/acid/proc.c b/src/cmd/acid/proc.c new file mode 100644 index 00000000..3b862aa9 --- /dev/null +++ b/src/cmd/acid/proc.c @@ -0,0 +1,251 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <ctype.h> +#include <mach.h> +#define Extern extern +#include "acid.h" +#include "y.tab.h" + +static void install(int); + +void +sproc(int xpid) +{ + Lsym *s; + int i; + + if(symmap == 0) + error("no map"); + + if(pid == xpid) + return; + + if(xpid <= 0) + error("bad pid"); + + unmapproc(cormap); + unmapfile(corhdr, cormap); + free(correg); + correg = nil; + + if(mapproc(xpid, cormap, &correg) < 0) + error("setproc %d: %r", pid); + + /* XXX check text file here? */ + + pid = xpid; + s = look("pid"); + s->v->store.u.ival = pid; + + for(i=0; i<cormap->nseg; i++) + if(cormap->seg[i].file == nil){ + if(strcmp(cormap->seg[i].name, "data") == 0) + cormap->seg[i].name = "*data"; + if(strcmp(cormap->seg[i].name, "text") == 0) + cormap->seg[i].name = "*text"; + } + install(pid); +} + +int +nproc(char **argv) +{ + char buf[128]; + int pid, i, fd; + + pid = fork(); + switch(pid) { + case -1: + error("new: fork %r"); + case 0: + rfork(RFNAMEG|RFNOTEG); + if(ctlproc(getpid(), "hang") < 0) + fatal("new: hang %d: %r", getpid()); + + close(0); + close(1); + close(2); + for(i = 3; i < NFD; i++) + close(i); + + open("/dev/tty", OREAD); + open("/dev/tty", OWRITE); + open("/dev/tty", OWRITE); + exec(argv[0], argv); + fatal("new: exec %s: %r"); + default: + install(pid); + msg(pid, "waitstop"); + notes(pid); + sproc(pid); + dostop(pid); + break; + } + + return pid; +} + +void +notes(int pid) +{ + Lsym *s; + Value *v; + int i, n; + char **notes; + List *l, **tail; + + s = look("notes"); + if(s == 0) + return; + + v = s->v; + n = procnotes(pid, ¬es); + if(n < 0) + error("procnotes pid=%d: %r", pid); + + v->set = 1; + v->type = TLIST; + v->store.u.l = 0; + tail = &v->store.u.l; + for(i=0; i<n; i++) { + l = al(TSTRING); + l->store.u.string = strnode(notes[i]); + l->store.fmt = 's'; + *tail = l; + tail = &l->next; + } + free(notes); +} + +void +dostop(int pid) +{ + Lsym *s; + Node *np, *p; + + s = look("stopped"); + if(s && s->proc) { + np = an(ONAME, ZN, ZN); + np->sym = s; + np->store.fmt = 'D'; + np->type = TINT; + p = con(pid); + p->store.fmt = 'D'; + np = an(OCALL, np, p); + execute(np); + } +} + +static void +install(int pid) +{ + Lsym *s; + List *l; + int i, new, p; + + new = -1; + for(i = 0; i < Maxproc; i++) { + p = ptab[i].pid; + if(p == pid) + return; + if(p == 0 && new == -1) + new = i; + } + if(new == -1) + error("no free process slots"); + + ptab[new].pid = pid; + + s = look("proclist"); + l = al(TINT); + l->store.fmt = 'D'; + l->store.u.ival = pid; + l->next = s->v->store.u.l; + s->v->store.u.l = l; + s->v->set = 1; +} + +void +deinstall(int pid) +{ + int i; + Lsym *s; + List *f, **d; + + for(i = 0; i < Maxproc; i++) { + if(ptab[i].pid == pid) { + detachproc(pid); + // close(ptab[i].ctl); + ptab[i].pid = 0; + s = look("proclist"); + d = &s->v->store.u.l; + for(f = *d; f; f = f->next) { + if(f->store.u.ival == pid) { + *d = f->next; + break; + } + } + s = look("pid"); + if(s->v->store.u.ival == pid) + s->v->store.u.ival = 0; + return; + } + } +} + +void +msg(int pid, char *msg) +{ + int i; + char err[ERRMAX]; + + for(i = 0; i < Maxproc; i++) { + if(ptab[i].pid == pid) { + if(ctlproc(pid, msg) < 0){ + errstr(err, sizeof err); + if(strcmp(err, "process exited") == 0) + deinstall(pid); + error("msg: pid=%d %s: %s", pid, msg, err); + } + return; + } + } + error("msg: pid=%d: not found for %s", pid, msg); +} + +char * +getstatus(int pid) +{ + int fd; + char *p; + + static char buf[128]; + + sprint(buf, "/proc/%d/status", pid); + fd = open(buf, OREAD); + if(fd < 0) + error("open %s: %r", buf); + read(fd, buf, sizeof(buf)); + close(fd); + p = buf+56+12; /* Do better! */ + while(*p == ' ') + p--; + p[1] = '\0'; + return buf+56; /* ditto */ +} + +Waitmsg* +waitfor(int pid) +{ + Waitmsg *w; + + for(;;) { + if((w = wait()) == nil) + error("wait %r"); + if(w->pid == pid) + return w; + free(w); + } + return nil; /* ken */ +} diff --git a/src/cmd/acid/util.c b/src/cmd/acid/util.c new file mode 100644 index 00000000..a40416c2 --- /dev/null +++ b/src/cmd/acid/util.c @@ -0,0 +1,344 @@ +#include <u.h> +#include <libc.h> +#include <bio.h> +#include <ctype.h> +#include <mach.h> +#define Extern extern +#include "acid.h" +#include "y.tab.h" + +static int syren; + +Lsym* +unique(char *buf, Symbol *s) +{ + Lsym *l; + int i, renamed; + + renamed = 0; + strcpy(buf, s->name); + for(;;) { + l = look(buf); + if(l == 0 || (l->lexval == Tid && l->v->set == 0)) + break; + + if(syren == 0 && !quiet) { + print("Symbol renames:\n"); + syren = 1; + } + i = strlen(buf)+1; + memmove(buf+1, buf, i); + buf[0] = '$'; + renamed++; + if(renamed > 5 && !quiet) { + print("Too many renames; must be X source!\n"); + break; + } + } + if(renamed && !quiet) + print("\t%s=%s %c/%Z\n", s->name, buf, s->type, s->loc); + if(l == 0) + l = enter(buf, Tid); + return l; +} + +void +varsym(void) +{ + Lsym *l; + Fhdr *fp; + + l = mkvar("symbols"); + if(l->v->set) + return; + + l->v->set = 1; + l->v->type = TLIST; + l->v->store.u.l = nil; + + for(fp=fhdrlist; fp; fp=fp->next){ + if(fp->ftype == FCORE) + continue; + addvarsym(fp); + } + + if(l->v->store.u.l == nil) + print("no debugging symbols\n"); +} + +void +addvarsym(Fhdr *fp) +{ + int i; + Symbol s; + Lsym *l; + String *file; + ulong v; + char buf[1024]; + List *list, **tail, *tl; + + if(fp == nil) + return; + + l = look("symbols"); + if(l == nil) + return; + + l->v->set = 1; + l->v->type = TLIST; + tail = &l->v->store.u.l; + while(*tail) + tail = &(*tail)->next; + + file = strnode(fp->filename); + for(i=0; findexsym(fp, i, &s)>=0; i++){ + switch(s.type) { + case 'T': + case 'L': + case 'D': + case 'B': + case 'b': + case 'd': + case 'l': + case 't': + if(s.name[0] == '.') + continue; + if(s.loc.type != LADDR) + continue; + v = s.loc.addr; + tl = al(TLIST); + *tail = tl; + tail = &tl->next; + + l = unique(buf, &s); + l->v->set = 1; + l->v->type = TINT; + l->v->store.u.ival = v; + if(l->v->store.comt == 0) + l->v->store.fmt = 'X'; + + /* Enter as list of { name, type, value, file } */ + list = al(TSTRING); + tl->store.u.l = list; + list->store.u.string = strnode(buf); + list->store.fmt = 's'; + list->next = al(TINT); + list = list->next; + list->store.fmt = 'c'; + list->store.u.ival = s.type; + list->next = al(TINT); + list = list->next; + list->store.fmt = 'X'; + list->store.u.ival = v; + list->next = al(TSTRING); + list = list->next; + list->store.fmt = 's'; + list->store.u.string = file; + } + } + *tail = nil; +} + +static int +infile(List *list, char *file, char **name) +{ + /* name */ + if(list->type != TSTRING) + return 0; + *name = list->store.u.string->string; + if(list->next == nil) + return 0; + list = list->next; + + /* type character */ + if(list->next == nil) + return 0; + list = list->next; + + /* address */ + if(list->next == nil) + return 0; + list = list->next; + + /* file */ + if(list->type != TSTRING) + return 0; + return strcmp(list->store.u.string->string, file) == 0; +} + +void +delvarsym(char *file) +{ + char *name; + Lsym *l; + List **lp, *p; + + l = look("symbols"); + if(l == nil) + return; + + if(l->v->type != TLIST) + return; + + for(lp=&l->v->store.u.l; *lp; lp=&(*lp)->next){ + while(*lp){ + p = *lp; + if(p->type != TLIST) + break; + if(!infile(p->store.u.l, file, &name)) + break; + *lp = p->next; + /* XXX remove from hash tables */ + } + if(*lp == nil) + break; + } +} + +void +varreg(void) +{ + Lsym *l; + Value *v; + Regdesc *r; + List **tail, *li; + + l = mkvar("registers"); + v = l->v; + v->set = 1; + v->type = TLIST; + v->store.u.l = 0; + tail = &v->store.u.l; + + if(mach == nil) + return; + + for(r = mach->reglist; r->name; r++) { + l = mkvar(r->name); + v = l->v; + v->set = 1; + v->store.u.ival = r->offset; + v->store.fmt = r->format; + v->type = TINT; + + li = al(TSTRING); + li->store.u.string = strnode(r->name); + li->store.fmt = 's'; + *tail = li; + tail = &li->next; + } + + l = mkvar("bpinst"); /* Breakpoint text */ + v = l->v; + v->type = TSTRING; + v->store.fmt = 's'; + v->set = 1; + v->store.u.string = gmalloc(sizeof(String)); + v->store.u.string->len = mach->bpsize; + v->store.u.string->string = gmalloc(mach->bpsize); + memmove(v->store.u.string->string, mach->bpinst, mach->bpsize); +} + +void +loadvars(void) +{ + Lsym *l; + Value *v; + + l = mkvar("proc"); + v = l->v; + v->type = TINT; + v->store.fmt = 'X'; + v->set = 1; + v->store.u.ival = 0; + + l = mkvar("pid"); /* Current process */ + v = l->v; + v->type = TINT; + v->store.fmt = 'D'; + v->set = 1; + v->store.u.ival = 0; + + mkvar("notes"); /* Pending notes */ + + l = mkvar("proclist"); /* Attached processes */ + l->v->type = TLIST; +} + +String* +strnodlen(char *name, int len) +{ + String *s; + + s = gmalloc(sizeof(String)+len+1); + s->string = (char*)s+sizeof(String); + s->len = len; + if(name != 0) + memmove(s->string, name, len); + s->string[len] = '\0'; + + s->gc.gclink = gcl; + gcl = (Gc*)s; + + return s; +} + +String* +strnode(char *name) +{ + return strnodlen(name, strlen(name)); +} + +String* +runenode(Rune *name) +{ + int len; + Rune *p; + String *s; + + p = name; + for(len = 0; *p; p++) + len++; + + len++; + len *= sizeof(Rune); + s = gmalloc(sizeof(String)+len); + s->string = (char*)s+sizeof(String); + s->len = len; + memmove(s->string, name, len); + + s->gc.gclink = gcl; + gcl = (Gc*)s; + + return s; +} + +String* +stradd(String *l, String *r) +{ + int len; + String *s; + + len = l->len+r->len; + s = gmalloc(sizeof(String)+len+1); + s->gc.gclink = gcl; + gcl = (Gc*)s; + s->len = len; + s->string = (char*)s+sizeof(String); + memmove(s->string, l->string, l->len); + memmove(s->string+l->len, r->string, r->len); + s->string[s->len] = 0; + return s; +} + +int +scmp(String *sr, String *sl) +{ + if(sr->len != sl->len) + return 0; + + if(memcmp(sr->string, sl->string, sl->len)) + return 0; + + return 1; +} |