Exemplo n.º 1
0
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);
}
Exemplo n.º 2
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);
}