From 74a4d8c26dd3c1e9febcb717cfd6cb6512991a7a Mon Sep 17 00:00:00 2001 From: "Charles.Forsyth" Date: Fri, 22 Dec 2006 21:39:35 +0000 Subject: 20060303 --- utils/acid/386 | 146 ++++++ utils/acid/B.sh | 7 + utils/acid/acid.h | 317 ++++++++++++ utils/acid/arm | 1 + utils/acid/builtin.c | 1285 +++++++++++++++++++++++++++++++++++++++++++++++++ utils/acid/dbg.y | 402 ++++++++++++++++ utils/acid/dot.c | 152 ++++++ utils/acid/exec.c | 490 +++++++++++++++++++ utils/acid/expr.c | 1032 +++++++++++++++++++++++++++++++++++++++ utils/acid/lex.c | 636 ++++++++++++++++++++++++ utils/acid/list.c | 276 +++++++++++ utils/acid/main.c | 616 ++++++++++++++++++++++++ utils/acid/mips | 217 +++++++++ utils/acid/mkfile | 30 ++ utils/acid/os-Nt.c | 198 ++++++++ utils/acid/os-Plan9.c | 157 ++++++ utils/acid/os-Posix.c | 183 +++++++ utils/acid/port | 547 +++++++++++++++++++++ utils/acid/print.c | 444 +++++++++++++++++ utils/acid/proc.c | 274 +++++++++++ utils/acid/rdebug.c | 274 +++++++++++ utils/acid/sparc | 218 +++++++++ utils/acid/util.c | 295 ++++++++++++ 23 files changed, 8197 insertions(+) create mode 100644 utils/acid/386 create mode 100644 utils/acid/B.sh create mode 100644 utils/acid/acid.h create mode 100644 utils/acid/arm create mode 100644 utils/acid/builtin.c create mode 100644 utils/acid/dbg.y create mode 100644 utils/acid/dot.c create mode 100644 utils/acid/exec.c create mode 100644 utils/acid/expr.c create mode 100644 utils/acid/lex.c create mode 100644 utils/acid/list.c create mode 100644 utils/acid/main.c create mode 100644 utils/acid/mips create mode 100644 utils/acid/mkfile create mode 100644 utils/acid/os-Nt.c create mode 100644 utils/acid/os-Plan9.c create mode 100644 utils/acid/os-Posix.c create mode 100644 utils/acid/port create mode 100644 utils/acid/print.c create mode 100644 utils/acid/proc.c create mode 100644 utils/acid/rdebug.c create mode 100644 utils/acid/sparc create mode 100644 utils/acid/util.c (limited to 'utils/acid') 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 +#include +#include +#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<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 +#include +#include "mach.h" +#define Extern extern +#include "acid.h" +%} + +%union +{ + Node *node; + Lsym *sym; + ulong ival; + float fval; + String *string; +} + +%type expr monexpr term stmnt name args zexpr slist +%type member members mname castexpr idlist +%type 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 Tid +%token Tconst Tfmt +%token Tfconst +%token 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 +#include +#include +#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 +#include +#include +#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 +#include +#include +#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<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 +#include +#include +#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 = ""; + } + + 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(""); + 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: 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: 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: 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 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 +#include +#include +#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 */ +#include +#include +#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 +#include +#include +#include "mach.h" +#define Extern extern +#include "acid.h" +#include + +#include + +#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 +#include +#include +#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 +#include +#include +#include +#undef getwd +#undef getwd +#include +#include "mach.h" +#define Extern extern +#include "acid.h" +#include + +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 +#include +#include +#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 +#include +#include +#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 +#include +#include +#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// 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; ifd, 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 +#include +#include +#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; +} -- cgit v1.2.3