Beispiel #1
0
/*  Handles only a location expression.
    If called on a loclist, just returns one of those.
    Cannot not handle a real loclist.
    It returns the location expression as a loclist with
    a single entry.
    See dwarf_loclist_n() which handles any number
    of location list entries.

    This is the original definition, and it simply
    does not work for loclists.
    Nor does it work on DWARF4 nor on some
    versions of gcc generating DWARF4.
    Kept for compatibility.
*/
int
dwarf_loclist(Dwarf_Attribute attr,
    Dwarf_Locdesc ** llbuf,
    Dwarf_Signed * listlen, Dwarf_Error * error)
{
    Dwarf_Debug dbg;

    /*  Dwarf_Attribute that describes the DW_AT_location in die, if
        present. */
    Dwarf_Attribute loc_attr = attr;

    /*  Dwarf_Block that describes a single location expression. */
    Dwarf_Block_c loc_block;

    /*  A pointer to the current Dwarf_Locdesc read. */
    Dwarf_Locdesc *locdesc = 0;

    Dwarf_Half form = 0;
    Dwarf_Addr lowpc = 0;
    Dwarf_Addr highpc = 0;
    Dwarf_CU_Context cucontext = 0;
    unsigned address_size = 0;

    int blkres = DW_DLV_ERROR;
    int setup_res = DW_DLV_ERROR;
    int cuvstamp = 0;

    /* ***** BEGIN CODE ***** */
    setup_res = _dwarf_setup_loc(attr, &dbg, &cucontext, &form, error);
    if (setup_res != DW_DLV_OK) {
        return setup_res;
    }
    cuvstamp = cucontext->cc_version_stamp;
    address_size = cucontext->cc_address_size;
    /*  If this is a form_block then it's a location expression. If it's
        DW_FORM_data4 or DW_FORM_data8 it's a loclist offset */
    if (((cuvstamp == DW_CU_VERSION2 ||
        cuvstamp == DW_CU_VERSION3) &&
            (form == DW_FORM_data4 || form == DW_FORM_data8)) ||
        ((cuvstamp == DW_CU_VERSION4) &&
            form == DW_FORM_sec_offset))
        {

        /*  A reference to .debug_loc, with an offset in .debug_loc of a
            loclist. */
        Dwarf_Unsigned loclist_offset = 0;
        int off_res = DW_DLV_ERROR;

        off_res = _dwarf_get_loclist_header_start(dbg,
            attr, &loclist_offset,
            error);
        if (off_res != DW_DLV_OK) {
            return off_res;
        }

        /* With dwarf_loclist, just read a single entry */
        blkres = _dwarf_read_loc_section(dbg, &loc_block,
            &lowpc,
            &highpc,
            loclist_offset,
            address_size,
            error);
        if (blkres != DW_DLV_OK) {
            return (blkres);
        }
    } else {
        if( form == DW_FORM_exprloc) {
            blkres = dwarf_formexprloc(loc_attr,&loc_block.bl_len,
                &loc_block.bl_data,error);
            if(blkres != DW_DLV_OK) {
                return blkres;
            }
            loc_block.bl_from_loclist = 0;
            loc_block.bl_section_offset  =
                (char *)loc_block.bl_data -
                (char *)dbg->de_debug_info.dss_data;
        } else {
            Dwarf_Block *tblock = 0;

            /* If DWARF5 this will surely fail, get an error. */
            blkres = dwarf_formblock(loc_attr, &tblock, error);
            if (blkres != DW_DLV_OK) {
                return (blkres);
            }
            loc_block.bl_len = tblock->bl_len;;
            loc_block.bl_data = tblock->bl_data;
            loc_block.bl_from_loclist = tblock->bl_from_loclist;
            loc_block.bl_section_offset = tblock->bl_section_offset;
            /*  We copied tblock contents to the stack var, so can dealloc
                tblock now.  Avoids leaks. */
            dwarf_dealloc(dbg, tblock, DW_DLA_BLOCK);
        }
        lowpc = 0;              /* HACK */
        highpc = (Dwarf_Unsigned) (-1LL);       /* HACK */
    }

    /*  An empty location description (block length 0) means the code
        generator emitted no variable, the variable was not generated,
        it was unused or perhaps never tested after being set. Dwarf2,
        section 2.4.1 In other words, it is not an error, and we don't
        test for block length 0 specially here.
        See *dwarf_loclist_n() which handles the general case, this case
        handles only a single location expression.  */
    blkres = _dwarf_get_locdesc(dbg, &loc_block,
        address_size,
        cucontext->cc_length_size,
        cucontext->cc_version_stamp,
        lowpc, highpc,
        &locdesc,
        error);
    if (blkres != DW_DLV_OK) {
        /* low level error already set: let it be passed back */
        return blkres;
    }

    *llbuf = locdesc;
    *listlen = 1;
    return (DW_DLV_OK);
}
Beispiel #2
0
QVariant DwarfDie::attributeLocal(Dwarf_Half attributeType) const
{
    Dwarf_Attribute attr;
    auto res = dwarf_attr(m_die, attributeType, &attr, nullptr);
    if (res != DW_DLV_OK)
        return {};

    Dwarf_Half formType;
    res = dwarf_whatform(attr, &formType, nullptr);
    if (res != DW_DLV_OK)
        return {};

    QVariant value;
    switch (formType) {
        case DW_FORM_data1:
        case DW_FORM_data2:
        case DW_FORM_data4:
        case DW_FORM_data8:
        case DW_FORM_udata:
        {
            Dwarf_Unsigned n;
            res = dwarf_formudata(attr, &n, nullptr);
            value = n;
            break;
        }
        case DW_FORM_sdata:
        {
            Dwarf_Signed n;
            res = dwarf_formsdata(attr, &n, nullptr);
            value = n;
            break;
        }
        case DW_FORM_string:
        case DW_FORM_strp:
        {
            char *str;
            res = dwarf_formstring(attr, &str, nullptr);
            value = QByteArray(str);
            break;
        }
        case DW_FORM_flag:
        case DW_FORM_flag_present:
        {
            Dwarf_Bool b;
            res = dwarf_formflag(attr, &b, nullptr);
            value = b ? true : false;
            break;
        }
        case DW_FORM_ref1:
        case DW_FORM_ref2:
        case DW_FORM_ref4:
        case DW_FORM_ref8:
        {
            Dwarf_Off offset;
            res = dwarf_global_formref(attr, &offset, nullptr);
            value = QVariant::fromValue(dwarfInfo()->dieAtOffset(offset));
            break;
        }
        case DW_FORM_sec_offset:
        {
            Dwarf_Off offset;
            res = dwarf_global_formref(attr, &offset, nullptr);
            value = offset;
            break;
        }
        case DW_FORM_addr:
        {
            Dwarf_Addr addr;
            res = dwarf_formaddr(attr, &addr, nullptr);
            value = addr;
            break;
        }
        case DW_FORM_exprloc:
        {
            Dwarf_Unsigned len;
            Dwarf_Ptr block;
            res = dwarf_formexprloc(attr, &len, &block, nullptr);
            value = QVariant::fromValue(DwarfExpression(block, len, dwarfInfo()->elfFile()->addressSize()));
            break;
        }
        default:
        {
            const char* formName;
            res = dwarf_get_FORM_name(formType, &formName);
            if (res != DW_DLV_OK)
                return {};
            value = QStringLiteral("TODO: ") + QString::fromLocal8Bit(formName);
            break;
        }
    }

    // post-process some well-known types
    switch (attributeType) {
        case DW_AT_decl_file:
        case DW_AT_call_file:
        {
            const auto fileIndex = value.value<Dwarf_Unsigned>();
            // index 0 means not present, TODO handle that
            value = compilationUnit()->sourceFileForIndex(fileIndex -1);
            break;
        }
        case DW_AT_ranges:
            value = QVariant::fromValue(DwarfRanges(this, value.toLongLong()));
            break;
        case DW_AT_accessibility:
            stringifyEnum(value, &dwarf_get_ACCESS_name);
            break;
        case DW_AT_language:
            stringifyEnum(value, &dwarf_get_LANG_name);
            break;
        case DW_AT_virtuality:
            value = QVariant::fromValue(static_cast<DwarfVirtuality>(value.toInt()));
            break;
        case DW_AT_visibility:
            stringifyEnum(value, &dwarf_get_VIS_name);
            break;
        case DW_AT_identifier_case:
            stringifyEnum(value, &dwarf_get_ID_name);
            break;
        case DW_AT_inline:
            stringifyEnum(value, &dwarf_get_INL_name);
            break;
        case DW_AT_encoding:
            stringifyEnum(value, &dwarf_get_ATE_name);
            break;
        case DW_AT_ordering:
            stringifyEnum(value, &dwarf_get_ORD_name);
            break;
        case DW_AT_calling_convention:
            stringifyEnum(value, &dwarf_get_CC_name);
            break;
        case DW_AT_discr_list:
            stringifyEnum(value, &dwarf_get_DSC_name);
            break;
        default:
            break;
    }

    return value;
}
Beispiel #3
0
/*  Handles simple location entries and loclists.
    Returns all the Locdesc's thru llbuf.

    Will not work properly for DWARF5 and may not
    work for some recent versions of gcc or llvm emitting
    DWARF4 with location extensions.

    Does not work for .debug_loc.dwo

    Use dwarf_get_loclist_b() and associated functions.
*/
int
dwarf_loclist_n(Dwarf_Attribute attr,
    Dwarf_Locdesc *** llbuf_out,
    Dwarf_Signed * listlen_out, Dwarf_Error * error)
{
    Dwarf_Debug dbg;

    /*  Dwarf_Attribute that describes the DW_AT_location in die, if
        present. */
    Dwarf_Attribute loc_attr = attr;

    /* Dwarf_Block that describes a single location expression. */
    Dwarf_Block_c loc_block;

    /* A pointer to the current Dwarf_Locdesc read. */
    Dwarf_Locdesc *locdesc = 0;

    Dwarf_Half form = 0;
    Dwarf_Addr lowpc = 0;
    Dwarf_Addr highpc = 0;
    Dwarf_Signed listlen = 0;
    Dwarf_Locdesc **llbuf = 0;
    Dwarf_CU_Context cucontext = 0;
    unsigned address_size = 0;
    int cuvstamp = 0;
    Dwarf_Bool is_cu = FALSE;

    int blkres = DW_DLV_ERROR;
    int setup_res = DW_DLV_ERROR;

    /* ***** BEGIN CODE ***** */
    setup_res = _dwarf_setup_loc(attr, &dbg,&cucontext, &form, error);
    if (setup_res != DW_DLV_OK) {
        return setup_res;
    }
    cuvstamp = cucontext->cc_version_stamp;
    address_size = cucontext->cc_address_size;
    /*  If this is a form_block then it's a location expression. If it's
        DW_FORM_data4 or DW_FORM_data8  in DWARF2 or DWARF3
        (or in DWARF4 or 5 a DW_FORM_sec_offset) it's a loclist offset */
    if (cuvstamp == DW_CU_VERSION5) {
        /* Use a newer interface. */
        _dwarf_error(dbg, error, DW_DLE_LOCLIST_INTERFACE_ERROR);
        return (DW_DLV_ERROR);
    }
    if (((cuvstamp == DW_CU_VERSION2 || cuvstamp == DW_CU_VERSION3) &&
        (form == DW_FORM_data4 || form == DW_FORM_data8)) ||
        ((cuvstamp == DW_CU_VERSION4) && form == DW_FORM_sec_offset)) {

        setup_res = context_is_cu_not_tu(cucontext,&is_cu,error);
        if(setup_res != DW_DLV_OK) {
            return setup_res;
        }
        /*  A reference to .debug_loc, with an offset in .debug_loc of a
            loclist */
        Dwarf_Unsigned loclist_offset = 0;
        int off_res  = DW_DLV_ERROR;
        int count_res = DW_DLV_ERROR;
        int loclist_count = 0;
        int lli = 0;

        off_res = _dwarf_get_loclist_header_start(dbg,
            attr, &loclist_offset, error);
        if (off_res != DW_DLV_OK) {
            return off_res;
        }
        count_res = _dwarf_get_loclist_count(dbg, loclist_offset,
            address_size, &loclist_count, error);
        listlen = loclist_count;
        if (count_res != DW_DLV_OK) {
            return count_res;
        }
        if (loclist_count == 0) {
            return DW_DLV_NO_ENTRY;
        }

        llbuf = (Dwarf_Locdesc **)
            _dwarf_get_alloc(dbg, DW_DLA_LIST, loclist_count);
        if (!llbuf) {
            _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
            return (DW_DLV_ERROR);
        }

        for (lli = 0; lli < loclist_count; ++lli) {
            int lres = 0;
            blkres = _dwarf_read_loc_section(dbg, &loc_block,
                &lowpc,
                &highpc,
                loclist_offset,
                address_size,
                error);
            if (blkres != DW_DLV_OK) {
                _dwarf_cleanup_llbuf(dbg, llbuf, lli);
                return (blkres);
            }
            lres = _dwarf_get_locdesc(dbg, &loc_block,
                address_size,
                cucontext->cc_length_size,
                cucontext->cc_version_stamp,
                lowpc, highpc,
                &locdesc,
                error);
            if (lres != DW_DLV_OK) {
                _dwarf_cleanup_llbuf(dbg, llbuf, lli);
                /* low level error already set: let it be passed back */
                return lres;
            }
            llbuf[lli] = locdesc;

            /* Now get to next loclist entry offset. */
            loclist_offset = loc_block.bl_section_offset +
                loc_block.bl_len;
        }
    } else {
        if( form == DW_FORM_exprloc) {
            blkres = dwarf_formexprloc(loc_attr,&loc_block.bl_len,
                &loc_block.bl_data,error);
            if(blkres != DW_DLV_OK) {
                return blkres;
            }
            loc_block.bl_from_loclist = 0;
            loc_block.bl_section_offset  =
                (char *)loc_block.bl_data -
                (char *)dbg->de_debug_info.dss_data;
        } else {
            Dwarf_Block *tblock = 0;
            blkres = dwarf_formblock(loc_attr, &tblock, error);
            if (blkres != DW_DLV_OK) {
                return (blkres);
            }
            loc_block.bl_len = tblock->bl_len;;
            loc_block.bl_data = tblock->bl_data;
            loc_block.bl_from_loclist = tblock->bl_from_loclist;
            loc_block.bl_section_offset = tblock->bl_section_offset;
            loc_block.bl_locdesc_offset = 0; /* not relevent */
            /*  We copied tblock contents to the stack var, so can dealloc
                tblock now.  Avoids leaks. */
            dwarf_dealloc(dbg, tblock, DW_DLA_BLOCK);
        }
        listlen = 1; /* One by definition of a location entry. */
        lowpc = 0;   /* HACK */
        highpc = (Dwarf_Unsigned) (-1LL); /* HACK */

        /*  An empty location description (block length 0) means the
            code generator emitted no variable, the variable was not
            generated, it was unused or perhaps never tested after being
            set. Dwarf2, section 2.4.1 In other words, it is not an
            error, and we don't test for block length 0 specially here. */
        blkres = _dwarf_get_locdesc(dbg, &loc_block,
            address_size,
            cucontext->cc_length_size,
            cucontext->cc_version_stamp,
            lowpc, highpc,
            &locdesc,
            error);
        if (blkres != DW_DLV_OK) {
            /* low level error already set: let it be passed back */
            return blkres;
        }
        llbuf = (Dwarf_Locdesc **)
            _dwarf_get_alloc(dbg, DW_DLA_LIST, listlen);
        if (!llbuf) {
            /* Free the locdesc we allocated but won't use. */
            dwarf_dealloc(dbg, locdesc, DW_DLA_LOCDESC);
            _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
            return (DW_DLV_ERROR);
        }
        llbuf[0] = locdesc;
    }

    *llbuf_out = llbuf;
    *listlen_out = listlen;
    return (DW_DLV_OK);
}
Beispiel #4
0
/*  New October 2015
    This interface requires the use of interface functions
    to get data from Dwarf_Locdesc_c.  The structures
    are not visible to callers. */
