summaryrefslogtreecommitdiff
path: root/limbo/dis.c
diff options
context:
space:
mode:
Diffstat (limited to 'limbo/dis.c')
-rw-r--r--limbo/dis.c638
1 files changed, 638 insertions, 0 deletions
diff --git a/limbo/dis.c b/limbo/dis.c
new file mode 100644
index 00000000..84f708ba
--- /dev/null
+++ b/limbo/dis.c
@@ -0,0 +1,638 @@
+#include "limbo.h"
+
+static void disbig(long, Long);
+static void disbyte(long, int);
+static void disbytes(long, void*, int);
+static void disdatum(long, Node*);
+static void disflush(int, long, long);
+static void disint(long, long);
+static void disreal(long, Real);
+static void disstring(long, Sym*);
+
+static uchar *cache;
+static int ncached;
+static int ndatum;
+static int startoff;
+static int lastoff;
+static int lastkind;
+static int lencache;
+
+void
+discon(long val)
+{
+ if(val >= -64 && val <= 63) {
+ Bputc(bout, val & ~0x80);
+ return;
+ }
+ if(val >= -8192 && val <= 8191) {
+ Bputc(bout, ((val>>8) & ~0xC0) | 0x80);
+ Bputc(bout, val);
+ return;
+ }
+ if(val < 0 && ((val >> 29) & 0x7) != 7
+ || val > 0 && (val >> 29) != 0)
+ fatal("overflow in constant 0x%lux\n", val);
+ Bputc(bout, (val>>24) | 0xC0);
+ Bputc(bout, val>>16);
+ Bputc(bout, val>>8);
+ Bputc(bout, val);
+}
+
+void
+disword(long w)
+{
+ Bputc(bout, w >> 24);
+ Bputc(bout, w >> 16);
+ Bputc(bout, w >> 8);
+ Bputc(bout, w);
+}
+
+void
+disdata(int kind, long n)
+{
+ if(n < DMAX && n != 0)
+ Bputc(bout, DBYTE(kind, n));
+ else{
+ Bputc(bout, DBYTE(kind, 0));
+ discon(n);
+ }
+}
+
+#define NAMELEN 64
+
+void
+dismod(Decl *m)
+{
+ char name[8*NAMELEN];
+ ulong fileoff;
+
+ fileoff = Boffset(bout);
+ strncpy(name, m->sym->name, NAMELEN);
+ name[NAMELEN-1] = '\0';
+ Bwrite(bout, name, strlen(name)+1);
+ for(m = m->ty->tof->ids; m != nil; m = m->next){
+ switch(m->store){
+ case Dglobal:
+ discon(-1);
+ discon(-1);
+ disword(sign(m));
+ Bprint(bout, ".mp");
+ Bputc(bout, '\0');
+ break;
+ case Dfn:
+if(debug['v']) print("Dfn: %s %d %p\n", m->sym->name, m->refs, m);
+ discon(m->pc->pc);
+ discon(m->desc->id);
+ disword(sign(m));
+ if(m->dot->ty->kind == Tadt)
+ Bprint(bout, "%s.", m->dot->sym->name);
+ Bprint(bout, "%s", m->sym->name);
+ Bputc(bout, '\0');
+ break;
+ default:
+ fatal("unknown kind %K in dismod", m);
+ break;
+ }
+ }
+ if(debug['s'])
+ print("%ld linkage bytes start %ld\n", Boffset(bout) - fileoff, fileoff);
+}
+
+void
+dispath(void)
+{
+ char name[8*NAMELEN], *sp;
+
+ sp = srcpath(name, 8*NAMELEN);
+ Bwrite(bout, sp, strlen(sp)+1);
+}
+
+void
+disentry(Decl *e)
+{
+ if(e == nil){
+ discon(-1);
+ discon(-1);
+ return;
+ }
+ discon(e->pc->pc);
+ discon(e->desc->id);
+}
+
+void
+disdesc(Desc *d)
+{
+ ulong fileoff;
+
+ fileoff = Boffset(bout);
+ for(; d != nil; d = d->next){
+ discon(d->id);
+ discon(d->size);
+ discon(d->nmap);
+ Bwrite(bout, d->map, d->nmap);
+ }
+ if(debug['s'])
+ print("%ld type descriptor bytes start %ld\n", Boffset(bout) - fileoff, fileoff);
+}
+
+void
+disvar(long size, Decl *d)
+{
+ ulong fileoff;
+
+ fileoff = Boffset(bout);
+ USED(size);
+
+ lastkind = -1;
+ ncached = 0;
+ ndatum = 0;
+
+ for(; d != nil; d = d->next)
+ if(d->store == Dglobal && d->init != nil)
+ disdatum(d->offset, d->init);
+
+ disflush(-1, -1, 0);
+
+ Bputc(bout, 0);
+
+ if(debug['s'])
+ print("%ld data bytes start %ld\n", Boffset(bout) - fileoff, fileoff);
+}
+
+void
+disldt(long size, Decl *ds)
+{
+ int m;
+ Decl *d, *id;
+ Sym *s;
+ Node *n;
+
+ if(0){
+ discon(size);
+ disvar(size, ds);
+ return;
+ }
+
+ m = 0;
+ for(d = ds; d != nil; d = d->next)
+ if(d->store == Dglobal && d->init != nil)
+ m++;
+ discon(m);
+ for(d = ds; d != nil; d = d->next){
+ if(d->store == Dglobal && d->init != nil){
+ n = d->init;
+ if(n->ty->kind != Tiface)
+ nerror(n, "disldt: not Tiface");
+ discon(n->val);
+ for(id = n->decl->ty->ids; id != nil; id = id->next){
+ disword(sign(id));
+ if(id->dot->ty->kind == Tadt){
+ s = id->dot->sym;
+ Bprint(bout, "%s", s->name);
+ Bputc(bout, '.');
+ }
+ s = id->sym;
+ Bprint(bout, "%s", s->name);
+ Bputc(bout, 0);
+ }
+ }
+ }
+ discon(0);
+}
+
+static void
+disdatum(long offset, Node *n)
+{
+ Node *elem, *wild;
+ Case *c;
+ Label *lab;
+ Decl *id;
+ Sym *s;
+ long e, last, esz;
+ int i;
+
+ switch(n->ty->kind){
+ case Tbyte:
+ disbyte(offset, n->val);
+ break;
+ case Tint:
+ case Tfix:
+ disint(offset, n->val);
+ break;
+ case Tbig:
+ disbig(offset, n->val);
+ break;
+ case Tstring:
+ disstring(offset, n->decl->sym);
+ break;
+ case Treal:
+ disreal(offset, n->rval);
+ break;
+ case Tadt:
+ case Tadtpick:
+ case Ttuple:
+ id = n->ty->ids;
+ for(n = n->left; n != nil; n = n->right){
+ disdatum(offset + id->offset, n->left);
+ id = id->next;
+ }
+ break;
+ case Tany:
+ break;
+ case Tcase:
+ c = n->ty->cse;
+ disint(offset, c->nlab);
+ offset += IBY2WD;
+ for(i = 0; i < c->nlab; i++){
+ lab = &c->labs[i];
+ disint(offset, lab->start->val);
+ offset += IBY2WD;
+ disint(offset, lab->stop->val+1);
+ offset += IBY2WD;
+ disint(offset, lab->inst->pc);
+ offset += IBY2WD;
+ }
+ disint(offset, c->iwild ? c->iwild->pc : -1);
+ break;
+ case Tcasel:
+ c = n->ty->cse;
+ disint(offset, c->nlab);
+ offset += 2*IBY2WD;
+ for(i = 0; i < c->nlab; i++){
+ lab = &c->labs[i];
+ disbig(offset, lab->start->val);
+ offset += IBY2LG;
+ disbig(offset, lab->stop->val+1);
+ offset += IBY2LG;
+ disint(offset, lab->inst->pc);
+ offset += 2*IBY2WD;
+ }
+ disint(offset, c->iwild ? c->iwild->pc : -1);
+ break;
+ case Tcasec:
+ c = n->ty->cse;
+ disint(offset, c->nlab);
+ offset += IBY2WD;
+ for(i = 0; i < c->nlab; i++){
+ lab = &c->labs[i];
+ disstring(offset, lab->start->decl->sym);
+ offset += IBY2WD;
+ if(lab->stop != lab->start)
+ disstring(offset, lab->stop->decl->sym);
+ offset += IBY2WD;
+ disint(offset, lab->inst->pc);
+ offset += IBY2WD;
+ }
+ disint(offset, c->iwild ? c->iwild->pc : -1);
+ break;
+ case Tgoto:
+ c = n->ty->cse;
+ disint(offset, n->ty->size/IBY2WD-1);
+ offset += IBY2WD;
+ for(i = 0; i < c->nlab; i++){
+ disint(offset, c->labs[i].inst->pc);
+ offset += IBY2WD;
+ }
+ if(c->iwild != nil)
+ disint(offset, c->iwild->pc);
+ break;
+ case Tarray:
+ disflush(-1, -1, 0);
+ disdata(DEFA, 1); /* 1 is ignored */
+ discon(offset);
+ disword(n->ty->tof->decl->desc->id);
+ disword(n->left->val);
+
+ if(n->right == nil)
+ break;
+
+ disdata(DIND, 1); /* 1 is ignored */
+ discon(offset);
+ disword(0);
+
+ c = n->right->ty->cse;
+ wild = nil;
+ if(c->wild != nil)
+ wild = c->wild->right;
+ last = 0;
+ esz = n->ty->tof->size;
+ for(i = 0; i < c->nlab; i++){
+ e = c->labs[i].start->val;
+ if(wild != nil){
+ for(; last < e; last++)
+ disdatum(esz * last, wild);
+ }
+ last = e;
+ e = c->labs[i].stop->val;
+ elem = c->labs[i].node->right;
+ for(; last <= e; last++)
+ disdatum(esz * last, elem);
+ }
+ if(wild != nil)
+ for(e = n->left->val; last < e; last++)
+ disdatum(esz * last, wild);
+
+ disflush(-1, -1, 0);
+ disdata(DAPOP, 1); /* 1 is ignored */
+ discon(0);
+
+ break;
+ case Tiface:
+ disint(offset, n->val);
+ offset += IBY2WD;
+ for(id = n->decl->ty->ids; id != nil; id = id->next){
+ offset = align(offset, IBY2WD);
+ disint(offset, sign(id));
+ offset += IBY2WD;
+
+ if(id->dot->ty->kind == Tadt){
+ s = id->dot->sym;
+ disbytes(offset, s->name, s->len);
+ offset += s->len;
+ disbyte(offset, '.');
+ offset++;
+ }
+ s = id->sym;
+ disbytes(offset, s->name, s->len);
+ offset += s->len;
+ disbyte(offset, 0);
+ offset++;
+ }
+ break;
+ default:
+ nerror(n, "can't dis global %n", n);
+ break;
+ }
+}
+
+void
+disexc(Except *es)
+{
+ int i, n;
+ Decl *d;
+ Except *e;
+ Case *c;
+ Label *lab;
+
+ n = 0;
+ for(e = es; e != nil; e = e->next)
+ if(e->p1->reach || e->p2->reach)
+ n++;
+ discon(n);
+ for(e = es; e != nil; e = e->next){
+ if(!e->p1->reach && !e->p2->reach)
+ continue;
+ c = e->c;
+ discon(e->d->offset);
+ discon(getpc(e->p1));
+ discon(getpc(e->p2));
+ if(e->desc)
+ discon(e->desc->id);
+ else
+ discon(-1);
+ discon(c->nlab|(e->ne<<16));
+ for(i = 0; i < c->nlab; i++){
+ lab = &c->labs[i];
+ d = lab->start->decl;
+ if(lab->start->ty->kind == Texception)
+ d = d->init->decl;
+ Bprint(bout, "%s", d->sym->name);
+ Bputc(bout, '\0');
+ discon(lab->inst->pc);
+ }
+ if(c->iwild == nil)
+ discon(-1);
+ else
+ discon(c->iwild->pc);
+ }
+ discon(0);
+}
+
+static void
+disbyte(long off, int v)
+{
+ disflush(DEFB, off, 1);
+ cache[ncached++] = v;
+ ndatum++;
+}
+
+static void
+disbytes(long off, void *v, int n)
+{
+ disflush(DEFB, off, n);
+ memmove(&cache[ncached], v, n);
+ ncached += n;
+ ndatum += n;
+}
+
+static void
+disint(long off, long v)
+{
+ disflush(DEFW, off, IBY2WD);
+ cache[ncached++] = v >> 24;
+ cache[ncached++] = v >> 16;
+ cache[ncached++] = v >> 8;
+ cache[ncached++] = v;
+ ndatum++;
+}
+
+static void
+disbig(long off, Long v)
+{
+ ulong iv;
+
+ disflush(DEFL, off, IBY2LG);
+ iv = v >> 32;
+ cache[ncached++] = iv >> 24;
+ cache[ncached++] = iv >> 16;
+ cache[ncached++] = iv >> 8;
+ cache[ncached++] = iv;
+ iv = v;
+ cache[ncached++] = iv >> 24;
+ cache[ncached++] = iv >> 16;
+ cache[ncached++] = iv >> 8;
+ cache[ncached++] = iv;
+ ndatum++;
+}
+
+static void
+disreal(long off, Real v)
+{
+ ulong bv[2];
+ ulong iv;
+
+ disflush(DEFF, off, IBY2LG);
+ dtocanon(v, bv);
+ iv = bv[0];
+ cache[ncached++] = iv >> 24;
+ cache[ncached++] = iv >> 16;
+ cache[ncached++] = iv >> 8;
+ cache[ncached++] = iv;
+ iv = bv[1];
+ cache[ncached++] = iv >> 24;
+ cache[ncached++] = iv >> 16;
+ cache[ncached++] = iv >> 8;
+ cache[ncached++] = iv;
+ ndatum++;
+}
+
+static void
+disstring(long offset, Sym *sym)
+{
+ disflush(-1, -1, 0);
+ disdata(DEFS, sym->len);
+ discon(offset);
+ Bwrite(bout, sym->name, sym->len);
+}
+
+static void
+disflush(int kind, long off, long size)
+{
+ if(kind != lastkind || off != lastoff){
+ if(lastkind != -1 && ncached){
+ disdata(lastkind, ndatum);
+ discon(startoff);
+ Bwrite(bout, cache, ncached);
+ }
+ startoff = off;
+ lastkind = kind;
+ ncached = 0;
+ ndatum = 0;
+ }
+ lastoff = off + size;
+ while(kind >= 0 && ncached + size >= lencache){
+ lencache = ncached+1024;
+ cache = reallocmem(cache, lencache);
+ }
+}
+
+static int dismode[Aend] = {
+ /* Aimm */ AIMM,
+ /* Amp */ AMP,
+ /* Ampind */ AMP|AIND,
+ /* Afp */ AFP,
+ /* Afpind */ AFP|AIND,
+ /* Apc */ AIMM,
+ /* Adesc */ AIMM,
+ /* Aoff */ AIMM,
+ /* Anoff */ AIMM,
+ /* Aerr */ AXXX,
+ /* Anone */ AXXX,
+ /* Aldt */ AIMM,
+};
+
+static int disregmode[Aend] = {
+ /* Aimm */ AXIMM,
+ /* Amp */ AXINM,
+ /* Ampind */ AXNON,
+ /* Afp */ AXINF,
+ /* Afpind */ AXNON,
+ /* Apc */ AXIMM,
+ /* Adesc */ AXIMM,
+ /* Aoff */ AXIMM,
+ /* Anoff */ AXIMM,
+ /* Aerr */ AXNON,
+ /* Anone */ AXNON,
+ /* Aldt */ AXIMM,
+};
+
+enum
+{
+ MAXCON = 4,
+ MAXADDR = 2*MAXCON,
+ MAXINST = 3*MAXADDR+2,
+ NIBUF = 1024
+};
+
+static uchar *ibuf;
+static int nibuf;
+
+void
+disinst(Inst *in)
+{
+ ulong fileoff;
+
+ fileoff = Boffset(bout);
+ ibuf = allocmem(NIBUF);
+ nibuf = 0;
+ for(; in != nil; in = in->next){
+ if(in->op == INOOP)
+ continue;
+ if(nibuf >= NIBUF-MAXINST){
+ Bwrite(bout, ibuf, nibuf);
+ nibuf = 0;
+ }
+ ibuf[nibuf++] = in->op;
+ ibuf[nibuf++] = SRC(dismode[in->sm]) | DST(dismode[in->dm]) | disregmode[in->mm];
+ if(in->mm != Anone)
+ disaddr(in->mm, &in->m);
+ if(in->sm != Anone)
+ disaddr(in->sm, &in->s);
+ if(in->dm != Anone)
+ disaddr(in->dm, &in->d);
+ }
+ if(nibuf > 0)
+ Bwrite(bout, ibuf, nibuf);
+ free(ibuf);
+ ibuf = nil;
+
+ if(debug['s'])
+ print("%ld instruction bytes start %ld\n", Boffset(bout) - fileoff, fileoff);
+}
+
+void
+disaddr(int m, Addr *a)
+{
+ long val;
+
+ val = 0;
+ switch(m){
+ case Anone:
+ case Aerr:
+ default:
+ break;
+ case Aimm:
+ case Apc:
+ case Adesc:
+ val = a->offset;
+ break;
+ case Aoff:
+ val = a->decl->iface->offset;
+ break;
+ case Anoff:
+ val = -(a->decl->iface->offset+1);
+ break;
+ case Afp:
+ case Amp:
+ case Aldt:
+ val = a->reg;
+ break;
+ case Afpind:
+ case Ampind:
+ disbcon(a->reg);
+ val = a->offset;
+ break;
+ }
+ disbcon(val);
+}
+
+void
+disbcon(long val)
+{
+ if(val >= -64 && val <= 63){
+ ibuf[nibuf++] = val & ~0x80;
+ return;
+ }
+ if(val >= -8192 && val <= 8191){
+ ibuf[nibuf++] = val>>8 & ~0xC0 | 0x80;
+ ibuf[nibuf++] = val;
+ return;
+ }
+ if(val < 0 && ((val >> 29) & 7) != 7
+ || val > 0 && (val >> 29) != 0)
+ fatal("overflow in constant 16r%lux", val);
+ ibuf[nibuf++] = val>>24 | 0xC0;
+ ibuf[nibuf++] = val>>16;
+ ibuf[nibuf++] = val>>8;
+ ibuf[nibuf++] = val;
+}