コード例 #1
0
ファイル: dwarf_loc.c プロジェクト: TEDYUN01/libdwarf
static int
_dwarf_get_loclist_count(Dwarf_Debug dbg,
    Dwarf_Off loclist_offset,
    Dwarf_Half address_size,
    int *loclist_count, Dwarf_Error * error)
{
    int count = 0;
    Dwarf_Off offset = loclist_offset;


    for (;;) {
        Dwarf_Block_c b;
        Dwarf_Addr lowpc;
        Dwarf_Addr highpc;
        int res = _dwarf_read_loc_section(dbg, &b,
            &lowpc, &highpc,
            offset, address_size,error);
        if (res != DW_DLV_OK) {
            return res;
        }
        offset = b.bl_len + b.bl_section_offset;
        if (lowpc == 0 && highpc == 0) {
            break;
        }
        count++;
    }
    *loclist_count = count;
    return DW_DLV_OK;
}
コード例 #2
0
ファイル: dwarf_loc.c プロジェクト: TEDYUN01/libdwarf
/*ARGSUSED*/ int
dwarf_get_loclist_entry(Dwarf_Debug dbg,
    Dwarf_Unsigned offset,
    Dwarf_Addr * hipc_offset,
    Dwarf_Addr * lopc_offset,
    Dwarf_Ptr * data,
    Dwarf_Unsigned * entry_len,
    Dwarf_Unsigned * next_entry,
    Dwarf_Error * error)
{
    Dwarf_Block_c b;
    Dwarf_Addr lowpc = 0;
    Dwarf_Addr highpc = 0;
    Dwarf_Half address_size = 0;
    int res = DW_DLV_ERROR;

    if (!dbg->de_debug_loc.dss_data) {
        int secload = _dwarf_load_section(dbg, &dbg->de_debug_loc,error);
        if (secload != DW_DLV_OK) {
            return secload;
        }
    }

    /* FIXME: address_size is not necessarily the same in every frame. */
    address_size = dbg->de_pointer_size;
    res = _dwarf_read_loc_section(dbg,
        &b, &lowpc, &highpc, offset,
        address_size,error);
    if (res != DW_DLV_OK) {
        return res;
    }
    *hipc_offset = highpc;
    *lopc_offset = lowpc;
    *entry_len = b.bl_len;
    *data = b.bl_data;
    *next_entry = b.bl_len + b.bl_section_offset;
    return DW_DLV_OK;
}
コード例 #3
0
ファイル: dwarf_loc.c プロジェクト: TEDYUN01/libdwarf
/*  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);
}
コード例 #4
0
ファイル: dwarf_loc.c プロジェクト: TEDYUN01/libdwarf
/*  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);
}
コード例 #5
0
ファイル: dwarf_loc2.c プロジェクト: jrfonseca/drmingw
/*  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);
}