int
dwarf_get_loclist_c(Dwarf_Attribute attr,
    Dwarf_Loc_Head_c * ll_header_out,
    Dwarf_Unsigned    * listlen_out,
    Dwarf_Error     * error)
{
    Dwarf_Debug dbg;

    /*  Dwarf_Attribute that describes the DW_AT_location in die, if
        present. */
    Dwarf_Attribute loc_attr = attr;

    /* Dwarf_Block that describes a single location expression. */
    Dwarf_Block_c loc_block;

    Dwarf_Half form = 0;
    Dwarf_Addr lowpc = 0;
    Dwarf_Addr highpc = 0;
    Dwarf_Unsigned     listlen = 0;
    Dwarf_Locdesc_c  llbuf = 0;
    Dwarf_Loc_Head_c llhead = 0;
    Dwarf_CU_Context cucontext = 0;
    unsigned address_size = 0;
    int cuvstamp = 0;
    Dwarf_Bool is_cu = FALSE;

    int blkres = DW_DLV_ERROR;
    int setup_res = DW_DLV_ERROR;

    /* ***** BEGIN CODE ***** */
    setup_res = _dwarf_setup_loc(attr, &dbg,&cucontext, &form, error);
    if (setup_res != DW_DLV_OK) {
        return setup_res;
    }
    cuvstamp = cucontext->cc_version_stamp;
    address_size = cucontext->cc_address_size;
    /*  If this is a form_block then it's a location expression. If it's
        DW_FORM_data4 or DW_FORM_data8  in DWARF2 or DWARF3
        (or in DWARF4 or 5 a DW_FORM_sec_offset) it's a loclist offset */
    if (((cuvstamp == DW_CU_VERSION2 || cuvstamp == DW_CU_VERSION3) &&
        (form == DW_FORM_data4 || form == DW_FORM_data8)) ||
        ((cuvstamp == DW_CU_VERSION4 || cuvstamp == DW_CU_VERSION5) &&
        form == DW_FORM_sec_offset)) {
        /* Here we have a loclist to deal with. */
        setup_res = context_is_cu_not_tu(cucontext,&is_cu,error);
        if(setup_res != DW_DLV_OK) {
            return setup_res;
        }
        if (cucontext->cc_is_dwo) {
            /*  dwo loclist. If this were a skeleton CU
                (ie, in the base, not dwo/dwp) then
                it could not have a loclist.  */
            /*  A reference to .debug_loc.dwo, with an offset
                in .debug_loc.dwo of a loclist */
            Dwarf_Unsigned loclist_offset = 0;
            int off_res  = DW_DLV_ERROR;
            int count_res = DW_DLV_ERROR;
            int loclist_count = 0;
            Dwarf_Unsigned lli = 0;

            off_res = _dwarf_get_loclist_header_start(dbg,
                attr, &loclist_offset, error);
            if (off_res != DW_DLV_OK) {
                return off_res;
            }
            count_res = _dwarf_get_loclist_count_dwo(dbg, loclist_offset,
                address_size, &loclist_count, error);
            if (count_res != DW_DLV_OK) {
                return count_res;
            }
            listlen = loclist_count;
            if (loclist_count == 0) {
                return DW_DLV_NO_ENTRY;
            }

            llhead = (Dwarf_Loc_Head_c)_dwarf_get_alloc(dbg,
                DW_DLA_LOC_HEAD_C, 1);
            if (!llhead) {
                _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
                return (DW_DLV_ERROR);
            }
            listlen = loclist_count;
            llbuf = (Dwarf_Locdesc_c)
                _dwarf_get_alloc(dbg, DW_DLA_LOCDESC_C, listlen);
            if (!llbuf) {
                dwarf_loc_head_c_dealloc(llhead);
                _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
                return (DW_DLV_ERROR);
            }
            llhead->ll_locdesc = llbuf;
            llhead->ll_locdesc_count = listlen;
            llhead->ll_from_loclist = 2;
            llhead->ll_context = cucontext;
            llhead->ll_dbg = dbg;

            /* New get loc ops, DWO version */
            for (lli = 0; lli < listlen; ++lli) {
                int lres = 0;
                Dwarf_Half lle_op = 0;
                Dwarf_Bool at_end = 0;

                blkres = _dwarf_read_loc_section_dwo(dbg, &loc_block,
                    &lowpc,
                    &highpc,
                    &at_end,
                    &lle_op,
                    loclist_offset,
                    address_size,
                    error);
                if (blkres != DW_DLV_OK) {
                    dwarf_loc_head_c_dealloc(llhead);
                    return blkres;
                }
                /* Fills in the locdesc at index lli */
                lres = _dwarf_get_locdesc_c(dbg,
                    lli,
                    llhead,
                    &loc_block,
                    address_size,
                    cucontext->cc_length_size,
                    cucontext->cc_version_stamp,
                    lowpc,
                    highpc,
                    error);
                if (lres != DW_DLV_OK) {
                    dwarf_loc_head_c_dealloc(llhead);
                    /* low level error already set: let it be passed back */
                    return lres;
                }
                /*  Override the syntesized lle value with the
                    real one. */
                llhead->ll_locdesc[lli].ld_lle_value = lle_op;

                /* Now get to next loclist entry offset. */
                loclist_offset = loc_block.bl_section_offset +
                    loc_block.bl_len;
            }
        } else {
            /*  Non-dwo loclist. If this were a skeleton CU
                (ie, in the base, not dwo/dwp) then
                it could not have a loclist.  */
            /*  A reference to .debug_loc, with an offset
                in .debug_loc of a loclist */
            Dwarf_Unsigned loclist_offset = 0;
            int off_res  = DW_DLV_ERROR;
            int count_res = DW_DLV_ERROR;
            int loclist_count = 0;
            Dwarf_Unsigned lli = 0;

            off_res = _dwarf_get_loclist_header_start(dbg,
                attr, &loclist_offset, error);
            if (off_res != DW_DLV_OK) {
                return off_res;
            }
            count_res = _dwarf_get_loclist_count(dbg, loclist_offset,
                address_size, &loclist_count, error);
            listlen = loclist_count;
            if (count_res != DW_DLV_OK) {
                return count_res;
            }
            if (loclist_count == 0) {
                return DW_DLV_NO_ENTRY;
            }
            llhead = (Dwarf_Loc_Head_c)_dwarf_get_alloc(dbg,
                DW_DLA_LOC_HEAD_C, 1);
            if (!llhead) {
                _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
                return (DW_DLV_ERROR);
            }
            listlen = loclist_count;
            llbuf = (Dwarf_Locdesc_c)
                _dwarf_get_alloc(dbg, DW_DLA_LOCDESC_C, listlen);
            if (!llbuf) {
                dwarf_loc_head_c_dealloc(llhead);
                _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
                return (DW_DLV_ERROR);
            }
            llhead->ll_locdesc = llbuf;
            llhead->ll_locdesc_count = listlen;
            llhead->ll_from_loclist = 1;
            llhead->ll_context = cucontext;
            llhead->ll_dbg = dbg;

            /* New locdesc and Loc,  non-DWO, so old format */
            for (lli = 0; lli < listlen; ++lli) {
                int lres = 0;
                Dwarf_Block_c c;
                blkres = _dwarf_read_loc_section(dbg, &c,
                    &lowpc,
                    &highpc,
                    loclist_offset,
                    address_size,
                    error);
                if (blkres != DW_DLV_OK) {
                    dwarf_loc_head_c_dealloc(llhead);
                    return (blkres);
                }
                loc_block.bl_len = c.bl_len;
                loc_block.bl_data = c.bl_data;
                loc_block.bl_from_loclist = c.bl_from_loclist;
                loc_block.bl_section_offset = c.bl_section_offset;
                loc_block.bl_locdesc_offset = loclist_offset;

                /* Fills in the locdesc at index lli */
                lres = _dwarf_get_locdesc_c(dbg,
                    lli,
                    llhead,
                    &loc_block,
                    address_size,
                    cucontext->cc_length_size,
                    cucontext->cc_version_stamp,
                    lowpc, highpc,
                    error);
                if (lres != DW_DLV_OK) {
                    dwarf_loc_head_c_dealloc(llhead);
                    /*  low level error already set:
                        let it be passed back */
                    return lres;
                }

                /* Now get to next loclist entry offset. */
                loclist_offset = loc_block.bl_section_offset +
                    loc_block.bl_len;
            }
        }
    } else {
        llhead = (Dwarf_Loc_Head_c)
            _dwarf_get_alloc(dbg, DW_DLA_LOC_HEAD_C, 1);
        if (!llhead) {
            _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
            return (DW_DLV_ERROR);
        }
        if( form == DW_FORM_exprloc) {
            blkres = dwarf_formexprloc(loc_attr,&loc_block.bl_len,
                &loc_block.bl_data,error);
            if(blkres != DW_DLV_OK) {
                dwarf_loc_head_c_dealloc(llhead);
                return blkres;
            }
            loc_block.bl_from_loclist = 0;
            loc_block.bl_section_offset  =
                (char *)loc_block.bl_data -
                (char *)dbg->de_debug_info.dss_data;
            loc_block.bl_locdesc_offset = 0; /* not relevant */
        } else {
            Dwarf_Block *tblock = 0;
            blkres = dwarf_formblock(loc_attr, &tblock, error);
            if (blkres != DW_DLV_OK) {
                dwarf_loc_head_c_dealloc(llhead);
                return (blkres);
            }
            loc_block.bl_len = tblock->bl_len;
            loc_block.bl_data = tblock->bl_data;
            loc_block.bl_from_loclist = tblock->bl_from_loclist;
            loc_block.bl_section_offset = tblock->bl_section_offset;
            loc_block.bl_locdesc_offset = 0; /* not relevant */
            /*  We copied tblock contents to the stack var, so can dealloc
                tblock now.  Avoids leaks. */
            dwarf_dealloc(dbg, tblock, DW_DLA_BLOCK);
        }
        listlen = 1; /* One by definition of a location entry. */
        /*  This hack ensures that the Locdesc_c
            is marked DW_LLE_start_end_entry */
        lowpc = 0;   /* HACK */
        highpc = (Dwarf_Unsigned) (-1LL); /* HACK */

        llbuf = (Dwarf_Locdesc_c)
            _dwarf_get_alloc(dbg, DW_DLA_LOCDESC_C, listlen);
        if (!llbuf) {
            dwarf_loc_head_c_dealloc(llhead);
            _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
            return (DW_DLV_ERROR);
        }
        llhead->ll_locdesc = llbuf;
        llhead->ll_locdesc = llbuf;
        llhead->ll_locdesc_count = listlen;
        llhead->ll_from_loclist = 0;
        llhead->ll_context = cucontext;
        llhead->ll_dbg = dbg;

        /*  An empty location description (block length 0) means the
            code generator emitted no variable, the variable was not
            generated, it was unused or perhaps never tested after being
            set. Dwarf2, section 2.4.1 In other words, it is not an
            error, and we don't test for block length 0 specially here. */
        /* Fills in the locdesc at index 0 */
        blkres = _dwarf_get_locdesc_c(dbg,
            0, /* fake locdesc is index 0 */
            llhead,
            &loc_block,
            address_size,
            cucontext->cc_length_size,
            cucontext->cc_version_stamp,
            lowpc, highpc,
            error);
        if (blkres != DW_DLV_OK) {
            dwarf_loc_head_c_dealloc(llhead);
            /* low level error already set: let it be passed back */
            return blkres;
        }
    }
    *ll_header_out = llhead;
    *listlen_out = listlen;
    return (DW_DLV_OK);
}