void except_fillInEHTable(symbol *s) { unsigned fsize = NPTRSIZE; // target size of function pointer dt_t **pdt = &s->Sdt; /* void* pointer to start of function (Windows) unsigned offset of ESP from EBP unsigned offset from start of function to return code unsigned nguards; // dimension of guard[] (Linux) Guard guard[]; // sorted such that the enclosing guarded sections come first catchoffset: unsigned ncatches; // number of catch blocks { void *type; // symbol representing type unsigned bpoffset; // EBP offset of catch variable void *handler; // catch handler code } catch[]; */ /* Be careful of this, as we need the sizeof Guard on the target, not * in the compiler. */ unsigned GUARD_SIZE; if (config.ehmethod == EH_DM) GUARD_SIZE = (I64 ? 3*8 : 5*4); else if (config.ehmethod == EH_WIN32) GUARD_SIZE = 3*4; else assert(0); int sz = 0; // Address of start of function if (config.ehmethod == EH_WIN32) { symbol_debug(funcsym_p); pdt = dtxoff(pdt,funcsym_p,0,TYnptr); sz += fsize; } //printf("ehtables: func = %s, offset = x%x, startblock->Boffset = x%x\n", funcsym_p->Sident, funcsym_p->Soffset, startblock->Boffset); // Get offset of ESP from EBP long spoff = cod3_spoff(); pdt = dtdword(pdt,spoff); sz += 4; // Offset from start of function to return code pdt = dtdword(pdt,retoffset); sz += 4; // First, calculate starting catch offset int guarddim = 0; // max dimension of guard[] int ndctors = 0; // number of ESCdctor's for (block *b = startblock; b; b = b->Bnext) { if (b->BC == BC_try && b->Bscope_index >= guarddim) guarddim = b->Bscope_index + 1; // printf("b->BC = %2d, Bscope_index = %2d, last_index = %2d, offset = x%x\n", // b->BC, b->Bscope_index, b->Blast_index, b->Boffset); if (usednteh & EHcleanup) for (code *c = b->Bcode; c; c = code_next(c)) { if (c->Iop == (ESCAPE | ESCddtor)) ndctors++; } } //printf("guarddim = %d, ndctors = %d\n", guarddim, ndctors); if (config.ehmethod == EH_DM) { pdt = dtsize_t(pdt,guarddim + ndctors); sz += NPTRSIZE; } unsigned catchoffset = sz + (guarddim + ndctors) * GUARD_SIZE; // Generate guard[] int i = 0; for (block *b = startblock; b; b = b->Bnext) { //printf("b = %p, b->Btry = %p, b->offset = %x\n", b, b->Btry, b->Boffset); if (b->BC == BC_try) { assert(b->Bscope_index >= i); if (i < b->Bscope_index) { int fillsize = (b->Bscope_index - i) * GUARD_SIZE; pdt = dtnzeros(pdt, fillsize); sz += fillsize; } i = b->Bscope_index + 1; int nsucc = b->numSucc(); if (config.ehmethod == EH_DM) { //printf("DHandlerInfo: offset = %x", (int)(b->Boffset - startblock->Boffset)); pdt = dtdword(pdt,b->Boffset - startblock->Boffset); // offset to start of block // Compute ending offset unsigned endoffset; for (block *bn = b->Bnext; 1; bn = bn->Bnext) { //printf("\tbn = %p, bn->Btry = %p, bn->offset = %x\n", bn, bn->Btry, bn->Boffset); assert(bn); if (bn->Btry == b->Btry) { endoffset = bn->Boffset - startblock->Boffset; break; } } //printf(" endoffset = %x, prev_index = %d\n", endoffset, b->Blast_index); pdt = dtdword(pdt,endoffset); // offset past end of guarded block } pdt = dtdword(pdt,b->Blast_index); // parent index if (b->jcatchvar) // if try-catch { assert(catchoffset); pdt = dtdword(pdt,catchoffset); pdt = dtsize_t(pdt,0); // no finally handler catchoffset += NPTRSIZE + (nsucc - 1) * (3 * NPTRSIZE); } else // else try-finally { assert(nsucc == 2); pdt = dtdword(pdt,0); // no catch offset block *bhandler = b->nthSucc(1); assert(bhandler->BC == BC_finally); // To successor of BC_finally block bhandler = bhandler->nthSucc(0); // finally handler address if (config.ehmethod == EH_DM) { assert(bhandler->Boffset > startblock->Boffset); pdt = dtsize_t(pdt,bhandler->Boffset - startblock->Boffset); // finally handler offset } else pdt = dtcoff(pdt,bhandler->Boffset); } sz += GUARD_SIZE; } } /* Append to guard[] the guard blocks for temporaries that are created and destroyed * within a single expression. These are marked by the special instruction pairs * (ESCAPE | ESCdctor) and (ESCAPE | ESCddtor). */ if (usednteh & EHcleanup) { #define STACKINC 16 int stackbuf[STACKINC]; int *stack = stackbuf; int stackmax = STACKINC; int scopeindex = guarddim; for (block *b = startblock; b; b = b->Bnext) { /* Set up stack of scope indices */ stack[0] = b->Btry ? b->Btry->Bscope_index : -1; int stacki = 1; unsigned boffset = b->Boffset; for (code *c = b->Bcode; c; c = code_next(c)) { if (c->Iop == (ESCAPE | ESCdctor)) { code *c2 = code_next(c); if (config.flags2 & CFG2seh) nteh_patchindex(c2, scopeindex); if (config.ehmethod == EH_DM) pdt = dtdword(pdt,boffset - startblock->Boffset); // guard offset // Find corresponding ddtor instruction int n = 0; unsigned eoffset = boffset; unsigned foffset; for (; 1; c2 = code_next(c2)) { // Bugzilla 13720: optimizer might elide the corresponding ddtor if (!c2) goto Lnodtor; if (c2->Iop == (ESCAPE | ESCddtor)) { if (n) n--; else { foffset = eoffset; code *cf = code_next(c2); if (config.flags2 & CFG2seh) { nteh_patchindex(cf, stack[stacki - 1]); foffset += calccodsize(cf); cf = code_next(cf); } foffset += calccodsize(cf); while (!cf->isJumpOP()) { cf = code_next(cf); foffset += calccodsize(cf); } // issue 9438 //cf = code_next(cf); //foffset += calccodsize(cf); if (config.ehmethod == EH_DM) pdt = dtdword(pdt,eoffset - startblock->Boffset); // guard offset break; } } else if (c2->Iop == (ESCAPE | ESCdctor)) { n++; } else eoffset += calccodsize(c2); } //printf("boffset = %x, eoffset = %x, foffset = %x\n", boffset, eoffset, foffset); pdt = dtdword(pdt,stack[stacki - 1]); // parent index pdt = dtdword(pdt,0); // no catch offset if (config.ehmethod == EH_DM) { assert(foffset > startblock->Boffset); pdt = dtsize_t(pdt,foffset - startblock->Boffset); // finally handler offset } else pdt = dtcoff(pdt,foffset); // finally handler address if (stacki == stackmax) { // stack[] is out of space; enlarge it int *pi = (int *)malloc((stackmax + STACKINC) * sizeof(int)); assert(pi); memcpy(pi, stack, stackmax * sizeof(int)); if (stack != stackbuf) free(stack); stack = pi; stackmax += STACKINC; } stack[stacki++] = scopeindex; ++scopeindex; sz += GUARD_SIZE; } else if (c->Iop == (ESCAPE | ESCddtor)) { stacki--; assert(stacki != 0); } Lnodtor: boffset += calccodsize(c); } } if (stack != stackbuf) free(stack); } // Generate catch[] for (block *b = startblock; b; b = b->Bnext) { if (b->BC == BC_try && b->jcatchvar) // if try-catch { int nsucc = b->numSucc(); pdt = dtsize_t(pdt,nsucc - 1); // # of catch blocks sz += NPTRSIZE; for (int i = 1; i < nsucc; ++i) { block *bcatch = b->nthSucc(i); pdt = dtxoff(pdt,bcatch->Bcatchtype,0,TYnptr); pdt = dtsize_t(pdt,cod3_bpoffset(b->jcatchvar)); // EBP offset // catch handler address if (config.ehmethod == EH_DM) { assert(bcatch->Boffset > startblock->Boffset); pdt = dtsize_t(pdt,bcatch->Boffset - startblock->Boffset); // catch handler offset } else pdt = dtcoff(pdt,bcatch->Boffset); sz += 3 * NPTRSIZE; } } } assert(sz != 0); }
void genDwarfEh(Funcsym *sfunc, int seg, Outbuffer *et, bool scancode, unsigned startoffset, unsigned retoffset) { #ifdef DEBUG unittest_dwarfeh(); #endif /* LPstart = encoding of LPbase * LPbase = landing pad base (normally omitted) * TType = encoding of TTbase * TTbase = offset from next byte to past end of Type Table * CallSiteFormat = encoding of fields in Call Site Table * CallSiteTableSize = size in bytes of Call Site Table * Call Site Table[]: * CallSiteStart * CallSiteRange * LandingPad * ActionRecordPtr * Action Table * TypeFilter * NextRecordPtr * Type Table */ et->reserve(100); block *startblock = sfunc->Sfunc->Fstartblock; //printf("genDwarfEh: func = %s, offset = x%x, startblock->Boffset = x%x, scancode = %d startoffset=x%x, retoffset=x%x\n", //sfunc->Sident, (int)sfunc->Soffset, (int)startblock->Boffset, scancode, startoffset, retoffset); #if 0 printf("------- before ----------\n"); for (block *b = startblock; b; b = b->Bnext) WRblock(b); printf("-------------------------\n"); #endif unsigned startsize = et->size(); assert((startsize & 3) == 0); // should be aligned DwEhTable *deh = &dwehtable; deh->dim = 0; Outbuffer atbuf; Outbuffer cstbuf; /* Build deh table, and Action Table */ int index = -1; block *bprev = NULL; // The first entry encompasses the entire function { unsigned i = deh->push(); DwEhTableEntry *d = deh->index(i); d->start = startblock->Boffset + startoffset; d->end = startblock->Boffset + retoffset; d->lpad = 0; // no cleanup, no catches index = i; } for (block *b = startblock; b; b = b->Bnext) { if (index > 0 && b->Btry == bprev) { DwEhTableEntry *d = deh->index(index); d->end = b->Boffset; index = d->prev; if (bprev) bprev = bprev->Btry; } if (b->BC == BC_try) { unsigned i = deh->push(); DwEhTableEntry *d = deh->index(i); d->start = b->Boffset; block *bf = b->nthSucc(1); if (bf->BC == BCjcatch) { d->lpad = bf->Boffset; d->bcatch = bf; unsigned *pat = bf->BS.BIJCATCH.actionTable; unsigned length = pat[0]; assert(length); unsigned offset = -1; for (unsigned u = length; u; --u) { /* Buy doing depth-first insertion into the Action Table, * we can combine common tails. */ offset = actionTableInsert(&atbuf, pat[u], offset); } d->action = offset + 1; } else d->lpad = bf->nthSucc(0)->Boffset; d->prev = index; index = i; bprev = b->Btry; } if (scancode) { unsigned coffset = b->Boffset; int n = 0; for (code *c = b->Bcode; c; c = code_next(c)) { if (c->Iop == (ESCAPE | ESCdctor)) { unsigned i = deh->push(); DwEhTableEntry *d = deh->index(i); d->start = coffset; d->prev = index; index = i; ++n; } if (c->Iop == (ESCAPE | ESCddtor)) { assert(n > 0); --n; DwEhTableEntry *d = deh->index(index); d->end = coffset; d->lpad = coffset; index = d->prev; } coffset += calccodsize(c); } assert(n == 0); } } //printf("deh->dim = %d\n", (int)deh->dim); #if 1 /* Build Call Site Table * Be sure to not generate empty entries, * and generate nested ranges reflecting the layout in the code. */ assert(deh->dim); unsigned end = deh->index(0)->start; for (unsigned i = 0; i < deh->dim; ++i) { DwEhTableEntry *d = deh->index(i); if (d->start < d->end) { #if ELFOBJ #define WRITE writeuLEB128 #elif MACHOBJ #define WRITE write32 #else assert(0); #endif unsigned CallSiteStart = d->start - startblock->Boffset; cstbuf.WRITE(CallSiteStart); unsigned CallSiteRange = d->end - d->start; cstbuf.WRITE(CallSiteRange); unsigned LandingPad = d->lpad ? d->lpad - startblock->Boffset : 0; cstbuf.WRITE(LandingPad); unsigned ActionTable = d->action; cstbuf.writeuLEB128(ActionTable); //printf("\t%x %x %x %x\n", CallSiteStart, CallSiteRange, LandingPad, ActionTable); #undef WRITE } } #else /* Build Call Site Table * Be sure to not generate empty entries, * and generate multiple entries for one DwEhTableEntry if the latter * is split by nested DwEhTableEntry's. This is based on the (undocumented) * presumption that there may not * be overlapping entries in the Call Site Table. */ assert(deh->dim); unsigned end = deh->index(0)->start; for (unsigned i = 0; i < deh->dim; ++i) { unsigned j = i; do { DwEhTableEntry *d = deh->index(j); //printf(" [%d] start=%x end=%x lpad=%x action=%x bcatch=%p prev=%d\n", // j, d->start, d->end, d->lpad, d->action, d->bcatch, d->prev); if (d->start <= end && end < d->end) { unsigned start = end; unsigned dend = d->end; if (i + 1 < deh->dim) { DwEhTableEntry *dnext = deh->index(i + 1); if (dnext->start < dend) dend = dnext->start; } if (start < dend) { #if ELFOBJ #define WRITE writeLEB128 #elif MACHOBJ #define WRITE write32 #else assert(0); #endif unsigned CallSiteStart = start - startblock->Boffset; cstbuf.WRITE(CallSiteStart); unsigned CallSiteRange = dend - start; cstbuf.WRITE(CallSiteRange); unsigned LandingPad = d->lpad - startblock->Boffset; cstbuf.WRITE(LandingPad); unsigned ActionTable = d->action; cstbuf.WRITE(ActionTable); //printf("\t%x %x %x %x\n", CallSiteStart, CallSiteRange, LandingPad, ActionTable); #undef WRITE } end = dend; } } while (j--); } #endif /* Write LSDT header */ const unsigned char LPstart = DW_EH_PE_omit; et->writeByte(LPstart); unsigned LPbase = 0; if (LPstart != DW_EH_PE_omit) et->writeuLEB128(LPbase); const unsigned char TType = (config.flags3 & CFG3pic) ? DW_EH_PE_indirect | DW_EH_PE_pcrel | DW_EH_PE_sdata4 : DW_EH_PE_absptr | DW_EH_PE_udata4; et->writeByte(TType); /* Compute TTbase, which is the sum of: * 1. CallSiteFormat * 2. encoding of CallSiteTableSize * 3. Call Site Table size * 4. Action Table size * 5. 4 byte alignment * 6. Types Table * Iterate until it converges. */ unsigned TTbase = 1; unsigned CallSiteTableSize = cstbuf.size(); unsigned oldTTbase; do { oldTTbase = TTbase; unsigned start = (et->size() - startsize) + uLEB128size(TTbase); TTbase = 1 + uLEB128size(CallSiteTableSize) + CallSiteTableSize + atbuf.size(); unsigned sz = start + TTbase; TTbase += -sz & 3; // align to 4 TTbase += sfunc->Sfunc->typesTableDim * 4; } while (TTbase != oldTTbase); if (TType != DW_EH_PE_omit) et->writeuLEB128(TTbase); unsigned TToffset = TTbase + et->size() - startsize; #if ELFOBJ const unsigned char CallSiteFormat = DW_EH_PE_absptr | DW_EH_PE_uleb128; #elif MACHOBJ const unsigned char CallSiteFormat = DW_EH_PE_absptr | DW_EH_PE_udata4; #else assert(0); #endif et->writeByte(CallSiteFormat); et->writeuLEB128(CallSiteTableSize); /* Insert Call Site Table */ et->write(&cstbuf); /* Insert Action Table */ et->write(&atbuf); /* Align to 4 */ for (unsigned n = (-et->size() & 3); n; --n) et->writeByte(0); /* Write out Types Table in reverse */ Symbol **typesTable = sfunc->Sfunc->typesTable; for (int i = sfunc->Sfunc->typesTableDim; i--; ) { Symbol *s = typesTable[i]; /* MACHOBJ 64: pcrel 1 length 1 extern 1 RELOC_GOT * 32: [0] address x004c pcrel 0 length 2 value x224 type 4 RELOC_LOCAL_SECTDIFF * [1] address x0000 pcrel 0 length 2 value x160 type 1 RELOC_PAIR */ dwarf_reftoident(seg, et->size(), s, 0); } assert(TToffset == et->size() - startsize); }