summaryrefslogtreecommitdiff
path: root/utils/acid
diff options
context:
space:
mode:
Diffstat (limited to 'utils/acid')
-rw-r--r--utils/acid/386146
-rw-r--r--utils/acid/B.sh7
-rw-r--r--utils/acid/acid.h317
-rw-r--r--utils/acid/arm1
-rw-r--r--utils/acid/builtin.c1285
-rw-r--r--utils/acid/dbg.y402
-rw-r--r--utils/acid/dot.c152
-rw-r--r--utils/acid/exec.c490
-rw-r--r--utils/acid/expr.c1032
-rw-r--r--utils/acid/lex.c636
-rw-r--r--utils/acid/list.c276
-rw-r--r--utils/acid/main.c616
-rw-r--r--utils/acid/mips217
-rw-r--r--utils/acid/mkfile30
-rw-r--r--utils/acid/os-Nt.c198
-rw-r--r--utils/acid/os-Plan9.c157
-rw-r--r--utils/acid/os-Posix.c183
-rw-r--r--utils/acid/port547
-rw-r--r--utils/acid/print.c444
-rw-r--r--utils/acid/proc.c274
-rw-r--r--utils/acid/rdebug.c274
-rw-r--r--utils/acid/sparc218
-rw-r--r--utils/acid/util.c295
23 files changed, 8197 insertions, 0 deletions
diff --git a/utils/acid/386 b/utils/acid/386
new file mode 100644
index 00000000..53f4ce22
--- /dev/null
+++ b/utils/acid/386
@@ -0,0 +1,146 @@
+// 386 support
+
+defn acidinit() // Called after all the init modules are loaded
+{
+ bplist = {};
+ bpfmt = 'b';
+
+ srcpath = {
+ "./",
+ "/sys/src/libc/port/",
+ "/sys/src/libc/9sys/",
+ "/sys/src/libc/386/"
+ };
+
+ srcfiles = {}; // list of loaded files
+ srctext = {}; // the text of the files
+ Labspoff = 4; // adjustment to Label's sp
+ Labpcoff = 0; // adjustment to Label's pc
+}
+
+defn linkreg(addr)
+{
+ return 0;
+}
+
+defn stk() // trace
+{
+ _stk(*PC, *SP, 0, 0);
+}
+
+defn lstk() // trace with locals
+{
+ _stk(*PC, *SP, 0, 1);
+}
+
+defn kstk() // kernel stack
+{
+ _stk(*PC-Labpcoff, *SP-Labspoff, 0, 0);
+}
+
+defn lkstk() // kernel stack and locals
+{
+ _stk(*PC-Labpcoff, *SP-Labspoff, 0, 1);
+}
+defn gpr() // print general(hah hah!) purpose registers
+{
+ print("AX\t", *AX, " BX\t", *BX, " CX\t", *CX, " DX\t", *DX, "\n");
+ print("DI\t", *DI, " SI\t", *SI, " BP\t", *BP, "\n");
+}
+
+defn spr() // print special processor registers
+{
+ local pc;
+ local cause;
+
+ pc = *PC;
+ print("PC\t", pc, " ", fmt(pc, 'a'), " ");
+ pfl(pc);
+ print("SP\t", *SP, " ECODE ", *ECODE, " EFLAG ", *EFLAGS, "\n");
+ print("CS\t", *CS, " DS\t ", *DS, " SS\t", *SS, "\n");
+ print("GS\t", *GS, " FS\t ", *FS, " ES\t", *ES, "\n");
+
+ cause = *TRAP;
+ print("TRAP\t", cause, " ", reason(cause), "\n");
+}
+
+defn regs() // print all registers
+{
+ spr();
+ gpr();
+}
+
+defn pstop(pid)
+{
+ local l;
+ local pc;
+
+ pc = *PC;
+
+ print(pid,": ", reason(*TRAP), "\t");
+ print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n");
+
+ if notes then {
+ if notes[0] != "sys: breakpoint" then {
+ print("Notes pending:\n");
+ l = notes;
+ while l do {
+ print("\t", head l, "\n");
+ l = tail l;
+ }
+ }
+ }
+}
+
+aggr Ureg
+{
+ 'U' 0 di;
+ 'U' 4 si;
+ 'U' 8 bp;
+ 'U' 12 nsp;
+ 'U' 16 bx;
+ 'U' 20 dx;
+ 'U' 24 cx;
+ 'U' 28 ax;
+ 'U' 32 gs;
+ 'U' 36 fs;
+ 'U' 40 es;
+ 'U' 44 ds;
+ 'U' 48 trap;
+ 'U' 52 ecode;
+ 'U' 56 pc;
+ 'U' 60 cs;
+ 'U' 64 flags;
+ {
+ 'U' 68 usp;
+ 'U' 68 sp;
+ };
+ 'U' 72 ss;
+};
+
+defn
+Ureg(addr) {
+ complex Ureg addr;
+ print(" di ", addr.di, "\n");
+ print(" si ", addr.si, "\n");
+ print(" bp ", addr.bp, "\n");
+ print(" nsp ", addr.nsp, "\n");
+ print(" bx ", addr.bx, "\n");
+ print(" dx ", addr.dx, "\n");
+ print(" cx ", addr.cx, "\n");
+ print(" ax ", addr.ax, "\n");
+ print(" gs ", addr.gs, "\n");
+ print(" fs ", addr.fs, "\n");
+ print(" es ", addr.es, "\n");
+ print(" ds ", addr.ds, "\n");
+ print(" trap ", addr.trap, "\n");
+ print(" ecode ", addr.ecode, "\n");
+ print(" pc ", addr.pc, "\n");
+ print(" cs ", addr.cs, "\n");
+ print(" flags ", addr.flags, "\n");
+ print(" sp ", addr.sp, "\n");
+ print("}\n");
+ print(" ss ", addr.ss, "\n");
+};
+
+print("/sys/lib/acid/386");
diff --git a/utils/acid/B.sh b/utils/acid/B.sh
new file mode 100644
index 00000000..15570c7d
--- /dev/null
+++ b/utils/acid/B.sh
@@ -0,0 +1,7 @@
+#!/bin/sh
+line=`/bin/echo $1 | /bin/sed 's/-//'`
+if [ "x$EDITOR" = "x" ] ; then
+ vi +$line $2
+else
+ $EDITOR +$line $2
+fi
diff --git a/utils/acid/acid.h b/utils/acid/acid.h
new file mode 100644
index 00000000..68c8913d
--- /dev/null
+++ b/utils/acid/acid.h
@@ -0,0 +1,317 @@
+/* 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 remote;
+Extern int rdebug;
+Extern int remfd;
+Extern int protodebug;
+Extern int text;
+Extern int silent;
+Extern Fhdr fhdr;
+Extern int line;
+Extern Biobuf* bout;
+Extern Biobuf* io[32];
+Extern int iop;
+Extern char symbol[Strsize];
+Extern int interactive;
+Extern Node* code;
+Extern int na;
+Extern int wtflag;
+Extern Map* cormap;
+Extern Map* symmap;
+Extern Lsym* hash[Hashsize];
+Extern long dogc;
+Extern Rplace* ret;
+Extern char* filename;
+Extern char* aout;
+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 void (*expop[])(Node*, Node*);
+#define expr(n, r) (r)->nstore.comt=0; (*expop[(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 sival;
+ double sfval;
+ String* sstring;
+ List* sl;
+ Node* scc;
+ } u0;
+};
+
+struct List
+{
+ Gc lgc;
+ List* next;
+ char type;
+ Store lstore;
+};
+
+struct Value
+{
+ char set;
+ char type;
+ Store vstore;
+ 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 ngc;
+ char op;
+ char type;
+ Node* left;
+ Node* right;
+ Lsym* sym;
+ Store nstore;
+};
+#define ZN (Node*)0
+
+struct String
+{
+ Gc sgc;
+ char *string;
+ int len;
+};
+
+List* addlist(List*, List*);
+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 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 detach(void);
+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 install(int);
+void installbuiltin(void);
+void kinit(void);
+int Lfmt(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 setup_os_notify(void);
+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*);
+int opentty(char*, int);
+void closetty(int);
+void pcode(Node*, int);
+void pexpr(Node*);
+int popio(void);
+void pstr(String*);
+void pushfile(char*);
+void pushstr(Node*);
+ulong raddr(char*);
+void readtext(char*);
+int remcondset(char, ulong);
+int remcondstartstop(int);
+int remget(struct segment*, ulong, long, char*, int);
+int remoteio(int, char*, char*, int);
+int remote_read(int, char*, int);
+int remote_write(int, char*, int);
+int remput(struct segment*, ulong, long, char*, int);
+void restartio(void);
+vlong rget(Map*, char*);
+String *runenode(Rune*);
+char* runcmd(char*);
+int scmp(String*, String*);
+void setdbg_opt(char, int);
+int sendremote(int, char*);
+void sproc(int);
+String* stradd(String*, String*);
+String* strnode(char*);
+String* strnodlen(char*, int);
+char* mysystem(void);
+void trlist(Map*, ulong, ulong, Symbol*);
+void unwind(void);
+void userinit(void);
+void varreg(void);
+void varsym(void);
+char* 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/utils/acid/arm b/utils/acid/arm
new file mode 100644
index 00000000..79f6eb14
--- /dev/null
+++ b/utils/acid/arm
@@ -0,0 +1 @@
+please remove this file
diff --git a/utils/acid/builtin.c b/utils/acid/builtin.c
new file mode 100644
index 00000000..2afc447b
--- /dev/null
+++ b/utils/acid/builtin.c
@@ -0,0 +1,1285 @@
+#include <lib9.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 dokill(Node*,Node*);
+void waitstop(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 regexp(Node*, Node*);
+void _bpcondset(Node*, Node*);
+void _bpconddel(Node*, Node*);
+void setdebug(Node*, Node*);
+
+typedef struct Btab Btab;
+struct Btab
+{
+ char *name;
+ void (*fn)(Node*, Node*);
+} tab[] =
+{
+ "atof", cvtatof,
+ "atoi", cvtatoi,
+ "error", doerror,
+ "file", getfile,
+ "readfile", readfile,
+ "access", doaccess,
+ "filepc", filepc,
+ "fnbound", funcbound,
+ "fmt", fmt,
+ "follow", follow,
+ "itoa", cvtitoa,
+ "kill", dokill,
+ "match", match,
+ "newproc", newproc,
+ "pcfile", pcfile,
+ "pcline", pcline,
+ "print", bprint,
+ "printto", printto,
+ "rc", rc,
+ "reason", reason,
+ "setproc", setproc,
+ "sh", rc,
+ "start", start,
+ "startstop", startstop,
+ "status", status,
+ "stop", stop,
+ "strace", strace,
+ "waitstop", waitstop,
+ "map", map,
+ "interpret", interpret,
+ "include", include,
+ "regexp", regexp,
+ "debug", setdebug,
+ "_bpcondset", _bpcondset,
+ "_bpconddel", _bpconddel,
+ 0
+};
+
+void
+mkprint(Lsym *s)
+{
+ prnt = gmalloc(sizeof(Node));
+ prnt->op = OCALL;
+ prnt->left = gmalloc(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->nstore.fmt = 'D';
+ r->nstore.u0.sival = -1;
+
+ i = 0;
+ for(f = resl.nstore.u0.sl; f; f = f->next) {
+ if(resi.type == f->type) {
+ switch(resi.type) {
+ case TINT:
+ if(resi.nstore.u0.sival == f->lstore.u0.sival) {
+ r->nstore.u0.sival = i;
+ return;
+ }
+ break;
+ case TFLOAT:
+ if(resi.nstore.u0.sfval == f->lstore.u0.sfval) {
+ r->nstore.u0.sival = i;
+ return;
+ }
+ break;
+ case TSTRING:
+ if(scmp(resi.nstore.u0.sstring, f->lstore.u0.sstring)) {
+ r->nstore.u0.sival = 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] = aout;
+
+ if(args) {
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("newproc(): arg not string");
+ if(res.nstore.u0.sstring->len >= sizeof(buf))
+ error("newproc(): too many arguments");
+ memmove(buf, res.nstore.u0.sstring->string, res.nstore.u0.sstring->len);
+ buf[res.nstore.u0.sstring->len] = '\0';
+ p = buf;
+ e = buf+res.nstore.u0.sstring->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->nstore.fmt = 'D';
+ r->nstore.u0.sival = nproc(argv);
+}
+void
+startstop(Node *r, Node *args)
+{
+ Node res;
+
+ if(args == 0)
+ error("startstop(pid): no pid");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("startstop(pid): arg type");
+ if(rdebug) {
+ Lsym *s;
+ r->op = OCONST;
+ r->type = TINT;
+ r->nstore.u0.sival = remcondstartstop(res.nstore.u0.sival);
+ r->nstore.fmt = 'D';
+
+ s = look("_breakid");
+ if(s)
+ s->v->vstore.u0.sival = (int)r->nstore.u0.sival;
+ } else
+ msg(res.nstore.u0.sival, "startstop");
+ notes(res.nstore.u0.sival);
+ dostop(res.nstore.u0.sival);
+}
+
+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.nstore.u0.sival, "waitstop");
+ notes(res.nstore.u0.sival);
+ dostop(res.nstore.u0.sival);
+}
+
+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.nstore.u0.sival, "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.nstore.u0.sival, "stop");
+ notes(res.nstore.u0.sival);
+ dostop(res.nstore.u0.sival);
+}
+
+void
+dokill(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.nstore.u0.sival, "kill");
+ deinstall(res.nstore.u0.sival);
+}
+
+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.nstore.u0.sival);
+ r->nstore.u0.sstring = strnode(p);
+ r->op = OCONST;
+ r->nstore.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->nstore.fmt = 's';
+ r->nstore.u0.sstring = strnode((*machdata->excep)(cormap, rget));
+}
+
+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 = (*machdata->foll)(cormap, res.nstore.u0.sival, rget, f);
+ if (n < 0)
+ error("follow(addr): %r");
+ tail = &r->nstore.u0.sl;
+ for(i = 0; i < n; i++) {
+ l = al(TINT);
+ l->lstore.u0.sival = f[i];
+ l->lstore.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.nstore.u0.sival, bounds);
+ if (n != 0) {
+ r->nstore.u0.sl = al(TINT);
+ l = r->nstore.u0.sl;
+ l->lstore.u0.sival = bounds[0];
+ l->lstore.fmt = 'X';
+ l->next = al(TINT);
+ l = l->next;
+ l->lstore.u0.sival = bounds[1];
+ l->lstore.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.nstore.u0.sival);
+}
+
+void
+filepc(Node *r, Node *args)
+{
+ Node res;
+ char *p, c;
+
+ 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.nstore.u0.sstring->string, ':');
+ if(p == 0)
+ error("filepc(filename:line): bad arg format");
+
+ c = *p;
+ *p++ = '\0';
+ r->nstore.u0.sival = file2pc(res.nstore.u0.sstring->string, atoi(p));
+ p[-1] = c;
+ if(r->nstore.u0.sival == -1)
+ error("filepc(filename:line): can't find address");
+
+ r->op = OCONST;
+ r->type = TINT;
+ r->nstore.fmt = 'D';
+}
+
+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->nstore.u0.sival = yyparse();
+ interactive = isave;
+ popio();
+ r->op = OCONST;
+ r->type = TINT;
+ r->nstore.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");
+
+ pushfile(res.nstore.u0.sstring->string);
+
+ isave = interactive;
+ interactive = 0;
+ r->nstore.u0.sival = yyparse();
+ interactive = isave;
+ popio();
+ r->op = OCONST;
+ r->type = TINT;
+ r->nstore.fmt = 'D';
+}
+
+void
+rc(Node *r, Node *args)
+{
+ Node res;
+
+ char *p, *q;
+
+ USED(r);
+ if(args == 0)
+ error("error(string): arg count");
+ expr(args, &res);
+ if(res.type != TSTRING)
+ error("error(string): arg type");
+
+ p = runcmd(res.nstore.u0.sstring->string);
+ q = strrchr(p, ':');
+ if (q)
+ p = q+1;
+
+ r->op = OCONST;
+ r->type = TSTRING;
+ r->nstore.u0.sstring = strnode(p);
+ r->nstore.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.nstore.u0.sstring->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->nstore.u0.sival = 0;
+ if(access(res.nstore.u0.sstring->string, OREAD) == 0)
+ r->nstore.u0.sival = 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.nstore.u0.sstring->string, OREAD);
+ if(fd < 0)
+ return;
+
+ db = dirfstat(fd);
+ if(db == nil || db->length == 0)
+ n = 8192;
+ else
+ n = db->length;
+ free(db);
+
+ buf = gmalloc(n);
+ n = read(fd, buf, n);
+
+ if(n > 0) {
+ r->op = OCONST;
+ r->type = TSTRING;
+ r->nstore.u0.sstring = strnodlen(buf, n);
+ r->nstore.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->nstore.u0.sl = 0;
+
+ p = res.nstore.u0.sstring->string;
+ bp = Bopen(p, OREAD);
+ if(bp == 0)
+ return;
+
+ l = &r->nstore.u0.sl;
+ 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->lstore.u0.sstring = s;
+ new->lstore.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->nstore.u0.sfval = atof(res.nstore.u0.sstring->string);
+ r->nstore.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->nstore.u0.sival = strtoul(res.nstore.u0.sstring->string, 0, 0);
+ r->nstore.fmt = 'D';
+}
+
+void
+cvtitoa(Node *r, Node *args)
+{
+ Node res;
+ char buf[128];
+
+ if(args == 0)
+ error("itoa(integer): arg count");
+ expr(args, &res);
+ if(res.type != TINT)
+ error("itoa(integer): arg type");
+
+ sprint(buf, "%d", (int)res.nstore.u0.sival);
+ r->op = OCONST;
+ r->type = TSTRING;
+ r->nstore.u0.sstring = strnode(buf);
+ r->nstore.fmt = 's';
+}
+
+List*
+mapent(Map *m)
+{
+ int i;
+ List *l, *n, **t, *h;
+
+ h = 0;
+ t = &h;
+ for(i = 0; i < m->nsegs; i++) {
+ if(m->seg[i].inuse == 0)
+ continue;
+ l = al(TSTRING);
+ n = al(TLIST);
+ n->lstore.u0.sl = l;
+ *t = n;
+ t = &n->next;
+ l->lstore.u0.sstring = strnode(m->seg[i].name);
+ l->lstore.fmt = 's';
+ l->next = al(TINT);
+ l = l->next;
+ l->lstore.u0.sival = m->seg[i].b;
+ l->lstore.fmt = 'X';
+ l->next = al(TINT);
+ l = l->next;
+ l->lstore.u0.sival = m->seg[i].e;
+ l->lstore.fmt = 'X';
+ l->next = al(TINT);
+ l = l->next;
+ l->lstore.u0.sival = m->seg[i].f;
+ l->lstore.fmt = 'X';
+ }
+ return h;
+}
+
+void
+map(Node *r, Node *args)
+{
+ int i;
+ Map *m;
+ List *l;
+ char *ent;
+ 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.nstore.u0.sl) != 4)
+ error("map(list): list must have 4 entries");
+
+ l = res.nstore.u0.sl;
+ if(l->type != TSTRING)
+ error("map name must be a string");
+ ent = l->lstore.u0.sstring->string;
+ m = symmap;
+ i = findseg(m, ent);
+ if(i < 0) {
+ m = cormap;
+ i = findseg(m, ent);
+ }
+ if(i < 0)
+ error("%s is not a map entry", ent);
+ l = l->next;
+ if(l->type != TINT)
+ error("map entry not int");
+ m->seg[i].b = l->lstore.u0.sival;
+ if (strcmp(ent, "text") == 0)
+ textseg(l->lstore.u0.sival, &fhdr);
+ l = l->next;
+ if(l->type != TINT)
+ error("map entry not int");
+ m->seg[i].e = l->lstore.u0.sival;
+ l = l->next;
+ if(l->type != TINT)
+ error("map entry not int");
+ m->seg[i].f = l->lstore.u0.sival;
+ }
+
+ r->type = TLIST;
+ r->nstore.u0.sl = 0;
+ if(symmap)
+ r->nstore.u0.sl = mapent(symmap);
+ if(cormap) {
+ if(r->nstore.u0.sl == 0)
+ r->nstore.u0.sl = mapent(cormap);
+ else {
+ for(l = r->nstore.u0.sl; 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;
+ }
+}
+
+void
+strace(Node *r, Node *args)
+{
+ Node *av[Maxarg], *n, res;
+ ulong pc, sp;
+
+ na = 0;
+ flatten(av, args);
+ if(na != 3)
+ error("strace(pc, sp, link): arg count");
+
+ n = av[0];
+ expr(n, &res);
+ if(res.type != TINT)
+ error("strace(pc, sp, link): pc bad type");
+ pc = res.nstore.u0.sival;
+
+ n = av[1];
+ expr(n, &res);
+ if(res.type != TINT)
+ error("strace(pc, sp, link): sp bad type");
+ sp = res.nstore.u0.sival;
+
+ n = av[2];
+ expr(n, &res);
+ if(res.type != TINT)
+ error("strace(pc, sp, link): link bad type");
+
+ tracelist = 0;
+ if ((*machdata->ctrace)(cormap, pc, sp, res.nstore.u0.sival, trlist) <= 0)
+ error("no stack frame");
+ r->type = TLIST;
+ r->nstore.u0.sl = 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.nstore.u0.sstring->string);
+ if(rp == 0)
+ return;
+
+ expr(av[1], &res);
+ if(res.type != TSTRING)
+ error("regexp(pattern, string): bad string");
+
+ r->nstore.fmt = 'D';
+ r->type = TINT;
+ r->nstore.u0.sival = regexec(rp, res.nstore.u0.sstring->string, 0, 0);
+ free(rp);
+}
+
+char vfmt[] = "aBbcCdDfFgGiIoOqQrRsuUVxXYZ";
+
+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.nstore.u0.sival) == 0)
+ error("fmt(obj, fmt): bad format '%c'", (char)res.nstore.u0.sival);
+ expr(av[0], r);
+ r->nstore.fmt = res.nstore.u0.sival;
+}
+
+void
+patom(char type, Store *res)
+{
+ int i;
+ char buf[512];
+ extern char *typenames[];
+
+ switch(res->fmt) {
+ case 'c':
+ Bprint(bout, "%c", (int)res->u0.sival);
+ break;
+ case 'C':
+ if(res->u0.sival < ' ' || res->u0.sival >= 0x7f)
+ Bprint(bout, "%3d", (int)res->u0.sival&0xff);
+ else
+ Bprint(bout, "%3c", (int)res->u0.sival);
+ break;
+ case 'r':
+ Bprint(bout, "%C", (int)res->u0.sival);
+ break;
+ case 'B':
+ memset(buf, '0', 34);
+ buf[1] = 'b';
+ for(i = 0; i < 32; i++) {
+ if(res->u0.sival & (1<<i))
+ buf[33-i] = '1';
+ }
+ buf[35] = '\0';
+ Bprint(bout, "%s", buf);
+ break;
+ case 'b':
+ Bprint(bout, "%3d", (int)res->u0.sival&0xff);
+ break;
+ case 'X':
+ Bprint(bout, "%.8lux", (int)res->u0.sival);
+ break;
+ case 'x':
+ Bprint(bout, "%.4lux", (int)res->u0.sival&0xffff);
+ break;
+ case 'Y':
+ Bprint(bout, "%.16llux", res->u0.sival);
+ break;
+ case 'D':
+ Bprint(bout, "%d", (int)res->u0.sival);
+ break;
+ case 'd':
+ Bprint(bout, "%d", (ushort)res->u0.sival);
+ break;
+ case 'u':
+ Bprint(bout, "%ud", (int)res->u0.sival&0xffff);
+ break;
+ case 'U':
+ Bprint(bout, "%ud", (ulong)res->u0.sival);
+ break;
+ case 'Z':
+ Bprint(bout, "%llud", res->u0.sival);
+ break;
+ case 'V':
+ Bprint(bout, "%lld", res->u0.sival);
+ break;
+ case 'o':
+ Bprint(bout, "0%.11uo", (int)res->u0.sival&0xffff);
+ break;
+ case 'O':
+ Bprint(bout, "0%.6uo", (int)res->u0.sival);
+ break;
+ case 'q':
+ Bprint(bout, "0%.11o", (short)(res->u0.sival&0xffff));
+ break;
+ case 'Q':
+ Bprint(bout, "0%.6o", (int)res->u0.sival);
+ break;
+ case 'f':
+ case 'F':
+ if(type != TFLOAT)
+ Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]);
+ else
+ Bprint(bout, "%g", res->u0.sfval);
+ break;
+ case 's':
+ case 'g':
+ case 'G':
+ if(type != TSTRING)
+ Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]);
+ else
+ Bwrite(bout, res->u0.sstring->string, res->u0.sstring->len);
+ break;
+ case 'R':
+ if(type != TSTRING)
+ Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]);
+ else
+ Bprint(bout, "%S", res->u0.sstring->string);
+ break;
+ case 'a':
+ case 'A':
+ symoff(buf, sizeof(buf), res->u0.sival, CANY);
+ Bprint(bout, "%s", buf);
+ break;
+ case 'I':
+ case 'i':
+ if(type != TINT)
+ Bprint(bout, "*%c<%s>*", res->fmt, typenames[type]);
+ else {
+ if ((*machdata->das)(symmap, res->u0.sival, res->fmt, buf, sizeof(buf)) < 0)
+ Bprint(bout, "no instruction: %r");
+ else
+ Bprint(bout, "%s", buf);
+ }
+ break;
+ }
+}
+
+void
+blprint(List *l)
+{
+ Bprint(bout, "{");
+ while(l) {
+ switch(l->type) {
+ default:
+ patom(l->type, &l->lstore);
+ break;
+ case TSTRING:
+ Bputc(bout, '"');
+ patom(l->type, &l->lstore);
+ Bputc(bout, '"');
+ break;
+ case TLIST:
+ blprint(l->lstore.u0.sl);
+ break;
+ case TCODE:
+ pcode(l->lstore.u0.scc, 0);
+ break;
+ }
+ l = l->next;
+ if(l)
+ Bprint(bout, ", ");
+ }
+ Bprint(bout, "}");
+}
+
+int
+comx(Node res)
+{
+ Lsym *sl;
+ Node *n, xx;
+
+ if(res.nstore.fmt != 'a' && res.nstore.fmt != 'A')
+ return 0;
+
+ if(res.nstore.comt == 0 || res.nstore.comt->base == 0)
+ return 0;
+
+ sl = res.nstore.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.nstore);
+ break;
+ case TCODE:
+ pcode(res.nstore.u0.scc, 0);
+ break;
+ case TLIST:
+ blprint(res.nstore.u0.sl);
+ 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.nstore.u0.sstring->string, OWRITE, 0666);
+ if(fd < 0)
+ fd = open(res.nstore.u0.sstring->string, OWRITE);
+ if(fd < 0)
+ error("printto: open %s: %r", res.nstore.u0.sstring->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.nstore);
+ break;
+ case TLIST:
+ blprint(res.nstore.u0.sl);
+ 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->nstore.fmt = 's';
+ if(fileline(buf, sizeof(buf), res.nstore.u0.sival) == 0) {
+ r->nstore.u0.sstring = strnode("?file?");
+ return;
+ }
+ p = strrchr(buf, ':');
+ if(p == 0)
+ error("pcfile(addr): funny file %s", buf);
+ *p = '\0';
+ r->nstore.u0.sstring = 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->nstore.fmt = 'D';
+ if(fileline(buf, sizeof(buf), res.nstore.u0.sival) == 0) {
+ r->nstore.u0.sival = 0;
+ return;
+ }
+
+ p = strrchr(buf, ':');
+ if(p == 0)
+ error("pcline(addr): funny file %s", buf);
+ r->nstore.u0.sival = atoi(p+1);
+}
+
+void
+_bpcondset(Node *r, Node *args)
+{
+ Node id, p, addr, conds;
+ Node *av[Maxarg];
+ List *l;
+ char *op;
+ List *val;
+ ulong pid;
+
+ USED(r);
+
+ if(!rdebug)
+ error("_bpcondset(id, pid, addr, conds): only available with remote debugger\n");
+
+ if(args == 0)
+ error("_bpcondset(id, pid, addr, conds): not enough args");
+ na = 0;
+ flatten(av, args);
+ if(na != 4)
+ error("_bpcondset(id, pid, addr, conds): %s args",
+ na > 4 ? "too many" : "too few");
+ expr(av[0], &id);
+ expr(av[1], &p);
+ expr(av[2], &addr);
+ expr(av[3], &conds);
+ if(id.type != TINT)
+ error("_bpcondset(id, pid, addr, conds): id: integer expected");
+ if(p.type != TINT)
+ error("_bpcondset(pid, addr, conds): pid: integer expected");
+ if(addr.type != TINT)
+ error("_bpcondset(pid, addr, conds): addr: integer expected");
+ if(conds.type != TLIST)
+ error("_bpcondset(pid, addr, conds): conds: list expected");
+ l = conds.nstore.u0.sl;
+ remcondset('n', (ulong)id.nstore.u0.sival);
+ pid = (ulong)p.nstore.u0.sival;
+ if (pid != 0)
+ remcondset('k', pid);
+ while(l != nil) {
+ if(l->type != TLIST || listlen(l->lstore.u0.sl) != 2)
+ error("_bpcondset(addr, list): list elements are {\"op\", val} pairs");
+ if(l->lstore.u0.sl->type != TSTRING)
+ error("_bpcondset(addr, list): list elements are {string, val} pairs");
+ op = l->lstore.u0.sl->lstore.u0.sstring->string;
+ val = l->lstore.u0.sl->next;
+ if(val->type != TINT)
+ error("_bpcondset(addr, list): list elements are {string, int} pairs");
+ remcondset(op[0], (ulong)val->lstore.u0.sival);
+ l = l->next;
+ }
+ remcondset('b', (ulong)addr.nstore.u0.sival);
+}
+
+void
+_bpconddel(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ if(!rdebug)
+ error("_bpconddel(id): only available with remote debugger\n");
+
+ expr(args, &res);
+ if(res.type != TINT)
+ error("_bpconddel(id): arg type");
+
+ remcondset('d', (ulong)res.nstore.u0.sival);
+}
+
+void
+setdebug(Node *r, Node *args)
+{
+ Node res;
+
+ USED(r);
+ expr(args, &res);
+ if (res.type != TINT)
+ error("debug(type): bad type");
+ setdbg_opt((char)res.nstore.u0.sival, 1);
+}
+
+
+void
+setdbg_opt(char c, int prflag)
+{
+ switch(c) {
+ case 'p':
+ if (protodebug) {
+ protodebug = 0;
+ if (prflag)
+ print("Serial protocol debug is OFF\n");
+ } else {
+ protodebug = 1;
+ if (prflag)
+ print("Serial protocol debug is ON\n");
+ }
+ break;
+ default:
+ print("Invalid debug flag(%c), supported values: p\n", c);
+ break;
+ }
+}
diff --git a/utils/acid/dbg.y b/utils/acid/dbg.y
new file mode 100644
index 00000000..66c1b11d
--- /dev/null
+++ b/utils/acid/dbg.y
@@ -0,0 +1,402 @@
+%{
+#include <lib9.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
+
+%%
+
+prog :
+ | prog bigstmnt
+ ;
+
+bigstmnt : stmnt
+ {
+ execute($1);
+ gc();
+ if(interactive)
+ Bprint(bout, "acid: ");
+ }
+ | Tfn Tid '(' args ')' zsemi '{' slist '}'
+ {
+ if($2->builtin)
+ print("warning: %s() is a builtin; definition ignored\n", $2->name);
+ else
+ $2->proc = an(OLIST, $4, $8);
+ }
+ | 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->nstore.u0.sival = $2;
+ $3->nstore.fmt = $1;
+ $$ = $3;
+ }
+ | Tconst mname Tconst mname ';'
+ {
+ $4->nstore.u0.sival = $3;
+ $4->nstore.fmt = $1;
+ $4->right = $2;
+ $$ = $4;
+ }
+ | mname Tconst mname ';'
+ {
+ $3->nstore.u0.sival = $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);
+ }
+ | name
+ | Tconst
+ {
+ $$ = con($1);
+ }
+ | Tfconst
+ {
+ $$ = an(OCONST, ZN, ZN);
+ $$->type = TFLOAT;
+ $$->nstore.fmt = 'f';
+ $$->nstore.u0.sfval = $1;
+ }
+ | Tstring
+ {
+ $$ = an(OCONST, ZN, ZN);
+ $$->type = TSTRING;
+ $$->nstore.u0.sstring = $1;
+ $$->nstore.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/utils/acid/dot.c b/utils/acid/dot.c
new file mode 100644
index 00000000..89bcb2c8
--- /dev/null
+++ b/utils/acid/dot.c
@@ -0,0 +1,152 @@
+#include <lib9.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.nstore.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.nstore.comt, s);
+ if(t == 0)
+ error("no tag for (expr).%s", s);
+
+ /* Propagate types */
+ if(t->type)
+ r->nstore.comt = t->type->lt;
+
+ addr = res.nstore.u0.sival+t->offset;
+ if(t->fmt == 'a') {
+ r->op = OCONST;
+ r->nstore.fmt = 'a';
+ r->type = TINT;
+ r->nstore.u0.sival = 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 = gmalloc(sizeof(Type));
+ t->next = 0;
+ t->depth = d;
+ t->tag = m->sym;
+ t->base = base;
+ t->offset = m->nstore.u0.sival;
+ 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->nstore.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->vstore.comt = type->lt;
+ v->vstore.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 = gmalloc(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/utils/acid/exec.c b/utils/acid/exec.c
new file mode 100644
index 00000000..d110673b
--- /dev/null
+++ b/utils/acid/exec.c
@@ -0,0 +1,490 @@
+#include <lib9.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, "%L: (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;
+
+ if(gotint)
+ error("interrupted");
+
+ if(n == 0)
+ return;
+
+ if(stmnt++ > 5000) {
+ Bflush(bout);
+ stmnt = 0;
+ }
+
+ l = n->left;
+ r = n->right;
+ res.right = 0;
+ res.left = 0;
+ res.sym = 0;
+
+ switch(n->op) {
+ default:
+ expr(n, &res);
+ if(ret || (res.type == TLIST && res.nstore.u0.sl == 0))
+ break;
+ prnt->right = &res;
+ xx.right = 0;
+ xx.left = 0;
+ xx.sym = 0;
+ 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.nstore.u0.sival;
+ expr(l->right, &res);
+ if(res.type != TINT)
+ error("loop must have integer end");
+ e = res.nstore.u0.sival;
+ 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->nstore.u0.sival != 0)
+ true = 1;
+ break;
+ case TFLOAT:
+ if(n->nstore.u0.sfval != 0.0)
+ true = 1;
+ break;
+ case TSTRING:
+ if(n->nstore.u0.sstring->len)
+ true = 1;
+ break;
+ case TLIST:
+ if(n->nstore.u0.sl)
+ 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->nstore.fmt = 's';
+ r->nstore.u0.sstring = strnode(flt);
+ }
+ else {
+ r->type = TFLOAT;
+ r->nstore.u0.sfval = atof(flt);
+ }
+}
+
+void
+indir(Map *m, ulong addr, char fmt, Node *r)
+{
+ int i;
+ long ival;
+ vlong vval;
+ int ret;
+ uchar cval;
+ ushort sval;
+ char buf[512], reg[12];
+
+ r->op = OCONST;
+ r->nstore.fmt = fmt;
+ switch(fmt) {
+ default:
+ error("bad pointer format '%c' for *", fmt);
+ case 'c':
+ case 'C':
+ case 'b':
+ r->type = TINT;
+ ret = get1(m, addr, &cval, 1);
+ if (ret < 0)
+ error("indir: %r");
+ r->nstore.u0.sival = cval;
+ break;
+ case 'x':
+ case 'd':
+ case 'u':
+ case 'o':
+ case 'q':
+ case 'r':
+ r->type = TINT;
+ ret = get2(m, addr, &sval);
+ if (ret < 0)
+ error("indir: %r");
+ r->nstore.u0.sival = sval;
+ break;
+ case 'a':
+ case 'A':
+ case 'B':
+ case 'X':
+ case 'D':
+ case 'U':
+ case 'O':
+ case 'Q':
+ r->type = TINT;
+ ret = get4(m, addr, &ival);
+ if (ret < 0)
+ error("indir: %r");
+ r->nstore.u0.sival = ival;
+ break;
+ case 'V':
+ case 'Y':
+ case 'Z':
+ r->type = TINT;
+ ret = get8(m, addr, &vval);
+ if (ret < 0)
+ error("indir: %r");
+ r->nstore.u0.sival = vval;
+ break;
+ case 's':
+ r->type = TSTRING;
+ for(i = 0; i < sizeof(buf)-1; i++) {
+ ret = get1(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->nstore.u0.sstring = strnode(buf);
+ break;
+ case 'R':
+ r->type = TSTRING;
+ for(i = 0; i < sizeof(buf)-2; i += 2) {
+ ret = get1(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->nstore.u0.sstring = runenode((Rune*)buf);
+ break;
+ case 'i':
+ case 'I':
+ if ((*machdata->das)(m, addr, fmt, buf, sizeof(buf)) < 0)
+ error("indir: %r");
+ r->type = TSTRING;
+ r->nstore.fmt = 's';
+ r->nstore.u0.sstring = strnode(buf);
+ break;
+ case 'f':
+ ret = get1(m, addr, (uchar*)buf, mach->szfloat);
+ if (ret < 0)
+ error("indir: %r");
+ machdata->sftos(buf, sizeof(buf), (void*) buf);
+ convflt(r, buf);
+ break;
+ case 'g':
+ ret = get1(m, addr, (uchar*)buf, mach->szfloat);
+ if (ret < 0)
+ error("indir: %r");
+ machdata->sftos(buf, sizeof(buf), (void*) buf);
+ r->type = TSTRING;
+ r->nstore.u0.sstring = strnode(buf);
+ break;
+ case 'F':
+ ret = get1(m, addr, (uchar*)buf, mach->szdouble);
+ if (ret < 0)
+ error("indir: %r");
+ machdata->dftos(buf, sizeof(buf), (void*) buf);
+ convflt(r, buf);
+ break;
+ case '3': /* little endian ieee 80 with hole in bytes 8&9 */
+ ret = get1(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 */
+ leieee80ftos(buf, sizeof(buf), reg);
+ convflt(r, buf);
+ break;
+ case '8': /* big-endian ieee 80 */
+ ret = get1(m, addr, (uchar*)reg, 10);
+ if (ret < 0)
+ error("indir: %r");
+ beieee80ftos(buf, sizeof(buf), reg);
+ convflt(r, buf);
+ break;
+ case 'G':
+ ret = get1(m, addr, (uchar*)buf, mach->szdouble);
+ if (ret < 0)
+ error("indir: %r");
+ machdata->dftos(buf, sizeof(buf), (void*) buf);
+ r->type = TSTRING;
+ r->nstore.u0.sstring = 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->nstore.fmt = res.nstore.fmt;
+ r->nstore = res.nstore;
+
+ switch(res.nstore.fmt) {
+ default:
+ error("bad pointer format '%c' for */@=", res.nstore.fmt);
+ case 'c':
+ case 'C':
+ case 'b':
+ cval = res.nstore.u0.sival;
+ ret = put1(m, aes.nstore.u0.sival, &cval, 1);
+ break;
+ case 'r':
+ case 'x':
+ case 'd':
+ case 'u':
+ case 'o':
+ sval = res.nstore.u0.sival;
+ ret = put2(m, aes.nstore.u0.sival, sval);
+ r->nstore.u0.sival = sval;
+ break;
+ case 'a':
+ case 'A':
+ case 'B':
+ case 'X':
+ case 'D':
+ case 'U':
+ case 'O':
+ ret = put4(m, aes.nstore.u0.sival, res.nstore.u0.sival);
+ break;
+ case 'V':
+ case 'Y':
+ case 'Z':
+ ret = put8(m, aes.nstore.u0.sival, res.nstore.u0.sival);
+ break;
+ case 's':
+ case 'R':
+ ret = put1(m, aes.nstore.u0.sival, (uchar*)res.nstore.u0.sstring->string, res.nstore.u0.sstring->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.nstore.u0.scc = avp[i];
+ res.type = TCODE;
+ res.nstore.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->vstore = res.nstore;
+ 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/utils/acid/expr.c b/utils/acid/expr.c
new file mode 100644
index 00000000..da413742
--- /dev/null
+++ b/utils/acid/expr.c
@@ -0,0 +1,1032 @@
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+
+static int fsize[] =
+{
+ 0,0,0,0,0,0,0,0, /* 0-7 */
+ 0,0,0,0,0,0,0,0, /* 8-15 */
+ 0,0,0,0,0,0,0,0, /* 16-23 */
+ 0,0,0,0,0,0,0,0, /* 24-31 */
+ 0,0,0,0,0,0,0,0, /* 32-39 */
+ 0,0,0,0,0,0,0,0, /* 40-47 */
+ 0,0,0,0,0,0,0,0, /* 48-55 */
+ 0,0,0,0,0,0,0,0, /* 56-63 */
+ 0, /* 64 */
+ 4, /* 65 ['A'] 4, */
+ 4, /* 66 ['B'] 4, */
+ 1, /* 67 ['C'] 1, */
+ 4, /* 68 ['D'] 4, */
+ 0, /* 69 */
+ 8, /* 70 ['F'] 8, */
+ 8, /* 71 ['G'] 8, */
+ 0,0,0,0,0,0,0, /* 72-78 */
+ 4, /* 79 ['O'] 4, */
+ 0, /* 80 */
+ 4, /* 81 ['Q'] 4, */
+ 4, /* 82 ['R'] 4, */
+ 4, /* 83 ['S'] 4, */
+ 0, /* 84 */
+ 4, /* 85 ['U'] 4, */
+ 8, /* 86 ['V'] 8, */
+ 0, /* 87 */
+ 4, /* 88 ['X'] 4, */
+ 8, /* 89 ['Y'] 8, */
+ 8, /* 90 ['Z'] 8, */
+ 0,0,0,0,0,0, /* 91-96 */
+ 4, /* 97 ['a'] 4, */
+ 1, /* 98 ['b'] 1, */
+ 1, /* 99 ['c'] 1, */
+ 2, /* 100 ['d'] 2, */
+ 0, /* 101 */
+ 4, /* 102 ['f'] 4, */
+ 4, /* 103 ['g'] 4, */
+ 0,0,0,0,0,0,0, /* 104-110 */
+ 2, /* 111 ['o'] 2, */
+ 0, /* 112 */
+ 2, /* 113 ['q'] 2, */
+ 2, /* 114 ['r'] 2, */
+ 4, /* 115 ['s'] 4, */
+ 0, /* 116 */
+ 2, /* 117 ['u'] 2, */
+ 0,0, /* 118-119 */
+ 2, /* 120 ['x'] 2, */
+};
+
+int
+fmtsize(Value *v)
+{
+ int ret;
+
+ switch(v->vstore.fmt) {
+ default:
+ return fsize[v->vstore.fmt];
+ case 'i':
+ case 'I':
+ if(v->type != TINT || machdata == 0)
+ error("no size for i fmt pointer ++/--");
+ ret = (*machdata->instsize)(cormap, v->vstore.u0.sival);
+ if(ret < 0) {
+ ret = (*machdata->instsize)(symmap, v->vstore.u0.sival);
+ 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->nstore.u0.scc, 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->nstore.comt = n->sym->lt;
+ res->nstore.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.nstore.u0.sival, l.nstore.fmt, res);
+ res->nstore.comt = l.nstore.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.nstore.u0.sival, l.nstore.fmt, res);
+ res->nstore.comt = l.nstore.comt;
+}
+
+void
+oframe(Node *n, Node *res)
+{
+ char *p;
+ Node *lp;
+ long ival;
+ Frtype *f;
+
+ p = n->sym->name;
+ while(*p && *p == '$')
+ p++;
+ lp = n->left;
+ if(localaddr(cormap, p, lp->sym->name, &ival, rget) < 0)
+ error("colon: %r");
+
+ res->nstore.u0.sival = ival;
+ res->op = OCONST;
+ res->nstore.fmt = 'X';
+ res->type = TINT;
+
+ /* Try and set comt */
+ for(f = n->sym->local; f; f = f->next) {
+ if(f->var == lp->sym) {
+ res->nstore.comt = f->type;
+ res->nstore.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.nstore.u0.sival+(r.nstore.u0.sival*fsize[l.nstore.fmt]), l.nstore.fmt, res);
+ res->nstore.comt = l.nstore.comt;
+ res->nstore.fmt = l.nstore.fmt;
+ break;
+ case TLIST:
+ nthelem(l.nstore.u0.sl, r.nstore.u0.sival, res);
+ break;
+ case TSTRING:
+ res->nstore.u0.sival = 0;
+ if(r.nstore.u0.sival >= 0 && r.nstore.u0.sival < l.nstore.u0.sstring->len) {
+ int xx8; /* to get around bug in vc */
+ xx8 = r.nstore.u0.sival;
+ res->nstore.u0.sival = l.nstore.u0.sstring->string[xx8];
+ }
+ res->op = OCONST;
+ res->type = TINT;
+ res->nstore.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.nstore.u0.sl, r.nstore.u0.sival, 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.nstore.u0.sl) {
+ res->type = l.nstore.u0.sl->type;
+ res->nstore = l.nstore.u0.sl->lstore;
+ }
+ else {
+ res->type = TLIST;
+ res->nstore.u0.sl = 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.nstore.u0.sl)
+ res->nstore.u0.sl = l.nstore.u0.sl->next;
+ else
+ res->nstore.u0.sl = 0;
+}
+
+void
+oconst(Node *n, Node *res)
+{
+ res->op = OCONST;
+ res->type = n->type;
+ res->nstore = n->nstore;
+ res->nstore.comt = n->nstore.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->nstore = v->vstore;
+ res->nstore.comt = v->vstore.comt;
+}
+
+void
+octruct(Node *n, Node *res)
+{
+ res->op = OCONST;
+ res->type = TLIST;
+ res->nstore.u0.sl = 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->vstore = r.nstore;
+ res->op = OCONST;
+ res->type = v->type;
+ res->nstore = v->vstore;
+ res->nstore.comt = v->vstore.comt;
+ }
+}
+
+void
+oadd(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = l.nstore.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->nstore.u0.sival = l.nstore.u0.sival+r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sfval = l.nstore.u0.sival+r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type +");
+ }
+ break;
+ case TFLOAT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sfval = l.nstore.u0.sfval+r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sfval = l.nstore.u0.sfval+r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type +");
+ }
+ break;
+ case TSTRING:
+ if(r.type == TSTRING) {
+ res->type = TSTRING;
+ res->nstore.fmt = 's';
+ res->nstore.u0.sstring = stradd(l.nstore.u0.sstring, r.nstore.u0.sstring);
+ break;
+ }
+ error("bad rhs for +");
+ case TLIST:
+ res->type = TLIST;
+ switch(r.type) {
+ case TLIST:
+ res->nstore.u0.sl = addlist(l.nstore.u0.sl, r.nstore.u0.sl);
+ break;
+ default:
+ r.left = 0;
+ r.right = 0;
+ res->nstore.u0.sl = addlist(l.nstore.u0.sl, construct(&r));
+ break;
+ }
+ }
+}
+
+void
+osub(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = l.nstore.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->nstore.u0.sival = l.nstore.u0.sival-r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sfval = l.nstore.u0.sival-r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type -");
+ }
+ break;
+ case TFLOAT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sfval = l.nstore.u0.sfval-r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sfval = l.nstore.u0.sfval-r.nstore.u0.sfval;
+ 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->nstore.fmt = l.nstore.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->nstore.u0.sival = l.nstore.u0.sival*r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sfval = l.nstore.u0.sival*r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type *");
+ }
+ break;
+ case TFLOAT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sfval = l.nstore.u0.sfval*r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sfval = l.nstore.u0.sfval*r.nstore.u0.sfval;
+ 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->nstore.fmt = l.nstore.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.nstore.u0.sival == 0)
+ error("zero divide");
+ res->nstore.u0.sival = l.nstore.u0.sival/r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ if(r.nstore.u0.sfval == 0)
+ error("zero divide");
+ res->nstore.u0.sfval = l.nstore.u0.sival/r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type /");
+ }
+ break;
+ case TFLOAT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sfval = l.nstore.u0.sfval/r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sfval = l.nstore.u0.sfval/r.nstore.u0.sfval;
+ 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->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TINT;
+ if(l.type != TINT || r.type != TINT)
+ error("bad expr type %");
+ res->nstore.u0.sival = l.nstore.u0.sival%r.nstore.u0.sival;
+}
+
+void
+olsh(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TINT;
+ if(l.type != TINT || r.type != TINT)
+ error("bad expr type <<");
+ res->nstore.u0.sival = l.nstore.u0.sival<<r.nstore.u0.sival;
+}
+
+void
+orsh(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TINT;
+ if(l.type != TINT || r.type != TINT)
+ error("bad expr type >>");
+ res->nstore.u0.sival = l.nstore.u0.sival>>r.nstore.u0.sival;
+}
+
+void
+olt(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+
+ res->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TINT;
+ switch(l.type) {
+ default:
+ error("bad lhs type <");
+ case TINT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sival < r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sival < r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type <");
+ }
+ break;
+ case TFLOAT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sfval < r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sfval < r.nstore.u0.sfval;
+ 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->nstore.fmt = 'D';
+ res->op = OCONST;
+ res->type = TINT;
+ switch(l.type) {
+ default:
+ error("bad lhs type >");
+ case TINT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sival > r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sival > r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type >");
+ }
+ break;
+ case TFLOAT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sfval > r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sfval > r.nstore.u0.sfval;
+ 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->nstore.fmt = 'D';
+ res->op = OCONST;
+ res->type = TINT;
+ switch(l.type) {
+ default:
+ error("bad expr type <=");
+ case TINT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sival <= r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sival <= r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad expr type <=");
+ }
+ break;
+ case TFLOAT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sfval <= r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sfval <= r.nstore.u0.sfval;
+ 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->nstore.fmt = 'D';
+ res->op = OCONST;
+ res->type = TINT;
+ switch(l.type) {
+ default:
+ error("bad lhs type >=");
+ case TINT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sival >= r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sival >= r.nstore.u0.sfval;
+ break;
+ default:
+ error("bad rhs type >=");
+ }
+ break;
+ case TFLOAT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sfval >= r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sfval >= r.nstore.u0.sfval;
+ 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->nstore.fmt = 'D';
+ res->op = OCONST;
+ res->type = TINT;
+ res->nstore.u0.sival = 0;
+ switch(l.type) {
+ default:
+ break;
+ case TINT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sival == r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sival == r.nstore.u0.sfval;
+ break;
+ default:
+ break;
+ }
+ break;
+ case TFLOAT:
+ switch(r.type) {
+ case TINT:
+ res->nstore.u0.sival = l.nstore.u0.sfval == r.nstore.u0.sival;
+ break;
+ case TFLOAT:
+ res->nstore.u0.sival = l.nstore.u0.sfval == r.nstore.u0.sfval;
+ break;
+ default:
+ break;
+ }
+ break;
+ case TSTRING:
+ if(r.type == TSTRING) {
+ res->nstore.u0.sival = scmp(r.nstore.u0.sstring, l.nstore.u0.sstring);
+ break;
+ }
+ break;
+ case TLIST:
+ if(r.type == TLIST) {
+ res->nstore.u0.sival = listcmp(l.nstore.u0.sl, r.nstore.u0.sl);
+ break;
+ }
+ break;
+ }
+ if(n->op == ONEQ)
+ res->nstore.u0.sival = !res->nstore.u0.sival;
+}
+
+
+void
+oland(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TINT;
+ if(l.type != TINT || r.type != TINT)
+ error("bad expr type &");
+ res->nstore.u0.sival = l.nstore.u0.sival&r.nstore.u0.sival;
+}
+
+void
+oxor(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TINT;
+ if(l.type != TINT || r.type != TINT)
+ error("bad expr type ^");
+ res->nstore.u0.sival = l.nstore.u0.sival^r.nstore.u0.sival;
+}
+
+void
+olor(Node *n, Node *res)
+{
+ Node l, r;
+
+ expr(n->left, &l);
+ expr(n->right, &r);
+ res->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TINT;
+ if(l.type != TINT || r.type != TINT)
+ error("bad expr type |");
+ res->nstore.u0.sival = l.nstore.u0.sival|r.nstore.u0.sival;
+}
+
+void
+ocand(Node *n, Node *res)
+{
+ Node l, r;
+
+ res->nstore.fmt = l.nstore.fmt;
+ res->op = OCONST;
+ res->type = TINT;
+ res->nstore.u0.sival = 0;
+ expr(n->left, &l);
+ if(bool(&l) == 0)
+ return;
+ expr(n->right, &r);
+ if(bool(&r) == 0)
+ return;
+ res->nstore.u0.sival = 1;
+}
+
+void
+onot(Node *n, Node *res)
+{
+ Node l;
+
+ res->op = OCONST;
+ res->type = TINT;
+ res->nstore.u0.sival = 0;
+ expr(n->left, &l);
+ if(bool(&l) == 0)
+ res->nstore.u0.sival = 1;
+}
+
+void
+ocor(Node *n, Node *res)
+{
+ Node l, r;
+
+ res->op = OCONST;
+ res->type = TINT;
+ res->nstore.u0.sival = 0;
+ expr(n->left, &l);
+ if(bool(&l)) {
+ res->nstore.u0.sival = 1;
+ return;
+ }
+ expr(n->right, &r);
+ if(bool(&r)) {
+ res->nstore.u0.sival = 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->vstore.u0.sival -= fmtsize(v);
+ else
+ v->vstore.u0.sival += fmtsize(v);
+ break;
+ case TFLOAT:
+ if(n->op == OEDEC)
+ v->vstore.u0.sfval--;
+ else
+ v->vstore.u0.sfval++;
+ break;
+ default:
+ error("bad type for pre --/++");
+ }
+ res->nstore = v->vstore;
+}
+
+void
+opinc(Node *n, Node *res)
+{
+ Value *v;
+
+ chklval(n->left);
+ v = n->left->sym->v;
+ res->op = OCONST;
+ res->type = v->type;
+ res->nstore = v->vstore;
+ switch(v->type) {
+ case TINT:
+ if(n->op == OPDEC)
+ v->vstore.u0.sival -= fmtsize(v);
+ else
+ v->vstore.u0.sival += fmtsize(v);
+ break;
+ case TFLOAT:
+ if(n->op == OPDEC)
+ v->vstore.u0.sfval--;
+ else
+ v->vstore.u0.sfval++;
+ 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->nstore.u0.sl = 0;
+
+ chklval(n->left);
+ s = n->left->sym;
+
+ if(s->builtin) {
+ (*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->nstore.fmt = n->right->nstore.u0.sival;
+}
+
+void
+owhat(Node *n, Node *res)
+{
+ res->op = OCONST; /* Default return value */
+ res->type = TLIST;
+ res->nstore.u0.sl = 0;
+ whatis(n->sym);
+}
+
+void (*expop[])(Node*, Node*) =
+{
+ oname, /* [ONAME] oname, */
+ oconst, /* [OCONST] oconst, */
+ omul, /* [OMUL] omul, */
+ odiv, /* [ODIV] odiv, */
+ omod, /* [OMOD] omod, */
+ oadd, /* [OADD] oadd, */
+ osub, /* [OSUB] osub, */
+ orsh, /* [ORSH] orsh, */
+ olsh, /* [OLSH] olsh, */
+ olt, /* [OLT] olt, */
+ ogt, /* [OGT] ogt, */
+ oleq, /* [OLEQ] oleq, */
+ ogeq, /* [OGEQ] ogeq, */
+ oeq, /* [OEQ] oeq, */
+ oeq, /* [ONEQ] oeq, */
+ oland, /* [OLAND] oland, */
+ oxor, /* [OXOR] oxor, */
+ olor, /* [OLOR] olor, */
+ ocand, /* [OCAND] ocand, */
+ ocor, /* [OCOR] ocor, */
+ oasgn, /* [OASGN] oasgn, */
+ oindm, /* [OINDM] oindm, */
+ oeinc, /* [OEDEC] oeinc, */
+ oeinc, /* [OEINC] oeinc, */
+ opinc, /* [OPINC] opinc, */
+ opinc, /* [OPDEC] opinc, */
+ onot, /* [ONOT] onot, */
+ 0, /* [OIF] 0, */
+ 0, /* [ODO] 0, */
+ olist, /* [OLIST] olist, */
+ ocall, /* [OCALL] ocall, */
+ octruct, /* [OCTRUCT] octruct, */
+ 0, /* [OWHILE] 0, */
+ 0, /* [OELSE] 0, */
+ ohead, /* [OHEAD] ohead, */
+ otail, /* [OTAIL] otail, */
+ oappend, /* [OAPPEND] oappend, */
+ 0, /* [ORET] 0, */
+ oindex, /* [OINDEX] oindex, */
+ oindc, /* [OINDC] oindc, */
+ odot, /* [ODOT] odot, */
+ 0, /* [OLOCAL] 0, */
+ oframe, /* [OFRAME] oframe, */
+ 0, /* [OCOMPLEX] 0, */
+ odelete, /* [ODELETE] odelete, */
+ ocast, /* [OCAST] ocast, */
+ ofmt, /* [OFMT] ofmt, */
+ oeval, /* [OEVAL] oeval, */
+ owhat, /* [OWHAT] owhat, */
+};
diff --git a/utils/acid/lex.c b/utils/acid/lex.c
new file mode 100644
index 00000000..364bcae9
--- /dev/null
+++ b/utils/acid/lex.c
@@ -0,0 +1,636 @@
+#include <lib9.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,
+ 0, 0
+};
+
+char cmap[256] =
+{
+ 0,0,0,0,0,0,0,0, /* 0-7 */
+ 0,0,0,0,0,0,0,0, /* 8-15 */
+ 0,0,0,0,0,0,0,0, /* 16-23 */
+ 0,0,0,0,0,0,0,0, /* 24-31 */
+ 0,0, /* 32-33 */
+ '"'+1, /* 34 ['"'] '"'+1, */
+ 0,0,0,0,0, /* 35-39 */
+ 0,0,0,0,0,0,0,0, /* 40-47 */
+ '\0'+1, /* 48 ['0'] '\0'+1, */
+ 0,0,0,0,0,0,0, /* 49-55 */
+ 0,0,0,0,0,0,0,0, /* 56-63 */
+ 0,0,0,0,0,0,0,0, /* 64-71 */
+ 0,0,0,0,0,0,0,0, /* 72-79 */
+ 0,0,0,0,0,0,0,0, /* 80-87 */
+ 0,0,0,0, /* 88-91 */
+ '\\'+1, /* 92 ['\\'] '\\'+1, */
+ 0,0,0,0, /* 93-96 */
+ '\a'+1, /* 97 ['a'] '\a'+1, */
+ '\b'+1, /* 98 ['b'] '\b'+1, */
+ 0,0,0, /* 99-101 */
+ '\f'+1, /* 102 ['f'] '\f'+1, */
+ 0,0,0,0,0,0,0, /* 103-109 */
+ '\n'+1, /* 110 ['n'] '\n'+1, */
+ 0,0,0, /* 111-113 */
+ '\r'+1, /* 114 ['r'] '\r'+1, */
+ 0, /* 115 */
+ '\t'+1, /* 116 ['t'] '\t'+1, */
+ 0, /* 117 */
+ '\v'+1, /* 118 ['v'] '\v'+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
+pushfile(char *file)
+{
+ Biobuf *b;
+ IOstack *io;
+ char buf[512];
+ extern char *acidlib;
+
+ if(file){
+ b = Bopen(file, OREAD);
+ if(b == nil && strchr(file, '/') == 0){
+ snprint(buf, sizeof(buf)-1, "%s/%s", acidlib, file);
+ b = Bopen(buf, OREAD);
+ }
+ }
+ else{
+ b = gmalloc(sizeof(Biobuf));
+ if (Binit(b, 0, OREAD) == Beof) {
+ free(b);
+ b = 0;
+ }
+ file = "<stdin>";
+ }
+
+ if(b == 0)
+ error("pushfile: %s: %r", file);
+
+ io = gmalloc(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;
+}
+
+void
+pushstr(Node *s)
+{
+ IOstack *io;
+
+ io = gmalloc(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->nstore.u0.sstring->string);
+ if(io->text == 0)
+ fatal("no memory");
+ io->ip = io->text;
+ io->fin = 0;
+ io->prev = lexio;
+ lexio = io;
+}
+
+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);
+ return 1;
+}
+
+int
+Lfmt(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");
+ return fmtstrcpy(f, buf);
+}
+
+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[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 '\r':
+ 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 '\r':
+ case '\t':
+ goto loop;
+
+ case '\n':
+ line++;
+ if(interactive == 0)
+ goto loop;
+ if(stacked) {
+ print("\t");
+ goto loop;
+ }
+ 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 == '\r')
+ continue;
+ 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));
+ s->name = strdup(name);
+
+ s->hash = hash[h];
+ hash[h] = s;
+ s->lexval = t;
+
+ v = gmalloc(sizeof(Value));
+ s->v = v;
+
+ v->vstore.fmt = 'X';
+ v->type = TINT;
+
+ return s;
+}
+
+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/utils/acid/list.c b/utils/acid/list.c
new file mode 100644
index 00000000..ced2f4d8
--- /dev/null
+++ b/utils/acid/list.c
@@ -0,0 +1,276 @@
+#include <lib9.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->lstore = res.nstore;
+ *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->lstore = val->nstore;
+ l->next = 0;
+
+ r->op = OCONST;
+ r->type = TLIST;
+
+ if(list->nstore.u0.sl == 0) {
+ list->nstore.u0.sl = l;
+ r->nstore.u0.sl = l;
+ return;
+ }
+ for(f = list->nstore.u0.sl; f->next; f = f->next)
+ ;
+ f->next = l;
+ r->nstore.u0.sl = list->nstore.u0.sl;
+}
+
+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->lstore.u0.sival != r->lstore.u0.sival)
+ return 0;
+ break;
+ case TFLOAT:
+ if(l->lstore.u0.sfval != r->lstore.u0.sfval)
+ return 0;
+ break;
+ case TSTRING:
+ if(scmp(l->lstore.u0.sstring, r->lstore.u0.sstring) == 0)
+ return 0;
+ break;
+ case TLIST:
+ if(listcmp(l->lstore.u0.sl, r->lstore.u0.sl) == 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->nstore.u0.sl = 0;
+ return;
+ }
+ res->type = l->type;
+ res->nstore = l->lstore;
+}
+
+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->nstore.u0.sl = l;
+
+ for(tl = &res->nstore.u0.sl; 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->lstore.u0.sl = l;
+ l->lstore.fmt = 's';
+ l->lstore.u0.sstring = strnode(s);
+ l->next = al(TINT);
+ l = l->next;
+ l->lstore.fmt = 'X';
+ l->lstore.u0.sival = v;
+
+ return tl;
+}
+
+static List*
+listlocals(Map *map, Symbol *fn, ulong fp)
+{
+ int i;
+ long val;
+ Symbol s;
+ List **tail, *l2;
+
+ l2 = 0;
+ tail = &l2;
+ s = *fn;
+
+ for(i = 0; localsym(&s, i); i++) {
+ if(s.class != CAUTO)
+ continue;
+ if(s.name[0] == '.')
+ continue;
+
+ if(get4(map, fp-s.value, &val) > 0) {
+ *tail = listvar(s.name, val);
+ tail = &(*tail)->next;
+ }
+ }
+ return l2;
+}
+
+static List*
+listparams(Map *map, Symbol *fn, ulong fp)
+{
+ int i;
+ Symbol s;
+ long v;
+ List **tail, *l2;
+
+ l2 = 0;
+ tail = &l2;
+ fp += mach->szaddr; /* skip saved pc */
+ s = *fn;
+ for(i = 0; localsym(&s, i); i++) {
+ if (s.class != CPARAM)
+ continue;
+
+ if(get4(map, fp+s.value, &v) > 0) {
+ *tail = listvar(s.name, v);
+ tail = &(*tail)->next;
+ }
+ }
+ return l2;
+}
+
+void
+trlist(Map *map, ulong pc, ulong sp, Symbol *sym)
+{
+ List *q, *l;
+
+ static List **tail;
+
+ if (tracelist == 0) { /* first time */
+ tracelist = al(TLIST);
+ tail = &tracelist;
+ }
+
+ q = al(TLIST);
+ *tail = q;
+ tail = &q->next;
+
+ l = al(TINT); /* Function address */
+ q->lstore.u0.sl = l;
+ l->lstore.u0.sival = sym->value;
+ l->lstore.fmt = 'X';
+
+ l->next = al(TINT); /* called from address */
+ l = l->next;
+ l->lstore.u0.sival = pc;
+ l->lstore.fmt = 'X';
+
+ l->next = al(TLIST); /* make list of params */
+ l = l->next;
+ l->lstore.u0.sl = listparams(map, sym, sp);
+
+ l->next = al(TLIST); /* make list of locals */
+ l = l->next;
+ l->lstore.u0.sl = listlocals(map, sym, sp);
+}
diff --git a/utils/acid/main.c b/utils/acid/main.c
new file mode 100644
index 00000000..5bd85f13
--- /dev/null
+++ b/utils/acid/main.c
@@ -0,0 +1,616 @@
+/*#include <u.h>*/
+#include <lib9.h>
+#include <bio.h>
+#include "mach.h"
+#define Extern
+#include "acid.h"
+#include "y.tab.h"
+
+char *argv0;
+char *acidlib;
+static Biobuf bioout;
+static char prog[128];
+static char* lm[16];
+static int nlm;
+static char* mtype;
+
+static int attachfiles(char*, int);
+int xfmt(Fmt*);
+extern int gfltconv(Fmt*), _ifmt(Fmt*);
+int isnumeric(char*);
+void die(void);
+
+void
+usage(void)
+{
+ fprint(2, "usage: acid [-l module] [-m machine] [-qrw] [-k] [-d flag] [-R tty] [pid] [file]\n");
+ exits("usage");
+}
+
+void
+main(int argc, char *argv[])
+{
+ Dir *db;
+ Lsym *l;
+ Node *n;
+ char buf[128], *s;
+ int pid, i;
+ char *p;
+ char afile[512];
+
+ argv0 = argv[0];
+ pid = 0;
+ aout = "v.out";
+ quiet = 1;
+ /* turn off all debugging */
+ protodebug = 0;
+
+ mtype = 0;
+ ARGBEGIN{
+ case 'm':
+ mtype = ARGF();
+ break;
+ case 'w':
+ wtflag = 1;
+ break;
+ case 'l':
+ s = ARGF();
+ if(s == 0)
+ usage();
+ lm[nlm++] = s;
+ break;
+ case 'd':
+ p = ARGF();
+ if (p == 0)
+ usage();
+ while (*p) {
+ setdbg_opt(*p, 0); /* don't print set message */
+ p++;
+ }
+ break;
+ case 'k':
+ kernel++;
+ break;
+ case 'q':
+ quiet = 0;
+ break;
+ case 'r':
+ pid = 1;
+ remote++;
+ kernel++;
+ break;
+ case 'R':
+ pid = 1;
+ rdebug++;
+ s = ARGF();
+ if(s == 0)
+ usage();
+ remfd = opentty(s, 0);
+ if(remfd < 0){
+ fprint(2, "acid: can't open %s: %r\n", s);
+ exits("open");
+ }
+ break;
+ default:
+ usage();
+ }ARGEND
+
+ if(argc > 0) {
+ if(remote || rdebug)
+ aout = argv[0];
+ else
+ if(isnumeric(argv[0])) {
+ pid = atoi(argv[0]);
+ sprint(prog, "/proc/%d/text", pid);
+ aout = prog;
+ if(argc > 1)
+ aout = argv[1];
+ else if(kernel)
+ aout = mysystem();
+ }
+ else {
+ if(kernel) {
+ print("-k requires a pid");
+ kernel = 0;
+ }
+ aout = argv[0];
+ }
+ } else if(rdebug)
+ aout = "/386/bpc";
+ else if(remote)
+ aout = "/mips/bcarrera";
+
+ fmtinstall('x', xfmt);
+ fmtinstall('L', Lfmt);
+ fmtinstall('f', gfltconv);
+ fmtinstall('F', gfltconv);
+ fmtinstall('g', gfltconv);
+ fmtinstall('G', gfltconv);
+ fmtinstall('e', gfltconv);
+ fmtinstall('E', gfltconv);
+ 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(aout, pid) < 0)
+ varreg(); /* use default register set on error */
+
+ acidlib = getenv("ACIDLIB");
+ if(acidlib == nil){
+ p = getenv("ROOT");
+ if(p == nil)
+ p = "/usr/inferno";
+ snprint(afile, sizeof(afile)-1, "%s/lib/acid", p);
+ acidlib = strdup(afile);
+ }
+
+ snprint(afile, sizeof(afile)-1, "%s/port", acidlib);
+ loadmodule(afile);
+ for(i = 0; i < nlm; i++) {
+ if((db = dirstat(lm[i])) != nil) {
+ free(db);
+ loadmodule(lm[i]);
+ } else {
+ sprint(buf, "%s/%s", acidlib, 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;
+
+ setup_os_notify();
+
+ 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(char *aout, int pid)
+{
+ interactive = 0;
+ if(setjmp(err))
+ return -1;
+
+ if(aout) { /* executable given */
+ if(wtflag)
+ text = open(aout, ORDWR);
+ else
+ text = open(aout, OREAD);
+
+ if(text < 0)
+ error("%s: can't open %s: %r\n", argv0, aout);
+ readtext(aout);
+ }
+ if(pid) /* pid given */
+ sproc(pid);
+ return 0;
+}
+
+void
+die(void)
+{
+ Lsym *s;
+ List *f;
+
+ Bprint(bout, "\n");
+
+ s = look("proclist");
+ if(!rdebug && s && s->v->type == TLIST) {
+ for(f = s->v->vstore.u0.sl; f; f = f->next)
+ Bprint(bout, "echo kill > /proc/%d/ctl\n", (int)f->lstore.u0.sival);
+ }
+ exits(0);
+}
+
+void
+userinit(void)
+{
+ Lsym *l;
+ Node *n;
+ char buf[512], *p;
+
+
+ p = getenv("home");
+ if(p == 0)
+ p = getenv("HOME");
+ if(p != 0) {
+ snprint(buf, sizeof(buf)-1, "%s/lib/acid", p);
+ silent = 1;
+ loadmodule(buf);
+ }
+
+ if(rdebug){
+ snprint(buf, sizeof(buf)-1, "%s/rdebug", acidlib);
+ loadmodule(buf);
+ }
+
+ snprint(buf, sizeof(buf)-1, "%s/%s", acidlib, mach->name);
+ 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;
+}
+
+void
+readtext(char *s)
+{
+ Dir *d;
+ Lsym *l;
+ Value *v;
+ Symbol sym;
+ ulong length;
+ extern Machdata mipsmach;
+
+ if(mtype != 0){
+ symmap = newmap(0, 1);
+ if(symmap == 0)
+ print("%s: (error) loadmap: cannot make symbol map\n", argv0);
+ length = 1<<24;
+ d = dirfstat(text);
+ if(d != nil) {
+ length = d->length;
+ free(d);
+ }
+ setmap(symmap, text, 0, length, 0, "binary");
+ free(d);
+ return;
+ }
+
+ machdata = &mipsmach;
+
+ if(!crackhdr(text, &fhdr)) {
+ print("can't decode file header\n");
+ return;
+ }
+
+ symmap = loadmap(0, text, &fhdr);
+ if(symmap == 0)
+ print("%s: (error) loadmap: cannot make symbol map\n", argv0);
+
+ if(syminit(text, &fhdr) < 0) {
+ print("%s: (error) syminit: %r\n", argv0);
+ return;
+ }
+ print("%s:%s\n\n", s, fhdr.name);
+
+ if(mach->sbreg && lookup(0, mach->sbreg, &sym)) {
+ mach->sb = sym.value;
+ l = enter("SB", Tid);
+ l->v->vstore.fmt = 'X';
+ l->v->vstore.u0.sival = mach->sb;
+ l->v->type = TINT;
+ l->v->set = 1;
+ }
+
+ l = mkvar("objtype");
+ v = l->v;
+ v->vstore.fmt = 's';
+ v->set = 1;
+ v->vstore.u0.sstring = strnode(mach->name);
+ v->type = TSTRING;
+
+ l = mkvar("textfile");
+ v = l->v;
+ v->vstore.fmt = 's';
+ v->set = 1;
+ v->vstore.u0.sstring = strnode(s);
+ v->type = TSTRING;
+
+ machbytype(fhdr.type);
+ varreg();
+}
+
+Node*
+an(int op, Node *l, Node *r)
+{
+ Node *n;
+
+ n = gmalloc(sizeof(Node));
+ n->ngc.gclink = gcl;
+ gcl = &n->ngc;
+ n->op = op;
+ n->left = l;
+ n->right = r;
+ return n;
+}
+
+List*
+al(int t)
+{
+ List *l;
+
+ l = gmalloc(sizeof(List));
+ l->type = t;
+ l->lgc.gclink = gcl;
+ gcl = &l->lgc;
+ return l;
+}
+
+Node*
+con(int v)
+{
+ Node *n;
+
+ n = an(OCONST, ZN, ZN);
+ n->nstore.u0.sival = v;
+ n->nstore.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: %L (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("%L: %s\n", buf);
+}
+
+void
+marktree(Node *n)
+{
+
+ if(n == 0)
+ return;
+
+ marktree(n->left);
+ marktree(n->right);
+
+ n->ngc.gcmark = 1;
+ if(n->op != OCONST)
+ return;
+
+ switch(n->type) {
+ case TSTRING:
+ n->nstore.u0.sstring->sgc.gcmark = 1;
+ break;
+ case TLIST:
+ marklist(n->nstore.u0.sl);
+ break;
+ case TCODE:
+ marktree(n->nstore.u0.scc);
+ break;
+ }
+}
+
+void
+marklist(List *l)
+{
+ while(l) {
+ l->lgc.gcmark = 1;
+ switch(l->type) {
+ case TSTRING:
+ l->lstore.u0.sstring->sgc.gcmark = 1;
+ break;
+ case TLIST:
+ marklist(l->lstore.u0.sl);
+ break;
+ case TCODE:
+ marktree(l->lstore.u0.scc);
+ 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->vstore.u0.sstring->sgc.gcmark = 1;
+ break;
+ case TLIST:
+ marklist(v->vstore.u0.sl);
+ break;
+ case TCODE:
+ marktree(v->vstore.u0.scc);
+ 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");
+ memset(p, 0, l);
+ return p;
+}
+
+void
+checkqid(int f1, int pid)
+{
+ int fd;
+ Dir *d1, *d2;
+ char buf[128];
+
+ if(kernel || rdebug)
+ return;
+
+ d1 = dirfstat(f1);
+ if(d1 == nil)
+ fatal("checkqid: (qid not checked) dirfstat: %r");
+
+ sprint(buf, "/proc/%d/text", pid);
+ fd = open(buf, OREAD);
+ if(fd < 0 || (d2 = dirfstat(fd)) == nil){
+ fatal("checkqid: (qid not checked) dirstat %s: %r", buf);
+ return; /* not reached */
+ }
+
+ 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);
+}
+
+char*
+mysystem(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/b%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/utils/acid/mips b/utils/acid/mips
new file mode 100644
index 00000000..5c267d1f
--- /dev/null
+++ b/utils/acid/mips
@@ -0,0 +1,217 @@
+// Mips support
+
+defn acidinit() // Called after all the init modules are loaded
+{
+ bplist = {};
+ bpfmt = 'X';
+
+ srcpath = {
+ "./",
+ "/sys/src/libc/port/",
+ "/sys/src/libc/9sys/",
+ "/sys/src/libc/mips/"
+ };
+
+ srcfiles = {}; // list of loaded files
+ srctext = {}; // the text of the files
+}
+
+defn stk() // trace
+{
+ _stk(*PC, *SP, linkreg(0), 0);
+}
+
+defn lstk() // trace with locals
+{
+ _stk(*PC, *SP, linkreg(0), 1);
+}
+
+defn gpr() // print general purpose registers
+{
+ print("R1\t", *R1, " R2\t", *R2, " R3\t", *R3, "\n");
+ print("R4\t", *R4, " R5\t", *R5, " R6\t", *R6, "\n");
+ print("R7\t", *R7, " R8\t", *R8, " R9\t", *R9, "\n");
+ print("R10\t", *R10, " R11\t", *R11, " R12\t", *R12, "\n");
+ print("R13\t", *R13, " R14\t", *R14, " R15\t", *R15, "\n");
+ print("R16\t", *R16, " R17\t", *R17, " R18\t", *R18, "\n");
+ print("R19\t", *R19, " R20\t", *R20, " R21\t", *R21, "\n");
+ print("R22\t", *R22, " R23\t", *R23, " R24\t", *R24, "\n");
+ print("R25\t", *R25, " R26\t", *R26, " R27\t", *R27, "\n");
+ print("R28\t", *R28, " R29\t", *SP, " R30\t", *R30, "\n");
+ print("R31\t", *R31, "\n");
+}
+
+defn Fpr()
+{
+ print("F0\t", *fmt(F0, 'G'), "\tF2\t", *fmt(F2, 'G'), "\n");
+ print("F4\t", *fmt(F4, 'G'), "\tF6\t", *fmt(F6, 'G'), "\n");
+ print("F8\t", *fmt(F8, 'G'), "\tF10\t", *fmt(F10, 'G'), "\n");
+ print("F12\t", *fmt(F12, 'G'), "\tF14\t", *fmt(F14, 'G'), "\n");
+ print("F16\t", *fmt(F16, 'G'), "\tF18\t", *fmt(F18, 'G'), "\n");
+ print("F20\t", *fmt(F20, 'G'), "\tF22\t", *fmt(F22, 'G'), "\n");
+ print("F24\t", *fmt(F24, 'G'), "\tF26\t", *fmt(F26, 'G'), "\n");
+ print("F28\t", *fmt(F28, 'G'), "\tF30\t", *fmt(F30, 'G'), "\n");
+}
+
+defn fpr()
+{
+ print("F0\t", *fmt(F0, 'g'), "\tF1\t", *fmt(F1, 'g'), "\n");
+ print("F2\t", *fmt(F2, 'g'), "\tF3\t", *fmt(F3, 'g'), "\n");
+ print("F4\t", *fmt(F4, 'g'), "\tF5\t", *fmt(F5, 'g'), "\n");
+ print("F6\t", *fmt(F6, 'g'), "\tF7\t", *fmt(F7, 'g'), "\n");
+ print("F8\t", *fmt(F8, 'g'), "\tF9\t", *fmt(F9, 'g'), "\n");
+ print("F10\t", *fmt(F10, 'g'), "\tF11\t", *fmt(F11, 'g'), "\n");
+ print("F12\t", *fmt(F12, 'g'), "\tF13\t", *fmt(F13, 'g'), "\n");
+ print("F14\t", *fmt(F14, 'g'), "\tF15\t", *fmt(F15, 'g'), "\n");
+ print("F16\t", *fmt(F16, 'g'), "\tF17\t", *fmt(F17, 'g'), "\n");
+ print("F18\t", *fmt(F18, 'g'), "\tF19\t", *fmt(F19, 'g'), "\n");
+ print("F20\t", *fmt(F20, 'g'), "\tF21\t", *fmt(F21, 'g'), "\n");
+ print("F22\t", *fmt(F22, 'g'), "\tF23\t", *fmt(F23, 'g'), "\n");
+ print("F24\t", *fmt(F24, 'g'), "\tF25\t", *fmt(F25, 'g'), "\n");
+ print("F26\t", *fmt(F26, 'g'), "\tF27\t", *fmt(F27, 'g'), "\n");
+ print("F28\t", *fmt(F28, 'g'), "\tF29\t", *fmt(F29, 'g'), "\n");
+ print("F30\t", *fmt(F30, 'g'), "\tF31\t", *fmt(F31, 'g'), "\n");
+}
+
+defn spr() // print special processor registers
+{
+ local pc, link, cause;
+
+ pc = *PC;
+ print("PC\t", pc, " ", fmt(pc, 'a'), " ");
+ pfl(pc);
+
+ link = *R31;
+ print("SP\t", *SP, "\tLINK\t", link, " ", fmt(link, 'a'), " ");
+ pfl(link);
+
+ cause = *CAUSE;
+ print("STATUS\t", *STATUS, "\tCAUSE\t", cause, " ", reason(cause), "\n");
+ print("TLBVIR\t", *TLBVIRT, "\tBADVADR\t", *BADVADDR, "\n");
+
+ print("HI\t", *HI, "\tLO\t", *LO, "\n");
+}
+
+defn regs() // print all registers
+{
+ spr();
+ gpr();
+}
+
+defn pstop(pid)
+{
+ local l, pc;
+
+ pc = *PC;
+
+ print(pid,": ", reason(*CAUSE), "\t");
+ print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n");
+
+ if notes then {
+ if notes[0] != "sys: breakpoint" then {
+ print("Notes pending:\n");
+ l = notes;
+ while l do {
+ print("\t", head l, "\n");
+ l = tail l;
+ }
+ }
+ }
+}
+
+sizeofUreg = 152;
+aggr Ureg
+{
+ 'X' 0 status;
+ 'X' 4 pc;
+ {
+ 'X' 8 sp;
+ 'X' 8 usp;
+ };
+ 'X' 12 cause;
+ 'X' 16 badvaddr;
+ 'X' 20 tlbvirt;
+ 'X' 24 hi;
+ 'X' 28 lo;
+ 'X' 32 r31;
+ 'X' 36 r30;
+ 'X' 40 r28;
+ 'X' 44 r27;
+ 'X' 48 r26;
+ 'X' 52 r25;
+ 'X' 56 r24;
+ 'X' 60 r23;
+ 'X' 64 r22;
+ 'X' 68 r21;
+ 'X' 72 r20;
+ 'X' 76 r19;
+ 'X' 80 r18;
+ 'X' 84 r17;
+ 'X' 88 r16;
+ 'X' 92 r15;
+ 'X' 96 r14;
+ 'X' 100 r13;
+ 'X' 104 r12;
+ 'X' 108 r11;
+ 'X' 112 r10;
+ 'X' 116 r9;
+ 'X' 120 r8;
+ 'X' 124 r7;
+ 'X' 128 r6;
+ 'X' 132 r5;
+ 'X' 136 r4;
+ 'X' 140 r3;
+ 'X' 144 r2;
+ 'X' 148 r1;
+};
+
+defn
+Ureg(addr) {
+ complex Ureg addr;
+ print(" status ", addr.status, "\n");
+ print(" pc ", addr.pc, "\n");
+ print(" sp ", addr.sp, "\n");
+ print(" cause ", addr.cause, "\n");
+ print(" badvaddr ", addr.badvaddr, "\n");
+ print(" tlbvirt ", addr.tlbvirt, "\n");
+ print(" hi ", addr.hi, "\n");
+ print(" lo ", addr.lo, "\n");
+ print(" r31 ", addr.r31, "\n");
+ print(" r30 ", addr.r30, "\n");
+ print(" r28 ", addr.r28, "\n");
+ print(" r27 ", addr.r27, "\n");
+ print(" r26 ", addr.r26, "\n");
+ print(" r25 ", addr.r25, "\n");
+ print(" r24 ", addr.r24, "\n");
+ print(" r23 ", addr.r23, "\n");
+ print(" r22 ", addr.r22, "\n");
+ print(" r21 ", addr.r21, "\n");
+ print(" r20 ", addr.r20, "\n");
+ print(" r19 ", addr.r19, "\n");
+ print(" r18 ", addr.r18, "\n");
+ print(" r17 ", addr.r17, "\n");
+ print(" r16 ", addr.r16, "\n");
+ print(" r15 ", addr.r15, "\n");
+ print(" r14 ", addr.r14, "\n");
+ print(" r13 ", addr.r13, "\n");
+ print(" r12 ", addr.r12, "\n");
+ print(" r11 ", addr.r11, "\n");
+ print(" r10 ", addr.r10, "\n");
+ print(" r9 ", addr.r9, "\n");
+ print(" r8 ", addr.r8, "\n");
+ print(" r7 ", addr.r7, "\n");
+ print(" r6 ", addr.r6, "\n");
+ print(" r5 ", addr.r5, "\n");
+ print(" r4 ", addr.r4, "\n");
+ print(" r3 ", addr.r3, "\n");
+ print(" r2 ", addr.r2, "\n");
+ print(" r1 ", addr.r1, "\n");
+};
+
+defn linkreg(addr)
+{
+ complex Ureg addr;
+ return addr.r31\X;
+}
+
+print("/sys/lib/acid/mips");
diff --git a/utils/acid/mkfile b/utils/acid/mkfile
new file mode 100644
index 00000000..697f7fc7
--- /dev/null
+++ b/utils/acid/mkfile
@@ -0,0 +1,30 @@
+<../../mkconfig
+
+TARG=acid
+
+OFILES= main.$O\
+ y.tab.$O\
+ lex.$O\
+ util.$O\
+ exec.$O\
+ expr.$O\
+ list.$O\
+ builtin.$O\
+ proc.$O\
+ dot.$O\
+ print.$O\
+ os-$TARGMODEL.$O\
+ rdebug.$O\
+
+YFILES=dbg.y
+HFILES=acid.h y.tab.h
+
+LIBS=mach math bio regexp 9
+
+CFLAGS=$CFLAGS -I../include
+
+BIN=$ROOT/$OBJDIR/bin
+
+<$ROOT/mkfiles/mkone-$SHELLTYPE
+
+CFLAGS= $CFLAGS -I../include
diff --git a/utils/acid/os-Nt.c b/utils/acid/os-Nt.c
new file mode 100644
index 00000000..5966d718
--- /dev/null
+++ b/utils/acid/os-Nt.c
@@ -0,0 +1,198 @@
+/*
+ * Windows Nt
+ */
+
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+#include <signal.h>
+
+#include <windows.h>
+
+#define MAXBUFSIZ 16640 /* 2 STYX messages plus headers */
+#define NT_DEBUG
+int nt_debug = 0;
+
+int
+opentty(char *tty, int baud)
+{
+ HANDLE comport;
+ DCB dcb;
+ COMMTIMEOUTS timeouts;
+
+ comport = CreateFile(tty, GENERIC_READ|GENERIC_WRITE,
+ 0, 0, OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL, 0);
+ if (comport == INVALID_HANDLE_VALUE) {
+ werrstr("could not create port %s", tty);
+ return -1;
+ }
+
+ if (SetupComm(comport, MAXBUFSIZ, MAXBUFSIZ) != TRUE) {
+ werrstr("could not set up %s Comm port", tty);
+ CloseHandle(comport);
+ return -1;
+ }
+
+ if (GetCommState(comport, &dcb) != TRUE) {
+ werrstr("could not get %s comstate", tty);
+ CloseHandle(comport);
+ return -1;
+ }
+
+ if (baud == 0) {
+ dcb.BaudRate = 19200;
+ } else {
+ dcb.BaudRate = baud;
+ }
+ dcb.ByteSize = 8;
+ dcb.fParity = 0;
+ dcb.Parity = NOPARITY;
+ dcb.StopBits = ONESTOPBIT;
+ dcb.fInX = 0;
+ dcb.fOutX = 0;
+ dcb.fAbortOnError = 1;
+
+ if (SetCommState(comport, &dcb) != TRUE) {
+ werrstr("could not set %s comstate", tty);
+ CloseHandle(comport);
+ return -1;
+ }
+
+ timeouts.ReadIntervalTimeout = 2;
+ /* char time in milliseconds, at 19.2K char time is .4 ms */
+ timeouts.ReadTotalTimeoutMultiplier = 0; /* was 100; */
+ timeouts.ReadTotalTimeoutConstant = 200; /* was 500; */
+ timeouts.WriteTotalTimeoutMultiplier = 0; /* was 10; */
+ timeouts.WriteTotalTimeoutConstant = 400; /* was 20; */
+
+ SetCommTimeouts(comport, &timeouts);
+
+ EscapeCommFunction(comport, SETDTR);
+
+ return (int) comport;
+}
+
+int
+remote_read(int fd, char *buf, int bytes)
+{
+ DWORD numread = 0;
+ BOOL rtn;
+
+#ifdef NT_DEBUG
+ if (nt_debug) {
+ print("NT:rread fd %x bytes: %d", fd, bytes);
+ }
+#endif
+ rtn = ReadFile((HANDLE) fd, buf, bytes, &numread, 0);
+#ifdef NT_DEBUG
+ if (nt_debug) {
+ print(" numread: %d rtn: %x\n", numread, rtn);
+ if (numread) {
+ char *cp;
+ int i;
+
+ cp = (char *) buf;
+ for (i=0; i < numread; i++) {
+ print(" %2.2x", *cp++);
+ }
+ print("\n");
+ }
+ }
+#endif
+ if (!rtn)
+ return -1;
+ else
+ return numread;
+}
+
+int
+remote_write(int fd, char *buf, int bytes)
+{
+ DWORD numwrt = 0;
+ BOOL rtn;
+ char *cp;
+ int i;
+
+#ifdef NT_DEBUG
+ if (nt_debug) {
+ print("NT:rwrite fd %x bytes: %d", fd, bytes);
+ print("\n");
+ cp = (char *) buf;
+ for (i=0; i < bytes; i++) {
+ print(" %2.2x", *cp++);
+ }
+ print("\n");
+ }
+#endif
+ while (bytes > 0) {
+ rtn = WriteFile((HANDLE) fd, buf, bytes, &numwrt, 0);
+ if (!rtn) {
+ break;
+ }
+ buf += numwrt;
+ bytes -= numwrt;
+ }
+ return numwrt;
+}
+
+void
+detach(void)
+{
+ /* ??? */
+}
+
+char *
+waitfor(int pid)
+{
+ fprint(2, "wait unimplemented");
+ return 0;
+}
+
+int
+fork(void)
+{
+ fprint(2, "fork unimplemented");
+ return -1;
+}
+
+char *
+runcmd(char *cmd)
+{
+ fprint(2, "runcmd unimplemented");
+ return 0;
+}
+
+void (*notefunc)(int);
+
+os_notify(void (*func)(int))
+{
+ notefunc = func;
+ signal(SIGINT, func);
+ return 0;
+}
+
+void
+catcher(int sig)
+{
+ if (sig == SIGINT) {
+ gotint = 1;
+ signal(SIGINT, notefunc);
+ }
+}
+
+void
+setup_os_notify(void)
+{
+ os_notify(catcher);
+}
+
+int
+nproc(char **argv)
+{
+ fprint(2, "nproc not implemented\n");
+ return -1;
+}
diff --git a/utils/acid/os-Plan9.c b/utils/acid/os-Plan9.c
new file mode 100644
index 00000000..1ac60404
--- /dev/null
+++ b/utils/acid/os-Plan9.c
@@ -0,0 +1,157 @@
+/*
+ * Plan9
+ */
+
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+
+int
+opentty(char *tty, int baud)
+{
+ int fd, cfd;
+ char ctty[100];
+
+ if(tty == 0)
+ tty = "/dev/eia0";
+ sprint(ctty, "%sctl", tty);
+ fd = open(tty, 2);
+ if(fd < 0)
+ return -1;
+ if(baud){
+ cfd = open(ctty, 1);
+ if(cfd < 0)
+ return fd;
+ fprint(cfd, "b%d", baud);
+ close(cfd);
+ }
+ return fd;
+}
+
+void
+detach(void)
+{
+ rfork(RFNAMEG|RFNOTEG|RFREND);
+}
+
+char *
+waitfor(int pid)
+{
+ Waitmsg *w;
+ static char buf[ERRMAX];
+
+ for(;;) {
+ w = wait();
+ if(w == nil)
+ error("wait %r");
+ if(w->pid == pid){
+ strecpy(buf, buf+ERRMAX, w->msg);
+ free(w);
+ return buf;
+ }
+ free(w);
+ }
+ return nil;
+}
+
+char *
+runcmd(char *cmd)
+{
+ char *argv[4];
+ int pid;
+
+ argv[0] = "/bin/rc";
+ argv[1] = "-c";
+ argv[2] = cmd;
+ argv[3] = 0;
+
+ pid = fork();
+ switch(pid) {
+ case -1:
+ error("fork %r");
+ case 0:
+ exec("/bin/rc", argv);
+ exits(0);
+ default:
+ return waitfor(pid);
+ }
+ return 0;
+}
+
+void
+catcher(void *junk, char *s)
+{
+ USED(junk);
+
+ if(strstr(s, "interrupt")) {
+ gotint = 1;
+ noted(NCONT);
+ }
+ noted(NDFLT);
+}
+
+void (*notefunc)(void *, char *);
+
+void
+setup_os_notify(void)
+{
+ notify(catcher);
+}
+
+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);
+
+ sprint(buf, "/proc/%d/ctl", getpid());
+ fd = open(buf, ORDWR);
+ if(fd < 0)
+ fatal("new: open %s: %r", buf);
+ write(fd, "hang", 4);
+ close(fd);
+
+ close(0);
+ close(1);
+ close(2);
+ for(i = 3; i < NFD; i++)
+ close(i);
+
+ open("/dev/cons", OREAD);
+ open("/dev/cons", OWRITE);
+ open("/dev/cons", 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;
+}
+
+int
+remote_read(int fd, char *buf, int bytes)
+{
+ return read(fd, buf, bytes);
+}
+
+int
+remote_write(int fd, char *buf, int bytes)
+{
+ return write(fd, buf, bytes);
+}
diff --git a/utils/acid/os-Posix.c b/utils/acid/os-Posix.c
new file mode 100644
index 00000000..58b4b255
--- /dev/null
+++ b/utils/acid/os-Posix.c
@@ -0,0 +1,183 @@
+#include <lib9.h>
+#include <bio.h>
+#include <sys/types.h>
+#include <termios.h>
+#undef getwd
+#undef getwd
+#include <unistd.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+#include <signal.h>
+
+static void
+setraw(int fd, int baud)
+{
+ struct termios sg;
+
+ switch(baud){
+ case 1200: baud = B1200; break;
+ case 2400: baud = B2400; break;
+ case 4800: baud = B4800; break;
+ case 9600: baud = B9600; break;
+ case 19200: baud = B19200; break;
+ case 38400: baud = B38400; break;
+ default:
+ werrstr("unknown speed %d", baud);
+ return;
+ }
+ if(tcgetattr(fd, &sg) >= 0) {
+ sg.c_iflag = sg.c_oflag = sg.c_lflag = 0;
+ sg.c_cflag &= ~CSIZE;
+ sg.c_cflag |= CS8 | CREAD;
+ sg.c_cflag &= ~(PARENB|PARODD);
+ sg.c_cc[VMIN] = 1;
+ sg.c_cc[VTIME] = 0;
+ if(baud) {
+ cfsetispeed(&sg, baud);
+ cfsetospeed(&sg, baud);
+ }
+ tcsetattr(fd, TCSANOW, &sg);
+ }
+}
+
+int
+opentty(char *tty, int baud)
+{
+ int fd;
+
+ if(baud == 0)
+ baud = 19200;
+ fd = open(tty, 2);
+ if(fd < 0)
+ return -1;
+ setraw(fd, baud);
+ return fd;
+}
+
+void
+detach(void)
+{
+ setpgid(0, 0);
+}
+
+char *
+waitfor(int pid)
+{
+ int n, status;
+ static char buf[32];
+
+ for(;;) {
+ n = wait(&status);
+ if(n < 0)
+ error("wait %r");
+ if(n == pid) {
+ sprint(buf, "%d", status);
+ return buf;
+ }
+ }
+}
+
+char *
+runcmd(char *cmd)
+{
+ char *argv[4];
+ int pid;
+
+ argv[0] = "/bin/sh";
+ argv[1] = "-c";
+ argv[2] = cmd;
+ argv[3] = 0;
+
+ pid = fork();
+ switch(pid) {
+ case -1:
+ error("fork %r");
+ case 0:
+ execv("/bin/sh", argv);
+ exits(0);
+ default:
+ return waitfor(pid);
+ }
+ return 0;
+}
+
+void (*notefunc)(int);
+
+os_notify(void (*func)(int))
+{
+ notefunc = func;
+ signal(SIGINT, func);
+}
+
+void
+catcher(int sig)
+{
+ if(sig==SIGINT) {
+ gotint = 1;
+ signal(SIGINT, notefunc);
+ }
+}
+
+void
+setup_os_notify(void)
+{
+ os_notify(catcher);
+}
+
+int
+nproc(char **argv)
+{
+ char buf[128];
+ int pid, i, fd;
+
+ if(rdebug)
+ error("can't newproc in remote mode");
+
+ pid = fork();
+ switch(pid) {
+ case -1:
+ error("new: fork %r");
+ case 0:
+ detach();
+
+ sprint(buf, "/proc/%d/ctl", getpid());
+ fd = open(buf, ORDWR);
+ if(fd < 0)
+ fatal("new: open %s: %r", buf);
+ write(fd, "hang", 4);
+ close(fd);
+
+ close(0);
+ close(1);
+ close(2);
+ for(i = 3; i < NFD; i++)
+ close(i);
+
+ open("/dev/cons", OREAD);
+ open("/dev/cons", OWRITE);
+ open("/dev/cons", OWRITE);
+ execvp(argv[0], argv);
+ fatal("new: execvp %s: %r");
+ default:
+ install(pid);
+ msg(pid, "waitstop");
+ notes(pid);
+ sproc(pid);
+ dostop(pid);
+ break;
+ }
+
+ return pid;
+}
+
+int
+remote_read(int fd, char *buf, int bytes)
+{
+ return read(fd, buf, bytes);
+}
+
+int remote_write(int fd, char *buf, int bytes)
+{
+ return write(fd, buf, bytes);
+}
diff --git a/utils/acid/port b/utils/acid/port
new file mode 100644
index 00000000..a348eb9c
--- /dev/null
+++ b/utils/acid/port
@@ -0,0 +1,547 @@
+// portable acid for all architectures
+
+defn pfl(addr)
+{
+ print(pcfile(addr), ":", pcline(addr), "\n");
+}
+
+defn
+notestk(addr)
+{
+ local pc, sp;
+ complex Ureg addr;
+
+ pc = addr.pc\X;
+ sp = addr.sp\X;
+
+ print("Note pc:", pc, " sp:", sp, " ", fmt(pc, 'a'), " ");
+ pfl(pc);
+ _stk(pc, sp, linkreg(addr), 1);
+}
+
+defn labstk(l) // trace from a label
+{
+ _stk(*(l+4)+Labpcoff, *l+Labspoff, linkreg(0), 0);
+}
+
+defn params(param)
+{
+ while param do {
+ sym = head param;
+ print(sym[0], "=", sym[1]);
+ param = tail param;
+ if param then
+ print (",");
+ }
+}
+
+defn locals(l)
+{
+ local sym;
+
+ while l do {
+ sym = head l;
+ print("\t", sym[0], "=", sym[1], "\n");
+ l = tail l;
+ }
+}
+
+defn _stk(pc, sp, link, dolocals)
+{
+ local stk;
+
+ print("At pc:", pc, ":", fmt(pc, 'a'), " ");
+ pfl(pc);
+
+ stk = strace(pc, sp, link);
+
+ while stk do {
+ frame = head stk;
+ print(fmt(frame[0], 'a'), "(");
+ params(frame[2]);
+ print(") ", pcfile(frame[0]), ":", pcline(frame[0]));
+ print("\n\tcalled from ", fmt(frame[1], 'a'), " ");
+ pfl(frame[1]);
+ stk = tail stk;
+ if dolocals then
+ locals(frame[3]);
+ }
+}
+
+defn findsrc(file)
+{
+ local lst, src;
+
+ if file[0] == '/' then {
+ src = file(file);
+ if src != {} then {
+ srcfiles = append srcfiles, file;
+ srctext = append srctext, src;
+ return src;
+ }
+ return {};
+ }
+
+ lst = srcpath;
+ while head lst do {
+ src = file(head lst+file);
+ if src != {} then {
+ srcfiles = append srcfiles, file;
+ srctext = append srctext, src;
+ return src;
+ }
+ lst = tail lst;
+ }
+}
+
+defn line(addr)
+{
+ local src, file;
+
+ file = pcfile(addr);
+ src = match(file, srcfiles);
+
+ if src >= 0 then
+ src = srctext[src];
+ else
+ src = findsrc(file);
+
+ if src == {} then {
+ print("no source for ", file, "\n");
+ return {};
+ }
+ line = pcline(addr)-1;
+ print(file, ":", src[line], "\n");
+}
+
+defn addsrcdir(dir)
+{
+ dir = dir+"/";
+
+ if match(dir, srcpath) >= 0 then {
+ print("already in srcpath\n");
+ return {};
+ }
+
+ srcpath = {dir}+srcpath;
+}
+
+defn source()
+{
+ local l;
+
+ l = srcpath;
+ while l do {
+ print(head l, "\n");
+ l = tail l;
+ }
+ l = srcfiles;
+
+ while l do {
+ print("\t", head l, "\n");
+ l = tail l;
+ }
+}
+
+defn Bsrc(addr)
+{
+ local lst;
+
+ lst = srcpath;
+ file = pcfile(addr);
+ if file[0] == '/' && access(file) then {
+ rc("B "+itoa(-pcline(addr))+" "+file);
+ return {};
+ }
+ while head lst do {
+ name = head lst+file;
+ if access(name) then {
+ rc("B "+itoa(-pcline(addr))+" "+name);
+ return {};
+ }
+ lst = tail lst;
+ }
+ print("no source for ", file, "\n");
+}
+
+defn src(addr)
+{
+ local src, file, line, cline, text;
+
+ file = pcfile(addr);
+ src = match(file, srcfiles);
+
+ if src >= 0 then
+ src = srctext[src];
+ else
+ src = findsrc(file);
+
+ if src == {} then {
+ print("no source for ", file, "\n");
+ return {};
+ }
+
+ cline = pcline(addr)-1;
+ print(file, ":", cline, "\n");
+ line = cline-5;
+ loop 0,10 do {
+ if line >= 0 then {
+ if line == cline then
+ print(">");
+ else
+ print(" ");
+ text = src[line];
+ if text == {} then
+ return {};
+ print(line, "\t", text, "\n");
+ }
+ line = line+1;
+ }
+}
+
+defn stopped(pid) // called from acid when a process changes state
+{
+ pstop(pid); // stub so this is easy to replace
+}
+
+defn procs() // print status of processes
+{
+ local c, lst, cpid;
+
+ cpid = pid;
+ lst = proclist;
+ while lst do {
+ np = head lst;
+ setproc(np);
+ if np == cpid then
+ c = '>';
+ else
+ c = ' ';
+ print(fmt(c, 'c'), np, ": ", status(np), " at ", fmt(*PC, 'a'), " setproc(", np, ")\n");
+ lst = tail lst;
+ }
+ pid = cpid;
+ if pid != 0 then
+ setproc(pid);
+}
+
+defn asm(addr)
+{
+ local bound;
+
+ bound = fnbound(addr);
+
+ addr = fmt(addr, 'i');
+ loop 1,30 do {
+ print(fmt(addr, 'a'), " ", fmt(addr, 'X'));
+ print("\t", @addr++, "\n");
+ if bound != {} && addr > bound[1] then {
+ lasmaddr = addr;
+ return {};
+ }
+ }
+ lasmaddr = addr;
+}
+
+defn casm()
+{
+ asm(lasmaddr);
+}
+
+defn new()
+{
+ bplist = {};
+ newproc(progargs);
+ // Dont miss the delay slot calls
+ bpset(follow(main)[0]);
+ cont();
+ bpdel(*PC);
+}
+
+defn stmnt() // step one statement
+{
+ local line;
+
+ line = pcline(*PC);
+ while 1 do {
+ step();
+ if line != pcline(*PC) then {
+ src(*PC);
+ return {};
+ }
+ }
+}
+
+defn func() // step until we leave the current function
+{
+ local bound, end, start, pc;
+
+ bound = fnbound(*PC);
+ if bound == {} then {
+ print("cannot locate text symbol\n");
+ return {};
+ }
+
+ pc = *PC;
+ start = bound[0];
+ end = bound[1];
+ while pc >= start && pc < end do {
+ step();
+ pc = *PC;
+ }
+}
+
+defn next()
+{
+ local sp, bound;
+
+ sp = *SP;
+ bound = fnbound(*PC);
+ stmnt();
+ pc = *PC;
+ if pc >= bound[0] && pc < bound[1] then
+ return {};
+
+ while (pc < bound[0] || pc > bound[1]) && sp >= *SP do {
+ step();
+ pc = *PC;
+ }
+ src(*PC);
+}
+
+defn dump(addr, n, fmt)
+{
+ loop 0, n do {
+ print(fmt(addr, 'X'), ": ");
+ addr = mem(addr, fmt);
+ }
+}
+
+defn mem(addr, fmt)
+{
+
+ local i, c, n;
+
+ i = 0;
+ while fmt[i] != 0 do {
+ c = fmt[i];
+ n = 0;
+ while '0' <= fmt[i] && fmt[i] <= '9' do {
+ n = 10*n + fmt[i]-'0';
+ i = i+1;
+ }
+ if n <= 0 then n = 1;
+ addr = fmt(addr, fmt[i]);
+ while n > 0 do {
+ print(*addr++, " ");
+ n = n-1;
+ }
+ i = i+1;
+ }
+ print("\n");
+ return addr;
+}
+
+defn symbols(pattern)
+{
+ local l, s;
+
+ l = symbols;
+ while l do {
+ s = head l;
+ if regexp(pattern, s[0]) then
+ print(s[0], "\t", s[1], "\t", s[2], "\n");
+ l = tail l;
+ }
+}
+
+defn spsrch(len)
+{
+ local addr, a, s, e;
+
+ addr = *SP;
+ s = origin & 0x7fffffff;
+ e = etext & 0x7fffffff;
+ loop 1, len do {
+ a = *addr++;
+ c = a & 0x7fffffff;
+ if c > s && c < e then {
+ print("src(", a, ")\n");
+ pfl(a);
+ }
+ }
+}
+
+defn bppush(val)
+{
+ return {"p", val};
+}
+
+defn bpderef()
+{
+ return {"*", 0};
+}
+
+defn bpmask()
+{
+ return {"&", 0};
+}
+
+defn bpeq()
+{
+ return {"=", 0};
+}
+
+defn bpneq()
+{
+ return {"!", 0};
+}
+
+defn bpand()
+{
+ return {"a", 0};
+}
+
+defn bpor()
+{
+ return {"o", 0};
+}
+
+defn bpcondset(pid, addr, conds)
+{
+ local l;
+ local id;
+ local found;
+
+ if status(pid) != "Stopped" then {
+ print("Waiting...\n");
+ stop(pid);
+ }
+
+ id = 0;
+ found = 0;
+
+ while !found && id <= 255 do {
+ l = bpl;
+ while l && head head l != id do {
+ l = tail l;
+ }
+
+ if !l then
+ found = 1;
+ else
+ id = id + 1;
+ }
+
+ if !found then {
+ print("error: no breakpoints available\n");
+ return -1;
+ }
+
+ bpl = append bpl, {id\d, pid\d, addr\X, conds};
+
+ _bpcondset(id, pid, addr, conds);
+
+ return id;
+}
+
+defn bpconddel(id)
+{
+ local i;
+ local l;
+
+ l = bpl;
+ i = 0;
+ while l do {
+ if id == head head l then {
+ bpl = delete bpl, i;
+ _bpconddel(id);
+ if id == bpid then
+ bpid = -1;
+ return {};
+ }
+ i = i + 1;
+ l = tail l;
+ }
+ print("no breakpoint with id ", id\d, ".\n");
+}
+
+defn bpprint(b)
+{
+ local l;
+
+ print(b[0], "\t", b[1], "\t", fmt(b[2], 'a'), " ", b[2]);
+ print("\t{");
+ l = b[3];
+ while l do {
+ print("\n\t\t\t\t\t", head l);
+ l = tail l;
+ }
+ print(" }\n");
+}
+
+defn bptab()
+{
+ local l;
+
+ l = bpl;
+ print("ID PID ADDR CONDITIONS\n");
+ while l do {
+ bpprint(head l);
+ l = tail l;
+ }
+}
+
+defn cont()
+{
+ local b, c, l, found;
+
+ l = bpl;
+ found = 0;
+ c = curpc();
+ while !found && l do {
+ b = head l;
+ if b[2] == c then {
+ nopstop = 1;
+ step();
+ nopstop = 0;
+ found = 1;
+ } else {
+ l = tail l;
+ }
+ }
+
+ return startstop(pid);
+}
+
+defn bpset(addr) // set a breakpoint
+{
+ return bpcondset(pid, addr, {});
+}
+
+defn bpdel(id)
+{
+ bpconddel(id);
+}
+
+defn bpaddr(id)
+{
+ local i;
+ local l;
+ local b;
+
+ l = bpl;
+ i = 0;
+ while l do {
+ b = head l;
+ if id == b[0] then
+ return b[2];
+ i = i + 1;
+ l = tail l;
+ }
+ print("bpaddr(", id\d, "): no match\n");
+ return {};
+}
+
+progargs="";
+print("/sys/lib/acid/port");
diff --git a/utils/acid/print.c b/utils/acid/print.c
new file mode 100644
index 00000000..8043fcd7
--- /dev/null
+++ b/utils/acid/print.c
@@ -0,0 +1,444 @@
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+
+static char *binop[] =
+{
+ 0,
+ 0,
+ "*", /* [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[] =
+{
+ "integer", /* [TINT] "integer", */
+ "float", /* [TFLOAT] "float", */
+ "string", /* [TSTRING] "string", */
+ "list", /* [TLIST] "list", */
+ "code", /* [TCODE] "code", */
+};
+
+int
+cmp(const void *a, const void *b)
+{
+ return strcmp(*(char**)a, *(char**)b);
+}
+
+void
+fundefs(void)
+{
+ Lsym *l;
+ char **vec;
+ int i, j, n, max, col, f, g, s;
+
+ max = 0;
+ f = 0;
+ g = 100;
+ vec = gmalloc(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->vstore.fmt);
+ if(l->v->vstore.comt)
+ Bprint(bout, " complex %s",
+ l->v->vstore.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", d, tabs);
+ if(r && r->op == OELSE) {
+ slist(r->left, d);
+ Bprint(bout, "%.*selse\n", d-1, tabs, d, tabs);
+ slist(r->right, d);
+ }
+ else
+ slist(r, d);
+ break;
+ case OWHILE:
+ Bprint(bout, "%.*swhile ", d, tabs);
+ pexpr(l);
+ d++;
+ Bprint(bout, " do\n", d, tabs);
+ 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->nstore.u0.sival);
+ break;
+ case TFLOAT:
+ Bprint(bout, "%g", n->nstore.u0.sfval);
+ break;
+ case TSTRING:
+ pstr(n->nstore.u0.sstring);
+ 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[n->op]);
+ pexpr(r);
+ Bputc(bout, ')');
+ break;
+ case OASGN:
+ pexpr(l);
+ Bprint(bout, binop[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->nstore.u0.sival);
+ break;
+ case OEVAL:
+ Bprint(bout, "eval ");
+ pexpr(l);
+ break;
+ case OWHAT:
+ Bprint(bout, "whatis", n->sym->name);
+ 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/utils/acid/proc.c b/utils/acid/proc.c
new file mode 100644
index 00000000..f13dbf95
--- /dev/null
+++ b/utils/acid/proc.c
@@ -0,0 +1,274 @@
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+#include "y.tab.h"
+
+void
+nocore(void)
+{
+ int i;
+
+ if(cormap == 0)
+ return;
+
+ for (i = 0; i < cormap->nsegs; i++)
+ if (cormap->seg[i].mget == 0 && cormap->seg[i].inuse && cormap->seg[i].fd >= 0)
+ close(cormap->seg[i].fd);
+ free(cormap);
+ cormap = 0;
+}
+
+void
+sproc(int pid)
+{
+ Lsym *s;
+ char buf[64];
+ ulong proctab;
+ int fd, i, fcor;
+
+ if(symmap == 0)
+ error("no map");
+
+ if(rdebug) {
+ fcor = -1;
+ proctab = 0;
+ i = remoteio(pid, "proc", buf, sizeof(buf));
+ if(i >= 0) {
+ buf[i] = '\0';
+ proctab = strtoul(buf, 0, 16);
+ } else
+ error("can't access pid %d: %r", pid);
+ s = look("proc");
+ if(s != 0)
+ s->v->vstore.u0.sival = proctab;
+ } else {
+ sprint(buf, "/proc/%d/mem", pid);
+ fcor = open(buf, ORDWR);
+ if(fcor < 0)
+ error("setproc: open %s: %r", buf);
+
+ checkqid(symmap->seg[0].fd, pid);
+
+ if(kernel) {
+ proctab = 0;
+ sprint(buf, "/proc/%d/proc", pid);
+ fd = open(buf, OREAD);
+ if(fd >= 0) {
+ i = read(fd, buf, sizeof(buf));
+ if(i >= 0) {
+ buf[i] = '\0';
+ proctab = strtoul(buf, 0, 0);
+ }
+ close(fd);
+ }
+ s = look("proc");
+ if(s != 0)
+ s->v->vstore.u0.sival = proctab;
+ }
+ }
+
+ s = look("pid");
+ s->v->vstore.u0.sival = pid;
+
+ nocore();
+ if(rdebug) {
+ cormap = attachremt(remfd, &fhdr);
+ for(i = 0; i < cormap->nsegs; i++)
+ setmapio(cormap, i, remget, remput);
+ } else
+ cormap = attachproc(pid, kernel, fcor, &fhdr);
+ if (cormap == 0)
+ error("setproc: cant make coremap");
+ i = findseg(cormap, "text");
+ if (i >= 0)
+ cormap->seg[i].name = "*text";
+ i = findseg(cormap, "data");
+ if (i >= 0)
+ cormap->seg[i].name = "*data";
+ install(pid);
+}
+
+void
+notes(int pid)
+{
+ Lsym *s;
+ Value *v;
+ int i, fd;
+ char buf[128];
+ List *l, **tail;
+
+ s = look("notes");
+ if(s == 0)
+ return;
+ v = s->v;
+
+ if(!rdebug) {
+ sprint(buf, "/proc/%d/note", pid);
+ fd = open(buf, OREAD);
+ if(fd < 0)
+ error("pid=%d: open note: %r", pid);
+ } else
+ fd = -1;
+
+ v->set = 1;
+ v->type = TLIST;
+ v->vstore.u0.sl = 0;
+ tail = &v->vstore.u0.sl;
+ for(;;) {
+ if(rdebug)
+ i = remoteio(pid, "note", buf, sizeof(buf));
+ else
+ i = read(fd, buf, sizeof(buf));
+ if(i <= 0)
+ break;
+ buf[i] = '\0';
+ l = al(TSTRING);
+ l->lstore.u0.sstring = strnode(buf);
+ l->lstore.fmt = 's';
+ *tail = l;
+ tail = &l->next;
+ }
+ if(fd >= 0)
+ close(fd);
+}
+
+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->nstore.fmt = 'D';
+ np->type = TINT;
+ p = con(pid);
+ p->nstore.fmt = 'D';
+ np = an(OCALL, np, p);
+ execute(np);
+ }
+}
+
+void
+install(int pid)
+{
+ Lsym *s;
+ List *l;
+ char buf[128];
+ int i, fd, 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");
+
+ if(!rdebug) {
+ sprint(buf, "/proc/%d/ctl", pid);
+ fd = open(buf, OWRITE);
+ if(fd < 0)
+ error("pid=%d: open ctl: %r", pid);
+ } else
+ fd = -1;
+ ptab[new].pid = pid;
+ ptab[new].ctl = fd;
+
+ s = look("proclist");
+ l = al(TINT);
+ l->lstore.fmt = 'D';
+ l->lstore.u0.sival = pid;
+ l->next = s->v->vstore.u0.sl;
+ s->v->vstore.u0.sl = 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) {
+ if(ptab[i].ctl >= 0)
+ close(ptab[i].ctl);
+ ptab[i].pid = 0;
+ s = look("proclist");
+ d = &s->v->vstore.u0.sl;
+ for(f = *d; f; f = f->next) {
+ if(f->lstore.u0.sival == pid) {
+ *d = f->next;
+ break;
+ }
+ }
+ s = look("pid");
+ if(s->v->vstore.u0.sival == pid)
+ s->v->vstore.u0.sival = 0;
+ return;
+ }
+ }
+}
+
+void
+msg(int pid, char *msg)
+{
+ int i;
+ int l;
+ int ok;
+ char err[ERRMAX];
+
+ for(i = 0; i < Maxproc; i++) {
+ if(ptab[i].pid == pid) {
+ l = strlen(msg);
+ if(rdebug)
+ ok = sendremote(pid, msg) >= 0;
+ else
+ ok = write(ptab[i].ctl, msg, l) == l;
+ if(!ok) {
+ 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];
+
+ if(rdebug) {
+ if(remoteio(pid, "status", buf, sizeof(buf)) < 0)
+ error("remote status: pid %d: %r", pid);
+ return buf;
+ }
+ 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 */
+}
diff --git a/utils/acid/rdebug.c b/utils/acid/rdebug.c
new file mode 100644
index 00000000..8903711e
--- /dev/null
+++ b/utils/acid/rdebug.c
@@ -0,0 +1,274 @@
+#include <lib9.h>
+#include <bio.h>
+#include <ctype.h>
+#include "mach.h"
+#define Extern extern
+#include "acid.h"
+#include "../../include/rdbg.h"
+
+/*
+ * remote kernel debugging
+ */
+
+enum {
+ chatty = 0
+};
+
+static long myreadn(int, void*, long);
+static int rproto(int, char*, int);
+
+void
+remotemap(Map *m, int i)
+{
+ setmapio(m, i, remget, remput);
+}
+
+/*
+ * send a /proc control message to remote pid,
+ * and await a reply
+ */
+int
+sendremote(int pid, char *msg)
+{
+ int tag;
+ char dbg[RDBMSGLEN];
+
+ if(protodebug)
+ fprint(2, "sendremote: pid %d: %s\n", pid, msg);
+ if(strcmp(msg, "startstop") == 0)
+ tag = Tstartstop;
+ else if(strcmp(msg, "waitstop") == 0)
+ tag = Twaitstop;
+ else if(strcmp(msg, "start") == 0)
+ tag = Tstart;
+ else if(strcmp(msg, "stop") == 0)
+ tag = Tstop;
+ else if(strcmp(msg, "kill") == 0)
+ tag = Tkill;
+ else {
+ werrstr("invalid sendremote: %s", msg);
+ return -1;
+ }
+ memset(dbg, 0, sizeof(dbg));
+ dbg[0] = tag;
+ dbg[1] = pid>>24;
+ dbg[2] = pid>>16;
+ dbg[3] = pid>>8;
+ dbg[4] = pid;
+ if(rproto(remfd, dbg, sizeof(dbg)) < 0)
+ return -1;
+ return 0;
+}
+
+/*
+ * read a line from /proc/<pid>/<file> into buf
+ */
+int
+remoteio(int pid, char *file, char *buf, int nb)
+{
+ char dbg[RDBMSGLEN];
+ int tag;
+
+ if(protodebug)
+ fprint(2, "remoteio %d: %s\n", pid, file);
+ memset(buf, nb, 0);
+ if(strcmp(file, "proc") == 0)
+ tag = Tproc;
+ else if(strcmp(file, "status") == 0)
+ tag = Tstatus;
+ else if(strcmp(file, "note") == 0)
+ tag = Trnote;
+ else {
+ werrstr("invalid remoteio: %s", file);
+ return -1;
+ }
+ memset(dbg, 0, sizeof(dbg));
+ dbg[0] = tag;
+ dbg[1] = pid>>24;
+ dbg[2] = pid>>16;
+ dbg[3] = pid>>8;
+ dbg[4] = pid;
+ if(rproto(remfd, dbg, sizeof(dbg)) < 0)
+ return -1;
+ if(nb > sizeof(dbg)-1)
+ nb = sizeof(dbg)-1;
+ memmove(buf, dbg+1, nb);
+ return strlen(buf);
+}
+
+int
+remget(struct segment *s, ulong addr, long off, char *buf, int size)
+{
+ int n, t;
+ char dbg[RDBMSGLEN];
+
+ if (protodebug)
+ fprint(2, "remget addr %#lux off %#lux\n", addr, off);
+ for (t = 0; t < size; t += n) {
+ n = size;
+ if(n > 9)
+ n = 9;
+ memset(dbg, 0, sizeof(dbg));
+ dbg[0] = Tmget;
+ dbg[1] = off>>24;
+ dbg[2] = off>>16;
+ dbg[3] = off>>8;
+ dbg[4] = off;
+ dbg[5] = n;
+ if(rproto(s->fd, dbg, sizeof(dbg)) < 0) {
+ werrstr("can't read address %#lux: %r", addr);
+ return -1;
+ }
+ memmove(buf, dbg+1, n);
+ buf += n;
+ }
+ return t;
+}
+
+int
+remput(struct segment *s, ulong addr, long off, char *buf, int size)
+{
+ int n, i, t;
+ char dbg[RDBMSGLEN];
+
+ if (protodebug)
+ fprint(2, "remput addr %#lux off %#lux\n", addr, off);
+ for (t = 0; t < size; t += n) {
+ n = size;
+ if(n > 4)
+ n = 4;
+ memset(dbg, 0, sizeof(dbg));
+ dbg[0] = Tmput;
+ dbg[1] = off>>24;
+ dbg[2] = off>>16;
+ dbg[3] = off>>8;
+ dbg[4] = off;
+ dbg[5] = n;
+ for(i=0; i<n; i++)
+ dbg[6+i] = *buf++;
+ if(rproto(s->fd, dbg, sizeof(dbg)) < 0) {
+ werrstr("can't write address %#lux: %r", addr);
+ return -1;
+ }
+ }
+ return t;
+}
+
+int
+remcondset(char op, ulong val)
+{
+ char dbg[RDBMSGLEN];
+
+ if (protodebug)
+ fprint(2, "remcondset op %c val: %#lux\n", op, val);
+ memset(dbg, 0, sizeof(dbg));
+
+ dbg[0] = Tcondbreak;
+ dbg[1] = val>>24;
+ dbg[2] = val>>16;
+ dbg[3] = val>>8;
+ dbg[4] = val;
+ dbg[5] = op;
+ if(rproto(remfd, dbg, sizeof(dbg)) < 0) {
+ werrstr("can't set condbreak: %c %#lux: %r", op, val);
+ return -1;
+ }
+ return 0;
+}
+
+int
+remcondstartstop(int pid)
+{
+ char dbg[RDBMSGLEN];
+
+ if (protodebug)
+ fprint(2, "remcondstartstop pid %d\n", pid);
+ memset(dbg, 0, sizeof(dbg));
+
+ dbg[0] = Tstartstop;
+ dbg[1] = pid>>24;
+ dbg[2] = pid>>16;
+ dbg[3] = pid>>8;
+ dbg[4] = pid;
+
+ if(rproto(remfd, dbg, sizeof(dbg)) < 0) {
+ werrstr("can't send Tstartstop");
+ return -1;
+ }
+
+ return dbg[1];
+}
+
+static int
+rproto(int fd, char *buf, int nb)
+{
+ int tag;
+
+ if (protodebug) {
+ int i;
+ print("rproto remote write fd %d bytes: %d\n", fd, nb);
+ for (i=0; i < nb; i++) {
+ print(" %2.2ux", buf[i]&0xFF);
+ }
+ print("\n");
+ }
+ tag = buf[0];
+ if(remote_write(fd, buf, nb) != nb ||
+ myreadn(fd, buf, nb) != nb){ /* could set alarm */
+ werrstr("remote i/o: %r");
+ return -1;
+ }
+ if(buf[0] == Rerr){
+ buf[nb-1] = 0;
+ werrstr("remote err: %s", buf+1);
+ return -1;
+ }
+ if(buf[0] != tag+1) {
+ werrstr("remote proto err: %.2ux", buf[0]&0xff);
+ return -1;
+ }
+ if(chatty) {
+ int i;
+ fprint(2, "remote [%d]: ", nb);
+ for(i=0; i<nb; i++)
+ fprint(2, " %.2ux", buf[i]&0xff);
+ fprint(2, "\n");
+ }
+ return nb;
+}
+
+/*
+ * this should probably be in lib9 as readn
+ */
+static long
+myreadn(int f, void *av, long n)
+{
+ char *a;
+ long m, t;
+
+ if (protodebug) {
+ print("remote read fd %d bytes: %ld", f, n);
+ }
+ a = av;
+ t = 0;
+ while(t < n){
+ m = remote_read(f, a+t, n-t);
+ if(m < 0){
+ if(t == 0)
+ return m;
+ break;
+ }
+ if (protodebug) {
+ print(" rtn: %ld\n", m);
+ if (m) {
+ int i;
+
+ for (i=0; i < m; i++)
+ print(" %2.2ux", a[i+t]&0xFF);
+ print("\n");
+ }
+ }
+ t += m;
+ }
+ return t;
+}
diff --git a/utils/acid/sparc b/utils/acid/sparc
new file mode 100644
index 00000000..76a1eba3
--- /dev/null
+++ b/utils/acid/sparc
@@ -0,0 +1,218 @@
+// Sparc support
+
+defn acidinit() // Called after all the init modules are loaded
+{
+ bplist = {};
+ bpfmt = 'X';
+
+ srcpath = {
+ "./",
+ "/sys/src/libc/port/",
+ "/sys/src/libc/9sys/",
+ "/sys/src/libc/sparc/"
+ };
+
+ srcfiles = {}; // list of loaded files
+ srctext = {}; // the text of the files
+}
+
+defn stk() // trace
+{
+ _stk(*PC, *R1, linkreg(0), 0);
+}
+
+defn lstk() // trace with locals
+{
+ _stk(*PC, *R1, linkreg(0), 1);
+}
+
+defn gpr() // print general purpose registers
+{
+ print("R1\t", *R1, "R2\t", *R2, "R3\t", *R3, "\n");
+ print("R4\t", *R4, "R5\t", *R5, "R6\t", *R6, "\n");
+ print("R7\t", *R7, "R8\t", *R8, "R9\t", *R9, "\n");
+ print("R10\t", *R10, "R11\t", *R11, "R12\t", *R12, "\n");
+ print("R13\t", *R13, "R14\t", *R14, "R15\t", *R15, "\n");
+ print("R16\t", *R16, "R17\t", *R17, "R18\t", *R18, "\n");
+ print("R19\t", *R19, "R20\t", *R20, "R21\t", *R21, "\n");
+ print("R22\t", *R22, "R23\t", *R23, "R24\t", *R24, "\n");
+ print("R25\t", *R25, "R26\t", *R26, "R27\t", *R27, "\n");
+ print("R28\t", *R28, "R29\t", *R29, "R30\t", *R30, "\n");
+ print("R31\t", *R31, "\n");
+}
+
+defn spr() // print special processor registers
+{
+ local pc;
+ local link;
+ local cause;
+
+ pc = *PC;
+ print("PC\t", pc, " ", fmt(pc, 'a'), " ");
+ pfl(pc);
+ print("PSR\t", *PSR, "\n");
+
+ link = *R15;
+ print("SP\t", *R1, "\tLINK\t\t", link, " ", fmt(link, 'a'));
+ pfl(link);
+
+ cause = *TBR;
+ print("Y\t", *Y, "\tCAUSE\t", *Y, cause, " ", reason(cause), "\n");
+}
+
+defn Fpr()
+{
+ print("F0\t", *fmt(F0, 'G'), "\tF2\t", *fmt(F2, 'G'), "\n");
+ print("F4\t", *fmt(F4, 'G'), "\tF6\t", *fmt(F6, 'G'), "\n");
+ print("F8\t", *fmt(F8, 'G'), "\tF10\t", *fmt(F10, 'G'), "\n");
+ print("F12\t", *fmt(F12, 'G'), "\tF14\t", *fmt(F14, 'G'), "\n");
+ print("F16\t", *fmt(F16, 'G'), "\tF18\t", *fmt(F18, 'G'), "\n");
+ print("F20\t", *fmt(F20, 'G'), "\tF22\t", *fmt(F22, 'G'), "\n");
+ print("F24\t", *fmt(F24, 'G'), "\tF26\t", *fmt(F26, 'G'), "\n");
+ print("F28\t", *fmt(F28, 'G'), "\tF30\t", *fmt(F30, 'G'), "\n");
+}
+
+defn fpr()
+{
+ print("F0\t", *fmt(F0, 'g'), "\tF1\t", *fmt(F1, 'g'), "\n");
+ print("F2\t", *fmt(F2, 'g'), "\tF3\t", *fmt(F3, 'g'), "\n");
+ print("F4\t", *fmt(F4, 'g'), "\tF5\t", *fmt(F5, 'g'), "\n");
+ print("F6\t", *fmt(F6, 'g'), "\tF7\t", *fmt(F7, 'g'), "\n");
+ print("F8\t", *fmt(F8, 'g'), "\tF9\t", *fmt(F9, 'g'), "\n");
+ print("F10\t", *fmt(F10, 'g'), "\tF11\t", *fmt(F11, 'g'), "\n");
+ print("F12\t", *fmt(F12, 'g'), "\tF13\t", *fmt(F13, 'g'), "\n");
+ print("F14\t", *fmt(F14, 'g'), "\tF15\t", *fmt(F15, 'g'), "\n");
+ print("F16\t", *fmt(F16, 'g'), "\tF17\t", *fmt(F17, 'g'), "\n");
+ print("F18\t", *fmt(F18, 'g'), "\tF19\t", *fmt(F19, 'g'), "\n");
+ print("F20\t", *fmt(F20, 'g'), "\tF21\t", *fmt(F21, 'g'), "\n");
+ print("F22\t", *fmt(F22, 'g'), "\tF23\t", *fmt(F23, 'g'), "\n");
+ print("F24\t", *fmt(F24, 'g'), "\tF25\t", *fmt(F25, 'g'), "\n");
+ print("F26\t", *fmt(F26, 'g'), "\tF27\t", *fmt(F27, 'g'), "\n");
+ print("F28\t", *fmt(F28, 'g'), "\tF29\t", *fmt(F29, 'g'), "\n");
+ print("F30\t", *fmt(F30, 'g'), "\tF31\t", *fmt(F31, 'g'), "\n");
+}
+
+defn regs() // print all registers
+{
+ spr();
+ gpr();
+}
+
+defn pstop(pid)
+{
+ local l;
+ local pc;
+
+ pc = *PC;
+
+ print(pid,": ", reason(*TBR), "\t");
+ print(fmt(pc, 'a'), "\t", fmt(pc, 'i'), "\n");
+
+ if notes then {
+ if notes[0] != "sys: breakpoint" then {
+ print("Notes pending:\n");
+ l = notes;
+ while l do {
+ print("\t", head l, "\n");
+ l = tail l;
+ }
+ }
+ }
+}
+
+aggr Ureg
+{
+ 'U' 0 r0;
+ {
+ 'U' 4 sp;
+ 'U' 4 usp;
+ 'U' 4 r1;
+ };
+ 'U' 8 r2;
+ 'U' 12 r3;
+ 'U' 16 r4;
+ 'U' 20 r5;
+ 'U' 24 r6;
+ 'U' 28 r7;
+ 'U' 32 r8;
+ 'U' 36 r9;
+ 'U' 40 r10;
+ 'U' 44 r11;
+ 'U' 48 r12;
+ 'U' 52 r13;
+ 'U' 56 r14;
+ 'U' 60 r15;
+ 'U' 64 r16;
+ 'U' 68 r17;
+ 'U' 72 r18;
+ 'U' 76 r19;
+ 'U' 80 r20;
+ 'U' 84 r21;
+ 'U' 88 r22;
+ 'U' 92 r23;
+ 'U' 96 r24;
+ 'U' 100 r25;
+ 'U' 104 r26;
+ 'U' 108 r27;
+ 'U' 112 r28;
+ 'U' 116 r29;
+ 'U' 120 r30;
+ 'U' 124 r31;
+ 'U' 128 y;
+ 'U' 132 tbr;
+ 'U' 136 psr;
+ 'U' 140 npc;
+ 'U' 144 pc;
+ 'U' 148 pad;
+};
+
+defn
+Ureg(addr) {
+ complex Ureg addr;
+ print(" r0 ", addr.r0, "\n");
+ print(" sp ", addr.sp, "\n");
+ print(" r2 ", addr.r2, "\n");
+ print(" r3 ", addr.r3, "\n");
+ print(" r4 ", addr.r4, "\n");
+ print(" r5 ", addr.r5, "\n");
+ print(" r6 ", addr.r6, "\n");
+ print(" r7 ", addr.r7, "\n");
+ print(" r8 ", addr.r8, "\n");
+ print(" r9 ", addr.r9, "\n");
+ print(" r10 ", addr.r10, "\n");
+ print(" r11 ", addr.r11, "\n");
+ print(" r12 ", addr.r12, "\n");
+ print(" r13 ", addr.r13, "\n");
+ print(" r14 ", addr.r14, "\n");
+ print(" r15 ", addr.r15, "\n");
+ print(" r16 ", addr.r16, "\n");
+ print(" r17 ", addr.r17, "\n");
+ print(" r18 ", addr.r18, "\n");
+ print(" r19 ", addr.r19, "\n");
+ print(" r20 ", addr.r20, "\n");
+ print(" r21 ", addr.r21, "\n");
+ print(" r22 ", addr.r22, "\n");
+ print(" r23 ", addr.r23, "\n");
+ print(" r24 ", addr.r24, "\n");
+ print(" r25 ", addr.r25, "\n");
+ print(" r26 ", addr.r26, "\n");
+ print(" r27 ", addr.r27, "\n");
+ print(" r28 ", addr.r28, "\n");
+ print(" r29 ", addr.r29, "\n");
+ print(" r30 ", addr.r30, "\n");
+ print(" r31 ", addr.r31, "\n");
+ print(" y ", addr.y, "\n");
+ print(" tbr ", addr.tbr, "\n");
+ print(" psr ", addr.psr, "\n");
+ print(" npc ", addr.npc, "\n");
+ print(" pc ", addr.pc, "\n");
+ print(" pad ", addr.pad, "\n");
+};
+
+defn linkreg(addr)
+{
+ complex Ureg addr;
+ return addr.r15\X;
+}
+
+print("/sys/lib/acid/sparc");
diff --git a/utils/acid/util.c b/utils/acid/util.c
new file mode 100644
index 00000000..0de244fd
--- /dev/null
+++ b/utils/acid/util.c
@@ -0,0 +1,295 @@
+#include <lib9.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, Sym *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/%lux\n", s->name, buf, s->type, s->value);
+ if(l == 0)
+ l = enter(buf, Tid);
+ return l;
+}
+
+void
+varsym(void)
+{
+ int i;
+ Sym *s;
+ long n;
+ Lsym *l;
+ ulong v;
+ char buf[1024];
+ List *list, **tail, *l2, *tl;
+
+ tail = &l2;
+ l2 = 0;
+
+ symbase(&n);
+ for(i = 0; i < n; i++) {
+ s = getsym(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;
+
+ v = s->value;
+ tl = al(TLIST);
+ *tail = tl;
+ tail = &tl->next;
+
+ l = unique(buf, s);
+
+ l->v->set = 1;
+ l->v->type = TINT;
+ l->v->vstore.u0.sival = v;
+ if(l->v->vstore.comt == 0)
+ l->v->vstore.fmt = 'X';
+
+ /* Enter as list of { name, type, value } */
+ list = al(TSTRING);
+ tl->lstore.u0.sl = list;
+ list->lstore.u0.sstring = strnode(buf);
+ list->lstore.fmt = 's';
+ list->next = al(TINT);
+ list = list->next;
+ list->lstore.fmt = 'c';
+ list->lstore.u0.sival = s->type;
+ list->next = al(TINT);
+ list = list->next;
+ list->lstore.fmt = 'X';
+ list->lstore.u0.sival = v;
+
+ }
+ }
+ l = mkvar("symbols");
+ l->v->set = 1;
+ l->v->type = TLIST;
+ l->v->vstore.u0.sl = l2;
+ if(l2 == 0)
+ print("no symbol information\n");
+}
+
+void
+varreg(void)
+{
+ Lsym *l;
+ Value *v;
+ Reglist *r;
+ List **tail, *li;
+
+ l = mkvar("registers");
+ v = l->v;
+ v->set = 1;
+ v->type = TLIST;
+ v->vstore.u0.sl = 0;
+ tail = &v->vstore.u0.sl;
+
+ for(r = mach->reglist; r->rname; r++) {
+ l = mkvar(r->rname);
+ v = l->v;
+ v->set = 1;
+ v->vstore.u0.sival = r->roffs;
+ v->vstore.fmt = r->rformat;
+ v->type = TINT;
+
+ li = al(TSTRING);
+ li->lstore.u0.sstring = strnode(r->rname);
+ li->lstore.fmt = 's';
+ *tail = li;
+ tail = &li->next;
+ }
+
+ if(machdata == 0)
+ return;
+
+ l = mkvar("bpinst"); /* Breakpoint text */
+ v = l->v;
+ v->type = TSTRING;
+ v->vstore.fmt = 's';
+ v->set = 1;
+ v->vstore.u0.sstring = gmalloc(sizeof(String));
+ v->vstore.u0.sstring->len = machdata->bpsize;
+ v->vstore.u0.sstring->string = gmalloc(machdata->bpsize);
+ memmove(v->vstore.u0.sstring->string, machdata->bpinst, machdata->bpsize);
+}
+
+void
+loadvars(void)
+{
+ Lsym *l;
+ Value *v;
+
+ l = mkvar("proc");
+ v = l->v;
+ v->type = TINT;
+ v->vstore.fmt = 'X';
+ v->set = 1;
+ v->vstore.u0.sival = 0;
+
+ l = mkvar("pid"); /* Current process */
+ v = l->v;
+ v->type = TINT;
+ v->vstore.fmt = 'D';
+ v->set = 1;
+ v->vstore.u0.sival = 0;
+
+ mkvar("notes"); /* Pending notes */
+
+ l = mkvar("proclist"); /* Attached processes */
+ l->v->type = TLIST;
+
+ l = mkvar("rdebug"); /* remote debugging enabled? */
+ v = l->v;
+ v->type = TINT;
+ v->vstore.fmt = 'D';
+ v->set = 1;
+ v->vstore.u0.sival = rdebug;
+
+ if(rdebug) {
+ l = mkvar("_breakid");
+ v = l->v;
+ v->type = TINT;
+ v->vstore.fmt = 'D';
+ v->set = 1;
+ v->vstore.u0.sival = -1;
+ }
+}
+
+vlong
+rget(Map *map, char *reg)
+{
+ Lsym *s;
+ long x;
+ vlong v;
+ int ret;
+
+ s = look(reg);
+ if(s == 0)
+ fatal("rget: %s\n", reg);
+
+ if(s->v->vstore.fmt == 'Y')
+ ret = get8(map, (long)s->v->vstore.u0.sival, &v);
+ else {
+ ret = get4(map, (long)s->v->vstore.u0.sival, &x);
+ v = x;
+ }
+ if(ret < 0)
+ error("can't get register %s: %r\n", reg);
+ return v;
+}
+
+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->sgc.gclink = gcl;
+ gcl = &s->sgc;
+
+ 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->sgc.gclink = gcl;
+ gcl = &s->sgc;
+
+ return s;
+}
+
+String*
+stradd(String *l, String *r)
+{
+ int len;
+ String *s;
+
+ len = l->len+r->len;
+ s = gmalloc(sizeof(String)+len+1);
+ s->sgc.gclink = gcl;
+ gcl = &s->sgc;
+ 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;
+}