/*
  Copyright (C) 2000-2004 Silicon Graphics, Inc.  All Rights Reserved.
  Portions Copyright (C) 2007-2018 David Anderson. All Rights Reserved.
  Portions Copyright (C) 2010-2012 SN Systems Ltd. All Rights Reserved.

  This program is free software; you can redistribute it
  and/or modify it under the terms of version 2.1 of the
  GNU Lesser General Public License as published by the Free
  Software Foundation.

  This program is distributed in the hope that it would be
  useful, but WITHOUT ANY WARRANTY; without even the implied
  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
  PURPOSE.

  Further, this software is distributed without any warranty
  that it is free of the rightful claim of any third person
  regarding infringement or the like.  Any license provided
  herein, whether implied or otherwise, applies only to this
  software file.  Patent licenses, if any, provided herein
  do not apply to combinations of this program with other
  software, or any other product whatsoever.

  You should have received a copy of the GNU Lesser General
  Public License along with this program; if not, write the
  Free Software Foundation, Inc., 51 Franklin Street - Fifth
  Floor, Boston MA 02110-1301, USA.

*/

#include "config.h"
#include <stdio.h> /* for debugging only. */
#ifdef HAVE_STDINT_H
#include <stdint.h> /* For uintptr_t */
#endif /* HAVE_STDINT_H */
#ifdef HAVE_STDLIB_H
#include <stdlib.h> /* For uintptr_t */
#endif /* HAVE_STDLIB_H */
#include "dwarf_incl.h"
#include "dwarf_alloc.h"
#include "dwarf_error.h"
#include "dwarf_util.h"
#include "dwarf_loc.h"
#include "dwarfstring.h"

#define TRUE 1
#define FALSE 0

static int _dwarf_read_loc_section_dwo(Dwarf_Debug dbg,
   Dwarf_Block_c * return_block,
   Dwarf_Addr * lowpc,
   Dwarf_Addr * highpc,
   Dwarf_Bool * at_end,
   Dwarf_Half * lle_op,
   Dwarf_Off    sec_offset,
   Dwarf_Half   address_size,
   Dwarf_Half   lkind,
   Dwarf_Error *error);


/*  Used to enable sanity checking of these data items before we return
    to caller. */
int
_dwarf_locdesc_c_constructor(Dwarf_Debug dbg, void *locd)
{
    Dwarf_Locdesc_c  ldp = (Dwarf_Locdesc_c)locd;

    if (!dbg) {
        return DW_DLV_ERROR;
    }
    ldp->ld_lle_value = DW_LLE_VALUE_BOGUS;
    ldp->ld_kind = DW_LKIND_unknown;
    return DW_DLV_OK;
}

static void
_dwarf_lkind_name(unsigned lkind, dwarfstring *m)
{
    switch(lkind) {
    case DW_LKIND_expression:
        dwarfstring_append(m,"DW_LKIND_expression");
        return;
    case DW_LKIND_loclist:
        dwarfstring_append(m,"DW_LKIND_loclist");
        return;
    case DW_LKIND_GNU_exp_list:
        dwarfstring_append(m,"DW_LKIND_GNU_exp_list");
        return;
    case DW_LKIND_loclists:
        dwarfstring_append(m,"DW_LKIND_loclists");
        return;
    case DW_LKIND_unknown:
        dwarfstring_append(m,"DW_LKIND_unknown");
        return;
    }
    dwarfstring_append_printf_u(m,
        "<DW_LKIND location kind is unknown and has value %u>.",
        lkind);
}


static int
determine_location_lkind(unsigned int version,
    unsigned int form,
    UNUSEDARG unsigned int attribute,
    Dwarf_Bool is_dwo)
{
    switch(form) {
    case DW_FORM_exprloc: /* only defined for
        DW_CFA_def_cfa_expression */
    case DW_FORM_block:
    case DW_FORM_block1:
    case DW_FORM_block2:
    case DW_FORM_block4:
        return DW_LKIND_expression;
        break;
    case DW_FORM_data4:
    case DW_FORM_data8:
        if (version > 1 && version < 4) {
            return DW_LKIND_loclist;
        }
        break;
    case DW_FORM_sec_offset:
        if (version == 5 ) {
            return DW_LKIND_loclists;
        }
        if (version == 4 &&  is_dwo  ) {
            return DW_LKIND_GNU_exp_list;
        }
        return DW_LKIND_loclist;
        break;
    case DW_FORM_loclistx:
        if (version == 5 ) {
            return DW_LKIND_loclists;
        }
        break;
    default:
        break;
    }
    return DW_LKIND_unknown;
}

static void
_dwarf_free_op_chain(Dwarf_Debug dbg,
    Dwarf_Loc_Chain headloc)
{
    Dwarf_Loc_Chain cur = headloc;

    while (cur) {
        Dwarf_Loc_Chain next = cur->lc_next;
        dwarf_dealloc(dbg, cur, DW_DLA_LOC_CHAIN);
        cur = next;
    }
}
/*  Given a Dwarf_Block that represents a location expression,
    this function returns a pointer to a Dwarf_Locdesc struct
    that has its ld_cents field set to the number of location
    operators in the block, and its ld_s field pointing to a
    contiguous block of Dwarf_Loc structs.  However, the
    ld_lopc and ld_hipc values are uninitialized.  Returns
    DW_DLV_ERROR on error.

    Created for DWARF2 this really does not work well
    as later DWARF needs the newer interface.
    You want Dwarf_Locdesc_c opaque struct, not what this
    function provides.

    This function assumes that the length of
    the block is greater than 0.  Zero length location expressions
    to represent variables that have been optimized away are
    handled in the calling function.

    address_size, offset_size, and version_stamp are
    per-CU, not per-object or per dbg.
    We cannot use dbg directly to get those values.

    Use for DWARF 2,3,4 only to avoid updating to
    later interfaces. Not for experimental
    dwarf4 dwo either.
    Better to switch to a newer interface.
*/
static int
_dwarf_get_locdesc(Dwarf_Debug dbg,
    Dwarf_Block_c * loc_block,
    Dwarf_Half address_size,
    Dwarf_Half offset_size,
    Dwarf_Small version_stamp,
    Dwarf_Addr lowpc,
    Dwarf_Addr highpc,
    Dwarf_Small * section_end,
    Dwarf_Locdesc ** locdesc_out,
    Dwarf_Error * error)
{
    /* Offset of current operator from start of block. */
    Dwarf_Unsigned offset = 0;

    /* Used to chain the Dwarf_Loc_Chain_s structs. */
    Dwarf_Loc_Chain new_loc = NULL;
    Dwarf_Loc_Chain prev_loc = NULL;
    Dwarf_Loc_Chain head_loc = NULL;
    /* Count of the number of location operators. */
    Dwarf_Unsigned op_count = 0;

    /* Contiguous block of Dwarf_Loc's for Dwarf_Locdesc. */
    Dwarf_Loc *block_loc = 0;

    /* Dwarf_Locdesc pointer to be returned. */
    Dwarf_Locdesc *locdesc = 0;

    Dwarf_Unsigned i = 0;
    int res = 0;

    /* ***** BEGIN CODE ***** */

    offset = 0;
    op_count = 0;


    res = _dwarf_loc_block_sanity_check(dbg,loc_block,error);
    if (res != DW_DLV_OK) {
        return res;
    }

    /* OLD loop getting Loc operators. No DWARF5 */
    while (offset <= loc_block->bl_len) {
        Dwarf_Unsigned nextoffset = 0;
        struct Dwarf_Loc_Expr_Op_s temp_loc;

        res = _dwarf_read_loc_expr_op(dbg,loc_block,
            op_count,
            version_stamp,
            offset_size,
            address_size,
            offset,
            section_end,
            &nextoffset,
            &temp_loc,
            error);
        if (res == DW_DLV_ERROR) {
            _dwarf_free_op_chain(dbg, head_loc);
            return res;
        }
        if (res == DW_DLV_NO_ENTRY) {
            /* Normal end. */
            break;
        }
        op_count++;
        new_loc =
            (Dwarf_Loc_Chain) _dwarf_get_alloc(dbg,
            DW_DLA_LOC_CHAIN, 1);
        if (new_loc == NULL) {
            dwarfstring m;

            _dwarf_free_op_chain(dbg, head_loc);
            dwarfstring_constructor(&m);
            dwarfstring_append_printf_u(&m,
                " DW_DLE_ALLOC_FAIL: out of memory"
                "  allocating location"
                " expression operator chain entry %u.",
                op_count);
            _dwarf_error_string(dbg, error, DW_DLE_ALLOC_FAIL,
                dwarfstring_string(&m));
            dwarfstring_destructor(&m);
            return DW_DLV_ERROR;
        }

        /* Copying only the fields needed by DWARF 2,3,4 */
        new_loc->lc_atom    = temp_loc.lr_atom;
        new_loc->lc_opnumber= temp_loc.lr_opnumber;
        new_loc->lc_number  = temp_loc.lr_number;
        new_loc->lc_number2 = temp_loc.lr_number2;
        new_loc->lc_number3 = temp_loc.lr_number3;
        new_loc->lc_raw1  = temp_loc.lr_raw1;
        new_loc->lc_raw2  = temp_loc.lr_raw2;
        new_loc->lc_raw3  = temp_loc.lr_raw3;
        new_loc->lc_offset  = temp_loc.lr_offset;
        offset = nextoffset;

        if (head_loc == NULL)
            head_loc = prev_loc = new_loc;
        else {
            prev_loc->lc_next = new_loc;
            prev_loc = new_loc;
        }
    }

    block_loc =
        (Dwarf_Loc *) _dwarf_get_alloc(dbg, DW_DLA_LOC_BLOCK,
        op_count);
    if (block_loc == NULL) {
        _dwarf_free_op_chain(dbg, head_loc);
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return DW_DLV_ERROR;
    }

    new_loc = head_loc;
    for (i = 0; i < op_count; i++) {
        /*  Copying only the fields needed by DWARF 2,3,4
            the struct is public and must never be changed. */
        (block_loc + i)->lr_atom = new_loc->lc_atom;
        (block_loc + i)->lr_number = new_loc->lc_number;
        (block_loc + i)->lr_number2 = new_loc->lc_number2;
        (block_loc + i)->lr_offset = new_loc->lc_offset;
        prev_loc = new_loc;
        new_loc = prev_loc->lc_next;
        dwarf_dealloc(dbg, prev_loc, DW_DLA_LOC_CHAIN);
    }

    locdesc =
        (Dwarf_Locdesc *) _dwarf_get_alloc(dbg, DW_DLA_LOCDESC, 1);
    if (locdesc == NULL) {
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return DW_DLV_ERROR;
    }

    locdesc->ld_cents = op_count;
    locdesc->ld_s = block_loc;
    locdesc->ld_section_offset = loc_block->bl_section_offset;
    locdesc->ld_lopc = lowpc;
    locdesc->ld_hipc = highpc;
    locdesc->ld_from_loclist = 1;
    *locdesc_out = locdesc;
    return DW_DLV_OK;
}

