]> git.llucax.com Git - software/druntime.git/blob - src/compiler/dmd/deh2.d
add hidden function error support
[software/druntime.git] / src / compiler / dmd / deh2.d
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 }