comparison druntime/src/compiler/dmd/deh2.d @ 759:d3eb054172f9

Added copy of druntime from DMD 2.020 modified for LDC.
author Tomas Lindquist Olsen <tomas.l.olsen@gmail.com>
date Tue, 11 Nov 2008 01:52:37 +0100
parents
children
comparison
equal deleted inserted replaced
758:f04dde6e882c 759:d3eb054172f9
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 module rt.deh2;
25
26 // Exception handling support for linux
27
28 //debug=1;
29
30 extern (C)
31 {
32 extern void* _deh_beg;
33 extern void* _deh_end;
34
35 int _d_isbaseof(ClassInfo oc, ClassInfo c);
36 }
37
38 alias int (*fp_t)(); // function pointer in ambient memory model
39
40 struct DHandlerInfo
41 {
42 uint offset; // offset from function address to start of guarded section
43 uint endoffset; // offset of end of guarded section
44 int prev_index; // previous table index
45 uint cioffset; // offset to DCatchInfo data from start of table (!=0 if try-catch)
46 void *finally_code; // pointer to finally code to execute
47 // (!=0 if try-finally)
48 }
49
50 // Address of DHandlerTable, searched for by eh_finddata()
51
52 struct DHandlerTable
53 {
54 void *fptr; // pointer to start of function
55 uint espoffset; // offset of ESP from EBP
56 uint retoffset; // offset from start of function to return code
57 uint nhandlers; // dimension of handler_info[]
58 DHandlerInfo handler_info[1];
59 }
60
61 struct DCatchBlock
62 {
63 ClassInfo type; // catch type
64 uint bpoffset; // EBP offset of catch var
65 void *code; // catch handler code
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 of these is generated for each function with try-catch or try-finally
76
77 struct FuncTable
78 {
79 void *fptr; // pointer to start of function
80 DHandlerTable *handlertable; // eh data for this function
81 uint fsize; // size of function in bytes
82 }
83
84 void terminate()
85 {
86 asm
87 {
88 hlt ;
89 }
90 }
91
92 /*******************************************
93 * Given address that is inside a function,
94 * figure out which function it is in.
95 * Return DHandlerTable if there is one, NULL if not.
96 */
97
98 DHandlerTable *__eh_finddata(void *address)
99 {
100 FuncTable *ft;
101
102 // debug printf("__eh_finddata(address = x%x)\n", address);
103 // debug printf("_deh_beg = x%x, _deh_end = x%x\n", &_deh_beg, &_deh_end);
104 for (ft = cast(FuncTable *)&_deh_beg;
105 ft < cast(FuncTable *)&_deh_end;
106 ft++)
107 {
108 // debug printf("\tfptr = x%x, fsize = x%03x, handlertable = x%x\n",
109 // ft.fptr, ft.fsize, ft.handlertable);
110
111 if (ft.fptr <= address &&
112 address < cast(void *)(cast(char *)ft.fptr + ft.fsize))
113 {
114 // debug printf("\tfound handler table\n");
115 return ft.handlertable;
116 }
117 }
118 // debug printf("\tnot found\n");
119 return null;
120 }
121
122
123 /******************************
124 * Given EBP, find return address to caller, and caller's EBP.
125 * Input:
126 * regbp Value of EBP for current function
127 * *pretaddr Return address
128 * Output:
129 * *pretaddr return address to caller
130 * Returns:
131 * caller's EBP
132 */
133
134 uint __eh_find_caller(uint regbp, uint *pretaddr)
135 {
136 uint bp = *cast(uint *)regbp;
137
138 if (bp) // if not end of call chain
139 {
140 // Perform sanity checks on new EBP.
141 // If it is screwed up, terminate() hopefully before we do more damage.
142 if (bp <= regbp)
143 // stack should grow to smaller values
144 terminate();
145
146 *pretaddr = *cast(uint *)(regbp + int.sizeof);
147 }
148 return bp;
149 }
150
151 /***********************************
152 * Throw a D object.
153 */
154
155 extern (Windows) void _d_throw(Object *h)
156 {
157 uint regebp;
158
159 debug
160 {
161 printf("_d_throw(h = %p, &h = %p)\n", h, &h);
162 printf("\tvptr = %p\n", *cast(void **)h);
163 }
164
165 asm
166 {
167 mov regebp,EBP ;
168 }
169
170 //static uint abc;
171 //if (++abc == 2) *(char *)0=0;
172
173 //int count = 0;
174 while (1) // for each function on the stack
175 {
176 DHandlerTable *handler_table;
177 FuncTable *pfunc;
178 DHandlerInfo *phi;
179 uint retaddr;
180 uint funcoffset;
181 uint spoff;
182 uint retoffset;
183 int index;
184 int dim;
185 int ndx;
186 int prev_ndx;
187
188 regebp = __eh_find_caller(regebp,&retaddr);
189 if (!regebp)
190 { // if end of call chain
191 debug printf("end of call chain\n");
192 break;
193 }
194
195 debug printf("found caller, EBP = x%x, retaddr = x%x\n", regebp, retaddr);
196 //if (++count == 12) *(char*)0=0;
197 handler_table = __eh_finddata(cast(void *)retaddr); // find static data associated with function
198 if (!handler_table) // if no static data
199 {
200 debug printf("no handler table\n");
201 continue;
202 }
203 funcoffset = cast(uint)handler_table.fptr;
204 spoff = handler_table.espoffset;
205 retoffset = handler_table.retoffset;
206
207 debug
208 {
209 printf("retaddr = x%x\n",cast(uint)retaddr);
210 printf("regebp=x%04x, funcoffset=x%04x, spoff=x%x, retoffset=x%x\n",
211 regebp,funcoffset,spoff,retoffset);
212 }
213
214 // Find start index for retaddr in static data
215 dim = handler_table.nhandlers;
216
217 debug
218 {
219 printf("handler_info[]:\n");
220 for (int i = 0; i < dim; i++)
221 {
222 phi = &handler_table.handler_info[i];
223 printf("\t[%d]: offset = x%04x, endoffset = x%04x, prev_index = %d, cioffset = x%04x, finally_code = %x\n",
224 i, phi.offset, phi.endoffset, phi.prev_index, phi.cioffset, phi.finally_code);
225 }
226 }
227
228 index = -1;
229 for (int i = 0; i < dim; i++)
230 {
231 phi = &handler_table.handler_info[i];
232
233 debug printf("i = %d, phi.offset = %04x\n", i, funcoffset + phi.offset);
234 if (cast(uint)retaddr > funcoffset + phi.offset &&
235 cast(uint)retaddr <= funcoffset + phi.endoffset)
236 index = i;
237 }
238 debug printf("index = %d\n", index);
239
240 // walk through handler table, checking each handler
241 // with an index smaller than the current table_index
242 for (ndx = index; ndx != -1; ndx = prev_ndx)
243 {
244 phi = &handler_table.handler_info[ndx];
245 prev_ndx = phi.prev_index;
246 if (phi.cioffset)
247 {
248 // this is a catch handler (no finally)
249 DCatchInfo *pci;
250 int ncatches;
251 int i;
252
253 pci = cast(DCatchInfo *)(cast(char *)handler_table + phi.cioffset);
254 ncatches = pci.ncatches;
255 for (i = 0; i < ncatches; i++)
256 {
257 DCatchBlock *pcb;
258 ClassInfo ci = **cast(ClassInfo **)h;
259
260 pcb = &pci.catch_block[i];
261
262 if (_d_isbaseof(ci, pcb.type))
263 { // Matched the catch type, so we've found the handler.
264
265 // Initialize catch variable
266 *cast(void **)(regebp + (pcb.bpoffset)) = h;
267
268 // Jump to catch block. Does not return.
269 {
270 uint catch_esp;
271 fp_t catch_addr;
272
273 catch_addr = cast(fp_t)(pcb.code);
274 catch_esp = regebp - handler_table.espoffset - fp_t.sizeof;
275 asm
276 {
277 mov EAX,catch_esp ;
278 mov ECX,catch_addr ;
279 mov [EAX],ECX ;
280 mov EBP,regebp ;
281 mov ESP,EAX ; // reset stack
282 ret ; // jump to catch block
283 }
284 }
285 }
286 }
287 }
288 else if (phi.finally_code)
289 { // Call finally block
290 // Note that it is unnecessary to adjust the ESP, as the finally block
291 // accesses all items on the stack as relative to EBP.
292
293 void *blockaddr = phi.finally_code;
294
295 asm
296 {
297 push EBX ;
298 mov EBX,blockaddr ;
299 push EBP ;
300 mov EBP,regebp ;
301 call EBX ;
302 pop EBP ;
303 pop EBX ;
304 }
305 }
306 }
307 }
308 }