/*  Using a loclist offset to get the in-memory
    address of .debug_loc data to read, returns the loclist
    'header' info in return_block.
*/

#define MAX_ADDR ((address_size == 8)?0xffffffffffffffffULL:0xffffffff)


static int
_dwarf_read_loc_section(Dwarf_Debug dbg,
    Dwarf_Block_c * return_block,
    Dwarf_Addr    * lowpc,
    Dwarf_Addr    * hipc,
    Dwarf_Half    * lle_val,
    Dwarf_Off       sec_offset,
    Dwarf_Half      address_size,
    UNUSEDARG unsigned   lkind,
    Dwarf_Error   * error)
{
    Dwarf_Small *beg = dbg->de_debug_loc.dss_data + sec_offset;
    Dwarf_Small *loc_section_end =
        dbg->de_debug_loc.dss_data + dbg->de_debug_loc.dss_size;

    /*  start_addr and end_addr are actually offsets
        of the applicable base address of the CU.
        They are address-size. */
    Dwarf_Addr start_addr = 0;
    Dwarf_Addr end_addr = 0;
    Dwarf_Half exprblock_size = 0;
    Dwarf_Unsigned exprblock_off =
        2 * address_size + DWARF_HALF_SIZE;

    if (sec_offset >= dbg->de_debug_loc.dss_size) {
        /* We're at the end. No more present. */
        return DW_DLV_NO_ENTRY;
    }

    /* If it goes past end, error */
    if (exprblock_off > dbg->de_debug_loc.dss_size) {
        _dwarf_error(dbg, error, DW_DLE_DEBUG_LOC_SECTION_SHORT);
        return DW_DLV_ERROR;
    }


    READ_UNALIGNED_CK(dbg, start_addr, Dwarf_Addr, beg, address_size,
        error,loc_section_end);
    READ_UNALIGNED_CK(dbg, end_addr, Dwarf_Addr,
        beg + address_size, address_size,
        error,loc_section_end);
    if (start_addr == 0 && end_addr == 0) {
        /*  If start_addr and end_addr are 0, it's the end and no
            exprblock_size field follows. */
        exprblock_size = 0;
        exprblock_off -= DWARF_HALF_SIZE;
        *lle_val = DW_LLE_end_of_list;
    } else if (start_addr == MAX_ADDR) {
        /*  End address is a base address, no exprblock_size field here
            either */
        exprblock_size = 0;
        exprblock_off -=  DWARF_HALF_SIZE;
        *lle_val = DW_LLE_base_address;
    } else {
        /*  Here we note the address and length of the
            expression operators, DW_OP_reg0 etc */
        READ_UNALIGNED_CK(dbg, exprblock_size, Dwarf_Half,
            beg + 2 * address_size, DWARF_HALF_SIZE,
            error,loc_section_end);
        /* exprblock_size can be zero, means no expression */
        if ( exprblock_size >= dbg->de_debug_loc.dss_size) {
            _dwarf_error(dbg, error, DW_DLE_DEBUG_LOC_SECTION_SHORT);
            return DW_DLV_ERROR;
        }
        if ((sec_offset +exprblock_off + exprblock_size) >
            dbg->de_debug_loc.dss_size) {
            _dwarf_error(dbg, error, DW_DLE_DEBUG_LOC_SECTION_SHORT);
            return DW_DLV_ERROR;
        }
        *lle_val = DW_LLE_start_end;
    }
    *lowpc = start_addr;
    *hipc = end_addr;

    return_block->bl_len = exprblock_size;
    return_block->bl_kind = DW_LKIND_loclist;
    return_block->bl_data = beg + exprblock_off;
    return_block->bl_section_offset =
        ((Dwarf_Small *) return_block->bl_data) -
        dbg->de_debug_loc.dss_data;
    return DW_DLV_OK;
}

static int
_dwarf_get_loclist_lle_count_dwo(Dwarf_Debug dbg,
    Dwarf_Off loclist_offset,
    Dwarf_Half address_size,
    unsigned lkind,
    int *loclist_count,
    Dwarf_Error * error)
{
    int count = 0;
    Dwarf_Off offset = loclist_offset;

    for (;;) {
        Dwarf_Block_c b;
        Dwarf_Bool at_end = FALSE;
        Dwarf_Addr lowpc = 0;
        Dwarf_Addr highpc = 0;
        Dwarf_Half lle_op = 0;
        int res = _dwarf_read_loc_section_dwo(dbg, &b,
            &lowpc,
            &highpc,
            &at_end,
            &lle_op,
            offset,
            address_size,
            lkind,
            error);
        if (res != DW_DLV_OK) {
            return res;
        }
        if (at_end) {
            count++;
            break;
        }
        offset = b.bl_len + b.bl_section_offset;
        count++;
    }
    *loclist_count = count;
    return DW_DLV_OK;
}

static int
_dwarf_get_loclist_lle_count(Dwarf_Debug dbg,
    Dwarf_Off loclist_offset,
    Dwarf_Half address_size,
    unsigned lkind,
    int *loclist_count,
    Dwarf_Error * error)
{
    int count = 0;
    Dwarf_Off offset = loclist_offset;


    for (;;) {
        Dwarf_Block_c b;
        Dwarf_Addr lowpc = 0;
        Dwarf_Addr highpc = 0;
        Dwarf_Half lle_val = DW_LLE_VALUE_BOGUS;

        int res = _dwarf_read_loc_section(dbg, &b,
            &lowpc, &highpc,
            &lle_val,
            offset, address_size,lkind,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;
}

/* Helper routine to avoid code duplication.
*/
static int
_dwarf_setup_loc(Dwarf_Attribute attr,
    Dwarf_Debug *     dbg_ret,
    Dwarf_CU_Context *cucontext_ret,
    Dwarf_Half       *form_ret,
    Dwarf_Error      *error)
{
    Dwarf_Debug dbg = 0;
    Dwarf_Half form = 0;
    int blkres = DW_DLV_ERROR;

    /*  Creating an error with NULL dbg is not a good thing.
        These won't be freed if we later call dealloc
        with a non-NULL dbg.
    */
    if (!attr) {
        _dwarf_error(NULL, error, DW_DLE_ATTR_NULL);
        return DW_DLV_ERROR;
    }
    if (attr->ar_cu_context == NULL) {
        _dwarf_error(NULL, error, DW_DLE_ATTR_NO_CU_CONTEXT);
        return DW_DLV_ERROR;
    }
    *cucontext_ret = attr->ar_cu_context;

    dbg = attr->ar_cu_context->cc_dbg;
    if (dbg == NULL) {
        _dwarf_error(NULL, error, DW_DLE_ATTR_DBG_NULL);
        return DW_DLV_ERROR;
    }
    *dbg_ret = dbg;
    blkres = dwarf_whatform(attr, &form, error);
    if (blkres != DW_DLV_OK) {
        return blkres;
    }
    *form_ret = form;
    return DW_DLV_OK;
}

/* Helper routine  to avoid code duplication.
*/
static int
_dwarf_get_loclist_header_start(Dwarf_Debug dbg,
    Dwarf_Attribute attr,
    Dwarf_Unsigned * loclist_offset_out,
    Dwarf_Error * error)
{
    Dwarf_Unsigned loc_sec_size = 0;
    Dwarf_Unsigned loclist_offset = 0;

    int blkres = dwarf_global_formref(attr, &loclist_offset, error);
    if (blkres != DW_DLV_OK) {
        return blkres;
    }
    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;
        }
        if (!dbg->de_debug_loc.dss_size) {
            return (DW_DLV_NO_ENTRY);
        }
    }
    loc_sec_size = dbg->de_debug_loc.dss_size;
    if (loclist_offset >= loc_sec_size) {
        _dwarf_error(dbg, error, DW_DLE_LOCLIST_OFFSET_BAD);
        return DW_DLV_ERROR;
    }

    {
        int fisres = 0;
        Dwarf_Unsigned fissoff = 0;
        Dwarf_Unsigned size = 0;
        fisres = _dwarf_get_fission_addition_die(attr->ar_die,
            DW_SECT_LOCLISTS,
            &fissoff, &size,error);
        if(fisres != DW_DLV_OK) {
            return fisres;
        }
        if (fissoff >= loc_sec_size) {
            _dwarf_error(dbg, error, DW_DLE_LOCLIST_OFFSET_BAD);
            return DW_DLV_ERROR;
        }
        loclist_offset += fissoff;
        if  (loclist_offset >= loc_sec_size) {
            _dwarf_error(dbg, error, DW_DLE_LOCLIST_OFFSET_BAD);
            return DW_DLV_ERROR;
        }
    }
    *loclist_offset_out = loclist_offset;
    return DW_DLV_OK;
}

/* When llbuf (see dwarf_loclist_n) is partially set up
   and an error is encountered, tear it down as it
   won't be used.
*/
static void
_dwarf_cleanup_llbuf(Dwarf_Debug dbg, Dwarf_Locdesc ** llbuf, int count)
{
    int i;
    for (i = 0; i < count; ++i) {
        dwarf_dealloc(dbg, llbuf[i]->ld_s, DW_DLA_LOC_BLOCK);
        dwarf_dealloc(dbg, llbuf[i], DW_DLA_LOCDESC);
    }
    dwarf_dealloc(dbg, llbuf, DW_DLA_LIST);
}

static int
context_is_cu_not_tu(Dwarf_CU_Context context,
    Dwarf_Bool *r)
{
    int ut = context->cc_unit_type;

    if (ut == DW_UT_type || ut == DW_UT_split_type ) {
        *r =FALSE;
        return DW_DLV_OK;
    }
    *r = TRUE;
    return DW_DLV_OK;
}

