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: