and core dumps in particular. See notes:
new types: register is something that when dereferenced gives you
the registers. the Ureg is no longer mapped at 0.
refconst is something that gives a constant when dereferenced.
new builtin register("AX") creates register values
new builtin refconst(0x123) creates refconst values
new builtin var("foo") is equivalent to the variable foo
(it returns foo but can also be used as the lhs of an assignment).
new acid function getregs() returns a list of the current values of registers.
new acid function setregs() sets the current registers to those values.
note that getregs and setregs operate on register locations, not the
register values themselves.
new acid function resetregs() sets registers to register("AX"), etc.
new acid function clearregs() sets all registers to constant -1.
the default register settings are as in resetregs(), not small numbers.
new acid variables coretext, pids, systype, corefile, cmdline.
new behavior: local variable lookup, stk, etc., use the acid values of registers
(*PC, *SP, and so on), so the thread support code can change the context
completely.
unary + is applicable to more data types and prints more often.
590 lines
9.7 KiB
C
590 lines
9.7 KiB
C
#include <u.h>
|
|
#include <libc.h>
|
|
#include <bio.h>
|
|
#include <ctype.h>
|
|
#include <mach.h>
|
|
#define Extern extern
|
|
#include "acid.h"
|
|
|
|
void
|
|
error(char *fmt, ...)
|
|
{
|
|
int i;
|
|
char buf[2048];
|
|
va_list arg;
|
|
|
|
/* Unstack io channels */
|
|
if(iop != 0) {
|
|
for(i = 1; i < iop; i++)
|
|
Bterm(io[i]);
|
|
bout = io[0];
|
|
iop = 0;
|
|
}
|
|
|
|
ret = 0;
|
|
gotint = 0;
|
|
Bflush(bout);
|
|
if(silent)
|
|
silent = 0;
|
|
else {
|
|
va_start(arg, fmt);
|
|
vseprint(buf, buf+sizeof(buf), fmt, arg);
|
|
va_end(arg);
|
|
fprint(2, "%Z: (error) %s\n", buf);
|
|
}
|
|
while(popio())
|
|
;
|
|
interactive = 1;
|
|
longjmp(err, 1);
|
|
}
|
|
|
|
void
|
|
unwind(void)
|
|
{
|
|
int i;
|
|
Lsym *s;
|
|
Value *v;
|
|
|
|
for(i = 0; i < Hashsize; i++) {
|
|
for(s = hash[i]; s; s = s->hash) {
|
|
while(s->v->pop) {
|
|
v = s->v->pop;
|
|
free(s->v);
|
|
s->v = v;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
execute(Node *n)
|
|
{
|
|
Value *v;
|
|
Lsym *sl;
|
|
Node *l, *r;
|
|
int i, s, e;
|
|
Node res, xx;
|
|
static int stmnt;
|
|
|
|
gc();
|
|
if(gotint)
|
|
error("interrupted");
|
|
|
|
if(n == 0)
|
|
return;
|
|
|
|
if(stmnt++ > 5000) {
|
|
Bflush(bout);
|
|
stmnt = 0;
|
|
}
|
|
|
|
l = n->left;
|
|
r = n->right;
|
|
|
|
switch(n->op) {
|
|
default:
|
|
expr(n, &res);
|
|
if(ret || (res.type == TLIST && res.store.u.l == 0))
|
|
break;
|
|
prnt->right = &res;
|
|
expr(prnt, &xx);
|
|
break;
|
|
case OASGN:
|
|
case OCALL:
|
|
expr(n, &res);
|
|
break;
|
|
case OCOMPLEX:
|
|
decl(n);
|
|
break;
|
|
case OLOCAL:
|
|
for(n = n->left; n; n = n->left) {
|
|
if(ret == 0)
|
|
error("local not in function");
|
|
sl = n->sym;
|
|
if(sl->v->ret == ret)
|
|
error("%s declared twice", sl->name);
|
|
v = gmalloc(sizeof(Value));
|
|
v->ret = ret;
|
|
v->pop = sl->v;
|
|
sl->v = v;
|
|
v->scope = 0;
|
|
*(ret->tail) = sl;
|
|
ret->tail = &v->scope;
|
|
v->set = 0;
|
|
}
|
|
break;
|
|
case ORET:
|
|
if(ret == 0)
|
|
error("return not in function");
|
|
expr(n->left, ret->val);
|
|
longjmp(ret->rlab, 1);
|
|
case OLIST:
|
|
execute(n->left);
|
|
execute(n->right);
|
|
break;
|
|
case OIF:
|
|
expr(l, &res);
|
|
if(r && r->op == OELSE) {
|
|
if(bool(&res))
|
|
execute(r->left);
|
|
else
|
|
execute(r->right);
|
|
}
|
|
else if(bool(&res))
|
|
execute(r);
|
|
break;
|
|
case OWHILE:
|
|
for(;;) {
|
|
expr(l, &res);
|
|
if(!bool(&res))
|
|
break;
|
|
execute(r);
|
|
}
|
|
break;
|
|
case ODO:
|
|
expr(l->left, &res);
|
|
if(res.type != TINT)
|
|
error("loop must have integer start");
|
|
s = res.store.u.ival;
|
|
expr(l->right, &res);
|
|
if(res.type != TINT)
|
|
error("loop must have integer end");
|
|
e = res.store.u.ival;
|
|
for(i = s; i <= e; i++)
|
|
execute(r);
|
|
break;
|
|
}
|
|
}
|
|
|
|
int
|
|
bool(Node *n)
|
|
{
|
|
int true = 0;
|
|
|
|
if(n->op != OCONST)
|
|
fatal("bool: not const");
|
|
|
|
switch(n->type) {
|
|
case TINT:
|
|
if(n->store.u.ival != 0)
|
|
true = 1;
|
|
break;
|
|
case TFLOAT:
|
|
if(n->store.u.fval != 0.0)
|
|
true = 1;
|
|
break;
|
|
case TSTRING:
|
|
if(n->store.u.string->len)
|
|
true = 1;
|
|
break;
|
|
case TLIST:
|
|
if(n->store.u.l)
|
|
true = 1;
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void
|
|
convflt(Node *r, char *flt)
|
|
{
|
|
char c;
|
|
|
|
c = flt[0];
|
|
if(('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z')) {
|
|
r->type = TSTRING;
|
|
r->store.fmt = 's';
|
|
r->store.u.string = strnode(flt);
|
|
}
|
|
else {
|
|
r->type = TFLOAT;
|
|
r->store.u.fval = atof(flt);
|
|
}
|
|
}
|
|
|
|
void
|
|
indir(Map *m, ulong addr, char fmt, Node *r)
|
|
{
|
|
int i;
|
|
u32int ival;
|
|
u64int vval;
|
|
int ret;
|
|
u8int cval;
|
|
u16int sval;
|
|
char buf[512], reg[12];
|
|
|
|
r->op = OCONST;
|
|
r->store.fmt = fmt;
|
|
switch(fmt) {
|
|
default:
|
|
error("bad pointer format '%c' for *", fmt);
|
|
case 'c':
|
|
case 'C':
|
|
case 'b':
|
|
r->type = TINT;
|
|
ret = get1(m, addr, &cval, 1);
|
|
if (ret < 0)
|
|
error("indir: %r");
|
|
r->store.u.ival = cval;
|
|
break;
|
|
case 'x':
|
|
case 'd':
|
|
case 'u':
|
|
case 'o':
|
|
case 'q':
|
|
case 'r':
|
|
r->type = TINT;
|
|
ret = get2(m, addr, &sval);
|
|
if (ret < 0)
|
|
error("indir: %r");
|
|
r->store.u.ival = sval;
|
|
break;
|
|
case 'a':
|
|
case 'A':
|
|
case 'B':
|
|
case 'X':
|
|
case 'D':
|
|
case 'U':
|
|
case 'O':
|
|
case 'Q':
|
|
r->type = TINT;
|
|
ret = get4(m, addr, &ival);
|
|
if (ret < 0)
|
|
error("indir: %r");
|
|
r->store.u.ival = ival;
|
|
break;
|
|
case 'V':
|
|
case 'W':
|
|
case 'Y':
|
|
case 'Z':
|
|
r->type = TINT;
|
|
ret = get8(m, addr, &vval);
|
|
if (ret < 0)
|
|
error("indir: %r");
|
|
r->store.u.ival = vval;
|
|
break;
|
|
case 's':
|
|
r->type = TSTRING;
|
|
for(i = 0; i < sizeof(buf)-1; i++) {
|
|
ret = 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->store.u.string = 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->store.u.string = runenode((Rune*)buf);
|
|
break;
|
|
case 'i':
|
|
case 'I':
|
|
if ((*mach->das)(m, addr, fmt, buf, sizeof(buf)) < 0)
|
|
error("indir: %r");
|
|
r->type = TSTRING;
|
|
r->store.fmt = 's';
|
|
r->store.u.string = strnode(buf);
|
|
break;
|
|
case 'f':
|
|
ret = get1(m, addr, (uchar*)buf, mach->szfloat);
|
|
if (ret < 0)
|
|
error("indir: %r");
|
|
mach->ftoa32(buf, sizeof(buf), (void*) buf);
|
|
convflt(r, buf);
|
|
break;
|
|
case 'g':
|
|
ret = get1(m, addr, (uchar*)buf, mach->szfloat);
|
|
if (ret < 0)
|
|
error("indir: %r");
|
|
mach->ftoa32(buf, sizeof(buf), (void*) buf);
|
|
r->type = TSTRING;
|
|
r->store.u.string = strnode(buf);
|
|
break;
|
|
case 'F':
|
|
ret = get1(m, addr, (uchar*)buf, mach->szdouble);
|
|
if (ret < 0)
|
|
error("indir: %r");
|
|
mach->ftoa64(buf, sizeof(buf), (void*) buf);
|
|
convflt(r, buf);
|
|
break;
|
|
case '3': /* little endian ieee 80 with hole in bytes 8&9 */
|
|
ret = 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 */
|
|
leieeeftoa80(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");
|
|
beieeeftoa80(buf, sizeof(buf), reg);
|
|
convflt(r, buf);
|
|
break;
|
|
case 'G':
|
|
ret = get1(m, addr, (uchar*)buf, mach->szdouble);
|
|
if (ret < 0)
|
|
error("indir: %r");
|
|
mach->ftoa64(buf, sizeof(buf), (void*) buf);
|
|
r->type = TSTRING;
|
|
r->store.u.string = strnode(buf);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
indirreg(Regs *regs, char *name, char fmt, Node *r)
|
|
{
|
|
ulong val;
|
|
|
|
if(regs == 0)
|
|
error("no register set for *%s=", name);
|
|
|
|
r->op = OCONST;
|
|
r->store.fmt = fmt;
|
|
switch(fmt){
|
|
default:
|
|
error("bad pointer format '%c' for *%s", fmt, name);
|
|
case 'c':
|
|
case 'C':
|
|
case 'b':
|
|
case 'x':
|
|
case 'd':
|
|
case 'u':
|
|
case 'o':
|
|
case 'q':
|
|
case 'r':
|
|
case 'a':
|
|
case 'A':
|
|
case 'B':
|
|
case 'X':
|
|
case 'D':
|
|
case 'U':
|
|
case 'O':
|
|
case 'Q':
|
|
case 'V':
|
|
case 'W':
|
|
case 'Y':
|
|
case 'Z':
|
|
if(rget(regs, name, &val) < 0)
|
|
error("reading %s: %r", name);
|
|
r->type = TINT;
|
|
r->store.u.ival = val;
|
|
break;
|
|
case 'f':
|
|
case 'g':
|
|
case 'F':
|
|
case '3':
|
|
case '8':
|
|
case 'G':
|
|
error("floating point registers not supported");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
windir(Map *m, Node aes, Node *rval, Node *r)
|
|
{
|
|
uchar cval;
|
|
ushort sval;
|
|
Node res;
|
|
int ret;
|
|
|
|
if(m == 0)
|
|
error("no map for */@=");
|
|
|
|
if(aes.type != TINT)
|
|
error("bad type lhs of */@=");
|
|
|
|
expr(rval, &res);
|
|
|
|
if(m != cormap && wtflag == 0)
|
|
error("not in write mode");
|
|
|
|
r->type = res.type;
|
|
r->store.fmt = res.store.fmt;
|
|
r->store = res.store;
|
|
|
|
switch(res.store.fmt) {
|
|
default:
|
|
error("bad pointer format '%c' for */@=", res.store.fmt);
|
|
case 'c':
|
|
case 'C':
|
|
case 'b':
|
|
cval = res.store.u.ival;
|
|
ret = put1(m, aes.store.u.ival, &cval, 1);
|
|
break;
|
|
case 'r':
|
|
case 'x':
|
|
case 'd':
|
|
case 'u':
|
|
case 'o':
|
|
sval = res.store.u.ival;
|
|
ret = put2(m, aes.store.u.ival, sval);
|
|
r->store.u.ival = sval;
|
|
break;
|
|
case 'a':
|
|
case 'A':
|
|
case 'B':
|
|
case 'X':
|
|
case 'D':
|
|
case 'U':
|
|
case 'O':
|
|
ret = put4(m, aes.store.u.ival, res.store.u.ival);
|
|
break;
|
|
case 'V':
|
|
case 'W':
|
|
case 'Y':
|
|
case 'Z':
|
|
ret = put8(m, aes.store.u.ival, res.store.u.ival);
|
|
break;
|
|
case 's':
|
|
case 'R':
|
|
ret = put1(m, aes.store.u.ival, (uchar*)res.store.u.string->string, res.store.u.string->len);
|
|
break;
|
|
}
|
|
if (ret < 0)
|
|
error("windir: %r");
|
|
}
|
|
|
|
void
|
|
windirreg(Regs *regs, char *name, Node *rval, Node *r)
|
|
{
|
|
Node res;
|
|
|
|
if(regs == 0)
|
|
error("no register set for *%s=", name);
|
|
|
|
expr(rval, &res);
|
|
|
|
r->type = res.type;
|
|
r->store.fmt = res.store.fmt;
|
|
r->store = res.store;
|
|
|
|
switch(res.store.fmt){
|
|
default:
|
|
error("bad format '%c' for *%s=", res.store.fmt, name);
|
|
case 'c':
|
|
case 'C':
|
|
case 'b':
|
|
case 'x':
|
|
case 'd':
|
|
case 'u':
|
|
case 'o':
|
|
case 'q':
|
|
case 'r':
|
|
case 'a':
|
|
case 'A':
|
|
case 'B':
|
|
case 'X':
|
|
case 'D':
|
|
case 'U':
|
|
case 'O':
|
|
case 'Q':
|
|
case 'V':
|
|
case 'W':
|
|
case 'Y':
|
|
case 'Z':
|
|
if(rput(regs, name, res.store.u.ival) < 0)
|
|
error("writing %s: %r", name);
|
|
break;
|
|
case 'f':
|
|
case 'g':
|
|
case 'F':
|
|
case '3':
|
|
case '8':
|
|
case 'G':
|
|
error("floating point registers not supported");
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
call(char *fn, Node *parameters, Node *local, Node *body, Node *retexp)
|
|
{
|
|
int np, i;
|
|
Rplace rlab;
|
|
Node *n, res;
|
|
Value *v, *f;
|
|
Lsym *s, *next;
|
|
Node *avp[Maxarg], *ava[Maxarg];
|
|
|
|
rlab.local = 0;
|
|
|
|
na = 0;
|
|
flatten(avp, parameters);
|
|
np = na;
|
|
na = 0;
|
|
flatten(ava, local);
|
|
if(np != na) {
|
|
if(np < na)
|
|
error("%s: too few arguments", fn);
|
|
error("%s: too many arguments", fn);
|
|
}
|
|
|
|
rlab.tail = &rlab.local;
|
|
|
|
ret = &rlab;
|
|
for(i = 0; i < np; i++) {
|
|
n = ava[i];
|
|
switch(n->op) {
|
|
default:
|
|
error("%s: %d formal not a name", fn, i);
|
|
case ONAME:
|
|
expr(avp[i], &res);
|
|
s = n->sym;
|
|
break;
|
|
case OINDM:
|
|
res.store.u.cc = avp[i];
|
|
res.type = TCODE;
|
|
res.store.comt = 0;
|
|
if(n->left->op != ONAME)
|
|
error("%s: %d formal not a name", fn, i);
|
|
s = n->left->sym;
|
|
break;
|
|
}
|
|
if(s->v->ret == ret)
|
|
error("%s already declared at this scope", s->name);
|
|
|
|
v = gmalloc(sizeof(Value));
|
|
v->ret = ret;
|
|
v->pop = s->v;
|
|
s->v = v;
|
|
v->scope = 0;
|
|
*(rlab.tail) = s;
|
|
rlab.tail = &v->scope;
|
|
|
|
v->store = res.store;
|
|
v->type = res.type;
|
|
v->set = 1;
|
|
}
|
|
|
|
ret->val = retexp;
|
|
if(setjmp(rlab.rlab) == 0)
|
|
execute(body);
|
|
|
|
for(s = rlab.local; s; s = next) {
|
|
f = s->v;
|
|
next = f->scope;
|
|
s->v = f->pop;
|
|
free(f);
|
|
}
|
|
}
|