/*  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
*/
int
dwarf_loclist_n(Dwarf_Attribute attr,
    Dwarf_Locdesc *** llbuf_out,
    Dwarf_Signed * listlen_out, Dwarf_Error * error)
{
    Dwarf_Debug dbg = 0;

    /*  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;
    Dwarf_Half attrnum = 0;
    int is_dwo = FALSE;
    unsigned lkind = 0;

    int blkres = DW_DLV_ERROR;
    int setup_res = DW_DLV_ERROR;
    Dwarf_Small * info_section_end = 0;

    /* ***** BEGIN CODE ***** */
    setup_res = _dwarf_setup_loc(attr, &dbg,&cucontext, &form, error);
    if (setup_res != DW_DLV_OK) {
        return setup_res;
    }
    info_section_end = _dwarf_calculate_info_section_end_ptr(cucontext);
    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);
    }
    attrnum = attr->ar_attribute;
    lkind =  determine_location_lkind(cuvstamp,form, attrnum, is_dwo);
    if (lkind == DW_LKIND_unknown ||
        lkind == DW_LKIND_GNU_exp_list ||
        lkind == DW_LKIND_loclists ) {
        /*  We cannot handle this here. */
        _dwarf_error(dbg, error, DW_DLE_LOCLIST_INTERFACE_ERROR);
        return (DW_DLV_ERROR);
    }

    if (lkind == DW_LKIND_loclist ) {
        /*  A reference to .debug_loc, with an offset in .debug_loc of a
            loclist */
        Dwarf_Small *loc_section_end = 0;
        Dwarf_Unsigned loclist_offset = 0;
        int off_res  = DW_DLV_ERROR;
        int count_res = DW_DLV_ERROR;
        int loclist_count = 0;
        int lli = 0;

        setup_res = context_is_cu_not_tu(cucontext,&is_cu);
        if(setup_res != DW_DLV_OK) {
            return setup_res;
        }

        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_lle_count(dbg, loclist_offset,
            address_size,lkind, &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;
            Dwarf_Half ll_op = 0;

            blkres = _dwarf_read_loc_section(dbg,
                &loc_block,
                &lowpc,
                &highpc,
                &ll_op,
                loclist_offset,
                address_size,lkind,
                error);
            if (blkres != DW_DLV_OK) {
                _dwarf_cleanup_llbuf(dbg, llbuf, lli);
                return (blkres);
            }
            loc_section_end = dbg->de_debug_loc.dss_data+
                dbg->de_debug_loc.dss_size;
            lres = _dwarf_get_locdesc(dbg,
                &loc_block,
                address_size,
                cucontext->cc_length_size,
                cucontext->cc_version_stamp,
                lowpc, highpc,
                loc_section_end,
                &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 { /* DW_LKIND_expression */
        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_kind = lkind;
            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_kind = lkind;
            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, but with bl_kind we do not need */
        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,
            info_section_end,
            &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);
}

/*  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 = 0;

    /*  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;
    int is_dwo             = FALSE;
    Dwarf_Small *info_section_end = 0;
    Dwarf_Half form        = 0;
    Dwarf_Addr lowpc       = 0;
    Dwarf_Addr highpc      = 0;
    Dwarf_CU_Context cucontext = 0;
    unsigned address_size  = 0;
    unsigned lkind         = 0;
    int blkres             = DW_DLV_ERROR;
    int setup_res          = DW_DLV_ERROR;
    int cuvstamp           = 0;
    unsigned attrnum       = 0;

    /* ***** BEGIN CODE ***** */
    setup_res = _dwarf_setup_loc(attr, &dbg, &cucontext, &form, error);
    if (setup_res != DW_DLV_OK) {
        return setup_res;
    }
    info_section_end = _dwarf_calculate_info_section_end_ptr(cucontext);
    memset(&loc_block,0,sizeof(loc_block));
    cuvstamp = cucontext->cc_version_stamp;
    address_size = cucontext->cc_address_size;
    attrnum = attr->ar_attribute;
    lkind =  determine_location_lkind(cuvstamp,form, attrnum, is_dwo);
    if (lkind == DW_LKIND_unknown ||
        lkind == DW_LKIND_GNU_exp_list ||
        lkind == DW_LKIND_loclists ) {
        /*  We cannot handle this here. */
        _dwarf_error(dbg, error, DW_DLE_LOCLIST_INTERFACE_ERROR);
        return (DW_DLV_ERROR);
    }

    /*  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 (lkind == DW_LKIND_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;
        Dwarf_Half  ll_op = 0;

        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,
            &ll_op,
            loclist_offset,
            address_size,
            lkind,
            error);
        if (blkres != DW_DLV_OK) {
            return (blkres);
        }
    } else { /* DW_LKIND_expression */
        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_kind = lkind;
            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_kind = tblock->bl_from_loclist;
            /* ASSERT: lkind == loc_block.bl_kind  */
            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);
        }
        /*  Because we set bl_kind we don't really
            need this hack any more */
        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,
        info_section_end, &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);
}



/*  Handles only a location expression.
    It returns the location expression as a loclist with
    a single entry.

    Usable to access dwarf expressions from any source, but
    specifically from
        DW_CFA_def_cfa_expression
        DW_CFA_expression
        DW_CFA_val_expression

    expression_in must point to a valid dwarf expression
    set of bytes of length expression_length. Not
    a DW_FORM_block*, just the expression bytes.

    If the address_size != de_pointer_size this will not work
    right.
    See dwarf_loclist_from_expr_b() for a better interface.
*/
int
dwarf_loclist_from_expr(Dwarf_Debug dbg,
    Dwarf_Ptr expression_in,
    Dwarf_Unsigned expression_length,
    Dwarf_Locdesc ** llbuf,
    Dwarf_Signed * listlen, Dwarf_Error * error)
{
    int res = 0;
    Dwarf_Half addr_size =  dbg->de_pointer_size;
    res = dwarf_loclist_from_expr_a(dbg,expression_in,
        expression_length, addr_size,llbuf,listlen,error);
    return res;
}

/*  New April 27 2009. Adding addr_size argument for the rare
    cases where an object has CUs with a different address_size.

    As of 2012 we have yet another version, dwarf_loclist_from_expr_b()
    with the version_stamp and offset size (length size) passed in.

    And later, dwarf_loclist_from_expr_c()
*/
int
dwarf_loclist_from_expr_a(Dwarf_Debug dbg,
    Dwarf_Ptr expression_in,
    Dwarf_Unsigned expression_length,
    Dwarf_Half addr_size,
    Dwarf_Locdesc ** llbuf,
    Dwarf_Signed * listlen,
    Dwarf_Error * error)
{
    int res;
    Dwarf_Debug_InfoTypes info_reading = &dbg->de_info_reading;
    Dwarf_CU_Context current_cu_context =
        info_reading->de_cu_context;
    Dwarf_Small version_stamp =  DW_CU_VERSION2;
    Dwarf_Half offset_size = dbg->de_length_size;

    if (current_cu_context) {
        /*  This is ugly. It is not necessarily right. Due to
            oddity in DW_OP_GNU_implicit_pointer, see its
            implementation above.
            For correctness, use dwarf_loclist_from_expr_b()
            instead of dwarf_loclist_from_expr_a(). */
        version_stamp = current_cu_context->cc_version_stamp;
        offset_size = current_cu_context->cc_length_size;
        if (version_stamp < 2) {
            /* This is probably totally silly.  */
            version_stamp = DW_CU_VERSION2;
        }
    }
    res = dwarf_loclist_from_expr_b(dbg,
        expression_in,
        expression_length,
        addr_size,
        offset_size,
        version_stamp, /* CU context DWARF version */
        llbuf,
        listlen,
        error);
    return res;
}
/*  New November 13 2012. Adding
    DWARF version number argument.
*/
int
dwarf_loclist_from_expr_b(Dwarf_Debug dbg,
    Dwarf_Ptr expression_in,
    Dwarf_Unsigned expression_length,
    Dwarf_Half addr_size,
    Dwarf_Half offset_size,
    Dwarf_Small dwarf_version,
    Dwarf_Locdesc ** llbuf,
    Dwarf_Signed * listlen,
    Dwarf_Error * error)
{
    /* 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_Addr lowpc = 0;
    Dwarf_Addr highpc = (Dwarf_Unsigned) (-1LL);
    Dwarf_Small version_stamp = dwarf_version;
    int res = 0;
    /* We do not know what the end is in this interface. */
    Dwarf_Small *section_start = 0;
    Dwarf_Unsigned section_size = 0;
    Dwarf_Small *section_end = 0;
    const char *section_name = 0;

    res = _dwarf_what_section_are_we(dbg,
        expression_in,&section_name,&section_start,
        &section_size,&section_end,error);
    if (res != DW_DLV_OK) {
        _dwarf_error(dbg, error,DW_DLE_POINTER_SECTION_UNKNOWN);
        return DW_DLV_ERROR;
    }

    memset(&loc_block,0,sizeof(loc_block));
    loc_block.bl_len = expression_length;
    loc_block.bl_data = expression_in;
    loc_block.bl_kind = DW_LKIND_expression;
    loc_block.bl_section_offset = 0; /* Fake. Not meaningful. */

    /* 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.  */
    /* We need the DWARF version to get a locdesc! */
    res = _dwarf_get_locdesc(dbg, &loc_block,
        addr_size,
        offset_size,
        version_stamp,
        lowpc, highpc,
        section_end,
        &locdesc,
        error);
    if (res != DW_DLV_OK) {
        /* low level error already set: let it be passed back */
        return res;
    }

    *llbuf = locdesc;
    *listlen = 1;
    return DW_DLV_OK;
}

/* Usable to read a single loclist or to read a block of them
   or to read an entire section's loclists.

   It's BROKEN because it's not safe to read a loclist entry
   when we do not know the address size (in any object where
   address size can vary by compilation unit).

   It also does not recognize split dwarf or DWARF4
   or DWARF5 adequately.

   Use get_locdesc_entry_c() instead.
*/
/*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;
    Dwarf_Half ll_op = 0;

    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: DO NOT USE the call. 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,
        &ll_op,offset,
        address_size,DW_LKIND_loclist,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;
}

/* ============== the October 2015 interfaces. */
int
_dwarf_loc_block_sanity_check(Dwarf_Debug dbg,
    Dwarf_Block_c *loc_block,Dwarf_Error* error)
{
    unsigned lkind = loc_block->bl_kind;
    if (lkind == DW_LKIND_loclist) {
        Dwarf_Small *loc_ptr = 0;
        Dwarf_Unsigned loc_len = 0;
        Dwarf_Small *end_ptr = 0;

        loc_ptr = loc_block->bl_data;
        loc_len = loc_block->bl_len;
        end_ptr =  dbg->de_debug_loc.dss_size +
            dbg->de_debug_loc.dss_data;
        if ((loc_ptr +loc_len) > end_ptr) {
            dwarfstring m;

            dwarfstring_constructor(&m);
            dwarfstring_append(&m,
                "DW_DLE_DEBUG_LOC_SECTION_SHORT kind: ");
            _dwarf_lkind_name(lkind, &m);
            _dwarf_error_string(dbg,error,
                DW_DLE_DEBUG_LOC_SECTION_SHORT,
                dwarfstring_string(&m));
            dwarfstring_destructor(&m);
            return DW_DLV_ERROR;
        }
        return DW_DLV_OK;
    }
    if (lkind == DW_LKIND_loclists) {
        Dwarf_Small *loc_ptr = 0;
        Dwarf_Unsigned loc_len = 0;
        Dwarf_Small *end_ptr = 0;

        loc_ptr = loc_block->bl_data;
        loc_len = loc_block->bl_len;
        end_ptr =  dbg->de_debug_loclists.dss_size +
            dbg->de_debug_loclists.dss_data;
        if ((loc_ptr +loc_len) > end_ptr) {
            dwarfstring m;

            dwarfstring_constructor(&m);
            dwarfstring_append(&m,
                "DW_DLE_DEBUG_LOC_SECTION_SHORT "
                "(the .debug_loclists section is short), kind: ");
            _dwarf_lkind_name(lkind, &m);
            _dwarf_error_string(dbg,error,
                DW_DLE_DEBUG_LOC_SECTION_SHORT,
                dwarfstring_string(&m));
            dwarfstring_destructor(&m);
            return DW_DLV_ERROR;
        }
    }
    return DW_DLV_OK;
}

