Mercurial > projects > ldc
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 |