ref: 94443daf8e248e65afc8d3f17f26efea22748b51
dir: /os/port/exception.c/
#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;
}