/*  ld_kind was checked before calling this, so we
    know its value is an intended value.  */
static const char *kindset[] = {
"DW_LKIND_expression",
"DW_LKIND_loclist",
"DW_LKIND_GNU_exp_list",
"DW_LKIND_unknown3",
"DW_LKIND_unknown4",
"DW_LKIND_loclists"
};
static const char *
get_loc_kind_str(Dwarf_Small lkind)
{
    if (lkind <= DW_LKIND_loclists) {
        return kindset[lkind];
    }
    if (lkind == DW_LKIND_unknown) {
        return "DW_LKIND_unknown";
    }
    return "UNKNOWN DW_LKIND!";
}
static int
validate_lle_value(Dwarf_Debug dbg,
    Dwarf_Locdesc_c locdesc,
    Dwarf_Error *error)
{
    dwarfstring m;

    if (locdesc->ld_kind != DW_LKIND_GNU_exp_list) {
        switch(locdesc->ld_lle_value) {
        case DW_LLE_end_of_list:
        case DW_LLE_base_addressx:
        case DW_LLE_startx_endx:
        case DW_LLE_startx_length:
        case DW_LLE_offset_pair:
        case DW_LLE_default_location:
        case DW_LLE_base_address:
        case DW_LLE_start_end:
        case DW_LLE_start_length:
            return DW_DLV_OK;
        }
        dwarfstring_constructor(&m);

        dwarfstring_append_printf_s(&m,
            "DW_DLE_LOCATION_ERROR: For location kind %s (",
            (char *)get_loc_kind_str(locdesc->ld_kind));
        dwarfstring_append_printf_u(&m,"%u) the DW_LLE value is "
            "not properly set",
            locdesc->ld_kind);
        dwarfstring_append_printf_u(&m," but is %u "
            " which is a libdwarf bug",
            locdesc->ld_lle_value);
        _dwarf_error_string(dbg,error,DW_DLE_LOCATION_ERROR,
            dwarfstring_string(&m));
        dwarfstring_destructor(&m);
        return DW_DLV_ERROR;
    }
    switch(locdesc->ld_lle_value) {
    case DW_LLEX_end_of_list_entry:
    case DW_LLEX_base_address_selection_entry:
    case DW_LLEX_start_end_entry:
    case DW_LLEX_start_length_entry:
    case DW_LLEX_offset_pair_entry:
        return DW_DLV_OK;
    }
    {
        dwarfstring_constructor(&m);
        dwarfstring_append_printf_s(&m,
            "DW_DLE_LOCATION_ERROR: For location kind %s (",
            (char *)get_loc_kind_str(locdesc->ld_kind));
        dwarfstring_append_printf_u(&m,"%u) the DW_LLEX value is "
            "not properly set",
            locdesc->ld_kind);
        dwarfstring_append_printf_u(&m," but is %u "
            " which is a libdwarf bug",
            locdesc->ld_lle_value);
        _dwarf_error_string(dbg,error,DW_DLE_LOCATION_ERROR,
            dwarfstring_string(&m));
        dwarfstring_destructor(&m);
    }
    return DW_DLV_ERROR;
}
/*  Sets locdesc operator list information in locdesc.
    Sets the locdesc values (rawlow, rawhigh etc).
    This synthesizes the ld_lle_value of the locdesc
    if it's not already provided.
    Not passing in locdesc pointer, the locdesc_index suffices
    to index to the relevant locdesc pointer.
    See also dwarf_loclists.c: build_array_of_lle*/
int
_dwarf_fill_in_locdesc_op_c(Dwarf_Debug dbg,
    Dwarf_Unsigned locdesc_index,
    Dwarf_Loc_Head_c loc_head,
    Dwarf_Block_c * loc_block,
    Dwarf_Half address_size,
    Dwarf_Half offset_size,
    Dwarf_Small version_stamp,
    Dwarf_Addr lowpc,
    Dwarf_Addr highpc,
    Dwarf_Half lle_op,
    Dwarf_Error * error)
{
    /* Offset of current operator from start of block. */
    Dwarf_Unsigned offset = 0;

    /*  Chain the  DW_OPerator structs. */
    Dwarf_Loc_Chain new_loc = NULL;
    Dwarf_Loc_Chain prev_loc = NULL;
    Dwarf_Loc_Chain head_loc = NULL;

    Dwarf_Unsigned  op_count = 0;

    /*  Contiguous block of Dwarf_Loc_Expr_Op_s
        for Dwarf_Locdesc. */
    Dwarf_Loc_Expr_Op block_loc = 0;

    Dwarf_Locdesc_c locdesc = loc_head->ll_locdesc + locdesc_index;
    Dwarf_Unsigned  i = 0;
    int             res = 0;
    Dwarf_Small    *section_start = 0;
    Dwarf_Unsigned  section_size = 0;
    Dwarf_Small    *section_end = 0;
    const char     *section_name = 0;
    Dwarf_Small    *blockdataptr = 0;
    unsigned lkind = loc_head->ll_kind;

    /* ***** BEGIN CODE ***** */
    blockdataptr = loc_block->bl_data;
    if (!blockdataptr || !loc_block->bl_len) {
        /*  an empty block has no operations so
            no section or tests need be done.. */
    } else {
        res = _dwarf_what_section_are_we(dbg,
            blockdataptr,&section_name,&section_start,
            &section_size,&section_end,error);
        if (res != DW_DLV_OK) {
            _dwarf_error(dbg, error,DW_DLE_POINTER_SECTION_UNKNOWN);
            return DW_DLV_ERROR;
        }
        res = _dwarf_loc_block_sanity_check(dbg,loc_block,error);
        if (res != DW_DLV_OK) {
            return res;
        }
    }
    /* New loop getting Loc operators. Non DWO */
    while (offset <= loc_block->bl_len) {
        Dwarf_Unsigned nextoffset = 0;
        struct Dwarf_Loc_Expr_Op_s temp_loc;

        /*  This call is ok even if bl_data NULL and bl_len 0 */
        res = _dwarf_read_loc_expr_op(dbg,loc_block,
            op_count,
            version_stamp,
            offset_size,
            address_size,
            offset,
            section_end,
            &nextoffset,
            &temp_loc,
            error);
        if (res == DW_DLV_ERROR) {
            return res;
        }
        if (res == DW_DLV_NO_ENTRY) {
            /*  Normal end.
                Also the end for an empty loc_block.  */
            break;
        }
        op_count++;
        new_loc =
            (Dwarf_Loc_Chain) _dwarf_get_alloc(dbg, DW_DLA_LOC_CHAIN, 1);
        if (new_loc == NULL) {
            _dwarf_free_op_chain(dbg,head_loc);
            _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
            return DW_DLV_ERROR;
        }

        /* Copying all the fields. DWARF 2,3,4,5. */
        new_loc->lc_atom    = temp_loc.lr_atom;
        new_loc->lc_opnumber= temp_loc.lr_opnumber;
        new_loc->lc_raw1    = temp_loc.lr_number;
        new_loc->lc_raw2    = temp_loc.lr_number2;
        new_loc->lc_raw3    = temp_loc.lr_number3;
        new_loc->lc_number  = temp_loc.lr_number;
        new_loc->lc_number2 = temp_loc.lr_number2;
        new_loc->lc_number3 = temp_loc.lr_number3;
        new_loc->lc_offset  = temp_loc.lr_offset;
        if (head_loc == NULL)
            head_loc = prev_loc = new_loc;
        else {
            prev_loc->lc_next = new_loc;
            prev_loc = new_loc;
        }
        offset = nextoffset;
    }
    block_loc =
        (Dwarf_Loc_Expr_Op ) _dwarf_get_alloc(dbg,
        DW_DLA_LOC_BLOCK_C, op_count);
    new_loc = head_loc;
    if (!block_loc) {
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        for (i = 0; i < op_count; i++) {
            prev_loc = new_loc;
            new_loc = prev_loc->lc_next;
            dwarf_dealloc(dbg, prev_loc, DW_DLA_LOC_CHAIN);
        }
        return DW_DLV_ERROR;
    }

    /* op_count could be zero. */
    new_loc = head_loc;
    for (i = 0; i < op_count; i++) {
        /* Copying only the fields needed by DWARF 2,3,4 */
        (block_loc + i)->lr_atom = new_loc->lc_atom;
        (block_loc + i)->lr_raw1 = new_loc->lc_raw1;
        (block_loc + i)->lr_raw2 = new_loc->lc_raw2;
        (block_loc + i)->lr_raw3 = new_loc->lc_raw3;
        (block_loc + i)->lr_number = new_loc->lc_number;
        (block_loc + i)->lr_number2 = new_loc->lc_number2;
        (block_loc + i)->lr_number3 = new_loc->lc_number3;
        (block_loc + i)->lr_offset = new_loc->lc_offset;
        (block_loc + i)->lr_opnumber = new_loc->lc_opnumber;
        prev_loc = new_loc;
        new_loc = prev_loc->lc_next;
        dwarf_dealloc(dbg, prev_loc, DW_DLA_LOC_CHAIN);
    }
    /*  Synthesizing the DW_LLE values for the old loclist
        versions. */
    switch(loc_head->ll_kind) {
    case DW_LKIND_loclist: {
        if(highpc == 0 && lowpc == 0) {
            locdesc->ld_lle_value =  DW_LLE_end_of_list;
        } else if(lowpc == MAX_ADDR) {
            locdesc->ld_lle_value = DW_LLE_base_address;
        } else {
            locdesc->ld_lle_value = DW_LLE_offset_pair;
        }
        }
        break;
    case DW_LKIND_GNU_exp_list:
        /* DW_LKIND_GNU_exp_list */
        locdesc->ld_lle_value = lle_op;
        break;
    case DW_LKIND_expression:
        /*  This is a kind of fake, but better than 0 */
        locdesc->ld_lle_value =  DW_LLE_start_end;
        break;
    case DW_LKIND_loclists:
        /* ld_lle_value already set */
        break;
    default:  {
        dwarfstring m;

        dwarfstring_constructor(&m);
        dwarfstring_append_printf_u(&m,
            "DW_DLE_LOCATION_ERROR: An impossible DW_LKIND"
            " value of %u encountered, likely internal "
            "libdwarf error or data corruption",
            (unsigned)loc_head->ll_kind);
        _dwarf_error_string(dbg,error,
            DW_DLE_LOCATION_ERROR,
            dwarfstring_string(&m));
        dwarfstring_destructor(&m);
        dwarf_dealloc(dbg,block_loc,DW_DLA_LOC_BLOCK_C);
        return DW_DLV_ERROR;
        }
    }
    locdesc->ld_cents = op_count;
    locdesc->ld_s = block_loc;

    locdesc->ld_kind = lkind;
    locdesc->ld_section_offset = loc_block->bl_section_offset;
    locdesc->ld_locdesc_offset = loc_block->bl_locdesc_offset;
    locdesc->ld_rawlow = lowpc;
    locdesc->ld_rawhigh = highpc;

    res = validate_lle_value(dbg,locdesc,error);
    if (res != DW_DLV_OK) {
        dwarf_dealloc(dbg,block_loc,DW_DLA_LOC_BLOCK_C);
        return res;
    }
    /*  Leaving the cooked values zero. Filled in later. */
    /*  We have not yet looked for debug_addr, so we'll
        set it as not-missing. */
    locdesc->ld_index_failed = FALSE;
    return DW_DLV_OK;
}


