diff options
Diffstat (limited to 'os/port/exception.c')
| -rw-r--r-- | os/port/exception.c | 216 |
1 files changed, 216 insertions, 0 deletions
diff --git a/os/port/exception.c b/os/port/exception.c new file mode 100644 index 00000000..84a74711 --- /dev/null +++ b/os/port/exception.c @@ -0,0 +1,216 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" +#include "interp.h" +#include "isa.h" +#include "runt.h" +#include "kernel.h" +#include "raise.h" + +static int +ematch(char *pat, char *exp) +{ + int l; + + if(strcmp(pat, exp) == 0) + return 1; + + l = strlen(pat); + if(l == 0) + return 0; + if(pat[l-1] == '*') { + if(l == 1) + return 1; + if(strncmp(pat, exp, l-1) == 0) + return 1; + } + return 0; +} + +static void +setstr(String *s, char *p) +{ + if(s == H) + return; + if(s->len < 0 || s->max < 4) + return; + kstrcpy(s->Sascii, p, s->max); /* TO DO: we are assuming they aren't runes */ + s->len = strlen(s->Sascii); +} + +static String *exstr; + +void +excinit(void) +{ + exstr = newstring(ERRMAX); + poolimmutable(D2H(exstr)); +} + +static String* +newestring(char *estr) +{ + String *s; + + if(waserror()){ + setstr(exstr, estr); + D2H(exstr)->ref++; + return exstr; + } + s = c2string(estr, strlen(estr)); + poperror(); + return s; +} + +#define NOPC 0xffffffff + +#define FRTYPE(f) ((f)->t == nil ? SEXTYPE(f)->reg.TR : (f)->t) + +/* + * clear up an uncalled frame + */ +static void +freeframe(uchar *fp, int setsp) +{ + Frame *f; + + f = (Frame*)fp; + if(f->t == nil) + unextend(f); + else if(f->t->np) + freeptrs(f, f->t); + if(setsp) + R.SP = fp; +} + +int +handler(char *estr) +{ + Prog *p; + Modlink *m, *mr; + int str, ne; + ulong pc, newpc; + long eoff; + uchar *fp, **eadr; + Frame *f; + Type *t, *zt; + Handler *h; + Except *e; + void *v; + + p = currun(); + if(*estr == 0 || p == nil) + return 0; + str = p->exval == H || D2H(p->exval)->t == &Tstring; + m = R.M; + if(m->compiled) + pc = (ulong)R.PC-(ulong)m->prog; + else + pc = R.PC-m->prog; + pc--; + fp = R.FP; + while(fp != nil){ /* look for a handler */ + if((h = m->m->htab) != nil){ + for( ; h->etab != nil; h++){ + if(pc < h->pc1 || pc >= h->pc2) + continue; + eoff = h->eoff; + zt = h->t; + for(e = h->etab, ne = h->ne; e->s != nil; e++, ne--){ + if(ematch(e->s, estr) && (str && ne <= 0 || !str && ne > 0)){ + newpc = e->pc; + goto found; + } + } + newpc = e->pc; + if(newpc != NOPC) + goto found; + } + } + if(!str && fp != R.FP){ /* becomes a string exception in immediate caller */ + v = p->exval; + p->exval = *(String**)v; + D2H(p->exval)->ref++; + destroy(v); + str = 1; + continue; + } + f = (Frame*)fp; + if(f->mr != nil) + m = f->mr; + if(m->compiled) + pc = (ulong)f->lr-(ulong)m->prog; + else + pc = f->lr-m->prog; + pc--; + fp = f->fp; + } + destroy(p->exval); + p->exval = H; + return 0; +found: + { + int n; + char name[3*KNAMELEN]; + + pc = modstatus(&R, name, sizeof(name)); + n = 10+1+strlen(name)+1+strlen(estr)+1; + p->exstr = realloc(p->exstr, n); + if(p->exstr != nil) + snprint(p->exstr, n, "%lud %s %s", pc, name, estr); + } + + /* + * there may be an uncalled frame at the top of the stack + */ + f = (Frame*)R.FP; + t = FRTYPE(f); + if(R.FP < R.EX || R.FP >= R.TS) + freeframe(R.EX+OA(Stkext, reg.tos.fr), 0); + else if(R.FP+t->size < R.SP) + freeframe(R.FP+t->size, 1); + + m = R.M; + while(R.FP != fp){ + f = (Frame*)R.FP; + R.PC = f->lr; + R.FP = f->fp; + R.SP = (uchar*)f; + mr = f->mr; + if(f->t == nil) + unextend(f); + else if(f->t->np) + freeptrs(f, f->t); + if(mr != nil){ + m = mr; + destroy(R.M); + R.M = m; + R.MP = m->MP; + } + } + if(zt != nil){ + freeptrs(fp, zt); + initmem(zt, fp); + } + eadr = (uchar**)(fp+eoff); + destroy(*eadr); + *eadr = H; + if(p->exval == H) + *eadr = (uchar*)newestring(estr); /* might fail */ + else{ + D2H(p->exval)->ref++; + *eadr = p->exval; + } + if(m->compiled) + R.PC = (Inst*)((ulong)m->prog+newpc); + else + R.PC = m->prog+newpc; + memmove(&p->R, &R, sizeof(R)); + p->kill = nil; + destroy(p->exval); + p->exval = H; + return 1; +} |
