xref: /inferno-os/emu/port/exception.c (revision 7ef44d652ae9e5e1f5b3465d73684e4a54de73c0)
1 #include "dat.h"
2 #include "fns.h"
3 #include "error.h"
4 #include "interp.h"
5 #include "isa.h"
6 #include "runt.h"
7 #include "kernel.h"
8 #include "raise.h"
9 
10 static int
11 ematch(char *pat, char *exp)
12 {
13 	int l;
14 
15 	if(strcmp(pat, exp) == 0)
16 		return 1;
17 
18 	l = strlen(pat);
19 	if(l == 0)
20 		return 0;
21 	if(pat[l-1] == '*') {
22 		if(l == 1)
23 			return 1;
24 		if(strncmp(pat, exp, l-1) == 0)
25 			return 1;
26 	}
27 	return 0;
28 }
29 
30 static void
31 setstr(String *s, char *p)
32 {
33 	if(s == H)
34 		return;
35 	if(s->len < 0 || s->max < 4)
36 		return;
37 	kstrcpy(s->Sascii, p, s->max);	/* TO DO: we are assuming they aren't runes */
38 	s->len = strlen(s->Sascii);
39 }
40 
41 static String *exstr;
42 
43 void
44 excinit(void)
45 {
46 	exstr = newstring(ERRMAX);
47 	poolimmutable(D2H(exstr));
48 }
49 
50 static String*
51 newestring(char *estr)
52 {
53 	String *s;
54 
55 	if(waserror()){
56 		setstr(exstr, estr);
57 		D2H(exstr)->ref++;
58 		return exstr;
59 	}
60 	s = c2string(estr, strlen(estr));
61 	poperror();
62 	return s;
63 }
64 
65 #define NOPC	0xffffffff
66 
67 #define FRTYPE(f)	((f)->t == nil ? SEXTYPE(f)->reg.TR : (f)->t)
68 
69 /*
70  * clear up an uncalled frame
71  */
72 static void
73 freeframe(uchar *fp, int setsp)
74 {
75 	Frame *f;
76 
77 	f = (Frame*)fp;
78 	if(f->t == nil)
79 		unextend(f);
80 	else if(f->t->np)
81 		freeptrs(f, f->t);
82 	if(setsp)
83 		R.SP = fp;
84 }
85 
86 int
87 handler(char *estr)
88 {
89 	Prog *p;
90 	Modlink *m, *mr;
91 	int str, ne;
92 	ulong pc, newpc;
93 	long eoff;
94 	uchar *fp, **eadr;
95 	Frame *f;
96 	Type *t, *zt;
97 	Handler *h;
98 	Except *e;
99 	void *v;
100 
101 	p = currun();
102 	if(*estr == 0 || p == nil)
103 		return 0;
104 	str = p->exval == H || D2H(p->exval)->t == &Tstring;
105 	m = R.M;
106 	if(m->compiled)
107 		pc = (ulong)R.PC-(ulong)m->prog;
108 	else
109 		pc = R.PC-m->prog;
110 	pc--;
111 	fp = R.FP;
112 
113 	while(fp != nil){		/* look for a handler */
114 		if((h = m->m->htab) != nil){
115 			for( ; h->etab != nil; h++){
116 				if(pc < h->pc1 || pc >= h->pc2)
117 					continue;
118 				eoff = h->eoff;
119 				zt = h->t;
120 				for(e = h->etab, ne = h->ne; e->s != nil; e++, ne--){
121 					if(ematch(e->s, estr) && (str && ne <= 0 || !str && ne > 0)){
122 						newpc = e->pc;
123 						goto found;
124 					}
125 				}
126 				newpc = e->pc;
127 				if(newpc != NOPC)
128 					goto found;
129 			}
130 		}
131 		if(!str && fp != R.FP){		/* becomes a string exception in immediate caller */
132 			v = p->exval;
133 			p->exval = *(String**)v;
134 			D2H(p->exval)->ref++;
135 			destroy(v);
136 			str = 1;
137 			continue;
138 		}
139 		f = (Frame*)fp;
140 		if(f->mr != nil)
141 			m = f->mr;
142 		if(m->compiled)
143 			pc = (ulong)f->lr-(ulong)m->prog;
144 		else
145 			pc = f->lr-m->prog;
146 		pc--;
147 		fp = f->fp;
148 	}
149 	destroy(p->exval);
150 	p->exval = H;
151 	return 0;
152 found:
153 	{
154 		int n;
155 		char name[3*KNAMELEN];
156 
157 		pc = modstatus(&R, name, sizeof(name));
158 		n = 10+1+strlen(name)+1+strlen(estr)+1;
159 		p->exstr = realloc(p->exstr, n);
160 		if(p->exstr != nil)
161 			snprint(p->exstr, n, "%lud %s %s", pc, name, estr);
162 	}
163 
164 	/*
165 	 * there may be an uncalled frame at the top of the stack
166 	 */
167 	f = (Frame*)R.FP;
168 	t = FRTYPE(f);
169 	if(R.FP < R.EX || R.FP >= R.TS)
170 		freeframe(R.EX+OA(Stkext, reg.tos.fr), 0);
171 	else if(R.FP+t->size < R.SP)
172 		freeframe(R.FP+t->size, 1);
173 
174 	m = R.M;
175 	while(R.FP != fp){
176 		f = (Frame*)R.FP;
177 		R.PC = f->lr;
178 		R.FP = f->fp;
179 		R.SP = (uchar*)f;
180 		mr = f->mr;
181 		if(f->t == nil)
182 			unextend(f);
183 		else if(f->t->np)
184 			freeptrs(f, f->t);
185 		if(mr != nil){
186 			m = mr;
187 			destroy(R.M);
188 			R.M = m;
189 			R.MP = m->MP;
190 		}
191 	}
192 	if(zt != nil){
193 		freeptrs(fp, zt);
194 		initmem(zt, fp);
195 	}
196 	eadr = (uchar**)(fp+eoff);
197 	destroy(*eadr);
198 	*eadr = H;
199 	if(p->exval == H)
200 		*eadr = (uchar*)newestring(estr);	/* might fail */
201 	else{
202 		D2H(p->exval)->ref++;
203 		*eadr = p->exval;
204 	}
205 	if(m->compiled)
206 		R.PC = (Inst*)((ulong)m->prog+newpc);
207 	else
208 		R.PC = m->prog+newpc;
209 	memmove(&p->R, &R, sizeof(R));
210 	p->kill = nil;
211 	destroy(p->exval);
212 	p->exval = H;
213 	return 1;
214 }
215