/* Non-standard DWARF4 dwo loclist */
static int
_dwarf_read_loc_section_dwo(Dwarf_Debug dbg,
    Dwarf_Block_c * return_block,
    Dwarf_Addr * lowpc,
    Dwarf_Addr * highpc,
    Dwarf_Bool *at_end,
    Dwarf_Half * lle_op,
    Dwarf_Off sec_offset,
    Dwarf_Half address_size,
    Dwarf_Half lkind,
    Dwarf_Error * error)
{
    Dwarf_Small *beg = dbg->de_debug_loc.dss_data + sec_offset;
    Dwarf_Small *locptr = 0;
    Dwarf_Small llecode = 0;
    Dwarf_Unsigned expr_offset  = sec_offset;
    Dwarf_Byte_Ptr section_end = dbg->de_debug_loc.dss_data
        + dbg->de_debug_loc.dss_size;

    if (sec_offset >= dbg->de_debug_loc.dss_size) {
        /* We're at the end. No more present. */
        return DW_DLV_NO_ENTRY;
    }
    memset(return_block,0,sizeof(*return_block));

    /* not the same as non-split loclist, but still a list. */
    return_block->bl_kind = lkind;

    /* This is non-standard  GNU Dwarf4 loclist */
    return_block->bl_locdesc_offset = sec_offset;
    llecode = *beg;
    locptr = beg +1;
    expr_offset++;
    switch(llecode) {
    case DW_LLEX_end_of_list_entry:
        *at_end = TRUE;
        return_block->bl_section_offset = expr_offset;
        expr_offset++;
        break;
    case DW_LLEX_base_address_selection_entry: {
        Dwarf_Unsigned addr_index = 0;

        DECODE_LEB128_UWORD_CK(locptr,addr_index,
            dbg,error,section_end);
        return_block->bl_section_offset = expr_offset;
        /* So this behaves much like non-dwo loclist */
        *lowpc=MAX_ADDR;
        *highpc=addr_index;
        }
        break;
    case DW_LLEX_start_end_entry: {
        Dwarf_Unsigned addr_indexs = 0;
        Dwarf_Unsigned addr_indexe= 0;
        Dwarf_Unsigned exprlen = 0;
        Dwarf_Unsigned leb128_length = 0;

        DECODE_LEB128_UWORD_LEN_CK(locptr,addr_indexs,
            leb128_length,
            dbg,error,section_end);
        expr_offset += leb128_length;

        DECODE_LEB128_UWORD_LEN_CK(locptr,addr_indexe,
            leb128_length,
            dbg,error,section_end);
        expr_offset +=leb128_length;

        *lowpc=addr_indexs;
        *highpc=addr_indexe;

        READ_UNALIGNED_CK(dbg, exprlen, Dwarf_Unsigned, locptr,
            DWARF_HALF_SIZE,
            error,section_end);
        locptr += DWARF_HALF_SIZE;
        expr_offset += DWARF_HALF_SIZE;

        return_block->bl_len = exprlen;
        return_block->bl_data = locptr;
        return_block->bl_section_offset = expr_offset;

        expr_offset += exprlen;
        if (expr_offset > dbg->de_debug_loc.dss_size) {
            dwarfstring m;

            dwarfstring_constructor(&m);
            dwarfstring_append(&m,
                "DW_DLE_DEBUG_LOC_SECTION_SHORT:");
            dwarfstring_append_printf_u(&m,
                " in DW_LLEX_start_end_entry "
                "The expression offset is 0x%x",
                expr_offset);
            dwarfstring_append_printf_u(&m,
                " which is greater than the section size"
                " of 0x%x. Corrupt Dwarf.",
                dbg->de_debug_loc.dss_size);
            _dwarf_error_string(dbg,error,
                DW_DLE_DEBUG_LOC_SECTION_SHORT,
                dwarfstring_string(&m));
            dwarfstring_destructor(&m);
            return DW_DLV_ERROR;
        }
        }
        break;
    case DW_LLEX_start_length_entry: {
        Dwarf_Unsigned addr_index = 0;
        Dwarf_Unsigned  range_length = 0;
        Dwarf_Unsigned exprlen = 0;
        Dwarf_Unsigned leb128_length = 0;

        DECODE_LEB128_UWORD_LEN_CK(locptr,addr_index,
            leb128_length,
            dbg,error,section_end);
        expr_offset +=leb128_length;

        READ_UNALIGNED_CK(dbg, range_length, Dwarf_Unsigned, locptr,
            DWARF_32BIT_SIZE,
            error,section_end);
        locptr += DWARF_32BIT_SIZE;
        expr_offset += DWARF_32BIT_SIZE;

        READ_UNALIGNED_CK(dbg, exprlen, Dwarf_Unsigned, locptr,
            DWARF_HALF_SIZE,
            error,section_end);
        locptr += DWARF_HALF_SIZE;
        expr_offset += DWARF_HALF_SIZE;

        *lowpc = addr_index;
        *highpc = range_length;
        return_block->bl_len = exprlen;
        return_block->bl_data = locptr;
        return_block->bl_section_offset = expr_offset;
        /* exprblock_size can be zero, means no expression */

        expr_offset += exprlen;
        if (expr_offset > dbg->de_debug_loc.dss_size) {
            dwarfstring m;

            dwarfstring_constructor(&m);
            dwarfstring_append(&m,
                "DW_DLE_DEBUG_LOC_SECTION_SHORT:");
            dwarfstring_append_printf_u(&m,
                " in DW_LLEX_start_length_entry "
                "The expression offset is 0x%x",
                expr_offset);
            dwarfstring_append_printf_u(&m,
                " which is greater than the section size"
                " of 0x%x. Corrupt Dwarf.",
                dbg->de_debug_loc.dss_size);
            _dwarf_error_string(dbg,error,
                DW_DLE_DEBUG_LOC_SECTION_SHORT,
                dwarfstring_string(&m));
            dwarfstring_destructor(&m);
            return DW_DLV_ERROR;
        }
        }
        break;
    case DW_LLEX_offset_pair_entry: {
        Dwarf_Unsigned  startoffset = 0;
        Dwarf_Unsigned  endoffset = 0;
        Dwarf_Unsigned exprlen = 0;

        READ_UNALIGNED_CK(dbg, startoffset,
            Dwarf_Unsigned, locptr,
            DWARF_32BIT_SIZE,
            error,section_end);
        locptr += DWARF_32BIT_SIZE;
        expr_offset += DWARF_32BIT_SIZE;

        READ_UNALIGNED_CK(dbg, endoffset,
            Dwarf_Unsigned, locptr,
            DWARF_32BIT_SIZE,
            error,section_end);
        locptr += DWARF_32BIT_SIZE;
        expr_offset +=  DWARF_32BIT_SIZE;
        *lowpc= startoffset;
        *highpc = endoffset;

        READ_UNALIGNED_CK(dbg, exprlen, Dwarf_Unsigned, locptr,
            DWARF_HALF_SIZE,
            error,section_end);
        locptr += DWARF_HALF_SIZE;
        expr_offset += DWARF_HALF_SIZE;

        return_block->bl_len = exprlen;
        return_block->bl_data = locptr;
        return_block->bl_section_offset = expr_offset;

        expr_offset += exprlen;
        if (expr_offset > dbg->de_debug_loc.dss_size) {
            dwarfstring m;

            dwarfstring_constructor(&m);
            dwarfstring_append(&m,
                "DW_DLE_DEBUG_LOC_SECTION_SHORT:");
            dwarfstring_append_printf_u(&m,
                " in DW_LLEX_offset_pair_entry "
                "The expression offset is 0x%x",
                expr_offset);
            dwarfstring_append_printf_u(&m,
                " which is greater than the section size"
                " of 0x%x. Corrupt Dwarf.",
                dbg->de_debug_loc.dss_size);
            _dwarf_error_string(dbg,error,
                DW_DLE_DEBUG_LOC_SECTION_SHORT,
                dwarfstring_string(&m));
            dwarfstring_destructor(&m);
            return DW_DLV_ERROR;
        }
        }
        break;
    default: {
        dwarfstring m;

        dwarfstring_constructor(&m);
        dwarfstring_append(&m,
            "DW_DLE_LLE_CODE_UNKNOWN:");
        dwarfstring_append_printf_u(&m,
            " in DW_LLEX_ code value "
            " is 0x%x ,not an expected value.",
            llecode);
        _dwarf_error_string(dbg,error,
            DW_DLE_LLE_CODE_UNKNOWN,
            dwarfstring_string(&m));
        dwarfstring_destructor(&m);
        _dwarf_error(dbg,error,DW_DLE_LLE_CODE_UNKNOWN);
        return DW_DLV_ERROR;
    }
    }
    *lle_op = llecode;
    return DW_DLV_OK;
}


