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