1: /*
2: * Copyright (c) 1994-1998 by Symantec
3: * Copyright (c) 2000-2011 by Digital Mars
4: * All Rights Reserved
5: * http://www.digitalmars.com
6: * http://www.dsource.org/projects/dmd/browser/branches/dmd-1.x/src/eh.c
7: * http://www.dsource.org/projects/dmd/browser/trunk/src/eh.c
8: * Written by Walter Bright
9: *
10: * This source file is made available for personal use
11: * only. The license is in /dmd/src/dmd/backendlicense.txt
12: * For any other uses, please contact Digital Mars.
13: */
14:
15: // Support for D exception handling
16:
17: #include <stdio.h>
18: #include <string.h>
19: #include <stdlib.h>
20: #include <time.h>
21:
22: #include "cc.h"
23: #include "el.h"
24: #include "code.h"
25: #include "oper.h"
26: #include "global.h"
27: #include "type.h"
28: #include "dt.h"
29: #include "exh.h"
30: #include "root.h"
31:
32: static char __file__[] = __FILE__; /* for tassert.h */
33: #include "tassert.h"
34:
35: /* If we do our own EH tables and stack walking scheme
36: * (Otherwise use NT Structured Exception Handling)
37: */
38: #define OUREH (TARGET_LINUX || TARGET_OSX || TARGET_FREEBSD || TARGET_OPENBSD || TARGET_SOLARIS)
39:
40:
41: /****************************
42: * Generate and output scope table.
43: */
44:
45: symbol *except_gentables()
46: {
47: //printf("except_gentables()\n");
48: #if OUREH
49:
50: // BUG: alloca() changes the stack size, which is not reflected
51: // in the fixed eh tables.
52: assert(!usedalloca);
53:
54: symbol *s = symbol_generate(SCstatic,tsint);
55: s->Sseg = UNKNOWN;
56: symbol_keep(s);
57: symbol_debug(s);
58:
59: except_fillInEHTable(s);
60:
61: outdata(s); // output the scope table
62:
63: obj_ehtables(funcsym_p,funcsym_p->Ssize,s);
64: #endif
65: return NULL;
66: }
67:
68: /**********************************************
69: * Initializes the symbol s with the contents of the exception handler table.
70: */
71:
72: struct Guard
73: {
74: #if OUREH
75: unsigned offset; // offset of start of guarded section (Linux)
76: unsigned endoffset; // ending offset of guarded section (Linux)
77: #endif
78: int last_index; // previous index (enclosing guarded section)
79: unsigned catchoffset; // offset to catch block from symbol
80: void *finally; // finally code to execute
81: };
82:
83: void except_fillInEHTable(symbol *s)
84: {
85: unsigned fsize = NPTRSIZE; // target size of function pointer
86: dt_t **pdt = &s->Sdt;
87:
88: /*
89: void* pointer to start of function
90: unsigned offset of ESP from EBP
91: unsigned offset from start of function to return code
92: unsigned nguards; // dimension of guard[] (Linux)
93: Guard guard[]; // sorted such that the enclosing guarded sections come first
94: catchoffset:
95: unsigned ncatches; // number of catch blocks
96: { void *type; // symbol representing type
97: unsigned bpoffset; // EBP offset of catch variable
98: void *handler; // catch handler code
99: } catch[];
100: */
101:
102: /* Be careful of this, as we need the sizeof Guard on the target, not
103: * in the compiler.
104: */
105: #if OUREH
106: #define GUARD_SIZE (I64 ? 3*8 : 5*4) // sizeof(Guard)
107: #else
108: #define GUARD_SIZE (sizeof(Guard))
109: #endif
110:
111: int sz = 0;
112:
113: // Address of start of function
114: symbol_debug(funcsym_p);
115: pdt = dtxoff(pdt,funcsym_p,0,TYnptr);
116: sz += fsize;
117:
118: //printf("ehtables: func = %s, offset = x%x, startblock->Boffset = x%x\n", funcsym_p->Sident, funcsym_p->Soffset, startblock->Boffset);
119:
120: // Get offset of ESP from EBP
121: long spoff = cod3_spoff();
122: pdt = dtdword(pdt,spoff);
123: sz += 4;
124:
125: // Offset from start of function to return code
126: pdt = dtdword(pdt,retoffset);
127: sz += 4;
128:
129: // First, calculate starting catch offset
130: int guarddim = 0; // max dimension of guard[]
131: int ndctors = 0; // number of ESCdctor's
132: for (block *b = startblock; b; b = b->Bnext)
133: {
134: if (b->BC == BC_try && b->Bscope_index >= guarddim)
135: guarddim = b->Bscope_index + 1;
136: // printf("b->BC = %2d, Bscope_index = %2d, last_index = %2d, offset = x%x\n",
137: // b->BC, b->Bscope_index, b->Blast_index, b->Boffset);
138: if (usednteh & EHcleanup)
139: for (code *c = b->Bcode; c; c = code_next(c))
140: {
141: if (c->Iop == (ESCAPE | ESCddtor))
142: ndctors++;
143: }
144: }
145: //printf("guarddim = %d, ndctors = %d\n", guarddim, ndctors);
146:
147: #if OUREH
148: pdt = dtsize_t(pdt,guarddim + ndctors);
149: sz += NPTRSIZE;
150: #endif
151:
152: unsigned catchoffset = sz + (guarddim + ndctors) * GUARD_SIZE;
153:
154: // Generate guard[]
155: int i = 0;
156: for (block *b = startblock; b; b = b->Bnext)
157: {
158: //printf("b = %p, b->Btry = %p, b->offset = %x\n", b, b->Btry, b->Boffset);
159: if (b->BC == BC_try)
160: {
161: assert(b->Bscope_index >= i);
162: if (i < b->Bscope_index)
163: { int fillsize = (b->Bscope_index - i) * GUARD_SIZE;
164: pdt = dtnzeros(pdt, fillsize);
165: sz += fillsize;
166: }
167: i = b->Bscope_index + 1;
168:
169: int nsucc = list_nitems(b->Bsucc);
170:
171: #if OUREH
172: //printf("DHandlerInfo: offset = %x", (int)(b->Boffset - startblock->Boffset));
173: pdt = dtdword(pdt,b->Boffset - startblock->Boffset); // offset to start of block
174:
175: // Compute ending offset
176: unsigned endoffset;
177: for (block *bn = b->Bnext; 1; bn = bn->Bnext)
178: {
179: //printf("\tbn = %p, bn->Btry = %p, bn->offset = %x\n", bn, bn->Btry, bn->Boffset);
180: assert(bn);
181: if (bn->Btry == b->Btry)
182: { endoffset = bn->Boffset - startblock->Boffset;
183: break;
184: }
185: }
186: //printf(" endoffset = %x, prev_index = %d\n", endoffset, b->Blast_index);
187: pdt = dtdword(pdt,endoffset); // offset past end of guarded block
188: #endif
189:
190: pdt = dtdword(pdt,b->Blast_index); // parent index
191:
192: if (b->jcatchvar) // if try-catch
193: {
194: pdt = dtdword(pdt,catchoffset);
195: pdt = dtsize_t(pdt,0); // no finally handler
196:
197: catchoffset += NPTRSIZE + (nsucc - 1) * (3 * NPTRSIZE);
198: }
199: else // else try-finally
200: {
201: assert(nsucc == 2);
202: pdt = dtdword(pdt,0); // no catch offset
203: block *bhandler = list_block(list_next(b->Bsucc));
204: assert(bhandler->BC == BC_finally);
205: // To successor of BC_finally block
206: bhandler = list_block(bhandler->Bsucc);
207: #if OUREH
208: pdt = dtxoff(pdt,funcsym_p,bhandler->Boffset - startblock->Boffset, TYnptr); // finally handler address
209: #else
210: pdt = dtcoff(pdt,bhandler->Boffset); // finally handler address
211: #endif
212: }
213: sz += GUARD_SIZE;
214: }
215: }
216:
217: /* Append to guard[] the guard blocks for temporaries that are created and destroyed
218: * within a single expression. These are marked by the special instruction pairs
219: * (ESCAPE | ESCdctor) and (ESCAPE | ESCddtor).
220: */
221: if (usednteh & EHcleanup)
222: {
223: int scopeindex = guarddim;
224: for (block *b = startblock; b; b = b->Bnext)
225: {
226: /* Set up stack of scope indices
227: */
228: #define STACKINC 16
229: int stackbuf[STACKINC];
230: int *stack = stackbuf;
231: int stackmax = STACKINC;
232: stack[0] = b->Bscope_index;
233: int stacki = 1;
234:
235: unsigned boffset = b->Boffset;
236: for (code *c = b->Bcode; c; c = code_next(c))
237: {
238: if (c->Iop == (ESCAPE | ESCdctor))
239: {
240: code *c2 = code_next(c);
241: if (config.flags2 & CFG2seh)
242: c2->IEV2.Vsize_t = scopeindex;
243: #if OUREH
244: pdt = dtdword(pdt,boffset - startblock->Boffset); // guard offset
245: #endif
246: // Find corresponding ddtor instruction
247: int n = 0;
248: unsigned eoffset = boffset;
249: unsigned foffset;
250: for (; 1; c2 = code_next(c2))
251: {
252: assert(c2);
253: if (c2->Iop == (ESCAPE | ESCddtor))
254: {
255: if (n)
256: n--;
257: else
258: {
259: foffset = eoffset;
260: code *cf = code_next(c2);
261: if (config.flags2 & CFG2seh)
262: { cf->IEV2.Vsize_t = scopeindex;
263: foffset += calccodsize(cf);
264: cf = code_next(cf);
265: }
266: foffset += calccodsize(cf);
267: while (cf->Iop != JMP && cf->Iop != JMPS)
268: {
269: cf = code_next(cf);
270: foffset += calccodsize(cf);
271: }
272: cf = code_next(cf);
273: foffset += calccodsize(cf);
274: #if OUREH
275: pdt = dtdword(pdt,eoffset - startblock->Boffset); // guard offset
276: #endif
277: break;
278: }
279: }
280: else if (c2->Iop == (ESCAPE | ESCdctor))
281: {
282: n++;
283: }
284: else
285: eoffset += calccodsize(c2);
286: }
287: //printf("boffset = %x, eoffset = %x, foffset = %x\n", boffset, eoffset, foffset);
288: pdt = dtdword(pdt,stack[stacki - 1]); // parent index
289: pdt = dtdword(pdt,0); // no catch offset
290: #if OUREH
291: pdt = dtxoff(pdt,funcsym_p,foffset - startblock->Boffset, TYnptr); // finally handler offset
292: #else
293: pdt = dtcoff(pdt,foffset); // finally handler address
294: #endif
295: if (stacki == stackmax)
296: { // stack[] is out of space; enlarge it
297: int *pi = (int *)alloca((stackmax + STACKINC) * sizeof(int));
warning C6255: _alloca indicates failure by raising a stack overflow exception. Consider using _malloca instead
warning C6263: Using _alloca in a loop: this can quickly overflow stack: Lines: 236
298: assert(pi);
299: memcpy(pi, stack, stackmax * sizeof(int));
300: stack = pi;
301: stackmax += STACKINC;
302: }
303: stack[stacki++] = scopeindex;
304: ++scopeindex;
305: sz += GUARD_SIZE;
306: }
307: else if (c->Iop == (ESCAPE | ESCddtor))
308: {
309: stacki--;
310: assert(stacki != 0);
311: }
312: boffset += calccodsize(c);
313: }
314: }
315: }
316:
317: // Generate catch[]
318: for (block *b = startblock; b; b = b->Bnext)
319: {
320: if (b->BC == BC_try && b->jcatchvar) // if try-catch
321: {
322: int nsucc = list_nitems(b->Bsucc);
323: pdt = dtsize_t(pdt,nsucc - 1); // # of catch blocks
324: sz += NPTRSIZE;
325:
326: for (list_t bl = list_next(b->Bsucc); bl; bl = list_next(bl))
327: {
328: block *bcatch = list_block(bl);
329:
330: pdt = dtxoff(pdt,bcatch->Bcatchtype,0,TYjhandle);
331:
332: pdt = dtsize_t(pdt,cod3_bpoffset(b->jcatchvar)); // EBP offset
333:
334: #if OUREH
335: pdt = dtxoff(pdt,funcsym_p,bcatch->Boffset - startblock->Boffset, TYnptr); // catch handler address
336: #else
337: pdt = dtcoff(pdt,bcatch->Boffset); // catch handler address
338: #endif
339: sz += 3 * NPTRSIZE;
340: }
341: }
342: }
343: assert(sz != 0);
344: }
345:
346: