comparison tango/lib/compiler/llvmdc/deh2.d @ 154:5cb946f323d2 trunk

[svn r160] Added cleaned version of dmd's linux exception runtime
author ChristianK
date Tue, 25 Mar 2008 18:25:24 +0100
parents
children
comparison
equal deleted inserted replaced
153:2c447715c047 154:5cb946f323d2
1 /*
2 * Copyright (C) 1999-2005 by Digital Mars, www.digitalmars.com
3 * Written by Walter Bright
4 *
5 * This software is provided 'as-is', without any express or implied
6 * warranty. In no event will the authors be held liable for any damages
7 * arising from the use of this software.
8 *
9 * Permission is granted to anyone to use this software for any purpose,
10 * including commercial applications, and to alter it and redistribute it
11 * freely, in both source and binary form, subject to the following
12 * restrictions:
13 *
14 * o The origin of this software must not be misrepresented; you must not
15 * claim that you wrote the original software. If you use this software
16 * in a product, an acknowledgment in the product documentation would be
17 * appreciated but is not required.
18 * o Altered source versions must be plainly marked as such, and must not
19 * be misrepresented as being the original software.
20 * o This notice may not be removed or altered from any source
21 * distribution.
22 */
23
24 // Exception handling support for linux
25
26 //debug=1;
27
28 extern (C)
29 {
30 extern void* _deh_beg;
31 extern void* _deh_end;
32
33 int _d_isbaseof(ClassInfo oc, ClassInfo c);
34 }
35
36 // One of these is generated for each function with try-catch or try-finally
37 // all of these structs are located between _deh_beg and _deh_end
38 struct FuncTable
39 {
40 void *fptr; // pointer to start of function
41 DHandlerTable *handlertable; // eh data for this function
42 uint fsize; // size of function in bytes
43 }
44
45 // lists all try-catch and try-finally blocks for a given function
46 // searched for by eh_finddata()
47 struct DHandlerTable
48 {
49 void *fptr; // pointer to start of function, used but seems redundant
50 uint espoffset; // offset of ESP from EBP
51 uint retoffset; // offset from start of function to return code, unused!
52 uint nhandlers; // dimension of handler_info[]
53 DHandlerInfo handler_info[1];
54 }
55
56 // information for a single try-finally or try-catch block
57 struct DHandlerInfo
58 {
59 uint offset; // offset from function address to start of guarded section
60 uint endoffset; // offset of end of guarded section
61 int enclosing_index; // enclosing table index, for nested trys
62 uint cioffset; // offset to DCatchInfo data from start of DHandlerTable
63 // (!=0 if try-catch)
64 void *finally_code; // pointer to finally code to execute
65 // (!=0 if try-finally)
66 }
67
68 // Create one of these for each try-catch
69 struct DCatchInfo
70 {
71 uint ncatches; // number of catch blocks
72 DCatchBlock catch_block[1]; // data for each catch block
73 }
74
75 // one for each catch in try-catch
76 struct DCatchBlock
77 {
78 ClassInfo type; // catch type
79 uint bpoffset; // EBP offset of catch var
80 void *code; // catch handler code
81 }
82
83
84 alias int (*fp_t)(); // function pointer in ambient memory model
85
86 void terminate()
87 {
88 asm
89 {
90 hlt ;
91 }
92 }
93
94 /*******************************************
95 * Given address that is inside a function,
96 * figure out which function it is in.
97 * Return DHandlerTable if there is one, NULL if not.
98 */
99
100 DHandlerTable *__eh_finddata(void *address)
101 {
102 FuncTable *ft;
103
104 // debug printf("__eh_finddata(address = x%x)\n", address);
105 // debug printf("_deh_beg = x%x, _deh_end = x%x\n", &_deh_beg, &_deh_end);
106 for (ft = cast(FuncTable *)&_deh_beg;
107 ft < cast(FuncTable *)&_deh_end;
108 ft++)
109 {
110 // debug printf("\tfptr = x%x, fsize = x%03x, handlertable = x%x\n",
111 // ft.fptr, ft.fsize, ft.handlertable);
112
113 if (ft.fptr <= address &&
114 address < cast(void *)(cast(char *)ft.fptr + ft.fsize))
115 {
116 // debug printf("\tfound handler table\n");
117 return ft.handlertable;
118 }
119 }
120 // debug printf("\tnot found\n");
121 return null;
122 }
123
124
125 /******************************
126 * Given EBP, find return address to caller, and caller's EBP.
127 * Input:
128 * regbp Value of EBP for current function
129 * *pretaddr Return address
130 * Output:
131 * *pretaddr return address to caller
132 * Returns:
133 * caller's EBP
134 */
135
136 uint __eh_find_caller(uint regbp, uint *pretaddr)
137 {
138 uint bp = *cast(uint *)regbp;
139
140 if (bp) // if not end of call chain
141 {
142 // Perform sanity checks on new EBP.
143 // If it is screwed up, terminate() hopefully before we do more damage.
144 if (bp <= regbp)
145 // stack should grow to smaller values
146 terminate();
147
148 *pretaddr = *cast(uint *)(regbp + int.sizeof);
149 }
150 return bp;
151 }
152
153 /***********************************
154 * Throw a D object.
155 */
156
157 extern (Windows) void _d_throw(Object *h)
158 {
159 uint regebp;
160
161 debug
162 {
163 printf("_d_throw(h = %p, &h = %p)\n", h, &h);
164 printf("\tvptr = %p\n", *cast(void **)h);
165 }
166
167 asm
168 {
169 mov regebp,EBP ;
170 }
171
172 while (1) // for each function on the stack
173 {
174 DHandlerTable *handler_table;
175 FuncTable *pfunc;
176 DHandlerInfo *handler;
177 uint calleraddr;
178 uint funcoffset;
179 int index;
180 int dim;
181 int ndx;
182 int enclosing_ndx;
183
184 regebp = __eh_find_caller(regebp,&calleraddr);
185 if (!regebp)
186 { // if end of call chain
187 debug printf("end of call chain\n");
188 break;
189 }
190 debug printf("found caller, EBP = x%x, calleraddr = x%x\n", regebp, calleraddr);
191
192 // find DHandlerTable associated with function
193 handler_table = __eh_finddata(cast(void *)calleraddr);
194 if (!handler_table) // if no static data
195 {
196 debug printf("no handler table\n");
197 continue;
198 }
199 funcoffset = cast(uint)handler_table.fptr;
200
201 debug
202 {
203 printf("calleraddr = x%x\n",cast(uint)calleraddr);
204 printf("regebp=x%04x, funcoffset=x%04x, spoff=x%x, retoffset=x%x\n",
205 regebp,funcoffset,handler_table.espoffset,handler_table.retoffset);
206 }
207
208 dim = handler_table.nhandlers;
209
210 debug
211 {
212 printf("handler_info[]:\n");
213 for (int i = 0; i < dim; i++)
214 {
215 handler = &handler_table.handler_info[i];
216 printf("\t[%d]: offset = x%04x, endoffset = x%04x, enclosing_index = %d, cioffset = x%04x, finally_code = %x\n",
217 i, handler.offset, handler.endoffset, handler.enclosing_index, handler.cioffset, handler.finally_code);
218 }
219 }
220
221 // Find index of DHandlerInfo coresponding to the innermost
222 // try block wrapping calleraddr
223 index = -1;
224 for (int i = 0; i < dim; i++)
225 {
226 handler = &handler_table.handler_info[i];
227
228 debug printf("i = %d, handler.offset = %04x\n", i, funcoffset + handler.offset);
229 if (cast(uint)calleraddr > funcoffset + handler.offset &&
230 cast(uint)calleraddr <= funcoffset + handler.endoffset)
231 index = i; // don't break if found, want innermost try
232 }
233 debug printf("index = %d\n", index);
234
235 // walk through handler infos for all try blocks enclosing the call,
236 // starting with the innermost one we just found
237 for (ndx = index; ndx != -1; ndx = enclosing_ndx)
238 {
239 handler = &handler_table.handler_info[ndx];
240 enclosing_ndx = handler.enclosing_index;
241
242 if (handler.cioffset)
243 {
244 // this is a catch handler (no finally)
245 DCatchInfo *pci;
246 int ncatches;
247 int i;
248
249 pci = cast(DCatchInfo *)(cast(char *)handler_table + handler.cioffset);
250 ncatches = pci.ncatches;
251 for (i = 0; i < ncatches; i++)
252 {
253 DCatchBlock *pcb;
254 ClassInfo ci = **cast(ClassInfo **)h;
255
256 pcb = &pci.catch_block[i];
257
258 if (_d_isbaseof(ci, pcb.type))
259 { // Matched the catch type, so we've found the handler.
260
261 // Initialize catch variable
262 *cast(void **)(regebp + (pcb.bpoffset)) = h;
263
264 // Jump to catch block. Does not return.
265 {
266 uint catch_esp;
267 fp_t catch_addr;
268
269 catch_addr = cast(fp_t)(pcb.code);
270 catch_esp = regebp - handler_table.espoffset - fp_t.sizeof;
271 asm
272 {
273 mov EAX,catch_esp ;
274 mov ECX,catch_addr ;
275 mov [EAX],ECX ;
276 mov EBP,regebp ;
277 mov ESP,EAX ; // reset stack
278 ret ; // jump to catch block
279 }
280 }
281 }
282 }
283 }
284 else if (handler.finally_code)
285 { // Call finally block
286 // Note that it is unnecessary to adjust the ESP, as the finally block
287 // accesses all items on the stack as relative to EBP.
288
289 void *blockaddr = handler.finally_code;
290
291 asm
292 {
293 push EBX ;
294 mov EBX,blockaddr ;
295 push EBP ;
296 mov EBP,regebp ;
297 call EBX ;
298 pop EBP ;
299 pop EBX ;
300 }
301 }
302 }
303 }
304 }
305