void unittest_LEB128() { Outbuffer buf; static int values[] = { 0,1,2,3,300,4000,50000,600000, -0,-1,-2,-3,-300,-4000,-50000,-600000, }; for (size_t i = 0; i < sizeof(values)/sizeof(values[0]); ++i) { const int value = values[i]; buf.reset(); buf.writeuLEB128(value); assert(buf.size() == uLEB128size(value)); unsigned char *p = buf.buf; int result = uLEB128(&p); assert(p == buf.p); assert(result == value); buf.reset(); buf.writesLEB128(value); assert(buf.size() == sLEB128size(value)); p = buf.buf; result = sLEB128(&p); assert(p == buf.p); assert(result == value); } }
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); }