2 * Copyright (C) 1999-2005 by Digital Mars, www.digitalmars.com
3 * Written by Walter Bright
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.
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
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
26 // Exception handling support for linux
32 extern void* _deh_beg;
33 extern void* _deh_end;
35 int _d_isbaseof(ClassInfo oc, ClassInfo c);
38 alias int (*fp_t)(); // function pointer in ambient memory model
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)
50 // Address of DHandlerTable, searched for by eh_finddata()
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];
63 ClassInfo type; // catch type
64 uint bpoffset; // EBP offset of catch var
65 void *code; // catch handler code
68 // Create one of these for each try-catch
71 uint ncatches; // number of catch blocks
72 DCatchBlock catch_block[1]; // data for each catch block
75 // One of these is generated for each function with try-catch or try-finally
79 void *fptr; // pointer to start of function
80 DHandlerTable *handlertable; // eh data for this function
81 uint fsize; // size of function in bytes
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.
98 DHandlerTable *__eh_finddata(void *address)
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;
108 // debug printf("\tfptr = x%x, fsize = x%03x, handlertable = x%x\n",
109 // ft.fptr, ft.fsize, ft.handlertable);
111 if (ft.fptr <= address &&
112 address < cast(void *)(cast(char *)ft.fptr + ft.fsize))
114 // debug printf("\tfound handler table\n");
115 return ft.handlertable;
118 // debug printf("\tnot found\n");
123 /******************************
124 * Given EBP, find return address to caller, and caller's EBP.
126 * regbp Value of EBP for current function
127 * *pretaddr Return address
129 * *pretaddr return address to caller
134 uint __eh_find_caller(uint regbp, uint *pretaddr)
136 uint bp = *cast(uint *)regbp;
138 if (bp) // if not end of call chain
140 // Perform sanity checks on new EBP.
141 // If it is screwed up, terminate() hopefully before we do more damage.
143 // stack should grow to smaller values
146 *pretaddr = *cast(uint *)(regbp + int.sizeof);
151 /***********************************
155 extern (Windows) void _d_throw(Object *h)
161 printf("_d_throw(h = %p, &h = %p)\n", h, &h);
162 printf("\tvptr = %p\n", *cast(void **)h);
171 //if (++abc == 2) *(char *)0=0;
174 while (1) // for each function on the stack
176 DHandlerTable *handler_table;
188 regebp = __eh_find_caller(regebp,&retaddr);
190 { // if end of call chain
191 debug printf("end of call chain\n");
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
200 debug printf("no handler table\n");
203 funcoffset = cast(uint)handler_table.fptr;
204 spoff = handler_table.espoffset;
205 retoffset = handler_table.retoffset;
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);
214 // Find start index for retaddr in static data
215 dim = handler_table.nhandlers;
219 printf("handler_info[]:\n");
220 for (int i = 0; i < dim; i++)
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);
229 for (int i = 0; i < dim; i++)
231 phi = &handler_table.handler_info[i];
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)
238 debug printf("index = %d\n", index);
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)
244 phi = &handler_table.handler_info[ndx];
245 prev_ndx = phi.prev_index;
248 // this is a catch handler (no finally)
253 pci = cast(DCatchInfo *)(cast(char *)handler_table + phi.cioffset);
254 ncatches = pci.ncatches;
255 for (i = 0; i < ncatches; i++)
258 ClassInfo ci = **cast(ClassInfo **)h;
260 pcb = &pci.catch_block[i];
262 if (_d_isbaseof(ci, pcb.type))
263 { // Matched the catch type, so we've found the handler.
265 // Initialize catch variable
266 *cast(void **)(regebp + (pcb.bpoffset)) = h;
268 // Jump to catch block. Does not return.
273 catch_addr = cast(fp_t)(pcb.code);
274 catch_esp = regebp - handler_table.espoffset - fp_t.sizeof;
281 mov ESP,EAX ; // reset stack
282 ret ; // jump to catch block
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.
293 void *blockaddr = phi.finally_code;