int
dwarf_get_loclist_head_kind(Dwarf_Loc_Head_c ll_header,
    unsigned int * kind,
    UNUSEDARG Dwarf_Error  * error)
{
    *kind = ll_header->ll_kind;
    return DW_DLV_OK;
}

static int
_dwarf_original_loclist_build(Dwarf_Debug dbg,
    Dwarf_Loc_Head_c llhead,
    Dwarf_Attribute  attr,
    Dwarf_Error     *error)
{
    Dwarf_Unsigned loclist_offset = 0;
    Dwarf_Unsigned starting_loclist_offset = 0;
    int            off_res  = DW_DLV_ERROR;
    int            count_res = DW_DLV_ERROR;
    int            loclist_count = 0;
    Dwarf_Unsigned lli = 0;
    unsigned       lkind = llhead->ll_kind;
    unsigned       address_size = llhead->ll_address_size;
    Dwarf_Unsigned listlen = 0;
    Dwarf_Locdesc_c llbuf = 0;
    Dwarf_CU_Context cucontext;

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

    if (lkind == DW_LKIND_GNU_exp_list) {
        count_res = _dwarf_get_loclist_lle_count_dwo(dbg,
            loclist_offset,
            address_size,
            llhead->ll_kind,
            &loclist_count,
            error);
    } else {
        count_res = _dwarf_get_loclist_lle_count(dbg,
            loclist_offset, address_size,
            llhead->ll_kind,
            &loclist_count,
            error);
    }
    if (count_res != DW_DLV_OK) {
        return count_res;
    }
    if (loclist_count == 0) {
        return DW_DLV_NO_ENTRY;
    }

    listlen = loclist_count;
    llbuf = (Dwarf_Locdesc_c)
        _dwarf_get_alloc(dbg, DW_DLA_LOCDESC_C, listlen);
    if (!llbuf) {
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return (DW_DLV_ERROR);
    }
    llhead->ll_locdesc = llbuf;
    llhead->ll_locdesc_count = listlen;
    cucontext = llhead->ll_context;
    llhead->ll_llearea_offset = loclist_offset;
    /* Now get loc ops */
    for (lli = 0; lli < listlen; ++lli) {
        int lres = 0;
        Dwarf_Half lle_op = 0;
        Dwarf_Bool at_end = 0;
        Dwarf_Block_c loc_block;
        Dwarf_Unsigned rawlowpc = 0;
        Dwarf_Unsigned rawhighpc = 0;
        int blkres = 0;

        memset(&loc_block,0,sizeof(loc_block));
        if( lkind == DW_LKIND_GNU_exp_list) {
            blkres = _dwarf_read_loc_section_dwo(dbg,
                &loc_block,
                &rawlowpc, &rawhighpc,
                &at_end, &lle_op,
                loclist_offset,
                address_size,
                lkind,
                error);
        } else {
            blkres = _dwarf_read_loc_section(dbg,
                &loc_block,
                &rawlowpc, &rawhighpc,
                &lle_op,
                loclist_offset,
                address_size,
                lkind,
                error);
        }
        if (blkres != DW_DLV_OK) {
            return blkres;
        }
        /* Fills in the locdesc and its operators list at index lli */
        lres = _dwarf_fill_in_locdesc_op_c(dbg,
            lli,
            llhead,
            &loc_block,
            address_size,
            cucontext->cc_length_size,
            cucontext->cc_version_stamp,
            rawlowpc,
            rawhighpc,
            lle_op,
            error);
        if (lres != DW_DLV_OK) {
            return lres;
        }
        /* Now get to next loclist entry offset. */
        loclist_offset = loc_block.bl_section_offset +
            loc_block.bl_len;
    }
    /*  We need to calculate the cooked values for
        each locldesc entry, that will be done
        in dwarf_get_loclist_c(). */

    llhead->ll_bytes_total = loclist_offset -
        starting_loclist_offset;
    return DW_DLV_OK;
}

static int
_dwarf_original_expression_build(Dwarf_Debug dbg,
    Dwarf_Loc_Head_c llhead,
    Dwarf_Attribute attr,
    Dwarf_Error *error)
{

    Dwarf_Block_c loc_blockc;
    Dwarf_Unsigned rawlowpc = 0;
    Dwarf_Unsigned rawhighpc = 0;
    unsigned form = llhead->ll_attrform;
    int blkres = 0;
    Dwarf_Locdesc_c llbuf = 0;
    unsigned listlen = 1;
    Dwarf_CU_Context cucontext = llhead->ll_context;
    unsigned address_size = llhead->ll_address_size;

    memset(&loc_blockc,0,sizeof(loc_blockc));
    if( form == DW_FORM_exprloc) {
        blkres = dwarf_formexprloc(attr,&loc_blockc.bl_len,
            &loc_blockc.bl_data,error);
        if(blkres != DW_DLV_OK) {
            dwarf_loc_head_c_dealloc(llhead);
            return blkres;
        }
        loc_blockc.bl_kind = llhead->ll_kind;
        loc_blockc.bl_section_offset  =
            (char *)loc_blockc.bl_data -
            (char *)dbg->de_debug_info.dss_data;
        loc_blockc.bl_locdesc_offset = 0; /* not relevant */
    } else {
        Dwarf_Block loc_block;

        memset(&loc_block,0,sizeof(loc_block));
        blkres = _dwarf_formblock_internal(dbg,attr,
            llhead->ll_context,
            &loc_block,
            error);
        if (blkres != DW_DLV_OK) {
            return blkres;
        }
        loc_blockc.bl_len = loc_block.bl_len;
        loc_blockc.bl_data = loc_block.bl_data;
        loc_blockc.bl_kind = llhead->ll_kind;
        loc_blockc.bl_section_offset =
            loc_block.bl_section_offset;
        loc_blockc.bl_locdesc_offset = 0; /* not relevant */
    }
    /*  We will mark the Locdesc_c DW_LLE_start_end
        shortly. Here we fake the address range
        as 'all addresses'. */
    rawlowpc = 0;
    rawhighpc = MAX_ADDR;

    llbuf = (Dwarf_Locdesc_c)
        _dwarf_get_alloc(dbg, DW_DLA_LOCDESC_C, listlen);
    if (!llbuf) {
        _dwarf_error(dbg, error, DW_DLE_ALLOC_FAIL);
        return (DW_DLV_ERROR);
    }
    llhead->ll_locdesc = llbuf;
    /* One by definition of a location entry. */
    llhead->ll_locdesc_count = listlen;

    /*  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 and its operators list
        at index 0 */
    blkres = _dwarf_fill_in_locdesc_op_c(dbg,
        0, /* fake locdesc is index 0 */
        llhead,
        &loc_blockc,
        llhead->ll_address_size,
        cucontext->cc_length_size,
        cucontext->cc_version_stamp,
        rawlowpc, rawhighpc,
        0,
        error);
    llhead->ll_bytes_total += loc_blockc.bl_len;
    if (blkres != DW_DLV_OK) {
        /* low level error already set: let it be passed back */
        return blkres;
    }
    return DW_DLV_OK;
}

/*  Following the original loclist definition the low
    value is all one bits, the high value is the base
    address. */
static int
cook_original_loclist_contents(Dwarf_Debug dbg,
    Dwarf_Loc_Head_c llhead,
    Dwarf_Error *error)
{
    Dwarf_Unsigned baseaddress = llhead->ll_cu_base_address;
    Dwarf_Unsigned count = llhead->ll_locdesc_count;
    Dwarf_Unsigned i = 0;

    for ( i = 0 ; i < count; ++i) {
        Dwarf_Locdesc_c  llc = 0;

        llc = llhead->ll_locdesc +i;
        switch(llc->ld_lle_value) {
        case DW_LLE_end_of_list: {
            /* nothing to do */
            break;
            }
        case DW_LLE_base_address: {
            llc->ld_lopc =  llc->ld_rawhigh;
            llc->ld_highpc =  llc->ld_rawhigh;
            baseaddress =  llc->ld_rawhigh;
            break;
            }
        case DW_LLE_offset_pair: {
            llc->ld_lopc = llc->ld_rawlow + baseaddress;
            llc->ld_highpc = llc->ld_rawhigh + baseaddress;
            break;
            }
        default: {
            dwarfstring m;

            dwarfstring_constructor(&m);
            dwarfstring_append_printf_u(&m,
                "DW_DLE_LOCLISTS_ERROR: improper synthesized LLE code "
                "of 0x%x is unknown. In standard DWARF3/4 loclist",
                llc->ld_lle_value);
            _dwarf_error_string(dbg,error,
                DW_DLE_LOCLISTS_ERROR,
                dwarfstring_string(&m));
            dwarfstring_destructor(&m);
            return DW_DLV_ERROR;
            }
        }
    }
    return DW_DLV_OK;
}

static int
cook_gnu_loclist_contents(Dwarf_Debug dbg,
    Dwarf_Loc_Head_c llhead,
    Dwarf_Error *error)
{
    Dwarf_Unsigned baseaddress = llhead->ll_cu_base_address;
    Dwarf_Unsigned count = llhead->ll_locdesc_count;
    Dwarf_Unsigned i = 0;
    Dwarf_CU_Context cucontext = llhead->ll_context;
    int res = 0;

    for (i = 0 ; i < count ; ++i) {
        Dwarf_Locdesc_c  llc = 0;

        llc = llhead->ll_locdesc +i;
        switch(llc->ld_lle_value) {
        case DW_LLEX_base_address_selection_entry:{
            Dwarf_Addr targaddr = 0;

            res = _dwarf_look_in_local_and_tied_by_index(
                dbg,cucontext,llc->ld_rawhigh,&targaddr,
                error);
            if (res != DW_DLV_OK) {
                llc->ld_index_failed = TRUE;
                llc->ld_lopc = 0;
                llc->ld_highpc = 0;
                if (res == DW_DLV_ERROR) {
                    dwarf_dealloc_error(dbg, *error);
                    *error = 0;
                }
            } else {
                llc->ld_lopc = targaddr;
                llc->ld_highpc = targaddr;
            }
            break;
            }
        case DW_LLEX_end_of_list_entry:{
            /* Nothing to do. */
            break;
            }
        case DW_LLEX_start_length_entry:{
            Dwarf_Addr targaddr = 0;
            res = _dwarf_look_in_local_and_tied_by_index(
                dbg,cucontext,llc->ld_rawlow,&targaddr,
                error);
            if (res != DW_DLV_OK) {
                llc->ld_index_failed = TRUE;
                llc->ld_lopc = 0;
                if (res == DW_DLV_ERROR) {
                    dwarf_dealloc_error(dbg, *error);
                    *error = 0;
                }
            } else {
                llc->ld_lopc = targaddr;
                llc->ld_highpc = llc->ld_lopc +llc->ld_rawhigh;
            }
            break;
            }
        case DW_LLEX_offset_pair_entry:{
            llc->ld_lopc = llc->ld_rawlow + baseaddress;
            llc->ld_highpc = llc->ld_rawhigh + baseaddress;
            break;
            }
        case DW_LLEX_start_end_entry:{
            Dwarf_Addr targaddr = 0;
            res = _dwarf_look_in_local_and_tied_by_index(
                dbg,cucontext,llc->ld_rawlow,&targaddr,
                error);
            if (res != DW_DLV_OK) {
                llc->ld_index_failed = TRUE;
                llc->ld_lopc = 0;
                if (res == DW_DLV_ERROR) {
                    dwarf_dealloc_error(dbg, *error);
                    *error = 0;
                }
            } else {
                llc->ld_lopc = targaddr;
            }
            res = _dwarf_look_in_local_and_tied_by_index(
                dbg,cucontext,llc->ld_rawlow,&targaddr,
                error);
            if (res != DW_DLV_OK) {
                llc->ld_index_failed = TRUE;
                llc->ld_highpc = 0;
                if (res == DW_DLV_ERROR) {
                    dwarf_dealloc_error(dbg, *error);
                    *error = 0;
                }
            } else {
                llc->ld_highpc = targaddr;
            }


            break;
            }
        default:{
            dwarfstring m;

            dwarfstring_constructor(&m);
            dwarfstring_append_printf_u(&m,
                "DW_DLE_LOCLISTS_ERROR: improper LLEX code "
                "of 0x%x is unknown. GNU LLEX dwo loclists error",
                llc->ld_lle_value);
            _dwarf_error_string(dbg,error,
                DW_DLE_LOCLISTS_ERROR,
                dwarfstring_string(&m));
            dwarfstring_destructor(&m);
            return DW_DLV_ERROR;

            break;
            }
        }
    }
    return DW_DLV_OK;
}


/* DWARF5 */
static int
cook_loclists_contents(Dwarf_Debug dbg,
    Dwarf_Loc_Head_c llhead,
    Dwarf_Error *error)
{
    Dwarf_Unsigned baseaddress = llhead->ll_cu_base_address;
    Dwarf_Unsigned count = llhead->ll_locdesc_count;
    Dwarf_Unsigned i = 0;
    Dwarf_CU_Context cucontext = llhead->ll_context;
    int res = 0;
    Dwarf_Bool base_address_fail = FALSE;
    Dwarf_Bool debug_addr_fail = FALSE;

    if (!llhead->ll_cu_base_address_present) {
        base_address_fail = TRUE;
    }
    for (i = 0 ; i < count ; ++i) {
        Dwarf_Locdesc_c  llc = 0;

        llc = llhead->ll_locdesc +i;
        switch(llc->ld_lle_value) {
        case DW_LLE_base_addressx: {
            Dwarf_Addr targaddr = 0;
            if (debug_addr_fail) {
                res = DW_DLV_NO_ENTRY;
            } else {
                res = _dwarf_look_in_local_and_tied_by_index(
                    dbg,cucontext,llc->ld_rawlow,&targaddr,
                    error);
            }
            if (res != DW_DLV_OK) {
                debug_addr_fail = TRUE;
                base_address_fail = TRUE;
                llc->ld_index_failed = TRUE;
                llc->ld_lopc = 0;
                if (res == DW_DLV_ERROR) {
                    dwarf_dealloc_error(dbg, *error);
                    *error = 0;
                }
            } else {
                base_address_fail = FALSE;
                baseaddress = targaddr;
                llc->ld_lopc = targaddr;
            }
            break;
        }
        case DW_LLE_startx_endx:{
            /* two indexes into debug_addr */
            Dwarf_Addr targaddr = 0;
            if (debug_addr_fail) {
                res = DW_DLV_NO_ENTRY;
            } else {
                res = _dwarf_look_in_local_and_tied_by_index(
                    dbg,cucontext,llc->ld_rawlow,&targaddr,
                    error);
            }
            if (res != DW_DLV_OK) {
                debug_addr_fail = TRUE;
                llc->ld_index_failed = TRUE;
                llc->ld_lopc = 0;
                if (res == DW_DLV_ERROR) {
                    dwarf_dealloc_error(dbg, *error);
                    *error = 0;
                }
            } else {
                llc->ld_lopc = targaddr;
            }
            if (debug_addr_fail) {
                res = DW_DLV_NO_ENTRY;
            } else {
                res = _dwarf_look_in_local_and_tied_by_index(
                    dbg,cucontext,llc->ld_rawhigh,&targaddr,
                    error);

            }
            if (res != DW_DLV_OK) {
                debug_addr_fail = TRUE;
                llc->ld_index_failed = TRUE;
                llc->ld_highpc = 0;
                if (res == DW_DLV_ERROR) {
                    dwarf_dealloc_error(dbg, *error);
                    *error = 0;
                }
            } else {
                llc->ld_highpc = targaddr;
            }
            break;
        }
        case DW_LLE_startx_length:{
            /* one index to debug_addr other a length */
            Dwarf_Addr targaddr = 0;
            if (debug_addr_fail) {
                res = DW_DLV_NO_ENTRY;
            } else  {
                res = _dwarf_look_in_local_and_tied_by_index(
                    dbg,cucontext,llc->ld_rawlow,&targaddr,
                    error);
            }
            if (res != DW_DLV_OK) {
                debug_addr_fail = TRUE;
                llc->ld_index_failed = TRUE;
                llc->ld_lopc = 0;
                if (res == DW_DLV_ERROR) {
                    dwarf_dealloc_error(dbg, *error);
                    *error = 0;
                }
            } else {
                llc->ld_lopc = targaddr;
                llc->ld_highpc = targaddr + llc->ld_rawhigh;
            }
            break;
        }
        case DW_LLE_offset_pair:{
            if (base_address_fail) {
                llc->ld_index_failed = TRUE;
                llc->ld_lopc = 0;
                llc->ld_highpc = 0;
            } else {
                /*offsets of the current base address*/
                llc->ld_lopc = llc->ld_rawlow +baseaddress;
                llc->ld_highpc = llc->ld_rawhigh +baseaddress;
            }
            break;
        }
        case DW_LLE_default_location:{
            /*  nothing to do here, just has a counted
                location description */
            break;
        }
        case DW_LLE_base_address:{
            llc->ld_lopc = llc->ld_rawlow;
            llc->ld_highpc = llc->ld_rawlow;
            baseaddress = llc->ld_rawlow;
            base_address_fail = FALSE;
            break;
        }
        case DW_LLE_start_end:{
            llc->ld_lopc = llc->ld_rawlow;
            llc->ld_highpc = llc->ld_rawhigh;
            break;
        }
        case DW_LLE_start_length:{
            llc->ld_lopc = llc->ld_rawlow;
            llc->ld_highpc = llc->ld_rawlow + llc->ld_rawhigh;
            break;
        }
        case DW_LLE_end_of_list:{
            /* do nothing */
            break;
        }
        default: {
            dwarfstring m;

            dwarfstring_constructor(&m);
            dwarfstring_append_printf_u(&m,
                "DW_DLE_LOCLISTS_ERROR: improper DW_LLE code "
                "of 0x%x is unknown. DWARF5 loclists error",
                llc->ld_lle_value);
            _dwarf_error_string(dbg,error,
                DW_DLE_LOCLISTS_ERROR,
                dwarfstring_string(&m));
            dwarfstring_destructor(&m);
            return DW_DLV_ERROR;
        }
        }
    }
    return DW_DLV_OK;
}

/*  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_Half form          = 0;
    Dwarf_Loc_Head_c llhead  = 0;
    Dwarf_CU_Context cucontext = 0;
    unsigned address_size    = 0;
    int cuversionstamp       = 0;
    Dwarf_Bool is_cu         = FALSE;
    Dwarf_Unsigned attrnum   = 0;
    Dwarf_Bool is_dwo        = 0;
    int setup_res            = DW_DLV_ERROR;
    int lkind                = 0;

    /* ***** BEGIN CODE ***** */
    setup_res = _dwarf_setup_loc(attr, &dbg,&cucontext, &form, error);
    if (setup_res != DW_DLV_OK) {
        return setup_res;
    }
    attrnum = attr->ar_attribute;
    cuversionstamp = cucontext->cc_version_stamp;
    address_size = cucontext->cc_address_size;
    is_dwo = cucontext->cc_is_dwo;
    lkind = determine_location_lkind(cuversionstamp,
        form, attrnum, is_dwo);
    if (lkind == DW_LKIND_unknown) {
        dwarfstring m;
        const char * formname = "<unknownform>";
        const char * attrname = "<unknown attribute>";

        dwarfstring_constructor(&m);
        dwarf_get_FORM_name(form,&formname);
        dwarf_get_AT_name(attrnum,&attrname);
        dwarfstring_append_printf_u(&m,
            "DW_DLE_LOC_EXPR_BAD: For Compilation Unit "
            "version %u",cuversionstamp);
        dwarfstring_append_printf_u(&m,
            ", attribute 0x%x (",attrnum);
        dwarfstring_append(&m,(char *)attrname);
        dwarfstring_append_printf_u(&m,
            ") form 0x%x (",form);
        dwarfstring_append(&m,(char *)formname);
        if (is_dwo) {
            dwarfstring_append(&m,") (the CU is a .dwo) ");
        } else {
            dwarfstring_append(&m,") (the CU is not a .dwo) ");
        }
        dwarfstring_append(&m," we don't undrstand the location");
        _dwarf_error_string(dbg,error,DW_DLE_LOC_EXPR_BAD,
            dwarfstring_string(&m));
        dwarfstring_destructor(&m);
        return DW_DLV_ERROR;
    }
    /*  Doing this early (first) to avoid repeating the alloc code
        for each type  */
    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);
    }
    llhead->ll_cuversion = cuversionstamp;
    llhead->ll_kind = lkind;
    llhead->ll_attrnum = attrnum;
    llhead->ll_attrform = form;
    llhead->ll_dbg = dbg;
    llhead->ll_address_size = address_size;
    llhead->ll_offset_size = cucontext->cc_length_size;
    llhead->ll_context = cucontext;

    llhead->ll_at_loclists_base_present =
        cucontext->cc_loclists_base_present;
    llhead->ll_at_loclists_base =  cucontext->cc_loclists_base;
    llhead->ll_cu_base_address_present = cucontext->cc_low_pc_present;
    llhead->ll_cu_base_address = cucontext->cc_low_pc;
    llhead->ll_cu_addr_base = cucontext->cc_addr_base;
    llhead->ll_cu_addr_base_present =
        cucontext->cc_addr_base_present;

    if (lkind == DW_LKIND_loclist ||
        lkind == DW_LKIND_GNU_exp_list) {
        int ores = 0;
        /* Here we have a loclist to deal with. */
        ores = context_is_cu_not_tu(cucontext,&is_cu);
        if(ores != DW_DLV_OK) {
            dwarf_loc_head_c_dealloc(llhead);
            return setup_res;
        }
        ores = _dwarf_original_loclist_build(dbg,
            llhead, attr, error);
        if (ores != DW_DLV_OK) {
            dwarf_loc_head_c_dealloc(llhead);
            return ores;
        }
        if (lkind == DW_LKIND_loclist) {
            ores = cook_original_loclist_contents(dbg,llhead,
                error);
        } else {
            ores = cook_gnu_loclist_contents(dbg,llhead,error);
        }
        if (ores != DW_DLV_OK) {
            dwarf_loc_head_c_dealloc(llhead);
            return ores;
        }
    } else if (lkind == DW_LKIND_expression) {
        /* DWARF2,3,4,5 */
        int eres = 0;
        eres = _dwarf_original_expression_build(dbg,
            llhead, attr, error);
        if (eres != DW_DLV_OK) {
            dwarf_loc_head_c_dealloc(llhead);
            return eres;
        }
    } else if (lkind == DW_LKIND_loclists) {
        /* DWARF5! */
        int leres = 0;

        leres = _dwarf_loclists_fill_in_lle_head(dbg,
            attr,llhead,error);
        if (leres != DW_DLV_OK) {
            dwarf_loc_head_c_dealloc(llhead);
            return leres;
        }
        leres = cook_loclists_contents(dbg,llhead,error);
        if (leres != DW_DLV_OK) {
            dwarf_loc_head_c_dealloc(llhead);
            return leres;
        }
    } /* ASSERT else impossible */
    *ll_header_out = llhead;
    *listlen_out = llhead->ll_locdesc_count;
    return DW_DLV_OK;
}

/*  An interface giving us no cu context!
    This is not going to be quite right. */
int
dwarf_loclist_from_expr_c(Dwarf_Debug dbg,
    Dwarf_Ptr expression_in,
    Dwarf_Unsigned expression_length,
    Dwarf_Half address_size,
    Dwarf_Half offset_size,
    Dwarf_Small dwarf_version,
    Dwarf_Loc_Head_c *loc_head,
    Dwarf_Unsigned * listlen,
    Dwarf_Error * error)
{
    /* Dwarf_Block that describes a single location expression. */
    Dwarf_Block_c loc_block;
    Dwarf_Loc_Head_c llhead = 0;
    Dwarf_Locdesc_c llbuf = 0;
    int local_listlen = 1;
    Dwarf_Addr rawlowpc = 0;
    Dwarf_Addr rawhighpc = MAX_ADDR;
    Dwarf_Small version_stamp = dwarf_version;
    int res = 0;

    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);
    }
    memset(&loc_block,0,sizeof(loc_block));
    loc_block.bl_len = expression_length;
    loc_block.bl_data = expression_in;
    loc_block.bl_kind = DW_LKIND_expression; /* Not from loclist. */
    loc_block.bl_section_offset = 0; /* Fake. Not meaningful. */
    loc_block.bl_locdesc_offset = 0; /* Fake. Not meaningful. */
    llbuf = (Dwarf_Locdesc_c)
        _dwarf_get_alloc(dbg, DW_DLA_LOCDESC_C, local_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 = local_listlen;
    llhead->ll_context = 0; /* Not available! */
    llhead->ll_dbg = dbg;
    llhead->ll_kind = DW_LKIND_expression;

    /*  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 and its operators list at index 0 */
    res = _dwarf_fill_in_locdesc_op_c(dbg,
        0,
        llhead,
        &loc_block,
        address_size,
        offset_size,
        version_stamp,
        rawlowpc,
        rawhighpc,
        DW_LKIND_expression,
        error);
    if (res != DW_DLV_OK) {
        /* low level error already set: let it be passed back */
        dwarf_loc_head_c_dealloc(llhead);
        return (DW_DLV_ERROR);
    }
    *loc_head = llhead;
    *listlen = local_listlen;
    return (DW_DLV_OK);
}


/*  New June 2020. */
int
dwarf_get_locdesc_entry_d(Dwarf_Loc_Head_c loclist_head,
   Dwarf_Unsigned   index,
   Dwarf_Small    * lle_value_out,
   Dwarf_Unsigned * rawval1,
   Dwarf_Unsigned * rawval2,
   Dwarf_Bool     * debug_addr_unavailable,
   Dwarf_Addr     * lowpc_out, /* 'cooked' value */
   Dwarf_Addr     * hipc_out, /* 'cooked' value */
   Dwarf_Unsigned * loclist_expr_op_count_out,
   /* Returns pointer to the specific locdesc of the index; */
   Dwarf_Locdesc_c* locdesc_entry_out,
   Dwarf_Small    * loclist_source_out, /* 0,1, or 2 */
   Dwarf_Unsigned * expression_offset_out,
   Dwarf_Unsigned * locdesc_offset_out,
   Dwarf_Error    * error)
{
    Dwarf_Locdesc_c descs_base =  0;
    Dwarf_Locdesc_c desc =  0;
    Dwarf_Unsigned desc_count = 0;
    Dwarf_Debug dbg;

    desc_count = loclist_head->ll_locdesc_count;
    descs_base  = loclist_head->ll_locdesc;
    dbg = loclist_head->ll_dbg;
    if (index >= desc_count) {
        _dwarf_error(dbg, error, DW_DLE_LOCLIST_INDEX_ERROR);
        return (DW_DLV_ERROR);
    }
    desc = descs_base + index;
    *lle_value_out = desc->ld_lle_value;
    *rawval1 = desc->ld_rawlow;
    *rawval2 = desc->ld_rawhigh;
    *lowpc_out = desc->ld_lopc;
    *hipc_out = desc->ld_highpc;
    *debug_addr_unavailable = desc->ld_index_failed;
    *loclist_expr_op_count_out = desc->ld_cents;
    *locdesc_entry_out = desc;
    *loclist_source_out = desc->ld_kind;
    *expression_offset_out = desc->ld_section_offset;
    *locdesc_offset_out = desc->ld_locdesc_offset;
    return DW_DLV_OK;
}

/*  Use  dwarf_get_locdesc_entry_d() instead
    This function is not sufficient for DWARF 5. */
int
dwarf_get_locdesc_entry_c(Dwarf_Loc_Head_c loclist_head,
    Dwarf_Unsigned   index,
    Dwarf_Small    * lle_value_out,
    Dwarf_Addr     * lowpc_out,
    Dwarf_Addr     * hipc_out,
    Dwarf_Unsigned * loclist_count_out,

    /* Returns pointer to the specific locdesc of the index; */
    Dwarf_Locdesc_c* locdesc_entry_out,

    /* 0,1,2 or 5  DW_LKIND_* */
    Dwarf_Small    * loclist_source_out,
    Dwarf_Unsigned * expression_offset_out,
    Dwarf_Unsigned * locdesc_offset_out,
    Dwarf_Error    * error)
{
    int res = 0;
    Dwarf_Unsigned cookedlow = 0;
    Dwarf_Unsigned cookedhigh = 0;
    Dwarf_Bool debug_addr_unavailable = FALSE;

    res = dwarf_get_locdesc_entry_d(loclist_head,
        index,lle_value_out,
        lowpc_out,hipc_out,
        &debug_addr_unavailable,
        &cookedlow,&cookedhigh,
        loclist_count_out,
        locdesc_entry_out,
        loclist_source_out,
        expression_offset_out,
        locdesc_offset_out,
        error);
    return res;
}


int
dwarf_get_location_op_value_d(Dwarf_Locdesc_c locdesc,
    Dwarf_Unsigned   index,
    Dwarf_Small    * atom_out,
    Dwarf_Unsigned * operand1,
    Dwarf_Unsigned * operand2,
    Dwarf_Unsigned * operand3,
    Dwarf_Unsigned * rawop1,
    Dwarf_Unsigned * rawop2,
    Dwarf_Unsigned * rawop3,
    Dwarf_Unsigned * offset_for_branch,
    Dwarf_Error*     error)
{
    Dwarf_Loc_Expr_Op op = 0;
    Dwarf_Unsigned max = locdesc->ld_cents;

    if(index >= max) {
        Dwarf_Debug dbg = locdesc->ld_loclist_head->ll_dbg;
        _dwarf_error(dbg, error, DW_DLE_LOCLIST_INDEX_ERROR);
        return (DW_DLV_ERROR);
    }
    op = locdesc->ld_s + index;
    *atom_out = op->lr_atom;
    *operand1 = op->lr_number;
    *operand2 = op->lr_number2;
    *operand3 = op->lr_number3;
    *rawop1 = op->lr_raw1;
    *rawop2 = op->lr_raw2;
    *rawop3 = op->lr_raw3;
    *offset_for_branch = op->lr_offset;
    return DW_DLV_OK;
}


int
dwarf_get_location_op_value_c(Dwarf_Locdesc_c locdesc,
    Dwarf_Unsigned   index,
    Dwarf_Small    * atom_out,
    Dwarf_Unsigned * operand1,
    Dwarf_Unsigned * operand2,
    Dwarf_Unsigned * operand3,
    Dwarf_Unsigned * offset_for_branch,
    Dwarf_Error*     error)
{
    Dwarf_Unsigned raw1 = 0;
    Dwarf_Unsigned raw2 = 0;
    Dwarf_Unsigned raw3 = 0;
    int res = 0;

    res = dwarf_get_location_op_value_d(locdesc,
        index,atom_out,
        operand1,operand2,operand3,
        &raw1,&raw2,&raw3,
        offset_for_branch,
        error);
    return res;
}

void
dwarf_loc_head_c_dealloc(Dwarf_Loc_Head_c loclist_head)
{
    Dwarf_Debug dbg = loclist_head->ll_dbg;
    /*  destructor will remove content then free head
        itself */
    dwarf_dealloc(dbg,loclist_head,DW_DLA_LOC_HEAD_C);
}
/* ============== End of the October 2015 interfaces. */
